【问题标题】:how to use trailing context in readable patterns with Flex?如何在 Flex 的可读模式中使用尾随上下文?
【发布时间】:2016-09-30 20:34:30
【问题描述】:

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

NAME  foo$|bar

这通过了 flex。

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

NAME  (?x: foo$ | bar )

但现在这失败了,因为根据手册,"‘$’, cannot be grouped inside parentheses"

恕我直言,这很愚蠢,允许一些构造,但不允许以可读的方式描述它。

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

【问题讨论】:

    标签: flex-lexer


    【解决方案1】:

    首先,回答您的问题:“如何在 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 */
    

    这些扩展中的任何一个都不太可能是您想要的,阅读您的代码的任何人都不太可能期待这些结果。

    【讨论】:

    • 谢谢,这是非常有用的信息。在我写完这个问题之后,我意识到自己写了什么,尾随上下文不能用于定义,只能用于规则。在阅读了您的回答并对我的问题进行了更多分析之后,我现在得出的结论是,我最好不要使用 flex 而是编写自己的词法分析器,并通过标准接口将其连接到野牛。
    • @Mark:如果您坚持,您可以在定义中使用尾随上下文。毕竟,定义只是一个宏——唯一适用的智能 flex 是(通常)用括号包围扩展,正如答案所示,它经常出错。因此,如果您想在定义中使用尾随上下文,您只需要在规则末尾使用定义,并且您应该自己插入括号:定义:FOO_OR_BAR_AT_EOL (foo|bar)$ 使用://.*{FOO_OR_BAR_AT_EOL} {puts("comment ends with foo");} 几乎可以实现它的外观就像它会做的那样......
    • ...但我不会那样做。我也不喜欢在 C 中使用宏,而且我只在有明显好处时才在 Flex 中使用定义。然而,对于每个人来说。尽管有一些粗糙的边缘,我个人认为 flex 是一个巨大的节省时间。 YMMV。祝你的项目好运。
    猜你喜欢
    • 2013-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多