Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.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
在Java中解析算术表达式并从中构建树_Java_Parsing_Tree - Fatal编程技术网

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

在Java中解析算术表达式并从中构建树,java,parsing,tree,Java,Parsing,Tree,我需要一些帮助来创建给定算术表达式的自定义树。例如,输入以下算术表达式: (5+2)*7 结果树应该如下所示: * / \ + 7 / \ 5 2 我有一些自定义类来表示不同类型的节点,例如PlusOp、LeafInt等。我不需要计算表达式,只需要创建树,以便以后可以对其执行其他函数。 此外,负运算符“-”只能有一个子运算符,若要表示“5-2”,必须将其输入为5+(-2) 需要对表达式进行一些验证,以确保每种类型的运算符都具有正确的参数/子参数数量,每个左括号都有

我需要一些帮助来创建给定算术表达式的自定义树。例如,输入以下算术表达式:

(5+2)*7
结果树应该如下所示:

    *
   / \
  +   7
 / \
5   2
我有一些自定义类来表示不同类型的节点,例如PlusOp、LeafInt等。我不需要计算表达式,只需要创建树,以便以后可以对其执行其他函数。 此外,负运算符“-”只能有一个子运算符,若要表示“5-2”,必须将其输入为5+(-2)

需要对表达式进行一些验证,以确保每种类型的运算符都具有正确的参数/子参数数量,每个左括号都有一个右括号

另外,我可能应该提到我的朋友已经编写了代码,可以将输入字符串转换成一堆令牌,如果这对这有帮助的话

如果有任何帮助,我将不胜感激。谢谢:)


(我听说您可以编写语法并使用antlr/JavaCC等创建解析树,但我不熟悉这些工具或编写语法,因此如果这是您的解决方案,如果您能为它们提供一些有用的教程/链接,我将不胜感激。)

其中包括一个算术语法示例。值得一看,尤其是因为antlr是开源的(BSD许可证)。

有几个选项供您选择:

  • 重新使用现有的表达式解析器。如果你在语法和语义上灵活,那就行了。我推荐的一个好方法是Java内置的统一表达式语言(最初用于JSP和JSF文件)

  • 从头开始编写自己的解析器。有一种定义良好的方法来编写解析器,该方法考虑了运算符优先级等因素。准确地描述如何完成这一工作超出了本答案的范围。如果你走这条路,那就给自己找一本关于编译器设计的好书。前几章将介绍语言分析理论。通常,表达式解析就是一个例子

  • 使用JavaCC或ANTLR生成lexer和解析器。我更喜欢JavaCC,但各有各的。只需谷歌“javacc样本”或“antlr样本”。你会发现很多

  • 在2和3之间,我强烈推荐3,即使你必须学习新技术。创建解析器生成器是有原因的

    还要注意的是,创建一个能够处理格式错误的输入的解析器(不仅仅是由于解析异常而失败)要比编写一个只接受有效输入的解析器复杂得多。基本上,你必须写一个语法来解释各种常见的语法错误

    更新:下面是我使用JavaCC编写的表达式语言解析器的示例。语法松散地基于统一表达式语言。它会让你对你所面临的挑战有一个相当好的了解


    假设这是一种家庭作业,你想自己做

    我做过一次,你需要一堆

    因此,您在示例中所做的是:

    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(,5 +推动+(,5+ 2推动2(,5,+,2 )评估至(7) *按*7* 7推动7+7,*,7 eof评估至前49名 像“5”或“+”这样的符号可以存储为字符串或简单对象,也可以将+存储为+()对象,而无需设置值,并在求值时进行设置

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

    在以下情况下:5+2*7

    您必须按5下一步按2下一步操作优先级较高,因此您也要按5下一步操作,然后按7。当遇到a)或文件结尾或优先级较低或相等的运算符时,您将开始计算上一个(或文件开头)的堆栈

    因为你的堆栈现在包含5+2*7,当你计算它时,你首先弹出2*7并将结果*(2,7)节点推到堆栈上,然后再次计算堆栈上最上面的三个东西(5+*节点),这样树就正确了

    如果它是按另一种方式排序的:5*2+7,你将推动直到你到达一个带有“5*2”的堆栈,然后你将点击较低的优先级+,这意味着计算你现在得到的值。你将5*2计算成一个*节点,然后推它,然后你将继续推+和3,这样你就有了*节点+7,在这一点上你将计算它

    这意味着您有一个“当前最高优先级”变量,该变量在按下+/-时存储一个1,在按下*或/时存储一个2,在“^”时存储一个3。这样,您只需测试该变量,查看下一个运算符的优先级是否<=您当前的优先级


    如果“)”被视为优先级4,则可以将其视为其他运算符,但它会删除匹配的“(”,较低的优先级则不会。

    我想回应Bill K.的答案,但我缺乏在那里添加注释的声誉(这才是这个答案的真正归属).你可以把这看作是Bill K.答案的附录,因为他的答案有点不完整。缺少的考虑是:即如何解析表达式,如:

    49 / 7 / 7
    
    根据除法是左关联还是右关联,答案是:

    49 / (7 / 7) => 49 / 1 => 49
    

    通常,除法和减法被认为是左关联的(即,上述情况二),而求幂是右关联的。因此,当您遇到一系列具有相同优先级的运算符时,如果它们是左关联的,您希望按顺序对其进行分析,如果它们是右关联的,则希望按相反顺序对其进行分析。这只决定了您是推送还是弹出堆栈,因此它不会使给定的算法过于复杂,它只是连续运算符ar时的ds情况
    (49 / 7) / 7 => 7 / 7 => 1
    
    Infix  :     (5+2)*7
    Prefix :     *+527