编译原理-语法分析(实验 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

相关文章

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于