Lex Yacc (三) 语法树打印

语法树打印 草木鱼(六) 源代码有百度云存盘

  • node.h 中有是否打印内容栈的开关

treeinput

  • treeinput
if(1>1||2>2)print(1);
else
if(3>1&&2>2)print(2);
else
print(3);
  • 和 再识语法树 中的文件放一起
  • bison -d lexya_e.y
  • lex lexya_e.l
  • gcc -g -o graph lex.yy.c lexya_e.tab.c liwei.c
  • ./graph < treeinput
  • ./graph < input 也可以用五中的输入

liwei.c

  • 这个文件需要与《Lex和Yacc应用方法(五).再识语法树》中提到的node.h,lexya_e.l,lexya_e.y

    一起编译,生成可执行文件。我这里编译的可执行文件名是graph,下文皆使用这个名称。

#include <stdio.h>
#include <string.h>
#include "node.h"
#include "lexya_e.tab.h"
/* 节点最大文本宽度 */
#define MAX_NODE_TEXT_LEN 10
/* 节点最大子节点个数 */
#define MAX_SUBNODE_COUNT 5
/* 节点宽度 */
#define NODE_WIDTH  4
#define MAX_NODE_COUNT    100
/* 排序后 树结点 */
#define MAX_TREE_WIDTH 20
#define MAX_TREE_DEEP  10
/* 树结点 图信息 */
struct NodePoint {
    int x;  /* 标准坐标X */
    int y;  /* 标准坐标Y */
    char text[MAX_NODE_TEXT_LEN]; /* 显示内容 */
    int textoffset1;
    int textoffset2;
    int parent; /* 父结点索引 */
    int idx;    /* 当前结点索引 */
    Node * node; /* 实际内存树节点 */
    int oppx;    /* 相对坐标 */
    int oppx_mid;/* 相对坐标中值 */
    int childnum; /* 子结点个数 */
    int child[MAX_SUBNODE_COUNT]; /* 子结点索引 */
};
struct NodePoint G_TreeNodePoint[MAX_NODE_COUNT]; /* 树结点全局全量 */
int G_iNodeCount; //存储树结点个数
int G_iNodeParent;//存储树的父结点
struct NodePoint * G_pTreeNodeOrder[MAX_TREE_DEEP][MAX_TREE_WIDTH]; /* 树结点按层次的排序数组 */
int G_iTreeNodeOrderCount[MAX_TREE_DEEP]; /* 每层树结点个数 */
int G_iDeepCount; /* 层次深度 */
int G_iMinNodeXValue; /* 树结点最小x值 */
int G_iGraphNum = -1; /* 图个数 */
/* 函数定义 */
void GraphNode(Node *, int, int, int);
void GraphNode_Set(int, int, int, char *, Node *);
void GraphNode_PrintVars();
void GraphNode_Order();
void GraphNode_Adjust();
void GraphNode_FillPos();
void GraphNode_Print();
struct NodePoint * NodeFind(struct NodePoint *, struct NodePoint *);
void NodeAdjust(struct NodePoint *, int tmp);
void PrintInfo(int, char *);
void InitVars();
int GetOffset(int, int, int);
char * itoa(int, char*);
/* 供内部调用函数 */
int NodeExecute(Node *p) {
    G_iNodeCount = -1;
    G_iNodeParent = -1;
    G_iMinNodeXValue = 0;
    InitVars();
    GraphNode(p, 0, 0, G_iNodeParent);
    GraphNode_Order();
    GraphNode_PrintVars();
    GraphNode_Adjust();
    GraphNode_FillPos();
    GraphNode_PrintVars();
    GraphNode_Print();
    return 0;
}
/* 主递归函数,用于填充全局变量值 */
void GraphNode(Node *p, int xoffset, int yoffset, int parent) {
    char sWord[MAX_NODE_TEXT_LEN];
    char *sNodeText;
    int i;
    G_iNodeCount++;
    if (parent != -1) {
        G_TreeNodePoint[parent].child[G_TreeNodePoint[parent].childnum] = G_iNodeCount;
        G_TreeNodePoint[parent].childnum++;
    }
    switch (p->type) {
    case TYPE_CONTENT:
        sprintf (sWord, "c(%g)", p->content);
        sNodeText = sWord;
        GraphNode_Set (xoffset, yoffset, parent, sNodeText, p);
        break;
    case TYPE_INDEX:
        sprintf (sWord, "idx(%s)", G_Var[p->index].mark);
        sNodeText = sWord;
        GraphNode_Set (xoffset, yoffset, parent, sNodeText, p);
        break;
    case TYPE_OP:
        switch (p->op.name) {
        case WHILE:  sNodeText = "while"; break;
        case IF:     sNodeText = "if";    break;
        case FOR:    sNodeText = "for";   break;
        case PRINT:  sNodeText = "print"; break;
        case ‘;‘:    sNodeText = "[;]";   break;
        case ‘=‘:    sNodeText = "[=]";   break;
        case UMINUS: sNodeText = "[_]";   break;
        case ‘+‘:    sNodeText = "[+]";   break;
        case ‘-‘:    sNodeText = "[-]";   break;
        case ‘*‘:    sNodeText = "[*]";   break;
        case ‘/‘:    sNodeText = "[/]";   break;
        case ‘<‘:    sNodeText = "[<]";   break;
        case ‘>‘:    sNodeText = "[>]";   break;
        case GE:     sNodeText = "[>=]";  break;
        case LE:     sNodeText = "[<=]";  break;
        case NE:     sNodeText = "[!=]";  break;
        case EQ:     sNodeText = "[==]";  break;
        case AND:    sNodeText = "[&&]";  break;
        case OR:     sNodeText = "[||]";  break;
        case ADD_T:  sNodeText = "[++v]";  break;
        case MUS_T:  sNodeText = "[--v]";  break;
        case ADD_TT: sNodeText = "[v++]";  break;
        case MUS_TT: sNodeText = "[v--]";  break;
        }
        GraphNode_Set (xoffset, yoffset, parent, sNodeText, p);
        for (i = 0; i < p->op.num; i++) {
            GraphNode(p->op.node[i], GetOffset(p->op.num, i + 1, 2), yoffset + 1, GetNodeIndex(p));
        }
        break;
    }
}
/* 树结点赋值函数 */
void GraphNode_Set(int xoffset, int yoffset, int parent, char * text, Node * p ) {
    int iBaseValue;
    if (parent <= -1)
        iBaseValue = 0;
    else
        iBaseValue = G_TreeNodePoint[parent].x;
    G_TreeNodePoint[G_iNodeCount].x = (iBaseValue + xoffset) ;
    G_TreeNodePoint[G_iNodeCount].y = yoffset;
    strcpy(G_TreeNodePoint[G_iNodeCount].text, text);
    iBaseValue = strlen(text);
    if (iBaseValue & 1) {
        G_TreeNodePoint[G_iNodeCount].textoffset1 = strlen(text) / 2 ;
        G_TreeNodePoint[G_iNodeCount].textoffset2 = strlen(text) - G_TreeNodePoint[G_iNodeCount].textoffset1 ;
    }
    else {
        G_TreeNodePoint[G_iNodeCount].textoffset1 = strlen(text) / 2 - 1;
        G_TreeNodePoint[G_iNodeCount].textoffset2 = strlen(text) - G_TreeNodePoint[G_iNodeCount].textoffset1 ;
    }
    G_TreeNodePoint[G_iNodeCount].parent = parent;
    G_TreeNodePoint[G_iNodeCount].idx = G_iNodeCount;
    G_TreeNodePoint[G_iNodeCount].node = p;
    G_TreeNodePoint[G_iNodeCount].oppx = 0;
    G_TreeNodePoint[G_iNodeCount].oppx_mid = 0;
    G_TreeNodePoint[G_iNodeCount].child[0] = 0;
    G_TreeNodePoint[G_iNodeCount].childnum = 0;
    /* 记录最小值 */
    if (G_TreeNodePoint[G_iNodeCount].x < G_iMinNodeXValue)G_iMinNodeXValue = G_TreeNodePoint[G_iNodeCount].x;
}
/* 根据树结点层次排序 */
void GraphNode_Order() {
    int i;
    int iDeep;
    G_iDeepCount = -1;
    for (i = 0; i <= G_iNodeCount; i++) {
        G_TreeNodePoint[i].x = G_TreeNodePoint[i].x - G_iMinNodeXValue + 1;
        iDeep = G_TreeNodePoint[i].y;
        G_iTreeNodeOrderCount[iDeep]++;
        G_pTreeNodeOrder[iDeep][G_iTreeNodeOrderCount[iDeep]] = &G_TreeNodePoint[i];
        if (iDeep > G_iDeepCount)G_iDeepCount = iDeep;
    }
}
/* 填充树结点真实坐标,相对坐标 */
void GraphNode_FillPos() {
    int iInt;
    int iBlank;
    int idx;
    int i, j;
    for (j = 0; j <= G_iDeepCount; j++) {
        iBlank = 0;
        for (i = 0; i <= G_iTreeNodeOrderCount[j]; i++) {
            idx = G_pTreeNodeOrder[j][i]->idx;
            if (i != 0) {
                iInt = (G_TreeNodePoint[idx].x - G_TreeNodePoint[G_pTreeNodeOrder[j][i - 1]->idx].x) * NODE_WIDTH ;
                iBlank = iInt - G_TreeNodePoint[idx].textoffset1 - G_TreeNodePoint[G_pTreeNodeOrder[j][i - 1]->idx].textoffset2;
            }
            else {
                iInt = (G_TreeNodePoint[idx].x) * NODE_WIDTH ;
                iBlank = iInt - G_TreeNodePoint[idx].textoffset1;
            }
            G_TreeNodePoint[idx].oppx = iInt ;
            G_TreeNodePoint[idx].oppx_mid = iBlank ;
        }
    }
}
/* 调整树结点位置 */
void GraphNode_Adjust() {
    int i, j;
    int tmp;
    for (i = G_iDeepCount; i >= 0; i--)
        for (j = 0; j <= G_iTreeNodeOrderCount[i]; j++)
            if (j != G_iTreeNodeOrderCount[i]) {
                if (j == 0) {
                    tmp = G_pTreeNodeOrder[i][j]->textoffset1 / NODE_WIDTH ;
                    if (tmp >= 1)
                        NodeAdjust(NodeFind(G_pTreeNodeOrder[i][j], G_pTreeNodeOrder[i][j + 1]), tmp);
                }
                tmp = G_pTreeNodeOrder[i][j]->x - G_pTreeNodeOrder[i][j + 1]->x + ( G_pTreeNodeOrder[i][j]->textoffset2 + G_pTreeNodeOrder[i][j + 1]->textoffset1 ) / NODE_WIDTH + 1;
                if (tmp >= 1)
                    NodeAdjust(NodeFind(G_pTreeNodeOrder[i][j], G_pTreeNodeOrder[i][j + 1]), tmp);
            }
}
/* 查找需要调整的子树的根结点
struct NodePoint * NodeFind(struct NodePoint * p) {
  while(p->parent!=-1 && G_TreeNodePoint[p->parent].child[0]==p->idx) {
    p=&G_TreeNodePoint[p->parent];
  }
  return p;
}
*/
/* 查找需要调整的子树的根结点 */
struct NodePoint * NodeFind(struct NodePoint * p1, struct NodePoint * p2) {
    while (p2->parent != -1 && p1->parent != p2->parent) {
        p1 = &G_TreeNodePoint[p1->parent];
        p2 = &G_TreeNodePoint[p2->parent];
    }
    return p2;
}
/* 递归调整坐标 */
void NodeAdjust(struct NodePoint * p, int tmp) {
    int i;
    if (p->childnum == 0)
        p->x = p->x + tmp;
    else {
        p->x = p->x + tmp;
        for (i = 0; i <= p->childnum - 1; i++)
            NodeAdjust(&G_TreeNodePoint[p->child[i]], tmp);
    }
}
/* 打印内存变量 */
void GraphNode_PrintVars() {
    printf("\n");
    int i, j;
    for (i = 0; i <= G_iNodeCount; i++) {
        printf("ID:%2d x:%2d y:%2d txt:%6s ofs:%d/%d rx:%2d b:%2d pa:%2d num:%2d child:",
               i,
               G_TreeNodePoint[i].x,
               G_TreeNodePoint[i].y,
               G_TreeNodePoint[i].text,
               G_TreeNodePoint[i].textoffset1,
               G_TreeNodePoint[i].textoffset2,
               G_TreeNodePoint[i].oppx,
               G_TreeNodePoint[i].oppx_mid,
               G_TreeNodePoint[i].parent,
               G_TreeNodePoint[i].childnum
              );
        for (j = 0; j <= G_TreeNodePoint[i].childnum - 1; j++)
            printf("%d ", G_TreeNodePoint[i].child[j]);
        printf("\n");
    }
    printf("\n");
}
/* 打印语法树 */
void GraphNode_Print() {
    G_iGraphNum++;
    printf("<Graph %d>\n", G_iGraphNum);
    int idx;
    int i, j;
    for (j = 0; j <= G_iDeepCount; j++) {
        /* 打印首行结点 [] */
        for (i = 0; i <= G_iTreeNodeOrderCount[j]; i++) {
            idx = G_pTreeNodeOrder[j][i]->idx;
            PrintInfo( G_TreeNodePoint[idx].oppx_mid , G_TreeNodePoint[idx].text);
        }
        printf("\n");
        if (j == G_iDeepCount)return; /* 结束 */
        /* 打印第二行分隔线 |  */
        int iHave = 0;
        for (i = 0; i <= G_iTreeNodeOrderCount[j]; i++) {
            idx = G_pTreeNodeOrder[j][i]->idx;
            if (G_pTreeNodeOrder[j][i]->childnum) {
                if (iHave == 0)
                    PrintInfo( G_TreeNodePoint[idx].oppx , "|");
                else
                    PrintInfo( G_TreeNodePoint[idx].oppx - 1 , "|");
                iHave = 1;
            }
            else
                PrintInfo( G_TreeNodePoint[idx].oppx , "");
        }
        printf("\n");
        /* 打印第三行连接线 ------   */
        for (i = 0; i <= G_iTreeNodeOrderCount[j + 1]; i++) {
            idx = G_pTreeNodeOrder[j + 1][i]->idx;
            int k;
            if (i != 0 && G_pTreeNodeOrder[j + 1][i]->parent == G_pTreeNodeOrder[j + 1][i - 1]->parent) {
                for (k = 0; k <= G_pTreeNodeOrder[j + 1][i]->oppx - 2; k++)
                    printf("-");
                printf("|");
            }
            else if (i == 0) {
                PrintInfo( G_TreeNodePoint[idx].oppx , "|");
            }
            else {
                PrintInfo( G_TreeNodePoint[idx].oppx - 1 , "|");
            }
        }
        printf("\n");
        /* 打印第四行分割连接线 | */
        for (i = 0; i <= G_iTreeNodeOrderCount[j + 1]; i++) {
            idx = G_pTreeNodeOrder[j + 1][i]->idx;
            if (i == 0)
                PrintInfo( G_TreeNodePoint[idx].oppx , "|");
            else
                PrintInfo( G_TreeNodePoint[idx].oppx - 1 , "|");
        }
        printf("\n");
    }
}
/* 获取节点位移 */
int GetOffset(int count, int idx, int base) {
    if (count & 1)
        return (idx - (count + 1) / 2) * base;
    else
        return idx * base - (count + 1) * base / 2;
}
/* 根据节点地址获取内存索引 */
int GetNodeIndex(Node * p) {
    int i;
    for (i = G_iNodeCount; i >= 0; i--) {
        if (p == G_TreeNodePoint[i].node)return G_TreeNodePoint[i].idx;
    }
}
/* 初始化变量 */
void InitVars() {
    /*
      int i,j;
      for(j=0;j<=MAX_TREE_DEEP-1;j++)
        for(i=0;i<=MAX_TREE_WIDTH-1;i++)
          G_pTreeNodeOrder[j][i]=0;
    */
    int i;
    for (i = 0; i <= MAX_TREE_DEEP - 1; i++)
        G_iTreeNodeOrderCount[i] = -1;
}
/* 打印固定信息 */
void PrintInfo(int val, char * str) {
    char sInt[10];
    char sPrint[20];
    itoa( val , sInt);
    strcpy(sPrint, "%");
    strcat(sPrint, sInt);
    strcat(sPrint, "s");
    printf(sPrint, "");
    printf(str);
}
/* int 转 char */
char * itoa(int n, char *buffer) {
    int i = 0, j = 0;
    int iTemp;  /* 临时int  */
    char cTemp; /* 临时char */
    do
    {
        iTemp = n % 10;
        buffer[j++] = iTemp + ‘0‘;
        n = n / 10;
    } while (n > 0);
    for (i = 0; i < j / 2; i++)
    {
        cTemp = buffer[i];
        buffer[i] = buffer[j - i - 1];
        buffer[j - i - 1] = cTemp;
    }
    buffer[j] = ‘\0‘;
    return buffer;
}
时间: 2024-10-11 16:12:52

Lex Yacc (三) 语法树打印的相关文章

Lex Yacc (二) 语法树

语法树的应用 草木鱼 (四) 源码见百度云盘 详细讲解:草木鱼(四) input input i=0; while(i<=10){ print(i); i=i+1; } print(i+i); node.h node.h /* 定义树结点的权举类型 */ typedef enum { TYPE_CONTENT, TYPE_INDEX, TYPE_OP } NodeEnum; /* 操作符 */ typedef struct { int name; /* 操作符名称 */ int num; /*

编译器架构的王者LLVM——(5)语法树模型的基本结构

LLVM平台,短短几年间,改变了众多编程语言的走向,也催生了一大批具有特色的编程语言的出现,不愧为编译器架构的王者,也荣获2012年ACM软件系统奖 -- 题记 版权声明:本文为 西风逍遥游 原创文章,转载请注明出处 西风世界 http://blog.csdn.net/xfxyy_sxfancy 语法树模型的基本结构 上次我们看了Lex和Yacc的翻译文件,可能一些朋友并不了解其中的执行部分,而且,对这个抽象语法树是怎么构建起来的还不清楚.今天我们就再详细介绍一下如果方便的构建一棵抽象语法树(A

Lex Yacc (四) 实际应用全代码

修改后的实际应用全代码 草木鱼(七) 精读 源代码有百度云存盘 复杂的逻辑判断简化成程序判断语句,可便于应用的扩展和维护,也极大增强了代码的可读性. 我们对整体文件划分如下: tree.l tree.y parser.h #内部编译使用的头文件 parser.c #内部编译的主函数 compile.h #内外部交互的头文件 main.c #外部程序 修改说明 1.将内部使用变量,函数,结构体和宏定义集中到parser.h 2.将yyparser的输入进行重定义,见#undef YY_INPUT部

Lex Yacc (一) 入门

github 项目地址 草木瓜 准备工作 文法分析用Flex(Lex):将数据分隔成一个个的标记token (标示符identifiers,关键字keywords,数字numbers, 中括号brackets, 大括号braces, 等等etc.) 语法分析用Bison(Yacc): 在分析标记的时候生成抽象语法树. Bison 将会做掉几乎所有的这些工作, 我们定义好我们的抽象语法树就OK了. 组装用LLVM: 这里我们将遍历我们的抽象语法树,并未每一个节点生成字节/机器码. 这听起来似乎很疯

[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285人阅读 评论(1) 收藏 举报  分类: Webkit(34)  JavascriptCore/JIT(3)  版权声明:本文为博主原创文章,未经博主允许不得转载. 看到HorkeyChen写的文章<[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现>

[WebKit内核] JavaScriptCore深度解析--基础篇(一)字节码生成及语法树的构建

看到HorkeyChen写的文章<[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现>,写的很好,深受启发.想补充一些Horkey没有写到的细节比如字节码是如何生成的等等,为此成文. JSC对JavaScript的处理,其实与Webkit对CSS的处理许多地方是类似的,它这么几个部分: (1)词法分析->出来词语(Token): (2)语法分析->出来抽象语法树(AST:Abstract Syntax Tree): (3)遍历抽象语法

Lex+YACC详解

1. 简介 只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一个Lex,Bison则是GNU版本的YACC.在此我们将统一称呼这些程序为Lex和YACC.新版本的程序是向上兼容的(译注:即兼容老版本),所以你可以用Flex和Bison来尝试下我们的实例. 这些程序实用性极广,但如同你的C编译器一样,在其主页上并没有描述它们,也没有关于怎样使用的信息.当和Lex结合使用时

[转帖]AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解

AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解 https://segmentfault.com/a/1190000016231512 太长没看完.. javascriptvue-clicommonjswebpackast 阅读约 27 分钟 抽象语法树(AST),是一个非常基础而重要的知识点,但国内的文档却几乎一片空白. 本文将带大家从底层了解AST,并且通过发布一个小型前端工具,来带大家了解AST的强大功能 Javascript就像一台精妙运作的机器,我们可以

AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解

AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解 javascriptvue-clicommonjswebpackast 阅读约 27 分钟 抽象语法树(AST),是一个非常基础而重要的知识点,但国内的文档却几乎一片空白. 本文将带大家从底层了解AST,并且通过发布一个小型前端工具,来带大家了解AST的强大功能 Javascript就像一台精妙运作的机器,我们可以用它来完成一切天马行空的构思. 我们对javascript生态了如指掌,却常忽视javascript本身