跳转至

框架接口介绍

LRTable: LR 分析表

所谓 LR 分析表, 实际上就是一张类似自动机的状态转移图, 当在当前状态遇到某某符号时便执行动作并转移. 规约时就根据 "Action 表" 里写的产生式生成非终结符, 然后将生成的非终结符作为 "输入符号" 根据 "Goto 表" 来确定转移; 移入时就直接根据 "Action 表" 转移到对应状态.

我们采用一种更接近邻接表而非邻接矩阵的方式来提供对 ACTION 与 GOTO 的访问; 虽然, 我们亦在 LRTable 中提供了 "更像邻接矩阵" 的访问接口:

class LRTable {
    /**
     * 根据当前状态与当前词法单元获取对应动作
     * @param status 当前状态
     * @param token 当前词法单元
     * @return 应采取的动作
     */
    public Action getAction(Status status, Token token) {
        final var tokenKind = token.getKind();
        return status.getAction(tokenKind);
    }

    /**
     * 根据当前状态与规约到非终结符获得应转移到的状态
     * @param status 当前状态
     * @param nonTerminal 规约出的非终结符
     * @return 应转移到的状态
     */
    public Status getGoto(Status status, NonTerminal nonTerminal) {
        return status.getGoto(nonTerminal);
    }

    /**
     * @return 起始状态
     */
    public Status getInit() {
        // return initStatus;
        return statusInIndexOrder.get(0);
    }
}

理论上一个 LRTable 只需要保存起始状态 (initStatus) 即可. 但是为了方便将整个表输出为 csv 查看, 我们于 LRTable 中保存了一些多余的状态, 而你的实现 不应该 使用这些信息:

class LRTable {
    private final List<Status> statusInIndexOrder;
    private final List<TokenKind> terminals;
    private final List<NonTerminal> nonTerminals;
}

Status: 状态

class Status {
    private Map<TokenKind, Action> action;
    private Map<NonTerminal, Status> goto_;
}
class Status {
    // API
}

Action: 动作

enum ActionKind {
    Shift, Reduce, Accept, Error
}

class Action {
    private ActionKind kind;
    private Production production;  // nullable, only for Reduce 
    private Status status;          // nullable, only for Shift
}
class Action {
    public Production getProduction() {

    }

    public Status getStatus() {

    }
}