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

编译原理实验报告一、实验目的本次编译原理实验的主要目的是通过实践加深对编译原理中词法分析、语法分析、语义分析和代码生成等关键环节的理解,并提高实际动手能力和问题解决能力。
二、实验环境本次实验使用的编程语言为 C/C++,开发工具为 Visual Studio 2019,操作系统为 Windows 10。
三、实验内容(一)词法分析器的设计与实现词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个具有独立意义的单词符号。
在本次实验中,我们使用有限自动机的理论来设计词法分析器。
首先,我们定义了单词的种类,包括关键字、标识符、常量、运算符和分隔符等。
然后,根据这些定义,构建了相应的状态转换图,并将其转换为程序代码。
在实现过程中,我们使用了字符扫描和状态转移的方法,逐步读取输入的字符,判断其所属的单词类型,并将其输出。
(二)语法分析器的设计与实现语法分析是编译过程的核心环节之一,其任务是在词法分析的基础上,根据给定的语法规则,判断输入的单词序列是否构成一个合法的句子。
在本次实验中,我们采用了自顶向下的递归下降分析法来实现语法分析器。
首先,我们根据给定的语法规则,编写了相应的递归函数。
每个函数对应一种语法结构,通过对输入单词的判断和递归调用,来确定语法的正确性。
在实现过程中,我们遇到了一些语法歧义的问题,通过仔细分析语法规则和调整函数的实现逻辑,最终解决了这些问题。
(三)语义分析与中间代码生成语义分析的任务是对语法分析所产生的语法树进行语义检查,并生成中间代码。
在本次实验中,我们使用了四元式作为中间代码的表示形式。
在语义分析过程中,我们检查了变量的定义和使用是否合法,类型是否匹配等问题。
同时,根据语法树的结构,生成相应的四元式中间代码。
(四)代码优化代码优化的目的是提高生成代码的质量和效率。
在本次实验中,我们实现了一些基本的代码优化算法,如常量折叠、公共子表达式消除等。
通过对中间代码进行分析和转换,减少了代码的冗余和计算量,提高了代码的执行效率。
编译原理 实验

编译原理实验编译原理实验。
编译原理是计算机科学中的一个重要领域,它研究的是编译器的设计和实现原理。
编译器是将高级语言代码转换成机器语言代码的程序,它在软件开发过程中起着至关重要的作用。
而编译原理实验则是帮助学生深入理解编译原理的重要手段之一,通过实际操作来加深对编译原理知识的理解和掌握。
在编译原理实验中,我们需要掌握以下几个关键点:1. 词法分析,词法分析是编译过程中的第一步,它负责将源代码分割成一个个的单词(Token)。
在词法分析实验中,我们需要实现一个词法分析器,能够正确地识别出源代码中的各种单词,并进行分类和标记。
2. 语法分析,语法分析是编译过程中的第二步,它负责将词法分析得到的单词序列转换成抽象语法树。
在语法分析实验中,我们需要实现一个语法分析器,能够根据给定的文法规则,将单词序列转换成抽象语法树,并进行语法检查。
3. 语义分析,语义分析是编译过程中的第三步,它负责对抽象语法树进行语义检查和翻译。
在语义分析实验中,我们需要实现一个语义分析器,能够对抽象语法树进行类型检查、作用域分析等,并生成中间代码。
4. 代码生成,代码生成是编译过程中的最后一步,它负责将中间代码转换成目标机器代码。
在代码生成实验中,我们需要实现一个代码生成器,能够将中间代码转换成目标机器代码,并进行优化。
通过以上实验,我们可以深入理解编译原理的各个环节,并掌握编译器的设计和实现原理。
同时,实验过程中还能培养我们的动手能力和解决问题的能力,为今后的软件开发打下坚实的基础。
总之,编译原理实验是非常重要的,它能够帮助我们深入理解编译原理知识,提高我们的动手能力和解决问题的能力。
希望大家能够认真对待编译原理实验,从中获得更多的收获和成长。
编译原理实验报告

编译原理实验报告班级姓名:学号:自我评定:实验一词法分析程序实现一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实验内容根据教学要求并结合学生自己的兴趣和具体情况,从具有代表性的高级程序设计语言的各类典型单词中,选取一个适当大小的子集。
例如,可以完成无符号常数这一类典型单词的识别后,再完成一个尽可能兼顾到各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。
输入:由符合或不符合所规定的单词类别结构的各类单词组成的源程序。
输出:把单词的字符形式的表示翻译成编译器的内部表示,即确定单词串的输出形式。
例如,所输出的每一单词均按形如(CLASS,VALUE)的二元式编码。
对于变量和常数,CLASS字段为相应的类别码;VALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。
对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。
另外,为便于查看由词法分析程序所输出的单词串,要求在CLASS字段上放置单词类别的助记符。
三、实现方法与环境词法分析是编译程序的第一个处理阶段,可以通过两种途径来构造词法分析程序。
其一是根据对语言中各类单词的某种描述或定义(如BNF),用手工的方式(例如可用C语言)构造词法分析程序。
一般地,可以根据文法或状态转换图构造相应的状态矩阵,该状态矩阵同控制程序便组成了编译器的词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。
构造词法分析程序的另外一种途径是所谓的词法分析程序的自动生成,即首先用正规式对语言中的各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程序所应进行的语义处理工作,然后由一个所谓词法分析程序的构造程序对上述信息进行加工。
编译原理实验二LL(1)语法分析实验报告

专题3_LL(1)语法分析设计原理与实现李若森 13281132 计科1301一、理论传授语法分析的设计方法和实现原理;LL(1) 分析表的构造;LL(1)分析过程;LL(1)分析器的构造。
二、目标任务实验项目实现LL(1)分析中控制程序(表驱动程序);完成以下描述算术表达式的 LL(1)文法的LL(1)分析程序。
G[E]:E→TE’E’→ATE’|εT→FT’T’→MFT’|εF→(E)|iA→+|-M→*|/设计说明终结符号i为用户定义的简单变量,即标识符的定义。
加减乘除即运算符。
设计要求(1)输入串应是词法分析的输出二元式序列,即某算术表达式“专题 1”的输出结果,输出为输入串是否为该文法定义的算术表达式的判断结果;(2)LL(1)分析程序应能发现输入串出错;(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结果。
任务分析重点解决LL(1)表的构造和LL(1)分析器的实现。
三、实现过程实现LL(1)分析器a)将#号放在输入串S的尾部b)S中字符顺序入栈c)反复执行c),任何时候按栈顶Xm和输入ai依据分析表,执行下述三个动作之一。
构造LL(1)分析表构造LL(1)分析表需要得到文法G[E]的FIRST集和FOLLOW集。
构造FIRST(α)构造FOLLOW(A)构造LL(1)分析表算法根据上述算法可得G[E]的LL(1)分析表,如表3-1所示:表3-1 LL(1)分析表主要数据结构pair<int, string>:用pair<int, string>来存储单个二元组。
该对照表由专题1定义。
map<string, int>:存储离散化后的终结符和非终结符。
vector<string>[][]:存储LL(1)分析表函数定义init:void init();功能:初始化LL(1)分析表,关键字及识别码对照表,离散化(非)终结符传入参数:(无)传出参数:(无)返回值:(无)Parse:bool Parse( const vector<PIS> &vec, int &ncol );功能:进行该行的语法分析传入参数:vec:该行二元式序列传出参数:emsg:出错信息epos:出错标识符首字符所在位置返回值:是否成功解析。
实验三编译原理综合实验报告——(LR(0)语法分析的实现)

m_pTree->SetControlInfo(IDC_TREE1, RESIZE_BOTH);
m_pTree->SetControlInfo(IDOK, ANCHORE_BOTTOM | ANCHORE_RIGHT);
void CAnalyzeDlg::OnOK()
{
// TODO: Add extra validation here
//CDialog::OnOK();
}
void CAnalyzeDlg::OnCancel()
{
// TODO: Add extra cleanup here
六、实验原理、数据(程序)记录
(一)实验原理:
利用LR(k)类分析算法的四个步骤,分别实现"移进"、"归约"、"成功"、"报错"的分析能力。同时采用相应的数据结构实现分析表的描述。
(二)程序框架:
#include "stdafx.h"
#include "GoData.h"
GoData::GoData()
assert(j != -1);
out.WriteString(GetStepInfo(iStep, Status, Symbol, m_input.Right(m_input.GetLength() - iPos), ToDo, j));
for(i = 0; i < m_g.GetPrecept(ToDo.two).GetRight().length(); i++)
编译原理课程设计报告C语言词法与语法分析器的实现

编写原理课程设计报告题目:编译原理课程设计C语言词法和语法分析器的实现C-词法和语法分析器的实现1.课程设计目标(1)题目的实用性C语言具有完整语言的基本属性,写C语言的词法分析和语法分析对理解编译原理的相关理论和知识会起到很大的作用。
通过编写C语言词法和语法分析程序,可以对编译原理的相关知识:正则表达式、有限自动机、语法分析等有一个清晰的认识和掌握。
(2)C语言的词法描述①语言的关键词:else if int返回void while的所有关键字都是保留字,必须小写。
②特殊符号:+ - * / < <= > >= == != = ;, ( ) [ ] { } /* */③其他标记是ID和NUM,它们由以下正则表达式定义:ID =字母字母*NUM =数字数字*字母= a|..|z|A|..|Zdigit = 0|..|9注:ID表示标识符,NUM表示数字,letter表示字母,digit表示数字。
小写字母和大写字母是有区别的。
④它由空格、换行符和制表符组成。
空格通常会被忽略。
⑤用常用的C语言符号/*将注释括起来...*/.注释可以放在任何空白位置(也就是注释不能放在标记上),可以多行。
注释不能嵌套。
(3)规划目标能够正确分析程序的词法和语法。
2.分析和设计(1)设计理念a.词汇分析词法分析的实现主要使用有限自动机理论。
有限自动机可以用来描述识别输入字符串中模式的过程,因此也可以用来构造扫描程序。
词法分析器可以很容易地用有限自动机理论来设计。
b.语法分析语法分析采用递归下降分析法。
递归下降法是语法分析中最容易理解的方法。
其主要原理是根据每个非终结符的产生式结构为其构造相应的解析子程序,其中终结符生成匹配命令,非终结符生成过程调用命令。
这种方法被称为递归子例程下降法或递归下降法,因为语法递归的相应子例程也是递归的。
子程序的结构与产生式的结构几乎相同。
(2)程序流程图主程序流程图:词法分析:语法分析:词汇分析子流程图:语法分析子流程图:3.程序代码实现整个词法与语法程序设计在同一个项目中,包含八个文件,分别是main.cpp、parse.cpp、scan.cpp、util.cpp、scan.h、util.h、globals.h和parse.h,其中scan.cpp和scan.h是词法分析程序。
(完整word版)编译原理词法分析程序实现实验报告

(完整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=='.')。
语法分析器设计实验报告

学号《编译原理》实验2:语法分析器设计学生姓名专业、班级指导教师赵璐成绩计算机与信息工程学院2018 年11 月27 日一、实验目的1.理解语法分析程序的功能。
2.熟悉语法分析程序的设计原理和构造方法。
3.掌握递归下降语法分析程序的构造方法。
4.设计一个递归下降的语法分析器,作为实验一构造的词法分析器的下一步编译工具,能语法分析前一步词法分析器输出的单词符号序列。
二、实验要求1.根据书P206给出的简单语言的语法规则,编写C或C++语言源程序,实现针对该简单语言的递归下降的语法分析器;2.独立做实验,输入、调试所编程序;3.实验结束后,根据实验报告模板编写实验报告。
三、实验内容和步骤用Visual C++作为实验开发环境,创建一个Win32 Console Application工程,工程名为你的学号,添加三个文件:(1)存储结构定义:以ParserDef.h和LexerDef.h为文件名;(2)基本操作的算法:以ParserAlgo.h和LexerAlgo.h为文件名;(3)调用基本操作的主程序:以ParserMain.cpp为文件名。
编写程序:(1)文件LexerDef.h和LexerAlgo.h为实验一的内容。
(2)文件ParserDef.h定义语法分析所需的全局变量等。
(3)文件ParserAlgo.h实现对语法规则中各语法成分的分析子算法。
(4)文件ParserMain.cpp实现针对P206简单语言语法规则的递归下降语法分析器。
源程序代码:=============================ParserDef.h================================ int kk;#define _KEY_WORD_END "waiting for your expanding"char * rwtab[]={"begin","if","then","while","do","end",_KEY_WORD_END};char input[255];char token[255]="";int p_input;int p_token;char ch;============================ParserAlgo.h================================ char prog[80];int syn,p,m,n,sum=0;void scaner() {m=0;for(n=0; n<8; n++) token[n]=NULL;ch=prog[p++];while(ch==' ') ch=prog[p++];if((ch>='a' && ch<='z') ||(ch>='A' && ch<='Z')) {while((ch>='a' && ch<='z') ||(ch>='A' && ch<='Z')||(ch>='0' && ch<='9')) {token[m++]=ch;ch=prog[p++];}token[m++]='\0';syn=10;p=p-1; //回退一个字符for(n=0; n<6; n++) {if(strcmp(token,rwtab[n])==0) {syn=n+1;break;}}} else if(ch>='0' && ch<='9') {sum=0;while(ch>='0' && ch<='9') {sum=sum*10+ch-'0';ch=prog[p++];}p=p-1;syn=11;} else {switch(ch) {case '<':m=0;token[m++]=ch;ch=prog[p];if(ch=='>') {syn=21;token[m++]=ch;} else if(ch=='=') {syn=22;token[m++]=ch;} else {syn=20;p=p-1;}p=p+1;token[m]='\0';break;case '>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=24;token[m++]=ch;} else {syn=23;p=p-1;}break;case ':':m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=18;token[m++]=ch;} else {syn=17;p=p-1;}break;case '+':syn=13;token[0]=ch;break;case '-':syn=14;token[0]=ch;break;case '*':syn=15;token[0]=ch;break;case '/':syn=16;token[0]=ch;break;case ';':syn=26;token[0]=ch;break;case '(':syn=27;token[0]=ch;break;case ')':syn=28;token[0]=ch;break;case '=':syn=25;token[0]=ch;break;case '#':syn=0;token[0]=ch;break;default:syn=-1;}}}============================ParserMain.cpp============================== #include<stdio.h>#include<stdlib.h>#include<string.h>#include"LexerDef.h"#include"ParserDef.h"#include"LexerAlgo.h"#include"ParserAlgo.h"void lrparser();void yucu();void statement();void expression();void term();void factor();void lrparser() {if (syn==1) { //beginscaner();yucu();if (syn==6) { //endscaner();if (syn==0 && kk==0) printf("success \n");} else {if(kk!=1) printf("error,lose 'end' ! \n");kk=1;}} else {printf("error,lose 'begin' ! \n");kk=1;}return;}void yucu() {statement();while(syn==26) {scaner();statement();}return;}void statement() {if (syn==10) { //为标识符scaner();if (syn==18) { //为:=scaner();expression();} else {printf("error!");kk=1;}} else {printf("error!");kk=1;}return;}void expression() {term();while(syn==13 || syn==14) {scaner();term();}return;}void term() {factor();while(syn==15 || syn==16) {scaner();factor();}return;}void factor() {if(syn==10 || syn==11)scaner(); //为标识符或整常数时,读下一个单词符号else if(syn==27) {scaner();expression();if(syn==28)scaner();else {printf(" ')' 错误\n");kk=1;}} else {printf("表达式错误\n");kk=1;}return;}void main() {p=0;printf("********************语法分析程序***************\n");printf("请输入源程序:\n");do {scanf("%c",&ch);prog[p++]=ch;} while(ch!='#');p=0;scaner();lrparser();printf("语法分析结束!\n");}四、解答下列问题(1)简述该语法分析器的算法思想。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理实验报告语法分析程序的设计文档编制序号:[KK8UY-LL9IO69-TTO6M3-MTOL89-FTT688]实验5语法分析程序的设计(2)一、实验目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析中算法优先分析方法。
二、实验内容设计一个文法的算法优先分析程序,判断特定表达式的正确性。
三、实验要求1、给出文法如下:G[E]E->T|E+T;T->F|T*F;F->i|(E);+*()i+*()i21)直接存放,2)为优先关系建立优先函数,这里由学生自己选择一种方式;1、给出算符优先分析算法如下:k:=1; S[k]:=‘#’;REPEAT把下一个输入符号读进a中;IF S[k]∈V T THEN j:=k ELSE j:=k-1;WHILE S[j] a DOBEGINREPEATQ:=S[j];IF S[j-1]∈V T THEN j:=j-1 ELSE j:=j-2UNTIL S[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 THENBEGINk:=k+1;S[k]:=aENDELSE ERRORUNTIL a=‘#’1、根据给出算法,利用适当的数据结构实现算符优先分析程序;2、利用算符优先分析程序完成下列功能:1)手工将测试的表达式写入文本文件,每个表达式写一行,用“;”表示结束;2)读入文本文件中的表达式;3)调用实验2中的词法分析程序搜索单词;4)把单词送入算法优先分析程序,判断表达式是否正确(是否是给出文法的语言),若错误,应给出错误信息;5)完成上述功能,有余力的同学可以对正确的表达式计算出结果。
四、实验环境PC微机DOS操作系统或 Windows 操作系统Turbo C 程序集成环境或 Visual C++ 程序集成环境五、实验步骤1、分析文法中终结符号的优先关系;2、存放优先关系或构造优先函数;3、利用算符优先分析的算法编写分析程序;4、写测试程序,包括表达式的读入和结果的输出;5、程序运行效果,测试数据可以参考下列给出的数据。
六、测试数据输入数据:编辑一个文本文文件,在文件中输入如下内正确结果:(1)10;输出:正确(2)1+2;输出:正确(3)(1+2)*3+(5+6*7);输出:正确(4)((1+2)*3+4输出:错误(5)1+2+3+(*4+5)输出:错误(6)(a+b)*(c+d)输出:正确(7)((ab3+de4)**5)+1输出:错误七、实验报告要求实验报告应包括以下几个部分:1、2、算符优先分析程序的算法和结构;程序从文本文件中逐行读取表达式,每行以“;”做标记。
调用词法分析程序将这行数据分析出由一个个的单词组成的表达式,再逐个分析单词。
另外,由于文法中没写入关于标识符和常数的产生式,所以在对单词符号进行语法分析时,会将标识符和常数自动规约为“i”。
数据结构:优先关系表R:二维数组,存储了终结符+、*、(、)、i、#的优先关系。
符号W:结构体,有四个成员,包括:ch:char类型,非终结符与终结符的字符标记;po:int类型,只对终结符有效,与在R中的位置有关,有词法分析器提供;对于非终结符,其po无效;val:string类型,综合属性;对终结符i,其值由词法分析器提供;对非终结符,其值由规约时对应的产生式的规则计算得到;对界符或运算符,val无效;type:int类型,标记属性值类型,0为标识符,不可计算;1为可计算的数值;由词法分析器提供;注意:程序内部数值的计算和标记一律使用十进制,文本中的表达式必须为十进制整数,即如果在文本中使用八进制或十六进制,词法分析器分析后不会添加至缓冲区,在表达式语法正确且其中不含标志符时,计算得到的结果一律使用十进制。
例:对于文本中十进制数字10,其对应的初始结构体成员的值ch=’i’,po=5,val=”10”,type=1。
符号栈S:符号结构体的一维数组。
算法:说明:G[E]E->T|E+T;T->F|T*F;F->i|(E);算符优先文法并未对非终结符定义优先关系,无法对单非产生式进行规约,所以实际上在规约时,上面的E->T,T->F基本没有使用,而且规约时并不严格按照产生式的右部规约,只要待规约项符合句型#N1a1N2a2…NnanNn+1#(每个ai都是终结符,Ni是可有可无的非终结符),并且相对产生式,在相同位置有相同的非终结符即可规约,这样算符优先文法规约很快,但有些语法错误将无法识别,在本实验中,只要在要规约的地方准确的判断可规约的项,即符合句型,在不严格要求非终结符相同而终结符位置符号相同时,存在可匹配文法的产生式,即可规约,例如:F * F 可以匹配T*F继而规约为T。
定义用W[ch]表示字符名为ch的符号;实际程序中关于终结符优先关系的比较是利用R获取优先关系标志的,算法中为了可读性,直接将结构体进行比较了。
从文本文件读入一行数据,反复调用scanP()得到符号集合,用符号结构体数组E存储;k = 1; i = 0; S[k] = W[#];Do {A = E[i++];if(S[k] 是终结符)j = k;elsej = k – 1;while(S[j] > A) {Do {Q = S[j];If(S[j - 1] 是终结符)j = j – 1;elsej = j – 2;}while(S[j] < Q);N = Statute(S,j + 1,k);k = j + 1;S[k] = N;}If(S[j] < A || S[j] == A) {k++;S[k] = A;}else error(S[j].po,;}while(A == W[#]);程序功能说明:程序从文本文件读入表达式,判断语法是否正确,正确则输出结果,其中有标识符的话,结果还是含有标识符的原表达式,语法错误的话,则输出错误信息。
源程序:程序中文本文件在桌面文件名为#include<iostream>#include<string>#include<>using namespace std;#define NULL 0#define MAXSIZE 30 h == 'i' && s == e) {= 'F';= S[s].val;= S[s].type;}else if (S[s].ch == '(' && !(checkVt(S[s + 1].ch)) &&S[e].ch == ')') {if (S[s + 1].type == 1) {= 'F';= S[s + 1].val;= S[s + 1].type;}else {= 'F';= '('+ S[s + 1].val + ')';= S[s + 1].type;}}else if (!(checkVt(S[s].ch)) && S[s + 1].ch == '+'&& !(checkVt(S[e].ch))) {= 'E';if (S[s].type == 1 && S[e].type == 1) {= 1;int v = atoi(S[s].()) + atoi(S[e].());char l[30];sprintf_s(l,30,"%d", v);= l;}else {= 0;= S[s].val + S[s + 1].ch + S[e].val;}}else if ((s != e) && !(checkVt(S[s].ch)) && S[s + 1].ch == '*' && !(checkVt(S[e].ch))) {= 'T';if (S[s].type == 1 && S[e].type == 1) {= 1;int v = atoi(S[s].()) * atoi(S[e].());char l[30];sprintf_s(l, 30,"%d", v);= l;}else {= 0;= S[s].val + S[s + 1].ch + S[e].val;}}else if(S[s].ch == 'T' && s == e){= 'E';= S[s].val;= S[s].type;}else {= '#';}= 4;return N;}void error(char errnum) { h)) o][] == '>') {do {Q = S[j];if (checkVt(S[j - 1].ch))j = j - 1;elsej = j - 2;} while (pre[S[j].po][] != '<');W N = Statute(S, j + 1, k);if == '#') {error('4');return 0;}k = j + 1;S[k] = N;}if (pre[S[j].po][] == '<' || pre[S[j].po][] == '=') { k++;S[k] = A;}else {error(pre[S[j].po][]);return 0;}} while != '#');if == '#') {printf("正确,结果为:%s\n\n", S[k - 1].());return 0;}}int main() {FILE* fp;errno_t err;if ((err =fopen_s(&fp,"C:\\Users\\Administrator\\Desktop\\", "r")) != NULL) { //以只读方式打开文件,失败则退出程序printf("file can not open!");exit(0);}int n = 0;printf("语法分析结果如下:\n\n");while (!feof(fp)) { //若不是文件尾则执行循环int num = 0;W E[MAXSIZE]; //存储一行表达式GetBC(fp);if (!feof(fp)) {n++;fseek(fp, -1L, 1);printf("(%d)", n);}else {break;}while (1) { //只读一行,行末标志为“;”int flag = scan(fp, E,num);if (flag == 0) break;num++;}printf("\n输出:");syntax(E,num);}fclose(fp); //关闭文件fp = NULL; //避免指向非法内存}Pascal的repeat…until与C语言的do…while并一样,实验时不注意会使程序出错,二者的循环条件是相反的。