我在大学有一个实验室。但我不明白我是怎么做到的。 我有一些语言的语法(例如,算术表达式语法)。我必须构建这种语法的树(我不知道如何)。然后我必须确定,输入句子是否是这种语言的句子?我该怎么做? 附:我读过龙书的几个章节,但我找不到任何我需要的东西。 P.P.S.我不能使用lex / flex和yacc / bison。
编辑抱歉!我更加专注。真的我有一个语法,我必须使用这个语法和输入句子(我明白该怎么做)构建树,如果可能的话(在另一种情况下我必须显示关于它的消息)。有没有简单的理解它的算法?我可以使用任何简单语言的语法,如算术表达式。
答案 0 :(得分:3)
我认为这是理论上的,因为它是家庭作业,而不是你现在需要编码的东西。 (肯德里克的答案涵盖了代码方法)
基本思路是从你的BNF开始变量开始,尝试弄清楚如何扩展它,一次应用一个规则,看看你是否可以提出你的输入序列。
对于如下规则集:
(1) start: expression
(2) expression: expression '+' term
(3) | expression '-' term
(4) | term
(5) term: 'a'
(6) | 'b'
鉴于表达式a + b - a
,您可能会这样:
一个。 start
(给定)
湾expression
(1)
C。 expression '-' term
(3)
d。 expression '-' 'a'
(5)
即expression '+' term '-' 'a'
(2)
F。 term '+' term '-' 'a'
(4)
G。 'a' '+' term '-' 'a'
(5)
H。 'a' '+' 'b' '-' 'a'
(6)
这就是你如何一步一步地做到这一点......现在的诀窍是,你需要追踪你所有的规则调用。所以你真正的树看起来像这样:
start
| (b)
expression
/ | \ (c)
expression '-' term
/ | \ (e) | (d)
expression '+' term 'a'
| (f) | (h)
term 'b'
| (g)
'a'
一开始有点复杂,但是一旦你真正看到它是如何完成的,它就不会太难接受。
注意:有些人发现向后工作更容易,从输入开始,然后反向应用规则以尝试查找起始表达式。当你编写解析器时,你将不可避免地需要在某种程度上遵循这条路线。
编辑:我使用上面的小写字母列出了所有表达式步骤,然后显示树中的每组分支实际上与其中一个规则应用程序对应。可能会或可能没有帮助。
答案 1 :(得分:2)
我已经做了很长时间了,所以我会给你简短的理论答案。我相信其他人会有更深入的解释。
由于你还没有说你做了什么(并且你将来作为问题的一部分),第一步是标记输入。
获得令牌后,您可以构建一个状态机来移动令牌并将其推入所需的树结构中。这应该在你的书中介绍(我还没有读过),但你可能想从纸上(或电子版)建立模型开始,并考虑每一步的有效输入。什么是相等声明的有效左手值?如果树上有令牌x,你可以从哪里出发?
如果您无法从当前状态确定下一步,那么您可能需要在状态机中实现预测(是否需要这取决于您的语言的复杂程度)。
同样,我在十多年内没有这样做,所以我的回忆是模糊的。希望我已经为你提供了足够的框架来改进你的答案,或者让那些对这个主题更有了解的人给我带来错误或过时的问题(从而得到你正在寻找的答案作为一个群体)。
答案 2 :(得分:1)
我想回答这个问题,但是没有足够的材料可以使用 - 我留下了这些问题:
编辑:考虑评论和更新的问题:我认为最直接的方法是递归下降解析器,它在输入匹配时构建树。寻找Niklaus Wirth的“编译器构建”一书,该书已在网上以PDF格式提供,并描述了一种简单语言的RDP。
递归下降解析器的基本思想是语法中的每个规则都对应一个函数,每个函数检查下一个令牌并调用相应的next-lower解析函数。例如,如果您的语法有规则
expression : constant '+' constant
相关的解析方法如下所示:
void parseExpression() {
parseConstant();
Token token = peek_at_next_token();
if (token == '+') {
parseConstant();
... tree building code here ...
}
else
throw ParseException("Expected '+', found "+token);
}
但请参阅此问题的其他答案。