Parsing 带DFS的AST的退出条件

Parsing 带DFS的AST的退出条件,parsing,recursion,abstract-syntax-tree,Parsing,Recursion,Abstract Syntax Tree,我正在尝试用DFS方法编写一个通用AST构建器 语法的原理相当简单:表达式可以有一个或多个选项,每个选项由节点列表组成,其中每个节点可以是终端或表达式 我有一个很好的状态,但我正在努力寻找“无止境循环”的退出条件 如果我这样定义语法: expr := addExpr; addExpr := NUMBER | NUMBER OPERATOR expr ; expr := addExpr; addExpr := NUMBER | expr

我正在尝试用DFS方法编写一个通用AST构建器

语法的原理相当简单:表达式可以有一个或多个选项,每个选项由节点列表组成,其中每个节点可以是终端或表达式

我有一个很好的状态,但我正在努力寻找“无止境循环”的退出条件

如果我这样定义语法:

expr := addExpr;

addExpr := NUMBER
         | NUMBER OPERATOR expr
         ;
expr := addExpr;

addExpr := NUMBER
         | expr OPERATOR NUMBER
         ;
expr (against 4 - 2 + 2)
  addExpr (against 4 - 2 + 2)
    0: NUMBER -> matches 4, won't finish.
    1: expr OPERATOR NUMBER
      expr (against 4 - 2 + 2) -> I cannot break yet.
        addExpr (against 4 - 2 + 2) -> I cannot break yet.
          0: NUMBER -> matches 4, won't finish.
          1: expr OPERATOR NUMBER
            expr (against 4 - 2 + 2) -> I cannot break yet.
              addExpr (against 4 - 2 + 2) -> I cannot break yet.
                0: NUMBER -> matches 4, will resolve in the end.
                1: expr OPERATOR NUMBER
                  expr (against 4 - 2 + 2) -> BREAK!
它通过了。该结构在语义上是正确的,但在遍历时会产生错误的结果。“4-2+2”将被评估为“4-(2+2)”,而不是所需的“(4-2)+2”

我需要这样定义语法:

expr := addExpr;

addExpr := NUMBER
         | NUMBER OPERATOR expr
         ;
expr := addExpr;

addExpr := NUMBER
         | expr OPERATOR NUMBER
         ;
expr (against 4 - 2 + 2)
  addExpr (against 4 - 2 + 2)
    0: NUMBER -> matches 4, won't finish.
    1: expr OPERATOR NUMBER
      expr (against 4 - 2 + 2) -> I cannot break yet.
        addExpr (against 4 - 2 + 2) -> I cannot break yet.
          0: NUMBER -> matches 4, won't finish.
          1: expr OPERATOR NUMBER
            expr (against 4 - 2 + 2) -> I cannot break yet.
              addExpr (against 4 - 2 + 2) -> I cannot break yet.
                0: NUMBER -> matches 4, will resolve in the end.
                1: expr OPERATOR NUMBER
                  expr (against 4 - 2 + 2) -> BREAK!
这里的问题是,它会导致无休止的迭代:

expr -> addExpr -> expr -> addExpr -> ...
这就是我被困的地方。我想不出何时停止尝试的退出条件。我想有一段历史,如果我把同一个表达式与剩余的标记进行比较,我可以停止。但这一切来得太早,不会产生任何结果

我想我需要的堆栈应该是这样的:

expr := addExpr;

addExpr := NUMBER
         | NUMBER OPERATOR expr
         ;
expr := addExpr;

addExpr := NUMBER
         | expr OPERATOR NUMBER
         ;
expr (against 4 - 2 + 2)
  addExpr (against 4 - 2 + 2)
    0: NUMBER -> matches 4, won't finish.
    1: expr OPERATOR NUMBER
      expr (against 4 - 2 + 2) -> I cannot break yet.
        addExpr (against 4 - 2 + 2) -> I cannot break yet.
          0: NUMBER -> matches 4, won't finish.
          1: expr OPERATOR NUMBER
            expr (against 4 - 2 + 2) -> I cannot break yet.
              addExpr (against 4 - 2 + 2) -> I cannot break yet.
                0: NUMBER -> matches 4, will resolve in the end.
                1: expr OPERATOR NUMBER
                  expr (against 4 - 2 + 2) -> BREAK!
什么时候分手似乎有点武断。是否有一些好的规则或条件来实现这一点


如果可以避免的话,我真的不想只设置一个“随机”最大深度。也许我应该考虑一个BFS方法(完全不同的一组问题),但是如果可能的话,我想坚持DFS。

这里的关键是迭代而不是递归。请参阅我关于如何编写递归下降解析器的答案:或者,自下而上构建树(即,执行后序遍历而不是前序遍历)。感谢@IraBaxter给出您的答案。我知道你发布的链接。我的问题是,我对为特定语法编写解析器不感兴趣。我想构建一个通用语法解析器——类似于ANTLR。但也许这就是答案?我不能只编写DSF搜索,但需要找到一种生成AST构建器函数的方法?有趣的@rici。我还不确定如何将postorder应用到我的算法中,我一定会尝试一下。然后你应该仔细看看MetaII,它可以根据语法生成递归下降解析器。你可以在几个令人兴奋的晚上实现这一点。看见MetaII的扩展名为“Tree Meta”(谷歌),它可以让你通过集成的树构建来构建语法,然后让你遍历这些树并发出代码。这里的关键是迭代而不是递归。请参阅我关于如何编写递归下降解析器的答案:或者,自下而上构建树(即,执行后序遍历而不是前序遍历)。感谢@IraBaxter给出您的答案。我知道你发布的链接。我的问题是,我对为特定语法编写解析器不感兴趣。我想构建一个通用语法解析器——类似于ANTLR。但也许这就是答案?我不能只编写DSF搜索,但需要找到一种生成AST构建器函数的方法?有趣的@rici。我还不确定如何将postorder应用到我的算法中,我一定会尝试一下。然后你应该仔细看看MetaII,它可以根据语法生成递归下降解析器。你可以在几个令人兴奋的晚上实现这一点。看见MetaII的扩展名为“Tree Meta”(google),它可以让你通过集成的树构建来构建语法,然后让你遍历这些树并发出代码。