java ll1文法分析,编译原理实验二 LL(1)分析法

一、 实验目的

通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区

别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方

法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质,为培

养适应社会多方面需要的能力。

二、 实验内容

根据某一文法编制调试 LL(1)分析程序,以便对任意输入的符号串进行分析。

构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。

分析法的功能是利用LL(1)控制程序根据显示栈栈顶

三、 LL(1)分析法实验设计思想及算法

对文法

math?formula=G的句子进行不含回溯的自上向下语法分析的充分必要条件是:

(1)文法不含左递归;

(2)对于文法中的每一个非终结符

math?formula=A的各个产生式的候选首符集两两不相交,即,若

8b777dd88ae7

8b777dd88ae7

(3)对于文法中的每一个非终结符,若它存在某个候选首符集包含,则

8b777dd88ae7

将满足上述条件的文法称为LL(1)文法。

一个LL(1)文法一定不是左递归的。因此要进行自下而上的LL(1)分析,那么首先要消除文法的左递归性。如果一个文法不含回路(is not cyclic,即不含有形如的推导),也不含有以为右部的产生式,那么执行以下的算法可以消除左递归。

消除左递归的算法:

(1)把文法的所有非终结符按任意一种顺序排列成,按此顺序执行(2)。

8b777dd88ae7

(3)化简由(2)所得的文法,即去除那些从开始符号出发永远无法到达的非终结符的产生规则。

同时,自上而下的LL(1)分析要求文法中的每一个非终结符的各个产生式的候选首符集两两不相交。当两者相交时,需要提取左公因子。算法如下:

提取左公因子算法:

对文法的每一个非终结符,执行下面的算法,直到文法中的每一个非终结符的各个产生式的候选首符集两两不相交。

假定关于某个非终结符的规则是

,其中,每个不以开头

将其改写成

8b777dd88ae7

8b777dd88ae7

First集合构造:

对每一文法符号构造,连续使用下面的规则,直至每个集合不再增大为止:

math?formula=X%E2%88%88V_T,则

math?formula=FIRST(X)%EF%BC%9D%5C%7BX%5C%7D

math?formula=X%E2%88%88V_N,且有产生式

math?formula=X%E2%86%92a%E2%8B%AF,则把

math?formula=a加入到

math?formula=FIRST(X)中;若

math?formula=X%E2%86%92%CE%B5也是一条产生式,则把

math?formula=%CE%B5也加到

math?formula=FIRST(X)中。

math?formula=X%E2%86%92Y%E2%8B%AF是一个产生式,且

math?formula=Y%E2%88%88V_N,则把

math?formula=FIRST(Y)中的所有非ε-元素都加到

math?formula=FIRST(X)中;若

math?formula=X%E2%86%92Y_1%20Y_2%E2%8B%AFY_k是一个产生式,

math?formula=Y_1%2C%E2%8B%AF%2CY_%7Bi-1%7D都是非终结符,而且,对于任何

math?formula=j,

math?formula=1%E2%89%A4j%E2%89%A4i-1

math?formula=FIRST(Y_j%20)都含有

math?formula=%CE%B5(即

math?formula=Y_1%20Y_2%E2%8B%AFY_%7Bi-1%7D%5Cstackrel%7B*%7D%7B%5CRightarrow%7D%CE%B5),则把

math?formula=FIRST(Y_j%20)中的所有非ε-元素都加到

math?formula=FIRST(X)中;特别是,若所有的

math?formula=FIRST(Y_j%20)均含有

math?formula=%CE%B5,

math?formula=j%3D1%2C2%2C%E2%8B%AF%2Ck,则把

math?formula=%CE%B5加到

math?formula=FIRST(X)中。

现在,我们能够对文法

math?formula=G的任何符号串

math?formula=%CE%B1%3DX_1%20X_2%E2%8B%AFX_n构造集合

math?formula=FIRST(%CE%B1)。首先,置

math?formula=FIRST(%CE%B1)%3DFIRST(X_1%20)%5Cbackslash%5C%7B%CE%B5%5C%7D;若对于任何

math?formula=1%E2%89%A4j%E2%89%A4i-1,

math?formula=%CE%B5%E2%88%88FIRST(X_j%20),则把

math?formula=FIRST(X_i%20)%5Cbackslash%5C%7B%CE%B5%5C%7D加至

math?formula=FIRST(%CE%B1)中;特别是,若所有的

math?formula=FIRST(Y_j%20)均含有

math?formula=%CE%B5,

math?formula=1%E2%89%A4j%E2%89%A4n,则把

math?formula=%CE%B5加到

math?formula=FIRST(%CE%B1)中。

Follow集合构造:

对于文法

math?formula=G的每个非终结符

math?formula=A构造

math?formula=FOLLOW(A)的算法是,连续使用下面的规则,直至每个

math?formula=FOLLOW不再增大为止:

对于文法的开始符号

math?formula=S,置#于

math?formula=FOLLOW(S)中;

math?formula=A%E2%86%92%CE%B1B%CE%B2是一个产生式,则把

math?formula=FIRST(%CE%B2)%5Cbackslash%5C%7B%CE%B5%5C%7D加至

math?formula=FOLLOW(B)中;

math?formula=A%E2%86%92%CE%B1B%CE%B2是一个产生式,或

math?formula=A%E2%86%92%CE%B1B%CE%B2是一个产生式而

math?formula=%CE%B2%E2%86%92%CE%B5 (即

math?formula=%CE%B5%E2%88%88FIRST(%CE%B2)),则把

math?formula=FOLLOW(A)加至

math?formula=FOLLOW(B)中。

预测分析表构造:

对于文法

math?formula=G,构造分析表

math?formula=M的算法是:

1.对文法

math?formula=G的每个产生式

math?formula=A%E2%86%92%CE%B1执行2和3;

2.对于每个终结符

math?formula=a%E2%88%88FIRST(%CE%B1),把

math?formula=A%E2%86%92%CE%B1加至

math?formula=M%5BA%2Ca%5D中;

3.若

math?formula=%CE%B5%E2%88%88FIRST(%CE%B1),则对于任何的

math?formula=b%E2%88%88FOLLOW(A)

math?formula=A%E2%86%92%CE%B1加至

math?formula=M%5BA%2Cb%5D中;

4.把所有无定义的

math?formula=M%5BA%2Ca%5D标上错误标志。

一个文法

math?formula=G的预测分析表

math?formula=M不含多重定义入口,当且仅当这个文法是LL(1)的。

四、 详细的算法描述

First集合构造

对于规则3,具有以下规律:

规则3的三条规则(3-1, 3-2, 3-3)的成立条件是以前一条规则成立为基础的。对于规则3-2,若规则3-1不成立,也就是

math?formula=X%E2%86%92Y%E2%80%A6

math?formula=Y不是非终结符,显然

math?formula=X%E2%86%92Y_1%20Y_2%20%E2%80%A6%20Y_n

math?formula=Y_1不会是非终结符,也就是3-2不成立。对于规则3-2内部,若

math?formula=X%E2%86%92Y_1%20Y_2%20%E2%80%A6%20Y_k%20Y_%7Bk%2B1%7D%20%E2%80%A6%20Y_n,若

math?formula=Y_k不是非终结符,那么对于

math?formula=Y_%7Bk%2B1%7D来说,前面的符号都不是非终结符,也就是规则3-2不成立。同理可得,规则3-2是规则3-3的前提条件。

以下是上述算法的略微形式化的描述:

/* 规则1 */

1. for-each 文法的终结符X

将First(X)置为{X}

/* 规则2 */

2. for-each文法的非终结符X

如果X含有X->a,a为非终结符,那么将a加入到First(X)。

/* 连续使用规则3,直至每个文法符号的First集不再增大为止 */

3. 设置标记modified,查看是否上一次First集有增大。

4. while modified do

还原modified

for-each 文法的非终结符X:

Lable1:

for-each文法的产生式:

/* 规则3-1 */

if 文法的产生式首位不是非终结符 continue

else 文法产生式为X->Y…,将First(Y)的非ε元素加到Fisrt(X)中,并检查First(X)的长度是否有变化,有变化,置位modified

/* 规则3-2 */

for-each 产生式右部的文法符号Y:

if Y不是非终结符 continue Lable1

else 将First(Y)的非ε元素加到Fisrt(X)中,并检查First(X)的长度是否有变化,有变化,置位modified

/* 规则3-3 */

将ε加到Fisrt(X)中,并检查First(X)的长度是否有变化,有变化,置位modified

5. 算法结束

将一个普通的文法转换为一个LL(1)文法

大致分为两大部分,第一大部分是消除左递归,第二大部分是提取左公因子。下面给出这个方法的略微形式化的描述:

1. 将非终结符进行排序,储存在tempVn中

2. for-each P_i in tempVn:

for-each j in range(1, i-1):

for-each P_i的产生式Pro:

if Pro以P_j开头

把P_j的所有规则带入到P_i->P_jγ中,并更新产生式Pro

改写P->Pα_1|Pα_2|…|α_m|β_1|β_2|…|β_n为P->β_1P'|β_2P'|...|β_nP',P'->α_1P'|α_2P'|…|α_mP'|ε。

3. 2中得到的文法可能含有多余的式子。下面通过新的Vn来替换未达到的文法。

do

置修改表示flag为false

for-each 2中得到的产生式:

将产生式中的所有非终结符加入到新的Vn中

若Vn大小发生变化,置flag为true

while flag

将Vn中的每个出现过的非终结符对应的产生式加入到新的产生式集合中

/* 以上步骤已经消除左递归,下面进行提左因子 */

4.

do

置左因子标志flag为false

for-each 文法的非终结符;

for-each 非终结符为左部的产生式:

以产生式右部的第一字母为键,计算以该字母为第一字母的产生式有多少个

根据结果置位flag

if 以该字母为第一字母的产生式不只有他自己:

/* 有左因子 */

将A->δβ_1|δβ_2|…|δβ_n|γ_1|γ_2|…|γ_m,改写为A->δA'|γ_1|γ_2|…|γ_m,A'->β_1|β_2|…|β_n。

while flag

5. 判断得到的文法的预测分析表是否含有多重入口来判断是否为LL(1)文法,从而得到结果。

预测分析的总控程序

begin

把#,文法的开始符号推入栈S

把第一个输入符号读进a

标志flag置为true

while true do

begin

把栈S的栈顶符号推出去放到X中

if X为非终结符

if X == a 把下一个输入符号读进a

else error

else if X是#

if X == a 置flag为false

else error

else if M[A, a] = {X->产生式右部}

if 产生式右部不是ε

将产生式右部逆序推入栈S

else error

end of while

stop

end

五、 源代码

仅给出核心部分

(1) GrammerSymbol.java

package exp2.grammer.symbol;

import exp2.grammer.exception.GrammerException;

import java.util.Objects;

import static java.lang.Character.isUpperCase;

/**

* 文法符号

*

* @version 2020-06-01

*/

public final class GrammerSymbol implements Comparable {

/* 文法符号储存在String中,可能的长度为1或者2 */

private final String symbol;

/* 空字对应的符号 */

public final static GrammerSymbol GS_EPSILON = new GrammerSymbol("\u03b5");

/**

* 从字符构造文法符号

*

* @param symbol 文法符号对应的字符

*/

public GrammerSymbol(char symbol) {

this.symbol = String.valueOf(symbol);

}

/**

* 从字符串构造文法符号

*

* @param symbol 文法符号对应的字符串

*/

public GrammerSymbol(String symbol) {

if (symbol == null) throw new NullPointerException();

if (symbol.length() > 2) throw new GrammerException("文法符的长度最大为2,而实际为" + symbol.length());

if (symbol.length() == 2 && (!isUpperCase(symbol.charAt(0)) || symbol.charAt(1) != '\''))

throw new GrammerException("非终结符必须是大写字母,或者是带有'的大写字母,而实际为" + symbol);

this.symbol = symbol;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || GrammerSymbol.class != o.getClass()) return false;

GrammerSymbol that = (GrammerSymbol) o;

return Objects.equals(symbol, that.symbol);

}

@Override

public int hashCode() {

return Objects.hash(symbol);

}

@Override

public String toString() {

return symbol;

}

@Override

public int compareTo(GrammerSymbol o) {

return this.symbol.compareTo(o.symbol);

}

/**

* 判断一个文法符号是不是非终结符,非终结符必须为大写字母,或者是带有'的大写字母

*

* @param gs 文法符号

* @return 若是非终结符,返回true,否则返回false

*/

public static boolean isNonterminal(GrammerSymbol gs) {

return isUpperCase(gs.symbol.charAt(0));

}

/**

* 判断一个文法符号是不是终结符,终结符应该为终结符是除大写字母和大写字母联合'外的其他非空可见字符

*

* @param gs 文法符号

* @return 若是非终结符,返回true,否则返回false

*/

public static boolean isTerminal(GrammerSymbol gs) {

return !isNonterminal(gs);

}

}

(2) GrammerSymbols.java

package exp2.grammer.symbol;

import java.util.*;

import static java.lang.Character.isUpperCase;

/**

* 文法符号序列

*

* @version 2020-06-01

*/

public final class GrammerSymbols implements Comparable, Iterable {

/* 储存文法符号序列 */

private final List value;

/* 文法符号序列对应的字符串 */

private final String valueString;

/**

* 从文法符号数组构造文法符号序列

*

* @param value 文法符号数组

*/

public GrammerSymbols(GrammerSymbol[] value) {

this.value = Collections.unmodifiableList(Arrays.asList(value));

StringBuilder sb = new StringBuilder();

for (GrammerSymbol gs : this.value)

sb.append(gs.toString());

this.valueString = sb.toString();

}

/**

* 从文法符号列表构造文法符号序列

*

* @param value 文法符号列表

*/

public GrammerSymbols(List value) {

this.value = Collections.unmodifiableList(value);

StringBuilder sb = new StringBuilder();

for (GrammerSymbol gs : this.value)

sb.append(gs.toString());

this.valueString = sb.toString();

}

/**

* 从文法符号序列字符串构造文法序列

*

* @param string 文法符号序列字符串

*/

public GrammerSymbols(String string) {

List value = new ArrayList<>();

int last = string.length() - 1;

for (int i = 0; i < last; ++i) {

char c = string.charAt(i);

if (isUpperCase(c)) {

if (string.charAt(i + 1) == '\'') {

value.add(new GrammerSymbol(c + "'"));

i += 1;

continue;

}

}

value.add(new GrammerSymbol(c));

}

if (string.charAt(last) != '\'') value.add(new GrammerSymbol(string.charAt(last)));

this.value = Collections.unmodifiableList(value);

this.valueString = string;

}

/**

* 返回序列的长度

*

* @return 序列的长度

*/

public int length() {

return value.size();

}

/**

* 取索引为index的文法符号

*

* @param index 索引

* @return 对应的文法符号

*/

public GrammerSymbol get(int index) {

try{

return value.get(index);

} catch (IndexOutOfBoundsException e) {

return null;

}

}

/**

* 根据给定的文法符号,匹配对应的索引

*

* @param gs 文法符号

* @return 如果找到,返回index,否则返回-1

*/

public int indexOf(GrammerSymbol gs) {

return value.indexOf(gs);

}

/**

* 根据给定的文法符号序列,匹配对应的索引首

*

* @param gs 文法符号序列

* @return 如果找到,返回index,否则返回-1

*/

public int indexOf(GrammerSymbols gs) {

return indexOf(value, value.size(),

gs.value, gs.value.size(), 0);

}

/**

* 根据给定的文法符号序列,匹配指定索引及以后的对应索引首

*

* @param gs 文法符号序列

* @param fromIndex 指定的开始索引

* @return 如果找到,返回index,否则返回-1

*/

public int indexOf(GrammerSymbols gs, int fromIndex) {

return indexOf(value, value.size(),

gs.value, gs.value.size(), fromIndex);

}

/**

* 根据给定的两个文法符号序列,匹配指定索引及以后的对应索引首

*

* @param source 原序列

* @param sourceCount 原序列的长度

* @param target 目标序列

* @param targetCount 目标序列的长度

* @param fromIndex 指定的开始索引

* @return 如果找到,返回index,否则返回-1

*/

static int indexOf(List source, int sourceCount,

List target, int targetCount,

int fromIndex) {

if (fromIndex >= sourceCount)

return (targetCount == 0 ? sourceCount : -1);

if (fromIndex < 0)

fromIndex = 0;

if (targetCount == 0)

return fromIndex;

GrammerSymbol first = target.get(0);

int max = (sourceCount - targetCount);

for (int i = fromIndex; i <= max; i++) {

/* 找到第一个文法符号匹配 */

if (!source.get(i).equals(first))

while (++i <= max && !source.get(i).equals(first));

/* 找到了第一个匹配,进行查看后面是否匹配 */

if (i <= max) {

int j = i + 1;

int end = j + targetCount - 1;

for (int k = 1; j < end && source.get(j).equals(target.get(k)); j++, k++);

if (j == end)

/* 整个字符串匹配 */

return i;

}

}

return -1;

}

/**

* 根据给定的索引,返回对应的子序列

*

* @param start 索引首

* @return sequence[start:]

*/

public GrammerSymbols subSequence(int start) {

return subSequence(start, value.size());

}

/**

* 根据给定的索引,返回对应的子序列

*

* @param start 索引首

* @param end 索引尾

* @return sequence[start:end)

*/

public GrammerSymbols subSequence(int start, int end) {

return new GrammerSymbols(value.subList(start, end));

}

@Override

public String toString() {

return valueString;

}

/**

* 返回序列中的所有非终结符号

*

* @return 所有非终结符号的集合

*/

public Set getVns() {

Set set = new TreeSet<>();

for (GrammerSymbol gs : value)

if (GrammerSymbol.isNonterminal(gs))

set.add(gs);

return set;

}

/**

* 返回序列中的所有终结符号

*

* @return 所有终结符号的集合

*/

public Set getVts() {

Set set = new TreeSet<>();

for (GrammerSymbol gs : value)

if (GrammerSymbol.isTerminal(gs))

set.add(gs);

return set;

}

@Override

public int compareTo(GrammerSymbols o) {

int lencmp = Integer.compare(this.value.size(), o.value.size());

if (lencmp != 0) return -lencmp;

return this.valueString.compareTo(o.valueString);

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

GrammerSymbols that = (GrammerSymbols) o;

return Objects.equals(valueString, that.valueString);

}

@Override

public int hashCode() {

return Objects.hash(valueString);

}

@Override

public Iterator iterator() {

return value.listIterator();

}

}

(3) Grammer.java

package exp2.grammer;

import exp2.grammer.exception.GrammerException;

import exp2.grammer.symbol.GrammerSymbol;

import exp2.grammer.symbol.GrammerSymbols;

import java.util.*;

import static exp2.grammer.symbol.GrammerSymbol.GS_EPSILON;

/**

* 文法

*

* @version 2020-06-01

*/

public class Grammer {

/* 终结符集合,在这里,我们假定终结符是除大写字母和大写字母联合'外的其他非空可见字符 */

final Set Vt;

/* 非终结符集合,在这里,我们假定非终结符是大写字母,或者是大写字母带有'字符 */

final Set Vn;

/* 文法的开始符号,一般来说为S或者S' */

final GrammerSymbol S;

/* 文法的产生式 */

final Map> Productions;

/**

* 从文法产生式输入构造一个文法

*

* @param src 文法输入

*/

public Grammer(String src) {

this(src.split("(\r\n)|(\n)|(\r)"));

}

/**

* 从文法产生式字符串数组构造一个文法

*

* @param srcs 文法字符串数组

*/

public Grammer(String[] srcs) {

if (srcs.length <= 0)

throw new GrammerException("文法构造时出错,输入的文法不应为空。");

this.S = new GrammerSymbol(srcs[0].split("->")[0]);

Set Vt = new TreeSet<>();

Set Vn = new TreeSet<>();

Map> Productions = new TreeMap<>();

for (String src : srcs) {

String[] items = src.split("->");

if (items.length != 2)

throw new GrammerException("文法构造时出错,输入的产生式不可能含有多个或不含有->。");

String left = items[0];

String right = items[1];

if ((left.length() > 2) || (left.length() == 0) || (left.length() == 2 && !left.endsWith("'")) || !(left.toUpperCase().equals(left)))

throw new GrammerException("文法构造时出错,输入的非终结符应当是大写字母,或者是带有'的大写字母。");

GrammerSymbol nonTerminal = new GrammerSymbol(left);

Vn.add(nonTerminal);

Set rights;

if (Productions.containsKey(nonTerminal))

rights = Productions.get(nonTerminal);

else {

rights = new TreeSet<>();

Productions.put(nonTerminal, rights);

}

for (String item : right.split("\\|")) {

String s = item.replaceAll("\\s*", "");

GrammerSymbols gss = new GrammerSymbols(s);

if (!s.equals(""))

rights.add(gss);

Vt.addAll(gss.getVts());

Vn.addAll(gss.getVns());

}

}

for (GrammerSymbol gs : Productions.keySet())

Productions.replace(gs, Collections.unmodifiableSet(Productions.get(gs)));

Vt.add(GS_EPSILON);

Vn.add(this.S);

this.Productions = Collections.unmodifiableMap(Productions);

this.Vt = Collections.unmodifiableSet(Vt);

this.Vn = Collections.unmodifiableSet(Vn);

}

/**

* 根据一个已经存在的文法构造一个副本

*

* @param grammer 已经存在的文法

*/

public Grammer(Grammer grammer) {

this.Productions = grammer.Productions;

this.S = grammer.S;

this.Vn = grammer.Vn;

this.Vt = grammer.Vt;

}

/**

* 从开始符号和产生式集合构造文法

*

* @param S 开始符号

* @param Productions 产生式集合

*/

public Grammer(GrammerSymbol S, Map> Productions) {

this.Productions = Collections.unmodifiableMap(Productions);

this.S = S;

Set Vt = new TreeSet<>();

Set Vn = new TreeSet<>();

for (GrammerSymbol gs : this.Productions.keySet()) {

Set set = this.Productions.get(gs);

for (GrammerSymbols gss : set) {

Vt.addAll(gss.getVts());

Vn.addAll(gss.getVns());

}

}

Vn.add(this.S);

Vt.add(GS_EPSILON);

this.Vt = Collections.unmodifiableSet(Vt);

this.Vn = Collections.unmodifiableSet(Vn);

}

public Set getVt() {

return Vt;

}

public Set getVn() {

return Vn;

}

public GrammerSymbol getS() {

return S;

}

public Map> getProductions() {

return Productions;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

Grammer grammer = (Grammer) o;

return Objects.equals(Vt, grammer.Vt) &&

Objects.equals(Vn, grammer.Vn) &&

Objects.equals(S, grammer.S) &&

Objects.equals(Productions, grammer.Productions);

}

@Override

public int hashCode() {

return Objects.hash(Vt, Vn, S, Productions);

}

@Override

public String toString() {

return "Grammer{" + "Vt=" + Vt +

", Vn=" + Vn +

", S=" + S +

", Productions=" + Productions +

'}';

}

}

(4) LL1Grammer.java

package exp2.grammer;

import exp2.grammer.exception.GrammerException;

import exp2.grammer.symbol.GrammerSymbol;

import exp2.grammer.symbol.GrammerSymbols;

import exp2.util.Pair;

import java.util.*;

import static exp2.grammer.symbol.GrammerSymbol.GS_EPSILON;

import static exp2.grammer.symbol.GrammerSymbol.isNonterminal;

/**

* LL(1)文法

*

* @version 2020-06-01

*/

public class LL1Grammer extends Grammer {

/* 文法的Fisrt集合 */

final Map> FirstSets;

/* 文法的Follow集合 */

final Map> FollowSets;

/* LL(1)文法的预测分析表 */

final Map> PATable;

/**

* 从一个已经存在的文法构造成LL(1)文法

*

* @param grammer 已经存在的文法

*/

public LL1Grammer(Grammer grammer) {

super(grammer);

Map> FirstSets = generateFirstSets();

for (GrammerSymbol gs : FirstSets.keySet())

FirstSets.replace(gs, Collections.unmodifiableSet(FirstSets.get(gs)));

this.FirstSets = Collections.unmodifiableMap(FirstSets);

Map> FollowSets = generateFollowSets();

for (GrammerSymbol gs : FollowSets.keySet())

FollowSets.replace(gs, Collections.unmodifiableSet(FollowSets.get(gs)));

this.FollowSets = Collections.unmodifiableMap(FollowSets);

Map, Set> PATable = generatePATable();

boolean isNotLL1 = false;

Map> LL1PATable = new TreeMap<>();

for (Pair pair : PATable.keySet()) {

Set set = PATable.get(pair);

isNotLL1 |= (set.size() > 1);

Iterator iter = PATable.get(pair).iterator();

GrammerSymbols grammerSymbols = iter.hasNext()?iter.next():null;

if (LL1PATable.containsKey(pair.value1))

LL1PATable.get(pair.value1).put(pair.value2, grammerSymbols);

else {

Map map = new TreeMap<>();

map.put(pair.value2, grammerSymbols);

LL1PATable.put(pair.value1, map);

}

}

if (isNotLL1) throw new GrammerException("该文法的预测分析表含有多重入口,不是LL(1)的。");

for (GrammerSymbol gs : LL1PATable.keySet())

LL1PATable.replace(gs, Collections.unmodifiableMap(LL1PATable.get(gs)));

this.PATable = Collections.unmodifiableMap(LL1PATable);

}

/**

* 构造一个LL(1)文法,并生成它的First,Follow集合以及预测分析表

*

* @param src 文法输入

*/

public LL1Grammer(String src) {

this(src.split("(\r\n)|(\n)|(\r)"));

}

/**

* 构造一个LL(1)文法,并生成它的First,Follow集合以及预测分析表

*

* @param srcs 文法字符串数组

*/

public LL1Grammer(String[] srcs) {

super(srcs);

Map> FirstSets = generateFirstSets();

for (GrammerSymbol gs : FirstSets.keySet())

FirstSets.replace(gs, Collections.unmodifiableSet(FirstSets.get(gs)));

this.FirstSets = Collections.unmodifiableMap(FirstSets);

Map> FollowSets = generateFollowSets();

for (GrammerSymbol gs : FollowSets.keySet())

FollowSets.replace(gs, Collections.unmodifiableSet(FollowSets.get(gs)));

this.FollowSets = Collections.unmodifiableMap(FollowSets);

Map, Set> PATable = generatePATable();

boolean isNotLL1 = false;

Map> LL1PATable = new TreeMap<>();

for (Pair pair : PATable.keySet()) {

Set set = PATable.get(pair);

isNotLL1 |= (set.size() > 1);

Iterator iter = PATable.get(pair).iterator();

GrammerSymbols grammerSymbols = iter.hasNext()?iter.next():null;

if (LL1PATable.containsKey(pair.value1))

LL1PATable.get(pair.value1).put(pair.value2, grammerSymbols);

else {

Map map = new TreeMap<>();

map.put(pair.value2, grammerSymbols);

LL1PATable.put(pair.value1, map);

}

}

if (isNotLL1) throw new GrammerException("该文法的预测分析表含有多重入口,不是LL(1)的。");

for (GrammerSymbol gs : LL1PATable.keySet())

LL1PATable.replace(gs, Collections.unmodifiableMap(LL1PATable.get(gs)));

this.PATable = Collections.unmodifiableMap(LL1PATable);

}

/**

* 产生文法的所有终结符和非终结符的First集合

*

* @return 由文法符号作为键,文法符号对应的First集合作为值的键值对构成的映射

*/

private Map> generateFirstSets() {

Map> FirstSets = new TreeMap<>();

Set firstX;

/* 规则1 若X∈Vt, 则First(X) = {X}*/

for (GrammerSymbol X : this.Vt) {

firstX = new TreeSet<>();

firstX.add(X);

FirstSets.put(X, firstX);

}

/* 规则2 若X∈Vn, 且有产生式X->a...,则把a加入到First(X)中 */

for (GrammerSymbol X : this.Vn) {

firstX = new TreeSet<>();

FirstSets.put(X, firstX);

Set Productions = this.Productions.get(X);

if (Productions == null) continue;

for (GrammerSymbols production : Productions) {

GrammerSymbol a = production.get(0);

if (GrammerSymbol.isTerminal(a))

firstX.add(a);

}

}

/* 连续使用规则3,直至每个文法符号的First集不再增大为止.

规则3-1 若X->Y...是一个产生式,且Y∈Vn,则把Fisrt(Y)中的所有非ε-元素都加到FIRST(X)中;

规则3-2 若X->Y_1Y_2...Y_k是一个产生式,Y_1,⋯,Y_(i-1)都是非终结符,而且,

对于任何j,1≤j≤i-1,First(Y_j)都含有ε(即Y_1Y_2...Y_(i-1)=*=>ε),则把First(Y_j )中的所有非ε-元素都加到First(X)中;

规则3-3 特别是,若所有的First(Y_j)均含有ε,j=1,2,⋯,k,则把ε加到First(X)中。

*/

boolean modified = true;

while (modified) {

modified = false;

for (GrammerSymbol X : this.Productions.keySet()) {

firstX = FirstSets.get(X);

Set Productions = this.Productions.get(X);

Label1:

for (GrammerSymbols production : Productions) {

/* 规则3-1 */

GrammerSymbol Y = production.get(0);

if (GrammerSymbol.isTerminal(Y)) continue;

Set firstY = new TreeSet<>(FirstSets.get(Y));

firstY.remove(GS_EPSILON);

int fslen = firstX.size();

firstX.addAll(firstY);

modified |= (fslen != firstX.size());

if (!FirstSets.get(Y).contains(GS_EPSILON)) continue;

/* 规则3-2 */

for (int i = 1; i < production.length(); ++i) {

Y = production.get(i);

if (GrammerSymbol.isTerminal(Y)) continue Label1;

firstY = new TreeSet<>(FirstSets.get(Y));

firstY.remove(GS_EPSILON);

fslen = firstX.size();

firstX.addAll(firstY);

modified |= (fslen != firstX.size());

if (!FirstSets.get(Y).contains(GS_EPSILON)) continue Label1;

}

/* 规则3-3 */

fslen = firstX.size();

firstX.add(GS_EPSILON);

modified |= (fslen != firstX.size());

}

}

}

return FirstSets;

}

/**

* 产生文法的所有非终结符的Follow集合

*

* @return 由文法符号作为键,文法中非终结符对应的Follow集合作为值的键值对构成的映射

*/

private Map> generateFollowSets() {

Map> FollowSets = new TreeMap<>();

Set FollowSet;

for (GrammerSymbol gs : this.Vn) {

FollowSet = new TreeSet<>();

FollowSets.put(gs, FollowSet);

}

/* 规则1 对于文法的开始符号S,置#于FOLLOW(S)中; */

FollowSets.get(this.S).add(new GrammerSymbol("#"));

boolean modified = true;

/* 连续使用规则2和3,直至每个Follow集不再增大为止. */

while (modified) {

modified = false;

for (GrammerSymbol A : Productions.keySet()) {

Set Productions = this.Productions.get(A);

for (GrammerSymbols production : Productions) {

GrammerSymbol B;

Set followB;

int fslen;

for (int i = 0; i < production.length() - 1; ++i) {

/* 规则2 若A→αBβ是一个产生式,则把FIRST(β)\{ε}加至FOLLOW(B)中; */

B = production.get(i);

if (GrammerSymbol.isTerminal(B)) continue;

followB = FollowSets.get(B);

GrammerSymbols beta = production.subSequence(i + 1, production.length());

Set fisrtSetBeta = this.FirstSet(beta);

boolean firstSetBetaHasEpsilon = fisrtSetBeta.contains(GS_EPSILON);

fisrtSetBeta.remove(GS_EPSILON);

fslen = followB.size();

followB.addAll(fisrtSetBeta);

modified |= (fslen != followB.size());

/* 规则3-1 若A→αBβ是一个产生式而β→ε (即εFirst(β)),则把Follow(A)加至Follow(B)中。 */

if (firstSetBetaHasEpsilon) {

fslen = followB.size();

followB.addAll(FollowSets.get(A));

modified |= (fslen != followB.size());

}

}

/* 规则3-2 若A→αB是一个产生式,则把Follow(A)加至Follow(B)中。 */

B = production.get(production.length() - 1);

if (GrammerSymbol.isTerminal(B)) continue;

followB = FollowSets.get(B);

fslen = followB.size();

followB.addAll(FollowSets.get(A));

modified |= (fslen != followB.size());

}

}

}

return FollowSets;

}

/**

* 返回对应文法字符串的First集合

*

* @param production 文法字符串

* @return 文法字符串production对应的First集合

*/

public Set FirstSet(GrammerSymbols production) {

/* 构造文法的一个任何符号串α的First集合 */

/* 规则1 置First(α)=First(X_1)\{ε}; */

GrammerSymbol gsY = production.get(0);

Set result = new TreeSet<>(this.FirstSets.get(gsY));

Set fsgsY;

result.remove(GS_EPSILON);

if (!FirstSets.get(gsY).contains(GS_EPSILON)) return result;

/* 规则2 若对于任何1≤j≤i-1,ε∈FIRST(X_j),则把FIRST(X_i)\{ε}加至FIRST(α)中; */

for (int i = 1; i < production.length(); ++i) {

gsY = production.get(i);

fsgsY = new TreeSet<>(FirstSets.get(gsY));

fsgsY.remove(GS_EPSILON);

result.addAll(fsgsY);

if (!FirstSets.get(gsY).contains(GS_EPSILON)) return result;

}

/* 规则3 特别是,若所有的First(Y_j)均含有ε,1≤j≤n,则把ε加到First(α)中。 */

result.add(GS_EPSILON);

return result;

}

/**

* 返回对应文法符号的First集合

*

* @param s 文法符号

* @return 文法符号s对应的Fisrt集合

*/

public Set FirstSet(GrammerSymbol s) {

return this.FirstSets.get(s);

}

/**

* 产生文法的预测分析表

*

* @return 文法的预测分析表M

*/

private Map, Set> generatePATable() {

Map, Set> PATable = new TreeMap<>();

Set Vt = new TreeSet<>(this.Vt);

Vt.remove(GS_EPSILON);

Vt.add(new GrammerSymbol("#"));

for (GrammerSymbol gsn : this.Vn)

for (GrammerSymbol gst : Vt)

PATable.put(new Pair<>(gsn, gst), new TreeSet<>());

/* 对文法G的每个产生式A->α */

for (GrammerSymbol A : this.Productions.keySet()) {

Set productions = this.Productions.get(A);

for (GrammerSymbols alpha : productions) {

Set firstSet = this.FirstSet(alpha);

for (GrammerSymbol a : firstSet)

/* 若ε∈FIRST(α),则对于任何的b∈FOLLOW(A)把A->α加至M[A,b]中 */

if (a.equals(GS_EPSILON)) {

Set followSet = this.FollowSet(A);

for (GrammerSymbol b : followSet)

PATable.get(new Pair<>(A, b)).add(alpha);

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

} else PATable.get(new Pair<>(A, a)).add(alpha);

}

}

return PATable;

}

/**

* 返回对应文法符号的Follow集合

* @param s 文法符号

* @return 文法符号s对应的Follow集合

*/

public Set FollowSet(GrammerSymbol s) {

return this.FollowSets.get(s);

}

@Override

public Set getVn() {

return super.getVn();

}

@Override

public GrammerSymbol getS() {

return super.getS();

}

@Override

public Set getVt() {

return super.getVt();

}

@Override

public Map> getProductions() {

return super.getProductions();

}

public Map> getFirstSets() {

return FirstSets;

}

public Map> getFollowSets() {

return FollowSets;

}

public Map> getLL1PATable() {

return this.PATable;

}

/**

* 判断一个文法是不是LL(1)的

* @param grammer 要判断的文法

* @return 如果文法是LL1的,返回true,否则返回false

*/

public static boolean isLL1Grammer(Grammer grammer) {

try {

LL1Grammer ll1Grammer = new LL1Grammer(grammer);

} catch (GrammerException e) {

return false;

}

return true;

}

/**

* 尝试将一个非LL(1)的文法转换为一个LL(1)文法

*

* @param grammer 一个普通的文法

* @return 是否能成功转换为LL(1)文法,如果是,那么返回转换后的文法,否则返回null

*/

public static LL1Grammer convertFrom(Grammer grammer) {

List tempVn = new ArrayList<>(grammer.getVn());

Set newVn = new TreeSet<>(tempVn);

Map> newMap = new TreeMap<>(grammer.Productions);

/* 对于每一个非终结符P_i */

for (int i = 0; i < tempVn.size(); ++i) {

GrammerSymbol P_i = tempVn.get(i);

Set newSet = new TreeSet<>();

/* 对于P_i的每一条规则 */

Set productions = newMap.get(P_i);

Set newProductions = new TreeSet<>(productions);

for (int j = 0; j < i; ++j) {

GrammerSymbol P_j = tempVn.get(j);

Set tempProductions = new TreeSet<>(newProductions);

for (GrammerSymbols production : tempProductions) {

/* 如果规则形如P_i->P_jγ */

if (production.indexOf(P_j) == 0) {

/* 把P_j的规则带入到P_i->P_jγ中 */

newProductions.remove(production);

String gammaString = production.subSequence(1).toString();

Set jProductions = newMap.get(P_j);

for (GrammerSymbols jProduction : jProductions)

newProductions.add(new GrammerSymbols(jProduction + gammaString));

}

}

}

/* 消除P_i的新规则中的所有左递归 */

Set newProductionHasLR = new TreeSet<>();

Set newProductionHasNoLR = new TreeSet<>();

for (GrammerSymbols newProduction : newProductions)

if (newProduction.indexOf(P_i) == 0)

newProductionHasLR.add(newProduction.subSequence(1));

else newProductionHasNoLR.add(newProduction);

if (newProductionHasLR.size() != 0) {

GrammerSymbol newSymbol = findNextNontermialinContext(P_i, newVn);

/* 所有的P->β_1P'|β_2P'|...|β_nP' */

for (GrammerSymbols beta : newProductionHasNoLR)

newSet.add(new GrammerSymbols(beta + newSymbol.toString()));

Set newSymbolSet = new TreeSet<>();

newMap.put(newSymbol, newSymbolSet);

for (GrammerSymbols alpha : newProductionHasLR)

newSymbolSet.add(new GrammerSymbols(alpha + newSymbol.toString()));

newSymbolSet.add(new GrammerSymbols(Collections.singletonList(GS_EPSILON)));

newVn.add(newSymbol);

}

/* 如果规则都不含左递归 */

else

newSet.addAll(newProductions);

newMap.replace(P_i, newSet);

}

/* 化简现在的文法 */

newVn = new TreeSet<>();

newVn.add(grammer.S);

boolean flag;

do {

flag = false;

for (GrammerSymbol Vn : newVn) {

Set set = newMap.get(Vn);

for (GrammerSymbols p : set) {

for (GrammerSymbol c : p) {

if (isNonterminal(c)) {

int fslen = newVn.size();

newVn.add(c);

flag |= (fslen != newVn.size());

}

}

}

}

} while (flag);

Map> tempMap = new TreeMap<>();

for (GrammerSymbol gs : newVn)

tempMap.put(gs, newMap.get(gs));

/* 以上步骤已经消除左递归,下面进行提左因子 */

/* 提左因子,直到没有左因子停止 */

do {

/* 假设没有左因子 */

flag = false;

Set curVn = new TreeSet<>(newVn);

for (GrammerSymbol gs : newVn) {

Set productions = tempMap.get(gs);

Map> counter = new TreeMap<>();

for (GrammerSymbols production : productions) {

GrammerSymbol first = production.get(0);

if (counter.containsKey(first))

counter.get(first).add(production);

else {

counter.put(first, new TreeSet<>());

counter.get(first).add(production);

}

}

Map> counterfilter = new TreeMap<>();

for (GrammerSymbol key : counter.keySet()) {

if (counter.get(key).size() > 1) {

counterfilter.put(key, counter.get(key));

}

}

/* 看看是否真的没有左因子 */

flag |= (counterfilter.size() > 0);

/* 如果有左因子,将A->δβ_1|δβ_2|...|δβ_n|γ_1|γ_2|...|γ_m

* 改写为A->δA'|γ_1|γ_2|...|γ_m

* A'->β_1|β_2|...|β_n

*/

if (counterfilter.size() > 0) {

for (GrammerSymbol delta : counterfilter.keySet()) {

GrammerSymbol A_ = findNextNontermialinContext(gs, curVn);

curVn.add(A_);

Set set = counterfilter.get(delta);

productions.removeAll(set);

productions.add(new GrammerSymbols(delta + A_.toString()));

Set secondSet = new TreeSet<>();

for (GrammerSymbols gss : set)

secondSet.add(gss.subSequence(1));

tempMap.put(A_, secondSet);

}

}

}

newVn.addAll(curVn);

} while (flag);

LL1Grammer ll1Grammer;

try {

Grammer temp = new Grammer(grammer.S, tempMap);

ll1Grammer = new LL1Grammer(temp);

} catch (GrammerException e) {

return null;

}

return ll1Grammer;

}

private static GrammerSymbol findNextNontermialinContext(GrammerSymbol prev, Set set) {

GrammerSymbol newSymbol;

/* 如果当前符号带',或者加上'后在set中,寻找一个不带'的大写字母代替 */

if (prev.toString().length() == 2) {

newSymbol = findNextNontermialNotinSet(set);

}

else {

newSymbol = new GrammerSymbol(prev.toString() + '\'');

if (set.contains(newSymbol)) {

newSymbol = findNextNontermialNotinSet(set);

}

}

return newSymbol;

}

private static GrammerSymbol findNextNontermialNotinSet(Set set) {

GrammerSymbol cur;

for (char c = 'A'; c <= 'Z'; ++c) {

cur = new GrammerSymbol(c);

if (!set.contains(cur))

return cur;

}

for (char c = 'A'; c <= 'Z'; ++c) {

cur = new GrammerSymbol(c + "'");

if (!set.contains(cur))

return cur;

}

throw new GrammerException("达到最大非终结符个数,无法产生新的非终结符。");

}

@Override

public String toString() {

return "LL1Grammer{" + "FirstSets=" + FirstSets +

", FollowSets=" + FollowSets +

", PATable=" + PATable +

", Vt=" + Vt +

", Vn=" + Vn +

", S=" + S +

", Productions=" + Productions +

'}';

}

}

(5) LL1Parser.java

package exp2.parser;

import exp2.grammer.Grammer;

import exp2.grammer.LL1Grammer;

import exp2.grammer.exception.GrammerException;

import exp2.grammer.symbol.GrammerSymbol;

import exp2.grammer.symbol.GrammerSymbols;

import exp2.util.*;

import java.util.*;

/**

* LL(1)预测分析器

*

* @version 2020-06-04

*/

public class LL1Parser {

/* 某个LL(1)文法 */

final LL1Grammer grammer;

/**

* 从某个一个存在的LL(1)文法构造LL(1)预测分析程序

*

* @param grammer 已经存在的LL(1)文法

*/

public LL1Parser(LL1Grammer grammer) {

this.grammer = grammer;

}

/**

* 从某个一个存在的文法构造LL(1)预测分析程序

*

* @param grammer 已经存在的文法

* @throws GrammerException 如果这个文法不是LL(1)的

*/

public LL1Parser(Grammer grammer) { this.grammer = new LL1Grammer(grammer); }

/**

* 采用给定的LL(1)文法{@link #grammer}分析字符串

*

* @param string 要分析的字符串

* @return 分析结果

*/

public List> parseString(String string) {

return parseGrammerSymbols(new GrammerSymbols(string));

}

/**

* 采用给定的LL(1)文法{@link #grammer}分析输入的文法符号序列

*

* @param input 要分析的文法符号序列

* @return 分析结果

*/

public List> parseGrammerSymbols(GrammerSymbols input) {

/* 符号栈, 剩余输入串, 所用产生式, 动作 */

List> snap = new LinkedList<>();

String inputString = input.toString();

String usedProduction = "";

Stack stack = new Stack<>();

StringBuilder action;

GrammerSymbol EOI = new GrammerSymbol("#");

GrammerSymbols Epsilon = new GrammerSymbols(Collections.singletonList(GrammerSymbol.GS_EPSILON));

/* 把#和文法开始符号推入栈中 */

stack.add(EOI);

stack.add(this.grammer.getS());

snap.add(new Quartet<>(stack.toString(), inputString, usedProduction, "INIT"));

int index = -1;

/* 把第一个输入符号读入a中 */

GrammerSymbol a = input.get(++index);

boolean flag = true;

while (flag) {

usedProduction = "";

/* 把栈顶符号托出去并放在X中 */

GrammerSymbol X = stack.pop();

action = new StringBuilder("POP");

/* 如果X在终结符且X==a,那么a指向下一个符号,否则出错 */

if (this.grammer.getVt().contains(X))

if (X.equals(a)) {

a = input.get(++index);

action.append(", GETNEXT");

}

else {

flag = false;

action.append(", ERROR");

}

/* 如果X==#并且a==#,程序分析结束,否则出错 */

else if (X.equals(EOI))

if (X.equals(a)) {

flag = false;

action.append(", SUCCESS");

}

else {

flag = false;

action.append(", ERROR");

}

else {

if (this.grammer.getLL1PATable().containsKey(X)) {

GrammerSymbols grammerSymbols = this.grammer.getLL1PATable().get(X).get(a);

/* 如果M[A,a]==null,表示出错 */

if (grammerSymbols == null) {

flag = false;

action.append(", ERROR");

}

/* 如果M[A,a]有产生式(不是Error),把产生式倒序推入栈 */

else {

usedProduction = X + "->" + grammerSymbols;

if (!grammerSymbols.equals(Epsilon)) {

action.append(", PUSH(");

for (int i = grammerSymbols.length() - 1; i >= 0; --i) {

GrammerSymbol g = grammerSymbols.get(i);

stack.add(g);

action.append(g.toString());

}

action.append(")");

}

}

}

/* 栈顶符号如果不是这几种其一,发生错误 */

else {

flag = false;

action.append(", ERROR");

}

}

/* 记录结果 */

snap.add(new Quartet<>(stack.toString(), inputString.substring(index), usedProduction, action.toString()));

}

return snap;

}

public LL1Grammer getGrammer() {

return grammer;

}

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 ()上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值