##目录
词法分析程序->语法分析程序->语义分析程序->中间代码生成程序
实验内容:
确定符号表的组织方式,一般应包括名字栏和信息栏,其中名字栏作为关键字。
(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文件,在每个生成式后面加上语法制导翻译。
实验内容:
可生成基本的四元式表示的中间代码,也可以生成虚拟机规定的汇编语言代码
实验内容:
根据以上过程打印输出中间代码
实验过程:
暂无
%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;
}
}
/*预计有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;
}
#ifndef _ANALYZE_H_
#define _ANALYZE_H_
/* buildSymtab()先序遍历语法树,构造符号表。
*/
void buildSymTab(TreeNode *);
/* checkNode()为类型检查。
返回值为type.
*/
int checkNode(TreeNode *);
#endif
#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等。
}
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);
#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];
}
}
#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;
}}