我想用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
答案 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
标题而改变。