在flex manual中,它提到了“尾随上下文”模式(r/s
),表示r
,但仅在其后跟随s
。但是,以下代码无法编译(相反,它会给出“无法识别的规则”错误。为什么?
LITERAL a/b
%%
{LITERAL} { }
最佳答案
简单的答案是,除非使用不建议使用的-l
选项,否则不能将尾随上下文放入名称定义中。那是因为flex:
不允许在括号内添加尾随上下文;和
除少数情况外(请参阅下文),自动用括号将定义的扩展括起来。
flex用括号括住扩展的原因是,否则会发生奇怪的事情。例如:
prefix milli|centi
%%
{prefix}pede return BUG;
如果没有自动括号,该模式将扩展为:
milli|centipede
与
millipede
不匹配。 (各种后缀运算符也存在类似的问题。例如,考虑{prefix}?pede
。)Flex不允许在括号内使用尾随上下文,因为许多这样的表达式更难编译。实际上,您可以结束编写两个正则表达式的交集的模式。 (例如,(
{base}/{a}){b}
匹配{base}
,后跟{b}
,它是{a}
的前缀或投影。)这些仍然是正则表达式,但Thomson算法并未考虑将它们用于将正则表达式转换为有限状态机由于该功能很少使用,因此从未尝试实现。不幸的是,在括号内禁止尾随上下文也禁止在包含尾随上下文的模式周围使用多余的括号,并且这包括定义扩展,因为定义使用可能的多余括号进行了扩展。
原始的AT&T词法未添加括号,这就是为什么强制与
-l
的词法兼容性允许编译flex文件的原因。但是,如上所述,它可能会导致各种各样的其他问题,所以我不建议这样做。另外,“跟踪上下文”在这里表示
r/s
形式或r$
形式的完整模式。将r/s
放在括号中(无论是显式还是隐式)都会产生错误消息,但是将r$
放在括号中只会使$
匹配$
字符,而不是强制模式在行末匹配。在这种情况下,不会发出错误或警告。这样就不可能在名称定义中使用
$
(或^
)。但是,在版本2.3.53之前的某个时刻,如果定义以^
开头或以$
结束,则插入了一个hack,该括号可以取消括号。而且,由于我不完全理解的原因,如果扩展出现在尾随上下文的末尾,它还会隐藏括号。这可能是一个错误,确实存在与此相关的错误报告。