实验二:递归下降语法分析

article/2025/10/15 6:06:36

文章目录

  • 一、实验目的
  • 二、实验原理与要求
    •  1、原理
    •  2、要求
  • 三、实验设备
  • 四、实验内容
  • 五、实验步骤
    •  1. 单词内码表
    •  2. 定义语言文法
    •  3. 语法分析器的实现(编码)
    •  4. 测试
  • 六、配套资源

一、实验目的

  理解自顶向下语法分析的基本模式,熟悉递归下降分析程序的构造。

二、实验原理与要求

 1、原理

 每个非终结符抽象为一个函数,语法树的上下级关系对应于函数的递归调用。

 2、要求

 (1)针对一个具体语言子集,设计出相应的文法。
 (2)递归过程按规定的模式。
 (3)测试用例覆盖每个产生式候选。

三、实验设备

 配置有C/C++开发环境的计算机设备。

四、实验内容

 采用递归下降分析法对变量定义语句、赋值语句、while语句、if语句进行语法分析。对每个非终结符设计递归子函数。

五、实验步骤

 1. 单词内码表

   在实验一 词法分析程序的设计的基础上,要求考虑while语句、if语句。以下为一参考实现:

单词的分类及其表示

 2. 定义语言文法

   选取高级语言的部分语句,先定义其中所涉及的非终结符:
定义所需的非终结符
语法规范1语法规范2
说明:
(1)把识别出来的单词均作为终结符对待。
(2)在本实验中用单词种类编号表示单词,所以和当前输入符号比较的时候比较的是单词种类编号。例如:

if(str[ip]==() 改成 if(str[ip]==19)
else if(str[ip]==’a’) 改成 else if(str[ip]==100)

 3. 语法分析器的实现(编码)

// -*- coding: utf-8 -*-
//  @ Date   : 2020/5/20 13:14
//  @ Author : RichardLau_Cx
//  @ file   : Richard.cpp
//  @ IDE    : Dex-C++
//  @ Source : 编译原理实验#include <iostream>
#include "实验一 词法分析程序.cpp"  // 调用实验一的代码文件 using namespace std;typedef int vtType;  // 终结符类型,用实验一识别出的单词作为终结符,并且用单词的种类编号(int)表示单词 
vtType lookAhead;  // 用来存放当前读出的输入符号(即:存放从Result[]中,当前读出的单词)
char value[100];  // 读出当前单词的内码值 
int ip=0;  // ip指向从Result[]中,当前读出单词的下标 
//  lookAhead = Result[ip].typeNumber void error2();
void match();void PR();
void DSS(); 
void DS();
void TYPE();
void ES();
void ESS();
void IDS();
void WS();
void IFS();
void AS();
void RE();void E();
void ROP();
void T();
void E1();
void OP1();
void OP2();
void F();
void T1();void grammar(); void error2()
{cout << endl << "语法发现错误!位置为:" << ip << endl; exit(0);
}void match()
{// 当前输入符号和推导过程中,待匹配符号相等,则“匹配 ”,输入串指示器ip指向下一个输入符号ip++;lookAhead = Result[ip].typeNumber;  // 读出下一个符号种别编码 
//	value = Result[ip].code;  // 读出下一个符号内码值 
}void PR()
{  // <PR> -> <DSS><ESS>DSS();ESS();
}void DSS()
{  // <DSS> -> <DS><DSS> |  εif (lookAhead == 4 || lookAhead == 5 || lookAhead == 6){  /** lookAhead属于FIRST(<DS><DSS>)* FIRST(<DS><DSS>) = {int, float, char} = {4, 5, 6}* 求出FIRST集经过计算之后,才能用代码表示*/ DS();DSS();  // 相当于递归调用 } 	 
}void ESS()
{  // <ESS> -> <ES><ESS> | εif (lookAhead == 3 || lookAhead == 1 || lookAhead == 100) {/** lookAhead属于FIRST(<ES><ESS>) * FIRST(<ES><ESS>) = {while, if, <id>} = {3, 1, 100} */ES();ESS();}
}void DS()
{  // <DS> -> <TYPE><id><IDS>;TYPE();if (lookAhead == 100){match();IDS();if (lookAhead == 18){  // ";"的种别编码为18 match();} else {error2();}} else {error2();}
}void TYPE()
{  // <TYPE> -> int | float | char cout << "lookAhead: " << lookAhead << endl; if (lookAhead == 4){  // 匹配到int 
//		printf("\n匹配到int!\n");match(); }else if (lookAhead == 5){  // 匹配到floatmatch();} else if (lookAhead == 6){  // 匹配到charmatch();	}else{error2();  // 语法错误 }
}void IDS()
{  // <IDS> -> ,<id><IDS> |  εif (lookAhead == 17){  // ","的种别编码为17  match();if (lookAhead == 100){match();IDS();}}// 因为有ε,所以不用写else error(); 
}void ES()
{// <ES> -> <WS> | <IFS> | <AS>/*** FIRST(<WS>) = {while} = {3},* FIRST(<IFS>) = {if} = {1},* FIRSR(<AS>) = {<id>} = {100}*/if (lookAhead == 3){
//		match();WS();} else if (lookAhead == 1){
//		match();IFS();}else if (lookAhead == 100){
//		match();AS();} else {error2();} }void WS()
{  // <WS> -> while "(" <RE> ")" {<ESS>} // 因为皆为递进关系,所以需要嵌套着写 if (lookAhead == 3){  // 读出while match(); if (lookAhead == 19){  // 读出"(" match();RE();if (lookAhead == 20){  // 读出")" match();if (lookAhead == 23){  // 读出"{" match();ESS();if (lookAhead == 24){  // 读出"}" match();}else {error2();}}else{error2();} }else {error2();} }else{error2();}}else{error2();} } void IFS()  
{  // if "(" <RE> ")" { <ESS> } else { <ESS> }if (lookAhead == 1){  // 读出if match();if (lookAhead == 19){  // 读出"(" match();RE();if (lookAhead == 20){  // 读出")" match();if (lookAhead == 23){  // 读出"{" match();ESS();if (lookAhead == 24){  // 读出"}" match();if (lookAhead == 2){  // 读出else match();if (lookAhead == 23){  // 读出"{" match();ESS();if (lookAhead == 24){  // 读出"}" match();}else{error2();}}else {error2();}}else {error2();}} else{error2();}}else{error2();}} else{error2();}}else{error2();}} else{error2();}
}void AS()
{  // <AS> -> <id>=<E>;if (lookAhead == 100){match();if (lookAhead == 13){  // 读出"=" match();E();if (lookAhead == 18){  // ";"的种别编码为18 match();} else{error2();}}else{error2();} }else{error2();}
}void RE()
{  // <RE> -> <E><ROP><E>E();ROP();E();
}void ROP()
{  // <ROP> -> > | >= | < | <= | == | !=  if (lookAhead == 10){  // 读出">" match();} else if (lookAhead == 11){  // 读出">=" match();}else if (lookAhead == 25){  // 读出"<" match();}else if (lookAhead == 26){  // 读出"<=" match();}else if (lookAhead == 14){  // 读出"==" match();}else if (lookAhead == 28){  // 读出"!=" match();}else{error2();}} void E()
{  // <E> -> <T><E1> T();E1();
}void E1()
{  // <E1 -> <OP1><T><E1> | ε/** 先计算FIRST(<OP1><T><E1>) = {+, -} = {7, 21}*/if (lookAhead == 7 || lookAhead == 21){OP1();T();E1();}
}void T()
{  // <T> -> <F><T1> F();T1();
}void T1()
{  // <T1> -> <OP2><F><T1> | ε/** 先计算FIRST(<OP2><F><T1>) = {*, /} = {15, 22}*/if (lookAhead == 15 || lookAhead == 22){OP2();F();T1();} } void F()
{  // F -> (E) | <id> | <digis>if (lookAhead == 19){  // 读出"("match(); E();if (lookAhead == 20){  // 读出")" match();}}else if (lookAhead == 100){  // 读出标识符 match(); } //	else if (atoi(value))
//else if ("0" <= value || value <= "999")else if (lookAhead == 110){match();}else{error2();}} void OP1()
{  // <OP1> -> + | -if (lookAhead == 7){match();} else if (lookAhead == 21){match();}else{error2();}
}void OP2()
{  // <OP2> -> * | /if (lookAhead == 15){match();} else if (lookAhead == 22){match();}else{error2();}
}void grammar()
{  // 语法分析 cout << "function: grammar(): " << endl;PR();if (ip == number){  // 相当于读取到最后一个单词,相当于从左至右扫描输入串到达尾部 cout << endl << "\n语法检查通过!\n" << endl; }else {  // 如3+2; 语法错误,而a=3+2; 语法正确 cout << endl << "\n语法检查未通过!\n" << endl; }} int main()  // 注:需要把实验一的main函数注释掉 
{words();  // 词法分析lookAhead = Result[ip].typeNumber;  // lookAhead存放第一个单词,相当于从输入串中读第一个符号的种别编码//	printf("\nlookAhead: %d\n", lookAhead); grammar();  // 语法分析 return 0;} 

 4. 测试

  • Notice:其中的位置是针对词为单位的。
  1. 输入:char
    char
  • 构造正反测试用例:
  1. 正确实例:float x, y; 错误实例:float x, y
    测试2-1测试2-2
  2. 正确实例:q=520; 错误实例:q=520 错误实例:q=520;;
    测试3-1
    测试3-2
    测试3-3
  3. 正确实例:while(r>=9){} 错误实例:while(r>=){}
    测试4-1
    测试4-2
  4. 正确实例:if(l>c){x=6;} else{x=0;} 错误实例:if(x>y)z=t; else k=t;
    测试5-1
    测试5-2

Notice:本程序内部分支多,且实验时间有限。要达到较为全面测试覆盖比较难,因此只要求变量定义语句、赋值语句、while、if四种语句均有正反测试用例。

六、配套资源

  • 实验指导书

http://chatgpt.dhexx.cn/article/Vb8Oop17.shtml

相关文章

编译原理递归下降语法分析器C++实现

编译原理递归下降语法分析器C简单实现 1.递归下降分析法的功能 语法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2.递归下降分析法的前提 改造文法&#xff1a;消除二义性、消除左递归、提取左因子&#xff0c;判断是否为LL&#xff08;1&#xff0…

编译原理(九)——递归下降法

背景&#xff1a; 自定向下的语法分析方法&#xff0c;LL(1)是一种非常直观的方法&#xff0c;它的分析过程是按照句子的定义来进行的&#xff0c;也就是说从开始符出发对要分析的串进行推导&#xff0c;如果推导成功就证明这个被分析的串是一个合法的句子&#xff0c;否则的话…

【编译原理】【C语言】实验三:递归下降分析法

C语言 实验环境&#xff1a;Visual Studio 2019 author&#xff1a;zoxiii 递归下降分析法 1、实验内容2、前期准备2.1 递归下降分析法原理2.2 要实现的文法2.3 需要的函数 3、分析过程3.1 递归下降分析法设计思想及算法3.2 分析栈的分析过程3.3 流程图3.4 源代码3.5 运行结果 …

JAVA游戏开发-超炫酷贪吃蛇游戏源码及教程

一&#xff0e;前言 某日&#xff0c;看见隔壁家的小朋友在玩一款网络爆款贪吃蛇游戏&#xff0c;感觉很好玩。自己刚好正在学习JAVA编程&#xff0c;也想实现一个类似功能的游戏Demo练手&#xff0c;在网上查看了不少源码案例&#xff0c;全都是很古老的方块式贪吃蛇游戏案例…

Java实现贪吃蛇游戏【代码】

Java实现贪吃蛇游戏【代码】 花了两个下午写了一个贪吃蛇小游戏&#xff0c;本人想写这游戏很长时间了。作为以前诺基亚手机上的经典游戏&#xff0c;贪吃蛇和俄罗斯方块一样&#xff0c;都曾经在我们的童年给我们带来了很多乐趣。世间万物斗转星移&#xff0c;诺基亚曾经作为手…

JavaSE项目 | 纯Java实现贪吃蛇小游戏

目录 一&#xff1a;贪吃蛇游戏的实现步骤 1. 画出窗口 2. 在窗口上添加画布 3. 在画布上添加黑色游戏区 4. 放静态蛇 5. 定义蛇的数据结构 6. 控制蛇头方向 7. 放上开始提示信息 8. 按空格键开始游戏 9. 让蛇动起来 10. 实现暂停 11. 实现转向功能 12. 添加食物 …

java 贪吃蛇 源码+图片

本人也是个初学者&#xff0c;有什么不对的地方&#xff0c;请大佬指点&#xff01;&#xff01;&#xff01; 一、涉及到的知识点如下&#xff1a; 循环&#xff0c;分支方法的抽取数组的使用面向对象继承&#xff0c;子类方法的重写接口&#xff0c;接口的实现 二、游戏图形…

JAVA贪吃蛇代码(带注释)

贪吃蛇 这是游戏效果图片是代码里面的素材游戏数据类 package com.tang.retor_snaker;import javax.swing.*; import java.net.URL;public class Data {private static URL bodyURL Data.class.getResource("/com/tang/retor_snaker/statics/body.png");private st…

JAVA贪吃蛇小游戏源代码系列

欢迎关注公众号&#xff1a; 获取贪吃蛇小游戏的源代码。 贪吃蛇小游戏运行结果如下&#xff1a; 启动界面&#xff1a; 运行界面&#xff1a; 重启界面&#xff1a; 源代码框架如下&#xff1a; 注&#xff1a;在运行程序的时候&#xff0c;得重新设计窗体的大小&#x…

JAVA 实现《贪吃蛇大作战》游戏|CSDN创作打卡

前言 贪吃蛇&#xff08;也叫做贪食蛇&#xff09;游戏是一款休闲益智类游戏&#xff0c;有PC和手机等多平台版本。既简单又耐玩。该游戏通过控制蛇头方向吃东西&#xff0c;从而使得蛇变得越来越长。 本程序是通过java的swing来实现《贪吃蛇大作战》这款游戏。 主要需求 1…

java贪吃蛇源码

欢迎访问我的个人博客 https://jialaner.cn/​​​​​​​ java是一种面向对象的语言&#xff0c;有着其中不用质疑的优点。学习java将近三个月了&#xff0c;一直在琢磨着“万物皆对象”的意义&#xff0c;却总是只知其表不知其意&#xff0c;做完这个java贪吃蛇后才有了那么…

贪吃蛇 java实现超简单的贪吃蛇(附源代码)

贪吃蛇游戏 贪吃蛇是个非常经典的游戏&#xff0c;希望对初学Java的小伙伴有一定帮助。希望大家喜欢&#xff0c;因为写得简单&#xff0c;希望大家都能看得懂。 游戏界面&#xff08;游戏背景素材不喜欢的话可以自己换&#xff0c;就别在乎我选的素材&#xff08;&#x1f9…

java实现贪吃蛇小游戏(源码+注释)

一.工程文件 二.Main.java package com.company;import javax.swing.*;public class Main {public static void main(String[] args) {//创建窗体对象JFrame frame new JFrame();//创建窗体参数&#xff08;&#xff09;frame.setBounds(10,10,900,720);//设置不允许更改大小…

使用Java实现一个简单的贪吃蛇小游戏

基于java实现贪吃蛇小游戏&#xff0c;主要通过绘制不同的图片并以一定速度一帧一帧地在窗体上进行展示。 开发工具&#xff1a;eclipse java工具包&#xff1a;jdk1.8 一、创建新项目 创建一个新的项目&#xff0c;并命名。创建一个名为images的文件夹用来存放游戏相关图片…

Java贪吃蛇全代码

用Java编写精典小游戏——贪吃蛇&#xff01; 前言 我想贪吃蛇应该是不少90后和00后的童年&#xff08;我本人是01年的&#xff09;&#xff0c;回想起从前偷偷拿着我爹的诺基亚在被窝里玩贪吃蛇&#xff0c;不禁感慨万分&#xff0c;时间飞逝&#xff0c;没想到10年后的我也可…

JAVA小项目(四)—— 贪吃蛇【轻松入门,附源码】

目录 &#xff08;一&#xff09;效果图 &#xff08;二&#xff09;代码实现 &#xff08;1&#xff09;将图片加载到程序中 &#xff08;2&#xff09;创建窗体 &#xff08;3&#xff09;创建面板 &#xff08;4&#xff09;绘制静态的小蛇 &#xff08;5&#xff09; 加入监…

Java贪吃蛇大作战

作为Java新手小白&#xff0c;渴望学习一些好玩有趣的java程序 废话不多说&#xff0c;接下来我会一步一步实现java小程序&#xff1a;贪吃蛇大作战哦&#xff01; 实现 Java贪吃蛇一共分四个步骤&#xff1a; 1、画出窗体对象 2、绘制静态ui 3、使用鼠标监听器事件和定时器事…

Java简易小游戏贪吃蛇(Java实战)

这个版本的贪吃蛇我是跟着“黑马程序员”写的。小伙伴们可以跟着视频试着做一下&#xff0c;同时视频也会更详细。 B站学习链接&#xff1a;【黑马】两个小时带你用Java语言写一个贪吃蛇游戏【配套源码笔记】_哔哩哔哩_bilibili 相对于新手而言&#xff0c;贪吃蛇应该算是一个…

JAVA实现贪吃蛇游戏

本文实现的功能有: 1.绘制静态窗口 2.绘制游戏面板 3.绘制静态小蛇 4.通过键盘控制小蛇移动 5.吃食物 6.积分系统和失败判定 最近在学GUI&#xff0c;然后又有读者希望我写一下相关的实战。刚好博主在b站漫无目的的寻找着题材的时候看到了一个写贪吃蛇游戏的视频&#xff0c;于…

Java实现贪吃蛇大作战小游戏(完整版)

大家好&#xff0c;今天尝试用swing技术写一个贪吃蛇大作战小游戏&#xff0c;供大家参考。 效果展示 目录 效果展示 一、游戏界面 二、得分情况 项目介绍 项目背景 总体需求 实现过程 代码展示 主类 &#xff1a;Demo类 MyPanel类 ①构造方法 ②初始化方法 ③绘制方法…