2015-08-08 33 views
0

我想寫一個語法,我遇到了一個問題,我簡化爲算術表達式的經典例子。我.Y文件的相關部分是:避免在野牛連續運營商

 
%left '+' '-' 
%left '*' 
%left UNARY 
%token UNARY 
%token INTEGER 
%% 
start: expr {printf("Result: %d\n",$1);} 
expr : INTEGER 
    | '-' expr %prec UNARY {$$ = -$2;} 
    | expr '+' expr   {$$ = $1 + $3;} 
    | expr '-' expr   {$$ = $1 - $3;} 
    | expr '*' expr   {$$ = $1 * $3;} 
    | '(' expr ')'   {$$ = $2;} 
    ; 
%% 

此語法接受這樣的表達式「1 + -2」和「1 + - 2」,但我想排除連續運營。有沒有一個簡單的方法來做到這一點,而不是太複雜的語法或訴諸一些複雜的堆棧操作?

+0

我不確定這是一個嚴重的建議,但是如果'--'是一個由詞法分析器識別但不能被語法識別的令牌,那麼當用戶鍵入'--'時,它們將會出現語法錯誤。我想,你可以用'+ -'來做同樣的事情。我不確定你是否想取締'2/-3'和'2 * -3'。顯然,你會允許'-2 + 1',並且加法是交換的,所以不應該允許使用'1 + -2'。它真的會傷害你和你的語法嗎?沒有小的限制,你的系統會更系統化(更容易預測,使用,記錄)。 –

+0

是的,我想禁止所有連續的操作員。無論如何,除非我讓詞法分析器變得更加複雜,否則,當它們被空格分隔時,您的建議將允許它們:「1-2-2」! – Tsf

+0

我懷疑你的需求變成語義規則,由語法的動作中的代碼強制執行,而不是由語法強制執行。你大概不會把括號作爲操作符。另一個選擇,我想是讓詞法分析器記住它最後返回的內容,並使它引發某種錯誤(返回一個無法識別的標記類型,例如'CONSECUTIVE_OPERATORS',如果它有兩個連續的操作符,但我不相信這是一個很好的限制,放在代碼上,正交性和所有...... –

回答

1

的常用方法是通過拆分元運算符成一個獨立的生產:

%left '+' '-' 
%left '*' 
%nonassoc UNARY 
%token INTEGER 
%% 
start: expr {printf("Result: %d\n",$1);} 
expr : primary 
    | '-' primary %prec UNARY {$$ = -$2;} 
    | expr '+' expr   {$$ = $1 + $3;} 
    | expr '-' expr   {$$ = $1 - $3;} 
    | expr '*' expr   {$$ = $1 * $3;} 
    ; 
primary : INTEGER 
    | '(' expr ')'   {$$ = $2;} 
    ; 

這是(部分)轉換的優先級規則爲「正常」的作品,然後調整他們得到你想要的效果。

Alterantely,如果你希望禁止所有連續的運營商,而不僅僅是同一個運營商重複,你可以因此它不能任何其他操作後發生分解出的前綴規則:

%left '+' '-' 
%left '*' 
%nonassoc UNARY 
%token INTEGER 
%% 
start: expr {printf("Result: %d\n",$1);} 
expr : INTEGER 
    | '-' non_unary_expr %prec UNARY  {$$ = -$2;} 
    | expr '+' non_unary_expr    {$$ = $1 + $3;} 
    | expr '-' non_unary_expr    {$$ = $1 - $3;} 
    | expr '*' non_unary_expr    {$$ = $1 * $3;} 
    | '(' expr ')'      {$$ = $2;} 
    ; 
non_unary_expr : INTEGER 
    | non_unary_expr '*' non_unary_expr {$$ = $1 * $3;} 
    | '(' expr ')'      {$$ = $2;} 
    ; 

你可能要好奇爲什麼二進制文件+-從最後一條規則中缺失 - 事實證明,它們因優先級而不需要(如果添加它們,會因爲衝突而得到野牛警告,說它們無用)。一般來說,當像這樣重構時,我寧願擺脫所有的優先級定義,而是對優先級使用單獨的規則,因爲這會使得事情更清晰:

%token INTEGER 
%% 
start : expr { printf("Result: %d\n",$1); } 
expr : term 
     | expr '+' non_unary_term { $$ = $1 + $2; } 
     | expr '-' non_unary_term { $$ = $1 - $2; } 
     ; 
term : factor 
     | term '*' non_unary_factor { $$ = $1 * $3; } 
     ; 
non_unary_term : non_unary_factor 
     | non_unary_term '*' non_unary_factor { $$ = $1 * $3; } 
     ; 
factor : INTEGER 
     | '-' non_unary_factor { $$ = -$2; } 
     | '(' expr ')'   { $$ = $2; } 
     ; 
non_unary_factor : INTEGER 
     | '(' expr ')'   { $$ = $2; } 
     ; 
+0

這仍然會接受OP說的「1 + -2」應該是非法的。 – rici

+0

Rici,你說得對。但它不接受「1 + - 2」;三名經營者出局! – Tsf

+0

@rici:我的印象是,他想讓這個,只是不允許連續的一元'-' –