编译原理实验二 LL(1)分析法

一、 实验目的

通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质,为培养适应社会多方面需要的能力。

二、 实验内容

根据某一文法编制调试 LL(1)分析程序,以便对任意输入的符号串进行分析。
构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。
分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。

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

对文法G的句子进行不含回溯的自上向下语法分析的充分必要条件是:
(1)文法不含左递归;
(2)对于文法中的每一个非终结符A的各个产生式的候选首符集两两不相交,即,若



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

将满足上述条件的文法称为LL(1)文法。
一个LL(1)文法一定不是左递归的。因此要进行自下而上的LL(1)分析,那么首先要消除文法的左递归性。如果一个文法不含回路(is not cyclic,即不含有形如P\stackrel{+}{\Rightarrow}P的推导),也不含有以\varepsilon为右部的产生式,那么执行以下的算法可以消除左递归。
消除左递归的算法:
(1)把文法G的所有非终结符按任意一种顺序排列成P_1, P_2, ..., P_n,按此顺序执行(2)。

(3)化简由(2)所得的文法,即去除那些从开始符号出发永远无法到达的非终结符的产生规则。
同时,自上而下的LL(1)分析要求文法中的每一个非终结符的各个产生式的候选首符集两两不相交。当两者相交时,需要提取左公因子。算法如下:
提取左公因子算法:
对文法的每一个非终结符,执行下面的算法,直到文法中的每一个非终结符的各个产生式的候选首符集两两不相交。
假定关于某个非终结符A的规则是
A→δβ_1 |δβ_2 |…|δβ_n | γ_1 |γ_2 |…|γ_m,其中,每个γ不以δ开头
将其改写成


First集合构造:
对每一文法符号X∈V_T∪V_N构造FIRST(X),连续使用下面的规则,直至每个集合FIRST不再增大为止:

  1. X∈V_T,则FIRST(X)=\{X\}
  2. X∈V_N,且有产生式X→a⋯,则把a加入到FIRST(X)中;若X→ε也是一条产生式,则把ε也加到FIRST(X)中。
  3. X→Y⋯是一个产生式,且Y∈V_N,则把FIRST(Y)中的所有非ε-元素都加到FIRST(X)中;若X→Y_1 Y_2⋯Y_k是一个产生式,Y_1,⋯,Y_{i-1}都是非终结符,而且,对于任何j,1≤j≤i-1FIRST(Y_j )都含有ε(即Y_1 Y_2⋯Y_{i-1}\stackrel{*}{\Rightarrow}ε),则把FIRST(Y_j )中的所有非ε-元素都加到FIRST(X)中;特别是,若所有的FIRST(Y_j )均含有ε,j=1,2,⋯,k,则把ε加到FIRST(X)中。
    现在,我们能够对文法G的任何符号串α=X_1 X_2⋯X_n构造集合FIRST(α)。首先,置FIRST(α)=FIRST(X_1 )\backslash\{ε\};若对于任何1≤j≤i-1,ε∈FIRST(X_j ),则把FIRST(X_i )\backslash\{ε\}加至FIRST(α)中;特别是,若所有的FIRST(Y_j )均含有ε,1≤j≤n,则把ε加到FIRST(α)中。

Follow集合构造:
对于文法G的每个非终结符A构造FOLLOW(A)的算法是,连续使用下面的规则,直至每个FOLLOW不再增大为止:

  1. 对于文法的开始符号S,置#于FOLLOW(S)中;
  2. A→αBβ是一个产生式,则把FIRST(β)\backslash\{ε\}加至FOLLOW(B)中;
  3. A→αBβ是一个产生式,或A→αBβ是一个产生式而β→ε (即ε∈FIRST(β)),则把FOLLOW(A)加至FOLLOW(B)中。
    预测分析表构造:
    对于文法G,构造分析表M的算法是:
    1.对文法G的每个产生式A→α执行2和3;
    2.对于每个终结符a∈FIRST(α),把A→α加至M[A,a]中;
    3.若ε∈FIRST(α),则对于任何的b∈FOLLOW(A)A→α加至M[A,b]中;
    4.把所有无定义的M[A,a]标上错误标志。
    一个文法G的预测分析表M不含多重定义入口,当且仅当这个文法是LL(1)的。

四、 详细的算法描述

  1. First集合构造
    对于规则3,具有以下规律:
    规则3的三条规则(3-1, 3-2, 3-3)的成立条件是以前一条规则成立为基础的。对于规则3-2,若规则3-1不成立,也就是X→Y…Y不是非终结符,显然X→Y_1 Y_2 … Y_nY_1不会是非终结符,也就是3-2不成立。对于规则3-2内部,若X→Y_1 Y_2 … Y_k Y_{k+1} … Y_n,若Y_k不是非终结符,那么对于Y_{k+1}来说,前面的符号都不是非终结符,也就是规则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. 算法结束
  1. 将一个普通的文法转换为一个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)文法,从而得到结果。
  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<GrammerSymbol> {
    /* 文法符号储存在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<GrammerSymbols>, Iterable<GrammerSymbol> {
    /* 储存文法符号序列 */
    private final List<GrammerSymbol> 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<GrammerSymbol> 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<GrammerSymbol> 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<GrammerSymbol> source, int sourceCount,
                       List<GrammerSymbol> 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<GrammerSymbol> getVns() {
        Set<GrammerSymbol> set = new TreeSet<>();
        for (GrammerSymbol gs : value)
            if (GrammerSymbol.isNonterminal(gs))
                set.add(gs);
        return set;
    }

    /**
     * 返回序列中的所有终结符号
     *
     * @return 所有终结符号的集合
     */
    public Set<GrammerSymbol> getVts() {
        Set<GrammerSymbol> 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<GrammerSymbol> 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<GrammerSymbol> Vt;
    /* 非终结符集合,在这里,我们假定非终结符是大写字母,或者是大写字母带有'字符 */
    final Set<GrammerSymbol> Vn;
    /* 文法的开始符号,一般来说为S或者S' */
    final GrammerSymbol S;
    /* 文法的产生式 */
    final Map<GrammerSymbol, Set<GrammerSymbols>> 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<GrammerSymbol> Vt = new TreeSet<>();
        Set<GrammerSymbol> Vn = new TreeSet<>();
        Map<GrammerSymbol, Set<GrammerSymbols>> 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<GrammerSymbols> 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<GrammerSymbol, Set<GrammerSymbols>> Productions) {
        this.Productions = Collections.unmodifiableMap(Productions);
        this.S = S;
        Set<GrammerSymbol> Vt = new TreeSet<>();
        Set<GrammerSymbol> Vn = new TreeSet<>();
        for (GrammerSymbol gs : this.Productions.keySet()) {
            Set<GrammerSymbols> 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<GrammerSymbol> getVt() {
        return Vt;
    }

    public Set<GrammerSymbol> getVn() {
        return Vn;
    }

    public GrammerSymbol getS() {
        return S;
    }

    public Map<GrammerSymbol, Set<GrammerSymbols>> 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<GrammerSymbol, Set<GrammerSymbol>> FirstSets;
    /* 文法的Follow集合 */
    final Map<GrammerSymbol, Set<GrammerSymbol>> FollowSets;
    /* LL(1)文法的预测分析表 */
    final Map<GrammerSymbol, Map<GrammerSymbol, GrammerSymbols>> PATable;

    /**
     * 从一个已经存在的文法构造成LL(1)文法
     *
     * @param grammer 已经存在的文法
     */
    public LL1Grammer(Grammer grammer) {
        super(grammer);
        Map<GrammerSymbol, Set<GrammerSymbol>> FirstSets = generateFirstSets();
        for (GrammerSymbol gs : FirstSets.keySet())
            FirstSets.replace(gs, Collections.unmodifiableSet(FirstSets.get(gs)));
        this.FirstSets = Collections.unmodifiableMap(FirstSets);
        Map<GrammerSymbol, Set<GrammerSymbol>> FollowSets = generateFollowSets();
        for (GrammerSymbol gs : FollowSets.keySet())
            FollowSets.replace(gs, Collections.unmodifiableSet(FollowSets.get(gs)));
        this.FollowSets = Collections.unmodifiableMap(FollowSets);
        Map<Pair<GrammerSymbol, GrammerSymbol>, Set<GrammerSymbols>> PATable = generatePATable();
        boolean isNotLL1 = false;
        Map<GrammerSymbol, Map<GrammerSymbol, GrammerSymbols>> LL1PATable = new TreeMap<>();
        for (Pair<GrammerSymbol, GrammerSymbol> pair : PATable.keySet()) {
            Set<GrammerSymbols> set = PATable.get(pair);
            isNotLL1 |= (set.size() > 1);
            Iterator<GrammerSymbols> 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<GrammerSymbol, GrammerSymbols> 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<GrammerSymbol, Set<GrammerSymbol>> FirstSets = generateFirstSets();
        for (GrammerSymbol gs : FirstSets.keySet())
            FirstSets.replace(gs, Collections.unmodifiableSet(FirstSets.get(gs)));
        this.FirstSets = Collections.unmodifiableMap(FirstSets);
        Map<GrammerSymbol, Set<GrammerSymbol>> FollowSets = generateFollowSets();
        for (GrammerSymbol gs : FollowSets.keySet())
            FollowSets.replace(gs, Collections.unmodifiableSet(FollowSets.get(gs)));
        this.FollowSets = Collections.unmodifiableMap(FollowSets);
        Map<Pair<GrammerSymbol, GrammerSymbol>, Set<GrammerSymbols>> PATable = generatePATable();
        boolean isNotLL1 = false;
        Map<GrammerSymbol, Map<GrammerSymbol, GrammerSymbols>> LL1PATable = new TreeMap<>();
        for (Pair<GrammerSymbol, GrammerSymbol> pair : PATable.keySet()) {
            Set<GrammerSymbols> set = PATable.get(pair);
            isNotLL1 |= (set.size() > 1);
            Iterator<GrammerSymbols> 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<GrammerSymbol, GrammerSymbols> 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<GrammerSymbol, Set<GrammerSymbol>> generateFirstSets() {
        Map<GrammerSymbol, Set<GrammerSymbol>> FirstSets = new TreeMap<>();
        Set<GrammerSymbol> 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<GrammerSymbols> 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<GrammerSymbols> Productions = this.Productions.get(X);
                Label1:
                for (GrammerSymbols production : Productions) {
                    /* 规则3-1 */
                    GrammerSymbol Y = production.get(0);
                    if (GrammerSymbol.isTerminal(Y)) continue;
                    Set<GrammerSymbol> 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<GrammerSymbol, Set<GrammerSymbol>> generateFollowSets() {
        Map<GrammerSymbol, Set<GrammerSymbol>> FollowSets = new TreeMap<>();
        Set<GrammerSymbol> 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<GrammerSymbols> Productions = this.Productions.get(A);
                for (GrammerSymbols production : Productions) {
                    GrammerSymbol B;
                    Set<GrammerSymbol> 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<GrammerSymbol> 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<GrammerSymbol> FirstSet(GrammerSymbols production) {
        /* 构造文法的一个任何符号串α的First集合 */
        /* 规则1 置First(α)=First(X_1)\{ε}; */
        GrammerSymbol gsY = production.get(0);
        Set<GrammerSymbol> result = new TreeSet<>(this.FirstSets.get(gsY));
        Set<GrammerSymbol> 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<GrammerSymbol> FirstSet(GrammerSymbol s) {
        return this.FirstSets.get(s);
    }

    /**
     * 产生文法的预测分析表
     *
     * @return 文法的预测分析表M
     */
    private Map<Pair<GrammerSymbol, GrammerSymbol>, Set<GrammerSymbols>> generatePATable() {
        Map<Pair<GrammerSymbol, GrammerSymbol>, Set<GrammerSymbols>> PATable = new TreeMap<>();
        Set<GrammerSymbol> 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<GrammerSymbols> productions = this.Productions.get(A);
            for (GrammerSymbols alpha : productions) {
                Set<GrammerSymbol> firstSet = this.FirstSet(alpha);
                for (GrammerSymbol a : firstSet)
                    /* 若ε∈FIRST(α),则对于任何的b∈FOLLOW(A)把A->α加至M[A,b]中 */
                    if (a.equals(GS_EPSILON)) {
                        Set<GrammerSymbol> 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<GrammerSymbol> FollowSet(GrammerSymbol s) {
        return this.FollowSets.get(s);
    }

    @Override
    public Set<GrammerSymbol> getVn() {
        return super.getVn();
    }

    @Override
    public GrammerSymbol getS() {
        return super.getS();
    }

    @Override
    public Set<GrammerSymbol> getVt() {
        return super.getVt();
    }

    @Override
    public Map<GrammerSymbol, Set<GrammerSymbols>> getProductions() {
        return super.getProductions();
    }

    public Map<GrammerSymbol, Set<GrammerSymbol>> getFirstSets() {
        return FirstSets;
    }

    public Map<GrammerSymbol, Set<GrammerSymbol>> getFollowSets() {
        return FollowSets;
    }

    public Map<GrammerSymbol, Map<GrammerSymbol, GrammerSymbols>> 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<GrammerSymbol> tempVn = new ArrayList<>(grammer.getVn());
        Set<GrammerSymbol> newVn = new TreeSet<>(tempVn);
        Map<GrammerSymbol, Set<GrammerSymbols>> newMap = new TreeMap<>(grammer.Productions);
        /* 对于每一个非终结符P_i */
        for (int i = 0; i < tempVn.size(); ++i) {
            GrammerSymbol P_i = tempVn.get(i);
            Set<GrammerSymbols> newSet = new TreeSet<>();
            /* 对于P_i的每一条规则 */
            Set<GrammerSymbols> productions = newMap.get(P_i);
            Set<GrammerSymbols> newProductions = new TreeSet<>(productions);
            for (int j = 0; j < i; ++j) {
                GrammerSymbol P_j = tempVn.get(j);
                Set<GrammerSymbols> 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<GrammerSymbols> jProductions = newMap.get(P_j);
                        for (GrammerSymbols jProduction : jProductions)
                            newProductions.add(new GrammerSymbols(jProduction + gammaString));
                    }
                }
            }
            /* 消除P_i的新规则中的所有左递归 */
            Set<GrammerSymbols> newProductionHasLR = new TreeSet<>();
            Set<GrammerSymbols> 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<GrammerSymbols> 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<GrammerSymbols> 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<GrammerSymbol, Set<GrammerSymbols>> tempMap = new TreeMap<>();
        for (GrammerSymbol gs : newVn)
            tempMap.put(gs, newMap.get(gs));
        /* 以上步骤已经消除左递归,下面进行提左因子 */
        /* 提左因子,直到没有左因子停止 */
        do {
            /* 假设没有左因子 */
            flag = false;
            Set<GrammerSymbol> curVn = new TreeSet<>(newVn);
            for (GrammerSymbol gs : newVn) {
                Set<GrammerSymbols> productions = tempMap.get(gs);
                Map<GrammerSymbol, Set<GrammerSymbols>> 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<GrammerSymbol, Set<GrammerSymbols>> 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<GrammerSymbols> set = counterfilter.get(delta);
                        productions.removeAll(set);
                        productions.add(new GrammerSymbols(delta + A_.toString()));
                        Set<GrammerSymbols> 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<GrammerSymbol> 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<GrammerSymbol> 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<Quartet<String, String, String, String>> parseString(String string) {
        return parseGrammerSymbols(new GrammerSymbols(string));
    }

    /**
     * 采用给定的LL(1)文法{@link #grammer}分析输入的文法符号序列
     *
     * @param input 要分析的文法符号序列
     * @return 分析结果
     */
    public List<Quartet<String, String, String, String>> parseGrammerSymbols(GrammerSymbols input) {
        /* 符号栈, 剩余输入串, 所用产生式, 动作 */
        List<Quartet<String, String, String, String>> snap = new LinkedList<>();
        String inputString = input.toString();
        String usedProduction = "";
        Stack<GrammerSymbol> 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;
    }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352