我想了解有关实现词法分析器的一些内容,我不想使用扫描仪生成器。从我所读到的是,我用不同的令牌的正则表达式识别语言的规范。然后我应该做一个大的正则表达式ORing所有令牌的表达式,对吧?!然后创建NFA,然后创建这个正则表达式的DFA,对吧?!如果是这样,当一个单词与最终DFA匹配时,我怎么知道这个单词代表哪个标记?!
答案 0 :(得分:3)
您在这里描述的是手动实现生成的扫描仪。那不是你怎么做的。只需编写一个包含大型switch语句的循环,其大小写是每个标记类型的首字母,每个case都是一个循环来使用其余的标记并返回其类型。除了没有返回之外,空白情况是相同的。标识符的大小写也需要查找关键字表。
答案 1 :(得分:2)
手动编写有限状态机(FSM)词法分析器,循环输入中的字符并使用两级switch语句处理它:
这是处理令牌的有限状态机的实现。这样做的缺点是维护起来会很复杂,特别是如果有许多状态要处理每个令牌。好处是重构更容易利用有限状态机(例如使用转换表而不是switch语句)。
转换表类似于switch语句:行定义状态,列定义数据值,单元定义要转换到的下一个状态(用-1
来表示停止处理)。使用此方法,可以使用结束状态来确定令牌类型。在这里,您将拥有一个token_type tokens[N_STATES];
数组,然后您可以token = tokens[current_state]
来获取令牌。
另一种方法是打开第一个字符,然后读取该标记中的其余字符作为该case语句的一部分。这可以更容易阅读,更易于编写。
您还可以将字符拆分为不同的类(例如数字,字母,减号和小于),您可以将其定义为256项查找表。这可以简化案例陈述。
正如您所指出的那样,使用大正则表达式是有问题的,因为您无法获得令牌类型。这里的方法是获得与令牌匹配的正则表达式列表,并将其与令牌类型相关联。例如,在python中:
_tokens = [
(re.compile('\\s+'), WhiteSpace),
(re.compile('[a-zA-Z_][a-zA-Z0-9_]*'), Identifier),
(re.compile('[0-9]+'), Integer),
]
您需要正确订购(例如,在标识符之前放置关键字匹配)。