您好,登錄后才能下訂單哦!
本篇內容主要講解“C++模板>>編譯問題舉例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++模板>>編譯問題舉例分析”吧!
在編譯理論中,通常將編譯過程抽象為5個主要階段:詞法分析(Lexical Analysis),語法分析(Parsing),語義分析(Semantic Analysis),優化(Optimization),代碼生成(Code Generation)。這5個階段類似Unix管道模型,上一個階段的輸出作為下一個階段的輸入。其中,詞法分析是根據輸入源代碼文本流,分割出詞,識 別類別,產生詞法元素(Token)流,如:
int a = 10;
經過詞法分析會得到[(Type, "int"), (Identifier, "a"), (AssignOperator, "="), (IntLiteral, 10)],在后續的語法分析階段,就會根據這些詞法元素匹配相應的語法規則。在我學習編譯原理時,教科書中對于詞法分析的介紹主要是基于正則表達式的,言 下之意就是普通語言的詞法規則是可以通過正則表達式描述的。比如,C語言的變量名規則是“包含字母、數字或下劃線,并且以字母或下劃線開頭”,這就可以用 正則表達式[a-zA-Z][a-zA-Z0-9]*
表達。但是,在實踐中我發現不管是主流語言,還是自己設計的DSL都大量存在不能簡單通過正則表達式進行詞法分析的例子。來看C++98的模版例子:
map<int, vector<int>>
上面這段代碼會被C++98編譯器中報語法錯誤,原因在于它把“>>”識別成了位右移運算符而不是兩個模版右括號,在C++98中必須在兩個括號中間加空格,寫成
map<int, vector<int> >
除此了C++模版,據我所知,經典的FORTRAN語言的語法規則更是大量存在詞法歧義。
我認為從本質上講,這類問題的根源在于詞法分析的依據只是簡單的詞法規則,并不具備所有的語法信息,而詞法歧義必須提升一層在語法規則中消除。所 以,在我自己設計一些DSL的時候干脆就把詞法分析和語法分析合二為一了,相當于讓語法分析在字符層次上去進行,而不是經典的詞法元素層次上,這就是所謂 的Scannerless Parsing。采用這種方法的例子并不少見,TeX, Wiki, Makefile和Perl 6等語言的語法分析器都屬此類。
Scannerless Parsing方法彌補了詞法規則無法消歧的問題,但是同時也破壞了詞法和語法分析簡單清晰的管道結構,總體上增加了實現和理解的復雜度。另外,像C++ 這樣大型的語言,如果開始是有詞法分析的,稍微碰到一個歧義就整個轉成Scannerless Parsing未免也顯得太夸張了。這個問題困擾了我很久,直到最近才找到了一個滿意的解決方案。還是以上面”>>”為例,我們知道現在 C++11已經允許不加空格了,那么C++11編譯器是如何處理這個詞法歧義的呢?答案是:詞法分析階段既然分析不好”>>”,干脆就不分析 了,直接把”>” “>”交給語法分析器來分析,其他沒有詞法歧義的照舊。當我知道這個方案的時候不由得感嘆:妙!理論上,詞法分析是可以什么也不做的,全部把字符一 一交給語法分析器也沒有問題,所以,干脆讓詞法分析只做有把握的部分,解決不了的交給語法分析器,這樣就既保留了管道結構,又解決了詞法歧義。
下面我們再來看看C++11規范關于這個問題的定義:
|
可見,在C++11中,詞法分析器是把”>>”直接當成兩個”>”傳給了語法分析器,然后在語法分析中如果匹配了template- argument-lis語法,***個”>”符號會被直接認為是模版結束符,而不是大于,也不是位移符號。根據這個定義,我構造了一個例子:
template<int N> class Foo { }; Foo<3>>1> foo;
這個例子在C++98中是能正確編譯的,”>>”被解釋成了位移運算,但是它反而不能在C++11中編譯了,因為根據規范***個”>”被解釋成了模版參數結束符。如果要在C++11中編譯,需要顯式地加上括號:
Foo<(3>>1)> foo;
到此,相信大家對“C++模板>>編譯問題舉例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。