编译原理课程设计符号表部分

《编译原理》课程设计实验报告

  • 姓名:xx
  • 班级:1617
  • 学号:1617
  • 分工部分:符号表

##目录

文章目录

  • 《编译原理》课程设计实验报告
    • 主要内容
      • 一、设计符号表
      • 二、设计词法分析器
    • 三、语法分析与中间代码产生器
      • 四、中间代码生成
    • 主要代码
      • lexcial.l
      • grammar.y
      • analyze.h
      • analyze.c
      • symtab.h
      • symtab.c
      • main.c

主要内容

词法分析程序->语法分析程序->语义分析程序->中间代码生成程序

一、设计符号表

实验内容:
确定符号表的组织方式,一般应包括名字栏和信息栏,其中名字栏作为关键字。
(1)查找:根据给定的名字,在符号表中查找其信息。如果该名字在符号表中不存在,则将其加入到符号表中,否则返回指向该名字的指针;
(2)删除:从符号表中删除给定名字的表项。
实验思路:
生成符号表:读入词法中的每一个token,遍历所有的token,在遍历的过程当中对token的属性进行检测。检测过程中判断当前token所处的位置,如果当前token是函数名,检查表中是否有该函数,如果没有加入到符号表中;如果是对函数进行调用,检查符号表,若表中不存在该函数或者未经声明就进行调用,进行报错处理;如果存在该函数并判断该函数名中的变量是否存在符号表中,如果是首次调用则将其加入符号表中。如果当前token为变量名,分为定义的调用的处理。如果变量为变量的定义,根据变量的定义只能存在在函数参数的小括号内来判断是否合法;如果变量是调用,检查表中是否存在,若不存在,进行报错处理。
实验过程:

struct domainNode;
typedef struct domainNode DomainNode;

searchSymTab()用于查找和插入符号表,并协助类型检查。
参数说明:
name是当前的变量名,varLineno是当前行号,用于错误提示,type为变量声明时需要填入符号表的符号类型,arrayLength为数组长度,为-123代表非数组,其他的小于0的值报错。
返回值:正确返回时为arrayLength,遇错为-1;

int insertSymTab( char * name, int dep, int depnum, int varLineno, int type, int arrayLength )
{	
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	sprintf(depthstr, "%d", dep);
	sprintf(depthnumstr, "%d", depnum);
	char namet[100];
	strcpy(namet, name);
	strcat(namet, depthstr);
	strcat(namet, cut);
	strcat(namet, depthnumstr);
	int h = hash(namet);
	Symbol s =  hashTable[h];
	/* 遍历符号表,查找是否有同名项 */
	while ((NULL != s)&&(0 != strcmp(name,s->name)))
		s = s->next;
	if(NULL == s)		/* 该符号不在符号表中,将其加入符号表,返回正确 */
	{	s = (Symbol) malloc(sizeof(struct SymbolRec));
		s->name = name;
		s->varLineno = varLineno;
		s->type = type;
		// debug fprintf(listing, "insertSymtab:%s\n", namet);
		if (0 > arrayLength)
		{	fprintf(listing,
				"Error:line %d:数组长度要大于0.\n", varLineno);
			Error = TRUE;
		}
		s->arrayLength = arrayLength;
		int tempArray[arrayLength];
		s->array.intArray = tempArray;
		s->next = hashTable[h];
		hashTable[h] = s;
		return arrayLength;
	}
	else	/* 若该符号在符号表中,报错 */
	{	fprintf(listing,
			"Error:line %d:变量 %s 已有同名变量声明在第 %d 行.\n",
				varLineno, name, s->varLineno);
		// debug fprintf(listing, "%d-%d  %s\n", dep, depnum, namet);
		Error = TRUE;
	}
	return -1;	//返回值为-1表示插入过程中出错。
}

查找符号表,若找不到则返回-1,否则返回变量的arrayLength,arrayLength为0表示非数组,arrayLength非0表示下标的值。

int lookupSymTab( char * name, DomainNode * domain, int int_val, double real_val, int varLineno)//查找符号表
{	
	int flag = 0;
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	char namet[100];
	while (domain)
	{
		if (domain->depth == -1 && domain->depthnum == -1) //depth的变化在语法树生成中变化
		{
			domain = domain->pre; //返回上一个域,初始为-1,然后递归嵌套寻找。
			continue;
		}
		sprintf(depthstr, "%d", domain->depth);
		sprintf(depthnumstr, "%d", domain->depthnum);
		strcpy(namet, name);
		strcat(namet, depthstr);
		strcat(namet, cut);
		strcat(namet, depthnumstr);
		int h = hash(namet);
		Symbol s =  hashTable[h];
		while ((s != NULL)&&(0 != strcmp(name,s->name)))
			s = s->next;
		if (s != NULL)
		{
			if ((int_val != -1) || (real_val != -1))
			{	
				if (real_val != -1)
					s->value.real_val = real_val;
				else
					s->value.int_val = int_val;
			}
			return s->arrayLength;
		}
		domain = domain->pre;
	}
	fprintf(listing,
		"Error:line %d:变量 %s 未声明.\n",varLineno, name);

	Error = TRUE;
	return -1;
	
}

参数type为0时,直接返回变量在符号表中的类型;type不为0时,检查变量名的类型与传入的type是否一致,一致返回0,不一致返回1。

int checkType(char * name, DomainNode * domain, int type, int varLineno)//检查类型。
{	
	int flag = 0;
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	char namet[100];
	while (domain)
	{
		if (domain->depth == -1 && domain->depthnum == -1) //在域中寻找符号TYPE是否出现
		{
			domain = domain->pre; 
			continue;
		}
		sprintf(depthstr, "%d", domain->depth);
		sprintf(depthnumstr, "%d", domain->depthnum);
		strcpy(namet, name);
		strcat(namet, depthstr);
		strcat(namet, cut);
		strcat(namet, depthnumstr);
		int h = hash(namet);
		Symbol s =  hashTable[h];
		while ((NULL != s)&&(0 != strcmp(name,s->name)))
			s = s->next;
		if(NULL != s)
		{	
			if (type != 0)
			{	if (type != s->type)
				{	fprintf(listing,
						"Error:line %d:变量 %s 类型不正确.",s->varLineno, name);
					Error = TRUE;
					return 1;
				}
				else
					return 0;
			}
			else
				return s->type;
			flag = 1;
			break;
		}
		domain = domain->pre;
	}
	if (flag == 0)
		{
			fprintf(listing,
				"Error:line %d:变量 %s 未声明.\n",varLineno, name);
			Error = TRUE;
			return -1;
		}
}

printSymTab()打印符号表,验证符号表是否正确构造。

void printSymTab(FILE * listing)
{	int i = 0;
	
	fprintf(listing,"\t  符号名      类型   是否为数组  声明时行号 \n");

	Symbol s = hashTable[i];
	while(i++ != SIZE)
	{	if(s != NULL)
		{	fprintf(listing,"\t   %-11s",s->name);
			switch(s->type)
			{	case Int:
					fprintf(listing, "Int ");
					break;
				default:
					break;
			}
			if(0 == s->arrayLength)
			{	fprintf(listing,"      0");
				fprintf(listing,"            %d \n", s->varLineno);
			}
			else
			{	fprintf(listing,"      %d",s->arrayLength);
				fprintf(listing,"            %d \n", s->varLineno);
			}
		}
		s = hashTable[i];
	}

以下为解释执行时所用的函数,分别为:得到变量的值,更新变量的值,得到数组元素的值,更新数组元素的值。

	double getValue(char * name)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	return (double)s->value.int_val;
}
void updateValue(char * name, int int_val, double real_val)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	s->value.int_val = int_val;
	return;
}
double getArray(char * name, int index)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	return (double)s->array.intArray[index];//返回
}
void updateArray(char * name, int index, int int_val, double real_val)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	s->array.intArray[index] = int_val;
	return;
}

二、设计词法分析器

实验内容:
设计各单词的状态转换图,并为不同的单词设计种别码。
(1)具备预处理功能。将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
(2)能够拼出语言中的各个单词;
(3)将拼出的标识符填入符号表;
(4)返回(种别码, 属性值)。
实验思路:
词法分析阶段是编译原理的第一个过程。这个阶段的任务是将字符一个一个的读入词法分析器,根据构词规则识别符号。其中构词规则我们借用状态机进行不同程序词法的匹配。
预处理:将源代码中多于空格和注释去掉,通过检验注释中的"/"的数量和匹配的种类,通过标志位进行标记,同时将处理后的文本存入新的文件当中。
词法分析:利用状态机进行每个单词的=按照规则进行匹配,词法分析程序打开源文件,读取文件内容,直至遇上文件结束符,然后读取结束。接下来就要对源文件从头到尾进行扫描了,从头开始扫描,这个时候扫描程序首先要询问当前的字符是不是空格,若是空格,则继续扫描下一个字符,直至不是空格。然后询问这个字符是不是字母,若是则进行标识符和保留字的识别;若这个字符为数字,则进行数字的判断。否则,依次对这个字符可能的情况进行判断(界符和运算符),若将所有可能都走了一遍还是没有知道它是谁,则认定为错误符号,输出该无法识别error,程序结束。每次成功识别了一个单词后,单词都会存在数组中,然后字符指针往后移,进行下一个单词的识别。
主控程序需要负责对每次识别的种别码进行判断,对于不同的单词种别做出不同的反应,直至文件结束。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYJXWVKb-1584672654929)(C:\Users\Lenovo\Desktop\e6b33a6041be654c31d95bc37529031.jpg)]

C语言常用操作符:
1.比较操作符:< <= > >= == =!
3.运算操作符:+,-,*,/
4.句末操作符: ;
5.结构分隔符:(),{},[]
6.关键字:else,if,int,return,void,while
实验过程:

三、语法分析与中间代码产生器

实验内容:
要求用预测分析法、算符优先分析法、SLR分析法,实现对表达式、各种说明语句、控制语句进行语法分析。
若语法正确,则用语法制导翻译法进行语义翻译:对说明语句,要求将说明的各符号记录到相应符号表中;对可执行语句,应产生出四元式中间代码并填写到三地址码表中;
若语法错误,要求指出出错性质和出错位置(行号)。出错处理应设计成一个出错处理子程序。

实验思路:
该部分实验使用flex和bison进行语法制导翻译,具体思路及过程见实验过程部分。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qz8d4hOS-1584672654931)(C:\Users\Lenovo\Desktop\e96373e767b561801bc413c251ea821.jpg)]
语义分析的内容:
实验过程:
1.将flex.exe加入程序所在文件夹中
2.用文本编译器编写flex文件,利用flex文件生成相应的.yy.c文件,代码如下:
在代码中,先定义正则表达式,也就是对letter,digit,专用符号,空格今行说明,然后在转换规则中定义是识别规则的代码。完成词法分析以后就可以将获取的词用于语法分析。
3.在文本编译器中编译相应的bison文件,在每个生成式后面加上语法制导翻译。

四、中间代码生成

实验内容:
可生成基本的四元式表示的中间代码,也可以生成虚拟机规定的汇编语言代码
实验内容:
根据以上过程打印输出中间代码
实验过程:
暂无

主要代码

lexcial.l


%option noyywrap
%{
#include "globals.h"
#include "util.h"
#include "scan.h"
#include "grammar.tab.h"
%}

digit		[0-9]
letter		[a-zA-Z]
ID 			{letter}({digit}|{letter})*
NUM 		{digit}{digit}*
whitespace	[ \t]*

%%

"if"		{ return IF;}
"else"		{ return ELSE;}
"while"		{ return WHILE;}
"int"		{ yylval.dataType = Int; return INT;} 
"void"		{ yylval.dataType = Void; return VOID;}
"return"	{ return RETURN;}


{ID}			{ yylval.idName = copyString(yytext); return ID;}
{NUM}		{ yylval.intval = atoi(yytext); return NUM;}
{whitespace}	{/*Do nothing.*/}

"+"		{ return PLUS;}
"-"		{ return SUB;}
"*"		{ return MUL;}
"/"		{ return DIV;}
"<"		{ return LT;}
">"		{ return GT;}
"<="	{ return LET;}
">="	{ return GET;}
"=="	{ return ET;}
"!="	{ return NET;}
"&&"	{ return AND;}
"||"	{ return OR;}

"="		{ return ASSIGN;}
"("		{ return LPAREN;}
")"		{ return RPAREN;}
";"		{ return SEMI;}
"{"		{ return LBRACE;}
"}"		{ return RBRACE;}
"["		{ return LBRACKET;}
"]"		{ return RBRACKET;}
","		{ return COMMA;}

"//"	{ char c = input();
		  while(c != '\n')
		  {	if (c == EOF) break;
		  	c = input();
		  }
		  lineno++;
		}
"/*"	{	char c;
			int flag = 1;
			do
			{	c = input();
				entry1:
				if (c == EOF) break;
				if (c == '\n') lineno++;
				if (c == '*')
				{	c = input();
					if (c == '/')
						flag = 0;
					else
						goto entry1;
				}
			} while (flag);
		}
\n		{lineno++;}
.		{yyerror("Mystery character \n", yytext);return ERROR;}

%%
/* 用于语法分析时初始化词法分析接口 */
void iniLexer(void)
{
	static int firstTime = TRUE;
	lineno = 0;
	if (firstTime)
	{	firstTime = FALSE;
		lineno++;
		yyin = source;
		yyout = listing;
	}
}

grammar.y


/*预计有1个移进/归约冲突*/
%expect 1
%{

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"

static TreeNode * savedTree; /* stores syntax tree for later return */

//最大递归深度10,也就是最大嵌套深度
#define MAXDEPTH 10

int Depth;
int DepthNum[MAXDEPTH];

%}

%union{
	struct treeNode * node;
	int intval;
	double realval;
	char * idName;
	int operatorType;
	int dataType;
}
%token  NUM
%token  ID
%token  PLUS SUB LT GT LET GET ET NET AND OR MUL DIV
%token  INT VOID

/* 优先级声明 */
%right ASSIGN
%left PLUS SUB
%left MUL DIV
%nonassoc LT GT LET GET ET NET AND OR
%nonassoc UMINUS
/* 声明文法中用到的tokens */
%token IF ELSE WHILE MAIN RETURN
%token LPAREN RPAREN SEMI LBRACE RBRACE LBRACKET RBRACKET COMMA
%token ASSIGN
%token NEWLINE ERROR

%type  decl_list stat params params_list local_decl stat_list fun_decl arg_list 
%type  sele_stmt decl compound_stmt iter_stmt var_decl exp_stmt return_stmt call if_last_stmt
%type  exp factor param var simp_exp add_exp term args
%type  addop mulop relop
%type  type-specifier

%start program

%% /* CM文法 */

program		: decl_list { savedTree = $1;}  /*static TreeNode * savedTree;*/
			;
decl_list	:	{ $$ = NULL; } 
			| decl_list decl /* $$代表产生式左部的符号 */
				{	
					TreeNode * t = $1;/* $1代表产生式右边的第一个符号,以此类推 */
					if (t != NULL)
					{	while (t->sibling != NULL){ t = t->sibling;}	/*兄弟节点*/
						t->sibling = $2;
						$$ = $1;
					}
					else $$ = $2;
				}
			;
decl 		: var_decl { $$ = $1; }
			| fun_decl { $$ = $1; }
			| error { $$ = NULL; }
			;
var_decl	: type-specifier ID SEMI /*例如 int a ;*/
				{	
					$$ = newStmtNode(DeclK);
					$$->attr.name = $2;
					$$->depth = Depth;/*表示作用域*/
					$$->depthnum = DepthNum[Depth];
					/* 数组长度为0代表非数组 */
					$$->arrayLength = 0;
					$$->type = $1;/*由type-specifier*/
					$$->lineno = lineno;
				}
			| type-specifier ID LBRACKET NUM RBRACKET SEMI /*数组*/
				{	$$ = newStmtNode(DeclK);
					$$->attr.name = $2;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->arrayLength = $4;
					$$->type = $1;
					if($$->type == Int) {
						int int_array_temp[$4];
						$$->array.intArray = int_array_temp;
					}
					$$->lineno = lineno;
				}
			;
type-specifier	/* 变量类型 */
			: INT 	{ $$ = $1; }
			| VOID  { $$ = $1; }
			;
fun_decl	: type-specifier ID /*函数,作用域加一*/
				{
					Depth = Depth+1; 
					DepthNum[Depth] = DepthNum[Depth]+1;
				}
			  LPAREN params RPAREN /*左括号 参数 右括号 */
				{
					$$ = newStmtNode(FuncK);
					$$->type = $1;
					$$->attr.name = $2;
					$$->child[0] = $5	;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];

				}
			| compound_stmt 
				{ 
					$$ = $1; 
					Depth = Depth-1;
				}
			; 
params		: VOID { $$ = NULL; }
			| params_list { $$ = $1; }
			;
params_list	: params_list COMMA param
				{
					TreeNode *t = $1;
					if (t != NULL)
					{
						while (t->sibling != NULL) t = t->sibling;
						t->sibling = $3;
					}
					else $$ = $3;
				}
			| param { $$ = $1; }
			;
param 		: type-specifier ID
				{
					$$ = newStmtNode(ParmK);
					$$->attr.name = $2;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					
					$$->arrayLength = 0;
					$$->type = $1;
					$$->lineno = lineno;
				}
			| type-specifier ID LBRACKET RBRACKET
				{
					$$ = newStmtNode(ParmK);
					$$->attr.name = $2;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->arrayLength = -1;
					$$->type = $1;
					$$->lineno = lineno;
				}
			;
compound_stmt
			: LBRACE local_decl stat_list RBRACE
				{
					$$ = newStmtNode(CompoundK);
					$$->child[0] = $2;
					$$->child[1] = $3;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;
				}
			;
local_decl	: { $$ = NULL; }
			| local_decl var_decl
				{	
					TreeNode * t = $1;
					if (t != NULL)
					{	
						while (t->sibling != NULL){ t = t->sibling;}
						t->sibling = $2;
						$$ = $1;
					}
					else $$ = $2;
				}
			;
stat_list	: { $$ = NULL; }
			| stat_list stat
				{	
					TreeNode * t = $1;
					if (t != NULL)
					{	
						while (t->sibling != NULL){ t = t->sibling;}
						t->sibling = $2;
						$$ = $1;
					}
					else $$ = $2;
				}
			;
stat 		: exp_stmt {$$ = $1;}
			| compound_stmt {$$ = $1;}
			| sele_stmt {$$ = $1;}
			| iter_stmt {$$ = $1;}
			| return_stmt {$$ = $1;}
			| error {$$ = NULL;}
			;
exp_stmt	: exp SEMI {$$ = $1;}
			| SEMI {$$ = NULL;}
			;
sele_stmt   : IF
				{
					Depth++;
					DepthNum[Depth]++;
				} 
			  if_last_stmt
			  	{
			  		$$ = $3;
			  	}
			;
if_last_stmt: LPAREN exp RPAREN stat
				{	
					$$ = newStmtNode(IfK);
					$$->child[0] = $2;
					$$->child[1] = $4;
					$$->child[2] = NULL;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;
					Depth--;
				}
			| LPAREN exp RPAREN stat ELSE stat
				{	
					$$ = newStmtNode(IfK);
					$$->child[0] = $2;
					$$->child[1] = $4;
					$$->child[2] = $6;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;
					Depth--;
				}
			;
iter_stmt	: WHILE
				{
					Depth++;
					DepthNum[Depth]++;
				} 
			  LPAREN exp RPAREN stat
				{	$$ = newStmtNode(WhileK);
					$$->child[0] = $4;
					$$->child[1] = $6;
					$$->lineno = lineno;
					Depth--;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth]-1;
				}
			;
return_stmt	: RETURN SEMI 
				{
					$$ = newStmtNode(ReturnK);

					$$->child[0] = NULL;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;
					
				}
			| RETURN exp SEMI
				{
					$$ = newStmtNode(ReturnK);
					$$->child[0] = $2;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;

				}
			;
exp 		: var ASSIGN exp
				{
					$$ = newStmtNode(AssignK);
					$$->child[0] = $1;
					$$->child[1] = $3;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
				}
			| simp_exp {$$ = $1;}
			;
var 		: ID
				{
					$$ = newExpNode(IdK);
					$$->attr.name = $1;
					//	child[0] is NULL means this is not array;
					$$->child[0] = NULL;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
				}
			| ID LBRACKET exp RBRACKET
				{
					$$ = newExpNode(IdK);
					$$->attr.name = $1;
					//	child[0] not NULL means x in array[x]
					$$->child[0] = $3;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
				}
			;
simp_exp 	: add_exp relop add_exp
				{
					$$ = newExpNode(OpK);
					$$->child[0] = $1;
					$$->child[1] = $3;
					$$->attr.op = $2;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
				}
			| add_exp { $$ = $1; }
			;
relop 		: LET { $$ = LET; }
			| LT { $$ = LT; }
			| GT { $$ = GT; }
			| GET { $$ = GET; }
			| ET { $$ = ET; }
			| NET { $$ = NET; }
			;
add_exp 	: add_exp addop term
				{
					$$ = newExpNode(OpK);
					$$->child[0] = $1;
					$$->child[1] = $3;
					$$->attr.op = $2;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
				}
			| term {$$ = $1;}
			;
addop		: PLUS { $$ = PLUS; }
			| SUB { $$ = SUB; }
			;
term		: term mulop factor
				{
					$$ = newExpNode(OpK);
					$$->child[0] = $1;
					$$->child[1] = $3;
					$$->attr.op = $2;
					$$->lineno = lineno;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					
				}
			| factor {$$ = $1;}
			;
mulop 		: MUL { $$ = MUL; }
			| DIV { $$ = DIV; }
			;
factor 		: LPAREN exp RPAREN {$$ = $2;}
			| var {$$ = $1;}
			| call {$$ = $1;}
			| NUM 
				{	
					$$ = newExpNode(IntValueK);
					$$->value.int_val = $1;
					$$->type = Int;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					$$->lineno = lineno;
				}
			;
call 		: ID LPAREN args RPAREN
				{
					$$ = newExpNode(CallK);
					
					$$->attr.name = $1;
					$$->child[0] = $3;
					$$->depth = Depth;
					$$->depthnum = DepthNum[Depth];
					
				}
			;
args 		: {$$ = NULL;}
			| arg_list {$$ = $1;}
			;
arg_list 	: arg_list COMMA exp
				{
					TreeNode *t = $1;
					if (t != NULL)
					{
						while (t->sibling != NULL) t = t->sibling;
						t->sibling = $3;
					}
					else $$ = $3;
				}
			| exp {$$ = $1;}
			;

%%

int yyerror(char * message)
{
	fprintf(listing,"Syntax error at line %d: %s\n",lineno,message);
	Error = TRUE;
return 0;
}
/* 与主函数交互的语法分析函数 */
TreeNode * parse(void)
{	iniLexer();
	yyparse();
	return savedTree;
}

analyze.h


#ifndef _ANALYZE_H_
#define _ANALYZE_H_

/*	buildSymtab()先序遍历语法树,构造符号表。
 */
void buildSymTab(TreeNode *);

/*	checkNode()为类型检查。
	返回值为type.
	*/
int checkNode(TreeNode *);


#endif

analyze.c


#include "globals.h"
#include "symtab.h"
#include "analyze.h"
#include "domain.h"

/* 建立域的关系链表 */
static void beforeBFS(TreeNode *tree)
{
	int n = 0;
	
	DomainNode *rootDomainNode = (DomainNode *)malloc(sizeof(DomainNode));
	rootDomainNode->pre = NULL;
	rootDomainNode->depth = -1;
	rootDomainNode->depthnum = -1;
	while (tree)
	{
		// debug fprintf(listing, "GOINBFS%d\n", ++n);
		// debug fprintf(listing, "tree:%s:%d\n", tree->attr.name,tree);
		BFS(tree, rootDomainNode);
		tree = tree->sibling;
	}
}

void BFS(TreeNode * tree, TreeNode *root)//广度优先遍历
{
	// debug fprintf(listing, "BFS:\n");
	TreeNode *queue[100000];
	queue[1] = tree;
	DomainNode *nowdomain = (DomainNode *)malloc(sizeof(DomainNode));
	tree->domain = nowdomain;
	nowdomain->pre = root;
	nowdomain->depth = tree->depth;
	nowdomain->depthnum = tree->depthnum;
	int head = 0, tail = 1;
	while (head < tail)
	{
		tree = queue[++head];
		for (int i = 0; i<3; i++)
		{
			if (tree->child[i] != NULL)
			{
				TreeNode * now = tree->child[i];
				while (now)
				{
					
					queue[++tail] = now;

					if (!(now->depth == tree->depth && now->depthnum == tree->depthnum))
					{

						if (now->domain == NULL)
						{

							DomainNode *nowdomain = (DomainNode *)malloc(sizeof(DomainNode));

							now->domain = nowdomain;
							nowdomain->pre = tree->domain;
							nowdomain->depth = now->depth;
							nowdomain->depthnum = now->depthnum;
							
						}
					}
					else
					{
						now->domain = tree->domain;
					}
					now = now->sibling;
				}
				
			}
		}
	}

}

/*	traverse()传入一个语法树节点,再传入一个遍历树的函数的指针
	这样既可以先序遍历,也可以后序遍历。
 */
static void traverse( TreeNode * tree,
               void (* preProc) (TreeNode *),
               void (* postProc) (TreeNode *) )
{	if (tree != NULL)
	{	
		preProc(tree);
		int i;
		for (i=0; i < MAXCHILDREN; i++)
			traverse(tree->child[i],preProc,postProc);
		postProc(tree);
		traverse(tree->sibling,preProc,postProc);
	}
}

/*	nullProc()为traverse提供空函数指针,以便只执行一种遍历
 */
static void nullProc(TreeNode * tree)
{	if (tree==NULL) return;
	else return;
}

/*	insertNode()将节点中的变量插入符号表,
	并检查变量是否曾被声明。
 */
static void insertNode(TreeNode * tree)
{	
	switch (tree->nodekind)
	{	case StmtK:
			switch (tree->kind.stmt)
			{	case DeclK:
				case ParmK:
					insertSymTab(tree->attr.name,tree->depth,tree->depthnum,tree->lineno,tree->type,tree->arrayLength);
					break;
				case AssignK:
					checkType (tree->child[0]->attr.name, tree->child[0]->domain,0, tree->child[0]->lineno);
					break;
					break;
				case CompoundK:
				case IfK:
				case WhileK:
				default:
					break;
			}
			break;
		case ExpK:
			switch (tree->kind.exp)
			{	case IdK:
					tree->type = checkType(tree->attr.name,tree->domain,0,tree->lineno);
					break;
				case OpK:
				case IntValueK:
				default:
					break;
			}
			break;
		default:
			break;
	}
}

/*	buildSymtab()构造符号表
	使用先序遍历法
 */
void buildSymTab(TreeNode * syntaxTree)
{	
	beforeBFS(syntaxTree);
	traverse(syntaxTree,insertNode,nullProc);
	fprintf(listing,"\nSymbol table:\n");
	printSymTab(listing);
}
/* 类型错误时的处理函数。 */
static void typeError(TreeNode * tree, char * message)
{	fprintf(listing,"Error at line %d:Type error: %s\n",tree->lineno,message);
	Error = TRUE;
}
/* 类型不匹配时警告,默认强制转换为整型。 */
static void typeWarn(TreeNode * tree, char * message)
{	fprintf(listing,"\nWarn:Type conflict at line %d: %s",tree->lineno,message);
}

/*	checkNode()检查每个节点的类型,返回值为每个节点的类型
 */
int checkNode(TreeNode * tree)
{	TreeNode * treeTemp = tree;
	if (NULL == treeTemp)
	{	
		return 0;
	}
	int temp1,temp2;
	switch (treeTemp->nodekind)
	{	
		case ExpK:
			switch (treeTemp->kind.exp)
			{	
				case OpK:
					temp1 = checkNode(treeTemp->child[0]);
					if(NULL == treeTemp->child[1])	//检查是否是负的表达式
					{
						return Int;
					}
					else
					{	temp2 = checkNode(treeTemp->child[1]);
						if ( temp1 != temp2 )
						{	typeWarn(treeTemp,"Op applied to numbers which aren't the same type.");
							return Int;
						}
						else
							return Int;
					}
				case IdK:
					/* 验证此变量在声明时是不是数组 */
					temp1 = lookupSymTab (treeTemp->attr.name, treeTemp->domain, -1, -1, treeTemp->lineno);
					if ( 0 == temp1 )
					{	/* 验证结果:不是数组,若引用时该变量有下标则报错 */
						if (NULL == treeTemp->child[0] )
							return checkType(treeTemp->attr.name, treeTemp->domain, 0, treeTemp->lineno);
						else	//是数组元素但是没有下标
							typeError(treeTemp->child[0], "This variable is not an array element.");
					}
					else	//	验证结果:是数组,若引用时该变量没有下标则报错
					{	if ( NULL == treeTemp->child[0] )
							typeError(treeTemp->child[0], "This variable should be an array element.");
						else
							return checkType(treeTemp->attr.name, treeTemp->domain, 0, treeTemp->lineno);
					}
					break;
				case IntValueK:
					return Int;
				default:
					break;
			}
			break;
		case StmtK:
			switch (treeTemp->kind.stmt)
			{	
				case AssignK:
					/* 查询符号表确认变量在声明时是不是数组 */
					temp1 = lookupSymTab (treeTemp->attr.name, treeTemp->domain, -1, -1, treeTemp->child[0]->lineno);
					if (0 == temp1 )	//声明时不是数组
					{	/* 若引用时也不是数组元素 */
						if (NULL == treeTemp->child[1])
						{	/* 最后确认赋值符左右的值类型一致,不一致则警告并返回,一致则直接返回 */
							if (checkType(treeTemp->attr.name, treeTemp->domain, 0, treeTemp->child[0]->lineno) !=
									checkNode(treeTemp->child[0]))
								typeWarn(treeTemp->child[0],
									"Variable and right value are not the same type.");
							break;
						}
						else	//若变量被当成了数组元素
						{	typeError(treeTemp->child[0],
								"This variable is not an array element.");
							break;
						}
					}
					else	//该变量是数组
					{	if (NULL == treeTemp->child[1])	//若没有下标
						{	typeError(treeTemp->child[0],
								"This variable should be an array element.");
							break;
						}
						else	//有下标
						{	if (Int != checkNode(treeTemp->child[0] ))	//若数组下标不为整数
							{	typeError(treeTemp->child[0], "The index must be an integer.");
								break;
							}
							else
							{	if (checkType(treeTemp->attr.name, treeTemp->domain, 0, treeTemp->child[0]->lineno) !=
										checkNode(treeTemp->child[1]))
									typeWarn(treeTemp->child[0],
									"Variable and right value are not the same type.");
								break;
							}
						}
					}
				case DeclK:
					break;
				case WhileK:
					checkNode(treeTemp->child[0]);
					checkNode(treeTemp->child[1]);
					break;
				case CompoundK:
					checkNode(treeTemp->child[0]);
					break;
				case IfK:
					checkNode(treeTemp->child[0]);
					checkNode(treeTemp->child[1]);
					checkNode(treeTemp->child[2]);
					break;
				default:
					break;
			}
			break;
		default:
			break;
	}
	treeTemp = treeTemp->sibling;
	checkNode(treeTemp);
	return 0;	//	开头的返回值0与此处的0表示检查完成,正常返回,如while,if,write,compound等。
}

symtab.h

struct domainNode;
typedef struct domainNode DomainNode;

/*	searchSymTab()用于查找和插入符号表,并协助类型检查。
	参数说明:
	name是当前的变量名,
	varLineno是当前行号,用于错误提示,
	type为变量声明时需要填入符号表的符号类型。
	arrayLength为数组长度,为-123代表非数组,其他的小于0的值报错。
	返回值:
	正确返回时为arrayLength,遇错为-1;
	*/
int insertSymTab( char * name, int dep, int depnum, int varLineno, int type, int arrayLength );

/*	查找符号表,若找不到则返回-1,否则返回变量的arrayLength,
	arrayLength为0表示非数组,arrayLength非0表示下标的值。
	*/
int lookupSymTab ( char * name, DomainNode * domain, int int_val, double real_val, int varLineno );

/*	参数type为0时,直接返回变量在符号表中的类型;
	type不为0时,检查变量名的类型与传入的type是否一致,一致返回0,不一致返回1。
	*/
int checkType(char * name, DomainNode * domain, int type, int varLineno);

/*	printSymTab()打印符号表,验证符号表是否正确构造。
	*/
void printSymTab(FILE * listing);

/*	以下为解释执行时所用的函数,分别为:
	得到变量的值,更新变量的值,
	得到数组元素的值,更新数组元素的值。
	*/
double getValue(char * name);

void updateValue(char * name, int int_val, double real_val);

double getArray(char * name, int index);

void updateArray(char * name, int index, int int_val, double real_val);


symtab.c

#include 
#include 
#include 
#include "symtab.h"
#include "globals.h"
#include "domain.h"
/* SIZE 为符号表大小,是一个比较合适的素数 */
#define SIZE 211

/* SHIFT 用于移位运算  */
#define SHIFT 4

/* 哈希函数*/
static int hash ( char * key )
{	int temp = 0;
	int i = 0;
	while (key[i] != '\0')
	{	temp = ((temp << SHIFT) + key[i]) % SIZE;
		++i;
	}
	return temp;
}

/*	符号表表项,每一个表项包含:
	变量名,类型,声明时的行号,下一个表项的地址
 */
typedef struct SymbolRec
{	
	char * name;
	ExpType type;
	//LineList lines;
	int varLineno;
	union {	int int_val;
			double real_val; } value;
	union {	int * intArray;
			double * realArray; } array;
	int arrayLength;
	struct SymbolRec * next;
} * Symbol;

/* the hash table */
static Symbol hashTable[SIZE];

int insertSymTab( char * name, int dep, int depnum, int varLineno, int type, int arrayLength )
{	
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	sprintf(depthstr, "%d", dep);
	sprintf(depthnumstr, "%d", depnum);
	char namet[100];
	strcpy(namet, name);
	strcat(namet, depthstr);
	strcat(namet, cut);
	strcat(namet, depthnumstr);
	int h = hash(namet);
	Symbol s =  hashTable[h];
	/* 遍历符号表,查找是否有同名项 */
	while ((NULL != s)&&(0 != strcmp(name,s->name)))
		s = s->next;
	if(NULL == s)		/* 该符号不在符号表中,将其加入符号表,返回正确 */
	{	s = (Symbol) malloc(sizeof(struct SymbolRec));
		s->name = name;
		s->varLineno = varLineno;
		s->type = type;
		// debug fprintf(listing, "insertSymtab:%s\n", namet);
		if (0 > arrayLength)
		{	fprintf(listing,
				"Error:line %d:数组长度要大于0.\n", varLineno);
			Error = TRUE;
		}
		s->arrayLength = arrayLength;
		int tempArray[arrayLength];
		s->array.intArray = tempArray;
		s->next = hashTable[h];
		hashTable[h] = s;
		return arrayLength;
	}
	else	/* 若该符号在符号表中,报错 */
	{	fprintf(listing,
			"Error:line %d:变量 %s 已有同名变量声明在第 %d 行.\n",
				varLineno, name, s->varLineno);
		// debug fprintf(listing, "%d-%d  %s\n", dep, depnum, namet);
		Error = TRUE;
	}
	return -1;	//返回值为-1表示插入过程中出错。
}

int lookupSymTab( char * name, DomainNode * domain, int int_val, double real_val, int varLineno)//查找符号表
{	
	int flag = 0;
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	char namet[100];
	while (domain)
	{
		if (domain->depth == -1 && domain->depthnum == -1) //depth的变化在语法树生成中变化
		{
			domain = domain->pre; //返回上一个域,初始为-1,然后递归嵌套寻找。
			continue;
		}
		sprintf(depthstr, "%d", domain->depth);
		sprintf(depthnumstr, "%d", domain->depthnum);
		strcpy(namet, name);
		strcat(namet, depthstr);
		strcat(namet, cut);
		strcat(namet, depthnumstr);
		int h = hash(namet);
		Symbol s =  hashTable[h];
		while ((s != NULL)&&(0 != strcmp(name,s->name)))
			s = s->next;
		if (s != NULL)
		{
			if ((int_val != -1) || (real_val != -1))
			{	
				if (real_val != -1)
					s->value.real_val = real_val;
				else
					s->value.int_val = int_val;
			}
			return s->arrayLength;
		}
		domain = domain->pre;
	}
	fprintf(listing,
		"Error:line %d:变量 %s 未声明.\n",varLineno, name);

	Error = TRUE;
	return -1;
	
}

int checkType(char * name, DomainNode * domain, int type, int varLineno)//检查类型。
{	
	int flag = 0;
	char *cut = "-";
	char depthstr[10], depthnumstr[10];
	char namet[100];
	while (domain)
	{
		if (domain->depth == -1 && domain->depthnum == -1) //在域中寻找符号TYPE是否出现
		{
			domain = domain->pre; 
			continue;
		}
		sprintf(depthstr, "%d", domain->depth);
		sprintf(depthnumstr, "%d", domain->depthnum);
		strcpy(namet, name);
		strcat(namet, depthstr);
		strcat(namet, cut);
		strcat(namet, depthnumstr);
		int h = hash(namet);
		Symbol s =  hashTable[h];
		while ((NULL != s)&&(0 != strcmp(name,s->name)))
			s = s->next;
		if(NULL != s)
		{	
			if (type != 0)
			{	if (type != s->type)
				{	fprintf(listing,
						"Error:line %d:变量 %s 类型不正确.",s->varLineno, name);
					Error = TRUE;
					return 1;
				}
				else
					return 0;
			}
			else
				return s->type;
			flag = 1;
			break;
		}
		domain = domain->pre;
	}
	if (flag == 0)
		{
			fprintf(listing,
				"Error:line %d:变量 %s 未声明.\n",varLineno, name);
			Error = TRUE;
			return -1;
		}
}

double getValue(char * name)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	return (double)s->value.int_val;
}

void updateValue(char * name, int int_val, double real_val)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	s->value.int_val = int_val;
	return;
}

double getArray(char * name, int index)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	return (double)s->array.intArray[index];//返回
}

void updateArray(char * name, int index, int int_val, double real_val)
{	int h = hash(name);
	Symbol s =  hashTable[h];
	while (0 != strcmp(name,s->name))
		s = s->next;
	s->array.intArray[index] = int_val;
	return;
}

/*	printSymTab()打印符号表,验证符号表是否正确构造。
 */
void printSymTab(FILE * listing)
{	int i = 0;
	
	fprintf(listing,"\t  符号名      类型   是否为数组  声明时行号 \n");

	Symbol s = hashTable[i];
	while(i++ != SIZE)
	{	if(s != NULL)
		{	fprintf(listing,"\t   %-11s",s->name);
			switch(s->type)
			{	case Int:
					fprintf(listing, "Int ");
					break;
				default:
					break;
			}
			if(0 == s->arrayLength)
			{	fprintf(listing,"      0");
				fprintf(listing,"            %d \n", s->varLineno);
			}
			else
			{	fprintf(listing,"      %d",s->arrayLength);
				fprintf(listing,"            %d \n", s->varLineno);
			}
		}
		s = hashTable[i];
	}

}

main.c

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"
#include "analyze.h"
#include "domain.h"

/* 行号、源文件、输出文件 */
int lineno = 0;
FILE * source;
FILE * listing;

int Parse = TRUE;//语法分析完毕, 常为1
int Analyze = TRUE;//词法分析完毕 ,常为1

int printSyntaxTree = TRUE;//输出语法树

int Error = FALSE;//错误,我设置为常为0,如果没错的话一直是0

int main( int argc, char * argv[] )
{
	TreeNode * syntaxTree;
	char pgm[120]; /* 源文件名 */
	if (argc < 2)
	{	fprintf(stderr,"usage: %s \n",argv[0]);
		exit(1);
	}
	if (argc > 2)
	{
		if (strcmp(argv[2],"-s"))
			printSyntaxTree = TRUE;
		else
		{
			fprintf(stderr,"无法识别的参数.\n");
		}
	}
	strcpy(pgm,argv[1]) ;
	if (strchr (pgm, '.') == NULL)
		strcat(pgm,".cm");
	source = fopen(pgm,"r");
	if (source==NULL)
	{	fprintf(stderr,"文件 %s 无法找到\n",pgm);
		exit(1);
	}
	listing = stdout;
	fprintf(listing,"\n编译分析: %s\n",pgm);
	printf("\n\n");

	if (Parse)
	{	
		syntaxTree = parse();
		printf("\n\n\n\n\n");
		if (printSyntaxTree)
		{	fprintf(listing,"语法树:\n");
			printTree(syntaxTree);
			fprintf(listing, "输出语法树成功!\n");
		}
//		Error=0;//让符号表构建进行下去
		if (! Error)
		{	
			if (Analyze)
			{
				buildSymTab(syntaxTree);
				if(! Error)
				{
					checkNode(syntaxTree);
					if(! Error)
						fprintf(listing,"类型检查完毕.\n");
					else
						fprintf(listing,"\n变量类型有错误\n");
				}
				else
					fprintf(listing,"\n结果:符号表的构造出现了一些错误\n");
			}
			
	}
	fclose(source);
	return 0;
	}}

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"
#include "analyze.h"
#include "domain.h"

/* 行号、源文件、输出文件 */
int lineno = 0;
FILE * source;
FILE * listing;

int Parse = TRUE;//语法分析完毕, 常为1
int Analyze = TRUE;//词法分析完毕 ,常为1

int printSyntaxTree = TRUE;//输出语法树

int Error = FALSE;//错误,我设置为常为0,如果没错的话一直是0

int main( int argc, char * argv[] )
{
	TreeNode * syntaxTree;
	char pgm[120]; /* 源文件名 */
	if (argc < 2)
	{	fprintf(stderr,"usage: %s \n",argv[0]);
		exit(1);
	}
	if (argc > 2)
	{
		if (strcmp(argv[2],"-s"))
			printSyntaxTree = TRUE;
		else
		{
			fprintf(stderr,"无法识别的参数.\n");
		}
	}
	strcpy(pgm,argv[1]) ;
	if (strchr (pgm, '.') == NULL)
		strcat(pgm,".cm");
	source = fopen(pgm,"r");
	if (source==NULL)
	{	fprintf(stderr,"文件 %s 无法找到\n",pgm);
		exit(1);
	}
	listing = stdout;
	fprintf(listing,"\n编译分析: %s\n",pgm);
	printf("\n\n");

	if (Parse)
	{	
		syntaxTree = parse();
		printf("\n\n\n\n\n");
		if (printSyntaxTree)
		{	fprintf(listing,"语法树:\n");
			printTree(syntaxTree);
			fprintf(listing, "输出语法树成功!\n");
		}
//		Error=0;//让符号表构建进行下去
		if (! Error)
		{	
			if (Analyze)
			{
				buildSymTab(syntaxTree);
				if(! Error)
				{
					checkNode(syntaxTree);
					if(! Error)
						fprintf(listing,"类型检查完毕.\n");
					else
						fprintf(listing,"\n变量类型有错误\n");
				}
				else
					fprintf(listing,"\n结果:符号表的构造出现了一些错误\n");
			}
			
	}
	fclose(source);
	return 0;
	}}

你可能感兴趣的:(编译原理课程设计符号表部分)