Flex在特定规则中永远备份

时间:2014-10-17 10:23:49

标签: bison flex-lexer

我的解析器是汇编程序,这里是lexbison文件以防万一

在这个例子中,所有的作品都像魅力一样:

nop
nop
nop

这是调试输出

--accepting rule at line 154 ("nop")
--accepting rule at line 248 ("
")
--accepting rule at line 154 ("nop")
--accepting rule at line 248 ("
")
--accepting rule at line 154 ("nop")
--accepting rule at line 248 ("
")
--(end of buffer or a NUL)
--accepting rule at line 248 ("
")
--(end of buffer or a NUL)
--EOF (start condition 0)

当我尝试解析此代码时,问题出现了(规则在lex文件中的第255行)

DEFB    '?'+$80
DEFM    "RN"
DEFB    'D'+$80

它永远备份,看起来无法到达换行符(我有规则)。 我从flex生成backup file,但无法理解如何使用它来查找根本原因。

--accepting rule at line 255 ("DEFB")
--accepting rule at line 280 (" ")
--accepting rule at line 280 (" ")
--accepting rule at line 280 (" ")
--accepting rule at line 280 (" ")
--(end of buffer or a NUL)
--scanner backing up
--accepting rule at line 105 ("'?'")
--accepting rule at line 233 ("+")
--accepting rule at line 56 ("$80")

1 个答案:

答案 0 :(得分:2)

备份问题与您的char模式有关:

ascii             [\x00-\x7F]+
char              '{ascii}{1}'

ascii可以是任意数量的“ascii”字符;该集包括换行符和撇号。由于flex模式总是贪婪,char将匹配从第一个'到最后一个',因此匹配的标记将是:

        '?'+$80
DEFM    "RN"
DEFB    'D'

然后匹配剩余的标记 + $ 80

模式存在类似的问题

\"{ascii}*\"        { SAVE_CTX; return STRING;}

我想知道您使用{ascii}{1}是否因为您认为{1}会以某种方式覆盖+扩展中的{ascii}。 (它不会。)否则,我发现在你的弹性模式的不同位置使用冗余的{1}运算符是神秘的。对我来说,它们只是视觉噪音,这使得理解模式更难,因为{1}只是一个身份运算符。

无论您希望char匹配一个还是任意数量的“ascii”字符,您肯定希望它在您点击'时停止匹配,类似于字符串模式。您可能还希望能够使用转义序列,尤其是(例如)'\''"Two lines\nwith \"quoted\" string"

(另外,你真的想在字符串中允许包含NUL的任意控制字​​符吗?如果是这样,为什么要随意排除代码值大于127的字符?)

识别所有可能的转义序列是有效的,我不知道你想要处理哪个序列,但基本上你需要的模式如下:

["]([\x00-\x7F]{-}["\\\n]|\\(.|\n))*["]

和(猜测你的意图):

[']([\x00-\x7F]{-}['\\\n]|\\([[:print:]]|[0-7]{1,3}|x[[:xdigit]]{2})[']

尽管如上所述,我不愿意赞同[\x00-\x7F],我仅将其用于说明目的,特别是用于说明特定于幻灯片的{-}运算符。


与问题无关的一些最终说明:

  1. 通常最好在源文件中包含最小可编辑摘录。由于SO旨在成为问题和答案的永久存储库,这可能使其他具有类似问题的程序员受益,可能在未来几年内,可能会过期的pastebin资源的链接也没有多大帮助。

  2. 自由地使用SAVE_CTX意味着您将在许多字符串(例如操作码)上不必要地调用strdup(),然后您需要free()。我没有查看你的野牛文件,因为它与问题无关,但总的来说,我试图避免将复制的字符串传递给具有已知(或规范)表示的令牌的bison,部分是因为所有字符串副本的开销,部分是因为必须释放所有的字符串会给每个野牛行为带来不必要的复杂性。 YMMV

  3. 通常不需要定义除标准之外的文件结束标记,这可能会导致模糊的错误。通常最好让扫描器实现其默认的<<EOF>>规则,该规则将被bison生成的解析器识别为文件结束信号,结果是解析器将知道它不应该尝试读取更多令牌。

  4. 虽然flex允许您使用特殊操作标记 | 将多个模式合并为一个操作,但模式仍然是独立的。通常应首选使用正则表达式交替运算符(也写为 | ),因为它会生成具有较小表的扫描程序。所以而不是:

    "xxx"          |
    ".xxx"         { /* some action */ }
    

    你应该更喜欢

    "xxx"|".xxx"   { /* some action */ }
    

    甚至

    [.]?"xxx"      { /* some action */ }
    

    当模式是单个字符并且动作是返回字符时尤其如此;我总是建议使用单一默认规则:

    .              { return yytext[0]; }
    

    语法结束时。这意味着“无效”字符将作为未知令牌代码传递给解析器,然后解析器将以错误拒绝;允许错误处理集中在解析器中,而不是在解析器和扫描程序之间传播。当将新操作符添加到解析器时,它具有使扫描器和解析器保持同步的额外优点; flex文件不需要修改。