0

我想用 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)}

这种语法模棱两可,出现冲突。所以我按照这些模式来解决悬空的 else 歧义:

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

它必须转换为: 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

4

1 回答 1

1

You need closed and non-closed forms of the for statement; it cannot just end with stmt. So you put a closed form ending with closed_stmt in the closed_stmt rules, and a non-closed form ending with non_closed_stmt in the non_closed_stmt rules.

That's because

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

is just as non-closed as

if (x==2) do_something();

in the sense that it will absorb a following else token. The closedness of the if statement is not altered by preceding it with one (or more) for headers.

于 2014-09-25T05:25:29.090 回答