Parsing 如何处理Lex中的关键字?

Parsing 如何处理Lex中的关键字?,parsing,yacc,lex,Parsing,Yacc,Lex,假设您有一种允许这样的生产的语言:optional optional=42,其中第一个“optional”是关键字,第二个“optional”是标识符 一方面,我希望有一个类似于optional{return optional;}的Lex规则,稍后将在YACC中使用,例如: optional : OPTIONAL identifier '=' expression ; 如果我将标识符定义为,那么说: identifier : OPTIONAL | FIXED32 | FIXED64 | ...

假设您有一种允许这样的生产的语言:
optional optional=42
,其中第一个“optional”是关键字,第二个“optional”是标识符

一方面,我希望有一个类似于
optional{return optional;}
的Lex规则,稍后将在YACC中使用,例如:

optional : OPTIONAL identifier '=' expression ;
如果我将
标识符定义为,那么说:

identifier : OPTIONAL | FIXED32 | FIXED64 | ... /* couple dozens of keywords */ 
    | IDENTIFIER ;
只是感觉很糟糕。。。此外,我需要两种标识符,一种用于关键字被允许作为标识符时,另一种用于关键字不被允许时

有没有一个惯用的方法来解决这个问题

有没有一个惯用的方法来解决这个问题

除了您已经找到的解决方案之外,没有。半保留关键字绝对不是lex/yacc语法的预期用例

lemon解析器生成器有一个针对此类情况设计的回退声明,但据我所知,该有用的特性从未添加到bison中


您可以使用GLR语法来避免必须计算出
标识符的所有不同子集。但是当然会有性能方面的损失。

您已经在lex/yacc中发现了处理这一问题的最常用方法,虽然不漂亮,但也不算太糟糕。通常,您会调用与标识符或(一组)关键字匹配的规则
whateverName
,您可能有多个规则,因为不同的上下文可能有不同的关键字集,它们可以接受为名称


如果您的关键字仅在易于识别的位置(例如在行的开头)被识别为关键字,那么另一种可能的方法是使用lex start状态,以便仅在关键字位于该上下文中时返回关键字标记。在任何其他上下文中,关键字将仅作为标识符令牌返回。您甚至可以使用yacc操作来为一些复杂的上下文设置lexer状态,但是您需要知道解析器可能会执行一个令牌lexer lookahead(规则可能会在读取操作后的令牌之后才会运行)。

这是一种不保留关键字的情况。一些编程语言允许这样做:PL/I、FORTRAN。这不是lexer的问题,因为lexer应该总是知道哪些标识符是关键字。这是一个解析器问题。它通常会在语言规范中造成太多的歧义,解析成为一场噩梦。语法应该是这样的:

标识符:关键字|标识符

关键词:可选|固定32 |固定64 |

如果你在语法上没有冲突,那么你就没事了。如果存在冲突,则需要更强大的解析器生成器,如LR(k)或GLR