编译原理比较复杂的词法分析器 含代码
- 格式:doc
- 大小:162.87 KB
- 文档页数:16
实验报告二 词法分析
一、总体设计思想 1)实验目的: 设计编制并调试一个词法分析程序,加深对构造词法分析器的原理和技术的理解与应用。
2)实验具体要求: 针对计算机高级程序语言——C语言子语言,运用恰当的词法分析技术线路,设计和实现C语言子语言的词法分析器。 编程语言:C语言/JAVA语言 平台选择:Linux/Windows 技术线路( 任选其一) 正规式→NFA→DFA→min DFA→程序设计 正规文法→NFA→DFA→min DFA→程序设计 词法分析器程序输出形式,参见◤输出形式设计◢ 具有出错处理功能 C语言子语言词法描述——涉及的单词类如下: (1)关键字 main if else while do for int void char (2)运算符和界符 = + - * / < <= > >= != = = ; ( ) : # { } 注:#为结束标志符,详见◤程序框架◢ (3)标识符 正规式:ID=letter(letter|digit)* (4)整型常数 正规式:NUM= digit(digit)*
3)词法分析器构造原理: 词法分析器就是根据语言的此法规则构造出识别其单词的有限自动机,它是一个数学模型,先给出识别各类单词的状态转换图,再将各类单词的状态转换图的初始状态合并成一个唯一的初状态;然后化简并调整冲突的状态编号;最后再将有限自动机变成一个可行的词法分析器。
二、种别码表设计及其在计算机中存放表示
1)单词种别码设计: 单 词 种 别 码 对 照 表 单词符号 种别码 单词符号 种别码 main 1 / 16 if 2 : 17 else 3 = 18 while 4 } 19 do 5 < 20 for 6 ! = 21 int 7 <= 22 char 8 > 23 void 9 >= 24 标识符 10 = = 25 整型常数 11 ; 26 { 12 ( 27 + 13 ) 28 - 14 # 0 * 15
2)输出形式设计: 词法分析器的输入是源程序字符串,输出是对应的单词串。每个单词按照二元组(种别码,单词符号本身)格式输出。 例如:假设源程序为 main( ) { x=9; y=4; if (x>0) x=2*x+1/3; }# 则词法分析器对应输出的结果是: (1,main) (27,( ) (28,) ) (12,{ ) (10,x) (18,=) (11,9) (26,;) (10,y) (18,=) (11,4) (26,;) (2,if) (27,( ) (10,x) (23,>) (11,0) (10,x) (18,=) (11,2) (15,*) (10,x) (13,+) (11,1) (16,/) (11,3) (26,;) (19,}) (0,#) 三、词法分析程序详细设计 1)算法构造思想: 依据建立的识别单词的DFA,设计算法,其框架如下。其中, ① syn存放单词的种别码; ② token存放符合C语言子语言词法规则的单词; ③ sum存放整型常量的单词。 ④ Prog存放所有输入的字符。 ⑤ isSignal判断是否带正负号(0不带,1负号,2正号)。 ⑥ isDecimal判断是否是小数。 ⑦ isExp判断是否是指数。
2)主要模块算法的框图描述: 四、 主要代码 #include #include #include char prog[80]; //存放所有输入字符 char token[32]; //② token存放符合C语言子语言词法规则的单词; char ch; //单个字符 int syn,p,m,n; // ① syn存放单词的种别码 double sum; //③ sum存放整型常量的单词。 int count; int isSignal; //是否带正负号(0不带,1负号,2正号) int isDecimal; //是否是小数 double decimal; //小数 int isExp; //是否是指数 int index; //指数幂 int isNegative; //是否带负号 double temp; int temp2; int repeat; void scanner(); char *rwtab[9]={"main", "if", "else", "while", "do", "for" , "int" , "char" , "void"}; void main() { p=0; count=0; isDecimal=0; index=0; repeat=0; printf("\nplease input a range of data, with the end of #:\n"); do{ ch=getchar(); prog[p++]=ch; }while(ch!='#'); //输入以#号键结束 p=0; do{ scanner(); //扫描,单词 switch(syn) { case 11: if(isDecimal==0) { //加了1个强制类型转换 printf("(%d,%d) ",syn,(int)sum); break; } else if(isExp==1) { printf("(%d,%e) ",syn,sum); isExp=0; isDecimal=0; break; } else if(isDecimal==1) { printf("(%d,%f) ",syn,sum); isDecimal=0; break; } case -1: printf("输入错误:") printf(" \n "); break; default: printf("(%d,%s) ",syn,token); } }while(syn!=0); getchar(); } void scanner() { sum=0; decimal=0; m=0; for(n=0;n<8;n++) token[n]=NULL; ch=prog[p++]; //从prog中读出一个字符到ch中 while(ch==' ') //跳过空字符(无效输入) ch=prog[p++]; if(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))) //ch是字母字符 { while(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))||((ch>='0')&&(ch<='9'))) { token[m++]=ch; //ch=>token ch=prog[p++]; //读下一个字符 } token[m++]='\0'; p--; //回退一格 syn=10; //如果是"main", "if", "else", "while", "do", "for" , "int" , "char" , "void"标识符中的一个 for(n=0;n<9;n++) if(strcmp(token,rwtab[n])==0) { syn=n+1; break; } } else if((ch>='0')&&(ch<='9')) { IsNum: if(isSignal==1) { //token[m++]='-'; } while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0'; //ch中数字本身是当做字符存放的 ch=prog[p++]; } if(ch=='.') { isDecimal=1; ch=prog[p++]; count=0; //之前忘了清零,123.123+123.123#两个浮点数就无法识别 while((ch>='0')&&(ch<='9')) { //pow(x,y)计算x的y次幂 temp=(ch-'0')*pow(0.1,++count); decimal=decimal+temp; //AddToDec(); ch=prog[p++]; } sum=sum+decimal; } if(ch=='e'||ch=='E') { isExp=1; ch=prog[p++]; if(ch=='-') { isNegative=1; ch=prog[p++]; } while((ch>='0')&&(ch<='9')) { //指数 index=index*10+ch-'0'; ch=prog[p++]; } //10的幂 //123e3代表123*10(3) //sum=sum*pow(10,index);是错误的 if(isNegative) sum=sum*pow(0.1,index); else sum=sum*pow(10,index); } if(isSignal==1) { sum=-sum; isSignal=0; } p--; syn=11; } else switch(ch) { case '<': m=0; token[m++]=ch;