LL(1)文法:从文法的开始符,向下推导,推出句子。

对文法G的句子进行确定的自顶向下语法分析的充分必要条件是,G的任意两个具有相同左部的
产生式A—>α|β 满足下列条件:
(1)如果α、β均不能推导出ε,则 FIRST(α) ∩ FIRST(β) = ∅。
(2)α 和 β 至多有一个能推导出 ε。
(3)如果 β *═> ε,则 FIRST(α) ∩ FOLLOW(A) = ∅。
将满足上述条件的文法称为LL(1)文法。
 
一、消除左递归
由于自上而下的分析方法不允许文法含有左递归。
因此对于包含直接左递归和间接左递归的文法都要消除左递归。
直接消除左递归比较容易。
例如:
  P->Pa | b
直接消除左递归
  P->bP'
  P'->aP' | ε
 
二、提左因子
如果不提左因子,当面临两个相同的前缀,不知道选择哪条,必然会产生回溯。为了消除回溯,我们需要提左因子。
例如
 
 
三、实验

已知算术表达式文法 G[E]:

E → T E'

E' → + T E'|ε

T → F T'

T' → * F T'|ε

F → ( E )|i

判断该文法是否为 LL(1)文法,计算 FIRST 集合和 FOLLOW 集合

SELECT(E→T E')= FIRST(T)= {(, i}

SELECT(E'→+ T E')= {+}

SELECT(E'→ε)= FOLLOW(E')= {), #}

SELECT(T→F T')= FIRST(F)= {(, i}

SELECT(T' →* F T')= {*}

SELECT(T'→ε)= FOLLOW(T')= {+, ), #}

SELECT(F → ( E ))= {(}

SELECT(F → i)= {i}

具有相同左部产生式的 SELECT 集合交集为空

SELECT(E'→+ T E')∩SELECT(E'→ε)= {+}∩{), #}=Φ

SELECT(T' →* F T')∩SELECT(T'→ε) = {*}∩{+, ), #}=Φ

SELECT(F → ( E ))∩SELECT(F → i) = {(}∩{i}=Φ

所以,转换后的文法是 LL(1)文法。

此外,我们构造LL(1)分析表

表1-1 LL(1)分析表

i

+

*

#

E

E->TE’

E->TE’

E’

E’->+TE’

E’->ε

E’->ε

T

T->FT’

T->FT’

T’

T’->ε

T’->*FT’

T’->ε

T’->ε

F

F->i

F->(E)

 
程序如下:
 1 #include<bits/stdc++.h>
2 #define ROW 6
3 #define COLUMN 9
4 using namespace std;
5 string table[ROW][COLUMN]={
6 {"","(",")","*","+","-","/","i","#"},
7 {"E","Te","","","","","","Te",""},
8 {"e","","ε","","+Te","-Te","","","ε"},
9 {"T","Ft","","","","","","Ft",""},
10 {"t","","ε","*Ft","ε","ε","/Ft","","ε"},
11 {"F","(E)","","","","","","i",""}};
12 string Get_table(string x,string a){
13 string ans="";
14 for(int i=0;i<ROW;i++){
15 for(int j=0;j<COLUMN;j++){
16 if(x==table[i][0]&&a==table[0][j]){
17 ans=table[i][j];
18 return ans;
19 }
20 }
21 }
22 return ans;
23 }
24 bool check_LL1(string input){
25 bool flag=true;
26 stack < string > s;
27 s.push("#");
28 s.push("E");
29 int i=0;
30 string a=input.substr(i,1);
31 string x;
32 while(flag){
33 string RS;
34 x=s.top();
35 if(x==a && a=="#"){
36 break;
37 }else if(x==a && a!="#"){
38 s.pop();
39 i++;
40 a=input.substr(i,1);
41 }else if((RS=Get_table(x,a))!=""){
42 if(RS!="ε"){
43 s.pop();
44 for(int j=RS.length()-1;j>=0;j--){
45 string tmp=RS.substr(j,1);
46 s.push(tmp);
47 }
48 }else{
49 s.pop();
50 }
51 }else{
52 flag=false;
53 break;
54 }
55 }
56 return flag;
57 }
58 int main(){
59 string input;
60 while(cin>>input){
61 input=input+"#";
62 if(check_LL1(input)){
63 cout<<"correct"<<endl;
64 }else{
65 cout<<"error"<<endl;
66 }
67 }
68 return 0;
69 }

实验截图:

 
 

自上而下的LL(1)语法分析法的更多相关文章

  1. 《编译原理》-用例题理解-自底向上的语法分析,FIRSTVT,LASTVT集

    <编译原理>-用例题理解-自底向上的语法分析,FIRSTVT,LASTVT集 上一篇:编译原理-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法 本 ...

  2. 《程序设计语言——实践之路》【PDF】下载

    程序设计语言--实践之路>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382240 内容简介 本书在美国大学已有使用了十余年,目前被欧 ...

  3. 【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

    近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIR ...

  4. 编译原理学习笔记·语法分析(LL(1)分析法/算符优先分析法OPG)及例子详解

    语法分析(自顶向下/自底向上) 自顶向下 递归下降分析法 这种带回溯的自顶向下的分析方法实际上是一种穷举的不断试探的过程,分析效率极低,在实际的编译程序中极少使用. LL(1)分析法 又称预测分析法, ...

  5. TINY语言采用递归下降分析法编写语法分析程序

    目录 自顶向下分析方法 TINY文法 消左提左.构造first follow 基本思想 python构造源码 运行结果 参考来源:聊聊编译原理(二) - 语法分析 自顶向下分析方法 自顶向下分析方法: ...

  6. 编译原理实习(应用预测分析法LL(1)实现语法分析)

    #include<iostream> #include<fstream> #include<iomanip> #include<cstdio> #inc ...

  7. Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法

    Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...

  8. 语法设计——基于LL(1)文法的预测分析表法

    实验二.语法设计--基于LL(1)文法的预测分析表法 一.实验目的 通过实验教学,加深学生对所学的关于编译的理论知识的理解,增强学生对所学知识的综合应用能力,并通过实践达到对所学的知识进行验证.通过对 ...

  9. 语法分析~LL1的实现

    语法分析之 LL1分析法实现 一.设计目的 根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析.本次实验的目的主要是加深对预测分析LL(1)分析法的理解. 二.设计要求 程序输入/ ...

  10. K近邻法(KNN)原理小结

    K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...

随机推荐

  1. 深入理解Linux内核——内存管理(3)

    提要:本系列文章主要参考MIT 6.828课程以及两本书籍<深入理解Linux内核> <深入Linux内核架构>对Linux内核内容进行总结. 内存管理的实现覆盖了多个领域: ...

  2. 图解Spark Graphx基于connectedComponents函数实现连通图底层原理

    原创/朱季谦 第一次写这么长的graphx源码解读,还是比较晦涩,有较多不足之处,争取改进. 一.连通图说明 连通图是指图中的任意两个顶点之间都存在路径相连而组成的一个子图. 用一个图来说明,例如,下 ...

  3. Kali-Linux-配置开发环境

    本文主要讲解JDK.SDK.eclipse-adt.android studio.cpu模式TensorFlow 的安装配置.update:2019-08-30 03:31:46 JDK 当前系统jd ...

  4. ORACEL12C ORA-01033:ORACLE 正在初始化或关闭

    问题:客户端报ORA-01033 原因:oracle12C CDB启动,但是可拔插的PDB实例未启动 解决办法: sqlplus / as sysdba--系统管理员登录 alter session ...

  5. Oracle12C登录PDB容器

    Oracle12C登录PDB用户,此为12C的新特性 ①首先管理员身份登录 sqlplus / as sysdba;--管理员身份登录 show con_name;--查看此时连接容器 显示:CDB$ ...

  6. 解决在VS Code中运行有中文字符的Java代码(第三种方式),出现编码 GBK 的不可映射字符 (0x81)

    写代码时,我们不避免的会使用一些中文注释,这些在其他的语言中没有问题.但是在Java的注释里面如果有中文字符,就会报错.即使文件编码是utf-8也无济于事.是因为使用CMD运行java程序的时候,系统 ...

  7. PostgreSQL学习笔记-3.基础知识:CROSS、INNER、LEFT OUTER、RIGHT OUTER、FULL OUTER、UNION

    PostgreSQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段. 在 PostgreSQL 中,JOIN 有五种连接类型: CROSS JOIN :交叉连接INNER ...

  8. linux日常运维(三) GRUB 2的维护

    GRUB 2简介 GRUB GRUB是linux系统默认的引导加载程序.linux加载一个系统前,它必须有一个引导加载程序中特定指令(比如MBR记录)去引导系统.这个程序一般是位于系统的主硬盘驱动器或 ...

  9. 是因为不同的浏览器内核吗--Could not register service workers到底是怎么回事

    什么是浏览器内核 浏览器内核(Rendering Engine),是浏览器最核心的部分. 它负责处理网页的HTML.CSS.JavaScript等代码,并将其转化为可视化的网页内容.即我们常说的对网页 ...

  10. 火山引擎 ByteHouse:只需 2 个方法,增强 ClickHouse 数据导入能力

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 作为企业数字化建设的必备要素,易用的数据引擎能帮助企业提升数据使用效率,更好提升数据应用价值,夯实数字化建设基础. ...