首先,回答您的问题:“如何在 Flex 中使用带有可读模式的尾随上下文?”。如果你坚持模式只有在被空格覆盖的情况下才可读,那么答案是“你不能。”抱歉,事实就是这样。 (?x: 标志在某些时候被黑进了 flex 中,仍然有很多粗糙的边缘。
在某种程度上,这并不重要,因为您不能将 $ 运算符用作r|s 正则表达式中的一个替代选项的一部分。因此,即使您可以使用“可读语法”,它也不意味着您想要的。您当然可以使用以下“可读语法”(至少,我认为它是可读的)。这意味着不同的东西,但它是 flex 支持的 $ 运算符的唯一用途:
NAME (?x: foo | bar )$
以下是一些注意事项。
在 Flex 中,我可以在名称定义中使用尾随模式,如下所示:
NAME foo$|bar
不,你不能。或者,更好的说法是,你可以这样写,但它不涉及尾随上下文,因为:
…没有出现在规则末尾的“$”将失去其特殊属性并被视为普通字符。
(来自Flex manual;这是该点的最后一个短语,它表示您不能将尾随上下文运算符放在括号内。)
flex 会拒绝是真的(并且有点好奇):
NAME (?x: foo$ | bar )
虽然它会接受:
NAME (?x: foo$| bar )
我会说这是一个错误。 $ 仅当它位于模式的末尾时才被识别为尾随上下文运算符。但是,检查代码只是检查下一个字符是否为空格,因为模式在第一个空格字符处终止。 (该模式在定义中没有被解析;当它实际包含在某个规则模式中时会被解析。)测试不检查 $ 是否在 (?x: 块内,所以在
(?x: foo$ | bar )
$ 是尾随上下文运算符,这是一个语法错误(运算符必须出现在模式的最末尾),而在
(?x: foo$| bar )
$ 只是一个普通字符,它是合法的,但可能是意想不到的。
最后,一点注意事项:以下是完全合法的,$ 将被视为尾随上下文运算符,前提是在模式的最末尾使用该定义:
NAME bar|foo$
但是,它可能也不是您认为的意思。尾随上下文运算符的优先级低于交替运算符,因此只要扩展位于模式的末尾,就会被解析为就像它被写入一样
NAME (bar|foo)$
我强烈建议不要使用这样的定义。 (事实上,我通常不鼓励使用定义,部分原因是所有这些怪癖。)以 $ 结尾的定义被插入到引用模式中,而不用括号括起来(这样 $ 可以被视为运算符)。这会导致各种意想不到的行为。例如,如果你写:
NAME bar|foo$
然后使用它:
x{NAME}y /* Some action */
最终结果就像你写的一样
xbar|foo"$"y /* Some action */
(没有括号,但 $ 是常规字符。)
另一方面,如果你这样使用它:
x{NAME} /* Some action */
就好像你写的一样
xbar|foo$ /* Some action */
其中 $ 是尾随上下文运算符,但由于该运算符的优先级较低,它最终等同于
(xbar|foo)$ /* Some action */
这些扩展中的任何一个都不太可能是您想要的,阅读您的代码的任何人都不太可能期待这些结果。