语法分析器的设计

合集下载

语法分析程序的设计与实现

语法分析程序的设计与实现

◆词法分析 用户必须提供一个词法分析器来读取输入流并把记号(带有值, 如果需要的话)传达到解析器。词法分析器使叫做 yylex 的整数值的 函数。这个函数返回一个整数的记号编号,它表示读取的记号的种类。 如果这个记号关联着一个值,应当把它赋予外部变量 yylval。 为使通信得以发生,解析器和词法分析器必须在记号编号上达成 一致。编号可以由 Yacc 或用户来选择。在这两种情况下,使用 C 语 言的“# define”机制允许词法分析器使用符号来返回这些编号。例如, 假定在 Yacc 规定文件的声明段中已经定义记号名字 DIGIT。 它的意图是返回一个 DIGIT 记号编号,和等于这个数字的数值 的一个值。倘若词法分析器代码位于规定文件的程序段,标识符 DIGIT 将被定义为与记号 DIGIT 关联的记号编号。 这种机制导致清晰的、易于修改的词法分析器;唯一的缺点是在 文法中需要避免使用任何在 C 语言或解析器中保留的或有意义的记 号名字;例如,使用记号名字 if 或 while 就一定会导致编译词法分 析器时出现严峻的困难。记号名字 error 保留给错误处理,不应该随 便使用。 同上所述,记号编号可以由 Yacc 或用户来选择。在缺省的条件 下,编号由 Yacc 选择。文字字符的缺省记号编号是它在本地字符集 中的字符数值。其他名字赋予从 257 开始的记号编号。 要把一个记号编号赋予一个记号(包括文字),可以在声明段中记 号或文字的第一次出现时直接跟随着一个非负整数。这个整数被接受
第四:YACC 内部名称: ................................................................................................ 7 第五:运行结果(源代码见附录).............................................................................. 8 第六:实验总结 ............................................................................................................... 8 第七:附录 ..................................................................................................................... 10

语法分析器报告

语法分析器报告
While S[j]>a do
Begin
Repeat
Q:=S[j]
If S[j-1]∈VTthenj:=j-1elsej:=j-2
UntilS[j]<Q
把S[j+1]……S[K]归约为某个N
记录归约产生式序号
K:=j+1
S[K]:=N
End of while
If S[j]<a OR S[j]=a then
j++;
}
strings[m+1]='#';
strings[m+2]='\0';
cout<<"算术表达式"<<id<<"为: "<<oldstrings<<endl;
cout<<"转换为输入串: "<<strings<<endl;
cout<<" 步骤号符号栈优先关系当前分析符剩余输入串动作";
prior_analysis();
cout<<" # < < < < < e3 < ="<<endl;
if((fp=fopen("预处理.txt","r"))==NULL)
{
cout<<"请先将实验文件夹中的预处理.txt文件复制到实验文件夹中!"<<endl;
system("pause");
exit(0);
}
charch=fgetc(fp);

PL0语言语法分析器实验报告

PL0语言语法分析器实验报告

PL0语言语法分析器实验报告一、引言编译器是一种用于把高级语言程序转换成机器可执行代码的软件工具。

编译器由多个组件构成,其中语法分析器是编译器中的重要组成部分,其主要功能是对输入的源代码进行解析,并生成一个语法树。

本实验旨在通过使用BNF(巴科斯范式)描述PL0语言的语法规则,并通过实现PL0语言的语法分析器,来深入理解语法分析的原理和过程。

二、PL0语言的语法规则1.程序结构:<程序>::=[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>2.常量说明部分:<常量说明部分> ::= const <常量定义> { , <常量定义> };<常量定义>::=<标识符>=<无符号整数>3.变量说明部分:<变量说明部分> ::= var <标识符> { , <标识符> };4.过程说明部分:<过程说明部分>::=<过程首部><分程序>;<过程首部> ::= procedure <标识符> ;5.语句:<语句> ::= <赋值语句> , <if语句> , <while语句> , <调用语句> , <复合语句> , <读语句> , <写语句> , <空><赋值语句>::=<标识符>:=<表达式><if语句> ::= if <条件> then <语句> else <语句><while语句> ::= while <条件> do <语句><调用语句> ::= call <标识符><复合语句> ::= begin <语句> { ; <语句> } end<读语句> ::= read ( <标识符> )<写语句> ::= write ( <表达式> )6.表达式:<表达式>::=[+,-]<项>{(+,-)<项>}<项>::=<因子>{(*,/)<因子>}<因子>::=<标识符>,<无符号整数>,(<表达式>)7.条件:<条件>::=<表达式><关系运算符><表达式><关系运算符>::==,<>,<,<=,>,>=三、PL0语言的语法分析器设计与实现1.设计思路本次实验中,我们将使用自顶向下的递归下降分析法,来对PL0语言进行语法分析。

Tiny语言语法分析器设计过程

Tiny语言语法分析器设计过程

Tiny语言语法分析器设计过程1、创建空工程
运行Microsoft Visual C++ 6.0 File菜单下选择New:
弹出下面对话框:
选择Win32 Console Application,同时在Project Name下输入工程名字:ParserByHand
点击Ok按钮,弹出下面对话框:
不做任何选择,按照默认“An empty project”,直接点击Finish按钮,弹出下面对话框:
直接点击OK按钮,工程创建完毕。

2、添加文件
首先在windows环境下,把设计好的文件GLOBALS.H、MAIN.C、PARSE.C、PARSE.H、SCAN.C、SCAN.H、UTIL.C 和UTIL.H拷贝到ParserByHand工程下:
如图所示,选中Project菜单,选择下面Add To Project子菜单下面的Files子菜单:
点击后弹出对话框:
在左侧的工程文件列表中,可以清楚地看到这些文件:
编译生成可执行文件ParserByHand.exe在本工程的debug目录下:
录下:
4、验证运行结果
Windows环境下点击“开始”,选中其中的“运行(R)”
,弹出下面对话框,输入cmd命令:
直接回车或者点击OK按钮,进入命令行方式(控制台方式):
输入上图所示的类似命令,进入可执行程序所在目录。

在当前目录下输入命令:ParserByHand sample.tny,然后回车,
西安理工大学计算机学院软061班吴松华制作张发存指导则得到相应的运行结果:命令行窗口太小,只显示其中的一部分:
第 11 页共 11 页。

编译原理词法分析器语法分析课程设计范本

编译原理词法分析器语法分析课程设计范本

《编译原理词法分析器语法分析课程设计-《编译原理》课程设计院系信息科学与技术学院专业软件工程年级级学号 2723姓名林苾湲西南交通大学信息科学与技术学院12月目录课程设计1 词法分析器 (2)设计题目 (2)设计内容 (2)设计目的 (2)设计环境 (2)需求分析 (2)概要设计 (2)详细设计 (4)编程调试 (5)测试 (11)结束语 (13)课程设计2 赋值语句的解释程序设计 (14)设计题目 (14)设计内容 (14)设计目的 (14)设计环境 (14)需求分析 (15)概要设计 (16)详细设计 (16)编程调试 (24)测试 (24)结束语 (25)课程设计一词法分析器设计一、设计题目手工设计c语言的词法分析器(能够是c语言的子集)。

二、设计内容处理c语言源程序,过滤掉无用符号,判断源程序中单词的合法性,并分解出正确的单词,以二元组形式存放在文件中。

三、设计目的了解高级语言单词的分类,了解状态图以及如何表示并识别单词规则,掌握状态图到识别程序的编程。

四、设计环境该课程设计包括的硬件和软件条件如下:.硬件(1)Intel Core Duo CPU P8700(2)内存4G.软件(1)Window 7 32位操作系统(2)Microsoft Visual Studio c#开发平台.编程语言C#语言五、需求分析.源程序的预处理:源程序中,存在许多编辑用的符号,她们对程序逻辑功能无任何影响。

例如:回车,换行,多余空白符,注释行等。

在词法分析之前,首先要先剔除掉这些符号,使得词法分析更为简单。

.单词符号的识别并判断单词的合法性:将每个单词符号进行不同类别的划分。

单词符号能够划分成5中。

(1)标识符:用户自己定义的名字,常量名,变量名和过程名。

(2)常数:各种类型的常数。

(3) 保留字(关键字):如if、else、while、int、float 等。

(4) 运算符:如+、-、*、<、>、=等。

语法分析器的设计

语法分析器的设计

编译原理语法分析器的设计◆根据某一文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号串进行分析。

◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。

◆分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。

实验设计方案1、设计思想(1)、LL(1)文法的定义LL(1)分析法属于确定的自顶向下分析方法。

LL(1)的含义是:第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式(规则)进行推导。

LL(1)文法的判别需要依次计算FIRST集、FOLLOW集和SELLECT集,然后判断是否为LL(1)文法,最后再进行句子分析。

需要预测分析器对所给句型进行识别。

即在LL(1)分析法中,每当在符号栈的栈顶出现非终极符时,要预测用哪个产生式的右部去替换该非终极符;当出现终结符时,判断其与剩余输入串的第一个字符是否匹配,如果匹配,则继续分析,否则报错。

LL(1)分析方法要求文法满足如下条件:对于任一非终极符A的两个不同产生式A→α,A→β,都要满足下面条件:SELECT(A→α)∩SELECT(A→β)=∅(2)、预测分析表构造LL(1)分析表的作用是对当前非终极符和输入符号确定应该选择用哪个产生式进行推导。

它的行对应文法的非终极符,列对应终极符,表中的值有两种:一是产生式的右部的字符串,一是null。

若用M表示LL(1)分析表,则M可表示如下:M: VN×VT→P∪{Error}M(A, t) = A→α,当t∈select(A→α) ,否则M(A, t) = Error其中P表示所有产生式的集合。

(3)、语法分析程序构造LL(1)分析中X为符号栈栈顶元素,a为输入流当前字符,E为给定测试数据的开始符号,#为句子括号即输入串的括号。

语法分析器实验报告

语法分析器实验报告

词法分析器实验报告实验名称:语法分析器实验内容:利用LL(1)或LR(1)分析语句语法,判断其是否符合可识别语法。

学会根据状态变化、first、follow或归约转移思想构造状态分析表,利用堆栈对当前内容进行有效判断实验设计:1.实现功能可对一段包含加减乘除括号的赋值语句进行语法分析,其必须以$为终结符,语句间以;隔离,判断其是否符合语法规则,依次输出判断过程中所用到的产生式,并输出最终结论,若有错误可以报错并提示错误所在行数及原因2.实验步骤3.算法与数据结构a)LLtable:left记录产生式左端字符;right记录产生式右端字符;ln记录产生式右端字符长度Status:记录token分析情况Token:category,类型;value,具体内容b)根据LL(1)算法,手工构造分析表,并将内容用数组存储,便于查找c)先将当前语句的各token按序存储,当前处理语句最后一个token以#标记,作为输入流与产生式比较,堆栈中初始放入#,x,a为处理输入流中当前读头内容✓若top=a=‘#‘表示识别成功,退出分析程序✓若top=a!=‘#‘表示匹配,弹出栈顶符号,读头前进一个✓若top为i或n,但top!=a,出错,输出当前语句所在行,出错具体字符✓若top不为i或n,查预测分析表,若其中存放关于top产生式,则弹出top,将产生式右部自右向左压入栈内,输出该产生式,若其中没有产生式,出错,输出当前语句所在行,出错具体字符d)以;作为语句终结,每次遇到分号则处理之前语句并清空后预备下语句处理,当遇到$表示该段程序结束,停止继续处理4.分析表构造过程a)x->i=ee->e+t|e-t|tt->t*f|t/f|ff->(e)|i|nnote: i表示变量,n表示数字,!表示空串b)提取左公因子x->i=ee->ea|ta->+t|-tt->tb|fb->*f|/ff->(e)|i|nc)消除左递归x->i=ee->tcc->ac|!a->+t|-tt->fdd->bd|!b->*e|/ff->(e)|i|n5.类class parser{public:LLtable table[100][100]; //LL(1)表void scanner(); //扫描输入流中内容并分析parser(istream& in); //初始化,得到输入文件地址int getLine() const; //得到当前行数private:int match(); //分析语法stack <char> proStack; //分析堆栈void constructTable(); //建立LL(1)表int getRow(char ch); //取字符所在表中行int getCol(char ch); //取字符所在表中列istream* pstream; //输入流void insertToken(token& t); //插入当前tokenstatus getToken(token& t); //找到tokenint getChar(); //得到当前字符int peekChar(); //下一个字符void putBackChar(char ch); //将字符放回void skipChar(); //跳过当前字符void initialization(); //初始化堆栈等int line; //当前行数token tokens[1000]; //字符表int counter; //记录当前字符表使用范围}6.主要代码void parser::constructTable() //建立LL(1)表{for (int i=0;i<8;i++){for (int j=0;j<9;j++){table[i][j].left=' ';for (int k=0;k<3;k++)table[i][j].right[k]=' ';}}table[0][6].left='x';table[0][6].ln=3;table[0][6].right[0]='i';table[0][6].right[1]='=';table[0][6].right[2]='e';table[1][4].left='e';table[1][4].ln=2;table[1][4].right[0]='t';table[1][4].right[1]='c';table[1][6].left='e';table[1][6].ln=2;table[1][6].right[0]='t';table[1][6].right[1]='c';table[1][7].left='e';table[1][7].ln=2;table[1][7].right[0]='t';table[1][7].right[1]='c';table[2][0].left='c';table[2][0].ln=2;table[2][0].right[0]='a';table[2][0].right[1]='c';table[2][1].left='c';table[2][1].ln=2;table[2][1].right[0]='a';table[2][1].right[1]='c';table[2][5].left='c';table[2][5].ln=0;table[2][5].right[0]='!';table[2][8].left='c';table[2][8].ln=0;table[2][8].right[0]='!';table[3][0].left='a';table[3][0].ln=2;table[3][0].right[0]='+'; table[3][0].right[1]='t'; table[3][1].left='a';table[3][1].ln=2;table[3][1].right[0]='-'; table[3][1].right[1]='t'; table[4][4].left='t';table[4][4].ln=2;table[4][4].right[0]='f'; table[4][4].right[1]='d'; table[4][6].left='t';table[4][6].ln=2;table[4][6].right[0]='f'; table[4][6].right[1]='d'; table[4][7].left='t';table[4][7].ln=2;table[4][7].right[0]='f'; table[4][7].right[1]='d'; table[5][0].left='d';table[5][0].ln=0;table[5][0].right[0]='!'; table[5][1].left='d';table[5][1].ln=0;table[5][1].right[0]='!'; table[5][2].left='d';table[5][2].ln=2;table[5][2].right[0]='b'; table[5][2].right[1]='d'; table[5][3].left='d';table[5][3].ln=2;table[5][3].right[0]='b'; table[5][3].right[1]='d'; table[5][5].left='d';table[5][5].ln=0;table[5][5].right[0]='!'; table[5][8].left='d';table[5][8].ln=0;table[5][8].right[0]='!'; table[6][2].left='b';table[6][2].ln=2;table[6][2].right[0]='*'; table[6][2].right[1]='f'; table[6][3].left='b';table[6][3].ln=2;table[6][3].right[0]='/'; table[6][3].right[1]='f'; table[7][4].left='f';table[7][4].ln=3;table[7][4].right[0]='(';table[7][4].right[1]='e';table[7][4].right[2]=')';table[7][6].left='f';table[7][6].ln=1;table[7][6].right[0]='i';table[7][7].left='f';table[7][7].ln=1;table[7][7].right[0]='n';}int parser::match() //分析语法{ofstream ofs("out.txt",ios::app);char a;int i=0;for (int p=0;p<counter;p++){cout<<tokens[p].value;ofs<<tokens[p].value;}cout<<endl;ofs<<endl<<"ANALYSIS:"<<endl;while(1){if(tokens[i].category=='n' || tokens[i].category=='i')a=tokens[i].category;elsea=(tokens[i].value)[0];if(a==proStack.top()){if(a=='#'){cout<<"This is valid!"<<endl<<endl;ofs<<"This is valid!"<<endl<<endl;return 0;}else{proStack.pop();i++;}}else{if(proStack.top() =='n'|| proStack.top() =='i'){if(a!='#'){cout<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;}else{cout<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;}cout<<"This is invalid!"<<endl<<endl;ofs<<"This is invalid!"<<endl<<endl;return 0;}else{if((table[getRow(proStack.top())][getCol(a)]).left!=' '){char pst=proStack.top();int n=table[getRow(pst)][getCol(a)].ln;int k=0;ofs<<table[getRow(pst)][getCol(a)].left<<"->"<<table[getRow(pst)][getCol(a)].right[0]<<table[getRow(pst)][g etCol(a)].right[1]<<table[getRow(pst)][getCol(a)].right[2]<<endl;proStack.pop();while (n>0){//cout<<n<<" "<<table[getRow(pst)][getCol(a)].right[n-1]<<endl;proStack.push(table[getRow(pst)][getCol(a)].right[n-1]);n--;}}else{if(a!='#'){cout<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;}else{cout<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;}cout<<"This is invalid!"<<endl<<endl;ofs<<"This is invalid!"<<endl<<endl;return 0;}}}}}实验结果:●输入(in.txt)●输出1输出2(out.txt)实验总结:原本以为处理四则运算赋值将会很困难,但在使用LL(1)后发现,思路还是挺清晰简单的,但在实验过程中,由于LL(1)不能出现左递归和左公因子,不得不将其消除,原本简单的产生式一下变多了,而在产生式理解上也没有原来直观,不过其状态复杂度没有LR高,故仍选择该方法。

编译原理语法分析器实验报告

编译原理语法分析器实验报告

编译原理语法分析器实验报告西安邮电大学编译原理实验报告学院名称:计算机学院****:***实验名称:语法分析器的设计与实现班级:计科1405班学号:04141152时间:2017年5月12日把SELECT (i)存放到temp中结果返回1;1.构建好的预测分析表2.语法分析流程图一.实验结果正确运行结果:错误运行结果:二.设计技巧和心得体会这次实验编写了一个语法分析方法的程序,但是在LL(1)分析器的编写中我只达到了最低要求,就是自己手动输入的select集,first集,follow集然后通过程序将预测分析表构造出来,然后自己编写总控程序根据分析表进行分析。

通过本次试验,我能够设计一个简单的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。

还能选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR分析分析程序。

三.源代码package com.LL1;import java.util.ArrayDeque;import java.util.Deque;/*** LL1文法分析器,已经构建好预测分析表,采用Deque实现* Created by HongWeiPC on 2017/5/12.*/public class LL1_Deque {//预测分析表private String[][] analysisTable = new String[][]{{"TE'", "", "", "TE'", "", ""},{"", "+TE'", "", "", "ε", "ε"},{"FT'", "", "", "FT'", "", ""},{"", "ε", "*FT'", "", "ε", "ε"},{"i", "", "", "(E)", "", ""}};//终结符private String[] VT = new String[]{"i", "+", "*", "(", ")", "#"};//非终结符private String[] VN = new String[]{"E", "E'", "T", "T'", "F"};//输入串strTokenprivate StringBuilder strToken = new StringBuilder("i*i+i");//分析栈stackprivate Deque<String> stack = new ArrayDeque<>();//shuru1保存从输入串中读取的一个输入符号,当前符号private String shuru1 = null;//X中保存stack栈顶符号private String X = null;//flag标志预测分析是否成功private boolean flag = true;//记录输入串中当前字符的位置private int cur = 0;//记录步数private int count = 0;public static void main(String[] args) {LL1_Deque ll1 = new LL1_Deque();ll1.init();ll1.totalControlProgram();ll1.printf();}//初始化private void init() {strToken.append("#");stack.push("#");System.out.printf("%-8s %-18s %-17s %s\n", "步骤", "符号栈", "输入串", "所用产生式");stack.push("E");curCharacter();System.out.printf("%-10d %-20s %-20s\n", count, stack.toString(), strToken.substring(cur, strToken.length()));}//读取当前栈顶符号private void stackPeek() {X = stack.peekFirst();}//返回输入串中当前位置的字母private String curCharacter() {shuru1 = String.valueOf(strToken.charAt(cur));return shuru1;}//判断X是否是终结符private boolean XisVT() {for (int i = 0; i < (VT.length - 1); i++) {if (VT[i].equals(X)) {return true;}}return false;}//查找X在非终结符中分析表中的横坐标private String VNTI() {int Ni = 0, Tj = 0;for (int i = 0; i < VN.length; i++) {if (VN[i].equals(X)) {Ni = i;}}for (int j = 0; j < VT.length; j++) {if (VT[j].equals(shuru1)) {Tj = j;}}return analysisTable[Ni][Tj];}//判断M[A,a]={X->X1X2...Xk}//把X1X2...Xk推进栈//X1X2...Xk=ε,不推什么进栈private boolean productionType() {return VNTI() != "";}//推进stack栈private void pushStack() {stack.pop();String M = VNTI();String ch;//处理TE' FT' *FT'特殊情况switch (M) {case "TE'":stack.push("E'");stack.push("T");break;case "FT'":stack.push("T'");stack.push("F");break;case "*FT'":stack.push("T'");stack.push("F");stack.push("*");break;case "+TE'":stack.push("E'");stack.push("T");stack.push("+");break;default:for (int i = (M.length() - 1); i >= 0; i--) {ch = String.valueOf(M.charAt(i));stack.push(ch);}break;}System.out.printf("%-10d %-20s %-20s %s->%s\n", (++count), stack.toString(), strToken.substring(cur, strToken.length()), X, M);}//总控程序private void totalControlProgram() {while (flag) {stackPeek(); //读取当前栈顶符号令X=栈顶符号if (XisVT()) {if (X.equals(shuru1)) {cur++;shuru1 = curCharacter();stack.pop();System.out.printf("%-10d %-20s %-20s \n", (++count), stack.toString(), strToken.substring(cur, strToken.length()));} else {ERROR();}} else if (X.equals("#")) {if (X.equals(shuru1)) {flag = false;} else {ERROR();}} else if (productionType()) {if (VNTI().equals("")) {ERROR();} else if (VNTI().equals("ε")) {stack.pop();System.out.printf("%-10d %-20s %-20s %s->%s\n", (++count), stack.toString(), strToken.substring(cur, strToken.length()), X, VNTI());} else {pushStack();}} else {ERROR();}}}//出现错误private void ERROR() {System.out.println("输入串出现错误,无法进行分析");System.exit(0);}//打印存储分析表private void printf() {if (!flag) {System.out.println("****分析成功啦!****");} else {System.out.println("****分析失败了****");}}}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
token = getnexttoken(); bf(); /*递归调用,not 后面应跟随另一个布尔量*/ } else /*处理括号(*/ if ( token = "(" ) {
token = getnexttoken( );
编译原理实验指导书
bexp( ); /*括号中仍然是表达式*/ token = getnexttoken( ); if ( token = ")" ) /*括号中的表达式处理完毕,后跟右括号*/
2.4 上机实验
【步骤一 语法分析总控程序的编写】
总控程序的功能就是识别以 program 开头的源程序头部结构,以及整个程序的框架,如 程序头部识别完之后,就是常量说明、变量说明、以及所有可执行语句的分析。具体步骤是:
(1) 利用实验四得到的 token 文件,如果直接调用词法分析,可以不使用文件。 (2) 利用自顶向下、逐个读入单词、判别是否符合程序头部的定义。 (3) 利用实验六的结果,判断各种说明语句和可执行语句是否正确。 (4) 重复(3)步,直到程序结束 例:可以按如下方式来编写总控程序:
编译原理实验指导书
开头),赋值语句(以标识符开头) 。每当读到前导词,表明一个新的语法结构的开始,以此 识别该语法单位是否符合定义。下图是语法分析程序的详细数据流图。
图 2-2 语法分析程序的详细数据流图 在语法分析过程中,各种语句的处理可以采用不同的语法分析方法,实验中希望能够使 用两种语法制导翻译技术:一是对各个语句和布尔表达式采用递归下降翻译法,二是对算术 表达式采用自底向上的算符优先分析方法。 根据采取的语法分析方法不同,就得到不同的详细数据流图。如下图是使用算符优先分 析方法的数据流。
(3) 编写识别算术表达式的函数,利用算符优先分析方法(也可以直接
使用递归下降的方法)。
(4) 实验思考题
1.语法分析程序的功能是什么?使用语法分析程序可以分析语言中的哪些语法成分? 2.语法分析的输入是什么?token 文件的特点是什么?你认为从 token 文件中读取一个 单词应采用什么方法? 3.递归下降分析方法的基本思路是什么?如何用它来编写程序? 4.请叙述对算术表达式的分析过程?
编译原理实验指导书
下面是根据上述处理流程利用递归下降的方法识别布尔表达式的函数描述如下:
bexp(char *token) /* 逻辑表达式的处理*/ {
bt( ); /* 处理布尔量*/ token = getnexttoken(); if ( token = "or" ) { /*首先处理 or*/
2.2 语法分析程序的设计方法
语法分析程序可以根据个人的掌握情况选用常见的几种语法分析方法:递归下降分析方 法、LL(1)预测分析法、算符优先分析、LR 分析等方法中的任何一种来实现,也可以选用不 同的方法来分析不同的语法成分,最后再综合起来。
2.3 语法分析程序的数据流图
词法分析程序把源程序变成 TOKEN 串,存放在 TOKEN 文件中。这个文件是 Sample 语言语法分析程序的输入文件。
实验思考题
1.语法分析总控程序应完成哪些操作? 2.为什么要对语句进行分类? 3.你编写的语法分析程序有哪些不足的地方,还有哪些功能是应该实现而你没有实现 的? 4.语法分析程序能够判别哪些错误?
【步骤二 编写识别算术表达式/逻辑表达式的函数】
(1) 编写从文件中读取一个单词的函数 getnexttoken(),返回该单词。
type = getnexttoken(); /*取出下一个token字,放入type中*/ if (type不是"integer","char","real","bool") error("变量说明错");
/*只能是这几种基本类型,若有其它类型,再加入*/ token= getnexttoken(); /*取出下一个token字*/ if (token不是";") error("缺少 ; ");/*处理完一行变量说明*/ token= getnexttoken(); /*取出下一个token字*/ if (isidentifier(token) ) varst(token);
编译原理实验指导书
《编译原理》综合性实验二:
语法分析器的设计
实验目的:掌握高级语言语法结构的定义,掌握语法分析的常用方法――递归下降的分析方 法。 实验要求:在 6 学时内完成全部内容,要求用 VC++窗口界面实现。 实验内容:分为 3 次实验内容完成。
2.1 语法分析程序的设计要求
语法分析程序要求能实现 Sample 语言中几种最常见的、基本的语法单位的分析:算术 表达式、逻辑表达式、赋值语句、IF 语句、for 语句、while 语句、repeat 语句等,各个语法 单位的定义见第 1 章,要求有完整的程序和说明。
图 2-3 算符优先分析的数据流图
编译原理实验指导书
图 2-4 算符优先分析的详细数据流图
但不管使用哪种语法分析方法,必须根据语法定义,下面详细说明变量说明的处理方法。 变量说明以var开头,格式如下:
<变量说明>::=var <变量定义>|ε <变量定义>::=<标识符表>:<类型>;|<标识符表>:<类型>;<变量定义> <标识符表>::=<标识符>, <标识符表>|<标识符>
处理流程如图:
下面是根据该流程采用递归下降的方法识别变量说明的算法描述。当读入前导词var后, 再读入一个token字,表明它是变量名称,调用下面的varst处理一行变量说明,当处理完一 行(读入;)后,下一行可能仍是变量说明,也可能是begin开始的可执行程序部分,否则就是 出错。
void varst(char *token) /*处理变量说明,读入var后进入该过程*/ {
语法分析是以单词为基本单位,因此,每次应读入一个单词。 语法分析的输入是词法分析的输出,即 token 字文件,在前面的实验中,将每个单词按 一行写入一个 token 文件中,因此首先应该打开文件,函数 getnexttoken()从文件的当前位置 读入一行,在 c 语言中可以使用函数 fgets(token,80,in)读入。
(2) 编制识别布尔表达式的函数
该函数逐个从文本中读取单词,判断所读入的以;结束的多个 token 是否构成了一个正 确的逻辑表达式。可以采用任何一种语法分析方法。布尔表达式的语法定义是:
(a) <逻辑表达式>::=<布尔项> or <布尔表达式> |<布尔项> (b) <布尔项>::=<布尔因子> and <布尔项> |<布尔因子> (c) <布尔因子>::=<布尔量> | not<布尔因子> (d) <布尔量>::=<布尔表达式>|<算术表达式><关系符><算术表达式> (e) <关系符>::=<|>|<>|<=| >=| = 下面是处理布尔表达式的流程:
文件名:parser 函数名:main()/* 从 token 文件中读取单词,根据定义进行分析*/ {
token = getnexttoken(); if (token = "program") { /*处理文件第一语句*/
token = getnexttoken(); isidentifier(token); /*判断是否是标识符*/ } token = getnexttoken(); if (token = ";") {/*程序头的结束*/ token = getnexttoken(); } if (token = "const") { /*表明下面是常量说明语句*/
/* 如果读入是标识符,继续处理变量说明*/ else if (token 是"begin")) return; /* 结束本函数的处理,
转入处理可执行程序部分*/
编译原理实验指导书
else error("语法错误:缺少BEGIN,或变量说明出错"); }
分析各种语法结构(算术表达式、逻辑表达式、说明语句、赋值语句、IF 语句、FOR 语 句、REPEAT 语句、WHILE 语句)的算法描述见语义分析一节。
token = getnexttoken(); bexp( ); /* 递归调用,or 后面应跟随另一个布尔表达式*/ } else 返回; /*布尔表达式分析结束*/ }
bt( ) /*处理 and*/
{
token = getnexttoken();
bf( );
/*处理布尔量*/
token = getnexttoken();
编译原理实验指导书
return 0; /*直接返回分析成功*/ } }
ST_SORT(chart *token) /* 可执行语句分类处理模块主程序*/ {
if (token = "if") ifs(); /*调用 IF 语句分析模块*/ else if (token= "while") whiles();/*调用 while 语句分析模块*/ else if (token= "repeat") repeats();/*调用 repeat 语句分析模块*/ else if (token= "for") fors();/*调用 for 语句分析模块*/ else assign();/*其余情况表示是赋值语句,直接调用赋值语句的分析*/ }
相关文档
最新文档