实验 2:语法分析程序的设计——以LL(1)为例(更适合njupt体质的宝宝)

实验 2:语法分析程序的设计——以LL(1)为例

PS:源码私聊

1.实验软件环境

​ 开发平台:Windows 11

​ 编程语言:C++

​ 编译器版本:GCC 11.20 C++20

​ IDE:VS Code

2.实验原理描述

在这里插入图片描述

F i r s t First First集合

对每一文法符号 X ∈ ( V n ∪ V t ) ∗ X∈(Vn\cup Vt)* X(VnVt)

①若 X ∈ V t ,则 F I R S T ( X ) = X X∈Vt ,则FIRST(X)={X} XVt,则FIRST(X)=X

②若 X ∈ V n ,且有产生式 X → a , a ∈ V t ,则 a ∈ F I R S T ( X ) X∈Vn ,且有产生式X→a,a∈Vt,则a∈FIRST(X) XVn,且有产生式XaaVt,则aFIRST(X)

③若 X ∈ V n , X → ε ,则 ε ∈ F I R S T ( X ) X∈Vn ,X→ε,则ε∈FIRST(X) XVnXε,则εFIRST(X)

④若 X ∈ V n , Y 1 , Y 2 , . . . , Y i ∈ V N X∈Vn,Y1,Y2,...,Yi ∈VN XVnY1Y2...YiVN

且有产生式 X → Y 1 , . . . , Y n X→Y1,...,Yn XY1,...,Yn

若对于 1 ≤ i ≤ k ≤ n 1≤i≤k≤n 1ikn,都有 Y i ∈ ε , Yi∈ε, Yiε, F I R S T ( Y k + 1 ) − ε ∈ F I R S T ( X ) FIRST(Yk+1)-{ε}∈FIRST(X) FIRST(Yk+1)εFIRST(X)

F O L L O W FOLLOW FOLLOW集合

①对文法开始符号 S ,将“ # ” ( 结束标记)置于 F O L L O W ( S ) 中。即 F O L L O W ( S ) = # 。 ( ∵ 有句型 # S # ) S ,将“ \# ” ( 结束标记) 置于 FOLLOW(S) 中。即 FOLLOW(S)= { \# } 。 ( ∵有句型 \#S\#) S,将“#”(结束标记)置于FOLLOW(S)中。即FOLLOW(S)=#(有句型#S#)

②若有 A → a B b ,则把 F I R S T ( β ) − ε 加至 F O L L O W ( B ) A→aBb,则把FIRST(β)-{ε}加至FOLLOW(B) AaBb,则把FIRST(β)ε加至FOLLOW(B)

③若有 A → a B A→aB AaB A → a B b A→aBb AaBb,而 b ∈ ε b∈ε bε ε ∈ F I R S T ( b ) ) ε∈FIRST(b)) εFIRST(b));则把 F O L L O W ( A ) FOLLOW(A) FOLLOW(A)加至 F O L L O W ( B ) FOLLOW(B) FOLLOW(B)中。

判断是否为 L L ( 1 ) LL(1) LL(1)文法

①文法 不包含左递归 ;
②对于文法中的每一个非终结符 A的各个产生式的 侯选首字符集两两不相交 。
③即 : 对于产生式 A → a ∣ b A→a| b Aab
b ≠ ε b ≠ ε b=ε, 则$ FIRST( a ) ∩ FIRST( b )= Ф$
b = ε b =ε bε , 则 F I R S T ( A ) ∩ F O L L O W ( A ) = Ф FIRST(A) ∩FOLLOW(A)=Ф FIRST(A)FOLLOW(A)=Ф
如果文法 G 满足以上条件,则称该文法 G 为 LL(1) 文法

3.功能实现描述

先分类 V n , V t Vn,Vt Vn,Vt

while (stream >> str) {
        char vnTem = str[0];
        vn.insert(vnTem);  // 生成非终结符
        string tem;
        for (int i = 1; i < str.size(); i++) {
            if (str[i] == ':' || str[i] == '=')
                continue;
            if (str[i] == '|') {
                production[vnTem].push_back(tem);
                rightSen.insert(tem);
                tem.clear();
                continue;
            }
            tem += str[i];
        }
        production[vnTem].push_back(tem);
        rightSen.insert(tem);
    }
    // 生成终结符
    for (auto i : production) {
        for (auto j : i.second) {
            for (auto ch : j) {
                if (vn.count(ch))
                    continue;
                vt.insert(ch);
                firstSet[ch].insert(ch);
            }
        }
    }

再生成First集合

// 生成First集合
void ShengChengFirst() {
    bool ok = true;
    while (ok) {
        ok = false;
        for (auto i : production) {
            char vnTem = i.first;
            int sz = (int)firstSet[vnTem].size();
            for (auto str : i.second) {
                if (str == "@") {  // 如果str只有空 则直接将空加入
                    firstSet[vnTem].insert('@');
                    break;
                }
                for (int j = 0; j < str.size(); j++) {
                    char ch = str[j];
                    // 如果是终结符号 则加入并退出
                    if (vt.count(ch)) {
                        firstSet[vnTem].insert(ch);
                        break;
                    }
                    // 不能推导为空时,将first集合加入并退出
                    if (!firstSet[ch].count('@')) {
                        addFirstFirst(vnTem, ch);
                        break;
                    }
                    // 如果能够推导为空 将出去空的first集合加入
                    addFirstFirst(vnTem, ch);
                    // 如果全部都能推导为空 加入空
                    if (j == str.size() - 1)
                        firstSet[vnTem].insert('@');
                }
            }
            if ((int)firstSet[vnTem].size() > sz)
                ok = true;
        }
    }
}

然后生成Follow集合

// 生成Follow集合
void ShengChengFollow() {
    followSet['E'].insert('#');
    bool ok = true;
    while (ok) {
        ok = false;
        for (auto i : production) {
            char vnTem = i.first;
            // 对于产生式 A -> aBc
            for (auto r : i.second) {  // 对于每个非终结符 产生式右块
                for (int j = 0; j < r.size(); j++) {
                    char ch = r[j];

                    if (vt.count(ch)) {  // 如果是终结符 跳过
                        continue;
                    }

                    // 如果是最后一个符号 将vnTem follow集合 加入到ch follow集合
                    if (j == r.size() - 1) {
                        int sz = followSet[ch].size();
                        addFollowFollow(ch, vnTem);
                        if (followSet[ch].size() > sz)
                            ok = true;
                        continue;
                    }

                    // 如果当前的下一个符号是终结符
                    if (vt.count(r[j + 1])) {
                        int sz = followSet[ch].size();
                        followSet[ch].insert(r[j + 1]);
                        if (followSet[ch].size() > sz)
                            ok = true;
                    }  // 如果是非终结符 将下一个符号的first集合除去空
                       // 加入到follow集合
                    else {
                        int sz = followSet[ch].size();
                        addFollowFirst(ch, r[j + 1]);
                        if (j + 1 == r.size() - 1 &&
                            firstSet[r[j + 1]].count('@'))
                            addFollowFollow(ch, vnTem);
                        if (followSet[ch].size() > sz)
                            ok = true;
                    }
                }
            }
        }
    }
}

接着生成LL(1)分析表

// 生成LL(1)分析表
void ShengChengTable() {
    vt.insert('#');
    for (auto i : vn) {
        for (auto j : vt) {
            FenXiTable[i][j] = {string("")};
        }
    }
    // 遍历文法
    for (auto i : production) {
        char vnTem = i.first;
        int sz = (int)firstSet[vnTem].size();
        for (auto str : i.second) {
            bool empty = false;
            for (auto first : firstSen[str]) {
                if (first == '@') {
                    empty = true;
                    continue;
                }
                FenXiTable[vnTem][first] = string(1, vnTem) + "::=" + str;
            }
            if (empty) {
                for (auto follow : followSet[vnTem]) {
                    FenXiTable[vnTem][follow] = string(1, vnTem) + "::=" + str;
                }
            }
        }
    }
}

最后再交互输入想要检验的字符串是否为文法中的句子

// 分析输入串
void FenXi(const string& str) {
    stack<char> FenXiStack;  // 分析栈
    stack<char> ShuRuStack;  // 输入栈
    FenXiStack.push('#');
    FenXiStack.push('E');
    ShuRuStack.push('#');
    for (int i = str.size() - 1; i >= 0; i--)
        ShuRuStack.push(str[i]);
    while (FenXiStack.size() && ShuRuStack.size()) {
        while (FenXiStack.size() && ShuRuStack.size() &&
               FenXiStack.top() == ShuRuStack.top())
            FenXiStack.pop(), ShuRuStack.pop();
        if (FenXiStack.empty() || ShuRuStack.empty())
            break;
        string tem = FenXiTable[FenXiStack.top()][ShuRuStack.top()];
        if (tem.empty())
            break;
        FenXiStack.pop();
        tem = tem.substr(4);
        for (int i = tem.size() - 1; i >= 0; i--) {
            if (tem[i] == '@')
                continue;
            FenXiStack.push(tem[i]);
        }
    }
    if (FenXiStack.size() || ShuRuStack.size()) {
        cout << "字符串:  " << str << "   不是该文法的句子!!" << endl;
    } else
        cout << "字符串:  " << str << "   是该文法的句子!!" << endl;
}

4.实验结果展示与分析

首先在同一文件夹下有一个 1. t x t 1.txt 1.txt文件,里面有符合条件的文法规则

在这里插入图片描述

接着运行 m a i n . c p p main.cpp main.cpp文件,在命令行中输入要打开的文法规则文件,即 1. t x t 1.txt 1.txt,按回车。在这里插入图片描述

接着命令行里面就会打印出 F i r s t , F E L L O W First,FELLOW First,FELLOW集合和 L L ( 1 ) LL(1) LL(1)文法分析表

在这里插入图片描述

同时,我们输入想检验的字符串,判断是否为该文法的句子

在这里插入图片描述

5.实验感想

通过这个实验,我对语法分析的重要性有了更深刻的认识,并学到了实现它的方法。LL(1)文法的特点使得语法分析过程简洁高效,它通过预测下一个输入符号和栈顶符号来进行分析,避免了回溯和冲突。这个实验不仅提升了我的代码设计能力,还加深了我对文法和语法规则的理解。通过手动构建LL(1)分析表和编写相应的程序,我深入了解了语法分析算法的工作原理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot数码论坛系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把数码论坛与现在网络相结合&#xff0c;利用java技术建设数码论坛系统&#xff0c;实现数码论坛的信息化。则对于进一步提高数码论坛发展&#xff0c;丰富数码论坛经验能起到不少的促进作用。 数码论坛系统能够通过互联网得到广泛…

如何判断售卖的医疗器械产品是二类还是三类

售卖医疗器械需关注产品本身是否为一、二、三类医疗器械。第一类医疗器械为一般项目的经营范围无需取得备案或许可证即可销售。第二类医疗器械产品需办理第二类医疗器械的备案方可销售。第三类医疗器械需取得医疗器械经营许可证且许可证上的经营范围需与销售的产品对应方可销售…

IIC协议

文章目录 IIC介绍通信距离通信速度主从方式通信方式物理结构 IIC协议空闲状态开始信号、结束信号和应答信号向从机发送数据的过程读取从机数据的过程数据有效性协议一帧构成 IIC介绍 IIC(Inter&#xff0d;Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线。…

ArkUI-X跨平台已至,何需其它!

运行环境 DevEco Studio&#xff1a;4.0Release OpenHarmony SDK API10 开发板&#xff1a;润和DAYU200 自从写了一篇ArkUI-X跨平台的文章之后&#xff0c;好多人都说对这个项目十分关注。 那么今天我们就来完整的梳理一下这个项目。 1、ArkUI-X 我们之前可能更多接触的…

class_5:在c++中一个类包含另一个类的对象叫做组合

#include <iostream> using namespace std;class Wheel{ public://成员数据string brand; //品牌int year; //年限//真正的成员函数void printWheelInfo(); //声明成员函数 };void Wheel::printWheelInfo() {cout<<"我的轮胎品牌是&#xff1a;"<…

MySQL之多表查询

1.创建student和score表 CREATE TABLE student ( id INT(10) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR(20) NOT NULL , sex VARCHAR(4) , birth YEAR, department VARCHAR(20) , address VARCHAR(50) ); 创建score表。SQL代码如下&#xff1a; CREATE TABLE sc…

数据库多表查询练习题

二、多表查询 1. 创建 student 和 score 表 CREATE TABLE student ( id INT ( 10 ) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR ( 20 ) NOT NULL , sex VARCHAR ( 4 ) , birth YEAR , department VARCHAR ( 20 ) , address VARCHAR ( 50 ) ); 创建 s…

02章【JAVA编程基础】

变量与标识符 变量 数学名词&#xff1a;变数或变量&#xff0c;是指没有固定的值&#xff0c;可以改变的数。变量以非数字的符号来表达&#xff0c;一般用拉丁字母。变量是常数的相反。变量的用处在于能一般化描述指令的方式。计算机解释&#xff1a;变量就是系统为程序分配…

IOS自动化测试元素定位

一、元素属性介绍 1、元素属性 2、查看各定位方式执行效率 二、iOS常用定位方法 1、accessibility_id 2、class_name 3、Xpath 4、ios_class_chain(类型链) 5、ios_predicate(谓词) 一个页面最基本组成单元是元素&#xff0c;想要定位一个元素&#xff0c;我们需…

德语B2 SampleAcademy

德语B2 SampleAcademy 一, Zweigliedrige Konnektion1, entweder... oder2, nicht nur... sondern auch3,sowohl... als auch4,einerseits... andererseits5, zwar...aber6, weder...noch7,je...desto/umso 一, Zweigliedrige Konnektion discontinuous conjunctions 1,…

基础面试题整理4

1.mybatis的#{}和${}区别 #{}是预编译处理&#xff0c;${}是字符串替换#{}可以防止SQL注入&#xff0c;提高安全性 2.mybatis隔离级别 读未提交 READ UNCOMMITED&#xff1a;读到了其他事务中未提交的数据&#xff0c;造成"脏读","不可重复读","幻读&…

Vue-19、Vue监测数据的原理_对象

1、数据代理 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>vue监测数据改变的的原理</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist…

翻译: Streamlit从入门到精通 部署一个机器学习应用程序 四

Streamlit从入门到精通 系列&#xff1a; 翻译: Streamlit从入门到精通 基础控件 一翻译: Streamlit从入门到精通 显示图表Graphs 地图Map 主题Themes 二翻译: Streamlit从入门到精通 构建一个机器学习应用程序 三 1. 5. 如何部署一个Streamlit应用 部署是将应用程序从开发…

如何用ArcGIS制作城市用地适应性评价

01概述 “城市用地适宜性评价是城市总体规划的一项重要前期工作&#xff0c;它首先对工程地质、社会经济和生态环境等要素进行单项用地适宜性评价&#xff0c;然后用地图叠加技术根据每个因子所占权重生成综合的用地适宜性评价结果&#xff0c;俗称“千层饼模式”。 做用地适…

C#,字符串匹配(模式搜索)AC(Aho Corasick)算法的源代码

Aho-Corasick算法简称AC算法&#xff0c;也称为AC自动机(Aho-Corasick)算法&#xff0c;1975年产生于贝尔实验室&#xff08;The Bell Labs&#xff09;&#xff0c;是一种用于解决多模式字符串匹配的经典算法之一。 the Bell Lab 本文的运行效果&#xff1a; AC算法以模式树…

阳光抑郁症测试

大部分人对抑郁症的理解&#xff0c;就是每天无精打采&#xff0c;死气沉沉&#xff0c;可实际上&#xff0c;还有一种阳光抑郁症&#xff0c;完全不是这个样子。这种抑郁症的人&#xff0c;做事情非常有活力&#xff0c;魅力十足&#xff0c;给人感觉十分有自信&#xff0c;但…

MATLAB读取图片并转换为二进制数据格式

文章目录 前言一、MATLAB 文件读取方法1、文本文件读取2、二进制文件读取3、 图像文件读取4、其他文件读取 二、常用的图像处理标准图片链接三、MATLAB读取图片并转换为二进制数据格式1、matlab 源码2、运行结果 前言 本文记录使用 MATLAB 读取图片并转换为二进制数据格式的方…

国科大软件安全原理期末复习笔记

1 软件安全总论 1.软件的三大特性&#xff1a;复杂性、互连性、可扩展性&#xff1b; 2.基本概念&#xff1a;缺陷、漏洞、风险 缺陷&#xff08;bug&#xff09;&#xff1a;软件在设计和实现上的错误&#xff1b;漏洞&#xff08;vulnerability&#xff09;&#xff1a;漏洞…

专访美国Foley Hoag律师事务所合伙人:2024量子计算颠覆制药业

人物介绍&#xff1a;美国Foley Hoag 律师事务所的合伙人Erik Huestis&#xff0c;兼任该事务所技术行业小组的联席主席&#xff0c;近期于采访中深入探讨了在未来一年&#xff0c;生命科学和生物技术行业将如何运用量子计算技术的相关问题。 ​编辑丨慕一 编译/排版丨琳梦 卉…

OPT(erlang)打造一套缓存系统(一)

缓存的设计 这个简易缓存存储的是键/值对&#xff0c;其中键与键之间不得重复&#xff0c;并且每个键只能映射到一个值。这个设计背后的核心思想是为写人缓存的每一个值都分配一个独立的存储进程再将对应的键映射至该进程。你可能会对这种为每个值分配一个进程的设计感到惊讶&…