Jison:if-else和ara结合时的语法冲突

时间:2014-09-24 21:31:18

标签: javascript parsing if-statement for-loop jison

我想用jison为JavaScript语言的一个子集制作一个解析器,但我遇到了一些问题。

起初我对非终结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 个答案:

答案 0 :(得分:1)

您需要for声明的封闭和非封闭形式;它不能以stmt结尾。因此,您在closed_stmt规则中以closed_stmt结尾的封闭表单和non_closed_stmt规则中以non_closed_stmt结尾的非封闭表单。

那是因为

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

一样非封闭
if (x==2) do_something();

从某种意义上说它将吸收以下else令牌。 if语句的封闭性不会因为它前面带有一个(或多个)for标题而改变。