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

2024-06-08 23:44

本文主要是介绍编译原理-语法分析(实验 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"); //缺少endkk = 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. 判断 + - * / 是否正确

这篇关于编译原理-语法分析(实验 C语言)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1043651

相关文章

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深度解析Python中递归下降解析器的原理与实现

《深度解析Python中递归下降解析器的原理与实现》在编译器设计、配置文件处理和数据转换领域,递归下降解析器是最常用且最直观的解析技术,本文将详细介绍递归下降解析器的原理与实现,感兴趣的小伙伴可以跟随... 目录引言:解析器的核心价值一、递归下降解析器基础1.1 核心概念解析1.2 基本架构二、简单算术表达

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

MyBatis-Plus 与 Spring Boot 集成原理实战示例

《MyBatis-Plus与SpringBoot集成原理实战示例》MyBatis-Plus通过自动配置与核心组件集成SpringBoot实现零配置,提供分页、逻辑删除等插件化功能,增强MyBa... 目录 一、MyBATis-Plus 简介 二、集成方式(Spring Boot)1. 引入依赖 三、核心机制

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路