假设您的语言允许这样生成:optional optional = 42
,其中第一个“可选”是关键字,第二个“可选”是标识符。
一方面,我希望有一个像optional { return OPTIONAL; }
这样的Lex规则,以后会在YACC中使用,例如:
optional : OPTIONAL identifier '=' expression ;
如果我然后将identifier
定义为:
identifier : OPTIONAL | FIXED32 | FIXED64 | ... /* couple dozens of keywords */
| IDENTIFIER ;
它只是感觉很糟糕...此外,我需要两种标识符,一种用于何时允许关键字作为标识符,另一种用于何时不是... ...
有解决这个问题的惯用方法吗?
答案 0 :(得分:1)
有解决这个问题的惯用方法吗?
除了你已经找到的解决方案,没有。半保留关键字绝对不是lex / yacc语法的预期用例。
柠檬解析器生成器有一个为这样的情况设计的回退声明,但据我所知,这个有用的功能从未被添加到野牛。
您可以使用GLR语法来避免必须找出DECLARE @a bigint;
SELECT @a = MAX(ABC.milisecDateTimeBigInt)
FROM ABC
WHERE ABC.ID = 1;
SELECT
*
FROM
XYZ
WHERE
XYZ.milisecDateTimeBigInt = @a
的所有不同子集。但当然会有性能损失。
答案 1 :(得分:1)
你已经发现了在lex / yacc中处理这个问题最常用的方法,虽然不是很好,但也不错。通常,您调用的规则与标识符或(一组)关键字whateverName
匹配,并且您可能拥有多个关键字 - 因为不同的上下文可能具有不同的关键字集,它们可以作为名称接受。
如果你在易于识别的地方(例如在行的开头)只识别出这样的关键字,那么可能有用的另一种方法是使用lex启动状态,以便只返回一个KEYWORD标记,如果关键字在这种背景下。在任何其他上下文中,关键字将仅作为标识符标记返回。您甚至可以使用yacc操作为某些复杂的上下文设置词法分析器状态,但是您需要知道解析器可能执行的一个令牌词法分析器前瞻(规则可能直到在操作已经读取后的令牌之后才会运行)。
答案 2 :(得分:1)
在这种情况下,没有保留关键字。几种编程语言允许这样做:PL / I,FORTRAN。这不是词法分析器的问题,因为词法分析器应该始终知道哪些IDENTIFIER是关键字。这是解析器问题。它通常在语言规范中引起太多歧义,并且解析成为噩梦。语法将具有以下内容:
标识符:关键字|标识符;
关键字:可选| FIXED32 | FIXED64 | ...;
如果语法没有冲突,那么您就可以了。如果存在冲突,则需要功能更强大的解析器生成器,例如LR(k)或GLR。