📄 parse.c
字号:
/************************************************************************
*
* 文件名:parse.c
*
* 文件描述:简单C语言编译器前驱
*
* 创建人: 哈工大2002级软件一班黄敬彬, 2004年12月
*
* 版本号:1.0
*
* 修改记录:
*
************************************************************************/
#include"stdio.h"
#include"ctype.h"
#include"string.h"
#include <malloc.h>
#include"math.h"
#include"stdlib.h"
#include"float.h"
#define init_size 1000
#define add_size 100
#define ID 0
/*算术表达式中的符号*/
#define add 1
#define multy 2
#define leftpar 3
#define rightpar 4
#define minus 5
#define divide 6
/*代表字符串*/
#define word_string 7
/*分界符*/
#define word_divide 8
/*其他符号*/
#define word_other 9
/*关键字*/
#define word_key 10
/*逻辑与&&*/
#define and 11
/*逻辑或||*/
#define or 12
/*逻辑非 !*/
#define not 13
/*比较判断符号>,>=,<,<=,==,!=*/
#define great 14
#define great_equal 15
#define small 16
#define small_equal 16
#define equal_equal 17
#define not_equal 18
/*循环和条件语句关键字*/
#define symbol_if 19
#define symbol_else 20
#define symbol_while 21
#define symbol_do 22
#define symbol_for 23
/*声明语句关键字*/
#define symbol_int 24
#define symbol_float 25
#define symbol_char 26
/*单目运算符*/
#define add_add 27
#define minus_minus 28
/*左右大括号与左右中括号*/
#define leftbig 29
#define rightbig 30
#define leftmiddle 31
#define rightmiddle 32
/*=*/
#define equal 33
/*分号*/
#define fenhao 34
#define NUM 35
#define symbol_void 36
#define symbol_long 37
#define symbol_double 38
#define ERRO 254
/*用来表示符号表中的mark项为ID*/
#define symbol_mark_ID 253
/*逻辑表达式中的非终结符*/
#define B 0
#define A 1
#define O 2
/*算术表达式中的非终结符*/
#define E 0
#define T 1
#define F 2
#define acc 256
/*赋值语句非终结符*/
#define evaluate 0
int action1[12][6]={ /*算术表达式action表*/
{5,-1,-1,4,-1,-1},
{-1,6,-1,-1,-1,acc},
{-1,102,7,-1,102,102},
{-1,104,104,-1,104,104},
{5,-1,-1,4,-1,-1},
{-1,106,106,-1,106,106},
{5,-1,-1,4,-1,-1},
{5,-1,-1,4,-1,-1},
{-1,6,-1,-1,11,-1},
{-1,101,7,-1,101,101},
{-1,103,103,-1,103,103},
{-1,105,105,-1,105,105}
};
int goto1[12][3] ={ /*算术表达式goto表*/
{1,2,3},{0,0,0},{0,0,0},{0,0,0},{8,2,3},{0,0,0},{0,9,3},{0,0,10},
{0,0,0},{0,0,0},{0,0,0},{0,0,0}};
int action2[16][8] ={
{1,-1,4,-1,5,-1,-1,-1},
{-1,2,-1,101,-1,101,101,101},
{3,-1,-1,-1,-1,-1,-1,-1},
{-1,-1,-1,102,-1,102,102,102},
{1,-1,4,-1,5,-1,-1,-1},
{1,-1,4,-1,5,-1,-1,-1},
{-1,-1,-1,104,-1,104,104,104},
{1,-1,4,-1,5,-1,-1,-1},
{1,-1,4,-1,5,-1,-1,-1},
{105,-1,105,-1,105,-1,-1,-1},
{107,-1,107,-1,107,-1,-1,-1},
{-1,-1,-1,12,-1,9,10,-1},
{-1,-1,-1,103,-1,103,103,103},
{-1,-1,-1,acc,-1,9,10,acc},
{-1,-1,-1,106,-1,9,10,106},
{-1,-1,-1,108,-1,9,10,108}
};
int goto2[16][3] = {
{13,7,8},{0,0,0},{0,0,0},{0,0,0},{11,7,8},{6,7,8},{0,0,0},{14,7,8},{15,7,8},
{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}};
struct keyword /*定义关键字结构体*/
{
char * key[10];
}keywords[32];
struct symbolize
{
int mark;
char *variable;
int type;
int value;
};
struct symbolize *symbol;
int symbol_size;/*当前符号表大小*/
int index = 0;/*符号表索引*/
char operater[] = "><=+-!*%&^|";/*操作符数组*/
char letter[]= "`~!@#$%^&*()_+|{}\":?><,./;'[]\\=-";/*定义C语言所用到的符号数组*/
FILE *fp;
FILE *output,*erro,*chart;/*分别定义测试程序文件,输出文件,错误文件,符号表文件指针*/
int linenumber = 1;/*用来表示测试文件的行号 */
int lex_word[300];/*存放词法分析的结果*/
int lex_index=0;/*表示词法分析结果数组元素个数 */
int pointer=0;/*当前语法分析的指针 */
/*算术表达式的临时变量*/
int E_value = 0,T_value = 0,F_value = 0;
int iscreate = 0;/*判断是否产生四元式的标志值*/
struct quaternion /*四元式结构体*/
{
char operate;
int arg1;
int arg2;
int result;
}four_element[100];
int findex = 0; /*四元式结构索引*/
int temporary = 1; /*用来表示当前临时变量的个数*/
void init()/*初始化关键字结构体数组*/
{
* keywords[0].key = "auto";
* keywords[1].key = "break";
* keywords[2].key = "case";
* keywords[3].key = "char";
* keywords[4].key = "const";
* keywords[5].key = "continue";
* keywords[6].key = "default";
* keywords[7].key = "do";
* keywords[8].key = "double";
* keywords[9].key = "else";
* keywords[10].key = "enum";
* keywords[11].key = "extern";
* keywords[12].key = "float";
* keywords[13].key = "for";
* keywords[14].key = "goto";
* keywords[15].key = "if";
* keywords[16].key = "int";
* keywords[17].key = "long";
* keywords[18].key = "register";
* keywords[19].key = "return";
* keywords[20].key = "short";
* keywords[21].key = "signed";
* keywords[22].key = "sizeof";
* keywords[23].key = "static";
* keywords[24].key = "struct";
* keywords[25].key = "switch";
* keywords[26].key = "typedef";
* keywords[27].key = "union";
* keywords[28].key = "unsigned";
* keywords[29].key = "void";
* keywords[30].key = "volatile";
* keywords[31].key = "while";
}
int lookletter(char a)/*用来查找符号a是否在letter符号数组中,如果在返回0,否则返回-1*/
{
int n;
int k = strlen(letter);
for(n=0;n<k;n++)
{
if(a == letter[n])
return 0;
}
return -1;
}
int findsymbol(char* b)/*用来查找标示符b[]是否在符号表中,如果在返回它的索引,否则返回-1*/
{
int i;
for(i=0;i<index; i++)
{
if(strcmp(symbol[i].variable,b) == 0)
return i;
}
return -1;
}
int insert(char b[],int s)/*将指定的标示符插入符号表*/
{
if(index>=symbol_size)
{
symbol_size+=add_size;
symbol=(struct symbolize*)realloc(symbol,symbol_size*(sizeof(struct symbolize)));
if(symbol==NULL)
{
printf("realloc memery error,exit\n");
exit(1);
}
}
symbol[index].variable=(char*)calloc(strlen(b),sizeof(char));
strcpy(symbol[index].variable,b);
symbol[index].mark = s; /*用于表示标示符是ID还是NUM */
symbol[index].type = 0;
symbol[index].value =0;
if(symbol[index].variable==NULL)
{
printf("malloc memery error,exit\n");
/*exit(1); */
}
return index++;
}
int lookoperater(char a)/*用来查找符号a是否在operater符号数组中,如果在返回0,否则返回-1*/
{
int n;
int k = strlen(operater);
for(n=0;n<k;n++)
{
if(a == operater[n])
return 0;
}
return -1;
}
int lookkey(char keys[])/*用来判断字符串是否为关键字*/
{
int i;
for(i=0;i<32; i++)
{
if(strcmp(keys,* keywords[i].key) == 0)
return i;
}
return -1;
}
int lex()
{
char ch;
ch = fgetc(fp);/*从文件中读出一个字符 */
while(1)
{
if(ch == ' '||ch == '\t')/*当字符为空格或制表符是,跳过*/
;
else if(ch == '\n')/*当字符为换行符时,行号加一 */
linenumber++;
else if (isdigit(ch))/*当字符为数字时,执行以下操作*/
{
char tokenval[100] = {'\0'};/*定义一个字符串数组用来存放数字*/
int k = 0;
int type =0;/*用来判断该常数的数值类型*/
int p;
tokenval[0] = ch;/*将第一个数字存入数组 */
ch = fgetc(fp);
k++;
while(isdigit(ch)||ch == '.')/*当接着读入的字符为数字,小数点,用来表示实数的l或L后缀时 */
{
if(ch=='.')
type = 1;
tokenval[k] = ch;/*否则将后继字符存入数组中 */
ch = fgetc(fp);
k++;
}
if(isalpha(ch)||ch == '_'||ch == '@'||ch == '#'||ch == '$'||ch == '?'||ch == '\\')
{/*当数字后面紧接着字母或其他不规范的符号是,输出表示符不规范的错误信息到错误文件中*/
tokenval[k] = ch;
printf("erro: 标识符命名错误,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,tokenval);
fprintf(erro,"erro: 标识符命名错误,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,tokenval);
while(ch != ' '&&ch!='\n')
ch = fgetc(fp);
}
else/*最后回退一个字符,并将相关信息输出到输出文件中 */
{
fseek(fp,-1L,1);
printf("(num,%s)\n",tokenval);
fprintf(output,"(num,%s)\n",tokenval);
}
p = findsymbol(tokenval);/*判断该标示符是否在符号表中,p用来表示符号表索引*/
if(p==-1)
{
p = insert(tokenval,NUM);
fprintf(chart,"%d\t%s\t\t\tnull\n",index-1,tokenval);
}
if(type ==1)
symbol[p].type = symbol_float;
else
symbol[p].type = symbol_int;
return p+1000;
}
else if(isalpha(ch)||ch == '_')/*当字符为字母或下划线时,执行以下操作*/
{
char sign[128]={'\0'};/*定义一个字符串数组用于存放标示符 */
int b = 0;
while(isalnum(ch)||ch == '_')/*当读入的字符为字母,数字或下划线时,持续将字符读入并存放到数组中 */
{
sign[b] = ch;
ch = fgetc(fp);
b++;
if(b>127)/*当标示符的长度超过128时,报错,并将错误信息输出 */
{
printf("erro: 操作符长度过长,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,sign);
fprintf(erro,"erro: 操作符长度过长,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,sign);
break;
}
}
if(ch == '@'||ch == '#'||ch == '$'||ch == '?'||ch == '\\')
{
printf("erro: 标识符命名错误,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,sign);
fprintf(erro,"erro: 标识符命名错误,出错地方在第%d行,出错单词是:(num,%s)\n",linenumber,sign);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -