我目前的代码(用非常简单的Ruby编写,包括词法分析器和解析器)可以在github上找到:https://gist.github.com/e9d4081b7d3409e30a57
有人可以解释我如何从目前的AST到AST吗?
或者,如果您不熟悉Ruby,但知道C,您能否告诉我如何在recursive descent parsing维基百科文章中为C代码构建AST.
请注意,我不想使用像yacc或antlr这样的解析器生成器来为我工作,我想从头开始做所有事情.
谢谢!
解决方法
a(b())
你的终端代币在这里是这样的:
> L_PAREN ='(”
> R_PAREN =’)’
> IDENTIFIER = [a-z]
你的非终结符号是这样的:
> FUNCTION_CALL = IDENTIFIER,L_PAREN,R_PAREN
>或;
> FUNCTION_CALL = IDENTIFIER,FUNCTION_CALL,R_PAREN
显然,规则FUNCTION_CALL的第二个替代方案是递归的.
您已经有一个解析器知道它找到了一个有效的符号.您缺少的一点是将回调附加到规则,该规则接收其组件作为输入并返回表示AST中该节点的值(通常).
想象一下,如果我们上面的FUNCTION_CALL规则的第一个替代方案有回调:
Proc.new do |id_tok,l_paren_tok,r_paren_tok| { item: :function_call,name: id_tok,args: [] } end
这意味着匹配产生的AST:
a()
将会:
{ item: :function_call,name: "a",args: [] }
现在将其推断为更复杂的a(b()).因为解析器是递归的,所以它首先会识别b(),回调从中返回我们上面的内容,但是使用“b”代替“a”.
现在让我们定义附加到与第二个备选方案匹配的规则的回调.它非常相似,除了它还处理它传递的参数:
Proc.new do |id_tok,func_call_item,args: [ func_call_item ] } end
因为解析器已经识别出b()并且从回调中返回了AST的那部分,所以生成的树现在是:
{ item: :function_call,args: [ { item: :function_call,name: "b",args: [] } ] }
希望这会给你一些思考的食物.将您匹配的所有标记传递给构建AST非常小部分的例程.