Regex 词法分析-从直接构造的DFA中提取标记

Regex 词法分析-从直接构造的DFA中提取标记,regex,compiler-construction,lexical-analysis,dfa,nfa,Regex,Compiler Construction,Lexical Analysis,Dfa,Nfa,我一直在读dragon的书,对将正则表达式直接转换为DFA(无显式NFA)的算法非常感兴趣。假设我的词法文件布局类似于lex: ... %% if { return IF_TOK; } else { return ELSE_TOK; } then { return THEN_TOK; } [a-zA-z][a-zA-Z0-9]* { return IDENT;

我一直在读dragon的书,对将正则表达式直接转换为DFA(无显式NFA)的算法非常感兴趣。假设我的词法文件布局类似于lex:

...
%%
if                       { return IF_TOK;   }
else                     { return ELSE_TOK; }
then                     { return THEN_TOK; }
[a-zA-z][a-zA-Z0-9]*     { return IDENT;    }
...more tokens
%%
...
我已经实现了这个算法,并且想知道如何从中提取令牌。我知道,当用汤普森的结构(龙书的变体)构造NFA,然后转换成DFA时,你可以从DFA所包含的NFA状态中获得标记,但我不确定在这种情况下。

a(f)lex description——事实上,任何词汇描述——都是正则表达式的集合。然而,所有实用算法都匹配一个正则表达式。这不是问题,因为我们可以简单地构造一个正则表达式,其中包含所有可能标记之间的交替。因此,您的示例中的前四个模式将组合为

(如果|那么|否则|[a-zA-z][a-zA-Z0-9]*)
Dragon book中给出的direct regex->DFA算法适用于扩展正则表达式,它是通过在regex的末尾添加一个输入端标记构建的。包含此增强标记位置的状态是接受状态

这对算法的描述很方便,但对构建实际的tokeniser没有太大帮助,因为tokeniser很少到达输入的末尾。它只会一直运行,直到无法再进行转换,此时它将备份到最后一个接受状态

regex->DFA算法中的状态对应于原始正则表达式中的位置集。(如果您已经编写了算法,您知道位置是什么,但为了让其他人阅读,位置粗略地说就是字符文本(或通配符)正则表达式中的偏移量)在正则表达式中,并不是所有的偏移量都是这个意义上的位置;例如,括号和运算符并不对应于任何匹配的字符。整个字符类文字都是一个位置。但通常更容易将位置想象成正则表达式中的字节偏移量就在它自己身上。)

这很有用,因为我们可以从正则表达式中扫描到达的状态的名称立即看到。由于组合正则表达式中的每个模式都有不同的位置范围,所以我们知道我们所处的规则。如果模式成功,则规则编号会告诉我们选择哪个操作。如果接受状态位于多个规则中,我们只选择位置最小的规则,因为这是(f)lex算法,用于在相同长度的两个最长匹配之间进行选择:选择扫描仪定义中的第一个

但是,正如我们前面提到的,唯一的接受状态是与扩展模式末尾的输入结束标记相对应的状态,而不是在任何原始模式中。因此,如果我们想要识别实际的模式,我们需要用它自己的结束标记来扩充每个规则,而不是让所有规则共享一个结束标记。此外,结束标记不能仅限于匹配输入末尾的(虚构的)角色,因为我们感兴趣的是最长的匹配前缀,而不是完全匹配。因此,我们必须考虑结束标记与任何单个字符匹配,包括输入字符的虚构结尾。(这使得它比
更为通配符,因为
只匹配真实字符,而不匹配输入字符的虚构结尾,而且也匹配真实字符(f)lex实现——只有恰好不是换行符的实字符。但原则上,它是一种通配符,只是它不吸收匹配的字符。)

因此,最终结果是我们将模式集合转换为:

(如果#|那么#|否则#|[a-zA-z][a-zA-Z0-9]*#)
其中,
#
是上述匹配结束通配符(或者更准确地说,总是成功的零长度断言)。然后,包含一个(或多个)通配符的每个状态都是接受状态。它所对应的位置是其名称中最小的位置,对应于一个
,应该采取的规则操作是其扩展模式包括
a(f)lex描述——实际上,任何词汇描述——是正则表达式的集合。然而,所有实用算法都匹配一个正则表达式。这不是问题,因为我们可以简单地构造一个正则表达式,其中包含所有可能标记之间的交替。因此,您的示例中的前四个模式将组合为

(如果|那么|否则|[a-zA-z][a-zA-Z0-9]*)
Dragon book中给出的direct regex->DFA算法适用于扩展正则表达式,它是通过在regex的末尾添加一个输入端标记构建的。包含此增强标记位置的状态是接受状态

这对算法的描述很方便,但对构建实际的tokeniser没有太大帮助,因为tokeniser很少到达输入的末尾。它只会一直运行,直到无法再进行转换,此时它将备份到最后一个接受状态

regex->DFA算法中的状态对应于原始正则表达式中的位置集。(如果您已经编写了算法,您知道位置是什么,但为了让其他人阅读,位置粗略地说就是字符文本(或通配符)正则表达式中的偏移量)正则表达式中并非所有的偏移量都是这个意义上的位置;括号和运算符并不对应于任何匹配的字符,例如