【发布时间】:2013-03-11 14:54:56
【问题描述】:
在flex manual 中,它提到了一个“尾随上下文”模式(r/s),这意味着r,但前提是后面跟着s。但是以下代码无法编译(而是给出“无法识别的规则”的错误。为什么?
LITERAL a/b
%%
{LITERAL} { }
【问题讨论】:
标签: parsing lex flex-lexer
在flex manual 中,它提到了一个“尾随上下文”模式(r/s),这意味着r,但前提是后面跟着s。但是以下代码无法编译(而是给出“无法识别的规则”的错误。为什么?
LITERAL a/b
%%
{LITERAL} { }
【问题讨论】:
标签: parsing lex flex-lexer
简单的答案是,除非您使用-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 lex 没有添加括号,这就是为什么强制 lex 与 -l 兼容允许您的 flex 文件编译。但是,如上所述,它可能会导致各种其他问题,因此我不推荐它。
此外,这里的“尾随上下文”是指r/s 或r$ 形式的完整模式。将r/s 放在括号内(无论是显式还是隐式)都会产生错误消息,但将r$ 放在括号内只会使$ 匹配$ 字符,而不是强制模式匹配在行尾.在这种情况下不会发出错误或警告。
这将导致无法在名称定义中使用$(或^)。但是,在版本 2.3.53 之前的某个时间点,如果定义以 ^ 开头或以 $ 结尾,则插入了一个 hack,它会抑制括号。而且,由于我不完全理解的原因,如果扩展发生在尾随上下文的末尾,它也会抑制括号。这可能是一个错误,并且确实有一个与之相关的错误报告。
【讨论】:
我在flex 的info 页面的常见问题解答中找到了您问题的答案:“您的问题是扫描仪中的某些定义使用了'/' 尾随上下文运算符,并将其包含在() 的。Flex 不允许将此运算符包含在 () 中,因为这样做允许未定义的正则表达式,例如 "(a/b)+"。因此解决方案是删除括号。请注意,您还必须构建扫描仪使用-l 选项以实现 AT&T lex 兼容性。没有此选项,flex 会自动将定义括在括号中。” (引自弗恩·帕克森)。另见FAQ trailing context
尽可能避免使用尾随上下文。如上所述,它不允许在嵌套表达式中使用。您的示例确实适用于 -l 选项。
【讨论】: