编译原理 实验一 词法分析程序开发
- 格式:doc
- 大小:156.50 KB
- 文档页数:11
编译原理实验报告实验名称:实验一编写词法分析程序实验类型:验证型实验指导教师:何中胜专业班级: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)。
编译原理实验⼀词法分析实验⼀词法分析【实验⽬的】 (1)熟悉词法分析器的基本功能和设计⽅法; (2)掌握状态转换图及其实现; (3)掌握编写简单的词法分析器⽅法。
【实验内容】 对⼀个简单语⾔的⼦集编制⼀个⼀遍扫描的词法分析程序。
【实验要求】 (1)待分析的简单语⾔的词法 1) 关键字 begin if then while do end 2) 运算符和界符 := + - * / < <= <> > >= = ; ( ) # 3) 其他单词是标识符(ID)和整形常数(NUM),通过以下正规式定义: ID=letter(letter|digit)* NUM=digitdigit* 4) 空格由空⽩、制表符和换⾏符组成。
空格⼀般⽤来分隔 ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
(2)各种单词符号对应的种别编码 (3)词法分析程序的功能 输⼊:所给⽂法的源程序字符串 输出:⼆元组(syn,token 或 sum)构成的序列。
syn 为单词种别码; token 为存放的单词⾃⾝字符串; sum 为整形常数。
【实验代码】1 #include<iostream>2 #include<string.h>3 #include<conio.h>4 #include<ctype.h>5using namespace std;6int sum,syn,p,m,n;7char ch,chs[8],s[100];8char *tab[6]={"begin","if","then","while","do","end"};910int scanner(){11for(n=0;n<8;n++) chs[n]='\0';12 m=0;13 n=0;14 ch=s[p++];15while(ch=='') ch=s[p++];16if(isalpha(ch)){17while(isalpha(ch)||isdigit(ch)){18//isalpha(ch)函数:判断字符ch是否为英⽂字母,⼩写字母为2,⼤写字母为1,若不是字母019//isdigit(ch)函数:判断字符ch是否为数字,是返回1,不是返回020 chs[m++]=ch;21 ch=s[p++];22 }23 syn=10;24for(n=0;n<6;n++)25if(strcmp(chs,tab[n])==0) syn=n+1;26 p--;27 }else if(isdigit(ch)){28 sum=0;29while(isdigit(ch)){30 sum=sum*10+(ch-'0');31 ch=s[p++];32 }33 syn=11;34 p--;35 }else if(ch==':'){36 syn=17;37 chs[m++]=ch;38 ch=s[p++];39if(ch=='='){ syn=18;chs[m]=ch;p++;}40 p--;41 }else if(ch=='<'){42 syn=20;43 chs[m++]=ch;44 ch=s[p++];45if(ch=='>') { syn=21;chs[m]=ch;p++;}46if(ch=='=') { syn=22;chs[m]=ch;p++;}47 p--;48 }else if(ch=='>'){49 syn=23;50 chs[m++]=ch;51 ch=s[p++];52if(ch=='=') { syn=24;chs[m]=ch;p++;}53 p--;54 }else switch(ch){55case'+':syn=13;chs[m]=ch;break;56case'-':syn=14;chs[m]=ch;break;57case'*':syn=15;chs[m]=ch;break;58case'/':syn=16;chs[m]=ch;break;59case'=':syn=25;chs[m]=ch;break;60case';':syn=26;chs[m]=ch;break;61case'(':syn=27;chs[m]=ch;break;62case')':syn=28;chs[m]=ch;break;63case'#':syn=0;chs[m]=ch;break;64default:syn=-1;65 }66return0;67 }68int main(){69 p=0;70 cout<<"Please input code and end with character '#':"<<endl;71do{72//cin>>ch;不识别空格73 ch=getchar();74 s[p++]=ch;75 }while(ch!='#');76 p=0;77do{78 scanner();79switch(syn){80case11:cout<<'('<<syn<<','<<sum<<')'<<endl;break;81case -1:cout<<'('<<syn<<','<<"error"<<')'<<endl;break;82default:cout<<'('<<syn<<','<<chs<<')'<<endl;83 }84 }while(syn!=0);85//getch():是⼀个不回显函数,当⽤户按下某个字符时,函数⾃动读取,⽆需按回车,所在头⽂件是conio.h。
编译原理实验报告班级姓名:学号:自我评定:实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容根据教学要求并结合学生自己的兴趣和具体情况,从具有代表性的高级程序设计语言的各类典型单词中,选取一个适当大小的子集。
例如,可以完成无符号常数这一类典型单词的识别后,再完成一个尽可能兼顾到各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。
输入:由符合或不符合所规定的单词类别结构的各类单词组成的源程序。
输出:把单词的字符形式的表示翻译成编译器的内部表示,即确定单词串的输出形式。
例如,所输出的每一单词均按形如(CLASS,VALUE)的二元式编码。
对于变量和常数,CLASS字段为相应的类别码;VALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。
对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。
另外,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上放置单词类别的助记符。
三、实现方法与环境词法分析是编译程序的第一个处理阶段,可以通过两种途径来构造词法分析程序。
其一是根据对语言中各类单词的某种描述或定义(如BNF),用手工的方式(例如可用C语言)构造词法分析程序。
一般地,可以根据文法或状态转换图构造相应的状态矩阵,该状态矩阵同控制程序便组成了编译器的词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。
构造词法分析程序的另外一种途径是所谓的词法分析程序的自动生成,即首先用正规式对语言中的各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程序所应进行的语义处理工作,然后由一个所谓词法分析程序的构造程序对上述信息进行加工。
编译原理词法分析实验报告实验一词法分析一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
二、实验内容(1)功能描述:该程序是实现一个词法分析器,词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是将单词分为五种的方法。
识别关键字:main、if、int、for、while、do、return、break、continue;单词种别码为1。
标识符:单词种别码为2。
常数:为无符号整形数;单词种别码为3。
运算符:包括:+、-、*、/、=、>、<、>=、<=、!= ;单词种别码为4。
分隔符:包括:,、;、{、}、(、);单词种别码为5。
(2)程序结构描述:输入:从控制台输入一段源程序代码,对输入的代码进行词法分析,处理:分离出关键字、标识符、数值、运算符和界符。
输出:在词法分析结果表中输出每个单词所在行号、类型以及它所对应的编码。
其中,编码是自定义的,一种类型对应一个编码。
词法分析结果显示在控制台上。
(3)程序设计思路1、定义编码表,用ArrayList集合存放单词,如:关键字、运算符、分界符。
这三种单词是固定的,标示符和数字这两种单词不存放在集合中。
编码表是固定的,只需要初始化一次就够了,所以将集合定义为static类型,使其在类加载时,进行一次初始化。
2、static char allstr[] = new char[100000];该数组用于存储用户从控制台输入的所有字符。
3、//从键盘获取一个一个的字符public char Getchar() {try {ch = (char) System.in.read();} catch (Exception e) {e.printStackTrace();}return ch;}4、用while循环遍历allstr数组中存放的字符,判断分离出关键字、标示符、数字、运算符、标示符。
编译原理实验一
编译原理实验一是一个非常重要的实验环节,它涉及到一些基本的编译原理知识和实践技能。
在这个实验中,我们将学习如何设计并实现一个简单的词法分析器。
在编译原理实验一中,我们将首先学习词法分析的基本概念和原理。
词法分析是编译器的第一阶段,它的主要任务是将输入的源代码分解成一个个的词法单元,如标识符、关键字、数字、运算符等。
为了完成这个任务,我们需要设计一个适用于特定编程语言的词法分析器。
接下来,我们将学习如何使用正则表达式来描述词法单元的模式。
通过定义正确的正则表达式,我们可以准确地识别出源代码中的各种词法单元。
为了实现这一功能,我们将使用一个常用的正则表达式引擎,如lex工具。
在实验过程中,我们将根据给定的编程语言规范,编写相应的正则表达式规则,并通过lex工具生成对应的词法分析器程序。
然后,我们将使用这个词法分析器程序来对一些示例源代码进行分析,确保它能正确地识别出各种词法单元。
最后,我们将对实验结果进行总结和分析。
通过实验一,我们将更深入地了解词法分析的原理和实现方法,为以后更复杂的编译原理实验和项目打下坚实的基础。
希望大家能够认真对待这个实验,积极探索和学习,并尽可能多地掌握相关知识和技能。
编译原理实验(一)——词法分析器一.实验描述运行环境: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. 计算机编程环境2. 编程语言三、实验步骤1. 了解词法分析的概念和作用。
词法分析是编译器中的第一个阶段,它的主要任务是将源代码中的字符序列转化为有意义的标识符,如关键字、操作符、常量和标识符等。
2. 设计词法分析器的流程和算法。
词法分析器的主要原理是通过有限状态自动机来识别和提取标识符。
在设计过程中,需考虑各种可能出现的字符序列,并定义相应的状态转移规则。
3. 根据设计的流程和算法,使用编程语言编写词法分析器的代码。
4. 编译并运行词法分析器程序,输入待分析的源代码文件,观察程序的输出结果。
5. 分析输出结果,检查程序是否正确地提取了源代码中的标识符。
四、实验结果经过词法分析器的处理,源代码将被成功地转化为有意义的标识符。
结果可以通过以下几个方面来验证:1. 关键字和操作符是否被正确识别和提取。
2. 常量和标识符是否被正确识别和提取。
3. 检查程序的错误处理能力,如能否发现非法字符或非法标识符。
4. 输出结果是否符合预期,可与自己编写的语法规则进行对比。
5. 对于特殊情况,如转义字符等是否正确处理。
五、实验总结通过本次实验,我深入了解了编译原理中词法分析的重要性和基本原理。
编写词法分析器的过程中,我学会了使用有限状态自动机来识别和提取标识符,并通过实践巩固了相关知识。
此外,我还对源代码的结构有了更深入的了解,并且掌握了如何运用编程语言来实现词法分析器。
通过本次实验,我不仅提升了自己的编程技术,也对编译原理有了更深入的认识和理解。
六、实验心得通过实验,我深刻体会到了词法分析在编译过程中的重要性。
合理设计和实现词法分析器,可以大大提高编译器的效率和准确性。
同时,通过编写词法分析器的代码,我不仅锻炼了自己的编程能力,还提升了对编译原理的理解和掌握。
这次实验让我更加深入地了解了编译原理中的词法分析,也为我今后在编程领域的发展打下了坚实的基础。
(完整word版)编译原理词法分析程序实现实验报告实验一词法分析程序实现一、实验内容选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来。
输入:由无符号数和+,-,*,/, ( , ) 构成的算术表达式,如1.5E+2-100。
输出:对识别出的每一单词均单行输出其类别码(无符号数的值暂不要求计算)。
二、设计部分因为需要选取无符号数的算术四则运算中的各类单词为识别对象,要求将其中的各个单词识别出来,而其中的关键则为无符号数的识别,它不仅包括了一般情况下的整数和小数,还有以E为底数的指数运算,其中关于词法分析的无符号数的识别过程流程图如下:GOTO 1:(完整word版)编译原理词法分析程序实现实验报告GOTO 2:三、源程序代码部分#include <stdio.h>#include<stdlib.h>#include <math.h>#define MAX 100#define UNSIGNEDNUMBER 1#define PLUS 2#define SUBTRACT 3#define MULTIPLY 4#define DIVIDE 5#define LEFTBRACKET 6#define RIGHTBRACKET 7#define INEFFICACIOUSLABEL 8#define FINISH 111int count=0;int Class;void StoreType();int Type[100];char Store[20]={'\0'};void ShowStrFile();//已经将要识别的字符串存在文件a中void Output(int a,char *p1,char *p2);//字符的输出过程int Sign(char *p);//'+''-''*''/'整体识别过程int UnsignedNum(char *p);//是否适合合法的正整数0~9int LegalCharacter(char *p);//是否是合法的字符:Sign(p)||UnsignedNum(p)||'E'||'.' void DistinguishSign(char *p);//'+''-''*''/'具体识别过程void TypyDistinguish();//字符的识别过程void ShowType();//将类别码存储在Type[100]中,为语法分析做准备void ShowStrFile()//已经将要识别的字符串存在文件a中{FILE *fp_s;char ch;if((fp_s=fopen("a.txt","r"))==NULL){printf("The FILE cannot open!");exit(0);}elsech=fgetc(fp_s);while(ch!=EOF){putchar(ch);ch=fgetc(fp_s);}printf("\n");}void StoreStr()//将文件中的字符串存储到数组Store[i] {FILE *fp=fopen("a.txt","r");char str;int i=0;while(!feof(fp)){fscanf(fp,"%c",&str);if(str=='?'){Store[i]='\0';break;}Store[i]=str;i++;}Store[i]='\0';}void ShowStore(){int i;for (i=0;Store[i]!='\0';i++)printf("%c",Store[i]);printf("\n");}void Output(int a,char *p1,char *p2){printf("%3s\t%d\t%s\t","CLASS",a,"VALUE");while(p1<=p2){printf("%c",*p1);p1++;}printf("\n");}int Sign(char *p){char ch=*p;if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')') return 1;elsereturn 0;}int UnsignedNum(char *p){char ch=*p;if('0'<=ch&&ch<='9')return 1;elsereturn 0;}int LegalCharacter(char *p){char ch=*p;if(Sign(p)||UnsignedNum(p)||ch=='E'||ch=='.')。
《编译原理》实验教学大纲一、实验目的和任务编译原理是计算机科学与技术专业的一门重要课程,它主要研究的是将高级语言程序翻译成机器语言程序的方法和技术。
通过本实验课程的学习,旨在使学生掌握编译原理的基本原理和方法,培养学生对编译器结构与构造技术的专门知识和技能,为学生今后进行编译器设计与实现打下基础。
二、实验设备和工具1.计算机和相关硬件设备2. 编程语言的开发环境,如C/C++或Java三、实验内容1.实验一:词法分析器设计与实现a)实验目的:学习词法分析器的原理和设计方法,掌握正则表达式、DFA和NFA的转换方法。
b)实验任务:i.设计并实现一个词法分析器的原型,能够正确地识别出给定的程序中的词法单元。
ii. 使用给定的正则表达式设计并实现识别给定程序中的关键字、标识符、常量等的词法分析器。
2.实验二:语法分析器设计与实现a)实验目的:学习语法分析器的原理和设计方法,掌握上下文无关文法和LR分析表的构造方法。
b)实验任务:i.学习并理解上下文无关文法和LR分析表的构造方法。
ii. 设计并实现一个简单的递归下降语法分析器。
3.实验三:语义分析器设计与实现a)实验目的:学习语义分析器的原理和设计方法,掌握语义动作的定义和处理方法。
b)实验任务:i.学习并理解语义分析器的原理和设计方法。
ii. 设计并实现一个简单的语义分析器,能够对给定的程序进行语义分析和语义动作的处理。
4.实验四:中间代码生成器设计与实现a)实验目的:学习中间代码生成器的原理和设计方法,掌握中间代码的生成和优化方法。
b)实验任务:i.学习并理解中间代码生成器的原理和设计方法。
ii. 设计并实现一个简单的中间代码生成器,能够将给定的程序翻译成中间代码。
5.实验五:目标代码生成器设计与实现a)实验目的:学习目标代码生成器的原理和设计方法,掌握目标代码的生成和优化方法。
b)实验任务:i.学习并理解目标代码生成器的原理和设计方法。
ii. 设计并实现一个简单的目标代码生成器,能够将中间代码翻译成目标代码。
编译原理实验报告一、实验目的编译原理是计算机科学中的重要课程,旨在让学生了解编译器的基本工作原理以及相关技术。
本次实验旨在通过设计和实现一个简单的编译器,来进一步加深对编译原理的理解,并掌握实际应用的能力。
二、实验环境本次实验使用了Java编程语言及相关工具。
在开始实验前,我们需要安装Java JDK并配置好运行环境。
三、实验内容及步骤1. 词法分析词法分析是编译器的第一步,它将源代码分割成一系列词法单元。
我们首先实现一个词法分析器,它能够将输入的源代码按照语法规则进行切割,并识别出关键字、标识符、数字、运算符等。
2. 语法分析语法分析是编译器的第二步,它将词法分析得到的词法单元序列转化为语法树。
我们使用自顶向下的LL(1)语法分析算法,根据文法规则递归地构建语法树。
3. 语义分析语义分析是编译器的第三步,它对语法树进行检查和转换。
我们主要进行类型检查、语法错误检查等。
如果源代码存在语义错误,编译器应该能够提供相应的错误提示。
4. 代码生成代码生成是编译器的最后一步,它将经过词法分析、语法分析和语义分析的源代码翻译为目标代码。
在本次实验中,我们将目标代码生成为Java字节码。
5. 测试与优化完成以上步骤后,我们需要对编译器进行测试,并进行优化。
通过多个测试用例的执行,我们可以验证编译器的正确性和性能。
四、实验心得通过完成这个编译器的实验,我收获了很多。
首先,我对编译原理的知识有了更深入的理解。
在实验过程中,我深入学习了词法分析、语法分析、语义分析和代码生成等关键技术,对编译器的工作原理有了更系统的了解。
其次,我提高了编程能力。
实现一个完整的编译器需要处理复杂的数据结构和算法,这对我的编程能力是一个很好的挑战。
通过实验,我学会了合理地组织代码,优化算法,并注意到细节对程序性能的影响。
最后,我锻炼了解决问题的能力。
在实验过程中,我遇到了很多困难和挑战,但我不断地调试和改进代码,最终成功地实现了编译器。
一、实验目的与要求1. 实验目的(1) 理解编译原理的基本概念和流程。
(2) 掌握常用的编译方法和技术。
(3) 熟练使用编译器开发工具。
2. 实验要求(1) 熟悉计算机专业基础知识。
(2) 掌握C/C++编程语言。
(3) 了解基本的编译原理。
二、实验环境1. 硬件环境(1) 计算机一台。
(2) 编译器开发工具(如GCC、Clang等)。
2. 软件环境(1) 操作系统(如Windows、Linux等)。
(2) 文本编辑器或集成开发环境(如Visual Studio、Eclipse等)。
三、实验内容1. 实验一:词法分析(1) 实现一个简单的词法分析器,识别出关键字、标识符、常量等。
(2) 分析输入的程序,输出词法分析结果。
2. 实验二:语法分析(1) 实现一个简单的语法分析器,根据给定的语法规则分析输入的程序。
(2) 分析输入的程序,输出语法分析树。
3. 实验三:语义分析(1) 实现一个简单的语义分析器,检查程序中的语义错误。
(2) 分析输入的程序,输出语义分析结果。
4. 实验四:中间代码(1) 实现一个简单的中间代码器,将转换为中间代码表示。
(2) 对输入的程序进行转换,输出中间代码。
5. 实验五:目标代码(1) 实现一个简单的目标代码器,将中间代码转换为目标代码。
(2) 对输入的中间代码进行转换,输出目标代码。
四、实验步骤与方法1. 实验一:词法分析(1) 编写词法分析器的代码。
(2) 测试并调试词法分析器。
2. 实验二:语法分析(1) 编写语法分析器的代码。
(2) 测试并调试语法分析器。
3. 实验三:语义分析(1) 编写语义分析器的代码。
(2) 测试并调试语义分析器。
4. 实验四:中间代码(1) 编写中间代码器的代码。
(2) 测试并调试中间代码器。
5. 实验五:目标代码(1) 编写目标代码器的代码。
(2) 测试并调试目标代码器。
五、实验注意事项1. 按照实验要求编写代码,注意代码规范和可读性。
编译原理实验报告**************************************************************************************************************************************************************PL0语言功能简单、结构清晰、可读性强,而又具备了一般高级程序设计语言的必须部分,因而PL0语言的编译程序能充分体现一个高级语言编译程序实现的基本方法和技术。
PL/0语言文法的EBNF表示如下:<程序>::=<分程序>.<分程序> ::=[<常量说明>][<变量说明>][<过程说明>]<语句><常量说明> ::=CONST<常量定义>{,<常量定义>};<常量定义> ::=<标识符>=<无符号整数><无符号整数> ::= <数字>{<数字>}<变量说明> ::=V AR <标识符>{, <标识符>};<标识符> ::=<字母>{<字母>|<数字>}<过程说明> ::=<过程首部><分程序>{; <过程说明> };<过程首部> ::=PROCEDURE <标识符>;<语句> ::=<赋值语句>|<条件语句>|<当循环语句>|<过程调用语句>|<复合语句>|<读语句><写语句>|<空><赋值语句> ::=<标识符>:=<表达式><复合语句> ::=BEGIN <语句> {;<语句> }END<条件语句> ::= <表达式> <关系运算符> <表达式> |ODD<表达式><表达式> ::= [+|-]<项>{<加法运算符> <项>}<项> ::= <因子>{<乘法运算符> <因子>}<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’<加法运算符> ::= +|-<乘法运算符> ::= *|/<关系运算符> ::= =|#|<|<=|>|>=<条件语句> ::= IF <条件> THEN <语句><过程调用语句> ::= CALL 标识符<当循环语句> ::= WHILE <条件> DO <语句><读语句> ::= READ‘(’<标识符>{,<标识符>}‘)’<写语句> ::= WRITE‘(’<表达式>{,<表达式>}‘)’<字母> ::= a|b|…|X|Y|Z<数字> ::= 0|1|…|8|9【预处理】对于一个pl0文法首先应该进行一定的预处理,提取左公因式,消除左递归(直接或间接),接着就可以根据所得的文法进行编写代码。
实验一词法分析一、实验目的:编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
二、实验内容:如源程序为C语言。
输入如下一段:main(){int a=-5,b=4,j;if(a>=b)j=a-b;else j=b-a;}要求输出如图:(2,”main”)(5,”(”)(5,”)”)(5,”{”)(1,”int”)(2,”a”)(4,”=”)(3,”-5”)(5,”,”)(2,”b”)(4,”=”)(3,”4”)(5,”,”)(2,”j”)(5,”;”)(1,”if”)(5,”(”)(2,”a”)(4,”>=”)(2,”b”)(5,”)”)(2,”j”)(4,”=”)(2,”a”)(4,”-”)(2,”b”)(5,”;”)(1,”else”)(2,”j”)(4,”=”)(2,”b”)(4,”-”)(2,”a”)(5,”;”)(5,”}”)在示例程序的基础上,增加对自加、自减、正负号的判断。
三、源程序:#include<iostream>using namespace std;FILE *fp;char cbuffer;char *key[8]={"if","else","for","while","do","return","break","continue"};int atype,id=4;int search(char searchchar[ ],int wordtype) /*判断单词是保留字还是标识符*/{int i=0;int p;switch (wordtype){case 1:for (i=0;i<=7;i++){if (strcmp(key[i],searchchar)==0){ p=i+1; break; } /*是保留字则p为非0且不重复的整数*/ else p=0; /*不是保留字则用于返回的p=0*/}return(p);}}char alphaprocess(char buffer){ int atype; /*保留字数组中的位置*/int i=-1;char alphatp[20];while ((isalpha(buffer))||(isdigit(buffer))||buffer=='_'){alphatp[++i]=buffer;buffer=fgetc(fp);} /*读一个完整的单词放入alphatp数组中*/alphatp[i+1]='\0';atype=search(alphatp,1);/*对此单词调用search函数判断类型*/if(atype!=0){ printf("%s, (1,%d)\n",alphatp,atype-1); id=1; }else{ printf("(%s ,2)\n",alphatp); id=2; }return buffer;}char digitprocess(char buffer){int i=-1;char digittp[20];while ((isdigit(buffer))){digittp[++i]=buffer;buffer=fgetc(fp);}digittp[i+1]='\0';printf("(%s ,3)\n",digittp);id=3;return(buffer); }char otherprocess(char buffer){char ch[20];ch[0]=buffer;ch[1]='\0';if(ch[0]==','||ch[0]==';'||ch[0]=='{'||ch[0]=='}'||ch[0]=='('||ch[0]==')') { printf("(%s ,5)\n",ch);buffer=fgetc(fp);id=4;return(buffer);}if(ch[0]=='*'||ch[0]=='/'){ printf("(%s ,4)\n",ch);buffer=fgetc(fp);id=4;return(buffer);}if(ch[0]=='='||ch[0]=='!'||ch[0]=='<'||ch[0]=='>'){ buffer=fgetc(fp);if(buffer=='='){ ch[1]=buffer;ch[2]='\0';printf("(%s ,4)\n",ch);}else {printf("(%s ,4)\n",ch);id=4;return(buffer);}buffer=fgetc(fp);id=4;return(buffer);}if(ch[0]=='+'||ch[0]=='-'){if(id==4){ /*在当前符号以前是运算符,则此时为正负号*/ int i=1;buffer=fgetc(fp);ch[1]=buffer;ch[2]='\0';if(ch[0] == ch[1]){printf("(%s,3)\n",ch);buffer=fgetc(fp);return buffer;}while(isdigit(ch[i])){ch[++i] = fgetc(fp);}ch[i] = '\0';id=3;printf("(%s ,3)\n",ch);return(buffer);}buffer=fgetc(fp);ch[1]=buffer;if(ch[0] == ch[1]){ch[2]='\0';printf("(%s,3)\n",ch);buffer=fgetc(fp);return buffer;}ch[1]='\0';printf("(%s ,4)\n",ch);buffer=fgetc(fp);id=4;return(buffer);}}void main(){if ((fp=fopen("example.c","r"))==NULL) /*只读方式打开一个文件*/ printf("error");else{cbuffer = fgetc(fp); /*fgetc( )函数:从磁盘文件读取一个字符*/while (cbuffer!=EOF){if(cbuffer==' '||cbuffer=='\n') /*掠过空格和回车符*/cbuffer=fgetc(fp);elseif(isalpha(cbuffer))cbuffer=alphaprocess(cbuffer);elseif (isdigit(cbuffer))cbuffer=digitprocess(cbuffer);else cbuffer=otherprocess(cbuffer);}}system("pause");}四、实验运行结果:五、实验心得:通过这次实验,更加深了我对编译中的词法分析过程的理解,我将老师所给的示例加以修改,添加了++,--,以及正负号的判断,虽然还有很多实际问题没有考虑进去,例如程序中若有‘//’或者‘/*..*/’时则无法判断出解释语句。
实验2-3 《编译原理》S语言词法分析程序设计方案一、实验目的了解词法分析程序的两种设计方法:根据状态转换图直接编程的方式;利用DFA编写通用的词法分析程序.二、实验内容1.根据状态转换图直接编程编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。
在此,词法分析程序作为单独的一遍,如下图所示。
具体任务有:(1)组织源程序的输入(2)拼出单词并查找其类别编号,形成二元式输出,得到单词流文件(3)删除注释、空格和无用符号(4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。
将错误信息输出到屏幕上。
(5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。
标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。
常量表结构:常量名,常量值2. 编写DFA模拟程序算法如下:DFA(S=S0,MOVE[][],F[],ALPHABET[],ALLS[])/*S为状态,初值为DFA的初态,MOVE[][]为状态转换矩阵,F[] 为终态集,ALPHABET[] 为字母表,其中的字母顺序与MOVE[][] 中列标题的字母顺序一致。
ALLS[]为状态集*/ {Char Wordbuffer[10]=“”//单词缓冲区置空Nextchar=getchar();//读字符i=0;while(nextchar!=NULL)//NULL代表此类单词{ if (nextcha r!∈ALPHABET[]){ERROR(“非法字符”),return(“非法字符”);}S=MOVE[S][nextchar] //下一状态if(S=NULL)return(“不接受”);//下一状态为空,不能识别,单词错误wordbuffer[i]=nextchar ;//保存单词符号i++;nextchar=getchar();}Wordbuffer[i]=‘\0’;If(S∈F)return(wordbuffer);//接受Else return(“不接受”);}该算法要求:实现DFA算法,给定一个DFA(初态、状态转换矩阵、终态集、字母表、状态集),调用DFA(),识别给定源程序中的单词,查看结果是否正确。
《编译原理》实验指导书实验一词法分析器的设计一、实验目的和要求加深对状态转换图的实现及词法分析器的理解。
熟悉词法分析器的主要算法及实现过程。
要求学生掌握词法分析器的设计过程,并实现词法分析。
二、实验基本内容给出一个简单语言的词法规则,画出状态转换图,并依据状态转换图编制出词法分析程序,能从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单Error”,然后跳过错误部分继续显示)词法规则如下:三、实验时间:上机三次。
第一次按照自己的思路设计一个程序。
第二、三次在理论课学习后修改程序,使得程序结构更加合理。
四、实验过程和指导:(一)准备:1.阅读课本有关章节(c/c++,数据结构),花一周时间明确语言的语法,写出基本算法以及采用的数据结构和要测试的程序例。
2.初步编制好程序。
3.准备好多组测试数据。
(二)上课上机:将源代码拷贝到机上调试,发现错误,再修改完善。
(三)程序要求:程序输入/输出示例:输入如下一段:main(){/*一个简单的c++程序*/int a,b; //定义变量a = 10;b = a + 20;}要求输出如右图。
要求:(1) 剔除注解符(2) 常数为无符号整数(可增加实型数,字符型数等)(四)练习该实验的目的和思路:程序开始变得复杂起来,可能是大家以前编过的程序中最复杂的,但相对于以后的程序来说还是简单的。
因此要认真把握这个过渡期的练习。
程序规模大概为200行及以上。
通过练习,掌握对字符进行灵活处理的方法。
(五)为了能设计好程序,注意以下事情:1.模块设计:将程序分成合理的多个模块(函数/类),每个模块(类)做具体的同一事情。
2.写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。
3.编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
4.程序设计语言不限,建议使用面向对象技术及可视化编程语言,如C++,VC,JA V A,VJ++等。
实习一词法分析一、实验目的:根据活动状态转换图,设计并实现一个具体的C语言的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编写一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。
二、实验过程1.活动状态转化图2.设计思路本C语言词法分析器使用JAVA语言编写。
(1)C语言词法分析●关键字将C语言32关键字"auto", "double", "int", "struct", "break","else","long", "switch", "case", "enum", "register", "typedef","char", " extern", "return", "union", "const", "float", "short"," unsigned", "continue", "for", "signed", "void","default", "goto","sizeof", "volatile", "do", "if", "while", "static"存储在keyword[]字符串数组中;●专用符号= + -* / <=>>= == != ;:, { } [ ] ( )将读入的字符与ASCLL表进行比较判断;对于像“==”,“<=”等字符进行超前搜索;●空格和空白、制表符和换行符。
集美大学计算机工程学院实验报告课程名称:编译原理指导教师:付永钢实验成绩:实验编号:实验一实验名称:词法分析程序开发班级:计算1214姓名:学号:上机实践日期:2014.11上机实践时间:4学时一、实验目的1、深入理解有限自动机及其应用;2、掌握词法分析程序的开发。
;3、掌握根据语言的词法规则构造识别其单词的有限自动机的方法;4、深入理解词法分析程序自动生成原理。
二、实验环境Windows7 x64、VC6.0三、实验原理词法分析是编译过程的第一阶段。
它的任务就是对输入的字符串形式的源程序按顺序进行扫描,根据源程序的词法规则识别具有独立意义的单词(符号),并输出与其等价的Token序列。
有限自动机是描述程序设计语言单词构成的工具,而状态转换图是有限自动机的比较直观的描述方法。
我们使用确定的有限状态自动机,简记为DFA。
PL/0的语言的词法分析器将要完成以下工作:(1)跳过分隔符(如空格,回车,制表符);(2)识别诸如begin,end,if,while等保留字;(3)识别非保留字的一般标识符,此标识符值(字符序列)赋给全局量id,而全局量sym赋值为SYM_IDENTIFIER。
(4)识别数字序列,当前值赋给全局量NUM,sym则置为SYM_NUMBER;(5)识别:=,<=,>=之类的特殊符号,全局量sym则分别被赋值SYM_BECOMES,SYM_LEQ,SYM_GEQ等。
相关过程(函数)有getsym(),getch(),其中getch()为获取单个字符的过程,除此之外,它还完成:(1)识别且跳过行结束符;(2)将输入源文件复写到输出文件;(3)产生一份程序列表,输出相应行号或指令计数器的值。
下面给出能够识别PL0语言中各类单词的DFA:入口出错识别PL0单词的DFA 表示其他S字母标识符状态, INID数字数字状态, INNUM数字=,:= , > , <= , <>, <字母,数字赋值状态INASSIGN标识符无符号整数出口其它符号查保留字关键字对应单词种类出错根据语言的词法规则构造出识别其单词的确定有限自动机DFA, 仅仅是词法分析程序的一个形式模型,距离词法分析程序的真正实现还有一定的距离。
状态转换图的程序实现通常是采用直接转向法。
直接转向法又称为程序中心法,是把状态转换图看成一个流程图,从状态转换图的初态开始,对它的每一个状态结点都编写一段相应的程序。
四、实验步骤 1、用自动生成工具LEX 生成上述给定DFA 所对应的PL0语言的词法分析程序①在txt 文档中编写lex 文件test1.l②在命令行下执行命令flex 解析test.l 文件,自动生成lex.yy.c 文件 ③在C 环境编译lex.yy.c ,生成可执行文件lex.yy.exe 对测试用例进行测试 2、根据DFA 在C 环境下构造词法分析器对测试用例进行测试五、实验结果测试程序:procedure divide;var w;beginr := x; q := 0; w := y;end1、自动生成工具LEX测试:2、C环境分析器测试:六、实验小结1、通过本次实验,对有限自动机及其应用有了进一步的了解,对词法分析程序的开发有了一定的认识;2、第一次使用自动生成工具LEX,对LEX语法不熟悉,通过查阅网上资料,词法分析程序自动生成原理有了一定的认识,能够基本完成本实验的需求,同时对本课程的实际意义也有了全面的理解;3、在通过C语言编写词法分析器的过程中,用二维数组构造分析表,但是不断出现栈溢出问题,后将分析表缩小,仅存保留字,对其他符号逐一判断,实现本实验要求词法分析器;4、利用C语言构造词法分析器,考虑到分隔符问题,在本次实验中,仅考虑了‘\n’、‘\t’、空格、以及‘;’,凡不以这四个字符结束的串都被视为错误。
程序代码:1、LEX:digit [0-9]letter [A-Za-z]id ({letter}|[_])({letter}|{digit}|[_])*%%[ |\t|\n]+"var" {printf("21,\"%s\"\n",yytext);}"if" {printf("22,\"%s\"\n",yytext);}"then" {printf("23,\"%s\"\n",yytext);}"else" {printf("24,\"%s\"\n",yytext);}"while" {printf("25,\"%s\"\n",yytext);}"for" {printf("26,\"%s\"\n",yytext);}"begin" {printf("27,\"%s\"\n",yytext);}"writeln" {printf("28,\"%s\"\n",yytext);}"procedure" {printf("29,\"%s\"\n",yytext);}"end" {printf("30,\"%s\"\n",yytext);}{id} {printf("1,\"%s\"\n",yytext);}{digit}+ {printf("2,\"%s\"\n",yytext);}"+" {printf("3,\"%s\"\n",yytext);}"-" {printf("4,\"%s\"\n",yytext);}"*" {printf("5,\"%s\"\n",yytext);}"/" {printf("6,\"%s\"\n",yytext);}"=" {printf("7,\"%s\"\n",yytext);}">" {printf("8,\"%s\"\n",yytext);}"<" {printf("9,\"%s\"\n",yytext);}"<>" {printf("10,\"%s\"\n",yytext);}"<=" {printf("11,\"%s\"\n",yytext);}">=" {printf("12,\"%s\"\n",yytext);}"(" {printf("13,\"%s\"\n",yytext);}")" {printf("14,\"%s\"\n",yytext);}"{" {printf("15,\"%s\"\n",yytext);}"}" {printf("16,\"%s\"\n",yytext);}";" {printf("17,\"%s\"\n",yytext);}"," {printf("18,\"%s\"\n",yytext);}"\"" {printf("19,\"%s\"\n",yytext);}":=" {printf("20,\"%s\"\n",yytext);}%%#include <ctype.h>int main(){yylex ( );return 0 ;}yywrap(){return 1;}2、C程序#include "stdio.h"#include "conio.h"#include "string.h"void main(){int i=0,j;int k1=0,k2=0;chartable[10][10]={"var","if","then","else","while","for","begin","writeln","procedure","end"};char c;char t[20]={"\0"}; //缓冲,用于存放临时串freopen("D:\\学习相关\\编译原理\\第一部分实验内容\\C\\in.txt","r",stdin);c=getchar();while(c!=EOF){if(c==' '||c=='\n'||c=='\t'){c=getchar();}else if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){t[i++]=c;c=getchar();while((c>='a'&&c<='z')||(c>='A'&&c<='Z')||(c>='0'&&c<='9')){t[i++]=c;c=getchar();}if(c==' '||c=='\n'||c=='\t'||c==';'){for(j=0;j<10;j++){if(strcmp(t,table[j])==0){printf("%d,\"%s\"\n",j+21,t);k1=1; //不是保留字标志break;}}if(k1==0)printf("1,\"%s\"\n",t); //标识符if(c==';')printf("17,\";\"\n");c=getchar();}elseprintf("100,error\n");for(j=0;j<=i;j++)t[j]='\0';k1=0;i=0;}else if(c>='0'&&c<='9'){t[i++]=c;c=getchar();while((c>='0'&&c<='9')){t[i++]=c;c = getchar();}if(c==' '||c=='\n'||c=='\t'||c==';'){printf("2,\"%s\"\n",t);}if(c==';')printf("17,\";\"\n");for(j=0;j<=i;j++)t[j]='\0';i=0;}else if(c=='>'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("8,\">\"\n");}else if(c=='='){c=getchar();if(c==' '||c=='\n'||c=='\t')printf("12,\">=\"\n");elseprintf("100,error\n");}else{printf("100,error\n");}}else if(c=='<'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("9,\"<\"\n");}else if(c=='>'||c=='='){if(c=='=')k2=1;c=getchar();if(c==' '||c=='\n'||c=='\t'){if(k1==0)printf("10,\"<>\"\n");elseprintf("11,\"<=\"\n");}elseprintf("100,error\n");}else{printf("100,error\n");}}else if(c=='+'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("3,\"+\"\n");}else{printf("100,error\n");}}else if(c=='-'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("4,\"-\"\n");}else{printf("100,error\n");}}else if(c=='*'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("5,\"*\"\n");}else{printf("100,error\n");}}else if(c=='/'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("6,\"/\"\n");}else{printf("100,error\n");}}else if(c=='='){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("7,\"=\"\n");}else{printf("100,error\n");}}else if(c=='('){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("13,\"(\"\n");}else{printf("100,error\n");}}else if(c==')'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("14,\")\"\n");}else{printf("100,error\n");}}else if(c=='{'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("15,\"{\"\n");}else{printf("100,error\n");}}else if(c=='}'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("16,\"}\"\n");}else{printf("100,error\n");}}else if(c==';'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("17,\";\"\n");}else{printf("100,error\n");}}else if(c=='\''){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("18,\"\'\"\n");}else{printf("100,error\n");}}else if(c=='\"'){c=getchar();if(c==' '||c=='\n'||c=='\t'){printf("19,\"\"\"\n");}else{printf("100,error\n");}}else if(c==':'){c=getchar();if(c=='='){c=getchar();if(c==' '||c=='\n'||c=='\t')printf("20,\":=\"\n");elseprintf("100,error\n");}else{printf("100,error\n");}}else{printf("100,error\n");c=getchar();}}fclose(stdin);//关闭文件}。