簡體   English   中英

使用yacc解析一系列表達式

[英]Parsing a sequence of expressions using yacc

我試圖解析一系列沒有分隔符的表達式,以便能夠解析ML / F#樣式函數調用:

myfunc expr1 expr2 expr3

但是,表達式序列給出了一個移位/減少沖突的列表。

我的猜測是沖突是由我的語法的遞歸性質引起的,但我不知道如何解決這些沖突。

我的(簡化的)優先規則和語法如下所示:

/* Lowest precedence */
%left PLUS
%left TIMES
%left LPAR
/* Highest precedence */

Expr: 
  | CSTINT                                { CstI $1                   }
  | LPAR Expr RPAR                        { $2                        }
  | Expr TIMES Expr                       { Prim("*", $1, $3)         }
  | Expr PLUS Expr                        { Prim("+", $1, $3)         }
  | NAME ExprList                         { Call(Var $1, $2)          }

ExprList:
  |                                      { []                        }
  | Expr ExprList                        { $1::$2                    }

當我把它傳遞給fsyacc時,我得到一個shift / reduce和減少/減少沖突的列表。 轉移/減少沖突的示例是

state 11: shift/reduce error on PLUS

來自狀態11的fsyacc的輸出是:

state 11:
  items:
    Expr -> Expr . 'TIMES' Expr
    Expr -> Expr . 'PLUS' Expr
    ExprList -> Expr . ExprList

  actions:
    action 'EOF' (noprec):   reduce ExprList --> 
    action 'LPAR' (explicit left 10000):   shift 6
    action 'RPAR' (noprec):   reduce ExprList --> 
    action 'COMMA' (noprec):   reduce ExprList --> 
    action 'PLUS' (explicit left 9998):   shift 13
    action 'TIMES' (explicit left 9999):   shift 12
    action 'NAME' (noprec):   shift 14
    action 'CSTINT' (noprec):   shift 5
    action 'error' (noprec):   reduce ExprList --> 
    action '#' (noprec):   reduce ExprList --> 
    action '$$' (noprec):   reduce ExprList --> 

  immediate action: <none>
 gotos:
    goto Expr: 11
    goto ExprList: 16

自從我參加編譯器理論課程以來已經有一段時間了,所以雖然我知道什么是轉移/減少和減少/減少沖突,但我不習慣考慮它們。 特別是,我沒有看到PLUS減少如何導致有效的解析。 總而言之,任何對以下一個或多個問題的見解都將受到高度贊賞:

  1. 為什么我的語法看似含糊不清?
  2. 我可以使用優先級和/或關聯性規則來修復它,如果沒有,
  3. 我是否需要重寫語法,如果是這樣,粗略地說,我該怎么做?
  4. yacc是否適合這樣的構造?

1.為什么我的語法似乎含糊不清?

你的語法歧義。 這不是一種幻覺。

假設f是一個函數。

f  x + 7

那是f(x) + 7還是f(x+7) 你的語法同時產生。

IIRC,功能應用程序綁定非常緊密並且與左側相關聯。 所以上面的表達式應解析為f(x) + 7

2.我可以使用優先級和/或關聯性規則修復它,如果沒有,

您可以使用優先級和關聯性規則消除功能應用程序的歧義; 你只需要用%prec聲明它的優先級。 然而,它最終看起來有點難看......

3.我是否需要重寫語法,如果是這樣,粗略地說,我該怎么做?

...我不認為將函數應用程序表示為Name ExprList是正確的。 如果你一次一個地討論一個參數,至少在構建AST時它會更清晰,如果你在語法中而不是使用優先規則(它實際上不是為隱形運算符設計),它看起來更漂亮。 見下文。

4. yacc是否適合這樣的結構?

當然,為什么不呢?

這是兩個工作(據我所知)yacc語法。 第一個使用優先級聲明的一切; 第二個分離出功能應用程序,我認為它更清潔:

// grammar1.y:

%left '+'
%left '*'
%left ATOM ';' '(' ')'

%%

program: /* empty */           { $$ = ""; }
       | program statement ';' { std::cout << $2 << std::endl; }
       | program ';'
       ;

statement: expr
         ;

expr: ATOM
    | '(' expr ')'             { $$ = $2; }
    | expr expr %prec ATOM     { $$ = '(' + $1 + ' ' + $2 + ')'; }
    | expr '+' expr            { $$ = "(+ " + $1 + ' ' + $3 + ')'; }
    | expr '*' expr            { $$ = "(* " + $1 + ' ' + $3 + ')'; }
    ;

// grammar2.y

%token ATOM

%left '+'
%left '*'

%%

program: /* empty */           { $$ = ""; }
       | program statement ';' { std::cout << $2 << std::endl; }
       | program ';'
       ;

statement: expr
         ;

term : ATOM
     | '(' expr ')'             { $$ = $2; }
     ;

apply: term
     | apply term              { $$ = '(' + $1 + ' ' + $2 + ')'; }
     ;

expr : apply
     | expr '+' expr            { $$ = "(+ " + $1 + ' ' + $3 + ')'; }
     | expr '*' expr            { $$ = "(* " + $1 + ' ' + $3 + ')'; }
     ;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM