C++:编译实验之递归下降分析器

article/2025/10/15 2:24:52

一、实验目的

1.加深对递归下降分析法一种自顶向下的语法分析方法的理解。

2.根据文法的产生式规则消除左递归,提取公共左因子构造出相应的递归下降分析器。

二、实验内容

根据课堂讲授的形式化算法,编制程序实现递归下降分析器,能对常见的语句进行分析。

三、实验要求

首先对上下文无关文法进行检查,消除左递归和左公共因子,从逻辑上检测避免死循环和低效率处理。 采用每个产生式的左边的文法符号对应一个函数或过程的形式,编写程序实现一个递归下降分析器。注意这里的语法分析,是在词法分析的基础上进行的。

要求实现以下语法的递归下降分析:

 

示例:

输入语句:

{i=2;while(i<=100){sum=sum+i;i=i+2;}
}

 推导过程:

 

四、算法分析

        语法分析是编译程序的核心功能之一。语法分析的作用是识别有词法分析个哦出的单词符号串是否是给定文法的正确句子。递归下降分析属于自顶向下分析,即从文法的开始符号出发企图推到出与输入的单词符号串完全相匹配的句子。

        这里的语法分析,是在词法分析的基础上进行的。输入示例内容,逐个读入单词,对其进行词法分析。采用每个产生式的左边的文法符号对应一个函数的形式,实现递归下降分析器。将最左推导的过程逐步完整输出,具体实现方式是将上一行的输出存储在一个字符串变量中,每次用产生式的右部替换字符串最左非终结符再输出。递归下降分析法是一种自顶向下的分析方法,文法的每个非终结符对应一个递归过程。分析过程就是从文法开始符出发执行一组递归过程,这样向下推导直到推出句子;或者说从根节点出发,自顶向下为输入串寻找一个最左匹配序列,建立一棵语法树。

代码:

#include<cstdio>
#include<cstring>
#include<ctype.h>
#include<iostream>
using namespace std;
char prog[1000],ch,ch1,token[1000],filename[30];
int p=0,sym=0,n,line=1;
FILE *fpin;
const char *keyword[22]={"if","else","while","do","main","int","float","for""double","return","const","void","continue","break","char","signed","enum","long","switch","case","auto","unsigned"};
char keywordtable[20][20],digittable[20][20],otherchartable[20][20],idtable[20][20],notetable[20][20],finaltable[100][20];                 
//存放保留字、存放数字、其他字符、标识符、注释、终结符 
int finaltableint[100];
char word[20];
void otherchar();
void note();
void program();
void block();
void stmts();
void stmt();
void expr();
void expr1();
void term();
void term1();
void factor();int digit_num=0,keyword_num=0,otherchar_num=0,id_num=0,note_num=0;
int final_num=0,finalnum=0;
int flag_error=0;                                  //0表示没有错误,1表示有错误 
int flagerror=0;void initialize()  //初始化数组word 
{for(int i=0;i<20;i++){word[i]='\0';}
}void error()
{flag_error=1;printf("出现错误,停止分析!\n");
}void alpha()
{int i=0,flag;word[i++]=ch;ch=prog[p++];while(isalpha(ch)||isdigit(ch))    //将标识符放到word数组中 {word[i++]=ch;ch=prog[p++];}	p--;flag=0;for(i=0;i<21;i++)//关键字 {if(strcmp(word,keyword[i])==0){flag=1;break;}}//只实现了部分保留字,可根据要求自行增删if(flag==1){strcpy(keywordtable[keyword_num++],word);strcpy(finaltable[final_num],word);if(strcmp(word,"if")==0)finaltableint[final_num++]=100;if(strcmp(word,"for")==0)finaltableint[final_num++]=200;if(strcmp(word,"else")==0)finaltableint[final_num++]=300;if(strcmp(word,"while")==0)finaltableint[final_num++]=400;if(strcmp(word,"do")==0)finaltableint[final_num++]=500;if(strcmp(word,"float")==0)finaltableint[final_num++]=600;if(strcmp(word,"int")==0)finaltableint[final_num++]=700;if(strcmp(word,"break")==0)finaltableint[final_num++]=800;}else{strcpy(idtable[id_num++],word);  //存放标识符在word数组strcpy(finaltable[final_num],"id");  //与存放id到终结符表 finaltableint[final_num++]=1;}
}void digit()
{int i=0,flag;word[i++]=ch;ch=prog[p++];while(isdigit(ch))    //整数 {word[i++]=ch;ch=prog[p++];}	p--;strcpy(digittable[digit_num++],word);strcpy(finaltable[final_num],"num");//数字数组,序号为99 finaltableint[final_num++]=99;}	void note()
{int i=0;while(1){if(ch=='*'){ch=prog[p++];if(ch=='/')break;else{p--;word[i++]=ch;	}  }else if(ch=='\n'){break;}else{word[i++]=ch;}ch=prog[p++];}strcpy(notetable[note_num++],word);//将注释的内容放入注释表 
}
void otherchar()
{switch(ch){case '!':{ch=prog[p++];if(ch=='='){strcpy(otherchartable[otherchar_num++],"!=");strcpy(finaltable[final_num],"!=");finaltableint[final_num++]=3;}else{p--;error();}}break;case '=':{ch=prog[p++];if(ch=='='){strcpy(otherchartable[otherchar_num++],"==");strcpy(finaltable[final_num],"==");finaltableint[final_num++]=4;}else{strcpy(otherchartable[otherchar_num++],"=");strcpy(finaltable[final_num],"=");finaltableint[final_num++]=5;p--;}}break;case '(':strcpy(otherchartable[otherchar_num++],"(");strcpy(finaltable[final_num],"(");finaltableint[final_num++]=6;break;case ')':strcpy(otherchartable[otherchar_num++],")");strcpy(finaltable[final_num],")");finaltableint[final_num++]=7;break;case ';':strcpy(otherchartable[otherchar_num++],";");strcpy(finaltable[final_num],";");finaltableint[final_num++]=8;break;case '{':strcpy(otherchartable[otherchar_num++],"{");strcpy(finaltable[final_num],"{");finaltableint[final_num++]=9;break;case '}':strcpy(otherchartable[otherchar_num++],"}");strcpy(finaltable[final_num],"}");finaltableint[final_num++]=10;break;case '|':{ch=prog[p++];if(ch=='|'){strcpy(otherchartable[otherchar_num++],"||");strcpy(finaltable[final_num],"||");finaltableint[final_num++]=11;}else{p--;error();}} break;case '&':{ch=prog[p++];if(ch=='&'){strcpy(otherchartable[otherchar_num++],"&&");strcpy(finaltable[final_num],"&&");finaltableint[final_num++]=12;}else{p--;error();}} break;case '+':strcpy(otherchartable[otherchar_num++],"+");strcpy(finaltable[final_num],"+");finaltableint[final_num++]=13;break;case '-':strcpy(otherchartable[otherchar_num++],"-");strcpy(finaltable[final_num],"-");finaltableint[final_num++]=19;break;case '>':{ch=prog[p++];if(ch=='='){strcpy(otherchartable[otherchar_num++],">=");strcpy(finaltable[final_num],">=");finaltableint[final_num++]=14;}else{strcpy(otherchartable[otherchar_num++],">");strcpy(finaltable[final_num],">");finaltableint[final_num++]=15;p--;}}break;case '<':{ch=prog[p++];if(ch=='='){strcpy(otherchartable[otherchar_num++],"<=");strcpy(finaltable[final_num],"<=");finaltableint[final_num++]=16;}else{strcpy(otherchartable[otherchar_num++],"<");strcpy(finaltable[final_num],"<");finaltableint[final_num++]=17;p--;}}break;case '*':strcpy(otherchartable[otherchar_num++],"*");strcpy(finaltable[final_num],"*");finaltableint[final_num++]=18;break;default:error();break;}
}void match(string str)
{char cha[20];//初始化数组cha for(int i=0;i<20;i++){cha[i]='\0';}for(int k=0;k<str.length();k++){cha[k]=str[k];}if(strcmp(finaltable[finalnum],cha)!=0){flagerror=1;return;}finalnum++;
}
void program()
{printf("program-->block\n");block();if(flagerror==1){error();return;}
}
void block()
{if(flagerror==1){return;}printf("block-->{stmts}\n");match("{");stmts();match("}"); 
}
void Bool()
{if(flagerror==1){return;}expr();switch(finaltableint[finalnum]){case 17:printf("bool-->expr < expr\n");match("<");expr();break;case 16:printf("bool-->expr <= expr\n");match("<=");expr();break;case 15:printf("bool-->expr > expr\n");match(">");expr();break;case 14:printf("bool-->expr >= expr\n");match(">=");expr();break;default:printf("bool-->expr\n");expr();break;}
}
void stmts()
{if(flagerror==1){return;}if(finaltableint[finalnum]==10){printf("stmts-->null\n");return;}printf("stmts-->stmt stmts\n");stmt();stmts();
}
void stmt()
{if(flagerror==1){return;}switch(finaltableint[finalnum]){case 1:printf("stmt-->id=expr;\n");match("id");match("=");expr();match(";");break;case 100:match("if");match("(");Bool();match(")");stmt();if(strcmp(finaltable[finalnum],"else")==0){printf("stmt-->if(bool) stmt else stmt\n");match("else");stmt();break;}else{printf("stmt-->if(bool) stmt\n");break;	}case 400:printf("stmt-->while(bool) stmt\n");match("while");match("(");Bool();match(")");stmt();break;case 500:printf("stmt-->do stmt while(bool)\n");match("do");stmt();match("while");match("(");Bool();match(")");break;case 800:printf("stmt-->break\n");match("break");break;default:printf("stmt-->block\n");block();break;}
}void expr()
{if(flagerror==1){return;}printf("expr-->term expr1\n");term();expr1();
}
void expr1()
{if(flagerror==1){return;}switch(finaltableint[finalnum]){case 13:printf("expr1-->+term expr1\n");match("+");term();expr1();break;case 19:printf("expr1-->-term expr1\n");match("-");term();expr1();break;default:printf("expr1-->null\n");return;}
}
void term()
{if(flagerror==1){return;}printf("term-->factor term1\n");factor();term1();
} 
void term1()
{if(flagerror==1){return;}switch(finaltableint[finalnum]){case 18:printf("term1-->*factor term1\n");match("*");factor();term1();break;case 2:printf("term1-->/factor term1\n");match("/");factor();term1();break;default:printf("term1-->null\n");return;}
}
void factor()
{if(flagerror==1){return;}switch(finaltableint[finalnum]){case 6:printf("factor-->(expr)\n");match("(");expr();match(")");break;case 1:printf("factor-->id\n");match("id");break;case 99:printf("factor-->num\n");match("num");break;default:flagerror=1;break;}
}//语法分析部分 
void YufaBegin(){p=0;while(1){	ch=prog[p++];  if(ch=='#') break;            if(isalpha(ch)||ch=='_') //isalpha测试字符是否为英文字母                   //a-z或A-Z时返回非零值(不一定是1),否则返回零 {alpha();             //存入字母表initialize();}else if(isdigit(ch))  //用来判断字符lookahead是否为数字 {digit();          //存入数字表initialize();}else if(ch=='\t'||ch==' '||ch=='\n'){continue;}else if(ch=='/'){ch=prog[p++];if(ch=='*'||ch=='/'){note();              //存入注释表initialize();}else{p--;                          					//把一个字符退回到输入流中//lookahead是写入的字符,stdin是文件流指针 strcpy(finaltable[final_num],"/");                //将"/"放到终结符号表中 strcpy(otherchartable[otherchar_num++],"/");      //将"/"放到其他符号表中 finaltableint[final_num++]=2;                     //"/"的序号是2 initialize();}}else{otherchar();            //其他字符存入otherchar表initialize();}}if(flag_error==0){finaltableint[final_num]='\0';printf("--------------------");printf("\n语法分析过程如下:\n");program();                      //从开始符号program()向下推导if(finalnum==final_num)printf("语法分析完成!");		}
}void GetToken() 
{sym=0;//先把token[]数组清空 for (n=0;n<1000;n++){token[n]='\0';}n=0;ch=prog[p++];ch1=prog[p];//跳过空格,回车,tab的识别 while(ch==' '||ch=='\t'){ch=prog[p++];}if(ch=='\n'){line++;return;}if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch=='_')) {//标识符 状态1sym=1;do{token[n++]=ch;ch=prog[p++];}while ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9'));//比较标识符与keyword的关键字是否相同,若相同转为状态2for(n=0;n<2;n++){if(strcmp(token,keyword[n])==0){sym=2;break;	}}p--;return;}else if (ch>='0'&&ch<='9') {	//识别到数字,置状态为3sym=3;do{	token[n++]=ch;ch=prog[p++];if(ch=='.'){sym=31;token[n++]=ch;ch=prog[p++];}if(ch=='S'){sym=32;ch=prog[p++];} if(ch=='L'){sym=33;ch=prog[p++];}if(ch=='O'){sym=34;ch=prog[p++];}	if(ch=='H'){sym=35;ch=prog[p++];}		}while(ch>='0'&&ch<='9'); p--;return;}//跳过注释的内容 else if(ch=='/' && ch1=='*'){	p++;do{ch=prog[p++];ch1=prog[p++];if(ch=='\n'){line++;}}while(ch!='*'||ch1!='/');return;}else if(ch=='/'&& ch1=='/'){p++;do{ch=prog[p++];}while(ch!='\n');line++;return;}else if(ch=='='&& ch1=='='){p++;sym=4;token[0]='=';token[1]='=';return;}else if(ch=='<'&& ch1=='='){p++;sym=4;token[0]='<';token[1]='=';return;}else if(ch=='>'&& ch1=='='){p++;sym=4;token[0]='>';token[1]='=';return;}else if(ch=='!'&& ch1=='='){p++;sym=4;token[0]='!';token[1]='=';return;}		else if(ch=='&'&& ch1=='&'){p++;sym=4;token[0]='&';token[1]='&';return;}	else if(ch=='|'&& ch1=='|'){p++;sym=4;token[0]='|';token[1]='|';return;}else {switch(ch)//识别关键符号 {	case '=':case '<':case '>':case '/':case '+':case '-':case '*':case '{':case '}':case ';':case '(':case ')':case ',':case '\'':case '\"':sym=4;token[0]=ch;break;default:sym=-1;break;}}return;}//词法分析器部分 
void CifaBegin()
{p=0;do {GetToken();//启动字符识别函数 switch(sym)//打印字符状态 {case 1:cout<<"("<<line<<" "<<token<<" "<<"标识符"<<")"<<endl;break;case 2:cout<<"("<<line<<" "<<token<<" "<<"保留字"<<")"<<endl;break;case 3:cout<<"("<<line<<" "<<token<<" "<<"整型"<<")"<<endl;break;case 31:cout<<"("<<line<<" "<<token<<" "<<"浮点型"<<")"<<endl;break;case 32:cout<<"("<<line<<" "<<token<<"S"<<" "<<"短类型"<<")"<<endl;break;case 33:cout<<"("<<line<<" "<<token<<"L"<<" "<<"长类型"<<")"<<endl;break;case 34:cout<<"("<<line<<" "<<token<<"O"<<" "<<"八进制数"<<")"<<endl;break;case 35:cout<<"("<<line<<" "<<token<<"H"<<" "<<"十六进制数"<<")"<<endl;break;case 4:cout<<"("<<line<<" "<<token<<" "<<"特殊符号"<<")"<<endl;break;case -1:cout<<"("<<line<<" "<<"错误!"<<")"<<endl;break;default:break;}}while(ch!='#');p=0;
}int main()
{cout<<"请输入要分析的语句:";//将文件内容存储到prog中 do{ch=getchar();prog[p++]=ch;}while(ch!='#');//调用词法分析部分 printf("-----------------\n");printf("词法分析结果如下:\n");ch=getchar( );CifaBegin();//调用语法分析部分		initialize();YufaBegin();return 0;
}  

运行结果:


http://chatgpt.dhexx.cn/article/kkD8TDPU.shtml

相关文章

递归下降分析程序的设计和实现

递归下降分析程序的设计和实现 一、实验的目的和要求 1、了解语法分析的主要任务。 2、实现基本的递归下降分析器&#xff0c;能够分析任意的符号串是否为该文法所定义的合法算术表达式。二、实验环境 Windows7 Dev-C三、实验准备 先将递归下降分析程序的生成认真的学习一…

利用递归下降分析方法完成语法分析

一、 程序设计题目与说明 利用递归下降分析方法完成语法分析。 递归下降分析法是一种自顶向下的分析方法&#xff0c;文法的每个非终结符对应一个递归过程&#xff08;函数&#xff09;。分析过程就是从文法开始符出发执行一组递归过程&#xff08;函数&#xff09;&#xff…

编译原理 --- 递归下降分析器

第一部分 --- 构造递归下降分析器 1.在上面这个例子中则是子程序序A先调用子程序B&#xff0c;本程序结束完调用之后再返回来继续调用下一个符号 如果下一个符号是终结符的话那就直接进行匹配&#xff0c;不进行调用&#xff0c;匹配完后继续调用下一个符号 如果不是的话则调…

递归下降分析法实现强化计算器

一. 实验概述 1.使用bison 和 flex 实现扩展版计算器 该计算器支持实型的两种表达,分别是小数和科学计数法. 该计算器支持 加, 减, 乘 除 四种运算 和括号()运算符. 该计算器支持整形,实型混合运算 2.通过递归下降分析法自行编写的语法分析和使用flex进行的词法分析的计算器.…

编译原理研究性学习专题 2——递归下降语法分析设计原理与实现

1 实验内容 完成以下描述赋值语句的 LL(1)文法的递归下降分析程序 G[S]: S→ VE E→ TE’ E’→ ATE’ | e T→ FT’ T’→ MFT’ | E F→ (E) | i A→ | - M→ * | / V→ i 设计说明&#xff1a;终结符号 i 为用户定义的简单变量&#xff0c;即标识符的定义。 2 实验要求 …

Python技法之简单递归下降Parser的实现方法

文章目录 一. 算术运算表达式求值二. 生成表达式树三、左递归和运算符优先级陷阱四. 相关包 一. 算术运算表达式求值 对于简单的算术运算表达式&#xff0c;假定我们已经用分词技术将其转化为输入的tokens流&#xff0c;如NUMNUM*NUM。 在此基础上&#xff0c;我们定义BNF规则…

编译实验 . 递归下降分析器

实验目的&#xff1a; 1.1掌握语法分析方法。 1.2掌握使用算符优先分析法。 1.3完成语法分析程序的设计和实现。 1.4程序能完成对指定语言的语法分析。 2. 递归下降分析器 在不含左递归和每个非终结符的所有候选终结首符集都两两不相交的条件下&#xff0c;我们就可能构造…

用c语言编译递归下降翻译器,Java实现C语言语义分析(递归下降)

说起这次的语义分析&#xff0c;不得不说的是我的重大的改变。上一次的语法分析是利用了预测分析法来实现的&#xff0c;经过多方考证&#xff0c;发现用预测分析法的语法分析器基础来实现语义分析的困难重重&#xff0c;例如在语法指导翻译的时候那个栈的变化和各种属性的传递…

递归下降分析法

介绍&#xff1a; 递归下降分析法是针对LL(1)文法的一种语法分析方法&#xff1b; 通过对文法的消除左递归&#xff0c;提取左公因子&#xff0c;对各个产生式和非终结符求first()和follow()集&#xff0c;通过first()和follow()集构造该文法的预测分析表&#xff0c;当这个预…

编译原理实验-递归下降语法分析

具体代码已放至Github&#xff08;仅供参考&#xff09;&#xff1a; qxpBlog/Compiler_UESTC: 电子科技大学编译原理实验 (github.com) 具体实验过程如下&#xff1a; 一、实验目的、原理、内容及步骤&#xff1a; &#xff08;1&#xff09;目的&#xff1a;通过本实验加深…

编译原理实验--实验二 递归下降法判断算术表达式的正确性--Python实现

目录 一、实验目的和要求 二、实验内容 三、实验环境 四、实验步骤 1、语法分析所依据的文法&#xff1b; 2、给出消除左递归及提取左公因子的文法&#xff1b; 五、测试要求 六、实验步骤 1、语法分析所依据的文法 2、给出消除左递归及提取左公因子的文法&#xff1…

递归下降语法分析

一、实验目的 递归下降语法分析 二、实验题目 三、分析与设计 四、源代码 #include <iostream> #include <fstream> #include <cstring> #include <string> #include <conio.h> #define digit 1 // 1数字 #define op 2 // -*/()# #define Hh …

Java递归下降分析器_递归下降语法分析器

用java语言编写的递归下降语法分析器&#xff0c;是一种适合手写语法编译器的方法&#xff0c;且非常简单。递归下降法对语言所用的文法有一些限制&#xff0c;但递归下降是现阶段主流的语法分析方法&#xff0c;因为它可以由开发人员高度控制&#xff0c;在提供错误信息方面也…

递归下降算法

递归下降算法 算法模型&#xff1a; Term Term Expr ExprExprFactor Factor 单个元素。最小单位。 实现原理&#xff1a; 一个程式进入算法及被看作是一个项&#xff0c;分解成项加表达式的形式&#xff0c;表达式被分解成 表达式加因子的形式&#xff0c;因子是这个算法…

实验二:递归下降语法分析

文章目录 一、实验目的二、实验原理与要求 1、原理 2、要求 三、实验设备四、实验内容五、实验步骤 1. 单词内码表 2. 定义语言文法 3. 语法分析器的实现&#xff08;编码&#xff09; 4. 测试 六、配套资源 一、实验目的 理解自顶向下语法分析的基本模式&#xff0c;熟悉…

编译原理递归下降语法分析器C++实现

编译原理递归下降语法分析器C简单实现 1.递归下降分析法的功能 语法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2.递归下降分析法的前提 改造文法&#xff1a;消除二义性、消除左递归、提取左因子&#xff0c;判断是否为LL&#xff08;1&#xff0…

编译原理(九)——递归下降法

背景&#xff1a; 自定向下的语法分析方法&#xff0c;LL(1)是一种非常直观的方法&#xff0c;它的分析过程是按照句子的定义来进行的&#xff0c;也就是说从开始符出发对要分析的串进行推导&#xff0c;如果推导成功就证明这个被分析的串是一个合法的句子&#xff0c;否则的话…

【编译原理】【C语言】实验三:递归下降分析法

C语言 实验环境&#xff1a;Visual Studio 2019 author&#xff1a;zoxiii 递归下降分析法 1、实验内容2、前期准备2.1 递归下降分析法原理2.2 要实现的文法2.3 需要的函数 3、分析过程3.1 递归下降分析法设计思想及算法3.2 分析栈的分析过程3.3 流程图3.4 源代码3.5 运行结果 …

JAVA游戏开发-超炫酷贪吃蛇游戏源码及教程

一&#xff0e;前言 某日&#xff0c;看见隔壁家的小朋友在玩一款网络爆款贪吃蛇游戏&#xff0c;感觉很好玩。自己刚好正在学习JAVA编程&#xff0c;也想实现一个类似功能的游戏Demo练手&#xff0c;在网上查看了不少源码案例&#xff0c;全都是很古老的方块式贪吃蛇游戏案例…

Java实现贪吃蛇游戏【代码】

Java实现贪吃蛇游戏【代码】 花了两个下午写了一个贪吃蛇小游戏&#xff0c;本人想写这游戏很长时间了。作为以前诺基亚手机上的经典游戏&#xff0c;贪吃蛇和俄罗斯方块一样&#xff0c;都曾经在我们的童年给我们带来了很多乐趣。世间万物斗转星移&#xff0c;诺基亚曾经作为手…