2014-09-24 52 views
0

我想用jison爲JavaScript語言的一個子集創建一個解析器,我有一些問題。Jison:當if-else和語句ara合併時語法發生衝突

起初,我有這個定義非終結stmt和它的作品:

stmt 
    : FOR LPAREN varlist_decl SEMICOLON expr SEMICOLON expr RPAREN stmt 
     {$$ = ['for ('].concat($3, ['; '], $5, ['; '], $7, [') '], $9)} 
    | varlist_decl 
     {$$ = $1} 
    | expr 
     {$$ = $1} 
    | LBRACE stmts RBRACE 
     {$$ = ['{', 0, 1].concat($2, [0, -1, '}'])} 
    ; 

後,我添加了以下規則stmt

: IF LPAREN expr RPAREN stmt 
     {$$ = ['if ('].concat($3, [') '], $5)} 
    | IF LPAREN expr RPAREN stmt ELSE stmt 
     {$$ = ['if ('].concat($3, [') '], $5, [0, 'else '], $7)} 

這個語法是模糊和衝突出現。所以我跟着這些模式來解決晃來晃去別的歧義:

stmt 
    : IF LPAREN expr RPAREN stmt 
    | IF LPAREN expr RPAREN stmt ELSE stmt 
    | other_stmt 
    ; 

它必須被轉換成: 語句 :closed_stmt | non_closed_stmt ;

closed_stmt 
    : IF LPAREN expr RPAREN closed_stmt ELSE closed_stmt 
    | other_stmt 
    ; 

non_closed_stmt 
    : IF LPAREN expr RPAREN stmt 
    | IF LPAREN expr RPAREN closed_stmt ELSE non_closed_stmt 
    ; 

這是我的語法當前部分:

stmt 
    : closed_stmt 
     {$$ = $1} 
    | non_closed_stmt 
     {$$ = $1} 
    ; 

closed_stmt 
    : IF LPAREN expr RPAREN closed_stmt ELSE closed_stmt 
     {$$ = ['if ('].concat($3, [') '], $5, [0, 'else '], $7)} 
    | FOR LPAREN varlist_decl SEMICOLON expr SEMICOLON expr RPAREN stmt 
     {$$ = ['for ('].concat($3, ['; '], $5, ['; '], $7, [') '], $9)} 
    | varlist_decl 
     {$$ = $1} 
    | expr 
     {$$ = $1} 
    | LBRACE stmts RBRACE 
     {$$ = ['{', 0, 1].concat($2, [0, -1, '}'])} 
    ; 

non_closed_stmt 
    : IF LPAREN expr RPAREN stmt 
     {$$ = ['if ('].concat($3, [') '], $5)} 
    | IF LPAREN expr RPAREN closed_stmt ELSE non_closed_stmt 
     {$$ = ['if ('].concat($3, [') '], $5, [0, 'else '], $7)} 
    ; 

而這部分只有當我發表意見for-statement規則工作。

你如何解決它?

這裏是我的全部代碼庫:https://github.com/xgbuils/if-for-grammar-issue

回答

1

您需要for聲明的封閉和不封閉的形式;它不能僅以stmt結束。因此,您在closed_stmt規則中放置了一個以closed_stmt結尾的封閉格式,在non_closed_stmt規則中放入了一個以non_closed_stmt結尾的非封閉格式。

這是因爲

for (x=0;x<3;++x) if (x==2) do_something(); 

是,它會吸收以下else令牌感覺就像非封閉,

if (x==2) do_something(); 

if聲明的封閉性不會因在其前面添加一個(或多個)for標頭而被更改。