编译原理实验一

合集下载

编译原理实验报告:实验一编写词法分析程序.

编译原理实验报告:实验一编写词法分析程序.

编译原理实验报告实验名称:实验一编写词法分析程序实验类型:验证型实验指导教师:何中胜专业班级:13软件四姓名:丁越学号:13030504电子邮箱:862245792@实验地点:秋白楼B720实验成绩:日期:2016年3 月18 日一、实验目的通过设计、调试词法分析程序,实现从源程序中分出各种单词的方法;熟悉词法分析程序所用的工具自动机,进一步理解自动机理论。

掌握文法转换成自动机的技术及有穷自动机实现的方法。

确定词法分析器的输出形式及标识符与关键字的区分方法。

加深对课堂教学的理解;提高词法分析方法的实践能力。

通过本实验,应达到以下目标:1、掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。

2、掌握词法分析的实现方法。

3、上机调试编出的词法分析程序。

二、实验过程以编写PASCAL子集的词法分析程序为例1.理论部分(1)主程序设计考虑主程序的说明部分为各种表格和变量安排空间。

数组 k为关键字表,每个数组元素存放一个关键字。

采用定长的方式,较短的关键字后面补空格。

P数组存放分界符。

为了简单起见,分界符、算术运算符和关系运算符都放在 p表中(编程时,还应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。

id和ci数组分别存放标识符和常数。

instring数组为输入源程序的单词缓存。

outtoken记录为输出内部表示缓存。

还有一些为造表填表设置的变量。

主程序开始后,先以人工方式输入关键字,造 k表;再输入分界符等造p表。

主程序的工作部分设计成便于调试的循环结构。

每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。

⑵词法分析过程考虑将词法分析程序设计成独立一遍扫描源程序的结构。

其流程图见图1-1。

图1-1该过程取名为 lexical,它根据输入单词的第一个字符(有时还需读第二个字符),判断单词类,产生类号:以字符 k表示关键字;i表示标识符;c表示常数;p表示分界符;s表示运算符(编程时类号分别为 1,2,3,4,5)。

编译原理实验一

编译原理实验一

实验内容:实现标准C语言词法分析器实验目的:1.掌握程序设计语言词法分析的设计方法;2.掌握DFA的设计与使用方法;3.掌握正规式到有限自动机的构造方法;实验要求:1.单词种别编码要求基本字(关键字)、运算符、界符:一符一种;标识符(变量名):统一为一种;常量():按类型编码;2.词法分析工作过程中建立符号表、常量表,并以文本文件形式输出;3.词法分析的最后结果以文本文件形式输出;4.完成对所设计词法分析器的功能测试,并给出测试数据和实验结果;5.为增加程序可读性,请在程序中进行适当注释说明;6.整理上机步骤,总结经验和体会;7.认真完成并按时提交实验报告。

二、设计方案:这个词法分析器分析的主要关键字有:main, int, float, char, if, else, for, while, do, switch, case, break; default……。

选择要分析的c文件,首先对其去掉注释和与空格处理,再根据字符的不同类型分析。

1、全局数据结构:*key[ ]:关键字表全局文件指针*fr,*fw, *temp1,*temp2用于文件的读写。

2、以层次图模块的组成及调用关系3、主要函数的设计要求(功能、参数、返回值):isKey:判断ch中的字符是否为关键字;isLer 和isNum:布尔函数过程,分别判断ch中的字符是否为字母和数字;isBoudany():布尔函数过程,分别判断ch组成的字符否为边界符号;check:词法分析;clock:时间函数,计算程序运行所需的时间main:主函数。

4、状态转换图:字符a包括:= , & , | , + , --字符b包括:-- , < , > , | , *字符c包括:, , : , ( , ) , { , } , [ , ] , ! ,# , % , ” , / , * , + , -- , > , <, .# include<stdio.h># include <string.h># include <stdlib.h># include <time.h># include <ctype.h>FILE *fr,*fw,*temp1,*temp2;char *key0[]={"main","printf","scanf","else","if","auto","double", "int","struct","break","long","switch","case","enum","register","typedef", "char","extern","return","union","const","float","short","unsigned","continue","for", "signed","void","default","goto","sizeof","volatile","do","while","static"};/*关键字表*/char *key1[]={"\"","\\","(",")","[","]","{","}",",",";","'"};/*边界符表*/int isLet(char c)//判断是否是字母{if(c>='a'&& c<='z'||c>='A'&&c<='Z')return 1;elsereturn 0;}int isNum(char c)//判断是否是数字{if (c>='0'&&c<='9')return 1;elsereturn 0;}int isKey(char *word){int m,i;for(i=0;i<36;i++){if((m=strcmp(word,key0[i]))==0){if(i==0)return 2;elsereturn 1;}}return 0;}int isBoudany(char c){if(c=='\\')return 2;elseif(c=='('||c==')'||c=='{'||c=='}'||c=='['||c==']'||c==','||c==';'||c=='\''||c=='\"'||c=='\"') return 1;elsereturn 0;}void check(FILE *fr){char word[30];while(!feof(fr)){memset(word,0,sizeof(word));char ch,temp;ch=fgetc(fr); //获取字符,指针fr并自动指向下一个字符int i,c;if(ch=='#')//预处理{//temp=fgetc(fr);while(ch!='>')ch=fgetc(fr);ch=fgetc(fr);fprintf(fw,"*****************************************跳过头文件和文件宏定义\n");}elseif (ch=='/')//跳过注释/**/类型{ch=fgetc(fr);if (ch=='/')//跳过注释//类型{while(ch!='\n')ch=fgetc(fr);fprintf(fw,"*********************************************************跳过注释\n");}elseif (ch=='*'){ch=fgetc(fr);temp=fgetc(fr);do{ch=fgetc(fr);temp=fgetc(fr);}while (ch!='*'||temp!='/');fprintf(fw,"******************************************************跳过注释\n");ch=fgetc(fr);}}elseif(isLet(ch)){word[0]=ch;ch=fgetc(fr);i=1;while(isNum(ch)||isLet(ch))//判断该字符是否是字母或数字{word[i]=ch;i++;ch=fgetc(fr);}word[i]='\0'; //'\0' 代表字符结束(空格)fseek(fr,-1,1);c=isKey(word); //判断是否是关键字if(c==0) //不是关键字{fprintf(temp1,"%s ",word);fprintf(fw,"字符%s是:标识符,种别编码为:%d\n",word,2);}else{if(ch!='"')//判断是否是定义的字符{if(c==2)fprintf(fw,"字符%s是:***************************************************主函数,种别编码为:%d\n",word,0);//主函数elsefprintf(fw,"字符%s是:关键字,种别编码为:%d\n",word,1);//关键字}else{fprintf(fw,"字符%s是:定义的字符常量,种别编码为:%d\n\n",word,32);}}}else//开始判断的字符不是字母if(isNum(ch)){ //判断是否是数字word[0]=ch;ch=fgetc(fr);i=1;while(isNum(ch)){word[i]=ch;i++;ch=fgetc(fr);}word[i]='\0';fseek(fr,-1,1); //回退fprintf(fw,"字符%s是:常量,种别编码为:%d\n",word,3);}else{c=isBoudany(ch);//开始判断的字符不是字母也不是数字//边界符if(c){if(c==2)//判断是否是转义字符{word[0]=ch;ch=fgetc(fr);word[1]=ch;word[2]='\0';fprintf(fw,"字符%s是:转义字符,种别编码为:%d\n",word,4);}elseif(c==1){fprintf(fw,"字符%c是:界符,种别编码为:%d\n",ch,5);fprintf(temp2,"%c ",ch);}}elseswitch(ch){case'+':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='='){word[2]='\0';fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,6);//运算符"+="}elseif(ch=='+'){word[2]='\0';fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,7); //判断结果为"++"}else {fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,8); //判断结果为"+"}break;case'-':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='='){word[2]='\0';fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,9); }elseif(ch=='-'){word[2]='\0';fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,10); //判断结果为"--"}else {fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,11); //判断结果为"-"}break;case'*':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch!='='){if(isNum(ch)){fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,12);//判断结果为"*"}else{ //判断是否是指针i=2;ch=fgetc(fr);while(isLet(ch)){word[i]=ch;ch=fgetc(fr);i++;}fprintf(fw,"字符%s:是指针定义运算符,种别编码为:%d\n",word,13);}}else{word[2]='\0';fprintf(fw,"字符%s:是运算符,种别编码为:%d\n",word,14);//判断结果为"*="}break;case'/':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch!='='){if(isNum(ch)){fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,15);//判断结果为"/"}}else {word[2]='\0';fprintf(fw,"字符%s:是运算符,,种别编码为:%d\n",word,16);//判断结果为"/="}break;case'!':case'?':case':':case'.':case'=':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch!='='){fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,17);}else {word[2]='\0';fprintf(fw,"字符%s:是运算符,种别编码为:%d\n",word,18);break;case'|':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='|'){word[2]='\0';fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,19); //判断结果为运算符"||"}else {fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,20); //判断结果为"|"}break;case'%':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='='){word[2]='\0';fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,21);}elseif(isLet(ch)){word[2]='\0';fprintf(fw,"字符%s是输出类型标识符,种别编码为:%d\n",word,22);}else{fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是取余运算符,种别编码为:%d\n",ch,23);}break;case'&':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='&'){word[2]='\0';fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,24); //判断结果为运算符"&&"}else {fseek(fr,-2,1);ch=getc(fr);fprintf(fw,"字符%c是:运算符,种别编码为:%d\n",ch,25); //判断结果为"&"}break;case'<':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='='){word[2]='\0';fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,26); //判断结果为运算符"<="}elseif(ch=='<'){word[2]='\0';fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,27); //判断结果为运算符"<<"}else{fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是:运算符,种别编码为:%d\n",ch,28); //判断结果为"<"}break;case'>':word[0]=ch;ch=fgetc(fr);word[1]=ch;if(ch=='=') {word[2]='\0';fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,29);}elseif(ch=='>'){word[2]='\0';fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,30);}else {fseek(fr,-2,1);ch=fgetc(fr);fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,31);}break;default: break;}}fprintf(fw,"\n");}}int main(){clock_t start,end;char cr;char str_in[25],str_out[25],str_out1[25],str_out2[25];double duration;start=clock();printf("请输入文件的读取路径(包含文件的后缀名):\n");scanf("%s",str_in);fr=fopen(str_in,"r");while(fr==NULL){printf("文件路径输入错误!请重新输入:\n");scanf("%s",str_in);fr=fopen(str_in,"r");}printf("文件读入成功!内容显示如下:\n");printf("**************************************************\n");cr=fgetc(fr);while (cr!=EOF) {putchar(cr);cr=fgetc(fr);}printf("\n");printf("**************************************************\n");printf("请输入文件的最终结果的写入路径(包含文件的后缀名):\n");scanf("%s",str_out);printf("请输入文件的常量表的写入路径(包含文件的后缀名):\n");scanf("%s",str_out1);printf("请输入文件的符号表的写入路径(包含文件的后缀名):\n");scanf("%s",str_out2);while(str_in==str_out||str_in==str_out1||str_in==str_out2){if(str_out==str_in){printf("请输入文件的最终结果的写入路径(包含文件的后缀名):\n");scanf("%s",str_out);}elseif(str_in==str_out1){printf("请输入文件的常量表的写入路径(包含文件的后缀名):\n");scanf("%s",str_out1);}elseif(str_in==str_out2){printf("请输入文件的符号表的写入路径(包含文件的后缀名):\n");scanf("%s",str_out2);}}fw=fopen(str_out,"w");temp1=fopen(str_out1,"w");temp2=fopen(str_out2,"w");while(fw==NULL||temp1==NULL||temp2==NULL){printf("文件写入路径错误,请重新输入:\n");if(fw==NULL){scanf("%s",str_out);fw=fopen(str_out,"w");}elseif(temp1=NULL){scanf("%s",str_out1);temp1=fopen(str_out1,"w");}elseif (temp2=NULL) {scanf("%s",str_out2);temp2=fopen(str_out2,"w");}}fprintf(temp1,"文件中依次出现的标识符\n");fprintf(temp2,"文件中依次出现的符号\n");fr=fopen(str_in,"r");check(fr);printf("文件写入成功!编译结果已写入指定文件区域!请注意查看...........\n\n");fclose(fw);fclose(temp1);fclose(temp2);fclose(fr);printf("\n");end=clock();duration=(double)(end-start)/CLOCKS_PER_SEC * 1000;printf("该词法分析程序共运行约%lf ms\n", duration);return 0;}测试结果:这个程序主要参考书上关于词法分析器的假设,完成了关于c语言词法分析的所有的功能。

编译原理实验报告(C语言)

编译原理实验报告(C语言)

编译原理实验报告实验项目1:词法分析程序实验一、实验的目的与任务:编译原理是计算机类专业特别是计算机软件专业的一门重要专业课。

设置该课程的目的在于系统地向学生讲述编译系统的结构、工作流程及编译程序各组成部分的设计原理和实现方法,使学生通过学习既掌握编译理论和方法方面的基本知识,也具有设计、实现、分析和维护编译程序等方面的初步能力。

编译原理是一门理论性和实践性都比较强的课程。

进行上机实验的目的是使学生通过完成上机实验题目加深对课堂教学内容的理解。

同时培养学生实际动手能力。

编译实验由三个独立实验组成,按照由浅入深进行排列,希望通过本实验使学生更深学习并理解编译的主要过程和相关方法。

词法分析的目的是将输入的源程序进行划分,给出基本符号(token)的序列,并掠过注解和空格等分隔符号。

基本符号是与输入的语言定义的词法所规定的终结符。

本实验要求学生编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。

并依次输出各个单词的内部编码及单词符号自身值。

(遇到错误时可显示“Error”,然后跳过错误部分继续进行)二、题目分析1.这里采用C语言编写的源程序作为词法分析程序的输入数据,输入数据保存在“in.txt”记事本中,将分析结果存在“out.txt”记事本中。

词法分析器的源代码使用C语言编写。

2.下面就词法分析程序中的主要变量进行说明:主函数main():打开要分析的C语言源程序,若不能正确打开,则报错。

先从源程序中读入一个字符ch,然后进行如下处理:1、cp消耗掉空格,制表符,换行符后,cp数组复位,开始检测cp;2、数字检测,对照符号表输出,若匹配成功,则返回序号;3、字符串检测, 对照符号表输出,若匹配成功,则返回序号;4、基本保留字检测,对照符号表输出,若匹配成功,则返回序号;5、运算符检测,对照符号表输出,若匹配成功,则返回序号;注意这里碰到‘/’时,要判断后面是否跟着是注释语句。

编译原理-实验1

编译原理-实验1

实验1《词法分析程序设计与实现》实验学时: 2 实验地点:实验日期:一、实验目的加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。

二、实验内容自定义一种程序设计语言,或者选择已有的一种高级语言,编制它的词法分析程序。

词法分析程序的实现可以采用任何一种编程语言和编程工具。

从输入的源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、界符。

并依次输出各个单词的内部编码及单词符号自身值。

(遇到错误时可显示“Error”,然后跳过错误部分继续显示)三、实验方法算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。

主程序初始包括以下两个方面:⑴关键字表的初值。

关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。

如能查到匹配的单词,则该单词为关键字,否则为一般标识符。

关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};图3-1(2)程序中需要用到的主要变量为syn,token和sum扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。

四、实验步骤1.定义目标语言的可用符号表和构词规则;2.依次读入源程序符号,对源程序进行单词切分和识别,直到源程序结束;3.对正确的单词,按照它的种别以<种别码,值>的形式保存在符号表中;4.对不正确的单词,做出错误处理。

五、实验结果输入begin x:=9: if x>9 then x:=2*x+1/3; end #显示结果如下:六、实验结论该词法分析器可以进行输入、预处理;关键字的识别;标识符的识别、常数的识别、算符和界符的识别等。

编译原理实验--词法分析器

编译原理实验--词法分析器

实验一词法分析器设计【实验目的】1.熟悉词法分析的基本原理,词法分析的过程以及词法分析中要注意的问题。

2.复习高级语言,进一步加强用高级语言来解决实际问题的能力。

3.通过完成词法分析程序,了解词法分析的过程。

【实验内容】用C语言编写一个PL/0词法分析器,为语法语义分析提供单词,使之能把输入的字符串形式的源程序分割成一个个单词符号传递给语法语义分析,并把分析结果(基本字,运算符,标识符,常数以及界符)输出。

【实验流程图】【实验步骤】1.提取pl/0文件中基本字的源代码while((ch=fgetc(stream))!='.'){int k=-1;char a[SIZE];int s=0;while(ch>='a' && ch<='z'||ch>='A' && ch<='Z'){if(ch>='A' && ch<='Z') ch+=32;a[++k]=(char)ch;ch=fgetc(stream);}for(int m=0;m<=12&&k!=-1;m++)for(int n=0;n<=k;n++){if(a[n]==wsym[m][n]) ++s;else s=0;if(s==(strlen(wsym[m]))) {printf("%s\t",wsym[m]);m=14;n=k+1;} }2.提取pl/0文件中标识符的源代码while((ch=fgetc(stream))!='.'){int k=-1;char a[SIZE]=" ";int s=0;while(ch>='a' && ch<='z'||ch>='A' && ch<='Z'){if(ch>='A' && ch<='Z') ch+=32;a[++k]=(char)ch;ch=fgetc(stream);}for(int m=0;m<=12&&k!=-1;m++)for(int n=0;n<=k;n++){if(a[n]==wsym[m][n]) ++s;else s=0;if(s==(strlen(wsym[m]))) {m=14;n=k+1;}}if(m==13) for(m=0;a[m]!=NULL;m++) printf("%c ",a[m]);3.提取pl/0文件中常数的源代码while((ch=fgetc(stream))!='.'){while(ch>='0' && ch<='9'){num=10*num+ch-'0';ch=fgetc(stream);}if(num!=0) printf("%d ",num);num=0;}4.提取pl/0文件中运算符的源代码int ch=fgetc(stream);while(ch!='.'){switch(ch){case'+': printf("+ ");break;case'-': printf("- ");break;case'*': printf("* ");break;case'/': printf("/ ");break;case'>': if(fgetc(stream)=='=')printf(">= "); else printf("> ");break;case'<': if(fgetc(stream)=='=')printf("<= "); else printf("< ");break;case':': printf(":= ");break;case'#': printf("# ");break;case'=': printf("= ");break;default: break;}ch=fgetc(stream);5.提取pl/0文件中界符的源代码int ch=fgetc(stream);while(ch!='.'){switch(ch){case',': printf(", ");break;case';': printf("; ");break;case'(': printf("( ");break;case')': printf(") ");break;default: break;}ch=fgetc(stream);}【实验结果】1.pl/0文件(222.txt)内容const a=10;var b,c;procedure p;beginc:=b+a;end;beginread(b);while b#0 dobegincall p;write(2*c);read(b)endend .2.实验运行结果【实验小结】1.了解程序在运行过程中对词法分析,识别一个个字符并组合成相应的单词,是机器能过明白程序,定义各种关键字,界符。

编译原理实验报告(手打)

编译原理实验报告(手打)

《编译原理》实验报告班级:计C104姓名:李云霄学号:108490实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。

二、实验内容选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来。

输入:由无符号数和+,-,*,/, ( , ) 构成的算术表达式,如1.5E+2-100。

输出:对识别出的每一单词均单行输出其类别码(无符号数的值暂不要求计算)。

三、实现方法与环境1、首先设计识别各类单词的状态转换图。

描述无符号常数的确定、最小化状态转换图如图1所示。

其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>, 1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。

图1 文法G[<无符号数>]的状态转换图其中编号0,1,2,…,6代表非终结符号<无符号数>、<余留无符号数>、<十进小数>、<小数部分>、<指数部分>、<整指数>及<余留整指数>, 1,2和6为终态,分别代表整数、小数和科学计数的识别结束状态。

在一个程序设计语言中,一般都含有若干类单词符号,为此可首先为每类单词建立一张状态转换图,然后将这些状态转换图合并成一张统一的状态图,即得到了一个有限自动机,再进行必要的确定化和状态数最小化处理,最后据此构造词法分析程序。

四则运算算术符号的识别很简单,直接在状态图的0状态分别引出相应标记的矢根据描述语言中各类单词的文法状态转换图或状态矩阵,利用某种语言(C语言或JAVA语言)直接编写词法分析程序。

编译原理—实验指导书-1

编译原理—实验指导书-1
(13)end.#
4.词法分析器的功能和输出格式
词法分析器的功能是输入以字符串表示的源程序,从左向右扫描每行源程序的符号,拼成单词,换成统一的二元式(单词种别码,单词符号的属性值)表示。对给定的程序通过词法分析器识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示,本程序是通过对给定路径的文件的分析后以单词符号和文字提示显示),本实验中,采用单词种别码是一符一种种别码的方式。
(4)var
(5)a,b,c:integer;
(6)x:char;
(7)begin
(8)if(a+c*3>b)and(b>3)thenc:=3;
(9)x:=2+(3*a)-b*c*8;
(10)forx:=1+2to3dob:=100;
(11)whilea>bdoc:=5;
(12)repeata:=10;untila>b;
(124){
(125)printf("%s\t$运算符\n\n",Word);
(126)}
(127)else if(ch=='-')
(128){
(129)printf("%s\t$运算符\n\n",Word); //判断结果为“--”
(2)设计描述Sample语言各类单词结构的状态转换图(即有限自动机FA);
如标识符的状态转换图可以用下图表示
其相应代码科为
(1)recog_id(char ch)
(2){
(3)char state='0';
(4)while(state!='2')
(5){
(6)switch(state)

《编译原理(实验部分)》实验1_程序预处理

《编译原理(实验部分)》实验1_程序预处理

《编译原理》(实验部分)实验1_程序预处理一、实验目的明确预处理子程序的任务,构造一个简单的预处理子程序,对源程序进行相应的预处理。

二、实验设备1、PC 兼容机一台;操作系统为WindowsWindowsXP。

2、Visual C++ 6.0 或以上版本, Windows 2000 或以上版本,汇编工具(在Software 子目录下)。

三、实验原理定义模拟的简单语言的词法构成,编制读入源程序和进行预处理的程序,要求将源程序读入到文件或存入数组中,再从文件或数组中逐个读取字符进行预处理,包括去掉注释、Tab、Enter和续行符等操作,并显示预处理后的程序。

四、实验步骤1、从键盘读入源程序存放到输入缓冲区中。

2、对源程序进行预处理,预处理后的程序存放到扫描缓冲区中。

3、显示预处理后的程序。

参考源程序(C++语言编写)//源程序的输入及预处理#include <fstream.h>#include <iostream.h>void pro_process(char *);void main( ) //测试驱动程序{//定义扫描缓冲区char buf[4048]={'\0'}; //缓冲区清0//调用预处理程序pro_process(buf); //在屏幕上显示扫描缓冲区的内容cout<<buf<<endl;}void pro_process(char *buf) //预处理程序{ifstream cinf("source.txt",ios::in);int i=0; //计数器char old_c='\0',cur_c; //前一个字符,当前字符。

bool in_comment=false; //false表示当前字符未处于注释中。

while(cinf.read(&cur_c,sizeof(char))){ //从文件读一个字符switch(in_comment){case false:if(old_c=='/' && cur_c=='*'){ //进入注释i--; //去除已存入扫描缓冲区的字符'/'in_comment=true;}else {if(old_c=='\\' && cur_c=='\n') //发现续行i--; //去除已存入扫描缓冲区的字符'\'else {if(cur_c>='A' && cur_c<='Z') //大写变小写cur_c+=32;if(cur_c =='\t' || cur_c =='\n')//空格取代TAB换行cur_c=' ';buf[i++]=cur_c ;}}break;case true:if(old_c=='*' && cur_c=='/') //离开注释in_comment=false;}//end of switchold_c= cur_c; //保留前一个字符}//end of whilebuf[i++]='#'; //在源程序尾部添加字符'#' }。

编译原理实验报告——词法分析器(内含源代码)

编译原理实验报告——词法分析器(内含源代码)

编译原理实验(一)——词法分析器一.实验描述运行环境:vc++2008对某特定语言A ,构造其词法规则。

该语言的单词符号包括:12状态转换图3程序流程:词法分析作成一个子程序,由另一个主程序调用,每次调用返回一个单词对应的二元组,输出标识符表、常数表由主程序来完成。

二.实验目的通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。

同时增强编写和调试程序的能力。

三.实验任务编制程序实现要求的功能,并能完成对测试样例程序的分析。

四.实验原理char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符char sign[50][10],constant[50][10];//存储标识符和常量定义了一个Analyzer类class Analyzer{public:Analyzer(); //构造函数 ~Analyzer(); //析构函数int IsLetter(char ch); //判断是否是字母,是则返回 1,否则返回 0。

int IsDigit(char ch); //判断是否为数字,是则返回 1,否则返回 0。

void GetChar(char *ch); //将下一个输入字符读到ch中。

void GetBC(char *ch); //检查ch中的字符是否为空白,若是,则调用GetChar直至ch进入一个非空白字符。

void Concat(char *strTaken, char *ch); //将ch中的字符连接到strToken之后。

int Reserve(char *strTaken); //对strTaken中的字符串查找保留字表,若是一个保留字返回它的数码,否则返回0。

void Retract(char *ch) ; //将搜索指针器回调一个字符位置,将ch置为空白字符。

计算机编译原理实验报告

计算机编译原理实验报告

编译原理实验报告实验一词法分析设计一、实验功能:1、对输入的txt文件内的内容进行词法分析:2、由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析3、打印出分析后的结果;二、程序结构描述:(源代码见附录)1、分别利用k[],s1[],s2[],s3[]构造关键字表,分界符表,算术运算符表和关系运算符表。

2、bool isletter(){} 用来判断其是否为字母,是则返回true,否则返回false;bool isdigit(){} 用来判断其是否为数字,是则返回true,否则返回false;bool iscalcu(){} 用来判断是否为算术运算符,是则返回true,否则返回false;bool reserve(string a[]){} 用来判断某字符是否在上述四个表中,是则返回true,否则返回false;void concat(){} 用来连接字符串;void getn(){} 用来读取字符;void getb(){} 用来对空格进行处理;void retract(){}某些必要的退格处理;int analysis(){} 对一个单词的单词种别进行具体判断;在主函数中用switch决定输出。

三、实验结果四、实验总结词法分析器一眼看上去很复杂,但深入的去做就会发现并没有一开始想象的那么困难。

对于一个字符的种别和类型可以用bool函数来判断,对于关键字和标示符的识别(尤其是3b)则费了一番功夫,最后对于常数的小数点问题处理更是麻烦。

另外,这个实验要设定好时候退格,否则将会导致字符漏读甚至造成字符重复读取。

我认为,这个实验在程序实现上大体不算困难,但在细节的处理上则需要好好地下功夫去想,否则最后的程序很可能会出现看上去没有问题,但实际上漏洞百出的状况。

将学过的知识应用到实际中并不简单,只有自己不断尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。

实验二LL(1)分析法一、实验原理:1、写出LL(1)分析法的思想:当一个文法满足LL(1)条件时,我们就可以为它构造一个不带回溯的自上而下的分析程序,这个分析程序是有一组递归过程组成的,每个过程对应文法的一个非终结符。

编译原理实验报告1

编译原理实验报告1

编译原理实验报告某某:班级:学号:自评:中实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。

二、实验内容根据教学要求并结合学生自己的兴趣和具体情况,从具有代表性的高级程序设计语言的各类典型单词中,选取一个适当大小的子集。

例如,可以完成无符号常数这一类典型单词的识别后,再完成一个尽可能兼顾到各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。

输入:由符合或不符合所规定的单词类别结构的各类单词组成的源程序。

输出:把单词的字符形式的表示翻译成编译器的内部表示,即确定单词串的输出形式。

例如,所输出的每一单词均按形如(CLASS,V ALUE)的二元式编码。

对于变量和常数,CLASS字段为相应的类别码;V ALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。

对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,V ALUE字段则为“空”。

另外,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上放置单词类别的助记符。

三、实现方法与环境词法分析是编译程序的第一个处理阶段,本次试验用手工的方式(C语言)构造词法分析程序。

根据文法和状态转换图直接编写词法分析程序。

四、基本实验题目1)题目1:试用手工编码方式构造识别以下给定单词的某一语言的词法分析程序。

语言中具有的单词包括五个有代表性的关键字begin、end、if、then、else;标识符;整型常数;六种关系运算符;一个赋值符和四个算术运算符。

参考实现方法简述如下。

单词的分类:构造上述语言中的各类单词符号及其分类码表。

表I 语言中的各类单词符号及其分类码表+ 15 PL- 16 MI* 17 MU/ 18 DI处理过程:在一个程序设计语言中,一般都含有若干类单词符号,为此首先为每类单词建立一X状态转换图,然后将这些状态转换图合并成一X统一的状态图,即得到了一个有限自动机,再进行必要的确定化和状态数最小化处理,最后据此构造词法分析程序。

编译原理实验报告1

编译原理实验报告1

03091337 李璐 03091339 宗婷婷一、上机题目:实现一个简单语言(CPL)的编译器(解释器)二、功能要求:接收以CPL编写的程序,对其进行词法分析、语法分析、语法制导翻译等,然后能够正确的执行程序。

三、试验目的1.加深编译原理基础知识的理解:词法分析、语法分析、语法制导翻译等2.加深相关基础知识的理解:数据结构、操作系统等3.提高编程能力4.锻炼独立思考和解决问题的能力四、题目说明1.数据类型:整型变量(常量),布尔变量(常量)取值范围{…, -2, -1, 0, 1, 2, …}, {true, false}2、运算表达式:简单的代数运算,布尔运算3、程序语句:赋值表达式,顺序语句,if-else语句,while语句五、环境配置1.安装Parser Generator、Visual C++;2.分别配置Parser Generator、Visual C++;3.使用Parser Generator创建一个工程编写l文件mylexer.l;编译mylexer.l,生成mylexer.h与mylexer.c;4.使用VC++创建Win32 Console Application工程并配置该项目;加入mylexer.h与mylexer.c,编译工程;执行标识符数字识别器;注意:每次修改l文件后,需要重新编译l文件,再重新编译VC工程六、设计思路及过程设计流程:词法分析LEX的此法分析部分主要利用有限状态机进行单词的识别,在分析该部分之前,首先应该对YACC的预定义文法进行解释。

在YACC中用%union扩充了yystype的内容,使其可以处理char型,int型,node型,其中Node即为定义的树形结点,其定义如下:typedef enum { TYPE_CONTENT, TYPE_INDEX, TYPE_OP } NodeEnum;/* 操作符 */typedef struct {int name; /* 操作符名称 */int num; /* 操作元个数 */struct NodeTag * node[1]; /* 操作元地址可扩展 */} OpNode;typedef struct NodeTag {NodeEnum type; /* 树结点类型 *//* Union 必须是最后一个成员 */union {int content; /* 内容 */int index; /* 索引 */OpNode op; /* 操作符对象 */};} Node;extern int Var[26];结点可以是三种类型(CONTENT,INDEX,OP)。

编译原理实验一1

编译原理实验一1

实验2:语法分析程序班级:计算机1103 姓名:王静 学号:1101308336一、 实验目的与实验1.复习上下文无关文法的基本结构、判断方法;2.理解文法存在左递归、回溯现象的害处及消除方法,掌握FIRST 集、FOLLOW 集的含义、求解方法与用途,掌握LL (1)文法的判断方法及构造技术;3.掌握预测分析法的理论精髓,理解下推自动机的基本概念及运行原理;4.学会基于上下文无关文法构造LL (1)预测表,并使用Visual C++编写LL(1)分析器;5.能利用预测分析法,在给定的文法基础上,分析特定输入串的语法结构, 能判断其是否合法,并能提取大部分中间信息,以备后续分析时使用。

二、 实验仪器与设备1. 微型电子计算机(PC 机)。

2. 配置Windows 2000及以上版本操作系统。

3. 安装Visual C++6.0或Visual C#2003或Delphi6.0等以上版本的 开发环境。

三、实验内容与步骤1.实验内容已知文法G[E]:E →E+T|E-T|TT →T*F|T/F|FF →(E)|I编写该文法的LL(1)语法分析程序,用以识别下面的符号串: #((i+i)*i-i)/i#1 2 0 0 1-90-9 其它 无符号整数 4 5 3 6 7 9 1其他 ( ) + - * #8/2.实验步骤(一)准备工作回答下面问题,并将分析过程与结果写在实验报告册上。

上述文法G[E]存在左递归吗?若存在,首先消除左递归,得到对应的文法G ’[E];构造文法G ’[E]的预测分析表(需要先求FIRST 、FOLLOW 集),并根据定义, 逐步判断该文法是否为LL(1)文法;基于上述分析表,仿照教材,写出符号串#((i+i)*i-i)/i#的详细的分析过程。

2. 状态转换图1 2 0 01-0-9|其它 无符号整数 4 5 3 6 7 8 9 其他 ()+-*/3. 实验步骤1. 判断所给出的转换图能否实现预期目的?若有错误,请加以修正;2. 尝试将状态图转换为正则文法;3. 试写出无符号整数对应的正则表达式;4. 根据上述结果,构造出最简的DFA;5.编写对应的词法分析程序,并识别下述符号串:((23+12)*9-200)/54. 流程图开始接受输入字符串是是否为字符串尾否按位字符判断否是否为有效输入是进入自动机判断结果结束1.源程序FILE *fp;char cbuffer;char*key[8]={"if","else","for","while","do","return","break","contin ue"};char *border[6]={",",";","{","}","(",")"};char *arithmetic[4]={"+","-","*","/"};char *relation[6]={"<","<=","=",">",">=","<>"};char *consts[20]={"0","1","2","3","4","5","6","7","8","9"}; char *label[20];int constnum=0,labelnum=0;int search(char searchchar[],int wordtype){ int i=0;switch (wordtype) {case 1:for (i=0;i<=7;i++){ if (strcmp(key[i],searchchar)==0){return(i+1);}}break;case 2:{for (i=0;i<=5;i++){ if (strcmp(border[i],searchchar)==0) return(i+1);} return(0);}break;case 3:{for (i=0;i<=3;i++){ if (strcmp(arithmetic[i],searchchar)==0) { return(i+1);}}return(0);}break;case 4:{for (i=0;i<=5;i++){ if (strcmp(relation[i],searchchar)==0) {return(i+1);} }return(0);}break;case 5:{for (i=0;i<=constnum;i++){ if (strcmp(consts[i],searchchar)==0){ return(i+1);} }}break;case 6:{for (i=0;i<=labelnum;i++){ if (strcmp(label[i],searchchar)==0){ return(i+1);} }label[i-1]=(char *)malloc(sizeof(searchchar));strcpy(label[i-1],searchchar);labelnum++;return(i);}break;}}char alphaprocess(char buffer)//关键字{ int atype;int i=-1;char alphatp[20];while ((isalpha(buffer))||(isdigit(buffer))){ alphatp[++i]=buffer;buffer=fgetc(fp);}alphatp[i+1]='\0';if (atype=search(alphatp,1))printf("%s \t(1,%d)\n",alphatp,atype-1);//结束else { atype=search(alphatp,6);printf("%s \t(6,%d)\n",alphatp,atype-1);}return(buffer);}char digitprocess(char buffer)//数字{ int i=-1;char digittp[20];int dtype;while ((isdigit(buffer))){ digittp[++i]=buffer;buffer=fgetc(fp);}digittp[i+1]='\0';dtype=search(digittp,5);printf("%s \t(5,%d)\n",digittp,dtype-1);return(buffer);}char otherprocess(char buffer)//其它字符{ int i=-1;char othertp[20];int otype,otypetp;othertp[0]=buffer;othertp[1]='\0';if (otype=search(othertp,3)){ printf("%s \t(3,%d)\n",othertp,otype-1);buffer=fgetc(fp);goto out;}if (otype=search(othertp,4)){ buffer=fgetc(fp);othertp[1]=buffer;othertp[2]='\0';if (otypetp=search(othertp,4)){ printf("%s \t(4,%d)\n",othertp,otypetp-1);goto out;}elseothertp[1]='\0';printf("%s \t(4,%d)\n",othertp,otype-1); goto out;}if (buffer==':'){ buffer=fgetc(fp);if (buffer=='=')printf(":= (2,2)\n");buffer=fgetc(fp);goto out;}else{ if (otype=search(othertp,2)) { printf("%s \t(2,%d)\n",othertp,otype-1); buffer=fgetc(fp);goto out;}}if ((buffer!='\n')&&(buffer!=' '))printf("%c error,not a word\n",buffer); buffer=fgetc(fp);out: return(buffer);}void main(){int i;for (i=0;i<=20;i++){label[i]=NULL;};if ((fp=fopen("message.txt","r"))==NULL)printf("error");else{cbuffer = fgetc(fp);while (cbuffer!=EOF){if (isalpha(cbuffer))cbuffer=alphaprocess(cbuffer);else if (isdigit(cbuffer))cbuffer=digitprocess(cbuffer);elsecbuffer=otherprocess(cbuffer);}printf("over\n");getchar();}}2.运行结果四、实验小结。

编译原理实验一

编译原理实验一

编译原理实验一实验1 词法分析程序的设计计科143 王祥真6103114095一、实验目的掌握计算机语言的词法分析程序的开发方法。

二、实验内容编制一个能够分析三种整数、标识符、主要运算符和主要关键字的词法分析程序。

三、实验要求1、根据以下的正规式,编制正规文法,画出状态图;标识符<字母>(<字母>|<数字字符>)*十进制整数0 |(1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*如有余力,则进一步分析八进制和十六进制整数,其正规式如下:八进制整数0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)*十六进制整数0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)*运算符和界符+ - * / > < = <= >= ( ) ;{ }关键字main if then else while do int (可根据需要添加)2、根据状态图,设计词法分析函数int scan( ),完成以下功能:1)从文本文件中读入测试源代码,根据状态转换图,分析出一个单词,2)以二元式形式输出单词<单词种类,单词属性>其中单词种类用整数表示:0:标识符1:十进制整数2:八进制整数3:十六进制整数运算符和界符,关键字采用一字一符,不编码其中单词属性表示如下:标识符,整数由于采用一类一符,属性用单词表示运算符和界符,关键字采用一字一符,属性为空3、编写测试程序,反复调用函数scan( ),输出单词种别和属性。

四、实验环境PC微机DOS操作系统或Windows 操作系统Turbo C 程序集成环境或Visual C++ 程序集成环境或Eclipse集成环境五、实验步骤1、根据正规式,画出状态转换图;2、根据状态图,设计词法分析算法;3、采用C或C++或Java语言,设计函数scan( ),实现该算法;4、编制测试程序(主函数main);5、调试程序:读入文本文件program.txt,运行程序得到输出结果result.txt,并检查输出结果是否正确。

编译原理实验报告

编译原理实验报告

实验一词法分析一、实验目的通过设计、编写和调试词法分析程序,了解词法分析程序的作用,组成结构,不同种类单词的识别方法,掌握由单词的词法规则出发,画出识别单词的状态转换图,然后在用程序实现词法分析程序设计方法。

二、词法规则1、注释用{和}括起来。

注释体中不能有{。

注释可以出现在任何记号的后面。

2、记号间的空格可有可无,但关键字前后必须有空格、换行、程序的开头或者结尾的原点。

3、标识符的记号id 与以字母开头的字母数字串相匹配:Letter->[a-zA-Z]Digit->[0-9]Id->letter (letter | digit)*4、记号num与无符号整数相匹配:Digits->digit digit*Optional_fraction -> . Digits | ɛOptional_exponent->(E(+ | - | ɛ ) digits) | ɛNum ->digits optional_fraction optional_exponent5、关键字要被保留且在文法中以黑体出现6、关系运算符(relop)指:=、<、<>、<=、>=、>7、Addop: + 、 - 、or8、Mulop:*、/ 、div、mod、and9、Assignop: :=三、词法分析程序详细设计及判别状态图1、无符号数(可带小数和指数)的状态转换图:2、标识符/关键字的状态转换图:字母或数程序详细设计:四、开发环境本程序在Microsoft Visual C++ 6.0环境中编写,无特殊编译要求。

五、函数清单void LexcialAnalysis(FILE *fp);//词法分析主函数int JudgeFirstLetter(char ch);//判断单词的第一个字符int IsDigit(char ch);//判断是否为数字int IsLetter(char ch);//判断是否为字母int IsSpecialPunc(char ch);//判断是否为特殊标点void RecogDigit(char StrLine[]);//用状态图识别无符号数字void RecogIdentifier(char strLine[]);//用状态图识别标识符void RecogPunc(char strLine[]);//识别特殊标点int IsKeyWord(string str);//判断标识符是否为关键字void error();//出错处理六、测试程序program example(input, output);{comments goes here!}var x, y: integer;function gcd(a, b: integer): integer;beginif b =1.2e3 then gcd := aelse gcd := gcd(b, a mod b)end;beginread(x, y);write(gcd(x, y));end.七、运行效果八、实验总结通过这次编译器词法分析程序的编写,我更好地了解了词法分析的作用及工作原理,讲课本中的知识融入到程序编写过程中,理论结合了实际。

编译原理实验内容一

编译原理实验内容一

实验一词法分析程序
一、实验目的
设计、编写、调试一个具体的词法分析程序,实现从源程序中识别出各种单词符号的功能,加深对词法分析原理的理解,并掌握对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

二、实验教学基本要求
1.掌握从源程序文件中读取有效字符的方法和并结合单词符号构词方法生成相应的单词符号,并将识别出的单词符号输出到文件中。

2.掌握词法分析的实现方法。

3.上机调试词法分析程序。

三、实验教学的内容或要求
1.编制一个词法分析程序,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。

2.并依次输出各个单词的内部编码(种别)及单词符号自身值。

编译原理实验

编译原理实验

实验一词法扫描器设计一实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。

二实验内容设计一个简单的类C语言的词法扫描器。

三实验要求(一)程序设计要求(1)根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。

(2)提供源程序输入界面;(3)词法分析后可查看符号表和TOKEN串表;(4)保存符号表和TOKEN串表(如:文本文件);(5)遇到错误时可显示提示信息,然后跳过错误部分继续进行分析。

(二)实验报告撰写要求(1)系统功能(包括各个子功能模块的功能说明);(2)开发平台(操作系统、设计语言);(3)设计方案;1)主数据流图;2)主要子程序的流程框图(若有必要);3)模块结构图;4)主要数据结构:符号表、TOKEN串表等。

(4)具体设计过程(包括主控程序、各个功能模块的具体实现)。

四实验总结附录:类C语言的词法文法id→ Letter <temp>int10→ Num int10 | NumOP→ +| - |* |/ |>| < | = | ( | ) | ; | ‘ | == | >= |<= | !=Keyword→if | then | else | while | doLetter→a|b|c|d|e|f|g|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T| U|V|W|X|Y|ZNum→0|1|2|3|4|5|6|7|8|9 |ε<temp>→ Letter <temp> | Num <temp> |ε实验二 LR语法分析技术一实验目的通过设计调试LR语法分析程序,实现根据词法分析的输入TOKEN字,进行文法的语法分析;加深对课堂教学的理解;提高语法分析方法的实践能力。

编译原理实验报告(一)

编译原理实验报告(一)

编译原理实验报告(一)一、实验题目:简单词法分析器的设计二、实验目的:熟悉并实现一个简单的扫描器三、实验内容:1.设计扫描器的自动机;2.设计翻译、生成Token的算法;3.编写代码并上机调试运行通过。

要求:输入——源程序文件;输出——(1)相应的Token序列;(2)关键字、界符表,符号表,常数表。

四、扫描器设计:自动机:关键字表和界符表单词编码program 3procedure 4④-begin 5end 6while 7do 8+ 9* 10⑧-:11:= 12⑨-= 13,14;15五、概要设计:(1)各模块概要设计1.判断当前读入的字符是字母还是数字int IsLetter(char ch) //判断ch是否为字母 { if (ch是A~Z或a~z) return 1;else return 0;}int IsDigit(char ch) //判断ch是否为数字{ if (ch是0~9) return 1;else return 0;}2.将读入的字符连接成单词或数while (IsLetter(ch)||IsDigit(ch)){ Concat(); //将ch中的字符拼接到strToken中ch=GetChar();}3.查表判断当前的独立串是关键字、标示符还是常数4.求出当前的独立串的code 和value(2)程序说明:1、关键字表、界符表和常数表中初始化后都有元素,即都不是空表。

而符号表则是空的。

它用来存放用户自己定义的变量名,按输入的被识别串中的顺序依次标识其value的值的1,2,3,……,n。

2、value=-1用来标识它是一个关键字;value=1用来标识它是一个界符常数的code值一定为2六、程序源代码及注释:#include "stdio.h"#include "string.h"#define N 15struct TokenType{ int code,value; };char*keywords[]={"program","procedure","begin","end","while","do","+","*",":",":=","=",",",";","(",")",}; //关键字表、界符表char ID[10][10]; //符号表int m;int Cons[10]; //常数表int n;void print(struct TokenTykpe token) //输出Token{ printf("( %d %d)\n",token.code,token.value);}void ProcError(){ printf("Error! You haven't defined it!");}int IsLetter(char ch) //判断ch是否为字母¸{ if (ch>='A' && ch<='Z' || ch>='a' && ch<='z')return 1; else return 0;}int IsDigit(char ch) //判断ch是否为数字{ if (ch>='0' && ch<='9') return 1;else return 0;}int Reserve(char *strToken) //用strToken中的单词去查关键字表。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

南昌航空大学实验报告课程名称:编译原理实验名称:实验一文法的判断与处理班级:学生姓名:学号:指导教师评定:签名: XXX一、实验目的理解文法的判断与处理。

二、实验要求:1)编写一段程序,接受文法的输入;2)从文法的产生式中分离出非终结符和终结符,并输出;3)判断该文法的文法类型,是否为0型,1型,2型或3型文法,并输出判断结果。

4)文法用二维数组来存储,定义符号→用“:”代替。

如文法G[S]:aS:aBbS:bAA:bAAA:aA:aSB:bB:bSB:aBB三、程序源代码1.该实例程序的源代码如下:#include <stdio.h>#include <string.h>#include <stdlib.h>/**//*全局变量定义*/char inputString[10]; /**//*用来存储用户输入的字符串,最长为20个字符*/char stack[10]; /**//*用来进行语法分析的栈结构*/int base=0; /**//*栈底指针*/int top=1; /**//*栈顶指针*/char VT[4]={'a','d','b','e'}; /**//*用来存放5个终结符*/char chanShengShi[10]; /**//*用来存放预测分析表M[A,a]中的一条产生式*/int firstCharIntex=0; /**//*如果a匹配产生式,则每次firstCharIntex 自增1 */ /**//*firstCharIntex用来存放用户输入串的第一个元素的下标*//**//*自定义函数声明*/char pop() ; /**//*弹出栈顶元素*/int push(char) ; /**//*向栈内添加一个元素,成功返回1,若栈已满则返回0*/int search(char temp) ; /**//*查找非终结符集合VT中是否存在变量temp,存在返回1,不存在返回0*/int M(char A, char a) ; /**//* 若预测分析表M[A,a]中存在产生式,则将该产生式赋给字符数组chanShengShi[10],并返回1,若M[A,a]中无定义产生式则返回0*/void init() ; /**//*初始化数组inputString[10] 、栈stack[10] 和chanShengShi[10]*/int yuCeFenXi() ; /**//* 进行输入串的预测分析的主功能函数,若输入串满足文法则返回1,不满足则返回0void printStack(); /**//*打印栈内元素*/void printinputString(); /**//*打印用户输入串*//**//*进入主函数*/void main(){system("cls");yuCeFenXi(); /**//*调用语法预测分析函数*/system("pause");}/**//*函数的定义*/int yuCeFenXi(){char X; /**//*X变量存储每次弹出的栈顶元素*/char a; /**//*a变量存储用户输入串的第一个元素*/int i;int counter=1; /**//*该变量记录语法分析的步骤数*/init(); /**//*初始化数组*/printf("wen fa : \n"); /**//*输出文法做为提示*/printf("S -> aH \n");printf("H -> aMd | d \n");printf("M -> Ab | \n");printf("A -> aM | e \n");printf("\ninput string ,'#' is a end sign !!(aaabd#) \n"); /**//*提示用户输入将要测试的字符串*/scanf("%s",inputString);push('#');push('S');printf("\nCounter-----Stack---------------Input string \n"); /**//*输出结果提示语句*/while(1) /**//*while循环为语法分析主功能语句块*/{printf(" ");printf(" %d",counter); /**//*输出分析步骤数*/printf(" "); /**//*输出格式控制语句*/printStack(); /**//*输出当前栈内所有元素*/X=pop(); /**//*弹出栈顶元素赋给变量X*/printinputString(); /**//*输出当前用户输入的字符串*/if( search(X)==0 ) /**//*在终结符集合VT中查找变量X的值,存在返回1,否则返回0*/{if(X == '#') /**//*栈已经弹空,语法分析结果正确,返回1*/{printf("success \n"); /**//*语法分析结束,输入字符串符合文法定义*/return 1;}else{a = inputString[firstCharIntex];if( M(X,a)==1 ) /**//*查看预测分析表M[A,a]是否存在产生式,存在返回1,不存在返回0*/{for(i=0;i<10;i++) /**//* '$'为产生式的结束符,for循环找出该产生式的最后一个元素的下标*/{if( chanShengShi[i]=='$' ) break;}i-- ; /**//*因为'$' 不是产生式,只是一个产生式的结束标志,所以i自减1*/while(i>=0){push( chanShengShi[i] );/**//*将当前产生式逆序压入栈内*/i-- ;}}else{printf(" error(1) !!\n"); /**//*若预测分析表M[A,a]不存在产生式,说明语法错误*/return 0;}}}else /**//*说明X为终结符*/{if( X==inputString[firstCharIntex] ) /**//*如果X等于a,说明a 匹配*/{firstCharIntex++; /**//*输入串的第一个元素被约去,下一个元素成为新的头元素*/}else{printf(" error(2) !! \n");return 0;}}counter++;}}void init(){int i;for(i=0;i<10;i++){inputString[i]=NULL; /**//*初始化数组inputString[10] */stack[i]=NULL; /**//*初始化栈stack[10] */chanShengShi[i]=NULL; /**//*初始化数组chanShengShi[10]*/ }}int M(char A, char a) /**//*文法定义因实际情况而定,该文法为课本例题的文法*/ { /**//*该函数模拟预测分析表中的二维数组*/if( A=='S'&& a=='a' ) { strcpy(&chanShengShi[0],"aH$"); return 1; }if( A=='H'&& a=='a' ) { strcpy(&chanShengShi[0],"aMd$"); return 1; }if( A=='H'&& a=='d' ) { strcpy(&chanShengShi[0],"d$"); return 1; }if( A=='M'&& a=='a' ) { strcpy(&chanShengShi[0],"Ab$"); return 1; }if( A=='M'&& a=='d' ) { strcpy(&chanShengShi[0],"$"); return 1; }if( A=='M'&& a=='b' ) { strcpy(&chanShengShi[0],"$"); return 1; }if( A=='M'&& a=='e' ) { strcpy(&chanShengShi[0],"Ab$"); return 1; }if( A=='A'&& a=='a' ) { strcpy(&chanShengShi[0],"aM$"); return 1; }if( A=='A'&& a=='e' ) { strcpy(&chanShengShi[0],"e$"); return 1; }else return 0; /**//*没有定义产生式则返回0*/}char pop() /**//*弹出栈顶元素,用topChar返回*/{char topChar;topChar=stack[--top];return topChar;}int push(char ch){if( top>9 ){printf(" error : stack overflow "); /**//*栈空间溢出*/return 0;}else{stack[top]=ch; /**//*给栈顶空间赋值*/top++;return 1;}}int search(char temp){int i,flag=0; /**//*flag变量做为标志,若找到temp则赋1,否则赋0*/for(i=0;i<4;i++){if( temp==VT[i] ) /**//*终结符集合中存在temp*/{flag=1;break;}}if(flag==1) return 1; /**//*flag==1说明已找到等于temp的元素*/else return 0;}void printStack() /**//*输出栈内内容*/{int temp;for(temp=1;temp<top;temp++){printf("%c",stack[temp]);}}void printinputString() /**//*输出用户输入的字符串*/{int temp=firstCharIntex ;printf(" "); /**//*该句控制输出格式*/do{printf("%c",inputString[temp]);temp++;}while(inputString[temp-1]!='#');printf(" \n");}。

相关文档
最新文档