1.项目要求

文法要求:

(1)从文件读入,每条产生式占用一行

(2)文法为LL(1)文法

从文件中读入文法,从键盘上输入待分析的符号串,采用 LL(1)分析算法判断该符号串是否为该文法的句子。

2.实验思路:

首先实现集合FIRST(X)构造算法和集合FOLLOW(A)构造算法,再根据FIRST和FOLLOW集合构造出预测分析表,并对指定的句子打印出分析栈的分析过程,判断是否为该文法的句子。

3.实验原理

(1)first集的算法思想

如果产生式右部第一个字符为终结符,则将其计入左部first集

如果产生式右部第一个字符为非终结符执行以下步骤

求该非终结符的first集

将该非终结符的非$first集计入左部的first集

若存在$,则将指向产生式的指针右移

若不存在$,则停止遍历该产生式,进入下一个产生式

若已经到达产生式的最右部的非终结符,则将$加入左部的first集

处理数组中重复的first集中的终结符

(2)follow集的算法思想

对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止.

对于文法的开始符号S,置#于FOLLOW(S)中;

若A->aBb是一个产生式,则把FIRST(b)\{ε}加至FOLLOW(B)中;

若A->aB是一个产生式,或A->aBb是一个产生式而b=>ε(即ε∈FIRST(b))则把FOLLOW(A)加至FOLLOW(B)中

(3)生成预测分析表的算法思想

构造分析表M的算法是:

对文法G的每个产生式A->a执行第二步和第三步;

对每个终结符a∈FIRST(a),把A->a加至M[A,a]中;

若ε∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;

把所有无定义的M[A,a]标上出错标志.

(4)对符号串的分析过程

预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号行事的,对于任何(X,a),总控程序

每次都执行下述三种可能的动作之一;

若X=a=”#”,则宣布分析成功,停止分析过程.

若X=a≠”#”,则把X从STACK栈顶逐出,让a指向下一个输入符号.

若X是一个非终结符,则查看分析表M,若M[A,a]中存放着关于X的一个产生式,那么,首先把X逐出STACK栈顶,然后把产生式的右部符号串按反序一一推进STACK栈(若右部符号为ε,则意味着不推什么东西进栈).在把产生式的右部符号推进栈的同时应做这个产生式相应得语义动作,若M[A,a]中存放着”出错标志”,则调用出错诊察程序ERROR.

4.实验代码

#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include<cstring>
using namespace std;
map<char,int>getnum;
char getchar[100];         //获得对应字符
vector<string>proce;
int table[100][100];      //预测分析表
int num=0;int numvt=0;     //numvt是终结符集合,0是‘#’,numvt表空字
string first[100];
string follow[200];
void readin()
{memset(table,-1,sizeof(table));getnum['#']=0;getchar[0]='#';cout<<"请输入所有的终结符:"<<endl;char x;do{cin>>x;getnum[x]=++num;getchar[num]=x;}while(cin.peek()!='\n');numvt=++num;getnum['@']=numvt;        //kong zigetchar[num]=('@');cout<<"请输入所有非终结符:"<<endl;do{cin>>x;getnum[x]=++num;getchar[num]=x;}while(cin.peek()!='\n');cout<<"输入产生式集合(空字用‘@’表示),以‘end’结束:"<<endl;string pro;while(cin>>pro&&pro!="end"){string ss;ss+=pro[0];for(int i=3;i<pro.size();i++){if(pro[i]=='|'){proce.push_back(ss);ss.clear();ss+=pro[0];}else{ss+=pro[i];}}proce.push_back(ss);}
}
void jiaoji(string &a,string b)  //a=a or b   取a,b交集赋值给a
{set<char>se;for(int i=0;i<a.size();i++)se.insert(a[i]);for(int i=0;i<b.size();i++)se.insert(b[i]);string ans;set<char>::iterator it;for(it=se.begin();it!=se.end();it++)ans+=*it;a=ans;
}
string get_f(int vn,int & has_0)     //dfs:vn能推出的不含空字的vt集合,并且判断vn能否推出空字
{if(vn==numvt)has_0=1;if(vn<numvt)return first[vn];string ans;for(int i=0;i<proce.size();i++){if(getnum[proce[i][0]]==vn)ans+=get_f(getnum[proce[i][1]],has_0);}return  ans;
}
void getfirst()
{for(int i=1;i<=numvt;i++)     //终结符,first集是其本身。{first[i]+=('0'+i);}for(int j=0;j<proce.size();j++)    //扫描所有产生式{int k=0;int has_0=0;        //k扫瞄该产生式do{has_0=0;k++;if(k==proce[j].size())  //推到最后一个了,则附加空字{first[getnum[proce[j][0]]]+=('0'+numvt);break;}                     //合并之jiaoji(first[getnum[proce[j][0]]],get_f(getnum[proce[j][k]],has_0));}while(has_0);  //到无法推出空字为止}
}
void print_first()
{cout<<"first集:"<<endl;for(int i=1;i<=num;i++){cout<<"first ["<<getchar[i]<<"]: ";for(int j=0;j<first[i].size();j++)cout<<getchar[first[i][j]-'0']<<" ";cout<<endl;}cout<<endl;
}
void getfollow()
{jiaoji(follow[getnum[proce[0][0]]],"0");  //先添加‘#’;for(int j=0;j<proce.size();j++)       //扫所有产生式{for(int jj=1;jj<proce[j].size();jj++)   //每个非终结符的follow集{if(getnum[proce[j][jj]]<=numvt)continue;  //vt无follow集int k=jj; int has_0;do{has_0=0;k++;if(k==proce[j].size())   //都能推出空字,follow集=产生式左边的vn,{jiaoji(follow[getnum[proce[j][jj]]],follow[getnum[proce[j][0]]]);break;}jiaoji(follow[getnum[proce[j][jj]]],get_f(getnum[proce[j][k]],has_0));}while(has_0);}}
}
void gettable()          //得预测分析表
{for(int i=0;i<proce.size();i++)   //扫所有产生式{if(proce[i][1]=='@')     //直接推出空字的,特判下(follow集=产生式左边的vn中元素填){string flw=follow[getnum[proce[i][0]]];for(int k=0;k<flw.size();k++){table[getnum[proce[i][0]]][flw[k]-'0']=i;}}string temps=first[getnum[proce[i][1]]];for(int j=0;j<temps.size();j++)               //考察first集{if(temps[j]!=('0'+numvt)){table[getnum[proce[i][0]]][temps[j]-'0']=i;}else                                     //有空字的,考察follw集{string flw=follow[getnum[proce[i][1]]];for(int k=0;k<flw.size();k++){table[getnum[proce[i][0]]][flw[k]-'0']=i;}}}}
}
string get_proce(int i)  //由对应下标获得对应产生式。
{if(i<0)return " ";    //无该产生式string ans;ans+=proce[i][0];ans+="->";//ans+=(proce[i][0]+"->");  注意这样不行!思之即可。for(int j=1;j<proce[i].size();j++)ans+=proce[i][j];return ans;
}
void print_table()
{cout<<"预测分析表:"<<endl;for(int i=0;i<numvt;i++)cout<<'\t'<<getchar[i];cout<<endl;for(int i=numvt+1;i<=num;i++){cout<<getchar[i];for(int j=0;j<numvt;j++){cout<<'\t'<<get_proce(table[i][j]);}cout<<endl;}cout<<endl;
}
void print_follow()
{cout<<"follow集:"<<endl;for(int i=numvt+1;i<=num;i++){cout<<"follow ["<<getchar[i]<<"]: ";for(int j=0;j<follow[i].size();j++)cout<<getchar[follow[i][j]-'0']<<" ";cout<<endl;}cout<<endl;
}
string word;
bool analyze()       //总控,分析字word的合法性,若合法,输出所有产生式。
{stack<char>sta;sta.push('#');sta.push(proce[0][0]);int i=0;while(!sta.empty()){int cur=sta.top();sta.pop();if(cur==word[i])       //是终结符,推进{i++;}else  if(cur=='#')   //成功,结束{return 1;}else  if(table[getnum[cur]][getnum[word[i]]]!=-1) //查表{int k=table[getnum[cur]][getnum[word[i]]];cout<<proce[k][0]<<"->";for(int j=1;j<proce[k].size();j++)cout<<proce[k][j];cout<<endl;for(int j=proce[k].size()-1;j>0;j--)  //逆序入栈{  if(proce[k][j]!='@')sta.push(proce[k][j]);}}else      //失败!{return 0;}}return 1;
}
int main()
{readin();getfirst();getfollow();getfollow();gettable();print_first();print_follow();print_table();cout<<"请输入字:"<<endl;cin>>word;if(analyze())cout<<"succeed!该字有效,所用产生式如上。"<<endl;else   cout<<"error!"<<endl;return 0;
}

实验输入及程序运行输出结果:

【编译原理】LL(1)语法分析器相关推荐

  1. 编译原理实验-LL1语法分析器(自动生成First集、Follow集求法)java实现

    编译原理实验-LL1语法分析器(自动生成First.Follow)java 博主在做实验时,参考众多他人代码,发现bug众多,在@moni_mm代码基础上,与伙伴把能看到的BUG都做出修正,同时增添了 ...

  2. 【编译原理】LR语法分析器的设计与实现

    LR语法分析器的设计与实现 本文为当时编译原理实验作业,要求用设计的思想完成,小题大做,仅供参考 文章目录 LR语法分析器的设计与实现 实验要求 实现功能 输入输出 样例 一.LR语法分析器问题定义 ...

  3. 【编译原理】词法分析器语法分析器

    简单编译器设计 采用Java语言对C++语言进行编译,具体的简单编译器设计 词法分析器-扫描器的设计与实现 基本符号表 状态转换图 代码实现 import java.io.*; import java ...

  4. 编译原理 LL(1)语法分析器的设计与实现

    实验内容 针对SysY语言中简单算术表达式文法G[E]: E→TE' E'→ATE'|ε T→FT' T'→MFT' |ε F→(E) | i A → + | - M → * | / 求解相应的FIR ...

  5. 编译原理之简单语法分析器(c语言)

    语法分析是编译过程的核心部分,其基本任务是根据语言的语法规则进行语法分析,如果不存在语法错误即给出正确的语法结果,并为语义分析和代码生成做准备. 语法分析器的两种方式 语法分析器的任务主要是确定是否可 ...

  6. 编译原理 实验2 语法分析器的构造

    [实验目的] 练习构造语法分析程序的方法,熟悉上下文无关文法的使用,加深对课堂教学的理解:提高词法分析方法的实践能力 [实验要求] 利用某一高级程序设计语言构造语法分析程序 [具体要求]对于给定的文法 ...

  7. 编译原理LR(1)语法分析器 C++实现

    LR(1)语法分析器 C++语言编写,已通过VS2019调试 文章目录 LR(1)语法分析器 一.测试结果 二.测试文件 三.核心代码 四.完整代码 感谢阅读! 如有错误,恳请指正! 一.测试结果 二 ...

  8. 编译原理-5-LL(1)语法分析器

    LL(1)语法分析器 1. 什么是LL(1)语法分析器 自顶向下的.递归下降的.预测分析的.适用于LL(1)文法的LL(1)语法分析器 自顶向下构建语法分析树 根节点是文法的起始符号SSS 每个中间节 ...

  9. 贵州大学-编译原理实验2-句法分析器

    贵州大学-编译原理实验2-句法分析器 考虑下面的C语言子集的文法,其中<>括起来的为非终结符,粗体为终结符. ® <statement_list> <statement_ ...

  10. 编译原理--语法制导的翻译

    前言 把一些属性附加到代表语言构造的文法符号上, 以把信息和一个语言的构造联系起来. 通过语义规则来说明文法符号的属性值如何确定. 产生式 语义规则 E -> E_{1} + T E.code ...

最新文章

  1. ajax异步提交 java_jquery ajax异步提交表单数据的方法
  2. 智源成立面向可持续发展的人工智能智库并发布公益研究计划
  3. load data with matlab
  4. ssd网络结构_SSD论文与代码详解
  5. Android开发 - 解决DialogFragment在全屏时View被状态栏遮住的问题
  6. Shader Compilation for Multiple Platforms
  7. Linux - alias 定义的变量
  8. View 的 android:visibility属性的讨论
  9. word里双横线怎么打_美人计 | 精致打工人秀智,教你内双怎么化
  10. LeetCode 167. Two Sum II - Input array is sorted
  11. 真真真真真签到题(计算几何)
  12. python opencv录制视频_Python-OpenCV 处理视频(一)(二): 输入输出 视频处理
  13. 3D视觉(二)四元数简要说明
  14. delphi 分析抓取html,delphi网页数据抓取
  15. 使电动机反转的matlab仿真图,基于MATLAB的电机仿真研究
  16. 2014年实习生招聘之腾讯实习生招聘面试(一面)—2014/04/01
  17. 阳春三月来几个python基础吧
  18. mysql索引,索引结构,索引类型,索引失效
  19. 不把鸡蛋放在一个篮子里面
  20. 【专利转让】掌纹识别、图像复原、人脸检测定位相关领域

热门文章

  1. linux下udev详解
  2. 大数据毕设 地铁客流分析与可视化系统
  3. ELK集群部署(六)之Kafka操作
  4. HTML Table之展开收起
  5. 【文本展开收起】uniapp—实现文本的展开与收起功能
  6. RHEL8安装podman
  7. 交换机开发(一)—— 交换机的工作原理
  8. 24点(给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利)
  9. mysqldump逻辑备份
  10. 三维重建技术(2)各种方法简介