如何使用 Java 在控制台中打印正确的解析树?

How to print a proper parse tree in console using Java?

提问人:Seifeldin Elkasrawy 提问时间:11/7/2023 最后编辑:Seifeldin Elkasrawy 更新时间:11/10/2023 访问量:76

问:

我正在编写一个使用 java 模拟 6 个编译器阶段的程序。目前,卡在了第二阶段的解析树的打印中,语法分析器。经过一些调试,我已经知道我的问题是什么。父节点和子节点是正确的,但在视觉上以错误的深度显示。

输入:z=y*y+x*3

当它到达具有子节点的 * 符号时,它首先显示其子节点,然后再显示其同级节点,该节点也是另一个 *,因为递归。

    public static void displayParseTree(ParseTreeNode node, int depth) {
        if (node != null) {
            StringBuilder indent = new StringBuilder();
            for (int i = 0; i < depth; i++) {
                indent.append(" ");
            }

            //if node has children print / -> child1  \ -> child2
            System.out.print(indent.toString() + node.token.getValue());
            // Check if the node has any children.
            if (!node.children.isEmpty()) {

                System.out.println("");
                
                System.out.print("/  ");
                System.out.println(" \\");

                // Print the left child node.
                displayParseTree(node.children.get(0), depth + 1);

                // Print the right child node.
                displayParseTree(node.children.get(1), depth + 1);
                System.out.println("");
            }
        }
    }

输出

万一img打不开,这是我目前的输出:

Please enter the source code: 
z=y*y+x*3
Source Form: z=y*y+x*3
Math Form: z=yxy+xx3
Lexical Analyzer: id1=id2*id2+id3*3
Syntax analysis completed. The input is valid.

=
/   \
 id1 +
/   \
  *
/   \
   id2   id2
  *
/   \
   id3   3

我希望我的输出看起来更像这样:

    =
  /  \
id1   +
    /    \
  *        *
/    \   /   \
id2  id2 id3  3

编辑:我有点硬编码它(不为此感到自豪),但我会把它留在那里,直到我找到更好的方法

    public static void displayParseTree(ParseTreeNode node, int depth) {
        if (node != null) {
            StringBuilder indent = new StringBuilder();
            for (int i = 0; i < depth; i++) {
                indent.append(" ");
            }

//if node has children print / -> child1  \ -> child2
            if (node.token.getValue().equals("=")){
                System.out.println("  " + indent.toString() + node.token.getValue());
            }

            // Check if the node has any children.
            if (!node.children.isEmpty()) {

                if (node.children.get(0).token.getValue().equals("*") && node.children.get(1).token.getValue().equals("*")) {
                    System.out.print("/  ");
                    System.out.println(" \\");

                    for (int i = 0; i < 2; i++) {
                        System.out.print(node.children.get(i).token.getValue() + "  ");
                    }
                    System.out.println("");

                    System.out.print("/  ");
                    System.out.print(" \\   ");
                    System.out.print("  /  ");
                    System.out.println(" \\");

                    for (int i = 0; i < 2; i++) {
                        for (int j = 0; j < 2; j++)
                        System.out.print(node.children.get(i).children.get(j).token.getValue() + "  ");
                    }
                    System.out.println("");
                }
                else {
                    // Print the left child node.
                    System.out.print("/  ");
                    System.out.println(" \\");

                    for (int i = 0; i < 2; i++) {
                        System.out.print(node.children.get(i).token.getValue() + "  ");
                    }
                    System.out.println("");

                    displayParseTree(node.children.get(0), depth + 1);

                    // Print the right child node.
                    displayParseTree(node.children.get(1), depth + 1);
                }
            }
        }
    }

电流输出:

      =
    /   \
    id1  +  
    /   \
    *  *  
    /   \     /   \
    id2  id2  id3  3
java 编译器构造 解析树

评论

0赞 khachik 11/7/2023
上层的缩进取决于下层。无论深度如何,具有仅右子项的树在根部的缩进量都将为 0,而仅具有左的树在根级别处将具有最深的缩进。您可以遍历树一次以计算为每个节点分配缩进,但这需要在任何树更改后重新计算,不确定这有多相关。
0赞 Seifeldin Elkasrawy 11/8/2023
上层的缩进会如何受到下层的影响?我相信情况恰恰相反。此外,这棵树确实有左边和右边的孩子。我不完全理解最后一部分。遍历我的树一次,首先计算并为每个节点分配缩进?那么它应该在每次添加新节点时重新计算吗?
0赞 queeg 11/10/2023
上层的缩进确实取决于底层项所在的位置。只需将标识符 id2、id3 替换为更长的名称 - >底线会发生变化,上面一行中的运算符需要居中等。

答:

-1赞 Seifeldin Elkasrawy 11/10/2023 #1

我想通了。虽然我认为可以有更好的解决方案,但这就是我设法想出的。 因为,只有乘法和除法运算符才能达到相同的深度,所以我专门为它们做了一个条件。首先检查两个运算是否都是 * 或 /,如果是,则打印 / \ 分支,然后打印运算,然后打印其所有子项的分支,即 4 个 / \ / \,然后使用嵌套循环在同一行上打印他们的两个子项,否则正常执行所有操作。就是这样。在那之后,只需调整空间即可获得我正在寻找的输出。

    public static void displayParseTree(ParseTreeNode node, int depth) {
        if (node != null) {
            StringBuilder indent = new StringBuilder();
            for (int i = 0; i < depth; i++) {
                indent.append(" ");
            }

//if node has children print / -> child1  \ -> child2
            if (node.token.getValue().equals("=")){
                System.out.println("       " + indent.toString() + node.token.getValue());
            }

            // Check if the node has any children.
            if (!node.children.isEmpty()) {

                if (node.children.get(0).token.getValue().equals("*") && node.children.get(1).token.getValue().equals("*") ||
                        node.children.get(0).token.getValue().equals("/") && node.children.get(1).token.getValue().equals("/")) {
                    System.out.print("        /   ");
                    System.out.println("  \\");

                    for (int i = 0; i < 2; i++) {
                        System.out.print("     "+ node.children.get(i).token.getValue() + "    ");
                    }
                    System.out.println("");

                    System.out.print("   /  ");
                    System.out.print(" \\   ");
                    System.out.print("  /  ");
                    System.out.println(" \\");

                    for (int i = 0; i < 2; i++) {
                        for (int j = 0; j < 2; j++)
                        System.out.print(" "+ node.children.get(i).children.get(j).token.getValue() + "  ");
                    }
                    System.out.println("");
                }
                else {
                    // Print the left child node.
                    System.out.print("   /  ");
                    System.out.println("    \\");

                    for (int i = 0; i < 2; i++) {
                        System.out.print("  " + node.children.get(i).token.getValue() + "    ");
                    }
                    System.out.println("");

                    displayParseTree(node.children.get(0), depth + 1);

                    // Print the right child node.
                    displayParseTree(node.children.get(1), depth + 1);
                }
            }
        }
    }
Please enter the source code: 
z=y*y+x*3
Source Form: z=y*y+x*3
Math Form: z=yxy+xx3
Lexical Analyzer: id1=id2*id2+id3*3
Syntax analysis completed. The input is valid.
       =
   /      \
  id1      +    
        /     \
     *         *    
   /   \     /   \
 id2   id2   id3   3

评论

0赞 user207421 11/10/2023
“只有乘法运算符和除法运算符才能达到相同的深度”:当您使用括号时,这种情况是正确的。找到一个通用的解决方案。