Parsing LL(1)使用堆栈实现的解析器:如何构建AST?
我目前正在手工构建一个解析器。它是一个LL(1)解析器。目前,它是一个很好的识别器:它的函数parse(List tokens)决定了tokens是否是该语言的成员 现在,我想为该输入构建相应的AST。然而,我知道如何以递归下降的方式实现它(已经做到了)。也就是说,对于挑战,我使用带有经典算法的堆栈实现我的堆栈:Parsing LL(1)使用堆栈实现的解析器:如何构建AST?,parsing,implementation,context-free-grammar,ll,Parsing,Implementation,Context Free Grammar,Ll,我目前正在手工构建一个解析器。它是一个LL(1)解析器。目前,它是一个很好的识别器:它的函数parse(List tokens)决定了tokens是否是该语言的成员 现在,我想为该输入构建相应的AST。然而,我知道如何以递归下降的方式实现它(已经做到了)。也就是说,对于挑战,我使用带有经典算法的堆栈实现我的堆栈: next <- first token of the input stack <- START_SYMBOL do { top <- stack.pop()
next <- first token of the input
stack <- START_SYMBOL
do {
top <- stack.pop()
if (top is a terminal and top == next) {
next <- next token of the input
} else if (top is a non terminal and PARSING_TABLE[top, next] exists) {
stack.push(PARSING_TABLE[top, next]);
} else {
return invalid input;
}
} while (stack is not empty);
return valid input;
next可以对堆栈进行注释,使其包含AST条目引用(即规则编号+规则中的位置+要存储的目标数据)+(终端/非终端)
您的初始堆栈之所以会出现困难,是因为用匹配规则的rhs替换堆栈上的非终结符的常用方法实际上会在预测时忘记语法结构。但要生成AST,您需要在稍后规则解析完成时使用该结构
与其用匹配规则的rhs符号替换非终结符,不如将其保留在原位,并将匹配的符号作为列表对象推送。这样,堆栈就保留了语法的层次结构
解析使用最顶端列表中的符号。列表的耗尽对应于规则的完成。非终结符在其规则完成时从堆栈中移除,而不是在预测它时
在使用堆栈时,构建一个必然的AST结构,该结构记住相关规则并存储解析的令牌。因此,堆栈的行为类似于流入已解析AST的预测AST
您可以将其视为模拟递归下降解析器的调用层次结构,将符号列表堆栈作为调用帧堆栈
在ruby中:
# g is the grammar; a list of rules
# s is a terminal sequence to parse
# note, this code does not tokenize EOF
def parse(g, s)
tab = gen_table(g)
stack = [[g.start_sym]]
# intermediate ast node format: [rule-action, symbols...]
ast = [[->(rhs){[:_S, rhs[0]]}]]
loop do
puts "PARSE\n #{s}\n #{stack}\n #{ast}"
if stack.first.empty?
raise "extraneous input" if not s.empty?
break
end
if stack.last.empty? # rule complete
stack.pop
node = ast.pop
# transform the node (eg to a class) using the associated rule-action
node = node.first.(node.drop(1))
ast.last.push(node)
stack.last.shift # rm sym from stack after completing it
next
end
raise "incomplete input" if s.empty?
tok = s.first
topsym = stack.last.first
if topsym.is_a? String # terminal
raise "mismatch #{tok} != #{topsym}" if tok != topsym
stack.last.shift
ast.last.push(s.shift)
elsif topsym.is_a? Symbol # nonterminal
ri = tab[topsym][tok]
raise "no rule for #{topsym}, #{tok}" if ri.nil?
stack.push(g[ri].rhs.clone)
ast.push([g[ri].action])
end
end
node = ast.first
node.first.(node.drop(1))
end
你知道一些简单的案例在网络上的实现吗?。我有同样的问题,但我不明白你的意思。如果你能详细说明答案,那对我会有帮助的。我刚刚搜索了将近半个小时。。。没有发现任何与AST建筑有关的内容,因此基本上没有:(以下内容:单独演示LL(1)非常好,但我找不到任何与AST有关的内容。