我想了解一些有关实现词法分析器的知识,并且我不想使用扫描仪生成器。据我了解,我用正则表达式标识了语言的规范,每个正则表达式用于不同的标记。然后,我应该做一个大的正则表达式或所有令牌的表达式进行运算,对吗?然后创建NFA,然后创建这个大正则表达式的DFA,对吗?如果是这样,那么当一个单词与最终DFA相匹配时,我如何知道该单词代表哪个标记?
最佳答案
基于FSM的Lexer
用手编写一个有限状态机(FSM)词法分析器,您可以遍历输入中的字符并使用两层switch语句处理该字符:
外部switch语句正在接通状态;
内部switch语句将打开已读取的字符。
这是用于处理令牌的有限状态机的实现。不利的是,它的维护可能会变得很复杂,尤其是在有很多状态要处理每个令牌的情况下。好处是可以更容易地重构以利用有限状态机(例如,使用过渡表而不是switch语句)。
转换表就像switch语句:行定义状态,列定义数据值,单元格定义要转换到的下一个状态(例如-1
表示停止处理)。通过这种方法,可以使用结束状态来确定令牌类型。在这里,您将有一个token_type tokens[N_STATES];
数组,然后可以执行token = tokens[current_state]
来获取令牌。
非FSM词法分析器
另一种方法是打开第一个字符,然后作为该case语句的一部分读取该令牌中的其余字符。这可以更容易阅读和编写。
您还可以将字符分为不同的类(例如,数字,字母,减号和小于号),它们可以定义为256个项目的查找表。这样可以简化案例陈述。
常用表达
正如您指出的那样,使用大的正则表达式是有问题的,因为您无法获取令牌类型。这里的一种方法是拥有一个与令牌匹配并将其与令牌类型相关联的正则表达式列表。例如,在python中:
_tokens = [
(re.compile('\\s+'), WhiteSpace),
(re.compile('[a-zA-Z_][a-zA-Z0-9_]*'), Identifier),
(re.compile('[0-9]+'), Integer),
]
您将需要正确订购这些商品(例如,将关键字匹配放在标识符之前)。