如何使用有限自动机实现扫描仪

How to use Finite Automaton to implement a scanner

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

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

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

!=?=? | { | <<?

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

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

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

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

一般来说,使用 DFA 扫描单个标记的算法如下:(要标记输入,重复此算法直到到达输入末尾,每次扫描从输入光标左侧开始通过之前的扫描。)

将DFA状态设置为开始状态。然后,对于序列中的每个输入字符:

  • 如果 DFA 对角色有转换,则移动到 iindicated 状态。如果那个状态是接受状态,记录当前输入光标和状态号。

  • 否则,将输入倒回到最后记录的接受位置和return记录的状态编号。

此处,接受状态编号用于指示遇到了哪个令牌。在实践中,通常将每个接受状态与令牌代码相关联,因为某些令牌类型将具有不止一种接受状态。

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

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