2013-01-06 70 views
1

我正在研究一個小型編譯器,以便更好地理解創建自己的語言的困難。現在我處於爲我的語法添加指針功能的階段,但我通過這樣做了減少/減少衝突。在我的語法中引入指針時減少/減少衝突

這是我的語法的簡化版本,可由bnfc編譯。我使用happy解析器生成器,這是程序告訴我存在減少/減少衝突。

entrypoints Stmt ; 

-- Statements 
------------- 
SDecl. Stmt ::= Type Ident; -- ex: "int my_var;" 
SExpr. Stmt ::= Expr;  -- ex: "printInt(123); " 

-- Types 
------------- 
TInt.  Type ::= "int" ; 
TPointer. Type ::= Type "*" ; 
TAlias. Type ::= Ident ; -- This is how I implement typedefs 

-- Expressions 
-------------- 
EMult.  Expr1 ::= Expr1 "*" Expr2 ; 
ELitInt. Expr2 ::= Integer ; 
EVariable. Expr2 ::= Ident ; 

-- and the standard corecions 
_.   Expr ::= Expr1 ; 
_.   Expr1 ::= Expr2 ; 

我正在學習語法如何工作的階段。但我想我知道會發生什麼。考慮這兩個方案

main(){ 
    int a; 
    int b; 
    a * b; 
} 

typedef int my_type; 
main(){ 
    my_type * my_type_pointer_variable; 
} 

(該typedefmain(){}部分是不相關的,在我的語法,但是他們給予一定的上下文中)

在第一個節目,我想它會將a "*" b解析爲Stmt ==(SExpr)==> Expr ==(EMult)==> Expr * Expr ==(..)==> Ident "*" Ident,即基本上使用SExpr規則開始步進。

與此同時,我想my_type * my_type_pointer_variable使用規則進行擴展。 Stmt ==(SDecl)==> Type Ident ==(TPointer)==> Type "*" Ident ==(TAlias)==> Ident "*" Ident

但是,語法階段不知道標識符最初是一個類型別名還是變量。 (1)我怎樣才能擺脫減少/減少衝突和(2)我是唯一有這個問題的人嗎?有沒有一個明顯的解決方案,c語法如何解決這個問題?

到目前爲止,我已經成功地通過使用「&」或其他符號而不是「*」成功地更改了我的語言的語法,但這是非常不可取的。另外,我不能從各種公共C語法中理解,並試圖明白爲什麼他們沒有這個問題,但我沒有在這方面運氣。

最後,我該如何自行解決這些問題?我從happy得知的更詳細的輸出是衝突發生的方式,是巧妙解決這些衝突的唯一方法嗎?恐怕我會偶然發現更多的問題,例如介紹EIndir. Expr = '*' Expr;

回答

3

這個問題在C解析器中處理的通常方式通常稱爲"the lexer feedback hack"。它是一種'黑客',它在語法上根本不涉及它;相反,當詞法分析器識別標識符時,它將該標識符分類爲類型名稱或非類型名稱,併爲每種情況返回不同的標記(通常將標識符指定爲「TypeIdent」作爲類型名稱,簡稱爲「Ident」任何其他)。詞法分析器通過查看符號表的當前狀態來進行選擇,因此它可以看到在解析中的當前點之前發生的所有typedef,而不是當前點之後的typedef。這就是爲什麼C要求你在每個編譯單元首次使用之前聲明typedefs。

+0

非常有趣!有沒有辦法做到這一點,而不用編寫自己的不需要有內存的詞法分析器?或者是否真的沒有類似c語法的編程語言(使用'*'乘法*和*指針聲明),並允許將類型別名聲明(typedefs)放在代碼中的任何位置? – Tarrasch

+0

現在標記爲正確。我剛剛意識到,詞法分析黑客是一個實際的術語,甚至在維基百科上進行了解釋。我編輯了答案,清楚地反映了這一點。 – Tarrasch