Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing LL(1)使用堆栈实现的解析器:如何构建AST?_Parsing_Implementation_Context Free Grammar_Ll - Fatal编程技术网

Parsing LL(1)使用堆栈实现的解析器:如何构建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()

我目前正在手工构建一个解析器。它是一个LL(1)解析器。目前,它是一个很好的识别器:它的函数parse(List tokens)决定了tokens是否是该语言的成员

现在,我想为该输入构建相应的AST。然而,我知道如何以递归下降的方式实现它(已经做到了)。也就是说,对于挑战,我使用带有经典算法的堆栈实现我的堆栈:

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有关的内容。