3.03 bison移进/规约冲突和操作符优先级
如果你已經儲備bison的相關基礎知識,閱讀理解下面的代碼會輕松得多。沒有bison基礎的同學請點擊查看bison基本的語法規則及相關介紹。
移進/規約沖突一般是由文法二義性造成的,關于二義性可以看看這篇文章,以及這位中科院老師的講解。對于這種問題bison提供了一個聰明的方法,它可以在語法規則之外單獨描述優先級。這不僅消除了二義性,也使得語法分析器代碼變得短小而且易于維護。
bison操作符優先級的規則
bison操作符優先級的規則,使用%left,%right,%nonassoc或%precedence聲明記號并指定其優先級和結合性。它的語法與%token語法非常相似,如下:
%left symbols… %left <type> symbols…以表達式“ x op y op z”為例,運算符op的關聯性決定了運算符嵌套,是通過先將x與y分組還是先將y與z分組來解析。
運算符的優先級確定它如何與其他運算符嵌套。在單個優先級聲明中聲明的所有標記都具有相同的優先級,并根據它們的關聯性嵌套在一起。當在不同優先級聲明中聲明的兩個標記相關聯時,后一個聲明的標記具有更高的優先級,并且首先分組。
結合下面的一個例子進一步學習bison操作符的優先級規則:
%{enum Node_T{NT_UNDEF,NT_ADD,NT_SUB,NT_MUL,NT_DIV,NT_ABS,NT_NEG,};struct ASTNode *newast(int NodeType, struct ASTNode *Lft, struct ASTNode *Rht);struct ASTNode *newnum(double d); %}/* %union關鍵字聲明了語法規則中所有語法值可能會用到的數據類型的一個集合 */ %union{struct ASTNode *a; } /* 聲明的順序決定了優先級,越后聲明的優先級越高。bison遇到移進/規約沖突時,它將查詢優先級表,來解決沖突 */ %left '+' '-' %left '*' '/' %nonassoc '|' UMINUS // UMINUS為符號操作符的偽記號。使用%nonassoc來聲明'|'和UMINUS,表示這兩個操作符沒有結合性,并且它們具有最高的優先級。%type <a> exp%% ... exp: exp '+' exp { $$ = newast(NT_ADD, $1, $3); }| exp '-' exp { $$ = newast(NT_SUB, $1, $3); }| exp '*' exp { $$ = newast(NT_MUL, $1, $3); }| exp '/' exp { $$ = newast(NT_DIV, $1, $3); }| '|' exp { $$ = newast(NT_ABS, $2, NULL); }| '(' exp ')' { $$ = $2; }| '-' exp %prec UMINUS { $$ = newast(NT_NEG, NULL, $2); } // '-'原本聲明時的優先級要小于'*',使用%pre UMINUS,可以讓'-'擁有UMINUS的優先級。從而使得表達出"負號"的效果| NUMBER { $$ = newnum($1); } %%什么時候不應該使用優先級規則
使用優先級規則解決移進/規約沖突時,有的時候會寫出讓人難以明白的語法規則。例如下面情況:表達式語法或解決在if/then/else語言結構的語法中的"dangling else"沖突,如下:
一個經典的例子:
Statement→if?Exprthen?Statementelse?Statement∣if?Exprthen?Statement∣Assignment∣...otherstatements...\begin{aligned} Statement \rightarrow&\ \text{if}\ Expr\ \text{then} \ Statement\ \text{else}\ Statement\\ &|\text{if}\ Expr\ \text{then} \ Statement\\ &|Assignment\\ &|\ \ ...other statements... \end{aligned} Statement→??if?Expr?then?Statement?else?Statement∣if?Expr?then?Statement∣Assignment∣??...otherstatements...?
從這個語法片段可以看出,else是可選的。不幸的是,下列代碼片段:
if?Expr1then?if?Expr2then?Assignment1else?Assignment2\text{if}\ Expr1\ \text{then}\ \text{if}\ Expr2\ \text{then}\ Assignment1\ \text{else}\ Assignment2if?Expr1?then?if?Expr2?then?Assignment1?else?Assignment2
這種語法的二義性,應該通過修正語法來解決沖突。引入新的規則來確定到底由哪個if來控制特定的else子句。應該將上面的語法規則修改為:
Statement→if?Exprthen?Statement∣if?Exprthen?WithElseelse?Statement∣AssignmentWithElse→if?Exprthen?WithElseelse?WithElse∣Assignment\begin{aligned} Statement \rightarrow&\ \text{if}\ Expr\ \text{then} \ Statement\\ &|\text{if}\ Expr\ \text{then} \ WithElse\ \text{else}\ Statement\\ &|Assignment\\ WithElse \rightarrow&\ \text{if}\ Expr\ \text{then} \ WithElse\ \text{else}\ WithElse\\ &|Assignment\\ \end{aligned} Statement→WithElse→??if?Expr?then?Statement∣if?Expr?then?WithElse?else?Statement∣Assignment?if?Expr?then?WithElse?else?WithElse∣Assignment?
通常出現二義性語法都可以通過引入新的規則來消除二義性,這樣做會增加語法樹的高度。
總結
以上是生活随笔為你收集整理的3.03 bison移进/规约冲突和操作符优先级的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PX4 avoidance ROS仿真之
- 下一篇: 大学教程