当前位置:
文档之家› 编译原理实验2语法分析器构造
编译原理实验2语法分析器构造
} else printf("\n错误e3:非法右括号!");
}
/* 打印过程 */ void print_process(int t, int prior) {
printf("%4d%12s", step++, symbols);
if(prior == HIGH) printf("%10c", '>');
push(curChar); print_process(0, LOW); if(symbols[top]!='#')
goto u; break; case HIGH: error(j); curChar = '#'; break; case EQUAL: push(curChar); print_process(0, EQUAL); if(symbols[top]!='#')
default: return -1;
} } /* 判断终结符 */ int isVT(char ch) {
if(ch=='N') return 0;
return 1; }
/* 读入终结符 */ char readVT(Байду номын сангаасnt k) {
if(isVT(inputStr[k])) { return inputStr[k];
// * > > > > < > < >
// / > > > > < > < >
// ( < < < < < = < ?
// ) > > > > ? > ? >
// i > > > > ? > ? >
// # < < < < < ? < =
//----------------------------------
2018~2019 年春季学期
序号:
《编译原理》课程 实验报告
实验二 语法分析器构造
专业班级: 学生姓名: 学生学号:
一、目的和要求
借助于词法分析程序提供的分析结果,编写一个算符优先语法分析程序,程 序能进行语法结构分析和错误检查,并产生相应的归约信息。同时给出出错信息 和错误类型,从而加深对语法分析的理解。
else if(prior == EQUAL) printf("%10c", '=');
else printf("%10c", '<');
curChar = curChar == 0 ? ' ' : curChar; printf("%12c", curChar); printf("%18s", &inputStr[k]); if(t) {
二、实验内容
给定文法 G 和算符优先分析法,构造其算符优先分析程序。文法 G:
语句→赋值语句|条件语句|转移语句|带标号的赋值语句
带标号的赋值语句→<标号><赋值语句>
赋值语句→变量=算术表达式
条件语句→TF <布尔表达式> THEN 语句
|TF <布尔表达式> THEN 语句 ELSE 语句
5. 实验运行结果及分析
四、本次实验总结体会
本次实验主要遇到的困难及解决方法包括:由于上一次实验打下的良好 基础,本次实验较为顺利,没有遇到明显的困难。
本程序的优点包括:比较完整地实现了 LL(1)分析算法;分析器只需要输 入起始符号、产生式、终结符号就可以初始化。
本程序还存在可以优化的地方,主要包括:将输入符号串改为由词法分 析器生成的二元式从文件中读取,为完整编译器的实现打下良好的基础;
goto u; break; } } while(curChar != '#'); printf("\n算术表达式%d的归约产生式步骤号为:", id++); n = 0; while(No[n]) printf(" %d", No[n++]); printf("\n"); while(symbols[0]!='\0') pop(); while(No[--n]) No[n]='\0'; top = -1; k = 0; n = 0; step = 1;
printf("%15s\n", "归约"); No[n++] = step-1; } else printf("%15s\n", "移进"); }
/* 规约过程 */ void prior_analysis() {
int i, j, m; char q, str, ch[20]; push('#'); print_process(0, LOW); u: curChar = readVT(k++); j = isVT(symbols[top]) ? top : top - 1; do {
}
return -1; }
/* 错误处理 */ void error(int t) {
if(index(symbols[t]) == 5 || index(symbols[t]) == 6) { printf("\n错误e2:缺少运算符!");
} else if(index(symbols[t])==4) { printf("\n错误e1:非法左括号!");
不为#N
将symbols中所有优先 级比当前字符低的弹 出栈存入ch直到有一
个不低于的
判断ch与word[i]是否相 等
是
规约为N,将N压入 symbols
从inputStr读入字符
判断当前字符优先级是
否
否不低于栈顶字符
是
将当前字符压入 symbols
当前字符是否为#
是
结束
报错
3. 主要技术问题的处理方法 (1) 判断优先级时,原本设置了三个函数,代码过于冗余,提取相同部分 后将他们整合为了一个函数,大大减少了代码量 (2) 最初基本功能全部写在了主函数内,虽然变量的传值十分简单,但是 逻辑也极其混乱,优化结构后将大部分功能封装在一个个的函数内部,结 构变得十分清晰,逻辑也更为优质。 (3) 在比较优先级的时候做的还不够完美,需要传入一个数组下标和一个 字符才可以比较,进一步的优化可以将其改为直接传入两个字符来进行优 先级的比较,代码也更加人性化。
while((priority(j, curChar) == HIGH) && strcmp(symbols,"#N") != 0) { do {
q = symbols[j]; j = isVT(symbols[j-1]) ? j-1 : j-2; } while(priority(j, q) != LOW);
转移语句→GOTO 标号
变量→标识符
标识符→字母|<标识符><数字>
字母→A|B|…|Z|a|b|…|z
数字→0|1|…|9
算术表达式→项|算术表达式+项|算术表达式-项
项→因子|项*因子|项/因子|因子↑项
因子→变量|常数|(表达式)
布尔表达式→<算术表达式><关系符><算术表达式>
/* 入栈 */ void push(char ch) {
symbols[++top] = ch; }
/* 出栈 */ char pop() {
char temp = symbols[top--]; symbols[top + 1] = '\0'; return temp; }
/* 对应下标 */ int index(char ch) {
switch(ch) { case'+': return 0; case'-': return 1; case'*': return 2; case'/': return 3; case'(': return 4; case')': return 5; case'i': return 6; case'#': return 7;
} srcStr[i]='\0'; while(srcStr[j] != '\0') {
if(isalnum(srcStr[j])) { if(isalnum(srcStr[j-1]) == 0) inputStr[++m] = 'i';
} else inputStr[++m] = srcStr[j];
否
读入字符
当前字符写入srcStr字
判断当前字符是否为
否
符串
空白符
是
将srcStr串转换为终结 符串,存入inputStr
结束,输出inputStr
规约过程
开始
将#压入符号栈 symbols
i++
否
是 i<6?
否
从inputStr读入字符
判断symbols最高终结符 j的优先级是否高于当前 字符,并且符号栈是否
j++; } inputStr[m+1] = '#'; inputStr[m+2] = '\0'; printf("\n------------------------------------------------------------\n"); printf("\n算术表达式%d为: %s\n", id, srcStr); printf("输入字符串: %s\n", inputStr); printf("\n%8s%13s%16s%18s%20s%14s\n", " 步骤号", "符号栈", "优先关系", "当前分析符 ", "剩余输入串", "动作"); }