南华大学计算机科学与技术学院实 验 报 告 ( 2023~2023学年度 第二学期 )课程名称编译原理实验名称词法分析器的设计与实现姓名学号专业班级地点教师1. 实验目的及规定实验目的加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;可以采用一种编程语言实现简朴的词法分析程序;可以使用自己编写的分析程序对简朴的程序段进行词法分析实验规定1. 对单词的构词规则有明确的定义;2. 编写的分析程序可以对的辨认源程序中的单词符号;3. 辨认出的单词以<种别码,值>的形式保存在符号表中,对的设计和维护符号表;4. 对于源程序中的词法错误,可以做出简朴的错误解决,给出简朴的错误提醒,保证顺利完毕整个源程序的词法分析;2. 实验环节1.词法分析规则<标记符>::=<字母>|<标记符><字母>|<标记符><数字><常数>::=<数字>|<数字序列><数字><数字序列>::=<数字序列><数字>|<数字>|<.><字母>::=a|b|c|……|x|y|z<数字>::=0|1|2|3|4|5|6|7|8|9<运算符>::=<关系运算符>|<算术运算符>|<逻辑运算符>|<位运算符>|<赋值运算符><算数运算符>::=+|-|*|/|...|--<关系运算符>::=<|>|!=|>=|<=|==<逻辑运算符>::=&&| || |!<位运算符>::=&| | |!<赋值运算符>::==|+=|-=|/=|*=<分界符>::=,|;|(|)|{|}|:| // |/**/<保存字>::=main|if|else|while|do|for|...|void2.单词符号的编码单词符号种别码单词符号种别码main0>26if1>=27else2<28while3<=29do4!30for5!=31switch6=32case7==33int8(34double9)35float10{36long11}37void12;38+13:39+=14|40++15||41-16数字42-=17标记符43--18,44&19//45&&20/**/46#21*22*=23/24/=253.状态转换图2字母非字母与数字1字母与数字0空白4数字非数字数字38/611+10=12!13=15其它3418<其它171921......&;,({},:)33其它2220=其它>1614+其它79*/=其它54.算法分析①词法分析器工作的第一步是输入源程序文本。
为了更好地对单词符号辨认,把输入串预解决一下预解决重要滤掉空格,跳过注释、换行符等②对预解决后的输入串依次扫描单个字符,使用if-while嵌套语句和switch case语句判断字符的类型,具体辨认方法可看状态转换图有时为了拟定词性,需要超前扫描,若超前扫描的字符对辨认当前单词无用处,则需要退还给输入串,以备辨认下一单词字符时使用③若读入的字符与单词符号编码表的字符匹配不上,则报错,并输出犯错行数对辨认处的单词符号以(单词符号,种别码)二元式的形式输出3. 实验内容1. 流程图2. 程序的变量与函数说明(1) input全局字符数组,用来存放输入串(2) word全局字符数组,用来存放获取到的单词符号,限定长度为8(3) ch全局字符变量,用来存放最新读入的字符(4) syn全局整型变量,表达单词符号的编码(5) p全局整型变量,表达当前字符在input数组的位置(6) m全局整型变量,表达最新读入的字符在word数组的下标(7) line全局整型变量,当前行数(8) keyword全局字符数组,存放关键字(9) init()获取输入串(10) isKey()判断关键字的函数,若参数数组中是关键字,则把syn置为该关键字相应的编码并返回1,否则返回0(11) isLetter()判断字母的函数,若参数字符是字母,则返回1,否则返回0(12) isDigit()判断数字的函数,若参数字符是数字,则返回1,否则返回0(13) isSpace()判断空白符的函数,若参数字符是空格、TAB或换行符,则返回1,否则返回0(14) scaner()扫描输入串的函数,对读出的字符进行判断,若是单词符号表中的符号,则将syn置为相应的编码3. 源程序#include #include char input[1000];//输入串 char word[8];//获取到的单词 char ch;int syn;//种别码 int p; int m;int line;//行数 //关键字 char keyword[][8]={"main","if","else","while","do","for","switch","case","int","double","float","long","void"};void scaner(void);//获取输入串 void init(){ int i=0; printf("\n please input a string(end with '#'):\n"); do{ scanf("%c",&ch); input[i++]=ch; }while(ch!='#');} //判断是不是关键字 int isKey(char *str){ int n; for(n=0;n<13;n++) { if(strcmp(str,keyword[n])==0) { syn=n; return 1; } } return 0;}//判断是不是数字int isDigit(char c){ if (c>='0'&&c<='9') return 1; else return 0;}//判断是不是字母int isLetter(char c){ if ((c<='z'&&c>='a')||(c>='A'&&c<='Z')) return 1; else return 0;} int isSpace(char c){ if (c==' '||c=='\t'||c=='\n') { return 1; } return 0;}void main(){ init();//输入字符串 line=0; p=0; do{ scaner(); switch(syn) { case -1: printf("you have input a wrong string in line %d\n",line); break; default: printf("( %s,%d )\n",word,syn); break; } }while(syn!=21); }void scaner(void){ //清空word for(m=0;m<8;m++) { word[m] = ' '; } //读取字符 ch=input[p++]; m=0; //当ch为空格或换行符时,继续往下读 while(isSpace(ch)) { if (ch=='\n') { line++; } ch=input[p++]; } //假如以字母开头 if(isLetter(ch)) { //假如往后是字母或数字,把字符存入word中,然后往下继续读 //串长超过8则截断 while((isLetter(ch)||isDigit(ch))&&m<8) { word[m++]=ch; ch=input[p++]; } p--; syn=43; word[m++]='\0'; isKey(word);//判断是不是关键字 } //假如是以数字开头,并且往后是数字 else if(isDigit(ch)) { while((isDigit(ch)||ch=='.')&&m<8) { word[m++]=ch; ch=input[p++]; } //假如数字之后是字母 ,则犯错 if (isLetter(ch)) { while(!isSpace(ch)) { ch=input[p++]; } syn=-1; return ; } p--; syn=42; } else { switch(ch) { //比较运算符 case '<': word[m++]=ch; ch=input[p++]; if(ch=='=') { syn=29; word[m++]=ch; } else { syn=28; p--; } break; case '>': word[m++]=ch; ch=input[p++]; if(ch=='=') { syn=27; word[m++]=ch; } else { syn=26; p--; } break; case '!': ch=input[p++]; if(ch=='=') { syn=31; word[m++]=ch; } else { syn=30; p--; } break; case '=': 。