【发布时间】:2014-07-21 12:55:42
【问题描述】:
我有兴趣学习如何编写像 flex 这样的词法分析器生成器。我一直在阅读“编译器:原理、技术和工具”(“龙书”),并且对 flex 的工作原理有了基本的了解。
我最初的方法是:用户将提供正则表达式的哈希映射,将正则表达式映射到令牌枚举。该程序将按照给定的顺序一个接一个地循环遍历正则表达式,并查看它们是否与字符串的开头匹配(我可以在每个正则表达式的开头添加一个^ 来实现这一点)。如果他们这样做了,我可以将该正则表达式的标记添加到程序的标记列表中。
我的第一个问题是,这是最有效的方法吗?目前我必须遍历每个正则表达式,但理论上我可以从所有组合的正则表达式构建一个 DFA,并更有效地逐步完成。但是,创建此 DFA 会产生一些开销。
我的第二个问题是,我将如何像 flex 那样实现最长匹配的字符串 tie break?即,我想匹配 ifa 作为标识符,而不是关键字 if 后跟字母 a。我没有看到任何有效的方法来使用正则表达式来做到这一点。我想我必须遍历所有正则表达式,尝试匹配它们,如果我有多个匹配项,则取最长的结果。但是,如果我将正则表达式转换为 DFA(即我自己的 DFA 数据结构),那么我可以继续遍历字符,直到 DFA 上不再有可能的过渡边缘。那时,我可以将我最后一次通过接受状态作为令牌的实际匹配,因为那应该是最长的匹配。
我的两个问题都指向我自己编写从正则表达式到 DFA 的翻译器。这是必需的,还是我仍然可以使用普通的正则表达式(由标准库实现)有效地做到这一点并且仍然获得最长的匹配?
编辑:我保留了我正在使用的正则表达式引擎,因为我想要一个通用的答案,但我使用的是 Rust 的正则表达式库:http://static.rust-lang.org/doc/master/regex/index.html
【问题讨论】:
-
您使用的是哪个正则表达式引擎? POSIX 引擎遵循最左最长规则,类似 Perl 的引擎通常使用最左优先匹配(因此您可以通过在正则表达式中将较长的子匹配放在首位来确保它是最长的)。
标签: regex language-agnostic programming-languages lexical-analysis dfa