【问题标题】:How to use Finite Automaton to implement a scanner如何使用有限自动机实现扫描仪
【发布时间】:2017-10-18 09:58:33
【问题描述】:

我正在构建一个简单的扫描仪。假设我为我的语言定义了以下标记:

!, !=, !==, <, <<, {

现在我可以使用正则表达式指定它们,所以:

!=?=? | { | <<?

然后我使用http://hackingoff.com 构建 NFA 和 DFA。现在每台机器都可以确定输入是否为正则表达式语言。但我的程序是一系列令牌,而不是一个令牌:

!!=!<!==<<!{

我的问题是我应该如何使用机器将字符串解析为令牌?我对方法而不是实现感兴趣。

【问题讨论】:

  • 你到底在问什么?
  • @melpomene,我的问题是如何处理这些机器?如何解析多个token的实际字符串?
  • 您是要我们为您编写代码吗?
  • @melpomene,方法,我没有在任何地方提到代码
  • 如果你不是在谈论代码,那么我不知道你所说的“方法”是什么意思。

标签: compiler-construction lexical-analysis finite-automata


【解决方案1】:

最常见的规则是“maximal munch”,它总是选择尽可能长的标记。

一般来说,使用 DFA 扫描单个标记的算法如下:(为了对输入进行标记,重复此算法直到到达输入的结尾,每次扫描都从输入光标左侧的输入光标开始上一次扫描。)

将 DFA 状态设置为启动状态。然后,对于每个输入的字符顺序:

  • 如果 DFA 对角色进行了转换,则移动到 iindicated 状态。如果该状态是接受状态,则记录当前输入光标和状态编号。

  • 否则,将输入回退到最后记录的接受位置并返回记录的状态编号。

这里,接受状态编号用于指示遇到了哪个令牌。在实践中,将每个接受状态与令牌代码相关联是很常见的,因为某些令牌类型将具有多个接受状态。

并不总是需要使用上述回溯算法。在某些情况下,对 DFA 的分析将揭示最后的接受状态总是在紧接在前的输入位置。但是,许多语言需要回溯。

例如,.... 都是标记但不是 .. 的语言(例如 C)必须在输入 ..1 上回溯,应将其标记为 ..1 .在这个输入的标记化中,第一次扫描将接受第一个.,继续第二个.(不是接受状态),然后在输入1上找不到转换。然后它会报告它找到了一个.(记录的接受令牌)并将输入光标重置到第二个字符位置,以便下一次扫描将看到令牌.1

【讨论】:

  • 我实际上曾经看过一篇关于一种算法的论文,该算法可以在 O(n) 中进行基于正则表达式的最大-munch 标记化(即没有回溯)。它只是没有在实践中使用。
  • @sepp2k:如果你有参考,我很乐意看到。我不相信 O(N) 词法分析通常在恒定空间中是可能的,但我很高兴被证明是错误的。 (如果你放宽空间限制,那么它应该是可行的,但是这很不有趣。)在实际语言中,通过为诸如未终止的字符串和 cmets 之类的东西添加模式,通常可以将回溯限制为 O( 1) 字符,在这种情况下,标记化是 O(N)。所以使用更复杂算法的动机是有限的。
  • @rici,非常感谢。我发现了以下内容: dfa 应该一直运行,直到它到达当前状态 S 在下一个字符上没有传出转换的点。此时,实现必须决定它匹配了哪个正则表达式。如果 S 是接受状态,则 dfa 已在该语言中找到一个词,并应报告该词及其句法类别。
  • 否则,如果 dfa 在去往 S 的途中经过一个或多个接受状态,识别器应该备份到最近的这种状态。此策略匹配输入字符串中最长的有效前缀。如果它从未达到接受状态,则输入字符串的前缀不是有效单词,识别器应报告错误。
  • 这似乎正是您在回答中建议的内容,对吗?
猜你喜欢
  • 2010-09-11
  • 2015-11-23
  • 1970-01-01
  • 2016-06-20
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
  • 2020-09-05
相关资源
最近更新 更多