Lex和Yacc应用方法(六).语法树打印
草木瓜 20070525
一、序
没有直观的语法树显示界面,理解前面两篇文章会比较难一些。(语法树的示例见
《Lex和Yacc应用教程(四).语法树的应用》) 其实语法树显示程序在Tom Niemann的
《A Compact Guide to Lex & Yacc》文中已有完整的示例,不过我很不喜欢,也许
是无法适应别人的代码习惯吧,这里针对《Lex和Yacc应用方法(五).再识语法树》,
完全重写了打印语法树的程序代码。我不敢说算法有多高明,起码十分便于理解和掌握。
<注:本站文章难免有错误疏漏之处。Lex,Yacc系列文章 http://blog.youkuaiyun.com/liwei_cmg/category/207528.aspx>
二、示例代码
老方法,先给出测试通过的完整代码。
liwei.c
001 #include <stdio.h>
002 #include <string.h>
003 #include "node.h"
004 #include "lexya_e.tab.h"
005
006 /* 节点最大文本宽度 */
007 #define MAX_NODE_TEXT_LEN 10
008 /* 节点最大子节点个数 */
009 #define MAX_SUBNODE_COUNT 5
010
011 /* 节点宽度 */
012 #define NODE_WIDTH 4
013
014 #define MAX_NODE_COUNT 100
015
016 /* 排序后 树结点 */
017 #define MAX_TREE_WIDTH 20
018 #define MAX_TREE_DEEP 10
019
020
021 /* 树结点 图信息 */
022 struct NodePoint {
023
024 int x; /* 标准坐标X */
025 int y; /* 标准坐标Y */
026
027 char text[MAX_NODE_TEXT_LEN]; /* 显示内容 */
028 int textoffset1;
029 int textoffset2;
030
031 int parent; /* 父结点索引 */
032 int idx; /* 当前结点索引 */
033
034 Node * node; /* 实际内存树节点 */
035
036 int oppx; /* 相对坐标 */
037 int oppx_mid;/* 相对坐标中值 */
038
039 int childnum; /* 子结点个数 */
040 int child[MAX_SUBNODE_COUNT]; /* 子结点索引 */
041
042 };
043
044 struct NodePoint G_TreeNodePoint[MAX_NODE_COUNT]; /* 树结点全局全量 */
045
046 int G_iNodeCount; //存储树结点个数
047 int G_iNodeParent;//存储树的父结点
048
049 struct NodePoint * G_pTreeNodeOrder[MAX_TREE_DEEP][MAX_TREE_WIDTH]; /* 树结点按层次的排序数组 */
050 int G_iTreeNodeOrderCount[MAX_TREE_DEEP]; /* 每层树结点个数 */
051
052 int G_iDeepCount; /* 层次深度 */
053 int G_iMinNodeXValue; /* 树结点最小x值 */
054 int G_iGraphNum=-1; /* 图个数 */
055
056 /* 函数定义 */
057
058 void GraphNode(Node *, int, int, int);
059 void GraphNode_Set(int, int, int, char *, Node *);
060 void GraphNode_PrintVars();
061
062 void GraphNode_Order();
063 void GraphNode_Adjust();
064 void GraphNode_FillPos();
065
066 void GraphNode_Print();
067
068 struct NodePoint * NodeFind(struct NodePoint *, struct NodePoint *);
069 void NodeAdjust(struct NodePoint *, int tmp);
070
071 void PrintInfo(int, char *);
072 void InitVars();
073
074 int GetOffset(int, int, int);
075
076 char * itoa(int,char*);
077
078 /* 供内部调用函数 */
079 int NodeExecute(Node *p) {
080
081 G_iNodeCount=-1;
082 G_iNodeParent=-1;
083 G_iMinNodeXValue=0;
084
085 InitVars();
086
087 GraphNode(p, 0, 0, G_iNodeParent);
088
089 GraphNode_Order();
090 GraphNode_PrintVars();
091 GraphNode_Adjust();
092 GraphNode_FillPos();
093 GraphNode_PrintVars();
094
095 GraphNode_Print();
096
097 return 0;
098 }
099
100 /* 主递归函数,用于填充全局变量值 */
101 void GraphNode(Node *p, int xoffset, int yoffset, int parent) {
102
103 char sWord[MAX_NODE_TEXT_LEN];
104 char *sNodeText;
105 int i;
106
107 G_iNodeCount++;
108
109 if(parent!=-1) {
110 G_TreeNodePoint[parent].child[G_TreeNodePoint[parent].childnum]=G_iNodeCount;
111 G_TreeNodePoint[parent].childnum++;
112 }
113
114 switch(p->type) {
115
116 case TYPE_CONTENT:
117 sprintf (sWord, "c(%g)", p->content);
118 sNodeText = sWord;
119 GraphNode_Set (xoffset, yoffset, parent, sNodeText, p);
120 break;
121
122 case TYPE_INDEX:
123 sprintf (sWord, "idx(%s)",G_Var[p->index].mark);
124 sNodeText = sWord;
125 GraphNode_Set (xoffset, yoffset, parent, sNodeText, p);
126 break;
127
128 case TYPE_OP:
129 switch(p->op.name){
130 case WHILE: sNodeText = "while"; break;
131 case IF: sNodeText = "if"; break;
132 case FOR: sNodeText = "for"; break;
133 case PRINT: sNodeText = "print"; break;
134 case ';': sNodeText = "[;]"; break;
135 case '=': sNodeText = "[=]"; break;
136 case UMINUS: sNodeText = "[_]"; break;
137 case '+':