编译原理-语法分析(实验 C语言)

news2024/11/25 11:02:08

语法分析

1. 实验目的

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

2. 实验要求

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

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

用扩充的BNF表示如下:

  1. <程序> ::= begin<语句串> end
  2. <语句串> ::= <语句> {;<语句>}
  3. <语句> ::= <赋值语句>
  4. <赋值表达式> ::= ID := <表达式>
  5. <表达式> ::= <项> { + <项> | - <项> }
  6. <项> ::= <因子> { * <因子> | / <因子>}
  7. <因子> ::= ID | NUM | (<表达式>)

2.2 实验要求说明

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

例如:
输入 begin a := 9; x := 2 * 3; b := a + x end #
输出 success
输入 x := a + b * c end #
输出 error

3. 语法分析程序的算法思想

  1. 主程序示意图如图
    在这里插入图片描述

  2. 递归下降分析程序示意图如图
    在这里插入图片描述

  3. 语句串分析过程示意图如图
    在这里插入图片描述

  4. statement语句分析函数流程如图
    statement语句分析函数示意图
    在这里插入图片描述

    expression表达式分析函数示意图
    在这里插入图片描述

    term分析函数示意图
    在这里插入图片描述

    factor分析过程示意图
    在这里插入图片描述

4. 实验源代码

源代码:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _KEY_WORD_END "waiting for your expanding"

//结构体
typedef struct
{
	int typenum;
	char *word;
}WORD;

//函数声明
char m_getch();
void getbc();
void concat();
int letter();
int digit();
int reserve();
void retract();
char *dtb();
WORD *scaner();
void lrparser(WORD *word);
WORD *yucu(WORD *word);
WORD *factor(WORD *word);
WORD *statement(WORD *word);
WORD *expression(WORD *word);
WORD *term(WORD *word);

char input[255];
char token[255] = "";
int p_input;
int p_token;
char ch;
int kk = 0;
char *rwtab[] = {"begin","if","then","while","do","end",_KEY_WORD_END};


int main(void)
{
	int over = 1;
	WORD *oneword = new WORD;//new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>
	while(1)  //无限循环
	{
		printf("Enter Your words(end with #):");
		scanf("%[^#]",input); //读入源程序字符串到缓冲区,以#结束,允许多行输入
		p_input = 0;
		printf("Your words: \n%s\n",input);
		oneword = scaner();
		lrparser(oneword);
		while(getchar() != '\n'){
		}
		printf("press # to exit:");
		if(getchar() == 35){
			return 0;
		}
		while(getchar() != '\n'){
		}
	}
}

// 词法分析
// 从输入缓冲区读取一个字符到ch中
char m_getch()
{
    ch = input[p_input];
    p_input = p_input + 1;
    return(ch);
}

// 去掉空白符号
void getbc()
{
    while(ch == ' ' || ch == 10)
    {
        ch = input[p_input];
        p_input = p_input + 1;
    }
}

//拼写单词
void concat()
{
    token[p_token] = ch;
    p_token = p_token + 1;
    token[p_token] = '\0';
}

//判断是否字母
int letter()
{
    if(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
        return 1;
    else 
        return 0;
}

//判断是否数字
int digit()
{
    if(ch >= '0' && ch <= '9')
        return 1;
    else 
        return 0;
}

// 检索关键字表格
int reserve()
{
    int i = 0;
    while(strcmp(rwtab[i],_KEY_WORD_END))
    {
        if(!strcmp(rwtab[i],token))
        {
            return i + 1;
        }
        i = i + 1;
    }
    return 10;
}

//回退一个字符
void retract()
{
	p_input = p_input - 1;
}

//数字转换成二进制
char *dtb(char *buffer)
{
	int j = 0;
	int flag = 0;
	int k = (sizeof(char)<<3) - 1;
	
	char temp = ch - '0';
	for(int i = 0; i < (sizeof(char)<<3); i++,k--){
		if((temp >> k & 0x01) == 0){
			if(flag == 1){
				buffer[j++] = 0 + '0';
			}	
		}
		else{
			flag = 1;
			buffer[j++] = (temp >> k & 0x01) + '0';
		}
	}
	buffer[j] = 0;
	return buffer;
	
   // Converts the ch to binary;
}


WORD *scaner()
{
	WORD *myword = (WORD *)malloc(sizeof(WORD));
	myword -> typenum = 10;
	myword -> word = "";
	p_token = 0;
	m_getch();
	getbc();
	if(letter())
	{
		while(letter() || digit())
		{
			concat();
			m_getch();
		}
		retract();
		myword -> typenum = reserve();
		myword -> word = token;
		return myword;
	}
	else if(digit())
	{
		while(digit())
		{
			concat();
			m_getch();
		}
		retract();
		myword -> typenum = 11;
		myword -> word = token;
		return myword;
	}
	else
	{
		switch(ch)
		{
			case'=':
				m_getch();
				if(ch == '=')
				{
					myword -> typenum = 39;
					myword -> word = "==";
					return myword;
				}
				retract();
				myword->typenum = 25;
				myword->word = "=";
				return myword;
				break;
			case'+':
				myword->typenum = 13;
				myword->word = "+";
				return myword;
				break;
			case'-':
				myword->typenum = 14;
				myword->word = "-";
				return myword;
				break;
			case'*':
				myword->typenum = 15;
				myword->word = "*";
				return myword;
				break;
			case'/':
				myword->typenum = 16;
				myword->word = "/";
				return myword;
				break;
			case'(':
				myword->typenum = 27;
				myword->word = "(";
				return myword;
				break;
			case')':
				myword->typenum = 28;
				myword->word = ")";
				return myword;
				break;
			case'[':
				myword->typenum = 28;
				myword->word = "[";
				return myword;
				break;
			case']':
				myword->typenum = 29;
				myword->word = "]";
				return myword;
				break;
			case'{':
				myword->typenum = 30;
				myword->word = "{";
				return myword;
				break;
			case'}':
				myword->typenum = 31;
				myword->word = "}";
				return myword;
				break;
			case',':
				myword->typenum = 32;
				myword->word = ",";
				return myword;
				break;
			case':':
				m_getch();
				if(ch == '=')
				{
					myword->typenum = 18;
					myword->word = ":=";
					return myword;
				}
				retract();
				myword->typenum = 17;
				myword->word = ":";
				return myword;
				break;
			case';':
				myword->typenum = 26;
				myword->word = ";";
				return myword;
				break;
			case'>':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 24;
					myword->word = ">=";
					return myword;
				}
				retract();
				myword->typenum = 23;
				myword->word = ">";
				return myword;
				break;
			case'<':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 22;
					myword->word = "<=";
					return myword;
				}else if(ch == '>')
				{
					myword->typenum = 21;
					myword->word = "<>";
				}
				retract();
				myword->typenum = 20;
				myword->word = "<";
				return myword;
				break;
			case'!':
				m_getch();
				if(ch=='=')
				{
					myword->typenum = 40;
					myword->word = "!=";
					return myword;
				}
				retract();
				myword->typenum = -1;
				myword->word = "ERROR";
				return myword;
				break;
			case'\0':
				myword->typenum = 1000;
				myword->word = "OVER";
				return myword;
				break;
			default:
				myword->typenum = 0;
				myword->word = "#";
				return myword;
		}
	}
}


// 语法分析 判断begin和end
void lrparser(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return;
	}
	if(word -> typenum == 1) //种别码为1,有关键字begin
	{  
		free(word); //释放空间
		w = scaner();
		w = yucu(w);
		if(w == NULL)
		{
			return ;
		}
		if(w -> typenum == 6)  //种别码为6,有关键字end
		{
			free(w);
			w = scaner();
			if(w -> typenum==0&&kk==0)
				free(w);
				printf("success  成功\n");
		}
		else
		{
			free(w);
			if(kk!=1)
				printf("lack END error!  错误 缺少END\n"); //缺少end
			kk = 1;
		}
	}
	else
	{
		free(word);
		printf("Begin error!  begin 错误\n");//无begin报错
		kk = 1;
	}
	return ;
}

//语句以;号结尾
WORD *yucu(WORD *word)
{
	WORD *w;
	w = statement(word); //语句段分析
	if(w == NULL)
	{
		return NULL;
	}
	while(w->typenum == 26) //有;号
	{
		free(w);
		w = scaner();
		w = statement(w);
		if(w == NULL)
		{
			return NULL;
		}
	}
	return w;
}

//语句段分析
WORD *statement(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return NULL;
	}
	if(word->typenum == 10) //字符串
	{ 
		free(word);
		w = scaner();
		if(w->typenum == 18) //赋值符号
		{ 
			free(w);
			w = scaner();
			w = expression(w); //表达式
			if(w == NULL)
			{
				return NULL;
			}
			return w;
		}
		else
		{
			free(w);
			printf("assignment token error! 赋值号错误\n");
			return NULL;
			kk = 1;
		}
	}
	else
	{
		free(word);
		printf("statement error! 语句错误\n");
		return NULL;
	}
}

//表达式处理
WORD *expression(WORD *word)
{
	WORD *w;
	w = term(word);
	if(w == NULL)
	{
		return NULL;
	}
	// +-法
	while(w -> typenum == 13 || w -> typenum == 14)
	{
		free(w);
		w = scaner();
		w = term(w);
		if(w == NULL){
			return NULL;
		}
	}
	return w;
}


WORD *term(WORD *word)
{
	WORD *w;
	w = factor(word);
	if(w == NULL)
	{
		return NULL;
	}
	// */法
	while(w -> typenum == 15 || w -> typenum == 16)
	{
		free(w);
		w = scaner();
		w = factor(w);
		if(w == NULL)
		{
			return NULL;
		}
	}
	return w;
}

//括号分析
WORD *factor(WORD *word)
{
	WORD *w;
	if(word == NULL)
	{
		return NULL;
	}
	if(word -> typenum == 10 || word -> typenum == 11)
	{
		free(word);
		w = scaner();
	}
	else if(word -> typenum == 27)
	{
		free(word);
		w = scaner();
		w = expression(w);
		if(w == NULL)
		{
			return NULL;
		}
		if(w -> typenum == 28)
		{
			free(w);
			w = scaner();
		}
		else{
			free(w);
			printf(") error!  ')' 错误\n");
			kk = 1;
			return NULL;
		}
	}
	else
	{
		free(word);
		printf("expression error!  表达式错误\n");
		kk = 1;
		return NULL;
	}
	return w;
}


5. 实验结果

  1. 输入正确语法

在这里插入图片描述

  1. 输入任意字符后继续输入无begin语法

在这里插入图片描述

  1. 输入赋值号错误的语法

在这里插入图片描述

6. 实验小结

  1. 将main函数中的输入输出语句放入无限循环中,使其不断调用,直至键盘输入#号

    int main(void)
    {
    	int over = 1;
    	WORD *oneword = new WORD;//new为c++中的关键字 在使用new进行内存分配时,需要包含相关类型的头文件。#include <iostream>
    	while(1)  //无限循环
    	{
    		printf("Enter Your words(end with #):");
    		scanf("%[^#]",input); //读入源程序字符串到缓冲区,以#结束,允许多行输入
    		p_input = 0;
    		printf("Your words: \n%s\n",input);
    		oneword = scaner();
    		lrparser(oneword);
    		while(getchar() != '\n'){
    		}
    		printf("press # to exit:");
    		if(getchar() == 35){
    			return 0;
    		}
    		while(getchar() != '\n'){
    		}
    	}
    }
    
  2. 使用原先词法分析中所写的代码,语法分析时在词法分析通过的前提下进行的

  3. 对代码进行语法检测需判断begin和end这两个开始和结束符

  4. 判断每个语句段是以;号结尾

  5. 判断语句段中的字符串,赋值符,表达式是否正确

  6. 判断 + - * / 是否正确

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1803745.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯元宝APP上线,AIGC产品的未来何去何从?

目录 腾讯元宝APP上线&#xff0c;AIGC产品的未来何去何从&#xff1f; 一、大模型AIGC产品概览 二、使用体验分享 1. 百度大脑 2. 阿里巴巴的AliMe 3. 字节跳动的TikTok AI 4. 腾讯元宝APP 小结 三、独特优势和倾向选择 1. 字节豆包 2. 百度文心一言 3. 阿里通义千…

[stm32]——uc/OS-III多任务程序

目录 一、获取uC/OS-III源码 二、移植源代码 &#xff08;1&#xff09;建立工程文件 &#xff08;2&#xff09;移植uC/OS-III源码 &#xff08;3&#xff09;添加工程组件和头文件路径 &#xff08;4&#xff09;添加头文件路径 三、修改代码 总结 一、获取uC/OS-III源码 …

大龄职场人的春招机遇:技术岗位主导,高薪与挑战并存

随着6月毕业季的临近&#xff0c;大批年轻人即将涌入人才市场&#xff0c;为职场注入新鲜血液。然而&#xff0c;这也意味着一些职场人可能面临被“优化”的风险。近几年&#xff0c;职场环境呈现出明显的年轻化趋势&#xff0c;企业更倾向于招聘具有创新活力的青年人才&#x…

170.二叉树:平衡二叉树(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr, right(nullptr) {}* Tree…

React + SpringBoot实现图片预览和视频在线播放,其中视频实现切片保存和分段播放

图片预览和视频在线播放 需求描述 实现播放视频的需求时&#xff0c;往往是前端直接加载一个mp4文件&#xff0c;这样做法在遇到视频文件较大时&#xff0c;容易造成卡顿&#xff0c;不能及时加载出来。我们可以将视频进行切片&#xff0c;然后分段加载。播放一点加载一点&am…

openGauss系数据库逻辑复制实现双写

本篇关于逻辑复制实现双写的案例&#xff0c;本来准备了3个环境&#xff0c;分别是306、501和505&#xff0c;奈何在5版本向3版本订阅的时候&#xff0c;出现了报错&#xff0c;但也将整个过程都记录下来吧。 环境准备 节点信息 MogDB# select version(); …

【Linux】进程间通信之匿名管道

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

易飞销货单出货时审核库存检查

公司接到一客户因品种多而数量少&#xff0c;单一出货计划行比较多&#xff0c;而只上了生产ERP易飞&#xff0c;审核时经常会出现倒催货&#xff0c;提前做销售单&#xff0c;行数有时超30行以上&#xff0c;审核跳窗报错时也不方便查找&#xff0c;特写一外挂程序&#xff0c…

代码随想录算法训练营第36期DAY49

DAY49 139单词拆分 没有思路。 回溯法 回溯怎么做呢&#xff1a;拼接str&#xff0c;看能不能拼出来。注意每个单词能用多次&#xff0c;不是用了就没。 但是语法还是难写。 自己的思路不好&#xff0c;题解思路&#xff1a;枚举所有分割字符串&#xff0c;判断是否在字典…

红队神器Evil-winrm的使用

前言 Evil-winrm 工具最初是由 Hackplayers 团队开发的。开发该工具的目的是尽可能简化渗透测试&#xff0c;尤其是在 Microsoft Windows 环境中。 Evil-winrm 使用 PowerShell 远程协议 (PSRP)&#xff0c;且系统和网络管理员经常使用Windows Remote Management 协议进行上传和…

哈尔滨三级等保测评需要测哪些设备?

哈尔滨三级等保测评需要测的设备&#xff0c;主要包括物理安全设备、网络安全设备和应用安全设备三大类别。这些设备在保障哈尔滨地区信息系统安全方面发挥着至关重要的作用。 首先&#xff0c;物理安全设备是确保信息系统实体安全的基础。在哈尔滨三级等保测评中&#xff0c;物…

Deepin安装PostGresql

最近要把开发环境完全从Windows移到Deepin上&#xff0c;本次介绍在Deepin借助apt-get安装和配置数据库。同时可以用Dbever提供图形化管理工具。 安装PostGreSQL数据库和创建数据库 #安装postgresql zhanglianzhuzhanglianzhu-PC:/$ sudo apt-get install postgresql-16 正在…

PyCharm中 Fitten Code插件的使用说明一

一. 简介 Fitten Code插件是是一款由非十大模型驱动的 AI 编程助手&#xff0c;它可以自动生成代码&#xff0c;提升开发效率&#xff0c;帮您调试 Bug&#xff0c;节省您的时间&#xff0c;另外还可以对话聊天&#xff0c;解决您编程碰到的问题。 前一篇文章学习了 PyCharm…

mysql数据库密码破解

一、Mysql数据库密码破解 ①一旦获取了网站一定的权限后&#xff0c;如果能够获取MSQL中保存用户数据&#xff0c;通过解密后&#xff0c;即可通过正常途径来访问数据库;一方面可以直接操作数据库中的数据&#xff0c;另一方面可以用来提升权限。 ②MySQL数据库用户密码跟其它…

安泰高压放大器应用领域分享:介电电泳(DEP)技术的具体应用

介电电泳&#xff08;Dielectrophoresis—DEP&#xff09;技术描述的是位于非匀称电场的中性微粒由于介电极化的作用而产生的平移运动。产生在微粒上的偶极矩可以有两个相同带电量但极性相反的电荷来表示&#xff0c;当它们在微粒界面上不对称分布时&#xff0c;产生一个宏观的…

小型柴油发电机不发电的原因

小型柴油发电机不发电的原因 小型柴油发电机不发电的原因可能有多种&#xff0c;以下是一些常见的原因&#xff1a; 发动机问题&#xff1a; 发动机油路不通畅&#xff0c;可能导致燃油无法顺利到达燃烧室。 气缸压缩不正常&#xff0c;影响发动机的正常工作。 润滑油粘度过大…

【c语言】自定义类型----结构体

结构体是c语言的一种自定义类型&#xff0c;自定义类型对于开发者及其重要的类型&#xff0c;它可以随意由开发者进行谱写功能&#xff0c;而今天的结构体可以用来表示一种变量的单个或多种具体属性&#xff0c;再编写代码时有着不可替代的作用&#xff01;&#xff01;&#x…

Android 代码打印meminfo

旨在替代adb shell dumpsys meminfo packageName&#xff0c;在log打印meminfo&#xff0c;以便分析内存情况 ActivityManager.MemoryInfo memoryInfo new ActivityManager.MemoryInfo(); activityManager.getMemoryInfo(memoryInfo); long totalMemory Runtime.getRuntime(…

绘唐官网绘唐科技

绘唐AI工具是一种基于人工智能技术的绘画辅助工具。 使用教程&#xff1a;https://iimenvrieak.feishu.cn/docx/CWwldSUU2okj0wxmnA0cHOdjnF 它可以根据用户提供的输入或指令生成各种类型的图像。 绘唐AI工具可以理解用户的绘画需求&#xff0c;并根据用户的要求生成具有艺术…

Python爬取与可视化-豆瓣电影数据

引言 在数据科学的学习过程中&#xff0c;数据获取与数据可视化是两项重要的技能。本文将展示如何通过Python爬取豆瓣电影Top250的电影数据&#xff0c;并将这些数据存储到数据库中&#xff0c;随后进行数据分析和可视化展示。这个项目涵盖了从数据抓取、存储到数据可视化的整个…