接受一个正则表达式并生成一个NFA(Java)

3

我想编写一个程序,能够接受描述正则表达式的字符串。例如:

10(0U1)*

其中U是联合操作符,*是Kleene星号(我们也看到暗示的连接)。

我考虑将字符串的原子标记化并根据运算符和操作数构建机器。我想使用类似于以下规则的算法对每个原子进行操作:http://www.cs.may.ie/staff/jpower/Courses/Previous/parsing/node5.html

我不知道如何以智能方式最好地解析此类型的输入,以便可以编程构造NFA。

我的程序的目标是接受上述描述的输入,并输出由其5-touple描述的相应NFA。非常感谢任何达成该目标的建议。


如果你正在尝试实现一个NFA,它将如何运作?你会有大规模并行的硬件来运行它吗?还是你会先内部转换为DFA? - user684934
我已经很久没有学习计算理论了。:) 这些正则表达式中是否有“运算顺序”?如果有的话,我可能会从那里开始解析(例如,假设Union具有最高优先级...然后找到所有的Union,执行这些操作,进入下一个运算符等)。 - asteri
bdares:有一个几乎微不足道的算法可以模拟NFA(在《龙书》中的算法3.4,尽管大多数算法教材中都可以找到某些变体);它经常用于介绍双端队列的概念(因为它非常自然,尽管《龙书》算法只使用了两个栈)。在grep、egrep和fgrep都是单独的程序的早期,grep使用它(在通过Thompson构造生成NFA之后)。 - ebohlman
1个回答

2
如果您可以使用外部库,最好使用现代解析器生成器(例如ANTLR)来完成所有解析工作,并为您的正则表达式提供抽象语法树,即使它是一个相对简单的语言。
否则,如果您需要从头开始编写它,则需要首先确定是否需要令牌化器(或“词法分析器”)。如果您的语言由单个字符标记组成(如您的示例中),那么您可以安全地跳过编写令牌化器并只是在字符串中循环遍历字符。然后,您将不得不编写解析器,这是一个扫描标记列表并构建语法树的大循环。
无论如何,您应该最终得到像这样的语法树,针对您的示例10(0U1)*

syntax tree

注意,在语法树中,所有括号和隐含的优先规则都被省略了,它们被树结构所代替。
之后,你需要递归地将树翻译成 NFA 图。
以下是一种可能的实现方式的简要概述。
为每种语法节点类型编写一个翻译方法。该方法将带有其起始和结束的NFA状态作为参数,后者为可选项。该方法将绘制自己的图形片段,并根据需要调用其子元素的翻译方法,并返回其结束状态(该状态可能已被省略为参数,因此对其调用者未知)。
创建一个起始状态,并调用语法树根节点的翻译方法,将起始状态作为其起始状态传递给它。
字面量语法节点(例如你的示例中的0和1)将从其起始状态绘制箭头到其结束状态,如果未提供,则创建一个新的结束状态。
星号节点将调用其子节点的翻译方法,将其自己的起始状态作为子节点的起始状态和结束状态(以便NFA能够“循环”多次)。
连接节点将调用第一个子节点,将其起始状态但没有结束状态传递给它;然后调用第二个子节点,将第一个子节点的结束状态作为起始状态传递给它;以此类推,构建一个子图的单向序列,每个子图对应一个子节点。
您应该已经有了这个想法。
在将NFA图构建为状态的链接结构之后(也许可以将其显示为实际图形,以进行调试或文档目的),您可以将其转换为正式元组并输出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接