算符优先文法语法分析

news2024/11/26 12:51:34

1、实验目的及要求

1.1、实验目的

        加深对语法分析器工作过程的理解;加强对算符优先分析法实现语法分析程序的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法翻译。

1.2、实验要求

        花一周时间写出表达式的文法,优先符号表等理论准备。设计好程序结构,画出模块结构图,写出模块接口和调用关系。描述每个模块的功能。上机编制子模块代码,并测试。业余继续完成代码设计。第二次上机进行调试、修改,对照测试数据比对结果。第三次上机要求全部通过。有余力的同学可编制解释执行程序,对表达式进行求值(此时可不考虑赋值语句)。

2、实验步骤

2.1、模块一:构建firstVT()和lastVT()集合

 

 

3、实验内容

3.1、流程图

 

3.2、源代码 

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <cctype>
#define MAX 512
using namespace std;
class WF
{
    public:
	    string left;//产生式的左部
	    vector<string> right;//产生式右部
	    WF ( const string& str )
	    {
	        left = str;
	    }
	    //一个非终结符可以有多个产生式
	    //把右部的起始指针存入right的最后
	    void insert ( char str[] )
	    {
	        right.push_back(str);
	    }
	    //合并和打印产生式
	    void print ( )
	    {
	        for ( unsigned i = 0 ; i < right.size() ; i++ )
	        {
	        	if (i==0)
				{
					printf ( "%s->%s" , left.c_str() , right[i].c_str() );
				}
				else
				{
					printf ( "|%s" , right[i].c_str() );
				}
			}
			puts("");
	    }
};
char relation[MAX][MAX];//优先关系表
vector<char> VT;//终结符集合
vector<WF> VN_set;//文法产生式
map<string,int> VN_dic;//非终结符及对应的顺序
set<char> first[MAX];//firstVT集合
set<char> last[MAX];//lastVT集合
int used[MAX];//终结符的出现顺序表
int vis[MAX];//标志第i条产生式是否处理了
//找出每个非终结符的对应的firstVT
//获取左部的非终结符
//遍历右部
void dfs_first (int x)
{

    if ( vis[x] )
{
		 return;
	 }
    vis[x] = 1;//表示第i条产生式处理过了
    string& left = VN_set[x].left;
    for ( unsigned i = 0 ; i < VN_set[x].right.size() ; i++ )
    {
        string& str = VN_set[x].right[i];//右部
        //如果第一个是大写的 ,获取它的下标
        if ( isupper(str[0]) )
        {
            int y = VN_dic[str.substr(0,1)]-1;//下标
            //后边还有且不是非终结符
            if ( str.length() > 1 && !isupper(str[1] ) )
            {
                first[x].insert ( str[1] );
            }
            dfs_first ( y );
            set<char>::iterator it = first[y].begin();
            for ( ; it!= first[y].end() ; it++ )
            {
                first[x].insert ( *it );
            }
        }
        else
		{
            first[x].insert ( str[0] );
         }
    }
}
//构建firstVT集
//如果vis[i]为0,表示第i条产生式还没处理,则调用dfs来查找它的firstVT,查找完后将vis[i]置1,表示已经处理了第i条产生式
void make_first ( )
{
	//将vis数组元素置0
    memset ( vis , 0 , sizeof ( vis ) );
    for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
    {
        if ( vis[i] )
        {
			continue;
	  }
        else
        {
					dfs_first (i);
			  }
	}
    puts("------------FIRSTVT集-------------------");
    for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
    {
        printf ( "%s : " , VN_set[i].left.c_str() );
        //迭代输出
        set<char>::iterator it = first[i].begin();
        for ( ; it!= first[i].end() ; it++ )
        {
            printf ( "%c " , *it );
        }
        puts ("" );
    }
}
//找出每个非终结符的对应的lastVT
void dfs_last ( int x )
{
    if ( vis[x] )
			  return;
    vis[x] = 1;
    string& left = VN_set[x].left;
    for ( unsigned i = 0 ; i < VN_set[x].right.size() ; i++ )
    {
        string& str = VN_set[x].right[i];
        int n = str.length() -1;
        if ( isupper(str[n] ) )
        {
            int y = VN_dic[str.substr(n,1)]-1;
            if ( str.length() > 1 && !isupper(str[n-1]) )
            {
                last[x].insert ( str[1] );
            }
            dfs_last ( y );
            set<char>::iterator it = last[y].begin();
            for ( ; it != last[y].end() ; it++ )
            {
                last[x].insert ( *it );
            }
        }
        else
		     {
            last[x].insert ( str[n] );
        }
    }
}
//构建lastVT集
void make_last ( )
{
    memset ( vis , 0 , sizeof ( vis ) );//vis数组元素全部置0
    for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
        if ( vis[i] ) continue;
        	 else dfs_last ( i );
    puts("--------------LASTVT集---------------------");
    for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
    {
        printf ( "%s : " , VN_set[i].left.c_str() );
        set<char>::iterator it = last[i].begin();
        for ( ; it!= last[i].end() ; it++ )
            printf ( "%c " , *it );
        puts ("" );
    }
}
//构造算法关系优先表
void make_table ( )
{
    for ( int i = 0 ; i < MAX ; i++ )
        for ( int j = 0 ; j < MAX ; j++ )
            relation[i][j] = ' ';
    for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
    {
        for ( unsigned j = 0 ; j < VN_set[i].right.size() ; j++ )
        {
            string& str = VN_set[i].right[j];
            for ( unsigned k = 0 ; k < str.length()-1 ; k++ )
            {
                if ( !isupper(str[k]) && !isupper(str[k+1]) )
                    relation[str[k]][str[k+1]] = '=';
                if ( !isupper(str[k]) && isupper(str[k+1]) )
                {
                    int x = VN_dic[str.substr(k+1,1)]-1;
                    set<char>::iterator it = first[x].begin();
                    for ( ; it != first[x].end() ; it++ )
                        relation[str[k]][*it] = '<';
                }
                if ( isupper(str[k]) && !isupper(str[k+1]) )
                {
                    int x = VN_dic[str.substr(k,1)]-1;
                    set<char>::iterator it = last[x].begin();
                    for ( ; it != last[x].end() ; it++ )
                        relation[*it][str[k+1]] = '>';
                }
                if ( k > str.length()-2 ) continue;
                if ( !isupper(str[k]) && !isupper(str[k+2]) && isupper(str[k+1]) )
                    relation[str[k]][str[k+2]] = '=';
            }
        }
    }
    for ( unsigned i = 0 ; i < VT.size()*5 ; i++ )
    {
			 printf ("-");
	    }
    printf ( "算符优先关系表" );
    for ( unsigned i = 0 ; i < VT.size()*5 ; i++ )
    {
			  printf ( "-" );
	       }
    puts("");
    printf ( "|%8s|" , "" );
    for ( unsigned i = 0 ; i < VT.size() ; i++ )
    {
    	  printf ( "%5c%5s" , VT[i] , "|" );
	    }
    puts ("");
    for ( unsigned i = 0 ; i < (VT.size()+1)*10 ; i++ )
    {
			  printf ( "-" );
}
    puts("");
    for ( unsigned i = 0 ; i < VT.size() ; i++ )
    {
        printf ( "|%4c%5s" , VT[i] , "|");
        for ( unsigned j = 0 ; j < VT.size() ; j++ )
        {
            printf ( "%5c%5s" , relation[VT[i]][VT[j]] , "|" );
        }
        puts ("");
        for ( unsigned i = 0 ; i < (VT.size()+1)*10 ; i++ )
	    	  {
				  printf ( "-" );
			  }
        puts("");
    }
}
int main ( )
{
    int n;
    char s[MAX];
    cout<<"产生式的条数n=";
    while ( ~scanf ( "%d" , &n ) )
    {
        memset ( used , 0 , sizeof ( used ) );
        cout<<"产生式:"<<endl;
        for ( int i = 0 ; i < n ; i++ )
        {
            scanf ( "%s" , s );
            int len = strlen(s);//每条产生式的长度
					int j;
            for ( j = 0 ; j < len ; j++ )
            {
            		if ( s[j] == '-' )
                   break;
					}
            s[j] = 0;//-替换成\0,以便截断产生式的左右部分
            //如果不存在这个非终结符,则会VN_dic中插入,对应的value为0
            if ( !VN_dic[s] )
            {
                VN_set.push_back ( WF(s) );//放入VN_set中
                VN_dic[s] = VN_set.size();//设置s的value当前元素个数
            }
            int x = VN_dic[s]-1;//获取这个产生式的下标
            VN_set[x].insert ( s+j+2 );//s+j+2为产生式右部的起始地址
            for ( int k = j+2 ; k < len; k++ )
            {
                if ( !isupper(s[k] ) )
                {
                    if ( used[s[k]] )
									continue;
                    VT.push_back ( s[k] );//把终结符放入终结符数组中
                    used[s[k]] = VT.size();//这个VT对应的位置,从1开始
                }
					}
        }
        puts ("************VT集*******************");
        for ( unsigned i = 0 ; i < VT.size() ; i++ )
        {
        	  printf ( "%c " , VT[i] );
			  }
        puts ("");
        puts("*************产生式*****************");
        for ( unsigned i = 0 ; i < VN_set.size() ; i++ )
        {
        		VN_set[i].print();
			  }
        puts("************************************");
        make_first();
        make_last();
        make_table();
    }
}

4、实验结果

 

 

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

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

相关文章

小龟带你妙写排序之选择排序

选择排序 一. 原理二. 题目三. 思路分析四. 代码 一. 原理 选择排序(Selection-sort)是一种简单直观的排序算法。 工作原理&#xff1a;首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放到排序序列的起始位置&#xff0c;然后&#xff0c;再从剩余未…

C语言快速回顾(三)

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。C/C是音视频必…

AtCoder Beginner Contest 314

A.直接模拟就行 #include <bits/stdc.h> using namespace std; const int N 2e510; #define int long long int n,m; string s"3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";void solve(){cin…

【电池-超级电容器混合存储系统】单机光伏电池-超级电容混合储能系统的能量管理系统(Simulink仿真)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Three.js 实现材质边缘通道发光效果

相关API的使用&#xff1a; 1. EffectComposer&#xff08;渲染后处理的通用框架&#xff0c;用于将多个渲染通道&#xff08;pass&#xff09;组合在一起创建特定的视觉效果&#xff09; 2. RenderPass(是用于渲染场景的通道。它将场景和相机作为输入&#xff0c;使用Three.…

MySQL数据库----------安装anaconda---------python与数据库的链接

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【福建事业单位-数学运算】04计算、最值和几何

【福建事业单位-数学运算】04计算、最值和几何 一、计算1.1 基础计算1.2 数列计算等差数列等比数列 总结 二、最值问题2.1 最不利构造最不利加排列组合 2.2 构造数列 三、几何问题2.1 公式计算类规则图形非规则图形 2.2结论技巧性&#xff08;三角形&#xff09;总结 一、计算 …

【Zabbix安装-5.5版本】

Zabbix安装&#xff08;rpm包安装&#xff09; Index of /zabbix/zabbix/5.5/rhel/8/x86_64/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror rpm包链接&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/5.5/rhel/8/x86_64/zabbix-release-5.5-1.e…

日常BUG——通过命令行创建vue项目报错

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 在使用vue命令行创建一个vue项目时&#xff0c;出现一下的错误&#xff1a; vue create my…

无涯教程-Perl - ref函数

描述 如果EXPR为引用,则此函数返回真值&#xff1b;如果未提供EXPR,则为$_。返回的实际值还定义了引用所引用的实体的类型。 内置类型为- REFSCALARARRAYHASHCODEGLOBLVALUEIO::Handle 如果使用bless()函数为变量设置了祝福,则将返回新的数据类型。新的数据类型通常将是一个…

homebrew安装

1.国内镜像安装 /bin/zsh -c "$(curl -fsSL https://gitee.com/huwei1024/HomebrewCN/raw/master/Homebrew.sh)"2.选中科大下载源 3.输入密码 4.排错 5.常见错误网址 添加链接描述 6.配置环境变量

texmaker-Latex,设置biber/bibtex

打开texmaker&#xff0c;【选项】–>配置texmaker–>[命令]–>bib(la)tex&#xff0c;然后在该选项里面已有的路径下改为添加biber的路径

【数据结构】树和二叉树的概念及结构

1.树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#…

【算法基础20-单调栈】

算法原理: 用单调递增栈&#xff0c;当该元素可以入栈的时候&#xff0c;栈顶元素就是它左侧第一个比它小的元素。 以&#xff1a;3 4 2 7 5 为例&#xff0c;过程如下&#xff1a; 动态模拟过程 题目&#xff1a; 给定一个长度为 N 的整数数列&#xff0c;输出每个数左边第一…

Vue.js 生命周期详解

Vue.js 是一款流行的 JavaScript 框架&#xff0c;它采用了组件化的开发方式&#xff0c;使得前端开发更加简单和高效。在 Vue.js 的开发过程中&#xff0c;了解和理解 Vue 的生命周期非常重要。本文将详细介绍 Vue 生命周期的四个阶段&#xff1a;创建、挂载、更新和销毁。 …

C语言快速回顾(一)

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。C/C是音视频必…

vue3中使用component动态组件常见问题

一. 在vue3中使用动态组件问题警告处理 1. 代码如下 <template><div v-for"(item, index) in navItems" :key"index"><component :is"item.component" :key"item.gameId"></component></div> </te…

【Pytroch】基于支持向量机算法的数据分类预测(Excel可直接替换数据)

【Pytroch】基于支持向量机算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.数学公式3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种强大的监…

【Megatron-DeepSpeed】张量并行工具代码mpu详解(四):张量并行版Embedding层及交叉熵的实现及测试

相关博客 【Megatron-DeepSpeed】张量并行工具代码mpu详解(四)&#xff1a;张量并行版Embedding层及交叉熵的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(三)&#xff1a;张量并行层的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(一)&#xff1a…

时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 1.Matlab实现CNN卷积神经网络时间序列预测未…