2014-02-22 112 views
1

我一直在Flex和Bison的計算器上工作。我可以指定單個變量如多變量計算器Bison

m = 5 
m * 5 
25 

,但現在我希望能夠分配多個變量,如m = n = 5

這裏就是我有我的野牛文件現在。我將如何修改它到上面?

%{ 
#include <stdio.h> 
void yyerror(char *); 
int yylex(void); 
int sym[26]; 
%} 
%token INTEGER VARIABLE 
%left '+' '-' '*' 
%% 
program: 
program statement '\n' 
| /* NULL */ 
; 
statement: 
expression { printf("%d\n", $1); } 
| VARIABLE '=' expression { sym[$1] = $3; } 
; 
expression: 
INTEGER 
| VARIABLE { $$ = sym[$1]; } 
| '-' expression { $$ = -$2; } 
| expression '+' expression { $$ = $1 + $3; } 
| expression '-' expression { $$ = $1 - $3; } 
| expression '*' expression { $$ = $1 * $3; } 
| '(' expression ')' { $$ = $2; } 
; 
%% 
void yyerror(char *s) { 
fprintf(stderr, "%s\n", s); 
} 
int main(void) { 
yyparse(); 
} 

回答

2

三點快意見:

1)你設置+-*具有相同的優先級,這意味着

1 + 2 * 3 

會,就好像是

(1 + 2) * 3 (9) 
解析

而正常解釋將是

1 + (2 * 3) (7) 

2)的確,賦值可以看作是表達式的另一種情況,其中=運算符的優先級低於其他運算符,並且與右側關聯。

3)最後,你應該設置一元減號的優先級。有關更多說明,請參見bison manual

使這些變化導致下面的簡單語法:

%token INTEGER VARIABLE 
%right '=' 
%left '+' '-' 
%left '*' 
%right UNOP 
%% 

program: 
program statement '\n' 
| /* NULL */ 
; 
statement: 
expression { printf("%d\n", $1); } 
| /* EMPTY; added to allow empty lines */ 
; 
expression: 
INTEGER 
| VARIABLE     { $$ = sym[$1]; } 
| VARIABLE '=' expression { $$ = sym[$1] = $3; } /* CHANGED; return result */ 
| '-' expression %prec UNOP { $$ = -$2; }   /* CHANGED; add precedence */ 
| expression '+' expression { $$ = $1 + $3; } 
| expression '-' expression { $$ = $1 - $3; } 
| expression '*' expression { $$ = $1 * $3; } 
| '(' expression ')'  { $$ = $2; } 
; 

注意expression是在上述規則左右兩個遞歸的情況下使用。這很正常。儘管在有關的權利遞歸野牛手冊中的相當危言聳聽說法,它實際上是完全合理的寫右遞歸規則時,這就是語言的語義表示。 (如果沒有語義差異,則傾向於使用左遞歸來避免使用解析器堆棧,但使用解析器堆棧很少是問題。)

正如Chris Dodd在評論中指出的那樣,上述簡化語法會改變語義因爲它會打印出賦值表達式的值;在原來的轉讓聲明中是啞巴。這很容易解決,但稍微乏味。我沒有在上面的答案中做,因爲它分散瞭解決方案的結構。

最簡單的解決方法是重複分配生產,既作爲statement部分和的expression;這導致減少/減少衝突,野牛會警告你,但因爲野牛更喜歡較早的文件中的減少,會產生正確的結果。許多人(包括我)會考慮在生產守則中依靠這個規則來醜陋難以維護。

另一種選擇是將表達式分解爲「安靜」和「響亮」表達式,它們對於statement具有不同的單位制作。這看起來更像是原始語法,優先級固定。

另一種選擇是構建抽象語法樹(AST)而不是立即執行程序。當AST執行時,如果頂層節點是分配,您可以輕鬆地抑制打印結果。 (與安靜/響亮的解決方案不同,AST的簡單實現將會抑制打印,這既適用於簡單分配,也適用於明顯的表達賦值(a = 3),但您也可以解決此問題。)

+0

一個小調 - 這會改變程序的行爲,導致它打印賦值語句後分配的值。 –

+0

@chrisDodd:是的。我要提到的是,但最後我不得不去做別的事情。我會添加一個註釋。 – rici

0

這是很容易做到的右遞歸,不幸的是不是很有效,在野牛:

statement: 
    expression {} 
    | assignment {} 
    ; 
assigment: 
    VARIABLE '=' assignment {} 
    | VARIABLE '=' expression {} 
    ; 

另外,左遞歸的解決方案:

statement: 
    expression {} 
    | assignment {} 
    ; 
assigment: 
    recursive_assignment '=' expression {} 
    ; 
recursive_assignment: 
    recursive_assignment '=' VARIABLE {} 
    | VARIABLE {} 
    ; 

Here是關於野牛遞歸的一些有用信息。