Flex lexer 如何使用Flex在可读模式中使用尾随上下文?

Flex lexer 如何使用Flex在可读模式中使用尾随上下文?,flex-lexer,Flex Lexer,在Flex中,我可以在名称定义中使用尾随模式,如下所示: NAME foo$|bar NAME foo$|bar x{NAME} /* Some action */ 这就通过了flex 但是我不喜欢这样写没有空格的正则表达式,因为它们很难阅读。因此,我想适当地: NAME (?x: foo$ | bar ) 但是现在flex失败了,因为根据手册,“$”不能分组在括号内“” 恕我直言,这是愚蠢的,允许一些构造,但不允许可读地描述它 如何在Flex中使用可读模式的尾部上下

在Flex中,我可以在名称定义中使用尾随模式,如下所示:

NAME  foo$|bar
NAME  foo$|bar
x{NAME}        /* Some action */
这就通过了flex

但是我不喜欢这样写没有空格的正则表达式,因为它们很难阅读。因此,我想适当地:

NAME  (?x: foo$ | bar )
但是现在flex失败了,因为根据手册,
“$”不能分组在括号内“

恕我直言,这是愚蠢的,允许一些构造,但不允许可读地描述它


如何在Flex中使用可读模式的尾部上下文?

首先,回答您的问题:“如何在Flex中使用可读模式的尾部上下文?”。如果你坚持认为模式只有在有空格的情况下才可读,那么答案是“你不能”。对不起,事实就是这样。
(?x:
标志在某个时候被侵入flex,仍然有很多粗糙的边缘

在某种程度上,这并不重要,因为您不能在
r | s
正则表达式中使用$operator作为一个备选方案的一部分。因此,即使您可以使用“可读语法”,它也不是您想要的。您当然可以使用以下“可读语法”(至少,我认为它是可读的)。它的意思不同,但它是flex支持的
$
运算符的唯一用法:

NAME (?x: foo | bar )$
下面是一些注释


在Flex中,我可以在名称定义中使用尾随模式,如下所示:

NAME  foo$|bar
NAME  foo$|bar
x{NAME}        /* Some action */
不,你不能。或者,更好地说,你可以写,但它不涉及尾随上下文,因为:

…不出现在规则末尾的“$”将丢失其特殊属性,并被视为普通字符

(从;这是这一点的最后一个短语,表示不能将尾部上下文运算符放在括号内。)

flex确实会拒绝以下内容(也有点奇怪):

NAME  (?x: foo$ | bar )
尽管它将接受:

NAME  (?x: foo$| bar )
我会断章取义地说这是一个bug。只有在模式结束时,$才被识别为尾随上下文运算符。但是,检查该运算符的代码只是检查下一个字符是否为空格,因为模式终止于第一个空格字符。(该模式在定义中未被解析;它在实际包含在某些规则模式中时被解析。)测试不会检查$是否在
(?x:
块中,因此在

(?x: foo$ | bar )
$是一个尾随上下文运算符,这是一个语法错误(该运算符必须出现在模式的末尾),而在

(?x: foo$| bar )
$只是一个普通字符,它是合法的,但可能出乎意料


最后,需要注意的是:以下内容是完全合法的,$将被视为尾随上下文操作符,前提是在模式的末尾使用定义:

但是,它也可能不是您认为它的意思。尾随上下文运算符的优先级低于交替运算符,因此只要扩展位于模式的末尾,就可以像编写模式一样对其进行解析

NAME  (bar|foo)$
我强烈建议不要使用这样的定义。(事实上,我通常不鼓励使用定义,部分是因为所有这些怪癖。)将以$结尾的定义插入到引用模式中,而不被括号包围(这样就可以将$视为运算符)。这会导致各种意外行为。例如,如果您写:

NAME  bar|foo$
然后使用它:

x{NAME}y       /* Some action */
最终的结果就像你写的一样

xbar|foo"$"y   /* Some action */
xbar|foo$      /* Some action */
(没有括号,但$是常规字符。)

另一方面,如果您这样使用它:

NAME  foo$|bar
NAME  foo$|bar
x{NAME}        /* Some action */
那好像是你写的

xbar|foo"$"y   /* Some action */
xbar|foo$      /* Some action */
其中,$是尾随上下文运算符,但由于该运算符的优先级较低,它最终等效于

(xbar|foo)$    /* Some action */

这些扩展不太可能是您想要的,阅读您的代码的人更不可能期望得到这些结果。

谢谢,这是非常有用的信息。在我写了这个问题之后,我意识到您写的是,后面的上下文不能用在定义中,只能用在规则中。在阅读了您的答案和mo之后重新分析我的问题,我现在得出结论,我最好不要使用flex,而是编写自己的lexer,并通过标准接口将其连接到bison。@Mark:如果你坚持的话,可以在定义中使用尾随上下文。定义毕竟只是一个宏——flex应用的唯一一点智能是(通常)用括号括住展开式,正如答案所示,它经常会出错。因此,如果你想在定义中使用尾随上下文,你只需要在规则末尾使用定义,你应该自己插入括号:定义:
FOO_或_BAR_at_EOL(FOO|BAR)$
use:
/.{FOO_或_BAR_at_EOL}{puts(“注释以foo结尾”);}
将做它看起来会做的事情……但我不会这么做。我也不喜欢在C中使用宏,而且我只在有明显好处的情况下在Flex中使用定义。然而,每个定义都有自己的优点。尽管有一些缺点,但我个人认为Flex可以节省大量时间。祝你的项目好运。