-
Notifications
You must be signed in to change notification settings - Fork 7
Bison实现句尾的可选分号 Optional semicolon grammar in Bison
西风逍遥游 edited this page Nov 8, 2021
·
5 revisions
句尾分号在Bison中一直是一个让人非常困扰的问题,绝大部分复杂的语法中,如果在两个语句中间不插入分号,会导致严重的歧义。这也是编程语言设计中,为何一定要添加分号的原因。试想下面的两条语句
int a = call
(b);
如果看做一条语句,可以认为是一条调用语句,如果看成两条语句,可以认为是一个赋值加一个表达式计算。这个歧义在bison中是不能通过简单的词语法设计来弥补的,原因如下:
-
如果词法分析器永远输出
'\n'
, 则必须讨论语法中换号符是可选的,则在语法定义中一定会出现这种结构:expr : expr oplb '+' oplb expr
。在各种位置都添加上oplb
表示一个可选的换行符,但这种语法本身同样带有大量歧义,产生的歧义数量甚至比不引入';'
还要多。 -
如果词法分析器永远不输出
'\n'
,则语法上,上面的例子则永远不能被识别为两条语句,因为bison是贪婪匹配的,永远想移入更多的符号,则用户无法通过分行来实现对语句的切割。
最好的方案是,如果语句确定不需要';'
时,词法分析器忽略换行符'\n'
,而用户在某些语句结尾需要分割时却没有分号';'
,自动检测我们是否遇到了一个换行符'\n'
,遇到后将其视为一个分号。
普通的手工写的LL parser由于可以精细控制什么时候lookahead,往往可以采用简单的代码实现。例如:
int getNextToken(bool requireSemicolon) {
int token = yylex();
if (token == '\n')
if (requireSemicolon) return ';';
else return getNextToken(false);
return token;
}
这种逻辑简单易懂,需要分号时,参数设置为true
即可,自动将下一个回车符合换成';'
发送给你,如果不是回车,那么说明用户不想在此分割,继续贪婪匹配更长的语句即可。