编译原理实验三 LR(1)分析法

一、 实验目的

构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

二、 描述 LR(1)语法分析程序的设计思想

1. 拓广文法

假定文法G是一个以S为开始符号的文法,我们构造一个G',它包含了整个G,但它引进了一个不出现在G中的非终结符S',并加进一个新产生式S'→S,而S'G'的开始符号。那么,我们称G'G的拓广文法。这样,便会有一个仅含项目S'→S的状态,这便是唯一的接受态。

2. 提取所有有效识别活前缀的式子:

形式上我们说一个LR(1)项目[A→α·β, a]对于活前缀γ是有效的,如果存在规范推导


其中,① γ=δα;② a是的ω第一个符号,或者a为#而ωε
[A→α·Bβ, a]对活前缀γ=δα是有效的,则对于每个形如B→ξ的产生式, 对任何的b∈FIRST(βa)[B→·ξ, b]γ也是有效的。

3. 构造项目集I的闭包CLOSURE(I):

假定I是一个项目集,它的闭包CLOSURE(I)可按如下方式构造:
(1) I的任何项目都属于CLOSURE(I)
(2) 若项目[A→α·Bβ, a]属于CLOSURE(I)B→ξ是一个产生式,那么,对于FIRST(βa)中的每个终结符b,如果[B→·ξ, b]原来不在CLOSURE(I)中,则把它加进去。
(3) 重复执行步骤2,直至CLOSURE(I)不再增大为止。

4. 构造GO(I, X)

I是一个项目集,X是一个文法符号,函数GO(I,X)定义为


其中

5. 构造LR(1)项目集族C

关于文法G'的LR(1)项目集族C的构造算法是:

6.分析表构造:

假设C={I_0,I_1,…,I_n },令每个I_k的下标k为分析表的状态,令含有[S'→·S, \#]I_kk为分析器的初态。动作ACTION和状态转换GOTO可构造如下:
(1) 若项目[A→α·aβ,b]属于I_kGO(I_k,a)=I_ja为终结符,则置ACTION[k,a]为“把状态j和符号a移入栈”,简记为"s_j"。
(2) 若项目[A→α·, a]属于I_k,则置ACTION[k,a]为“用产生式A→α规约”,简记为"r_j",其中假定A→α为文法G'的第j个产生式。
(3) 若项目[S'→S·,\#]属于I_k,则置ACTION[k,\#]为“接受”,简记为"acc"。
(4) 若GO(I_k,A)=I_j,则置GOTO[k,A]=j
(5) 分析表中凡不能用规则1至4填入信息的空白栏均填上“出错标志”。

三、 LR分析器详细的算法描述

LR分析器的总控程序本身的工作是比较简单的。它的任何一步只需按照栈顶状态s和现行输入符号a执行ACTION[s, a]所规定的动作。不管什么分析表,总控程序都是一样的工作。
一个LR分析器的工作过程可以看成是栈里的状态序列、已规约串和输入串所构成的三元式的变化过程。分析开始时的初始三元式是
(s_0,\#, a_1 a_2…a_n\#)
其中,s_0为分析器的初态; \#为句子的左括号; a_1 a_2…a_n为输入串;其后的\#为结束符(句子右括号)。分析过程的每步结果可以表示为
(s_0 s_1…s_m,\#X_1 X_2…X_m,a_i a_{i+1} … a_n\#)
分析器的下一步动作是由栈顶状态s_m和现行输入符号a_i所唯一确定的。即,执行ACTION[s_m, a_i]所规定的动作。经执行每种动作后,三元式的变化情况是:
(1) 若ACTION[s_m, a_i]为移进,且s=GOTO[s_m, a_i],则三元式变成
(s_0 s_1…s_m s,\#X_1 X_2…X_m a_i,a_{i+1}…a_n\#)
(2) 若ACTION[s_m, a_i]为使用A→β规约,则三元式变成
(s_0 s_1…s_{m-r} s,\#X_1 X_2…X_{m-r} A,a_i a_{i+1}…a_n\#)
其中,s=GOTO[S_{m-r}, A]rβ的长度,β=X_{m-r+1} … Xm
(3) 若ACTION[s_m, a_i]为接受,则三元式不再变化,宣布分析成功
(4) 若ACTION[s_m, a_i]为报错,则三元式的变化过程终止,报告错误。
用流程图表示如下:

四、 源代码

(1) LR1Project.java

package exp3;

import exp2.grammer.symbol.GrammerSymbol;
import exp2.grammer.symbol.GrammerSymbols;

import java.util.Objects;

/**
 * LR(1)项目
 *
 * @version 2020-06-07
 */
public class LR1Project implements Comparable<LR1Project> {
    /** 产生式左部 */
    public final GrammerSymbol left;
    /** 产生式右部 */
    public final GrammerSymbols right;
    /** 圆点的位置 */
    public final int pos;
    /** 向前搜索的符号 */
    public final GrammerSymbol forward;

    /**
     * 构造LR(1)项目
     *
     * @param left 产生式左部
     * @param right 产生式右部
     * @param pos 圆点的位置
     * @param forward 向前搜索符
     */
    public LR1Project(GrammerSymbol left, GrammerSymbols right, int pos, GrammerSymbol forward) {
        this.left = left;
        this.right = right;
        this.pos = pos;
        this.forward = forward;
    }

    @Override
    public String toString() {
        return "[" + left +
                "->" +
                right.subSequence(0, pos) +
                "·" +
                right.subSequence(pos) +
                ", " + forward +
                ']';
    }

    @Override
    public int compareTo(LR1Project o) {
        int cmp = this.left.compareTo(o.left);
        if (cmp != 0) return cmp;
        cmp = this.right.compareTo(o.right);
        if (cmp != 0) return cmp;
        cmp = Integer.compare(this.pos, o.pos);
        if (cmp != 0) return cmp;
        return this.forward.compareTo(o.forward);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LR1Project that = (LR1Project) o;
        return this.toString().equals(that.toString());
    }

    @Override
    public int hashCode() {
        return Objects.hash(left, right, pos, forward);
    }
}

(2) LR1Action.java

package exp3;

import java.util.Objects;

/**
 * LR(1)文法的动作
 *
 * @version 2020-06-14
 */
public class LR1Action {
    /** 动作类型编号,0为s,1为r,2为acc */
    public final static int PUSHSTACK = 0;
    public final static int REDUCE = 1;
    public final static int ACCEPT = 2;

    /** 动作类型 */
    public int type;
    /** 当为进栈操作时,表示把状态j放入栈中;当为规约操作时,表示使用第j个产生式进行规约 */
    public int j;

    /**
     * 根据类型构造动作,应当为接受动作的构造方法,也就是type应为2
     *
     * @param type 类型,应为2,也就是ACCEPT
     */
    public LR1Action(int type) {
        this.type = type;
    }

    /**
     * 根据类型构造动作,不应当为接受动作的构造方法
     *
     * @param type 类型,应为0和1,也就是PUSHSTACK和REDUCE
     * @param j 当为进栈操作时,表示把状态j放入栈中;当为规约操作时,表示使用第j个产生式进行规约
     */
    public LR1Action(int type, int j) {
        this.type = type;
        this.j = j;
    }

    @Override
    public String toString() {
        switch (this.type) {
            case PUSHSTACK: return "s" + this.j;
            case REDUCE: return "r" + this.j;
            case ACCEPT: return "acc";
            default: return "error";
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LR1Action lr1Action = (LR1Action) o;
        return type == lr1Action.type &&
                j == lr1Action.j;
    }

    @Override
    public int hashCode() {
        return Objects.hash(type, j);
    }
}

(3) LR1Grammer.java

package exp3;

import exp2.grammer.Grammer;
import exp2.grammer.exception.GrammerException;
import exp2.grammer.symbol.*;
import exp2.util.Pair;

import java.util.*;

import static exp2.grammer.symbol.GrammerSymbol.*;
import static java.util.AbstractMap.SimpleImmutableEntry;

/**
 * LR(1)文法
 *
 * @version 2020-06-14
 */
public class LR1Grammer extends Grammer {
    /* 文法的Fisrt集合 */
    Map<GrammerSymbol, Set<GrammerSymbol>> FirstSets;
    /* 文法的Follow集合 */
    Map<GrammerSymbol, Set<GrammerSymbol>> FollowSets;
    /** LR(1)文法中的所有项目 */
    Set<LR1Project> allProjects;
    /** LR(1)文法的项目集族 */
    List<Set<LR1Project>> C;
    /** ACTION表 */
    Map<Integer, Map<GrammerSymbol, LR1Action>> ACTION;
    /** GOTO表 */
    Map<Integer, Map<GrammerSymbol, Integer>> GOTO;
    /** (有序的)产生式列表 */
    List<Pair<GrammerSymbol, GrammerSymbols>> ProdList;

    /**
     * 从文法产生式输入构造一个文法
     *
     * @param src 文法输入
     */
    public LR1Grammer(String src) {
        this(src.split("(\r\n)|(\n)|(\r)"));
    }

    /**
     * 从文法产生式字符串数组构造一个文法
     *
     * @param srcs 文法字符串数组
     */
    public LR1Grammer(String[] srcs) {
        super(srcs);
        this.FirstSets = this.generateFirstSets();
        this.FollowSets = this.generateFollowSets();
        this.allProjects = this.generateProjects();
        this.C = this.generateC();
        this.ProdList = this.generateProdList();
        SimpleImmutableEntry<Map<Integer, Map<GrammerSymbol, LR1Action>>, Map<Integer, Map<GrammerSymbol, Integer>>> Tables = this.generateActionTableAndGotoTable();
        this.ACTION = Tables.getKey();
        this.GOTO = Tables.getValue();
    }

    /**
     * 根据一个已经存在的文法构造一个副本
     *
     * @param grammer 已经存在的文法
     */
    public LR1Grammer(Grammer grammer) {
        super(grammer);
        this.FirstSets = this.generateFirstSets();
        this.FollowSets = this.generateFollowSets();
        this.allProjects = this.generateProjects();
        this.C = this.generateC();
        this.ProdList = this.generateProdList();
        SimpleImmutableEntry<Map<Integer, Map<GrammerSymbol, LR1Action>>, Map<Integer, Map<GrammerSymbol, Integer>>> Tables = this.generateActionTableAndGotoTable();
        this.ACTION = Tables.getKey();
        this.GOTO = Tables.getValue();
    }

    /**
     * 从开始符号和产生式集合构造文法
     *
     * @param S           开始符号
     * @param Productions 产生式集合
     */
    public LR1Grammer(GrammerSymbol S, Map<GrammerSymbol, Set<GrammerSymbols>> Productions) {
        super(S, Productions);
        this.FirstSets = this.generateFirstSets();
        this.FollowSets = this.generateFollowSets();
        this.allProjects = this.generateProjects();
        this.C = this.generateC();
        this.ProdList = this.generateProdList();
        SimpleImmutableEntry<Map<Integer, Map<GrammerSymbol, LR1Action>>, Map<Integer, Map<GrammerSymbol, Integer>>> Tables = this.generateActionTableAndGotoTable();
        this.ACTION = Tables.getKey();
        this.GOTO = Tables.getValue();
    }
    /**
     * 产生文法的所有终结符和非终结符的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.getVt()) {
            firstX = new TreeSet<>();
            firstX.add(X);
            FirstSets.put(X, firstX);
        }
        /* 规则2 若X∈Vn, 且有产生式X->a...,则把a加入到First(X)中 */
        for (GrammerSymbol X : this.getVn()) {
            firstX = new TreeSet<>();
            FirstSets.put(X, firstX);
            Set<GrammerSymbols> Productions = this.getProductions().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.getProductions().keySet()) {
                firstX = FirstSets.get(X);
                Set<GrammerSymbols> Productions = this.getProductions().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.getVn()) {
            FollowSet = new TreeSet<>();
            FollowSets.put(gs, FollowSet);
        }
        /* 规则1 对于文法的开始符号S,置#于FOLLOW(S)中; */
        FollowSets.get(this.getS()).add(new GrammerSymbol("#"));
        boolean modified = true;
        /* 连续使用规则2和3,直至每个Follow集不再增大为止. */
        while (modified) {
            modified = false;
            for (GrammerSymbol A : getProductions().keySet()) {
                Set<GrammerSymbols> Productions = this.getProductions().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;
    }

    /**
     * 产生文法的所有LR(1)项目
     *
     * @return 所有的LR(1)项目
     */
    private Set<LR1Project> generateProjects() {
        Set<LR1Project> result = new TreeSet<>();
        Set<GrammerSymbol> Vt = new TreeSet<>(this.getVt());
        Vt.remove(GS_EPSILON);
        Vt.add(new GrammerSymbol("#"));
        Map<GrammerSymbol, Set<GrammerSymbols>> productions = this.getProductions();
        for (GrammerSymbol left : productions.keySet()) {
            Set<GrammerSymbols> rights = productions.get(left);
            for (GrammerSymbols right : rights) {
                for (int i = 0; i <= right.length(); ++i) {
                    for (GrammerSymbol forward : Vt) {
                        result.add(new LR1Project(left, right, i, forward));
                    }
                }
            }
        }
        return result;
    }

    /**
     * 生成项目集族C
     *
     * @return 项目集族C
     */
    private List<Set<LR1Project>> generateC() {
        /* 找到文法中的所有符号 */
        Set<GrammerSymbol> allSymbols = new TreeSet<>(this.getVn());
        allSymbols.addAll(this.getVt());
        allSymbols.remove(GS_EPSILON);
        /* 采用LinkedHashSet来实现Set的首位元素即为分析器的初态 */
        LinkedHashSet<Set<LR1Project>> result = new LinkedHashSet<>();
        Set<LR1Project> startSet = new TreeSet<>();
        startSet.add(new LR1Project(new GrammerSymbol("S'"), new GrammerSymbols("S"), 0, new GrammerSymbol("#")));
        result.add(this.Closure(startSet));
        boolean modified = true;
        while (modified) {
            modified = false;
            int fslen;
            Set<Set<LR1Project>> C = new HashSet<>(result);
            for (Set<LR1Project> I : C) {
                for (GrammerSymbol X : allSymbols) {
                    Set<LR1Project> go_I_X = GO(I, X);
                    if (go_I_X.size() > 0) {
                        fslen = result.size();
                        result.add(go_I_X);
                        modified |= (fslen != result.size());
                    }
                }
            }
        }
        return new ArrayList<>(result);
    }

    /**
     * 生成产生式列表
     *
     * @return 产生式列表
     */
    private List<Pair<GrammerSymbol, GrammerSymbols>> generateProdList() {
        List<Pair<GrammerSymbol, GrammerSymbols>> result = new ArrayList<>();
        GrammerSymbol S_ = new GrammerSymbol("S'");
        GrammerSymbol S = new GrammerSymbol("S");
        Map<GrammerSymbol, Set<GrammerSymbols>> productions = this.getProductions();
        Set<GrammerSymbol> lefts = new TreeSet<>(productions.keySet());
        lefts.remove(S_);
        lefts.remove(S);
        List<GrammerSymbol> leftlist = new ArrayList<>();
        leftlist.add(S_);
        leftlist.add(S);
        leftlist.addAll(lefts);
        for (GrammerSymbol left : leftlist) {
            Set<GrammerSymbols> rights = productions.get(left);
            for (GrammerSymbols right : rights) {
                result.add(new Pair<>(left, right));
            }
        }
        return result;
    }

    /**
     * 生成规范LR(1)分析表
     *
     * @return 规范LR(1)分析表
     */
    private SimpleImmutableEntry<Map<Integer, Map<GrammerSymbol, LR1Action>>, Map<Integer, Map<GrammerSymbol, Integer>>> generateActionTableAndGotoTable() {
        Map<Integer, Map<GrammerSymbol, LR1Action>> ActionTable = new TreeMap<>();
        Map<Integer, Map<GrammerSymbol, Integer>> GotoTable = new TreeMap<>();
        for (int i = 0; i < this.C.size(); ++i) {
            ActionTable.put(i, new TreeMap<>());
            GotoTable.put(i, new TreeMap<>());
        }
        for (int i = 0; i < this.C.size(); ++i) {
            Set<LR1Project> I = C.get(i);
            for (LR1Project project : I) {
                GrammerSymbols right = project.right;
                GrammerSymbol a = right.get(project.pos);
                if (a != null && isTerminal(a)) {
                    int j = this.C.indexOf(GO(I, a));
                    LR1Action action = new LR1Action(LR1Action.PUSHSTACK, j);
                    if (!ActionTable.get(i).containsKey(a)) ActionTable.get(i).put(a, action);
                    else if (!ActionTable.get(i).get(a).equals(action))
                        throw new GrammerException("这个文法的LR(1)分析表含有多重定义入口,不是LR(1)的。");
                }
                else if (a == null) {
                    if (project.left.toString().equals("S'")) {
                        LR1Action action = new LR1Action(LR1Action.ACCEPT);
                        if (!ActionTable.get(i).containsKey(project.forward)) ActionTable.get(i).put(project.forward, action);
                        else if (!ActionTable.get(i).get(project.forward).equals(action))
                            throw new GrammerException("这个文法的LR(1)分析表含有多重定义入口,不是LR(1)的。");
                    }
                    else {
                        int j = ProdList.indexOf(new Pair<>(project.left, project.right));
                        LR1Action action = new LR1Action(LR1Action.REDUCE, j);
                        if (!ActionTable.get(i).containsKey(project.forward)) ActionTable.get(i).put(project.forward, action);
                        else if (!ActionTable.get(i).get(project.forward).equals(action))
                            throw new GrammerException("这个文法的LR(1)分析表含有多重定义入口,不是LR(1)的。");
                    }
                }
            }
            for (GrammerSymbol A : this.getVn()) {
                Set<LR1Project> go_I_A = this.GO(I, A);
                if (go_I_A.size() > 0) {
                    int j = this.C.indexOf(go_I_A);
                    if (!GotoTable.get(i).containsKey(A)) GotoTable.get(i).put(A, j);
                    else if (GotoTable.get(i).get(A).equals(j))
                        throw new GrammerException("这个文法的LR(1)分析表含有多重定义入口,不是LR(1)的。");
                }
            }

        }
        return new SimpleImmutableEntry<>(ActionTable, GotoTable);
    }

    /**
     * 返回对应文法字符串的First集合
     *
     * @param production 文法字符串
     * @return 文法字符串production对应的First集合
     */
    public Set<GrammerSymbol> FirstSet(GrammerSymbols production) {
        /* 构造文法的一个任何符号串α的First集合 */
        /* 规则1 置First(α)=First(X_1)\{ε}; */
        GrammerSymbol gsY = production.get(0);
        if (gsY.toString().equals("#")) {
            Set<GrammerSymbol> result = new TreeSet<>();
            result.add(new GrammerSymbol("#"));
            return result;
        }
        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;
    }

    /**
     * CLOSURE(I)
     *
     * @param I 项目集
     * @return CLOSURE(I)
     */
    public Set<LR1Project> Closure(Set<LR1Project> I) {
        /* (1) I的任何项目都属于CLOUSURE(I) */
        Set<LR1Project> result = new TreeSet<>(I);
        /* (3) 重复执行步骤(2),直至CLOSURE(I)不再增大为止 */
        boolean modified = true;
        /* (2) 若项目[A→·αBβ,a]属于CLOSURE(I),B→ξ是一个产生式,那么,对于FIRST(βa)中的每个终结符b
                如果[B→·ξ,b]原来不在CLOSURE(I)中,则把它加进去 */
        while (modified) {
            modified = false;
            int fslen;
            Set<LR1Project> backup = new TreeSet<>(result);
            for (LR1Project project : backup) {
                if (project.right.get(project.pos) != null && isNonterminal(project.right.get(project.pos))) {
                    GrammerSymbol B = project.right.get(project.pos);
                    GrammerSymbols beta = project.right.subSequence(project.pos + 1);
                    GrammerSymbol a = project.forward;
                    Set<GrammerSymbol> first_beta_a = FirstSet(new GrammerSymbols(beta+a.toString()));
                    for (GrammerSymbol b : first_beta_a) {
                        for (GrammerSymbols rightProduction : this.getProductions().get(B)) {
                            fslen = result.size();
                            result.add(new LR1Project(B, rightProduction, 0, b));
                            modified |= (fslen != result.size());
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * GO(I, X)
     *
     * @param I 项目集
     * @param X 文法符号
     * @return GO(I, X)=CLOSURE(J),其中J={任何形如[A→αX·β,a]的项目|[A→α·Xβ,a]∈I}
     */
    public Set<LR1Project> GO(Set<LR1Project> I, GrammerSymbol X) {
        Set<LR1Project> J = new TreeSet<>();
        for (LR1Project project : I) {
            GrammerSymbols right = project.right;
            GrammerSymbols XA = new GrammerSymbols(X.toString());
            int rightPos = right.indexOf(X);
            while (rightPos >= 0) {
                if (rightPos == project.pos) {
                    J.add(new LR1Project(project.left, project.right, rightPos+1, project.forward));
                }
                rightPos = right.indexOf(XA, rightPos + 1);
            }
        }
        return this.Closure(J);
    }

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

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

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

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

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

    public List<Pair<GrammerSymbol, GrammerSymbols>> getProdList() {
        return ProdList;
    }

    public List<Set<LR1Project>> getC() {
        return C;
    }

    public Map<Integer, Map<GrammerSymbol, Integer>> getGOTO() {
        return GOTO;
    }

    public Map<Integer, Map<GrammerSymbol, LR1Action>> getACTION() {
        return ACTION;
    }

    public Set<LR1Project> getAllProjects() {
        return allProjects;
    }

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

    public static void main(String[] args) {
        String[] srcs1 = {
                "S'->S",
                "S->BB",
                "B->aB",
                "B->b"
        };
        String[] srcs2 = {
                "S'->S",
                "S->S+T",
                "E->T",
                "T->T*F",
                "T->F",
                "F->(S)",
                "F->i"
        };
        LR1Grammer lr1Grammer = new LR1Grammer(srcs1);
        lr1Grammer = new LR1Grammer(srcs2);
    }

    @Override
    public String toString() {
        return "LR1Grammer{" +
                "FirstSets=" + FirstSets +
                ", FollowSets=" + FollowSets +
                ", allProjects=" + allProjects +
                ", C=" + C +
                ", ACTION=" + ACTION +
                ", GOTO=" + GOTO +
                ", ProdList=" + ProdList +
                '}';
    }
}

(4) LR1Parser.java

package exp3;

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.Pair;
import exp2.util.Quartet;

import java.util.*;

import static exp3.LR1Action.*;

/**
 * LR(1)语法分析器
 *
 * @version 2020-06-15
 */
public class LR1Parser {
    /* 某个LL(1)文法 */
    final LR1Grammer grammer;

    /**
     * 从某个一个存在的LL(1)文法构造LL(1)预测分析程序
     *
     * @param grammer 已经存在的LL(1)文法
     */
    public LR1Parser(LR1Grammer grammer) {
        this.grammer = grammer;
    }

    /**
     * 从某个一个存在的文法构造LL(1)预测分析程序
     *
     * @param grammer 已经存在的文法
     * @throws GrammerException 如果这个文法不是LL(1)的
     */
    public LR1Parser(Grammer grammer) { this.grammer = new LR1Grammer(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();
        Stack<GrammerSymbol> symbolStack = new Stack<>();
        Stack<Integer> stateStack = new Stack<>();
        GrammerSymbol EOI = new GrammerSymbol("#");
        GrammerSymbols Epsilon = new GrammerSymbols(Collections.singletonList(GrammerSymbol.GS_EPSILON));
        /* 把#推入符号栈中 */
        symbolStack.add(EOI);
        /* 把初态推入状态栈中,初态按照实现,应当为项目集的第一个 */
        stateStack.add(0);
        snap.add(new Quartet<>(stateStack.toString(), symbolStack.toString(), inputString, "初始化"));
        int index = 0;
        GrammerSymbol a;
        Set<LR1Project> curState;
        int curStateID;
        LR1Action action;
        String actionString;
        boolean flag = true;
        while (flag) {
            /* 栈顶状态 */
            curState = this.grammer.C.get(stateStack.peek());
            /* 栈顶状态的标号 */
            curStateID = this.grammer.C.indexOf(curState);
            /* 现行输入符号a */
            a = input.get(index);
            /* 目前的动作 */
            action = this.grammer.ACTION.get(curStateID).get(a);
            switch (action.type) {
                case PUSHSTACK: {
                    actionString = "状态" + action.j + "和符号" + a + "入栈";
                    stateStack.add(action.j);
                    symbolStack.add(a);
                    ++index;
                    break;
                }
                case REDUCE: {
                    Pair<GrammerSymbol, GrammerSymbols> prod = this.grammer.ProdList.get(action.j);
                    actionString = "用" + prod.value1 + "->" + prod.value2 +"规约";
                    int r = prod.value2.length();
                    for (int i = r-1; i >= 0; --i) {
                        GrammerSymbol curs = prod.value2.get(i);
                        GrammerSymbol symbolStackPeek = symbolStack.pop();
                        if (!curs.equals(symbolStackPeek)) {
                            flag = false;
                            actionString = "分析错误";
                            break;
                        }
                        stateStack.pop();
                    }
                    if (!flag) break;
                    symbolStack.add(prod.value1);
                    stateStack.add(this.grammer.GOTO.get(stateStack.peek()).get(prod.value1));
                    break;
                }
                case ACCEPT: {
                    flag = false;
                    actionString = "分析成功";
                    break;
                }
                default: {
                    flag = false;
                    actionString = "分析错误";
                    break;
                }
            }
            /* 记录结果 */
            snap.add(new Quartet<>(stateStack.toString(), symbolStack.toString(), inputString.substring(index), actionString));
        }
        return snap;
    }

    public LR1Grammer getGrammer() {
        return grammer;
    }


    public static void main(String[] args) {
        String[] srcs = {
                "S'->S",
                "S->BB",
                "B->aB",
                "B->b"
        };
        LR1Grammer lr1Grammer = new LR1Grammer(srcs);
        LR1Parser parser = new LR1Parser(lr1Grammer);
        List<Quartet<String, String, String, String>> snap = parser.parseString("aabab#");
        System.out.println(snap);
        System.out.println(snap.size());
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容