在Java中解析算术表达式并从中构建树

Cho*_*ear 38 java tree parsing

给定一个算术表达式,我需要一些创建自定义树的帮助.比如说,您输入此算术表达式:

(5+2)*7
Run Code Online (Sandbox Code Playgroud)

结果树应如下所示:

    *
   / \
  +   7
 / \
5   2
Run Code Online (Sandbox Code Playgroud)

我有一些自定义类来表示不同类型的节点,即PlusOp,LeafInt等.我不需要评估表达式,只需创建树,所以我可以在以后执行其他功能.此外,否定运算符' - '只能有一个子节点,并且要表示'5-2',您必须将其输入为5 +( - 2).

需要对表达式进行一些验证,以确保每种类型的运算符都具有正确的no.参数/儿童,每个开口括号都附有一个结束括号.

另外,我应该提一下,我的朋友已经编写了将输入字符串转换为一堆标记的代码,如果这对此有帮助的话.

我会感激任何帮助.谢谢 :)

(我读过你可以编写一个语法并使用antlr/JavaCC等来创建解析树,但我不熟悉这些工具或编写语法,所以如果这是你的解决方案,我将不胜感激,如果你可以为他们提供一些有用的教程/链接.)

Bil*_*l K 49

假设这是某种功课,你想自己做.

我做了一次,你需要一个堆栈

所以你为这个例子做的是:

    parse    what to do?                Stack looks like
      (      push it onto the stack     (
      5      push 5                     (, 5
      +      push +                     (, 5, +
      2      push 2                     (, 5, +, 2
      )      evaluate until (           7            
      *      push *                     7, *
      7      push 7                     +7, *, 7
      eof    evaluate until top         49

像"5"或"+"这样的符号可以存储为字符串或简单对象,或者您可以将+存储为+()对象而不设置值,并在评估时设置它们.

我认为这也需要一个优先顺序,所以我将描述它是如何工作的.

在:5 + 2*7的情况下

你必须推5推+推2下一个优先级更高,所以你也推它,然后推三个.当您遇到a)或文件结尾或优先级较低或相同的运算符时,您开始计算堆栈到前一个(或文件的开头).

因为您的堆栈现在包含5 + 2*7,所以当您评估它时,首先弹出2*7并将生成的*(2,7)节点推入堆栈,然后再次评估堆栈中的前三项( 5 +*节点)所以树出来是正确的.

如果它是以另一种方式订购的:5*2 + 7,你会推动直到你得到一个"5*2"的堆栈然后你会达到较低的优先级+这意味着评估你现在得到的.你将5*2评估成一个*节点并推送它,然后你继续推动+和3,这样你就得到了*node + 7,此时你就可以评估它了.

这意味着你有一个"最高当前优先级"变量,当你按下+/-时存储1,当你按*或/和3时为"^"时存储2.这样您就可以测试变量,看看下一个运算符的优先级是否<=您当前的优先级.

如果")"被认为是优先级4,则可以将其视为其他运算符,除非它删除匹配的"(",较低的优先级不会.

  • @SasQ更好地尝试解释一些事情而不是传递一个链接 - 教你和他们.此外,我从未将此视为算法,有人向我提到计算可以在树中完成而且我做了 - 不知道要查找的名称(虽然我知道它已经重复完成,但并不复杂 - 这就是我回答的原因) (8认同)
  • 难道不只是Edsger Dijkstra的"Shunting Yard"算法吗?(http://en.wikipedia.org/wiki/Shunting-yard_algorithm) (3认同)
  • @Bill K:我不会贬低你的解释努力.很好.我只粘贴一个链接作为参考,如果有人想要查看更多.是的,解释比传递链接更好,但如果在链接文章中已经解释过,最好传递链接并节省时间而不是重新发明轮子.在网上重复了太多相同知识的副本. (2认同)

小智 13

我想回答Bill K.的答案,但我缺乏在那里添加评论的声誉(这真的是这个答案所属的地方).您可以将此视为Bill K.答案的附录,因为他有点不完整.缺少的考虑因素是运营商的相关性 ; 即,如何解析如下表达式:

49 / 7 / 7
Run Code Online (Sandbox Code Playgroud)

根据是否为左或右关联,答案是:

49 / (7 / 7) => 49 / 1 => 49
Run Code Online (Sandbox Code Playgroud)

要么

(49 / 7) / 7 => 7 / 7 => 1
Run Code Online (Sandbox Code Playgroud)

通常,除法和减法被认为是左关联的(即上面的情况二),而取幂是右关联的.因此,当您遇到具有相同优先级的一系列运算符时,如果它们是关联的,则需要按顺序解析它们,如果是右关联的,则按顺序解析它们.这只是决定你是推送还是弹出堆栈,所以它不会使给定的算法过于复杂,它只是为连续运算符具有相同优先级时添加的情况(即如果左关联则评估堆栈,如果是右关联则推送到堆栈) .


Cam*_*ner 9

所述"五分钟的介绍ANTLR"包括算术语法例子.值得一试,特别是因为antlr是开源的(BSD许可证).

  • @CameronSkinner,需要注意的是,ANTLR不能被认为是开源项目,因为开源项目也应该开源文档(这是项目的一部分),但是ANTLR的文档不是免费的,所以它是一个免费软件,但不是开源[来自维基百科](http://en.wikipedia.org/wiki/Antlr) (2认同)