我想用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
;
必须将其转化为:stmt:closed_stmt|非闭合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)}
;
并且这部分仅在我评论CCD_ 3规则时起作用。
你是怎么修的?
这是我的完整代码库:https://github.com/xgbuils/if-for-grammar-issue
您需要for
语句的闭合和非闭合形式;它不能仅仅以CCD_ 5结束。因此,在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();
在其将吸收随后的CCD_ 10令牌的意义上。if
语句的封闭性不会通过在其前面加一个(或多个)for
标头来改变。