3.03 bison移进/规约冲突和操作符优先级
如果你已經(jīng)儲(chǔ)備bison的相關(guān)基礎(chǔ)知識(shí),閱讀理解下面的代碼會(huì)輕松得多。沒有bison基礎(chǔ)的同學(xué)請點(diǎn)擊查看bison基本的語法規(guī)則及相關(guān)介紹。
移進(jìn)/規(guī)約沖突一般是由文法二義性造成的,關(guān)于二義性可以看看這篇文章,以及這位中科院老師的講解。對于這種問題bison提供了一個(gè)聰明的方法,它可以在語法規(guī)則之外單獨(dú)描述優(yōu)先級(jí)。這不僅消除了二義性,也使得語法分析器代碼變得短小而且易于維護(hù)。
bison操作符優(yōu)先級(jí)的規(guī)則
bison操作符優(yōu)先級(jí)的規(guī)則,使用%left,%right,%nonassoc或%precedence聲明記號(hào)并指定其優(yōu)先級(jí)和結(jié)合性。它的語法與%token語法非常相似,如下:
%left symbols… %left <type> symbols…以表達(dá)式“ x op y op z”為例,運(yùn)算符op的關(guān)聯(lián)性決定了運(yùn)算符嵌套,是通過先將x與y分組還是先將y與z分組來解析。
運(yùn)算符的優(yōu)先級(jí)確定它如何與其他運(yùn)算符嵌套。在單個(gè)優(yōu)先級(jí)聲明中聲明的所有標(biāo)記都具有相同的優(yōu)先級(jí),并根據(jù)它們的關(guān)聯(lián)性嵌套在一起。當(dāng)在不同優(yōu)先級(jí)聲明中聲明的兩個(gè)標(biāo)記相關(guān)聯(lián)時(shí),后一個(gè)聲明的標(biāo)記具有更高的優(yōu)先級(jí),并且首先分組。
結(jié)合下面的一個(gè)例子進(jìn)一步學(xué)習(xí)bison操作符的優(yōu)先級(jí)規(guī)則:
%{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關(guān)鍵字聲明了語法規(guī)則中所有語法值可能會(huì)用到的數(shù)據(jù)類型的一個(gè)集合 */ %union{struct ASTNode *a; } /* 聲明的順序決定了優(yōu)先級(jí),越后聲明的優(yōu)先級(jí)越高。bison遇到移進(jìn)/規(guī)約沖突時(shí),它將查詢優(yōu)先級(jí)表,來解決沖突 */ %left '+' '-' %left '*' '/' %nonassoc '|' UMINUS // UMINUS為符號(hào)操作符的偽記號(hào)。使用%nonassoc來聲明'|'和UMINUS,表示這兩個(gè)操作符沒有結(jié)合性,并且它們具有最高的優(yōu)先級(jí)。%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); } // '-'原本聲明時(shí)的優(yōu)先級(jí)要小于'*',使用%pre UMINUS,可以讓'-'擁有UMINUS的優(yōu)先級(jí)。從而使得表達(dá)出"負(fù)號(hào)"的效果| NUMBER { $$ = newnum($1); } %%什么時(shí)候不應(yīng)該使用優(yōu)先級(jí)規(guī)則
使用優(yōu)先級(jí)規(guī)則解決移進(jìn)/規(guī)約沖突時(shí),有的時(shí)候會(huì)寫出讓人難以明白的語法規(guī)則。例如下面情況:表達(dá)式語法或解決在if/then/else語言結(jié)構(gòu)的語法中的"dangling else"沖突,如下:
一個(gè)經(jīng)典的例子:
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...?
從這個(gè)語法片段可以看出,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
這種語法的二義性,應(yīng)該通過修正語法來解決沖突。引入新的規(guī)則來確定到底由哪個(gè)if來控制特定的else子句。應(yīng)該將上面的語法規(guī)則修改為:
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?
通常出現(xiàn)二義性語法都可以通過引入新的規(guī)則來消除二義性,這樣做會(huì)增加語法樹的高度。
總結(jié)
以上是生活随笔為你收集整理的3.03 bison移进/规约冲突和操作符优先级的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PX4 avoidance ROS仿真之
- 下一篇: 大学教程