编译原理实验 四

编译原理实验 四
编译原理实验 四

实验四算符优先文法处理算术表达式与赋值语句

一、实验目的

算术表达式和赋值语句的文法可以是(你可以根据需要适当改变):

S→i=E

E→E+E|E-E|E*E|E/E|(E)|i

根据算符优先分析法,将赋值语句进行语法分析,翻译成等价的一组基本操作,每一基本操作用四元式表示。

二、估计实验时间

1.课余准备15小时;

2.上机三次6小时;

3.完成实验报告5小时。

三、实验过程和指导

(一)准备:1.阅读课本有关章节,花一周时间确定算术表达式的文法,设计出算符优先关系表;2.考虑好设计方案;3.设计出模块结构、测试数据,初步编制好程序。

(二)上课上机:上机调试,发现错误,分析错误,再修改完善。教师根据学生的设计方案与学生进行探讨,以修改方案和代码。

(三)程序要求:

程序输入/输出示例:

如参考C语言的运算符。输入如下表达式(以分号为结束)和输出结果:

(1)a = 10;

输出:(=, a,10,-)

(2)b = a + 20;

输出:(=,r1,20,-)

(+,r2,a,r1)

(=,b,r2,-)

注:此例可以进行优化后输出(不作要求):(+,b,a,20)

(3)c=(1+2)/3+4-(5+6/7);

输出:(+,r1,1,2) (/,r2,r1,3) (/,r3,6,7) (+,r4,5,r3,) (+,r5,r2,4) (-,r6,r5,r4) (=,c,r6,-)

注:输出格式有多种,如上面第二个括号可改为(/,r1,r1,3)以节约变量(当然后面相应的变量引用也要改变)。

注意:

1.表达式中允许使用运算符(+-*/)、分割符(括号)、常量(无符号整数)和变量;

2只要能表达正确的计算过程,任何输出方式都可以;

3.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);

4.测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;

5.其中临时变量名可不用r1,r2,也可用别的形式代替,如r[1],r[2]等。

6.为了降低难度,文法可适当降低要求,如只处理含有+-()的表达式,也可只处理+-*/的表达式;

7.对学有余力的同学,可增加一个函数来计算四元式,最后输出被赋值变量的值(如果表达式中含有变量,则设它为0),计算过程用浮点表示,但要注意不要被0除。

程序思路(仅供参考):

1.借用实验二的结果,可将其中的取字符函数几乎原封不动地移植过来,其中的分割和分析单词的方法可借用过来分割现在这个实验的运算符、常量和变量。

2.模块结构:

(1)初始化:设立算符优先关系表(或优先函数)、初始化变量空间(包括堆栈、结构体、数组、临时变量等);

(2)控制部分:将一个表达式从文件中读出;

(3)词法分析:将表达式分割成单词序列;

(4)利用算符优先文法进行表达式处理:根据算符优先关系表(或优先函数)对表达式单词序列进行堆栈(或其他)操作,得到并保存四元组,如果遇到错误则显示错误信息;(5)输出四元组。

(四)练习该实验的目的和思路:

程序相当复杂,需要利用到大量的编译原理,也用到了大量编程技巧和数据结构,通过这个练习可大大提高软件开发能力。程序规模大概为400行。本实验的结果可作为课程设计的基础。通过练习,掌握对表达式进行处理的一种方法。

(五)为了能设计好程序,主意以下事情:

1.模块设计:将程序分成合理的多个模块(函数),每个模块做具体的同一事情。

2.写出(画出)设计方案:模块关系简图、流程图、全局变量、函数接口等。

3.编程时注意编程风格:空行的使用、注释的使用、缩进的使用、变量合理命名等。

四、上交

1.程序源代码(主文件名为by3);

2.已经测试通过的测试数据10组(全部存在test

3.txt文件中,以“第一组输入/输出/第二组输入/输出/第三组输入/输出……”的格式存放);

3.实验报告:

(1)功能描述:该程序具有什么功能?

(2)程序结构描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图、程序总体执行流程图(参考课本第二章)。

(3)实验过程记录:出错次数、出错严重程度、解决办法摘要。

(4)实验总结:你在编程过程中花时多少?多少时间在纸上设计?多少时间上机输入和调试?多少时间在思考问题?遇到了哪些难题?你是怎么克服的?你对你的程序的评价?你的收获有哪些?

五、参考源代码

//程序功能:

//根据算符优先分析法,将表达式进行语法分析,判断一个表达式是否正确。

//文法:E→E+E|E-E|E*E|E/E|(E)|i

// 其中i为无符号整数

//

//例:

//输入:10;

//输出:正确

//输入:1+2;

//输出:正确

//输入:(1+2)/3+4-(5+6/7);

//输出:正确

//输入:((1-2)/3+4;

//输出:错误

//

//输入测试数据保存在同目录的文本文件testin.txt中,保存格式:

// 表达式行;

// 表达式行;

// .....

//预期的输出保存在同目录的文本文件testout.txt中,保存格式:

// 表达式行;

// 正确/错误

// 表达式行;

// 正确/错误

// .....

/////////////////////////////////////////////////////////////////

#include "stdio.h"

#include "stdlib.h"

#define TRUE 1

#define FALSE 0

//文件信息:

#define TESTIN_FILENAME "testin.txt"

#define TESTOUT_FILENAME "testout.txt"

FILE * fTestIn;

FILE * fTestOut; //打开文件后的柄

//运算符定义:

#define O_NUMBER 8 //运算符个数,+-*/()i#

#define O_PLUS 0 // 加+

#define O_MINUS 1 // 减-

#define O_TIMES 2 // 乘*

#define O_SLASH 3 // 除/

#define O_L_PAREN 4 //左括号(parenthesis)

#define O_R_PAREN 5 //右括号

#define O_IDENT 6 //标识符

#define O_NUL 7 //语法界符#

//表达式缓冲区:由专门函数操作(ReadFormula(),GetChar())

#define BUFFER_SIZE 1000 //表达式缓冲区大小

char Buffer[BUFFER_SIZE]; //表达式缓冲区,以'\0'表示结束

int ipBuffer = 0; //表达式缓冲区当前位置序号

//算符优先关系表:

char O_Table[O_NUMBER][O_NUMBER] = {

{'>','>','<','<','<','>','<','>'},

{'>','>','<','<','<','>','<','>'},

{'>','>','>','>','<','>','<','>'},

{'>','>','>','>','<','>','<','>'},

{'<','<','<','<','<','=','<','-'},

{'>','>','>','>','-','>','-','>'},

{'>','>','>','>','-','>','-','>'},

{'<','<','<','<','<','-','<','='}

}; //优先关系表:八个字符分别是+-*/()i#,其中'-'表示出错

//文法:

#define OG_NUMBER 6 //文法个数

char OG[OG_NUMBER][4] = {"E+E","E-E","E*E","E/E","(E)","i"}; //文法右部

//单词序列存放格式定义:

#define TOKEN_MAX_LENTH 100 //最大的单词长度+1

typedef struct

{

char ch; //存放字符:+-*/()i#E

int No; //存放算符优先关系表中的序号

//double Value; //当ch==i时,且为数值时,存放值的大小} SToken;

#define MAX_TOKEN_NUMBER 1000 //在一个表达式中允许最大的单词个数SToken Token[MAX_TOKEN_NUMBER]; //单词序列,最后一个以“#”结束

int TokenNumber = 0; //单词序列中包含的单词个数

int ipToken = 0; //进行“移进-规约”时的位置指示

//堆栈:由专门的函数操作(PopUp(),Push(),…)

#define STACK_MAX_SIZE 1000 //堆栈最大存储量

SToken Stack[STACK_MAX_SIZE]; //堆栈

int ipStack = 0; //堆栈指针,指向栈顶(下一个空位置)

//词法分析专用全局变量:

char ch; //存放取得的一个字符

//char AToken[TOKEN_MAX_LENTH]; //存放组成的单词,存放时以\0为结束

//int ipAToken; //用于读字符时,指向下一个AToken[]的位置,便于组成单词

//错误信息:

char * ErrMsg; //出错信息

//函数声明:

bool Judge(); //利用算符优先关系表判断单词序列是否正确

int GuiYue(); //规约,并判断是否完成

bool IsOK(); //判断规约是否全部完成

bool GuiYueN(int n); //将堆栈中0~n单词规约

int FindPriorOp(int Begin); //在堆栈中,从Begin开始,查找前一个终结符位置

int MoveIn(); //移进,并判断是否需要规约

void JudgeInit(); //(利用算符优先关系表判断单词序列是否正确)判断前的初始化SToken Peek(int n); //窥视堆栈

bool PopUp(int n); //弹出堆栈

void PushToken(char ch, int O_No); //压栈(以字符形式)

void Push(SToken Token); //压栈

bool Init(); //全局初始化

void End(); //程序退出前作善后处理

void OutPut(char * Formula, char * Result); //将结果输出到文件

bool ReadFormula(); //从文件中读出一个表达式存于表达式缓冲区Buffer[]中,以'\0'结束,并置ipBuffer=0;

bool ChangeToTokens(); //将表达式分割成单词序列

char GetFirstChar(); //从表达式缓冲区中取到下面第一个非空字符

char GetChar(); //从表达式缓冲区取一个字符,返回该字符的同时将它存于全局变量ch 中

bool MakeErr(char * ErrMassage); //生成错误信息,错误信息存于全局变量ErrMsg中///////////////////////////////////////

void main()

{

if(! Init()) //初始化

{

printf("初始化失败!程序不能继续。错误信息如下:\n%s\n",ErrMsg);

exit(0);

}

while(ReadFormula()) //从文件中读表达式成功

{

if(ChangeToTokens()) //将表达式分割成单词序列

{

if(Judge()) //利用算符优先关系表判断表达式(单词序列)是否正确

OutPut(Buffer,"正确!");

else

OutPut(Buffer,ErrMsg); //输出错误信息

}

else //出错

{

OutPut(Buffer,ErrMsg); //输出错误信息

}

}

End(); //程序退出前作善后处理

}

//利用算符优先关系表判断单词序列是否正确

//返回:TRUE正确;FALSE错误,且错误信息存于ErrMsg

//本函数的实现思路:

// 将单词序列进行“移进-规约”操作,最后判断是否能全部完成

// 使用到:堆栈(SToken Stack[])、文法(char OG[][])、算符优先关系表(char O_Table[][])等

bool Judge()

{

JudgeInit();

PushToken('#',O_NUL); //将“#”号置栈底

while(TRUE) //进行“移进-规约”操作

{

switch(MoveIn())

{

case 1: //需要规约

switch(GuiYue())//规约

{

case 1: //这一步规约成功

break;

case 2: //规约全部完成

return TRUE;

default: //出错

ErrMsg = "规约错误。";

return FALSE;

}

break;

case 2: //需要继续移进

break;

default: //出错

return FALSE;

}

}

}

//规约,并判断是否完成

//返回:-1出错,1这一步规约成功,2规约全部完成

int GuiYue()

{

int n0,n;

char r; //存优先关系

n = FindPriorOp(-1); //取得堆栈中第一个终结符

if(Peek(n).ch == '#') //出错或全部结束

{

if(IsOK())

return 2;

else

return -1;

}

while(TRUE)

{

n0 = n;

n = FindPriorOp(n0); //前一个终结符的堆栈位置

if(n - n0 > 2) //出错(多个非终结符相邻)

return -1;

r = O_Table[Peek(n).No][Peek(n0).No];

if(r == '<') //寻找结束

{

if(! GuiYueN(n - 1)) //规约(从前一个后的字符开始)规约失败

return -1;

else //规约成功,还要判断是否全部完成

{

if(IsOK())

return 2; //规约全部完成

else

return 1; //这一步规约成功

}

}

else if(r == '=') //继续向前找

{

continue;

}

else //出错(r为>或没有关系)

return -1;

}

}

//判断规约是否全部完成

//返回:TRUE全部完成;FALSE没有完成

bool IsOK()

{

//if(Peek(1) == NULL) return FALSE;

if(Peek(0).ch == 'E'&& Peek(1).ch == '#' && Token[ipToken].ch == '#') return TRUE;

else

return FALSE;

}

//返回:TRUE成功,FALSE失败

bool GuiYueN(int n) //将堆栈中0~n单词规约

{

int i,j;

bool k;

for(i=0;i

{

for(j=n,k=FALSE;j>=0;j--)

{

if(OG[i][n-j] != Peek(j).ch)

{

k = TRUE; //TRUE表示规约串和文法右部不符,

break;

}

}

if(k) continue;

//k==FALSE表示规约串判断完成

if(OG[i][n+1]=='\0') //文法也判断完成,匹配成功

{

PopUp(n + 1); //弹出规约串

PushToken('E',O_IDENT); //压入左部“E”

return TRUE;

}

}

return FALSE;

}

//在堆栈中,从Begin开始,查找前一个终结符位置

//如果从开始找,让 Begin = -1

int FindPriorOp(int Begin)

{

int n;

n = Begin + 1;

while(Peek(n).ch == 'E')

{

n ++;

}

return n;

}

//移进,并判断是否需要规约

//返回:-1出错,1需要规约,2可继续移进

// 1.单词结束(遇到“#”号),无法移进,需要规约,返回:1

// 2.单词没有结束,需判断是否可以移进

// 2-1.堆栈单词<=单词:移进后返回:2

// 2-2.堆栈单词>单词:不能移进,需要规约,返回:1

// 2-3.两单词没有优先关系:出错,返回:-1

int MoveIn()

{

SToken s,t; //分别存堆栈顶单词和单词序列的第一个单词

char r; //存放优先关系

s = Peek(FindPriorOp(-1)); //取得堆栈中第一个终结符位置

t = Token[ipToken];

r = O_Table[s.No][t.No];

if(t.ch == '#') //单词结束,无法移进,需要规约

return 1;

else //单词没有结束,需判断是否可以移进

{

if(r == '<' || r == '=') //需要移进

{

Push(t);

ipToken ++;

return 2;

}

else if(r == '>') //不能移进,需要规约

return 1;

else //没有优先关系,出错

{

MakeErr("移进时出现两个没有优先关系的相邻单词。");

return -1;

}

}

}

//(利用算符优先关系表判断单词序列是否正确)判断前的初始化

//由于多个表达式需要依次判断,因此对每个表达式判断前都需要初始化

void JudgeInit()

{

ipStack = 0; //堆栈初始化(如果有专门的StackClear()函数则更好)

ipToken = 0; //指向首个单词

}

//窥视堆栈

//参数:n相对栈顶的位置(0开始)

//成功返回:返回单词

//不成功返回:NULL

SToken Peek(int n)

{

SToken Token;

if(n > 0 || n < ipStack)

Token = Stack[ipStack - n - 1];

else if(n < 0)

Token = Stack[ipStack - 1];

else

Token = Stack[0];

return Token;

}

//弹出堆栈

//参数:n弹出单词个数(不能全部弹空,即保留#号)

//不成功返回:FALSE

//成功返回:TRUE

bool PopUp(int n)

{

if(ipStack < 2) return FALSE; //只剩0个或1个

if(n > ipStack - 1) n = ipStack - 1;

ipStack -= n;

return TRUE;

}

//压栈(以字符形式)

//参数:ch是要压栈的字符(+-*/()i#E 之一),O_No运算符序号//调用:Push()

void PushToken(char ch, int O_No)

{

SToken Token;

Token.ch = ch;

Token.No = O_No;

Push(Token);

}

//压栈

//参数:Token是要压栈的SToken结构体类型的单词

//缺点:没有判断堆栈是否满

void Push(SToken Token)

{

Stack[ipStack ++] = Token;

}

//全局初始化

//成功:返回TRUE;失败:返回FALSE

bool Init()

{

//if((fTestIn = fopen(TESTIN_FILENAME, "r")) = NULL) return ! MakeErr("不能打开测试文件!");

//if((fTestOut = fopen(TESTOUT_FILENAME, "w")) = NULL) return ! MakeErr("不能打开结果输出文件!");

fTestIn = fopen(TESTIN_FILENAME, "r");

fTestOut = fopen(TESTOUT_FILENAME, "w");

return TRUE;

}

//程序退出前作善后处理

//主要是关闭文件等

void End()

{

fclose(fTestIn);

fclose(fTestOut);

}

//将结果输出到文件

//要求文件事先以追加方式打开,文件指针为fTestOut

//参数:Formula表达式内容,Result判断结果

void OutPut(char * Formula, char * Result)

{

fprintf(fTestOut,"%s\n%s\n",Formula,Result);

}

//从文件中读出一个表达式存于表达式缓冲区Buffer[]中,以'\0'结束,并置ipBuffer=0;//需要先打开文件,文件指针存于fTestIn

//读出非空表达式:返回 TRUE;文件结束:返回 FALSE

bool ReadFormula()

{

int n = 0;

bool k = FALSE; //当 k==TRUE 时表示文件结束,否则文件没有结束

while(TRUE)

{

if((Buffer[n] = fgetc(fTestIn)) != EOF) //读出一个字符成功

{

if(Buffer[n] == ';') break;

n ++;

}

else //文件结束

{

k = TRUE;

break;

}

}

Buffer[n] = '\0'; //最后一个字符用结束标记'\0'代替

ipBuffer = 0; //初始化缓冲区指针

if(n > 0) //读出的数据非空,返回成功

return TRUE;

else //读出的数据为空,需要判断文件结束,还是只有';'的空表达式

{

if(k) //文件结束

return FALSE;

else //空表达式,文件没有结束,让它继续读下一个表达式

return ReadFormula();

}

}

//将表达式分割成单词序列

//结果:单词序列存于SToken Token[]中,单词个数存于TokenNumber中

//这是一个大模块,其中要调用一些子函数

//本函数只识别:运算符+-*/、括号()、无符号整数i,并在末尾添加#号

// 遇到其它任何字符都返回错误信息

//返回:TRUE表示成功;FALSE表示失败,同时将错误信息存于全局变量ErrMsg中

//使用到的其他全局变量:ch(取一个字符)、AToken[](取到的单词)

bool ChangeToTokens()

{

TokenNumber = 0;

if(GetFirstChar() == '\0') return ! MakeErr("表达式为空。");

while(TRUE) //对缓冲区进行循环读

{

if(ch <= 32 && ch > 0) GetFirstChar(); //滤去空格

switch(ch) //对单词的第一个进行判断,在下面一次处理整个单词

{

case '\0':

Token[TokenNumber].ch = '#';

Token[TokenNumber].No = O_NUL;

return TRUE; //处理结束

case '+':

Token[TokenNumber].ch = '+';

Token[TokenNumber].No = O_PLUS;

GetChar();

break;

case '-':

Token[TokenNumber].ch = '-';

Token[TokenNumber].No = O_MINUS;

GetChar();

break;

case '*':

Token[TokenNumber].ch = '*';

Token[TokenNumber].No = O_TIMES;

GetChar();

break;

case '/':

Token[TokenNumber].ch = '/';

Token[TokenNumber].No = O_SLASH;

GetChar();

break;

case '(':

Token[TokenNumber].ch = '(';

Token[TokenNumber].No = O_L_PAREN;

GetChar();

break;

case ')':

Token[TokenNumber].ch = ')';

Token[TokenNumber].No = O_R_PAREN;

GetChar();

break;

default:

if(ch >= '0' && ch <= '9') //整数

{

while(GetChar()>0)

{

if(ch < '0' || ch > '9') break;

}

Token[TokenNumber].ch = 'i';

Token[TokenNumber].No = O_IDENT;

}

else

{

return ! MakeErr("表达式中含有非法字符。");

}

break;

}

TokenNumber ++;

}

}

//从表达式缓冲区中取到下面第一个非空字符

//成功:返回字符;不成功:返回'\0'

char GetFirstChar()

{

while(GetChar() != '\0')

{

if(ch>32) return ch;

}

return '\0';

}

//从表达式缓冲区取一个字符,返回该字符的同时将它存于全局变量ch中//成功:返回字符;不成功:返回'\0'

char GetChar()

{

if((ch = Buffer[ipBuffer]) != '\0')

ipBuffer ++;

return ch;

}

//生成错误信息

//错误信息存于全局变量ErrMsg中

//返回:TRUE

bool MakeErr(char * ErrMassage)

{

ErrMsg = ErrMassage;

return TRUE;

}

编译原理实验指导

编译原理实验指导 实验安排: 上机实践按小组完成实验任务。每小组三人,分别完成TEST语言的词法分析、语法分析、语义分析和中间代码生成三个题目,语法分析部分可任意选择一种语法分析方法。先各自调试运行,然后每小组将程序连接在一起调试,构成一个相对完整的编译器。 实验报告: 上机结束后提交实验报告,报告内容: 1.小组成员; 2.个人完成的任务; 3.分析及设计的过程; 4.程序的连接; 5.设计中遇到的问题及解决方案; 6.总结。

实验一词法分析 一、实验目的 通过设计编制调试TEST语言的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。 二、实验预习提示 1.词法分析器的功能和输出格式 词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示 成以下的二元式(单词种别码,单词符号的属性值)。 2.TEST语言的词法规则 |ID|ID |NUM →a|b|…|z|A|B|…|Z →1|2|…|9|0 →+|-|*|/|=|(|)|{|}|:|,|;|<|>|! →>=|<=|!=|== →/* →*/ 三、实验过程和指导 1.阅读课本有关章节,明确语言的语法,画出状态图和词法分析算法流程图。 2.编制好程序。 3.准备好多组测试数据。 4.程序要求 程序输入/输出示例:

编译原理实验 中间代码生成

实验四中间代码生成 一.实验目的: 掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。 二.实验内容: 1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表 达式也称做后缀式。 2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。 3、三元式:形式序号:(op,arg1,arg2) 4、四元式:形式(op,arg1,arg2,result) 三、以逆波兰式为例的实验设计思想及算法 (1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。 (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。 (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。 (4)如果不是数字,该字符则是运算符,此时需比较优先关系。 做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。 (5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。 四、程序代码: //这是一个由中缀式生成后缀式的程序 #include<> #include<> #include<> #include<> #define maxbuffer 64 void main() { char display_out(char out_ch[maxbuffer], char ch[32]); //int caculate_array(char out_ch[32]); static int i=0; static int j=0; char ch[maxbuffer],s[maxbuffer],out[maxbuffer]; cout<<"请输入中缀表达式: ";

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

编译原理实验报告实验名称:实验一编写词法分析程序 实验类型:验证型实验 指导教师:何中胜 专业班级:13软件四 姓名:丁越 学号: 电子邮箱: 实验地点:秋白楼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)。 对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有 该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组id中,将常数 变为二进制形式存入数组中 ci中,并记录其在表中的位置。 lexical过程中嵌有两个小过程:一个名为getchar,其功能为从instring中按顺序取出一个字符,并将其指针pint加1;另一个名为error,当出现错误时,调用这个过程, 输出错误编号。 2.实践部分

编译原理实验词法解析总结器的设计及实现.doc

南华大学 计算机科学与技术学院 实验报告 ( 2018~2019学年度第二学期) 课程名称编译原理 实验名称词法分析器的设计与 实现 姓名学号

专业班级 地点教师 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|...|void 2.符号的 符号种符号种 main0>26 if1>=27 else2<28 while3<=29 do4!30 for5!=31

编译原理实验指导书2010

《编译原理》课程实验指导书 课程编号: 课程名称:编译原理/Compiler Principles 实验总学时数: 8 适用专业:计算机科学与技术、软件工程 承担实验室:计算机学院计算机科学系中心实验室、计算机技术系中心实验室 一、实验教学的目的与要求 上机实习是对学生的一种全面综合训练,是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。通常,实习题中的问题比平时的练习题要复杂,也更接近实际。编译原理这门课程安排的2次上机实验都属于一种设计类型的实验,每个实验的训练重点在于基本的编译技术和方法,而不强调面面俱到;实验的目的是旨在使学生进一步巩固课堂上所学的理论知识,深化理解和灵活掌握教学内容;培养学生编制算法的能力和编程解决实际问题的动手能力。 要求学生在上机前应认真做好各种准备工作,熟悉机器的操作系统和语言的集成环境,独立完成算法设计和程序代码的编写;上机时应随带有关的编译原理教材或参考书;要学会程序调试与纠错。 每次实验后要交实验报告,实验报告的内容应包括: (1)实验题目、班级、学号、姓名、完成日期; (2)简要的需求分析与概要设计; (3)详细的算法描述; (4)源程序清单; (5)给出软件的测试方法和测试结果; (6)实验的评价、收获与体会。 开发工具: (1)DOS环境下使用Turbo C; (2)Windows环境下使用Visual C++ 。 考核: 实验成绩占编译原理课程结业成绩的10%。 三、单项实验的内容和要求: 要求每个实验保证每个学生一台微机。 实验一(4学时):单词的词法分析程序设计。 (一)目的与要求 1.目的 通过设计、编制、调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。

编译原理实验报告

院系:计算机科学学院 专业、年级: 07计科2大班 课程名称:编译原理 学号姓名: 指导教师: 2010 年11月17 日 组员学号姓名

实验 名称 实验一:词法分析实验室9205 实验目的或要求 通过设计一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。 具体要求:输入为某语言源代码,达到以下功能: 程序输入/输出示例:如源程序为C语言。输入如下一段: main() { int a,b; a=10; b=a+20; } 要求输出如下(并以文件形式输出或以界面的形式输出以下结果)。 (2,”main”) (5,”(“) (5,”)“) (5,”{“} (1,”int”) (2,”a”) (5,”,”) (2,”b”) (5,”;”) (2,”a”) (4,”=”) (3,”10”) (5,”;”) (2,”b”) (4,”=”) (2,”a”) (4,”+”) (3,”20”) (5,”;”) (5,”}“) 要求: 识别保留字:if、int、for、while、do、return、break、continue等等,单词种别码为1。 其他的标识符,单词种别码为2。常数为无符号数,单词种别码为3。 运算符包括:+、-、*、/、=、>、<等;可以考虑更复杂情况>=、<=、!= ;单词种别码为4。分隔符包括:“,”“;”“(”“)”“{”“}”等等,单词种别码为5。

编译原理实验题目及报告要求

编译原理上机实验试题 一、实验目的 通过本实验使学生进一步熟悉和掌握程序设计语言的词法分析程序的设计原理及相关的设计技术, 如何针对确定的有限状态自动机进行编程序;熟悉和 掌握程序设计语言的语法分析程序的设计原理、熟悉 和掌握算符优先分析方法。 二、实验要求 本实验要求:①要求能熟练使用程序设计语言编程;②在上机之前要有详细的设计报告(预习报告); ③要编写出完成相应任务的程序并在计算机上准确 地运行;④实验结束后要写出上机实验报告。 三、实验题目 针对下面文法G(S): S→v = E E→E+E│E-E│E*E│E/E│(E)│v │i 其中,v为标识符,i为整型或实型数。要求完成 ①使用自动机技术实现一个词法分析程序; ②使用算符优先分析方法实现其语法分析程序,在 语法分析过程中同时完成常量表达式的计算。

1、题目(见“编译原理---实验题目.doc,“实验题目”中的第一项) 2、目的与要求(见“编译原理---实验题目.doc”) 3、设计原理: (1)单词分类:标识符,保留字,常数,运算符,分隔符等等 (2)单词类型编码 (3)自动机 4、程序流程框图 5、函数原型(参数,返回值) 6、关键代码(可打印,只打印关键代码) 7、调试: (1)调试过程中遇到的错误,如何改进的; (2)需要准备测试用例(至少3个,包含输入和输出)——(可打印) 8、思考: (1)你编写的程序有哪些要求是没有完成的,你觉得该采用什么方法去完成; (2)或者是你觉得程序有哪些地方可以进一步完善,简述你的完善方案。

1、题目(见“编译原理---实验题目.doc,“实验题目”中的第二项) 2、目的与要求(见“编译原理---实验题目.doc”) 3、设计原理:构造出算法优先关系表 4、程序流程框图 5、函数原型(参数,返回值) 6、关键代码(可打印,只打印关键代码) 7、调试: (1)调试过程中遇到的错误,如何改进的; (2)需要准备测试用例(至少3个,包含输入和输出)——(可打印) 8、思考: (1)你编写的程序有哪些要求是没有完成的,你觉得该采用什么方法去完成; (2)或者是你觉得程序有哪些地方可以进一步完善,简述你的完善方案。

《编译原理》实验指导书-2015

武汉科技大学计算机科学与技术学院 编译原理实验指导书

实验一词法分析器设计 【实验目的】 1.熟悉词法分析的基本原理,词法分析的过程以及词法分析中要注意的问题。 2.复习高级语言,进一步加强用高级语言来解决实际问题的能力。 3.通过完成词法分析程序,了解词法分析的过程。 【实验内容】 用C语言编写一个PL/0词法分析器,为语法语义分析提供单词,使之能把输入的字符串形式的源程序分割成一个个单词符号传递给语法语义分析,并把分析结果(基本字,运算符,标识符,常数以及界符)输出。 【实验要求】 1.要求绘出词法分析过程的流程图。 2.根据词法分析的目的以及内容,确定完成分析过程所需模块。 3.写出每个模块的源代码,并给出注释。 4.整理程序清单及所得结果。 【说明】 运行成功以后,检查程序,并将运行结果截图打印粘贴到实验报告上。 辅助库函数scanerLib设计以及使用说明: 下面内容给出了一个辅助库函数的接口说明以及具体实现。 接口设计 //字符类 class Token { TokenType type; String str; Int line; } //词法分析结果输出操作类 class TokenWriter { ArrayList tokens; //用来记录所识别出来的token TokenWriter(); //构造函数指定输入文件名,创建文件输出流 V oid Add(Token); //将词法分析器中分析得到的Token添加到tokens中 WriteXML(); //将tokens写出到目标文件.xml中 } //词法分析操作词法分析生成文件接口<暂时不需要对该类的操作;下一步做语法分析的时候使用> class TokenReader

编译原理实验报告一

实验一词法分析程序实现 一、实验目得与要求 通过编写与调试一个词法分析程序,掌握在对程序设计语言得源程序进行扫描得过程中,将字符流形式得源程序转化为一个由各类单词符号组成得流得词法分析方法 二、实验内容 基本实验题目:若某一程序设计语言中得单词包括五个关键字begin、end、if、then、else;标识符;无符号常数;六种关系运算符;一个赋值符与四个算术运算符,试构造能识别这些单词得词法分析程序(各类单词得分类码参见表I)。 表I语言中得各类单词符号及其分类码表 输入:由符合与不符合所规定得单词类别结构得各类单词组成得源程序文件。 输出:把所识别出得每一单词均按形如(CLASS,VALUE)得二元式形式输出,并将结果放到某个文件中。对于标识符与无符号常数,CLASS字段为相应得类别码得助记符;V AL UE字段则就是该标识符、常数得具体值;对于关键字与运算符,采用一词一类得编码形式,仅需在二元式得CLASS字段上放置相应单词得类别码得助记符,V ALUE字段则为“空". 三、实现方法与环境 词法分析就是编译程序得第一个处理阶段,可以通过两种途径来构造词法分析程序.其一就是根据对语言中各类单词得某种描述或定义(如BNF),用手工得方式(例如可用C语言)构造词法分析程序。一般地,可以根据文法或状态转换图构造相应得状态矩阵,该状态矩阵连同控制程序一起便组成了编译器得词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。构造词法分析程序得另外一种途径就是所谓得词法分析程序得自动生成,即首先用正规式对语言中得各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程

《编译原理》实验指导书

《编译原理》实验指导书 实验目的和内容 编译原理实验的目的是使学生将编译理论运用到实际当中,实现一个简单语言集的词法、语法和语义分析程序,验证实际编译系统的实现方法,并加深对编译技术的认识。 实验内容共需实现编译器的词法、语法和语义分析程序三个组成部分。要求学生必须完成每个实验的基本题目要求,有余力的同学可尝试实验的扩展要求部分。 实验报告 要求每人针对所完成的实验内容上交一份实验报告,其中主要包括三方面内容:1、实验设计:实验采用的实现方法和依据(如描述语言的文法及其机内表示,词分析 的单词分类码表、状态转换图或状态矩阵等,语法分析中用到的分析表或优先矩阵等,语法制导翻译中文法的拆分和语义动作的设计编写等);具体的设计结果(应包括整体设计思想和实现算法,程序结构的描述,各部分主要功能的说明,法以及所用数据结构的介绍等)。 2、程序代码:实验实现的源程序清单,要求符合一般的程序书写风格,有详细的注释。 3、实验结果分析:自行编写若干源程序作为测试用例,对所生成的编译程序进行测试 (编译程序的输入与输出以文件的形式给出);运行结果分析(至少包括一个正确和一个错误单词或语句的运行结果);以及改进设想等。 注意事项 1、电子版实验报告和源程序在最后一次机时后的一周内上交。(每个同学上交一个压 缩文件,其命名格式为“学号_姓名.rar”,内含实验报告和一个命名为“源程序” 的文件夹。注意提交的源程序应是经过调试、测试成功的较为通用的程序,并应有相应的注释、运行环境和使用方法简介。) 2、不接受不完整的实验报告和没有说明注释的源程序,或者说明与程序、运行结果不 符合的作业。 特别鼓励:扩展题目 1、为亲身经历一个小型编译器的开发全过程,触摸一下与实际编译器开发相关的工作, 大家可以自由组成3人左右的小组,推举组长,模拟一个团队分工协作开发大型软件的实战环境,融入软件工程的思想规范和一般理论方法,初步体验从系统分析设计、编码测试到交付维护的一个完整编译器软件的开发过程。要求组长为每个小组成员分配主要负责的任务,完成相应的分析设计员、程序员和测试员等角色的工作,并以小组为单位提交一份实验报告和源程序,在报告封面上写明每个同学主要完成和负责的部分。 2、以组为单位完成的实验内容至少必须整合词法、语法和语义三个部分的实验,对于 选定的适当规模的文法(如C语言的一个大小适宜的子集),进行系统的总体设计、功能分析、编码测试等工作。完成一个从对源程序的词法分析开始,到中间代码生成的完整的编译器前端的开发,使所涉及到的编译系统的各个组成模块有机地衔接在一起,提交一份完整的实验报告和源程序,并将以下几个方面描述清楚:

编译原理实验指导书

编译原理 实 验 指 导 书 作者:莫礼平 2011年3月

实验一简单词法分析程序设计 一、实验目的 了解词法分析程序的基本构造原理,掌握词法分析程序的手工构造方法。 二、实验内容 1、了解编译程序的词法分析过程。 2、根据PASCAL语言的说明语句形式,用手工方法构造一个对说明语句进行词法分析的程序。该程序能对从键盘输入或从文件读入的形如: “const count=10,sum=81.5,char1=’f’,string1=”hj”, max=169;” 的常量说明串进行处理,分析常量说明串中各常量名、常量类型及常量值,并统计各种类型常量个数。 三、实验要求 1、输入的常量说明串,要求最后以分号作结束标志; 2、根据输入串或读入的文本文件中第一个单词是否为“const”判断输入串或文本文件是否为常量说明内容; 3、识别输入串或打开的文本文件中的常量名。常量名必须是标识符,定义为字母开头,后跟若干个字母,数字或下划线; 4、根据各常量名紧跟等号“=”后面的内容判断常量的类型。其中:字符型常量定 义为放在单引号内的一个字符;字符串常量定义为放在双引号内所有内容;整型常量定 义为带或不带+、- 号,不以0开头的若干数字的组合;实型常量定义为带或不带+、- 号, 不以0开头的若干数字加上小数点再后跟若干数字的组合; 5、统计并输出串或文件中包含的各种类型的常量个数; 6、以二元组(类型,值)的形式输出各常量的类型和值; 7、根据常量说明串置于高级语言源程序中时可能出现的错误情况,模仿高级语言编 译器对不同错误情况做出相应处理。 四、运行结果 1、输入如下正确的常量说明串: const count=10,sum=81.5,char1=‘f’,max=169,str1=“h*54 2..4S!AAsj”, char2=‘@’,str2=“aa!+h”; 输出: count(integer,10) sum(float,81.5) char1(char, ‘f’) max(integer,169) str1(string,“h*54 2..4S!AAsj”) char2(char, ‘@’) str2(string,“aa!+h”) int_num=2; char_num=2; string_num=2; float_num=1. 2、输入类似如下的保留字const错误的常量说明串: Aconstt count=10,sum=81.5,char1=‘f’; 输出类似下面的错误提示信息:

编译原理实验报告

《编译原理》实验报告软件131 陈万全132852

一、需求分析 通过对一个常用高级程序设计语言的简单语言子集编译系统中词法分析、语法分析、语义处理模块的设计、开发,掌握实际编译系统的核心结构、工作流程及其实现技术,获得分析、设计、实现编译程序等方面的实际操作能力,增强设计、编写和调试程序的能力。 通过开源编译器分析、编译过程可视化等扩展实验,促进学生增强复杂系统分析、设计和实现能力,鼓励学生创新意识和能力。 1、词法分析程序设计与实现 假定一种高级程序设计语言中的单词主要包括五个关键字begin、end、if、then、else;标识符;无符号常数;六种关系运算符;一个赋值符和四个算术运算符,试构造能识别这些单词的词法分析程序。 输入:由符合和不符合所规定的单词类别结构的各类单词组成的源程序文件。 输出:把所识别出的每一单词均按形如(CLASS,VALUE)的二元式形式输出,并将结果放到某个文件中。对于标识符和无符号常数,CLASS字段为相应的类别码的助记符;VALUE字段则是该标识符、常数的具体值;对于关键字和运算符,采用一词一类的编码形式,仅需在二元式的CLASS字段上放置相应单词的类别码的助记符,VALUE字段则为“空”。 2、语法分析程序设计与实现 选择对各种常见高级程序设计语言都较为通用的语法结构——算术表达式的

一个简化子集——作为分析对象,根据如下描述其语法结构的BNF定义G2[<算术表达式>],任选一种学过的语法分析方法,针对运算对象为无符号常数和变量的四则运算,设计并实现一个语法分析程序。 G2[<算术表达式>]: <算术表达式>→<项> | <算术表达式>+<项> | <算术表达式>-<项> <项>→<因式>|<项>*<因式>|<项>/<因式> <因式>→<运算对象> | (<算术表达式>) 若将语法范畴<算术表达式>、<项>、<因式>和<运算对象>分别用E、T、F和i 代表,则G2可写成: G2[E]:E → T | E+T | E-T T → F | T*F | T/F F → i | (E) 输入:由实验一输出的单词串,例如:UCON,PL,UCON,MU,ID······输出:若输入源程序中的符号串是给定文法的句子,则输出“RIGHT”,并且给出每一步分析过程;若不是句子,即输入串有错误,则输出“ERROR”,并且显示分析至此所得的中间结果,如分析栈、符号栈中的信息等,以及必要的出错说明信息。 3、语义分析程序设计与实现 对文法G2[<算术表达式>]中的产生式添加语义处理子程序,完成运算对象是简单变量(标识符)和无符号数的四则运算的计值处理,将输入的四则运算转换为四元式形式的中间代码。 输入:包含测试用例(由标识符、无符号数和+、?、*、/、(、)构成的算术表达式)的源程序文件。 输出:将源程序转换为中间代码形式表示,并将中间代码序列输出到文件中。 若源程序中有错误,应指出错误信息 二、设计思路 1、词法分析程序设计与实现 1)单词分类 为了编程的实现。我们假定要编译的语言中,全部关键字都是保留字,程序员不得将它们作为源程序中的标识符;作了这些限制以后,就可以把关键字和标识符的识别统一进行处理。即每当开始识别一个单词时,若扫视到的第一个字符为字母,则把后续输入的字母或数字字符依次进行拼接,直至扫视到非字母、数字字符为止,以期获得一个尽可能长的字母数字字符串,然后以此字符串查所谓保留字表(此保留字表要事先造好),若查到此字符串,则取出相应的类别码;反之,则表明该字符串应为一标识符。

编译原理实验-词法分析器的设计说明

集美大学计算机工程学院实验报告 课程名称:编译原理班级: 指导教师:: 实验项目编号:实验一学号: 实验项目名称:词法分析器的设计实验成绩: 一、实验目的 通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 二、实验容 编写一个词法分析器,从输入的源程序(编写的语言为C语言的一个子集)中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示) 三、实验要求 1、词法分析器的功能和输出格式 词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符 2 别单词的类型,将标识符和常量分别插入到相应的符号表中,增加错误处理等。 3、编程语言不限。

四、实验设计方案 1、数据字典 本实验用到的数据字典如下表所示:

3、实验程序 #include #include #include #include //判断读入的字符是否为字母 bool isLetter(char c){ if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')){ return true; } else return false; } //判断读入的字符是否为数字 bool isDigit(char c){ if(c >='0' && c <= '9'){ return true; } else return false; } //判断是否为关键字 bool isKey(char *string) { if(!strcmp(string,"void") || !strcmp(string,"if")|| !strcmp(string,"for")|| !strcmp(string,"wh ile") || !strcmp(string,"do")|| !strcmp(string,"return")|| !strcmp(stri ng,"break") || !strcmp(string,"main")|| !strcmp(string,"int")|| !strcmp(strin g,"float")|| !strcmp(string,"char") || !strcmp(string,"double")|| !strcmp(string,"String"))

编译原理实验指导

编译原理实验指导书 主编:徐静李娜 信息与电气工程学院 2010年3月

概述 一、本课程实验的目的和任务 编译原理是一门实践性很强的课程,只有通过实践,才能真正掌握。实际的编译程序是十分复杂的,有时由多达十几万条指令组成。为此,编译原理的实践教学,采用简化编译过程的办法,选择最关键的3个环节──词法分析、语法分析(包括语义处理、产生无优化的目标指令)、连接调试,进行编程和调试训练。每个环节作为一个实践课题。先分别编程调试,再连接在一起总调。 二、实验方法 任何一个实用的高级语言,其语法都比较复杂,如选其作为源语言,很难实践全过程。故本实验将定义一个简化的语言── C语言的一个子集作为源语言,设计调试出它的编译程序。前后贯穿这一条主线进行实践。每次都可利用课余时间编程,利用上机时间进行输入和调试。 三、实验报告的规范和要求 每个实验完成后写出实验报告。实验报告的内容包括如下内容: 一、实验目的 二、程序设计时采用的算法和方法 三、输入的源程序 四、词法分析程序清单和输出结果。 五、心得体会

实验一词法分析 一、实验目的: (1)通过设计编制调试一个具体的词法分析程序,理解词法分析在编译程序中的作用。 (2)加深对有穷自动机模型的理解。 (3)掌握词法分析程序的实现方法和技术。 (4)用C语言对一个简单语言的子集编制一个一遍扫描的程序,以加深对编译原理的理解,掌握编译程序的实现方法和技术。 编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。 二、实验预习提示 1. 词法分析器的功能和输出格式 词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。 2. 单词的BNF表示 <标识符>→ <字母><字母数字串> <字母数字串>→<字母><字母数字串>|<数字> <字母数字串>| <下划线><字母数字串>|ε <无符号整数>→<数字> <数字串> <数字串>→<数字><数字串>|ε <加法运算符>→+ <减法运算符>→- <大于关系运算符>→> <大于等于关系运算符>→>= 3. “超前搜索”方法

编译原理实验指导书-语法分析

编译原理实验指导书 实验2 语法分析 实验目的 1.巩固对语法分析的基本功能和原理的认识。 2.通过对语法分析表的自动生成加深语法分析表的认识。 3.理解并处理语法分析中的异常和错误。 实验要求 一、对学生要求: 1.掌握语法分析程序的总体框架,并将其实现。 2.掌握语法分析表的构造方法 3.掌握语法分析的异常和错误处理。 二、对实验指导教师要求: 1.明确语法分析的基本功能和原理。 2.语法分析程序的总体结构及其关键之处。 3.语法分析表的生成程序。 4.语法分析的异常和错误处理。 5.编写并运行该题目程序代码,具有该题目的参考答案。 6.深刻理解题目内涵,能够清晰描述问题,掌握该题目涉及的知识点,指导学生实验时需要注意的问题。 实验内容 采用至少一种语法分析技术(LL(1)、SLR(1)、LR(1)或LALR(1))分析类高级语言中的基本语句(至少包括函数定义、变量说明、赋值、循环、分支等语句)。 对如下工作进行展开描述 (1)给出如下语言成分的文法描述 ?函数定义(或过程定义) ?变量说明 ?赋值

?表达式 ?循环 ?分支 (2) 语法分析程序的总体结构及物理实现(程序框图) (3) 核心数据结构和功能函数的设计 (4) 错误处理 错误的位置及类型等 实验评分标准 一、课堂表现(10分) 1.出勤情况(按时,迟到,早退,缺席) 2.是否遵守课堂纪律 二、实验结果(50分) 1.当堂按时完成(10分) 2.独立完成(10分),(和同学协商完成,在老师帮助下完成)3.结果正确无误(15分)其中分析表的输出占5分 4.功能齐全,界面美观,具有较好演示效果(10分) 5.在源程序中有必要的注释和说明,程序文档齐全(5分)三、实验报告(40分) 1.语言的文法描述(10分) 2.语法分析程序的模块结构图(10分) 3.核心数据结构的设计(10分) 4.错误处理(5分) 5.实验过程中遇到的问题的总结及实验的体会(5分)

编译原理实验1

大学学生实验报告 开课学院及实验室:年月日 实验目的 设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。 针对表达各类词语的一组正规表达式,设计一个确定化的最简的有限自动机,对输入的符号串进行单词划分及词类识别。 实验容 将词法分析器分解为以下几个部分: 1.正规表达式的解析:将正规表达式中的符号分解为常量字符、正规表达 式标识符和正规表达式运算符,然后基于正规表达式运算将正规表达式 分解为更小的正规表达式(通过正规表达式运算符进行串接)。 2.正规表达式到NFA的转换:根据转换规则,基于正规表达式运算,将正 规表达式转换为非确定有限自动机,并确定各类词的终止状态。

3.NFA的确定化:通过计算各状态的传递闭包,将NFA确定化,并确定 各类词的终止状态。 4.最小化:通过子集法,求得最简的确定有限自动机,并确定各类词的终 止状态。 例如:分析C语言子集的词法 1)关键字 main if else int return void while (都是小写)2)专用符号 = + —* / < <= < >= = = != ;:,{ } [ ] ( ) 3)其他模式(正规表达式) STRING::=" [^"]* ID::=letter(letter|digit)* INT::=digit digit* letter::= a|…|z|A|…|Z digit::= 0|…|9 4)空格由空白、制表符和换行符组成 空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。 部分单词符号对应的种别码

词法分析程序的功能 输入:所给文法的源程序字符串 输出:二元组(syn, token或sum)构成的序列。其中syn 为单词种别码;token 为存放的单词自身字符串;sum为整型常量(作为常量的值)。实现时,可将单词的二元组用结构进行处理 代码: #include #include

编译原理实验报告2词法分析程序的设计

实验2 词法分析程序的设计 一、实验目的 掌握计算机语言的词法分析程序的开发方法。 二、实验内容 编制一个能够分析三种整数、标识符、主要运算符和主要关键字的词法分析程序。 三、实验要求 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)* 运算符和界符+ - * / > < = ( ) ; 关键字if then else while do 2、根据状态图,设计词法分析函数int scan( ),完成以下功能: 1)从文本文件中读入测试源代码,根据状态转换图,分析出一个单词, 2)以二元式形式输出单词<单词种类,单词属性> 其中单词种类用整数表示: 0:标识符 1:十进制整数 2:八进制整数 3:十六进制整数 运算符和界符,关键字采用一字一符,不编码 其中单词属性表示如下: 标识符,整数由于采用一类一符,属性用单词表示 运算符和界符,关键字采用一字一符,属性为空 3、编写测试程序,反复调用函数scan( ),输出单词种别和属性。 四、实验环境 PC微机 DOS操作系统或Windows 操作系统 Turbo C 程序集成环境或Visual C++ 程序集成环境 五、实验步骤 1、根据正规式,画出状态转换图;

编译原理实验指导书

编译原理实验指导 书

《编译原理》实验指导书 太原科技大学计算机学院 -3-1

序 《编译原理》是国内外各高等院校计算机科学技术类专业,特别是计算机软件专业的一门重要专业课程。该课程系统地向学生介绍编译程序的结构、工作流程及编译程序各组成部分的设计原理和实现技术。由于该课程理论性和实践性都比较强,内容较为抽象复杂,涉及到大量的软件设计和算法,因此,一直是一门比较难学的课程。为了使学生更好地理解和掌握编译原理和技术的基本概念、基本原理和实现方法,实践环节非常重要,只有经过上机进行程序设计,才能使学生对比较抽象的教学内容产生具体的感性认识,增强学生综合分析问题、解决问题的能力,并对提高学生软件设计水平大有益处。 为了配合《编译原理》课程的教学,考虑到本课程的内容和特点,本指导书设置了七个综合性实验,分别侧重于词法分析、NFA的确定化、非递归预测分析、算符优先分析器的构造、LR分析、语义分析和中间代码的生成、基于DAG的基本块优化,以支持编译程序的各个阶段,基本涵盖了《编译原理》课程的主要内容。 本指导书可作为《编译原理》课程的实验或课程设计内容,在课程教学的同时,安排学生进行相关的实验。实验平台可选择在MS-DOS或Windows操作系统环境,使用C/C++的任何版本作为开发工具。学生在做完试验后,应认真撰写实验报告,内容应

包括实验名称、实验目的、实验要求、实验内容、测试或运行结果等。

目录 实验一词法分析 ........................................................... 错误!未定义书签。实验二 NFA的确定化.................................................... 错误!未定义书签。实验三非递归预测分析 ............................................... 错误!未定义书签。实验四算符优先分析器的构造................................... 错误!未定义书签。实验五 LR分析 .............................................................. 错误!未定义书签。实验六语义分析和中间代码生成................................ 错误!未定义书签。实验七基于DAG的基本块优化................................... 错误!未定义书签。

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

《编译原理》实验报告 班级:计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状态分别引出相应标记的矢

编译原理实验四

编译原理实验报告 实验名称NFA转换为DFA 实验时间2014-5-18 院系计算机科学与技术学院 班级 学号 姓名

1.试验目的 不确定有限状态自动机的确定化(Affirmation of the indefinitely finite automata) 2.实验原理 一个确定的有限自动机(DFA)M可以定义为一个五元组,M=(K,∑,F,S,Z),其中: (1)K是一个有穷非空集,集合中的每个元素称为一个状态; (2)∑是一个有穷字母表,∑中的每个元素称为一个输入符号; (3)F是一个从K×∑→K的单值转换函数,即F(R,a)=Q,(R,Q∈K)表示当前状态为R,如果输入字符a,则转到状态Q,状态Q称为状态R的后继状态; (4)S∈K,是惟一的初态; (5)Z?K,是一个终态集。 由定义可见,确定有限自动机只有惟一的一个初态,但可以有多个终态,每个状态对字母表中的任一输入符号,最多只有一个后继状态。 对于DFA M,若存在一条从某个初态结点到某一个终态结点的通路,则称这条通路上的所有弧的标记符连接形成的字符串可为DFA M所接受。若M的初态结点同时又是终态结点,则称ε可为M所接受(或识别),DFA M所能接受的全部字符串(字)组成的集合记作L(M)。 一个不确定有限自动机(NFA)M可以定义为一个五元组,M=(K,∑,F,S,Z),其中: (1)k是一个有穷非空集,集合中的每个元素称为一个状态; (2)∑是一个有穷字母表,∑中的每个元素称为一个输入符号; (3)F是一个从K×∑→K的子集的转换函数; (4)S?K,是一个非空的初态集; (5)Z?K,是一个终态集。 由定义可见,不确定有限自动机NFA与确定有限自动机DFA的主要区别是: (1)NFA的初始状态S为一个状态集,即允许有多个初始状态; (2)NFA中允许状态在某输出边上有相同的符号,即对同一个输入符号可以有多个后继状态。即DFA中的F是单值函数,而NFA中的F是多值函数。 因此,可以将确定有限自动机DFA看作是不确定有限自动机NFA的特例。和DFA一样,NFA也可以用矩阵和状态转换图来表示。 对于NFA M,若存在一条从某个初态结点到某一个终态结点的通路,则称这条通路上的所有弧的标记(ε除外)连接形成的字符串可为M所接受。NFA M所能接受的全部字符串(字)组成的集合记作L(M)。 由于DFA是NFA的特例,所以能被DFA所接受的符号串必能被NFA所接受。 设M 1和M 2 是同一个字母集∑上的有限自动机,若L(M 1 )=L(M 2 ),则称有 限自动机M 1和M 2 等价。 由以上定义可知,若两个自动机能够接受相同的语言,则称这两个自动机等 价。DFA是NFA的特例,因此对于每一个NFA M 1总存在一个DFA M 2 ,使得L(M 1 ) =L(M 2 )。即一个不确定有限自动机能接受的语言总可以找到一个等价的确定有限自动机来接受该语言。

相关文档
最新文档