新聞中心
在編譯理論中,通常將編譯過程抽象為5個(gè)主要階段:詞法分析(Lexical Analysis),語(yǔ)法分析(Parsing),語(yǔ)義分析(Semantic Analysis),優(yōu)化(Optimization),代碼生成(Code Generation)。這5個(gè)階段類似Unix管道模型,上一個(gè)階段的輸出作為下一個(gè)階段的輸入。其中,詞法分析是根據(jù)輸入源代碼文本流,分割出詞,識(shí) 別類別,產(chǎn)生詞法元素(Token)流,如:

創(chuàng)新互聯(lián)公司長(zhǎng)期為1000多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為桃源企業(yè)提供專業(yè)的成都做網(wǎng)站、成都網(wǎng)站建設(shè),桃源網(wǎng)站改版等技術(shù)服務(wù)。擁有十年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
- int a = 10;
?經(jīng)過詞法分析會(huì)得到[(Type, "int"), (Identifier, "a"), (AssignOperator, "="), (IntLiteral, 10)],在后續(xù)的語(yǔ)法分析階段,就會(huì)根據(jù)這些詞法元素匹配相應(yīng)的語(yǔ)法規(guī)則。在我學(xué)習(xí)編譯原理時(shí),教科書中對(duì)于詞法分析的介紹主要是基于正則表達(dá)式的,言 下之意就是普通語(yǔ)言的詞法規(guī)則是可以通過正則表達(dá)式描述的。比如,C語(yǔ)言的變量名規(guī)則是“包含字母、數(shù)字或下劃線,并且以字母或下劃線開頭”,這就可以用 正則表達(dá)式[a-zA-Z][a-zA-Z0-9]*表達(dá)。但是,在實(shí)踐中我發(fā)現(xiàn)不管是主流語(yǔ)言,還是自己設(shè)計(jì)的DSL都大量存在不能簡(jiǎn)單通過正則表達(dá)式進(jìn)行詞法分析的例子。來看C++98的模版例子:
- map
>
上面這段代碼會(huì)被C++98編譯器中報(bào)語(yǔ)法錯(cuò)誤,原因在于它把“>>”識(shí)別成了位右移運(yùn)算符而不是兩個(gè)模版右括號(hào),在C++98中必須在兩個(gè)括號(hào)中間加空格,寫成
- map
>
除此了C++模版,據(jù)我所知,經(jīng)典的FORTRAN語(yǔ)言的語(yǔ)法規(guī)則更是大量存在詞法歧義。
我認(rèn)為從本質(zhì)上講,這類問題的根源在于詞法分析的依據(jù)只是簡(jiǎn)單的詞法規(guī)則,并不具備所有的語(yǔ)法信息,而詞法歧義必須提升一層在語(yǔ)法規(guī)則中消除。所 以,在我自己設(shè)計(jì)一些DSL的時(shí)候干脆就把詞法分析和語(yǔ)法分析合二為一了,相當(dāng)于讓語(yǔ)法分析在字符層次上去進(jìn)行,而不是經(jīng)典的詞法元素層次上,這就是所謂 的Scannerless Parsing。采用這種方法的例子并不少見,TeX, Wiki, Makefile和Perl 6等語(yǔ)言的語(yǔ)法分析器都屬此類。
Scannerless Parsing方法彌補(bǔ)了詞法規(guī)則無法消歧的問題,但是同時(shí)也破壞了詞法和語(yǔ)法分析簡(jiǎn)單清晰的管道結(jié)構(gòu),總體上增加了實(shí)現(xiàn)和理解的復(fù)雜度。另外,像C++ 這樣大型的語(yǔ)言,如果開始是有詞法分析的,稍微碰到一個(gè)歧義就整個(gè)轉(zhuǎn)成Scannerless Parsing未免也顯得太夸張了。這個(gè)問題困擾了我很久,直到最近才找到了一個(gè)滿意的解決方案。還是以上面”>>”為例,我們知道現(xiàn)在 C++11已經(jīng)允許不加空格了,那么C++11編譯器是如何處理這個(gè)詞法歧義的呢?答案是:詞法分析階段既然分析不好”>>”,干脆就不分析 了,直接把”>” “>”交給語(yǔ)法分析器來分析,其他沒有詞法歧義的照舊。當(dāng)我知道這個(gè)方案的時(shí)候不由得感嘆:妙!理論上,詞法分析是可以什么也不做的,全部把字符一 一交給語(yǔ)法分析器也沒有問題,所以,干脆讓詞法分析只做有把握的部分,解決不了的交給語(yǔ)法分析器,這樣就既保留了管道結(jié)構(gòu),又解決了詞法歧義。
下面我們?cè)賮砜纯碈++11規(guī)范關(guān)于這個(gè)問題的定義:
|
可見,在C++11中,詞法分析器是把”>>”直接當(dāng)成兩個(gè)”>”傳給了語(yǔ)法分析器,然后在語(yǔ)法分析中如果匹配了template- argument-lis語(yǔ)法,***個(gè)”>”符號(hào)會(huì)被直接認(rèn)為是模版結(jié)束符,而不是大于,也不是位移符號(hào)。根據(jù)這個(gè)定義,我構(gòu)造了一個(gè)例子:
- template
- class Foo {
- };
- Foo<3>>1> foo;
這個(gè)例子在C++98中是能正確編譯的,”>>”被解釋成了位移運(yùn)算,但是它反而不能在C++11中編譯了,因?yàn)楦鶕?jù)規(guī)范***個(gè)”>”被解釋成了模版參數(shù)結(jié)束符。如果要在C++11中編譯,需要顯式地加上括號(hào):
- Foo<(3>>1)> foo;
當(dāng)前題目:C++模板”>>”編譯問題與詞法消歧設(shè)計(jì)
文章來源:http://fisionsoft.com.cn/article/cddcseg.html


咨詢
建站咨詢
