之前做课程设计时写过二叉树的输出,最近,写 SNL 语言的编译程序的语法分析器,需要输出语法树,而语法树是多叉树,与二叉树的输出有点不一样。
然后是语法树的输出:
你可以在 Github 上找到完整的 SNL 词法分析与语法分析程序,其中包含了语法树的输出代码。
输出二叉树的思想:二叉树的文本模式输出
- 非递归进行中根遍历,遍历过程中确定每个结点的坐标(即其距离左边的偏移)
- 层次遍历依次输出每一层
竖版的输出树使用的是先根遍历,因此我们可以用栈来实现(层次遍历用队列)。 通用的先根遍历过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17Syntax Tree for source code: hello.snl(by Recursive Descent) Program_ProgramHead_program | |_ProgramName_sd |_DeclarePart_TypeDecPart_Пе | |_VarDecPart_Пе | |_ProcDecpart_Пе |_ProgramBody_begin | |_StmList_Stm_OutputStm_write | | | |_( | | | |_Exp_Term_Factor_1 | | | | | |_OtherFactor_Пе | | | | |_OtherTerm_Пе | | | |_) | | |_StmMore_Пе | |_end |_.
- 根结点入栈;
-
- 当栈非空:
-
- 弹出一个结点,访问之,同时其子结点入栈;
- 一个标记 isLineHead 记录当前结点是否为每行的第一个结点;
- 一个列表用来记录每行还有子孩子没有输出的结点。
1 2 3 4 5 |
|
- 设置1.的作用是,非行首结点的处理很简单,输出连接号下划线再输出自身结点值就行了(如上图 a, b 等),而行首结点需要输出更多内容(竖线)(如上图 c, d 等)。
- 设置2.的作用是,并不是处理每个行首结点时,都需要在每个行首处画竖线,如上图 f, 并不要在 root 之下画竖线,因为 root 的所有子孩子都已输出。
-
- 访问结点时,如果当前结点不是行首:
- 输出 _值
-
- 否则,当前结点是行首结点:
-
- 遍历列表(上面定义的),
- 如果当前要输出结点是当前遍历结点的子孩子,则输出足够的空格和竖线及下划线和结点值 如上图输出 d 时。
- 如果当前要输出结点不是当前遍历列表结点的子孩子则只需输出足够多的空格和竖线。
[root, a, b] 遍历到 root 时,只需输出 root 的宽度个空格和一个竖线。遍历到 a 时才是 空格(a的宽度个)竖线下划线 c 的值。
说得很明白了吧,下面是完整代码:
首先是结点的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
|

Reader Echoes
3 comments