在flex&bison的基础上利用符号表进行语义分析

如何编译

两种方法:
(1)使用make命令:先将要执行的所有命令写入到Makefile文件中,然后执行make命令,这就相当于将Makefile中的所有命令都执行完毕了,在终端可以清楚地看到系统每执行一条命令的结果,如果有错或者有警告都会输出。make执行完之后,就生成a.out文件,使用cat filename|./a.out就可以对filename中的文件就行语义分析了。
当文件有更新时,只需要执行以下make即可。
(2)这种是最笨的方法,就是不写Makefile文件,每次都是逐条去执行编译命令,文件有更新之后也要逐条执行,这种效率是最低的。make命令的出现就是为了提高编译效率的,有关make的知识点可以自行百度。

下面是第一种编译方法的具体过程:

0,Makefile——编译文件

程序总共包含4个文件gramtree_v1.h gramtree_v1.c gramtree.l gramtree_v1.y
gramtree_v1.h gramtree_v1.c定义和实现了创建语法树和遍历语法树的函数
gramtree.l是flex词法分析模块
gramtree_v1.y是bison语法分析模块

编译时使用Makefile文件,编写文件内容,vim Makefile

result:gramtree_v1.y gramtree.l gramtree_v1.h
    bison -d  gramtree_v1.y
    flex gramtree.l
    gcc gramtree_v1.tab.c lex.yy.c gramtree_v1.c 

编译过程如下:

[root@localhost flex]# make
[root@localhost flex]# cat input3.c|./a.out 

先执行make命令,这代表Makefile的编译步骤全都执行完毕了。然后使用
cat filename|./a.out就可以对filename中的代码进行语义分析。

/*
*Name:gramtree_v1.h
*Author:WangLin
*Created on:2015-10-03
*Version 2.0
*Function:定义语法树&变量符号表&函数符号表&数组符号表&结构体符号表
*/
/*来自于词法分析器*/
extern int yylineno;//行号
extern char* yytext;//词
void yyerror(char *s,...);//错误处理函数

/*抽象语法树的结点*/
struct ast
{
    int line; //行号
    char* name;//语法单元的名字
    int tag;//1为变量,2为函数,3为常数,4为数组,5为结构体
    struct ast *l;//左孩子
    struct ast *r;//右孩子
    char* content;//语法单元语义值(int i;i是一个ID,ID的content是‘i’)
    char* type;//语法单元数据类型:主要用于等号和操作符左右类型匹配判断
    float value;//常数值(记录integer和float的数据值)
};

/*变量符号表的结点*/
struct var
{
    char* name;//变量名
    char* type;//变量类型
    struct var *next;//指针
}*varhead,*vartail;

/*函数符号表的结点*/
struct func
{
    int tag;//0表示未定义,1表示定义
    char* name;//函数名
    char* type;//函数类型
    char* rtype;//实际返回值类型
    int pnum;//形参数个数
    struct func *next;
}*funchead,*functail;
int rpnum;//记录函数实参个数

/*数组符号表的结点*/
struct array
{
    char* name;//数组名
    char* type;//数组类型
    struct array *next;
}*arrayhead,*arraytail;

/*结构体符号表的结点*/
struct struc
{
    char* name;//结构体名
    char* type;//数组类型
    struct struc *next;
}*struchead,*structail;

/*=====抽象语法树========================*/
/*构造抽象语法树,变长参数,name:语法单元名字;num:变长参数中语法结点个数*/
struct ast *newast(char* name,int num,...);

/*遍历抽象语法树,level为树的层数*/
void eval(struct ast*,int level);

/*=====变量符号表========================*/
/*建立变量符号表*/
void newvar(int num,...);

/*查找变量是否已经定义,是返回1,否返回0*/
int  exitvar(struct ast*tp);

/*查找变量类型*/
char* typevar(struct ast*tp);

/*=================函数符号表==============*/
/*建立函数符号表,flag:1表示变量符号表,2表示函数符号表,num是参数个数*/
void newfunc(int num,...);

/*查找函数是否已经定义,是返回1,否返回0*/
int extitfunc(struct ast*tp);

/*查找函数类型*/
char* typefunc(struct ast*tp);

/*查找函数的形参个数*/
int pnumfunc(struct ast*tp);

/*=================数组符号表==============*/
/*建立数组符号表*/
void newarray(int num,...);

/*查找数组是否已经定义,是返回1,否返回0*/
int extitarray(struct ast*tp);

/*查找数组类型*/
char* typearray(struct ast*tp);

/*=================结构体符号表==============*/
/*建立结构体符号表*/
void newstruc(int num,...);

/*查找结构体是否已经定义,是返回1,否返回0*/
int extitstruc(struct ast*tp);


/*
*Name:gramtree_v1.c
*Author:WangLin
*Created on:2015-10-03
*Function:实现变长参数构造树&遍历树函数&错误处理函数,yyparse()启动文法分析
*/
# include<stdio.h>
# include<stdlib.h>
# include<stdarg.h>//变长参数函数所需的头文件
# include"gramtree_v1.h"

int i;
struct ast *newast(char* name,int num,...)//抽象语法树建立
{
    va_list valist; //定义变长参数列表
    struct ast *a=(struct ast*)malloc(sizeof(struct ast));//新生成的父节点
    struct ast *temp=(struct ast*)malloc(sizeof(struct ast));
    if(!a)
    {
        yyerror("out of space");
        exit(0);
    }
    a->name=name;//语法单元名字
    va_start(valist,num);//初始化变长参数为num后的参数

    if(num>0)//num>0为非终结符:变长参数均为语法树结点,孩子兄弟表示法
    {
        temp=va_arg(valist, struct ast*);//取变长参数列表中的第一个结点设为a的左孩子
        a->l=temp;
        a->line=temp->line;//父节点a的行号等于左孩子的行号
        if(num==1)//只有一个孩子
        {
            a->content=temp->content;//父节点的语义值等于左孩子的语义值
            a->tag=temp->tag;
        }
        else //可以规约到a的语法单元>=2
        {
            for(i=0; i<num-1; ++i)//取变长参数列表中的剩余结点,依次设置成兄弟结点
            {
                temp->r=va_arg(valist,struct ast*);
                temp=temp->r;
            }
        }
    }
    else //num==0为终结符或产生空的语法单元:第1个变长参数表示行号,产生空的语法单元行号为-1。
    {
        int t=va_arg(valist, int); //取第1个变长参数
        a->line=t;
        if(!strcmp(a->name,"INTEGER"))//函数符号表头指针a->name,"INTEGER"))
        {
            a->type="int";
        }
        else if(!strcmp(a->name,"FLOAT"))
        {
            a->type="float";
            a->value=atof(yytext);
        }
        else
        {
            char* s;
            s=(char*)malloc(sizeof(char* )*40);
            strcpy(s,yytext);//存储词法单元的语义值
            a->content=s;
        }
    }
    return a;
}
void eval(struct ast *a,int level)//先序遍历抽象语法树
{
    if(a!=NULL)
    {
        for(i=0; i<level; ++i)//孩子结点相对父节点缩进2个空格
            printf("  ");
        if(a->line!=-1)  //产生空的语法单元不需要打印信息
        {
            printf("%s ",a->name);//打印语法单元名字,ID/TYPE/INTEGER要打印yytext的值
            if((!strcmp(a->name,"ID"))||(!strcmp(a->name,"TYPE")))printf(":%s ",a->content);
            else if(!strcmp(a->name,"INTEGER"))printf(":%d",a->type);
            else
                printf("(%d)",a->line);
        }
        printf("\n");
        eval(a->l,level+1);//遍历左子树
        eval(a->r,level);//遍历右子树
    }
}
/*====(1)变量符号表的建立和查询================*/
voi
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值