编译原理------语法分析器C/C++代码实现

2023-11-05

一、实验目的

编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。

二、实验内容

利用C语言编制递归下降分析程序,并对简单语言进行语法分析。

2.1 待分析的简单语言的语法

用扩充的BNF表示如下:

⑴<程序>::=begin<语句串>end

⑵<语句串>::=<语句>{;<语句>}

⑶<语句>::=<赋值语句>

⑷<赋值语句>::=ID:=<表达式>

⑸<表达式>::=<项>{+<项> | -<项>}

⑹<项>::=<因子>{*<因子> | /<因子>}

⑺<因子>::=ID | NUM | (<表达式>)

2.2 实验要求说明

输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。

例如:

    输入  begin a:=9; x:=2*3; b:=a+x end #

    输出  success!

    输入  x:=a+b*c end #

    输出  error!

 

 

代码如下:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
//定义几个全局变量 
int syn;
char s[1000];
int p=0;
int k=0;// 定义 k 作为一个标记符,记录是否出错,若 k=0 ,则说明没有出错,否则发生错误 
char key[6][20] = {"begin","if","then","while","do","end"};//定义一个二维数组存放关键字 
char token[20];	//存放字符(单词) 
void expression();
//判断关键字 
int isKey(char s[])
{
	for(int i = 0; i < 6;i++)
	{
		if(strcmp(s,key[i]) == 0)
		{
			return i+1;	//关键字的种别码依次为 begin=1,if=2,then=3,while=4,do=5,end=6即为 i+1 的值 
		}
	}
	return -1;
}
//判断是不是字母 
bool isChar(char ch)
{
	if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
	return true;
	else
	return false;
}
//判断是不是数字 
bool isNum(char ch)
{
	if(ch>='0' && ch<='9')
	return true;
	else
	return false;
}
//词法分析器 
void scanner()
{
	int count = 0;
	if(s[p] == ' ') p++;
	//开头是字母
	if(isChar(s[p]))
	{
		while(isNum(s[p]) || isChar(s[p]))
		{
			token[count++] = s[p];
			p++;
		}
		token[count] = '\0';	//'\0'作为结束符 ,将单词分隔开 
		syn = isKey(token);
		if(syn == -1)	
		{
			syn = 10;	//标识符letter(letter|digit) *
		}
	}
	
	//开头是数字
	else if(isNum(s[p]))
	{
		while(isNum(s[p]))
		{
			token[count++] = s[p];
			p++;
		}
		token[count] = '\0';//结束标识 
		syn = 11;	//数字digit(digit) *
	}
	
	//如果是运算符或者界符
	else
	{
		//先处理没有争议的字符 
		switch(s[p])
		{
			case '+': syn = 13;token[0] = s[p];token[1]='\0';break;
			case '-': syn = 14;token[0] = s[p];token[1]='\0';break;
			case '*': syn = 15;token[0] = s[p];token[1]='\0';break;
			case '/': syn = 16;token[0] = s[p];token[1]='\0';break;
			case '=': syn = 25;token[0] = s[p];token[1]='\0';break;
			case ';': syn = 26;token[0] = s[p];token[1]='\0';break;
			case '(': syn = 27;token[0] = s[p];token[1]='\0';break;
			case ')': syn = 28;token[0] = s[p];token[1]='\0';break;
			case '#': syn = 0 ;token[0] = s[p];token[1]='\0';break;
		}
		
		
		//处理有争议的
		//: :=
		if(s[p] == ':')
		{
			token[count++] = s[p];
			if(s[p+1] == '=')
			{
				p++;
				token[count++] = s[p];
				syn = 18;
			}
			else
			{
				syn = 17;
			}
			token[count] = '\0';
		}
		
		//< <> <=
		if(s[p] == '<')
		{
			token[count++] = s[p];
			if(s[p+1] == '>')
			{
				p++;
				token[count++] = s[p];
				syn = 21;
			}
			else if(s[p+1] == '=')
			{
				p++;
				token[count++] = s[p];
				syn = 22;
			}
			else
			{
				syn = 20;
			}
			token[count] = '\0';
		}
		
		//> >=
		if(s[p] == '>')
		{
			token[count++] = s[p];
			if(s[p+1] == '=')
			{
				p++;
				token[count++] = s[p];
				syn = 24;
			}
			else
			{
				syn = 23;
			}
			token[count] = '\0';
		}
		
		//后移 
		p++;	//判断运算符和界符的这部分由于指针 p 没有向后指,所以需要将指针 p 向后移一位 
	}
	 
} 

以下各函数均要先调用 scanner()函数,用于首先产生 syn 的值 
//因子-->项-->表达式-->赋值语句-->语句-->程序
//由小到大逐层封装函数 
void factor()	//因子 :<因子> :=ID | NUM | (<表达式>) 
{
	if(syn==10||syn==11)	//当扫描的是数字或者字母时,继续扫描
	{
		scanner();
	} 
	else if(syn==27)	//当扫描到 '('时,后面应该为一个表达式,继续扫描
	{
		scanner();
		expression();
		if(syn==28)		//当扫描的是 ')'时,继续扫描
			scanner();
		else
		{
			k=1;	//出错 
			cout<<"ERROR!缺少')'"<<endl;	//表达式缺 ')',出错 
		}
	} 
	else
	{
		k=1;
		cout<<"ERROR!运算符号后面不是常数或'('或标识符"<<endl;	//扫描表达式 ,表达式不是以 '('开头 
	}
} 

void term()//项 : <项> :=<因子>{*<因子> | /<因子> } 
{
	factor();
	while(syn==15||syn==16)	//当开头扫描的是 '*' 或者 '/'时('*'或者'/'后面是因子),继续扫描
	{
		scanner();
		factor();
	} 
} 

void expression()//表达式 : <表达式> :=<项>{+<项> | -<项>}
{
	term();
	while(syn==13||syn==14)	//当开头扫描的是 '+' 或者 '-'时('+'或者'-'后面是项),继续扫描
	{
		scanner();
		term();
	}
} 

void statement()//赋值语句 : ID = <表达式>
{
	if(syn==10)	//当开头扫描的是字母时,继续扫描
	{
		scanner();
		if(syn==18)		//扫描的是 ':='时,继续扫描
		{
			scanner();
			expression();
		} 
		else
		{
			k=1;
			cout<<"ERROR!缺少 ':=' "<<endl;
		 } 
	 } 
	else
	{
		k=1; 
		cout<<"ERROR!开头不是标识符!"<<endl;
	}
 } 
 
void sens()//语句串 :<语句串>:=<语句>{;<语句>}
{
	statement();
	while(syn==26)	//当开始扫描的是 ';'时,继续扫描
	{
		scanner();
		statement();
	 } 
} 

//程序 : <程序> :=begin<语句串>end
void lrparser() 
{
	if(syn==1)	//当开头扫描的是 'begin'时,继续扫描
	{
		scanner() ;
		sens();
		if(syn==6) //扫描到 'end'时,继续扫描 
		{
			scanner();
			if(syn==0&&k==0)	//当数字串最后扫描的是 '#',而且无出错,分析成功
				cout<<"success!" <<endl;
			else if(syn!=0||k==1)
				cout<<"error!"<<endl;
		} 
		else
		{
			cout<<"ERROR!没有 'end'"<<endl;
		}
 	}
 	else
 	{
 		cout<<"ERROR!没有 'begin'"<<endl;
	}
}
int main()
{
	char ch;
	while(true)
	{
		cout<<"Please input a string:  "<<endl;
		cin.getline(s,1000);//getline()函数可以滤去空格 
		p=0;
		scanner();
		lrparser();
	}
	return 0; 
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编译原理------语法分析器C/C++代码实现 的相关文章

  • 深入浅出编译原理-5-一个简单语法分析器的C语言实现

    引言 前面已经介绍了编译器的预处理 词法分析 词法分析器的实现 也在其中说到了语法分析的任务和过程 语法分析的输入是词法单元序列 然后根据语言的文法表示 展开式 利用有限状态机理论 生成抽象语法树 然后遍历得到中间代码 即 三地址码 本节就
  • 静态单赋值(二)—gcc中的SSA化算法

    版权声明 本文为CSDN博主 ashimida 的原创文章 遵循CC 4 0 BY SA版权协议 转载请附上原文出处链接及本声明 原文链接 https blog csdn net lidan113lidan article details
  • 编译原理实验 实验二 LL(1)分析法 Python实现

    1 实验目的 通过完成预测分析法的语法分析程序 了解预测分析法和递归子程序法的区别和联系 使学生了解语法分析的功能 掌握语法分析程序设计的原理和构造方法 训练学生掌握开发应用程序的基本方法 有利于提高学生的专业素质 为培养适应社会多方面需要
  • 【编译原理】【C语言】实验三:递归下降分析法

    C语言 实验环境 Visual Studio 2019 author zoxiii 递归下降分析法 1 实验内容 2 前期准备 2 1 递归下降分析法原理 2 2 要实现的文法 2 3 需要的函数 3 分析过程 3 1 递归下降分析法设计思
  • LLVM里的寄存器分配 - 线性扫描算法(二)

    1 背景介绍 在上一篇博文 LLVM 里的寄存器分配 准备工作 一 里 我主要整理了 LLVM 在做寄存器分配前所做的准备工作 介绍了 LLVM 是在怎样的 MIR 上做的寄存器分配 接下来 就需要讲讲 LLVM 是如何做寄存器分配了 虽然
  • 编译原理------语法分析器C/C++代码实现

    一 实验目的 编制一个递归下降分析程序 实现对词法分析程序所提供的单词序列的语法检查和结构分析 二 实验内容 利用C语言编制递归下降分析程序 并对简单语言进行语法分析 2 1 待分析的简单语言的语法 用扩充的BNF表示如下 lt 程序 gt
  • 初识 flex & bison

    基本概念 flex 和 bison 经常结合使用 分别用于词法分析和语法分析 词法分析器 flex flex 用于生成词法分析器或者说是扫描器 scanner 它将输入的文本分解为称为 tokens 的序列 每个 token 都有一个特定的
  • cucu: a compiler u can understand (part 2)

    原文地址 http blog csdn net roger wong article details 8502477 原文地址 http zserge com blog cucu part2 html 到目前为止 我们已经定义了我们语言的语
  • LLVM IR / LLVM指令集入门

    本文基于LLVM 12官方文档的LLVM Language Reference Manual 以学习笔记为主 所以本文会摘录一些常见 常用的指令 对于一些更加深层次的指令属性 特性 待我对LLVM有更深的理解再单独写文章记录 1 LLVM
  • LLVM里的寄存器分配 - 准备工作(一)

    1 背景介绍 本文档是基于 LLVM 的寄存器分配系列科研笔记第一篇 以一个 C 语言程序为主干介绍 LLVM 在寄存器分配前做的一些主要工作 分析在寄存器分配前期可能的写操作来源 并记录了我在研究 LLVM 后端中 SSA 形式的中间表示
  • 简单的递归下降语法分析程序

    简单递归分析程序 其代码如下 include
  • [学习flex] 1.利用flex实现文字和谐小程序

    灵感来自于09平台dota1 游戏选手对喷时经常互飙国粹 问候对方全家 后来09平台进行了聊天和谐 不和谐的文字都会被 替换 今天我就就用flex实现类似的效果 话不多说上flex代码 脏话 printf 国粹 printf printf
  • 【编译原理】LALR(1)语法分析方法(c++实现)

    前文回顾 编译原理 LR 0 分析方法 c 实现 编译原理 SLR 1 分析方法 c 实现 编译原理 LR 1 分析方法 c 实现 这几个程序的代码大部分是一样的 根据不同算法特点做了部分修改而已 代码 LALR 1 的代码就是在LR 1
  • 编译原理实验二:Bison

    编译原理实验二 Bison 实验要求 1 了解Bision基础知识 如何将文法产生式转换为Bison语句 2 阅读 src common SyntaxTree c 对应头文件 include SyntaxTree h 理解分析树生成的过程
  • 程序语言翻译器的设计与实现----算术表达式转换四元式(编译原理)

    此篇博客是将前面的内容进行整合并进一步提升 真正实现一个简单表达式语法的编译器 如果有不了解的地方请查看下面链接 词法分析 LR 1 分析 一 LR 1 分析 二 这里说的程序语言编译器是指将算术表达式部分进行翻译 暂时不包括优化以及目标语
  • 【编译原理】LR(0)分析方法(c++实现)

    基本流程 Created with Rapha l 2 2 0 输入文法 拓广文法 求项目集规范族 GO I a 转移函数 构造DF
  • 编译原理-总概

    语言执行过程 代码 解释器编译器 机器代码 cpu执行 编译型语言 在程序在执行之前需要一个专门的编译过程 通过编译器把程序编译成为可执行文件 再由机器运行这个文件 运行时不需要重新翻译 直接使用编译的结果就行了 解释型语言 是一边执行一边
  • 递归下降算法语法分析c语言

    递归下降算法 自上而下文法的递归下降的预测分析 从根节点出发逐步构造分析树 所以被称作自上而下文法 在文法中有递归的函数 例如 E gt TE 所以叫做递归下降算法 使用的文法如下 E gt TE E gt TE e T gt FT T g
  • Compiler- volatile关键字

    为了直观的感受编译器为程序所做的编译优化 我们通过以下的C 程序来进行演示 只能体现编译优化的一小部分hh 请大家预测一下下面代码的输出结果 include
  • 【编译原理】 CS143 斯坦福大学公开课 第一周:简介

    youtube 1 1 Introduction to Compilers and interpreters 1 1 Introduction to Compilers and interpreters 编译器解释器介绍 两种主要的实现编程

随机推荐

  • Qt 连接、操作数据库(增删改查)

    文章目录 Qt 5 9连接MySQL5 7 32 64位 操作数据库 QSqlQuery类 执行SQL语句 查 浏览结果集方法 增 删 改 事务 Qt 5 9连接MySQL5 7 32 64位 MySQL5 7安装好后将其安装路径lib下
  • Django--ORM 多表查询

    目录 数据准备 正向查询与反向查询 基于对象的跨表查询 正向查询 一对多 多对多 一对一 反向查询 一对多 多对多 一对一 正向查询 反向查询 基于双下线的跨表查询 正向查询 一对一 一对多 多对多 反向查询 一对一 一对多 多对多 双下高
  • Pytorch—模型微调(fine-tune)

    随着深度学习的发展 在大模型的训练上都是在一些较大数据集上进行训练的 比如Imagenet 1k Imagenet 11k 甚至是ImageNet 21k等 但我们在实际应用中 我们自己的数据集可能比较小 只有几千张照片 这时从头训练具有几
  • fatal error: ceres/ceres.h: 没有那个文件或目录

    用ubuntu18跑的loam livox算法 系统报错 In file included from home lisheng catkin ws src loam livox master source laser mapping cpp
  • java面试---IO与NIO

    一 概念 NIO即New IO 这个库是在JDK1 4中才引入的 NIO和IO有相同的作用和目的 但实现方式不同 NIO主要用到的是块 所以NIO的效率要比IO高很多 在Java API中提供了两套NIO 一套是针对标准输入输出NIO 另一
  • springboot+mybatis配置多数据源实战

    1 背景说明 2 配置多数据源步骤 2 1 项目结构变更 2 2 添加配置类 2 3 修改配置文件数据连接配置信息 2 4 多数据源配置导致 Transactional失效问题 1 背景说明 一般一个项目中只会连接一个数据库 但是随着需求变
  • 后端配置(宝塔):处理php禁用函数

    一 找到php的文件路径 在软件商店中 找到已安装文件 选择需要更改的php文件 选择 设置 二 选择需要取消禁用的文件进行删除 扩展 可解决 The Process class relies on proc open which is n
  • vue常用指令和用法

    文章目录 1 v text 2 v html 3 v on 4 v show 5 v if 6 v bind 7 v for 8 v model 1 v text 设置标签的文本值内容 默然写法会替换全部内容 使用插值表达式 可以替换指定内
  • 题解:按钮加减计数器设计(单片机C51)(外部中断)

    需求 使用4位共阴极段码表及共阳极数码管 通过外部中断方式 实现两个按钮分配加1 减1功能 今天我就来讲解一下这道题 目录 1 代码 1 1定义头文件 1 2定义延时函数 毫秒 1 3定义主函数 1 4定义0 15共阴极数码管字符码 1 5
  • Linux 操作系统管理命令(全)

    目录 1 Linux常用命令 1 date 2 pwd命令 3 cd命令 4 cal命令 5 who命令 6 wc命令 7 uname命令 8 clear命令 9 logout命令 10 shutdown命令 2 命令高级操作 1 命令补全
  • VQ-VAE-2

    原文链接 Generating Diverse High Fidelity Images with VQ VAE 2 加载速度慢点这里 中科院镜像 由于科研需要 最近在学习图像生成相关的文献知识 VQ VAE 2是我目前了解到的比较新的生成
  • PMD检查java代码:为了提升性能,正确使用记录日志的语句(GuardLogStatement)

    https docs pmd code org pmd doc 6 55 0 pmd rules java bestpractices html guardlogstatement 对应记录日志的语句 要首先检查对应的日志级别有没有实际打开
  • Windows下VS2015编译caffe(CPU ONLY)

    本文参照了 Windows下VS2015编译caffe 零基础 1 环境 Windows 7VS2015 CPU ONLY 2 准备工作 原文说 https github com BVLC caffe tree windows Requir
  • linux验证cuda安装成功_CUDA9.1在Linux系统下runfile方式安装手册

    一 准备工作 确认是CUDA9 1 支持的Linux系统版本 3 确认gcc已安装 输入gcc version命令 如果有报错信息 需要重新安装gcc 4 确认安装了正确版本的kernel devel和kernel headers unam
  • 利用三轴加速度求解位移的算法—来自飞思卡尔方案

    在要求精度不高的情况 可以使用三轴加速度积分得到位移 飞思卡尔给出了官方方法 下文来自翻译说明 cache freescale com files senso 摘要 此文档描述并使用MMA7260QT三轴加速计和低功耗的9S08QG8八位单
  • Qt在connect中使用lambda表达式(最简单)

    若想在QT中使用lambda表达式需要在项目文件中的 pro 中加入 CONFIG c 11 例子 当点击按钮时 打印一个 输出 需要包含按钮类和打印调试类 include
  • ROS-Qt-转CMake编译以及qmake第三方库添加及其他

    Qt 开发ROS 界面的方法 方法2 带ui的工作空间配置 以ROS节点执行 步骤1 mkdir catkin qt cd catkin qt mkdir src cd src catkin init workpasce cd catkin
  • volatile足以保证数据同步吗

    在讨论之前必须先搞清四种存储介质 寄存器 高级缓存 RAM和ROM RAM与ROM大家都比较熟悉了 可以看成是我们经常说的内存与硬盘 寄存器属于处理器里面的一部分 而高级缓存cache是CPU设计者为提高性能引入的一个缓存 也可以说是属于处
  • axios post方式同时传递pram和json参数

    废话不多说 直接上代码 1 单独传递表单参数 后台使用 RequestParam接收 let postData mobile this account password this password loginType 0 let postD
  • 编译原理------语法分析器C/C++代码实现

    一 实验目的 编制一个递归下降分析程序 实现对词法分析程序所提供的单词序列的语法检查和结构分析 二 实验内容 利用C语言编制递归下降分析程序 并对简单语言进行语法分析 2 1 待分析的简单语言的语法 用扩充的BNF表示如下 lt 程序 gt