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. mysql到底需不需要容器化?

    前言:在容器化的时代,当然一切皆可容器化.在docker官网首页赫然有下面这几个大字.足以知道docker的优势.那么且问,mysql适合跑在docker中吗? 当然,这个问题有人说可以,也有人说不可 ...

  2. CodeForces-1278B-A-and-B

    题意 对于\(t(1\leq t\leq 100)\)个测试点,给两个数\(a\)和\(b\),作如下操作: 第一次挑一个数使其加\(1\),第二次挑一个数使其加\(2\),以此类推,最后两个数相等, ...

  3. iframe标签下的通信

    通常在页面中嵌套iframe的情况下还需要进行消息传递的通信需求.一般分为两种情况: 1.iframe里的链接与父页面链接是非跨域 这种情况处理比较简单,直接在父级页面下就可以写脚本控制iframe里 ...

  4. antd/fusion表格增加圈选复制功能

    背景介绍 我们存在着大量在PC页面通过表格看数据业务场景,表格又分为两种,一种是 antd / fusion 这种基于 dom 元素的表格,另一种是通过 canvas 绘制的类似 excel 的表格. ...

  5. ArcGIS地图投影与坐标系转换的方法

      本文介绍在ArcMap软件中,对矢量图层或栅格图层进行投影(即将地理坐标系转为投影坐标系)的原理与操作方法.   首先,地理坐标系与投影坐标系最简单的区别就是,地理坐标系用经度.纬度作为空间衡量指 ...

  6. MapReduce和Spark读取HBase快照表

    1.概述 随着大数据技术的不断发展,处理海量数据的需求变得愈发迫切.MapReduce作为一种分布式计算模型,为处理大规模数据提供了有效的解决方案.在这篇博客中,我们将探讨如何使用MapReduce框 ...

  7. getchar()和putchar()

    #include <stdio.h> #include <stdlib.h> int main() { char ch; /*.putchar() a. putchar函数的格 ...

  8. 轻松掌握组件启动之Redis单机、主从、哨兵、集群配置

    单机配置启动 Redis安装 下载地址:http://redis.io/download 安装步骤: 1: 安装gcc编译器:yum install gcc 2: 将下载好的redis‐5.0.3.t ...

  9. 产品代码都给你看了,可别再说不会DDD(八):应用服务与领域服务

    这是一个讲解DDD落地的文章系列,作者是<实现领域驱动设计>的译者滕云.本文章系列以一个真实的并已成功上线的软件项目--码如云(https://www.mryqr.com)为例,系统性地讲 ...

  10. Java核心知识体系5:反射机制详解

    Java核心知识体系1:泛型机制详解 Java核心知识体系2:注解机制详解 Java核心知识体系3:异常机制详解 Java核心知识体系4:AOP原理和切面应用 1 介绍 无论是那种语言体系,反射都是必 ...