c++消除左递归算法

编译原理中文法左递归消除技术详解与实战 左递归的核心在于递归定义的产生式结构。在形式语言理论中,一个文法 $ G = (V, T, P, S) $,其中 $ V $ 是非终结符集合,$ T $ 是终结符集合,$ P $ 是产生式集合,$ S $ 是起始符号。左递归可以分为两种基本形式:直接左递归与间接左递归。递归是指某个非终结符 $ A $ 可以通过若干步推导重新生成自己。如果这个推导过程的第一步就直接使用了以 $ A $ 为左部的产生式,则称为直接左递归。 阅读详情

[`原文网址](https://blog.youkuaiyun.com/qq_24451605/article/details/50075467)

课程设计选这个题,然后找到了上述文章。拿去vs一跑发现不少错误。主要是指针越界的错误。
故稍作修改,起码能跑。还添加了一些注释,方便像我一样的混子看懂
删除了化简和dfs函数,因为没啥用。。。。
下面是输入:
在这里插入图片描述
说实话,这个输入不是很方便,明明可以一次输入R->Sa|a,非要自找麻烦输入两次。
不说了,上代码!
``

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cctype>
#include <map>
#include <set>
#define MAX 500

using namespace std;

class WF  //定义一个用于存放p的类
{
public:
    string left; //产生式左部
    set<string> right; //右部
    WF(const string& temp) //默认构造函数
    {
        left = temp;
        right.clear();
    }
    void print()
    {
        printf("%s->", left.c_str());
        set<string>::iterator it = right.begin();//遍历右部
        printf("%s", it->c_str());
        it++;
        for (; it != right.end(); it++)
            printf("|%s", it->c_str());
        puts("");//输出字符串
    }
    void insert(const string& temp)//右部插入
    {
        right.insert(temp);
    }
};

map<string, int> VN_dic;//下标类型为string,数组每一个元素的类型为int的数组
vector<WF> VN_set;//存放文法G的容器
string start;
bool used[MAX];

//消除间接左递归
void remove1()
{
    //如果j的左部字母出现在i的右部,就把j的右部代入到i的右部,直到i是最后一个产生式
    for (int i = 0; i < VN_set.size(); i++)
        for (int j = 0; j < i; j++)
        {
            vector<string> cont;  //代入后的右部
            set<string>& right1 = VN_set[i].right;   //获取第i个产生式的右部
            set<string>& right2 = VN_set[j].right;   //获取第j个产生式的右部
            char ch = VN_set[j].left[0];    //j的左部字母
            set<string>::iterator it1 = right1.begin(); //遍历i的右部
            set<string>::iterator it2;
            for (; it1 != right1.end(); it1++)
                if (it1->at(0) == ch) //是否代入
                    for (it2 = right2.begin(); it2 != right2.end(); it2++)
                        //substr(a)截取下标a后的字符串
                        //截取的字符串加入到cont中
                        cont.push_back(*it2 + it1->substr(1)); 
            int nn = right1.size();
            while (nn--)
            {
                //i的右部中可以代入的字母所在式子删除
                if (right1.begin()->at(0) == ch) 
                    right1.erase(right1.begin()); 
                else
                {
                    //更新cont,删除i的第一个右部式子,直到i的右部被删除完毕
                    cont.push_back(*right1.begin());
                    right1.erase(right1.begin());
                }
            }
            //把代入完成的i的右部cont插入到i的右部
            for (int i = 0; i < cont.size(); i++)
                right1.insert(cont[i]);
        }
}

//消除直接左递归
void remove2()
{
    for (int i = 0; i < VN_set.size(); i++)
    {
        char ch = VN_set[i].left[0];    //获取i的左部字母
        set<string>& temp = VN_set[i].right;    //获取i的右部指针
        set<string>::iterator it = temp.begin();//遍历
        //新产生式左部为原左部字母加'
        string tt = VN_set[i].left.substr(0, 1) + "\'";    
        bool flag = true;
        //当遍历到左部字母时,添加新产生式
        for (; it != temp.end(); it++)
            if (it->at(0) == ch)
            {
                VN_set.push_back(WF(tt));
                VN_dic[tt] = VN_set.size();
                flag = false;
                break;
            }
        //获取i的右部指针
        set<string>& tempp = VN_set[i].right;
        int x = VN_dic[tt] - 1;
        if (flag) continue;
        vector<string> cont;//原产生式的右部
        //获取新产生式的右部
        set<string>& ss = VN_set[x].right;
        ss.insert("~");
        while (!tempp.empty())
        {   
            //右部按第一个字母是否为左部字母分别处理
            if (tempp.begin()->at(0)==ch)
                //新式添加的右部为原式右部第二个元素开始字符串+新式左部字母
                ss.insert(tempp.begin()->substr(1) + tt);
            else
            {
                //原式右部为原右部+新式左部字母
                cont.push_back(tempp.begin()->substr(0) + tt);
            }
            //删除右部第一个式子
            tempp.erase(tempp.begin());
        }
        puts("");
        //更新原产生式的右部
        for (int i = 0; i < cont.size(); i++)
        {
            tempp.insert(cont[i]);
        }
    }
}

void  print()
{
    cout << "**********消除左递归后的结果********" << endl;
    for (int i = 0; i < VN_set.size(); i++)
        VN_set[i].print();
    puts("");
}

//  P->Pa     R->Sa       R->a      
//  P->a      S->Qb       S->b      Q->Rc       Q->c

int main()
{
    char buf[MAX];
    int n;
    VN_dic.clear();
    VN_set.clear();
    start = "S";
    cout << "请输入文法G[S]的产生式数量:";
    cin >> n;
        while (n--)
        {
            cin >> buf;
            int len = strlen(buf), i;//返回buf长度
            for (i = 0; i < len; i++)
                if (buf[i] == '-')
                {
                    buf[i] = 0;
                    break;
                }
            string temp = buf;
            if (!VN_dic[temp])
            {
                //添加左部字母
                VN_set.push_back(WF(temp));
                VN_dic[temp] = VN_set.size();
            }
            //添加右部式子Pa和a都算是式子
            int x = VN_dic[temp] - 1;
            int j = 3; string tempp;
            while (buf[j] != '\0') {
                string buf(1, buf[j]);
                tempp = tempp + buf;
                j++;
            }
            temp = tempp;
            VN_set[x].insert(temp);
        }
        cout << endl << "完整的G文法:" << endl;
        for (int i = 0; i < VN_set.size(); i++)
            VN_set[i].print();
      
        remove1();
        remove2();
        print();
        
        return 0;
}
用C++自动生成LL(1)分析器:左递归消除与预测表实现 语法分析是编译器前端的核心环节,自顶向下的LL(1)分析器因预测表简洁、表驱动易于实现而成为经典方案。手工递归下降在文法简单时虽直观,但随着产生式增多,维护成本与左递归变形问题逐渐失控。自动生成LL(1)分析器能从根本上解决文法与分析器不同步的痛点:通过消除左递归、迭代计算FIRST/FOLLOW集合,再依据表填充规则构造预测分析表,即可获得可用的表驱动分析函数。这一方法特别适合课程编译器、静态分析前端等场景。基于C++实现一个从文本文法到预测表的完整工具链,涵盖产生式解析、数据结构设计、固定点算法及冲突检 阅读详情

相关推荐

c实现消除文法左递归

编译原理消除文法的左递归,用C语言实现的 在vc++6.0运行环境下编译通过

编译原理实验二——消除一切文法的左递归(c++实现)

详细解读消除左递归的算法原理,并给出完整代码,注释和解释详细,可耐心阅读

qq_56067262的博客 5784

编译系统设计 课程设计报告 哈工程 实验环境的使用、消除左递归(无替换)、提取左因子、First 集合、Follow集合、符号表

最后得了优秀。 1. 实验1:实验环境的使用 2. 实验4消除左递归(无替换) 3. 实验6提取左因子 4. 实验7 First 集合 5. 实验8 Follow集合 6. 实验10 符号表的构建与使用

【C++实现】编译原理 免考小队 消除一切左递归

背景 期末考试免考,冲! 实验名称 消除一切左递归 实验时间 2020年5月27日 到 2020年5月31日 院系 信息科学与工程学院 组员姓名 Chocolate、kry2025、钟先生、leo、小光 实验环境介绍 windows 10 操作系统 Eclipse 进行 java 编程 CodeBlocks 进行 C++ 编程 实验目的与要求 目的 深刻理解左递归的算法 掌握消除左递归的过程 加强团队合作能力 提高自身的编程能力和解决问题的能力 要求 编程实现消除一切左递归 算法简洁,不冗余

超逸の学习技术博客 5091

华硕主板UEFI模式下安装Ubuntu与Windows双系统全攻略

本文详细讲解了在华硕主板UEFI模式下安装Ubuntu与Windows双系统的完整流程。从安装前的BIOS关键设置(如处理安全启动与CSM)、使用GPT分区表,到在Windows中安全分配空间、手动创建Ubuntu分区,最后完成引导配置,提供了避免常见错误的实用技巧,确保双系统稳定共存。

weixin_29199873的博客 346

win10自动修复-无限循环【通用完美】超简单解决办法

2020.02.14今个我的笔记本电脑(Thinkpad Carbon 7 X1)(win10)早晨起来发现蓝屏,上面显示自动修复失败,重启后依然自动修复失败,不断手动重启,始终是修复失败。然后上网开始搜集资料找解决办法。 前边介绍关闭自动修复,如何找出错文件的方法;如果想看最终解决办法,直接看第三部分 上网就会发现这种现象很常见,同时是电脑自动安装系统更新,或者安装某些驱动出现。解决办法也大...

y15941300574的博客 19万+

编译原理-消除一切左递归(C++实现)

消除间接左递归消除直接左递归去掉无用产生式。

PURSUE__LIFE的博客 1464

避开SAM3安装大坑:手把手教你用国内镜像和Modelscope权重快速跑通Demo

本文详细介绍了如何在国内环境下快速部署SAM3视觉大模型,包括使用国内镜像加速Python包安装、通过Modelscope获取权重文件以及解决CUDA 11.8等低版本适配问题。手把手教你避开常见安装陷阱,实现高效Demo运行。

weixin_30642561的博客 1407

消除文法的左递归

1.试验目的 输入:任意的上下文无关文法。 输出:消除了左递归的等价文法。 2.实验原理 1.直接左递归的消除 消除产生式中的直接左递归是比较容易的。例如假设非终结符P的规则为 P→Pα / β 其中,β是不以P开头的符号串。那么,我们可以把P的规则改写为如下的非直接左递归形式:                   P→βP’

lvting470484446的专栏 3万+

Pytorch实现之SRGAN+CBAM的结构设计

在SRGAN的残差连接中加入了CBAM注意力机制,同时设计了四类损失来训练。

LJ1147517021的博客 574

【推荐100个unity插件】帮助你快速开发一款FPS游戏—— FPS Framework

FPS Framework 快速入门指南 FPS Framework 是一个 Unity 开发框架,可加速 FPS 游戏开发。主要功能包括: 第一人称控制器:基于 Character Controller 实现,提供移动、跳跃、下蹲等功能,支持自定义参数调整 渲染管线转换:内置 RP 转换器,支持 URP/HDRP 等渲染管线一键切换 库存系统: 采用双列表管理:物品列表(Items)和可收集物列表(Collectables) 支持自定义库存物品和可收集物类型 提供拾取/丢弃功能实现 快速开始: 通过预制件

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2571

消除左递归c++代码_读懂递归算法

递归的学习绝对是一个持久战,没有人可以一蹴而就,要循循渐进。一:什么是递归所谓递归,简单点来说,就是一个函数直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。我们可以把” 递归 “比喻成 “查字典 “,当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词。可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个...

weixin_39929254的博客 389

华为云计算——FusionCompute创建虚拟机

华为云计算——FusionCompute创建虚拟机

jks212454的博客 3680

消除左递归c++代码_一文速懂递归算法

一:什么是递归所谓递归,简单点来说,就是一个函数直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。我们可以把" 递归 "比喻成 "查字典 ",当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词。可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退...

weixin_39801465的博客 290

【生信分析】clusterProfiler: universal enrichment tool for functional and comparative study(1)

clusterProfiler: universal enrichment tool for functional and comparative studyClusterProfiler: 用于功能和比较研究的通用富集工具总览1. 引言1.1 术语1.1.1 基因集和通路1.1.2 基因同源(GO)1.1.3 京都基因与基因组百科全书(KEGG)1.1.4 其他基因集2. 功能富集分析方法2.1 过度表征分析(Over Representation Analysis)2.2 基因集富集分析(Gene Se

小哲的博客 1367

懒人必备!Coze一键制作火柴人心理学视频,新号45天涨了2.6w粉!(附超详细实战教程)

其实,只需要借助扣子(https://www.coze.cn/),采用的是 AI 智能体工作流模式,这种模式能够一站式搞定上述所有环节,一条四五十秒的视频,短短一两分钟就能轻松搞定!让制作效率提升了整整百倍!在这篇教程里,我将毫无保留地为大家分享,如何使用扣子 Coze 批量制作 “火柴人风格的心理学视频” 的超详细步骤。

李同学Lino的博客 3859

消除左递归c++代码_算法素颜(第8篇):史上最猛之递归屠龙奥义

创作时间:2019-05-03作者:周林版权所有,转载请联系作者获取授权、并注明作者与出处今日头条同步链接周林的简书主页周林的优快云博客主页周林的知乎主页引言本系列的第6篇《再不会“降维打击”你就Out了!》讲述了递归算法的意义、套路,第7篇《神力加身!动态编程》讲述了递归算法的优化,但是在大量的实际项目、工程和大家关心的求职面试中,却会碰到大量消除递归的需求。于是产生了两个问题:1. 为什么会...

weixin_39523280的博客 101

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

消除左递归c++代码_数据结构+算法(第08篇):史上最猛之递归屠龙奥义

点击上方“Java研发军团”,选择“置顶公众号”关键时刻,第一时间送达!阅读本文需要5分钟引言本系列的第6篇《再不会“降维打击”你就Out了!》讲述了递归算法的意义、套路,第7篇《神力加身!动态编程》讲述了递归算法的优化,但是在大量的实际项目、工程和大家关心的求职面试中,却会碰到大量消除递归的需求。于是产生了两个问题:1. 为什么会有消除递归的需求?2. 如果都采用非递归的方式,那么递归...

weixin_39784263的博客 168

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

c++消除左递归文法_FBI Tree递归算法优化【数据结构与算法】by 306024

【题目描述】 把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:1) T的...

weixin_39688378的博客 126

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

消除左递归c++代码_【原创连载】算法素颜(第8篇):史上最猛之递归屠龙奥义...

引言本系列的第6篇《再不会“降维打击”你就Out了!》讲述了递归算法的意义、套路,第7篇《神力加身!动态编程》讲述了递归算法的优化,但是在大量的实际项目、工程和大家关心的求职面试中,却会碰到大量消除递归的需求。于是产生了两个问题:1. 为什么会有消除递归的需求?2. 如果都采用非递归的方式,那么递归算法的独特价值又是什么呢?本文以此为引子,将以你在任何其他算法书中都不会看到的方式,向你揭示递归的高...

weixin_39732866的博客 249

消除左递归c++代码_【每日算法Day 85】图解算法:一行代码解决约瑟夫环的变体...

题目链接LeetCode 390. 消除游戏[1]题目描述给定一个从 到 排序的整数列表。 首先,从左到右,从第一个数字开始,每隔一个数字进行删除,直到列表的末尾。 第二步,在剩下的数字中,从右到左,从倒数第一个数字开始,每隔一个数字进行删除,直到列表开头。 我们不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。 返回长度为 的列表中,最后剩下的数字。示例1输入: n = 9,...

weixin_39750731的博客 93

合工大 编译原理 实验二

合工大 编译原理实验二 LL(1)文法 本实验为必做实验,使用C++开发,利用Windows API制作了简易的界面。 基本功能: 支持自定义文法 多个显示窗口,支持显示FIRST集、FOLLOW集、状态转换表、分析表 支持直接/间接左递归文法转化为LL(1)文法后识别 详细功能,示例截图、项目代码请见GitHub页面:LL(1)文法 部分核心代码如下: 消除直接/间接左递归 /*************************************************************

wjh776a68的博客 1959

c\c++编译原理实现消除直接\间接左递归,first集,follow集,预测分析表,主控程序

#include<iostream> #include<map> #include<list> #include<vector> #include<stdio.h> #include<set> #include<string> #include<stack> using namespace std; typedef struct { string left; string right[200];

qq_26011155的博客 618

编译原理——相关代码-记录

关于左递归的算法

qq_44918665的博客 339

LL(1)语法分析器 C++ 实现:从文法文件到分析表构建的 5 个核心步骤

本文详细介绍了使用C++实现LL(1)语法分析器的5个核心步骤,包括文法文件解析、First集与Follow集计算、分析表构建、预测分析算法实现及交互式演示。重点讲解了LL(1)分析表的构建方法,帮助开发者掌握编译原理中的关键语法分析技术。

weixin_34348174的博客 376
上一篇: vivado2018.3安装时遇到中文乱码。
下一篇: 谷歌浏览器百度搜索引擎输入后跳转到百度首页并且会吞掉输入内容
error_code007
博客等级 码龄8年 6粉丝 6原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值