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

语法分析

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.mfbz.cn/a/691553.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring AOP(实现,动态原理)详解版

Spring AOP 1.什么是AOP&#xff1f;1.1引入AOP依赖1.2编写AOP程序 2.Spring AOP核⼼概念2.1 切点(Pointcut)2.2连接点(Join Point)2.3通知(Advice)2.4 切⾯(Aspect) 3.通知类型3.1顺序3.2切⾯优先级 Order3.3 ⾃定义注解 MyAspect 4. Spring AOP 原理5 动态代理怎么实现5.1 JD…

BeagleBone Black入门总结

文章目录 参考连接重要路径系统镜像下载访问 BeagleBone 参考连接 镜像下载启动系统制作&#xff1a;SD卡烧录工具入门书籍推荐&#xff1a;BeagleBone cookbookBeagleBone概况&#xff1f; 重要路径 官方例程及脚本路径&#xff1a;/var/lib/cloud9BeagleBone Cookbook例程…

03-3.5.1~4 特殊矩阵的压缩存储

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以订…

最新区块链论文速读--CCF A会议 CCS 2023 共25篇 附pdf下载(3/4)

Conference&#xff1a;ACM Conference on Computer and Communications Security (CCS) CCF level&#xff1a;CCF A Categories&#xff1a;network and information security Year&#xff1a;2023 Num&#xff1a;25 第1~7篇区块链文章请点击此处查看 第8~13篇区块链文…

【介绍下什么是Kubernetes编排系统】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

java线程池介绍

在Java中&#xff0c;线程池是用来管理和复用线程的一种机制&#xff0c;它可以显著提升程序性能&#xff0c;特别是在大量短期异步任务的场景下。以下是创建和使用线程池的基本步骤&#xff1a; 1.创建线程池: 使用java.util.concurrent.Executors类的静态工厂方法创建线程池&…

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

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

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

编译原理-词法分析 1. 实验目的 设计、编写并调试一个词法分析程序&#xff0c;加深对词法分析原理的理解 2. 实验要求 2.1 待分析的简单语言的词法 关键字&#xff1a;begin&#xff0c;if&#xff0c;then&#xff0c;while&#xff0c;do&#xff0c;end 所有关键字都是…

Nginx(openresty) 查看连接数和并发送

1 通过浏览器查看 #修改nginx配置文件 location /status {stub_status on;access_log off;allow 192.168.50.0/24;deny all;} #重新加载 sudo /usr/local/openresty/nginx/sbin/nginx -s reloadActive connections //当前 Nginx 当前处理的活动连接数。 server accepts handl…

HPC: perf入门

如果你想查看你的程序在cpu上运行时&#xff0c;耗时时如何分布的&#xff0c;那么perf是一个合理的选择。 准备工作 为了支持使用perf&#xff0c;首先你要安装相关的库 sudo apt install linux-tools-5.15.0-67-generic此外&#xff0c;因为使用perf进行benchmark&#xf…

四种跨域解决方案

文章目录 1.引出跨域1.基本介绍2.具体演示1.启动之前学习过的springboot-furn项目2.浏览器直接访问 [localhost:8081/furns](http://localhost:8081/furns) 可以显示信息3.启动前端项目&#xff0c;取消请求拦截器&#xff0c;这样设置&#xff0c;就会出现跨域4.跨域原因 2.跨…

linux指令--sed

sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 语法解析 sed [选项] 编辑命令 文件 选项&#xff1a; -n&#xff1a;只显示匹配处理的行-e&#xff1a;执行多个编辑命令时-i&#xff1a;在原文件中进行修改&#xff0c;不输出到屏幕-…

零基础入门学用Arduino 第二部分(一)

重要的内容写在前面&#xff1a; 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。个人把这个教程学完之后&#xff0c;整体感觉是很好的&#xff0c;如果有条件的可以先学习一些相关课程&#xff0c;学起来会更加轻松&#xff0c;相关课程有数字电路…

系统思考—决策

为‮么什‬模型及‮式公‬通常比人‮决类‬策更有效&#xff1f;究‮是竟‬什么让‮些某‬模型和公‮表式‬现出色&#xff1f;事实上&#xff0c;我‮应们‬该探究的‮人是‬类在决策‮程过‬中的不足。关‮在键‬于人类‮策决‬中存在的“噪声”。尽‮模管‬型或公‮不式‬完…

【JavaScript】内置对象 - 字符串对象 ⑤ ( 判断对象中是否有某个属性 | 统计字符串中每个字符出现的次数 )

文章目录 一、判断对象中是否有某个属性1、获取对象属性2、判定对象是否有某个属性 二、统计字符串中每个字符出现的次数1、算法分析2、代码示例 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、判…

【NI国产替代】电池模拟器,快速模拟 3C 产品电池的充放电功能

电池模拟器 快速模拟 3C 产品电池的充放电功能输出灵活可调节的电压/电流内置双向 DC-DC 降压变换器为 3C 产品提供漏电检测 电池模拟器系列包含单节双通道&#xff08;1S&#xff09;、双节双通道&#xff08;2S&#xff09;、三节单通道&#xff08;3S&#xff09;三种规格&…

贪心(不相交的开区间、区间选点、带前导的拼接最小数问题)

目录 1.简单贪心 2.区间贪心 不相交的开区间 1.如何删除&#xff1f; 2.如何比较大小 区间选点问题 3.拼接最小数 1.简单贪心 比如&#xff1a;给你一堆数&#xff0c;你来构成最大的几位数 2.区间贪心 不相交的开区间 思路&#xff1a; 首先&#xff0c;如果有两个…

LeetCode刷题之HOT100之颜色分类

下午好呀&#xff0c;大家&#xff01;昨天估计是喝了假酒&#xff0c;现在没有胃口&#xff0c;喝酒真的没有任何好处。以后尽量避免此活动。今天几乎没睡觉&#xff0c;准备做完这题回宿舍&#xff0c;把电脑也带回去。 1、题目描述 2、逻辑分析 对颜色排序&#xff0c;要求…

数字孪生技术体系和核心能力整理

最近对数字孪生技术进行了跟踪调研学习,整理形成了调研成果,供大家参考。通过学习,发现数字孪生技术的构建过程其实就是数字孪生体的构建与应用过程,数字孪生体的构建是一个体系化的系统工程,数字化转型的最终形态应该就是数实融合互动互联的终极状态。数实融合是每个行业…

自定义类型:结构体+结构体内存对齐+结构体实现位段

结构体内存对齐实现位段 一.结构体1.结构体的声明2.结构体变量成员访问操作符3.结构体传参4.匿名结构体5.结构的自引用 二.结构体内存对齐1.对齐规则2.为什么存在内存对齐&#xff1f;3.修改默认对齐数 三.结构体实现位段1.什么是位段2.位段的内存分配3.位段的跨平台问题4.位段…