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; /* 操作元个数 */
    struct NodeTag * node[1]; /* 操作元地址 可扩展 */
} OpNode;
typedef struct NodeTag {
    NodeEnum type; /* 树结点类型 */
    /* Union 必须是最后一个成员 */
    union {
        int content; /* 内容 */
        int index; /* 索引 */
        OpNode op; /* 操作符对象 */
    };
} Node;
extern int Var[26];

lexya_e.l

  • lexya_e.l
%{
#include <stdlib.h>
#include "node.h"
#include "lexya_e.tab.h"
void yyerror(char *);
%}
%%
[a-z] { yylval.sIndex = *yytext - ‘a‘; return VARIABLE;}
[0-9]+ { yylval.iValue = atoi(yytext); return INTEGER;}
[()<>=+*/;{}.] { return *yytext;}
">=" return GE;
"<=" return LE;
"==" return EQ;
"!=" return NE;
"&&" return AND;
"||" return OR;
"while" return WHILE;
"if" return IF;
"else" return ELSE;
"print" return PRINT;
[\t\n]+ ; /* 去除空格,回车 */
. printf("unknow symbol:[%s]\n", yytext);
%%
int yywrap(void) {
    return 1;
}

lexya_e.y

  • lexya_e.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "node.h"
/* 属性操作类型 */
Node * opr(int name, int num, ...);
//Node *opr(int name, int num, ...);  //在内存空间中分配操作符相关的树结点
Node * set_index(int value);  //在内存空间分配index的树结点
Node * set_content(int value);
void freeNode(Node * p);
int exeNode(Node * p);
int yylexeNode(void);
void yyerror(char *s);
int Var[26]; /* 变量数组 */
%}
%union {
    int iValue; /* 变量值 */
    char sIndex; /* 变量数组索引 */
    Node *nPtr; /* 结点地址 */
};
%token <iValue> VARIABLE
%token <sIndex> INTEGER
%token WHILE IF PRINT
%nonassoc IFX     //有关优先级
%nonassoc ELSE
%left AND OR GE LE EQ NE ‘>‘ ‘<‘
%left ‘+‘ ‘-‘
%left ‘*‘ ‘/‘
%nonassoc UMINUS
%type <nPtr> stmt expr stmt_list
%%
program:
function { exit(0); }
;
function:
function stmt { exeNode($2); freeNode($2); }
|
;
stmt:
‘;‘ { $$ = opr(‘;‘, 2, NULL, NULL); }
| expr ‘;‘ { $$ = $1; }
| PRINT expr ‘;‘ { $$ = opr(PRINT, 1, $2); }
| VARIABLE ‘=‘ expr ‘;‘ { $$ = opr(‘=‘, 2, set_index($1), $3); }
| WHILE ‘(‘ expr ‘)‘ stmt { $$ = opr(WHILE, 2, $3, $5); }
| IF ‘(‘ expr ‘)‘ stmt %prec IFX { $$ = opr(IF, 2, $3, $5); }
| IF ‘(‘ expr ‘)‘ stmt ELSE stmt %prec ELSE { $$ = opr(IF, 3, $3, $5, $7); }
| ‘{‘ stmt_list ‘}‘ { $$ = $2; }
;
stmt_list:
stmt { $$ = $1; }
| stmt_list stmt { $$ = opr(‘;‘, 2, $1, $2); }
;
expr:
INTEGER {$$ = set_content($1); }
| VARIABLE {$$ = set_index($1); }
| ‘-‘ expr %prec UMINUS {$$ = opr(UMINUS, 1, $2); }
| expr ‘+‘ expr {$$ = opr(‘+‘, 2, $1, $3); }
| expr ‘-‘ expr { $$ = opr(‘-‘, 2, $1, $3); }
| expr ‘*‘ expr { $$ = opr(‘*‘, 2, $1, $3); }
| expr ‘/‘ expr { $$ = opr(‘/‘, 2, $1, $3); }
| expr ‘<‘ expr { $$ = opr(‘<‘, 2, $1, $3); }
| expr ‘>‘ expr { $$ = opr(‘>‘, 2, $1, $3); }
| expr GE expr { $$ = opr(GE, 2, $1, $3); }
| expr LE expr { $$ = opr(LE, 2, $1, $3); }
| expr NE expr { $$ = opr(NE, 2, $1, $3); }
| expr EQ expr { $$ = opr(EQ, 2, $1, $3); }
| expr AND expr { $$ = opr(AND, 2, $1, $3); }
| expr OR expr { $$ = opr(OR, 2, $1, $3); }
| ‘(‘ expr ‘)‘ { $$ = $2; }
;
%%
#define SIZE_OF_NODE ((char *)&p->content - (char *)p)
Node *set_content(int value) {
    Node *p;
    size_t sizeNode;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(int);
    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_CONTENT;
    p->content = value;
    return p;
}
Node *set_index(int value) {
    Node *p;
    size_t sizeNode;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(int);
    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_INDEX;
    p->index = value;
    return p;
}
Node *opr(int name, int num, ...) {
    va_list valist;   //声明变量
    Node *p;
    size_t sizeNode;
    int i;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(OpNode) + (num - 1) * sizeof(Node*);
    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_OP;
    p->op.name = name;
    p->op.num = num;
    va_start(valist, num);    //开始解析。valist指向num后面的参数。实现变换函数参数的
    for (i = 0; i < num; i++)
        p->op.node[i] = va_arg(valist, Node*);   //取下一个参数并返回。valist指向下一个参数
    va_end(valist);   //结束解析
    return p;
}
void freeNode(Node *p) {
    int i;
    if (!p) return;
    if (p->type == TYPE_OP) {
        for (i = 0; i < p->op.num; i++)
            freeNode(p->op.node[i]);
    }
    free (p);
}
void yyerror(char *s) {
    fprintf(stdout, "%s\n", s);
}
int main(void) {
    yyparse();
    return 0;
}

parser.c

  • parser.c
#include <stdio.h>
#include "node.h"
#include "lexya_e.tab.h"

int exeNode(Node *p) {
    if (!p) return 0;
    switch (p->type) {
    case TYPE_CONTENT: return p->content;
    case TYPE_INDEX:   return Var[p->index];
    case TYPE_OP:
        switch (p->op.name) {

        case WHILE:  while (exeNode(p->op.node[0]))exeNode(p->op.node[1]);
            return 0;

        case IF:     if (exeNode(p->op.node[0]))
                exeNode(p->op.node[1]);
            else if (p->op.num > 2)
                exeNode(p->op.node[2]);
            return 0;

        case PRINT:  printf("%d\n", exeNode(p->op.node[0]));
            return 0;

        case ‘;‘:    exeNode(p->op.node[0]);
            return exeNode(p->op.node[1]);

        case ‘=‘:    return Var[p->op.node[0]->index] = exeNode(p->op.node[1]);
        case UMINUS: return exeNode(p->op.node[0]);
        case ‘+‘:    return exeNode(p->op.node[0]) + exeNode(p->op.node[1]);
        case ‘-‘:    return exeNode(p->op.node[0]) - exeNode(p->op.node[1]);
        case ‘*‘:    return exeNode(p->op.node[0]) * exeNode(p->op.node[1]);
        case ‘/‘:    return exeNode(p->op.node[0]) / exeNode(p->op.node[1]);
        case ‘<‘:    return exeNode(p->op.node[0]) < exeNode(p->op.node[1]);
        case ‘>‘:    return exeNode(p->op.node[0]) > exeNode(p->op.node[1]);
        case GE:     return exeNode(p->op.node[0]) >= exeNode(p->op.node[1]);
        case LE:     return exeNode(p->op.node[0]) <= exeNode(p->op.node[1]);
        case NE:     return exeNode(p->op.node[0]) != exeNode(p->op.node[1]);
        case EQ:     return exeNode(p->op.node[0]) == exeNode(p->op.node[1]);
        case AND:    return exeNode(p->op.node[0]) && exeNode(p->op.node[1]);
        case OR:     return exeNode(p->op.node[0]) || exeNode(p->op.node[1]);
        }
    }
    return 0;
}
  • bison -d lexya_e.y
  • lex -d lexya_e.l
  • gcc -g -o parser lex.yy.c lexya_e.tab.c parser.c
  • ./parser < input

再识语法树 草木鱼(五) 源代码有百度云存盘

node.h

  • node.h
/* 定义树结点的权举类型 */
typedef enum { TYPE_CONTENT, TYPE_INDEX, TYPE_OP } NodeEnum;

/* 操作符 */
typedef struct {
    int name; /* 操作符名称 */
    int num; /* 操作元个数 */
    struct NodeTag * node[1]; /* 操作元地址 可扩展 */
} OpNode;
typedef struct NodeTag {
    NodeEnum type; /* 树结点类型 */
    /* Union 必须是最后一个成员 */
    union {
        float content; /* 内容 */
        int index; /* 索引 */
        OpNode op; /* 操作符对象 */
    };

} Node;

struct VarIndex
{
    float val;
    char mark[10];
};

struct VarDefine
{
    int index;
    char * name;
};

#define USER_DEF_NUM 259 /* Yacc编译的保留字开始索引 */

#define MAX_VARS 100     /* 最多变量数 */
#define MAX_DEFS 20      /* 最多保留字数 */

#define MAX_BUFF_COLS 40   /* 分析语句最多行数 */
#define MAX_BUFF_ROWS 40   /* 分析语句每行最多字符数 */

extern struct VarIndex G_Var[MAX_VARS];  /* 存储的变量数组 */
extern struct VarDefine G_Def[MAX_DEFS]; /* 系统保留字变量 */

extern int G_iVarMaxIndex;   /* 变量目前总数 */
extern int G_iVarCurIndex;   /* 当前操作变量索引 */

extern char G_sBuff[MAX_BUFF_ROWS][MAX_BUFF_COLS];  /* 存储分析语句 */
extern int G_iBuffRowCount;  /* 当前语句行数 */
extern int G_iBuffColCount;  /* 当前语句列数 */

/* 是否打印调试信息的开关 */
// #define PARSE_DEBUG

lexya_e.l

  • lexya_e.l
%{
#include <stdlib.h>
#include "node.h"
#include "lexya_e.tab.h"
struct VarDefine G_Def[MAX_DEFS];             /* 存储的变量数组 */
char G_sBuff[MAX_BUFF_ROWS][MAX_BUFF_COLS];   /* 存储分析语句   */
int G_iBuffRowCount = 0;     /* 当前语句行数 */
int G_iBuffColCount = 0;     /* 当前语句列数 */
extern void add_var(char *);  /* 在内存中添加变量 */
void add_buff(char *); /* 在内存中添加语句 */
void yyerror(char *);
%}
/* 使用代变量表示任意字符 */
any  .
%%
#{any}*[\n] {
    add_buff(yytext);
    G_iBuffColCount = 0;
    G_iBuffRowCount++;
} /* 单行注释 */
[\n]    {
    G_iBuffColCount = 0;
    G_iBuffRowCount++;
} /* 回车 */
"for"   {
    yylval.index = FOR - USER_DEF_NUM;
    G_Def[yylval.index].name = "for";
    add_buff(yytext);
    return FOR;
}
"while" {
    yylval.index = WHILE - USER_DEF_NUM;
    G_Def[yylval.index].name = "while";
    add_buff(yytext);
    return WHILE;
}
"if"    {
    yylval.index = IF - USER_DEF_NUM;
    G_Def[yylval.index].name = "if";
    add_buff(yytext);
    return IF;
}
"else"  {
    yylval.index = ELSE - USER_DEF_NUM;
    G_Def[yylval.index].name = "else";
    add_buff(yytext);
    return ELSE;
}
"print" {
    yylval.index = PRINT - USER_DEF_NUM ;
    G_Def[yylval.index].name = "print";
    add_buff(yytext);
    return PRINT;
}
[a-zA-Z][a-zA-Z0-9]* {
    add_var(yytext);
    yylval.index = G_iVarCurIndex;
    add_buff(yytext);
    return VARIABLE;
}
[0-9]+ {
    yylval.val = atof(yytext);
    add_buff(yytext);
    return NUMBER;
}
[0-9]*/.[0-9]+ {
    yylval.val = atof(yytext);
    add_buff(yytext);
    return NUMBER;
}
"++" { yylval.index = ADD_T - USER_DEF_NUM; G_Def[yylval.index].name = "++"; G_Def[yylval.index + 1].name = "++";  add_buff(yytext); return ADD_T; }
"--" { yylval.index = MUS_T - USER_DEF_NUM; G_Def[yylval.index].name = "--"; G_Def[yylval.index + 1].name = "++";  add_buff(yytext); return MUS_T; }
">=" { yylval.index = GE - USER_DEF_NUM;  G_Def[yylval.index].name = ">=";  add_buff(yytext); return GE;}
"<=" { yylval.index = LE - USER_DEF_NUM;  G_Def[yylval.index].name = "<=";  add_buff(yytext); return LE;}
"==" { yylval.index = EQ - USER_DEF_NUM;  G_Def[yylval.index].name = "==";  add_buff(yytext); return EQ;}
"!=" { yylval.index = NE - USER_DEF_NUM;  G_Def[yylval.index].name = "!=";  add_buff(yytext); return NE;}
"&&" { yylval.index = AND - USER_DEF_NUM; G_Def[yylval.index].name = "&&";  add_buff(yytext); return AND;}
"||" { yylval.index = OR - USER_DEF_NUM;  G_Def[yylval.index].name = "||";  add_buff(yytext); return OR; }
[()<>=+/-*/;{}.] {
    yylval.index = *yytext;  /* 存储运算符 */
    add_buff(yytext);
    return *yytext;
}
[\t]    { add_buff(yytext); } /* 去除TAB  */
[ ]     { add_buff(yytext); }  /* 去除空格 */
{any}   { printf("Ignore Unknow Symbol:[%s]/n", yytext); }
%%
void add_buff(char * buff) {
    strcat(G_sBuff[G_iBuffRowCount], buff);
    G_iBuffColCount = G_iBuffColCount + strlen(buff);
}
int yywrap(void) {
    return 1;
}

lexya_e.y

  • lexya_e.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "node.h"
/* 属性操作类型 */
Node * opr(int name, int num, ...);
Node * set_index(int value);
Node * set_content(float value);
/* 树结点操作 */
void NodeFree(Node * p);
float NodeExecute(Node * p);
typedef union {
    float val;  /* 变量值 */
    int index;  /* 用于存放 变量数组索引 或 一元操作符值 或 多元操作符索引 */
    Node *node; /* 结点地址 */
} yystype;
#define YYSTYPE yystype
/* 打印分析调试信息 */
void debug_vsp(YYSTYPE , char * , YYSTYPE *, char * );
void print_stmt();
/* 在内存中添加变量 */
void add_var(char *);
int G_iVarMaxIndex = 0;  /* 变量最大个数 */
int G_iVarCurIndex = -1; /* 变量当前索引 */
struct VarIndex G_Var[MAX_VARS];  /* 变量内存数组 */
void yyerror(char *s);
%}
%union {
    float val; /* 变量值 */
    int index; /* 变量数组索引 */
    Node *node; /* 结点地址 */
};
%token <val> NUMBER
%token <index> VARIABLE
%token PRINT
%token FOR WHILE
%nonassoc IF
%nonassoc ELSE
%left AND OR
%left GE LE EQ NE ‘>‘ ‘<‘
%left ‘+‘ ‘-‘
%left ‘*‘ ‘/‘
%left ADD_T ADD_TT MUS_T MUS_TT
%nonassoc UMINUS
%type <node> stmt stmt_list expr_set expr_setself expr_comp expr
%%
program:
function { exit(0); }
;
function:
function stmt { NodeExecute($2); NodeFree($2); }
| /* NULL */
;
stmt:
‘;‘                 {
    $$ = opr(‘;‘, 2, NULL, NULL); debug_vsp(yyval, ";", yyvsp, "0");
}
| expr_set ‘;‘      {
    $$ = $1; debug_vsp(yyval, "es;", yyvsp, "01");
}
| PRINT expr ‘;‘    {
    $$ = opr(PRINT, 1, $2); debug_vsp(yyval, "p(e);", yyvsp, "401");
}
| PRINT expr_set ‘;‘    {
    $$ = opr(PRINT, 1, $2); debug_vsp(yyval, "p(es);", yyvsp, "401");
}
| FOR ‘(‘ expr_set ‘;‘ expr_comp ‘;‘ expr_set ‘)‘ stmt {
    $$ = opr(FOR, 4, $3, $5, $7, $9); debug_vsp(yyval, "for(es;ec;es) st", yyvsp, "410101010"); }
| WHILE ‘(‘ expr_comp ‘)‘ stmt       {
    $$ = opr(WHILE, 2, $3, $5); debug_vsp(yyval, "while(ec) st", yyvsp, "41010"); }
| IF ‘(‘ expr_comp ‘)‘ stmt %prec IF {
    $$ = opr(IF, 2, $3, $5);    debug_vsp(yyval, "if(ec) st", yyvsp, "41010");    }
| IF ‘(‘ expr_comp ‘)‘ stmt ELSE stmt %prec ELSE       {
    $$ = opr(IF, 3, $3, $5, $7);      debug_vsp(yyval, "if(ec)else st", yyvsp, "4101040");      }
| ‘{‘ stmt_list ‘}‘ { $$ = $2; debug_vsp(yyval, "{stl}", yyvsp, "101"); }
;
stmt_list:
stmt              {
    $$ = $1;  debug_vsp(yyval, "st", yyvsp, "0");  }
| stmt_list stmt  {
    $$ = opr(‘;‘, 2, $1, $2); debug_vsp(yyval, "stl st", yyvsp, "00"); }
;
expr_set:
VARIABLE ‘=‘ expr {
    $$ = opr(‘=‘, 2, set_index($1), $3); debug_vsp(yyval, "v=e", yyvsp, "210"); }
| VARIABLE ‘=‘ expr_setself {
    $$ = opr(‘=‘, 2, set_index($1), $3); debug_vsp(yyval, "v=ess", yyvsp, "210"); }
| expr_setself
;
expr_setself:
ADD_T VARIABLE  {
    $$ = opr(ADD_T, 1, set_index($2));  debug_vsp(yyval, "++v", yyvsp, "42");   }
| MUS_T VARIABLE  {
    $$ = opr(MUS_T, 1, set_index($2));  debug_vsp(yyval, "--v", yyvsp, "42");   }
| VARIABLE ADD_T  {
    $$ = opr(ADD_TT, 1, set_index($1));  debug_vsp(yyval, "v++", yyvsp, "24");  }
| VARIABLE MUS_T  {
    $$ = opr(MUS_TT, 1, set_index($1));  debug_vsp(yyval, "v--", yyvsp, "24");  }
| ‘(‘ expr_setself ‘)‘ { $$ = $2; debug_vsp(yyval, "(ess)", yyvsp, "101");   }
;
expr_comp:
expr ‘<‘ expr   {
    $$ = opr(‘<‘, 2, $1, $3); debug_vsp(yyval, "e<e", yyvsp, "010");    }
| expr ‘>‘ expr   {
    $$ = opr(‘>‘, 2, $1, $3); debug_vsp(yyval, "e>e", yyvsp, "010");    }
| expr GE expr    {
    $$ = opr(GE, 2, $1, $3);  debug_vsp(yyval, "e>=e", yyvsp, "040");   }
| expr LE expr    {
    $$ = opr(LE, 2, $1, $3);  debug_vsp(yyval, "e<=e", yyvsp, "040");   }
| expr NE expr    {
    $$ = opr(NE, 2, $1, $3);  debug_vsp(yyval, "e!=e", yyvsp, "040");   }
| expr EQ expr    {
    $$ = opr(EQ, 2, $1, $3);  debug_vsp(yyval, "e==e", yyvsp, "040");   }
| expr_comp AND expr_comp {
    $$ = opr(AND, 2, $1, $3); debug_vsp(yyval, "ec&&ec", yyvsp, "040"); }
| expr_comp OR expr_comp  {
    $$ = opr(OR, 2, $1, $3);  debug_vsp(yyval, "ec||ec", yyvsp, "040"); }
| ‘(‘ expr_comp ‘)‘       { $$ = $2;                  debug_vsp(yyval, "(ec)", yyvsp, "101");   }
;
expr:
NUMBER            {
    $$ = set_content($1);      debug_vsp(yyval, "f", yyvsp, "3");     }
| VARIABLE        {
    $$ = set_index($1);        debug_vsp(yyval, "v", yyvsp, "2");     }
| ‘-‘ NUMBER %prec UMINUS {
    $$ = set_content(-$2);   debug_vsp(yyval, "-e", yyvsp, "13"); }
| expr ‘+‘ expr   {
    $$ = opr(‘+‘, 2, $1, $3);  debug_vsp(yyval, "e+e", yyvsp, "010"); }
| expr ‘-‘ expr   {
    $$ = opr(‘-‘, 2, $1, $3);  debug_vsp(yyval, "e-e", yyvsp, "010"); }
| expr ‘*‘ expr   {
    $$ = opr(‘*‘, 2, $1, $3);  debug_vsp(yyval, "e*e", yyvsp, "010"); }
| expr ‘/‘ expr   {
    $$ = opr(‘/‘, 2, $1, $3);  debug_vsp(yyval, "e/e", yyvsp, "010"); }
| ‘(‘ expr ‘)‘    {
    $$ = $2;                   debug_vsp(yyval, "(e)", yyvsp, "101");
}
;
//| ‘(‘ expr error        { $$ = $2; printf("ERROR"); exit(0); }
%%
#define SIZE_OF_NODE ((char *)&p->content - (char *)p)
Node *set_content(float value) {
    Node *p;
    size_t sizeNode;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(float);
    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_CONTENT;
    p->content = value;
    return p;
}
Node *set_index(int value) {
    Node *p;
    size_t sizeNode;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(int);

    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_INDEX;
    p->index = value;
    return p;
}
Node *opr(int name, int num, ...) {
    va_list valist;
    Node *p;
    size_t sizeNode;
    int i;
    /* 分配结点空间 */
    sizeNode = SIZE_OF_NODE + sizeof(OpNode) + (num - 1) * sizeof(Node*);

    if ((p = malloc(sizeNode)) == NULL)
        yyerror("out of memory");
    /* 复制内容 */
    p->type = TYPE_OP;
    p->op.name = name;
    p->op.num = num;
    va_start(valist, num);
    for (i = 0; i < num; i++)
        p->op.node[i] = va_arg(valist, Node*);
    va_end(valist);
    return p;
}
/**/
void debug_vsp(YYSTYPE yval, char * info, YYSTYPE * vsp, char * mark) {
#ifdef PARSE_DEBUG
    printf("/n -RULE  0x%x  %s /n ", yval.node, info  );
    int i;
    int ilen = strlen(mark);
    for (i = 1 - ilen; i <= 0; i++) {
        switch (mark[ilen + i - 1]) {
        case ‘0‘:
            printf(" [ 0x%x ", vsp[i].node); //「」
            switch (vsp[i].node->type) {
            case TYPE_CONTENT:
                printf("%g ] ", vsp[i].node->content);
                break;
            case TYPE_INDEX:
                printf("%s ] ", G_Var[vsp[i].node->index].mark);
                break;
            case TYPE_OP:
                if (vsp[i].node->op.name < USER_DEF_NUM)
                    printf("%c ] ", vsp[i].node->op.name);
                else
                    printf("%s ] ", G_Def[vsp[i].node->op.name - USER_DEF_NUM].name);
                break;
            }
            break;
        case ‘1‘:
            printf(" %c ", vsp[i].index);  /* 打印运算符 */
            break;
        case ‘2‘:
            printf(" %s ", G_Var[vsp[i].index].mark);
            break;
        case ‘3‘:
            printf(" %g ", vsp[i].val);
            break;
        case ‘4‘:
            printf(" %s ", G_Def[vsp[i].index].name);
            break;
        }
    }
    printf("/n");
    print_stmt();
#endif
}
void add_var(char *mark) {
    if (G_iVarMaxIndex == 0) {
        strcpy(G_Var[0].mark, mark);
        G_iVarMaxIndex++;
        G_iVarCurIndex = 0;
        return;
    }
    int i;
    for (i = 0; i <= G_iVarMaxIndex - 1; i++) {
        if (strcmp(G_Var[i].mark, mark) == 0) {
            G_iVarCurIndex = i;
            return;
        }
    }
    strcpy(G_Var[G_iVarMaxIndex].mark, mark);
    G_iVarCurIndex = G_iVarMaxIndex;
    G_iVarMaxIndex++;
}
void print_stmt() {
    printf(" -STMT: /n");
    /*
    int i;
    for(i=0;i<=G_iBuffRowCount;i++)
     printf("%s /n",G_sBuff[i]);
    */
    if (G_iBuffColCount == 0)
        printf("  %s /n", G_sBuff[G_iBuffRowCount - 1]);
    else
        printf("  %s /n", G_sBuff[G_iBuffRowCount]);
    printf("/n");
}
void NodeFree(Node *p) {
    int i;
    if (!p) return;
    if (p->type == TYPE_OP) {
        for (i = 0; i < p->op.num; i++)
            NodeFree(p->op.node[i]);
    }
    free (p);
}
void yyerror(char *s) {
//fprintf(stdout, "%s/n", s);
    printf("<Parser Error> Line %d ,Col %d /n", G_iBuffRowCount + 1, G_iBuffColCount + 1);
    printf(" %s/n", G_sBuff[G_iBuffRowCount]);
}
int main(void) {
    yyparse();
    return 0;
}

parser.c

  • parser.c
#include <stdio.h>
#include "node.h"
#include "lexya_e.tab.h"
float NodeExecute(Node *p) {
    if (!p) return 0;
    switch (p->type) {
    case TYPE_CONTENT: return p->content;
    case TYPE_INDEX:   return G_Var[p->index].val;
    case TYPE_OP:
        switch (p->op.name) {
        case WHILE:  while (NodeExecute(p->op.node[0]))NodeExecute(p->op.node[1]);
            return 0;
        case FOR:    NodeExecute(p->op.node[0]);
            while (NodeExecute(p->op.node[1])) {
                NodeExecute(p->op.node[3]);
                NodeExecute(p->op.node[2]);
            }
            return 0;
        case IF:     if (NodeExecute(p->op.node[0]))
                NodeExecute(p->op.node[1]);
            else if (p->op.num > 2)
                NodeExecute(p->op.node[2]);
            return 0;
        case PRINT:  printf("%g\n", NodeExecute(p->op.node[0]));
            return 0;
        case ‘;‘:    NodeExecute(p->op.node[0]);
            return NodeExecute(p->op.node[1]);
        case ‘=‘:    return G_Var[p->op.node[0]->index].val = NodeExecute(p->op.node[1]);
        case UMINUS: return NodeExecute(p->op.node[0]);
        case ‘+‘:    return NodeExecute(p->op.node[0]) + NodeExecute(p->op.node[1]);
        case ‘-‘:    return NodeExecute(p->op.node[0]) - NodeExecute(p->op.node[1]);
        case ‘*‘:    return NodeExecute(p->op.node[0]) * NodeExecute(p->op.node[1]);
        case ‘/‘:    return NodeExecute(p->op.node[0]) / NodeExecute(p->op.node[1]);
        case ‘<‘:    return NodeExecute(p->op.node[0]) < NodeExecute(p->op.node[1]);
        case ‘>‘:    return NodeExecute(p->op.node[0]) > NodeExecute(p->op.node[1]);
        case GE:     return NodeExecute(p->op.node[0]) >= NodeExecute(p->op.node[1]);
        case LE:     return NodeExecute(p->op.node[0]) <= NodeExecute(p->op.node[1]);
        case NE:     return NodeExecute(p->op.node[0]) != NodeExecute(p->op.node[1]);
        case EQ:     return NodeExecute(p->op.node[0]) == NodeExecute(p->op.node[1]);
        case AND:    return NodeExecute(p->op.node[0]) && NodeExecute(p->op.node[1]);
        case OR:     return NodeExecute(p->op.node[0]) || NodeExecute(p->op.node[1]);
        case ADD_T:  return ++G_Var[p->op.node[0]->index].val;
        case MUS_T:  return --G_Var[p->op.node[0]->index].val;
        case ADD_TT: return G_Var[p->op.node[0]->index].val++;
        case MUS_TT: return G_Var[p->op.node[0]->index].val--;
        }
    }
    return 0;
}

input

  • input
k=9;
if((1>1)||(-9>-1))
  for(i=0;i<=9;i=i+1)
    print(i);
else
  if(3>1&&2>1) {
    for(j=-1.1;j<=3;j++)
      print(j);
    for(jdd=1;jdd<=3;++jdd)
      print(jdd);
    while(k<=9) {
      print(k++);
      print(++k);
    }
  }
#test

功能介绍

  • bison -d lexya_e.y
  • lex -d lexya_e.l
  • gcc -g -o parser lex.yy.c lexya_e.tab.c parser.c
  • ./parser < input
  • 以上示例显然是根据《Lex和Yacc应用教程(四).语法树》文中的示例扩展而来。主要演示C语言类似的语法编译方法。支持的功能如下:
    1. 支持整型和浮点型
    2. 支持变量存储,变量名可为多个字符
    3. 支持+-*/()=运算法则
    4. 支持负数及负数运算
    5. 支持变量的自加(++)和自减运算(--),区分前自加减和后自加减
    6. 支持print打印值和变量
    7. 支持for while if else控制结构,并支持控制结构的嵌套
    8. 支持>= <= != ==四种比较运算
    9. 支持&& ||的复合比较运算
    10. 支持对空格和TAB的忽略处理
    11. 支持#的单行注释
    12. 支持{}多重组合
    13. 支持编译错误的具体显示
    14. 支持编译过程的变量堆栈信息打印,便于调试分析
    15. 支持保留字的存储显示。
    16. 支持语法树打印(将在下一篇文章着重说明)
时间: 2024-11-05 21:34:46

Lex Yacc (二) 语法树的相关文章

Lex Yacc (一) 入门

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

使用PHP-Parser生成AST抽象语法树

0.前言 最近项目的流程逐渐清晰,但是很多关键性的技术没有掌握,也只能一步一步摸索. 由于要做基于数据流分析的静态代码分析,所以前端的工作如:词法分析.语法分析必不可少.Yacc和Lex什么的就不再考虑了,查了一天的资料,发现两款比较适合,一款是Java下的ANTLR,另一款是专门做PHP AST生成的PHP-Parser. ANTLR是编译原理领域比较著名的工具了,相对于Yacc和Lex,更加实用.但是对PHP的语法文件只有一个,折腾了半天才生成调通,发现不太适合,对于"$a=1"生

淘宝数据库OceanBase SQL编译器部分 源代码阅读--解析SQL语法树

OceanBase是阿里巴巴集团自主研发的可扩展的关系型数据库,实现了跨行跨表的事务,支持数千亿条记录.数百TB数据上的SQL操作. 在阿里巴巴集团下,OceanBase数据库支持了多个重要业务的数据存储.包含收藏夹.直通车报表.天猫评价等. 截止到2013年4月份.OceanBase线上业务的数据量已经超过一千亿条. 看起来挺厉害的,今天我们来研究下它的源码. 关于OceanBase的架构描写叙述有非常多文档.这篇笔记也不打算涉及这些东西,仅仅讨论OceanBase的SQL编译部分的代码. O

淘宝数据库OceanBase SQL编译器部分 源码阅读--解析SQL语法树

OceanBase是 阿里巴巴集团自主研发的可扩展的关系型数据库,实现了跨行跨表的事务,支持数千亿条记录.数百TB数据上的SQL操作.在阿里巴巴集团 下,OceanBase数据库支持了多个重要业务的数据存储,包括收藏夹.直通车报表.天猫评价等.截止到2013年4月份,OceanBase线上业务 的数据量已经超过一千亿条. 看起来挺厉害的,今天我们来研究下它的源代码.关于OceanBase的架构描述有很多文档,这篇笔记也不打算涉及这些东西,只讨论OceanBase的SQL编译部分的代码. Ocea

Clang之语法抽象语法树AST

语法分析器的任务是确定某个单词流是否能够与源语言的语法适配,即设定一个称之为上下文无关语言(context-free language)的语言集合,语法分析器建立一颗与(词法分析出的)输入单词流对应的正确语法树.语法分析树的建立过程主要有两种方法:自顶向下语法分析法和自底向上分析法.AST作为语法分析树(parse tree)的一种简写方式,它独立于具体编程语言(C++.Java.C等),而且与语法分析树的建立过程无关(自顶向下和自底向上逻辑等价),是联系编译器前端.后端的重要接口.Clang的

形式语言之语言和语法树

1,句型,句子和语言: 从文法的开始符号出发,利用其中的产生式逐步推导出待分析的符号串,如果能推导出这个符号串则表明此符号串是该文法的一个句型或句子.否则便不是.句型与句子的区别在于符号串是否全部由终结符构成,如果经过多步推导出的符号串全部由终结符构成就是句子,否则便是句型(句子一定是句型,句型不一定是句子).文法的所有的句子的集合就是该文法所对应的语言. 2,描述形式语言的两种方法 1,枚举(描述有穷的语言集合) 2,文法(描述无穷的语言集合) 3,文法和语言的关系:文法是用来生成(定义)语言

Atitti. 语法树AST、后缀表达式、DAG、三地址代码

抽象语法树的观点认为任何复杂的语句嵌套情况都可以借助于树的形式加以描述.确实,不得不承认应用抽象语法树可以使语句翻译变得相对容易,它很好地描述了语句.表达式之间的联系.不过,由于Neo Pascal并不会显式构造抽象语法树,所以不得不借助于其他数据结构实现.根据先前的经验,栈结构就是不二之选. DAG(有向无环图) 后缀表达式:也称为逆波兰表达式,这种形式简单明晰,便于存储.在处理表达式翻译时,后缀表达式有着其他形式无法比拟的优势.不过,由于后缀表达式的应用领域比较单一,所以很少独立作为一个实际

AST 抽象语法树

提起 AST 抽象语法树,大家可能并不感冒.但是提到它的使用场景,也许会让你大吃一惊.原来它一直在你左右与你相伴,而你却不知. 一.什么是抽象语法树 在计算机科学中,抽象语法树(abstract syntax tree 或者缩写为 AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码.树上的每个节点都表示源代码中的一种结构. 之所以说语法是「抽象」的,是因为这里的语法并不会表示出真实语法中出现的每个细节. 二.使用场景 JS 反编译,语法

复杂网络,抽象语法树

近期看了一些软件抽象为复杂网络,以及软件抽象成静态语法树的文章.做一个小总结. 1.复杂网络是由大量的边和点组成的,边点都可以有类型,加权值,边还可以有方向.如何计算边和点的权值是一个关键点,如何在不执行代码的情况下确定边的方向,目前不确定是否已经解决. 有许多工具,可以直接扫描软件源代码,抽象为复杂网络.然而我还没亲身实践,且做个记录. Dependency Finder分析编译后的java代码,能够提取依赖图. Doxygen是使用c++开发的基于源代码注释的文档生成工具.但是这个注释,是人