2014-09-24 55 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标头而被更改。