Python implementa el analizador de sintaxis SLR (1), principio de compilación yyds!

Python implementa el analizador de sintaxis SLR (1)

La noche anterior a la clase del experimento, tenía un analizador SLR. En ese momento, también publiqué un analizador Moments y tenía que ir con uno por la noche. Desde el estado del día siguiente, deberíamos ser los dos los que nos fuimos juntos (risas)

  • El tiempo de escritura es relativamente corto, por lo que algunas partes del código no se implementan muy bien y hay algunos problemas. Si tiene tiempo en el futuro, lo solucionaré. Por ejemplo, la eficiencia es relativamente baja cuando se comparan dos familias de especificaciones de proyectos. El primer conjunto y el enfoque siguiente son más continuos Puede haber errores cuando un símbolo no terminal se empuja a ε, pero ε se omite deliberadamente en mi definición gramatical y apenas se puede usar.
  • Para facilitar la lectura del código, se agregan muchas declaraciones de impresión comentadas. Descomente estas declaraciones de impresión y ejecútelas para decirle qué está haciendo el código actual.
  • En el proceso de escritura, intente encapsular los módulos y separar las definiciones de lógica y gramática, de modo que la gramática se pueda modificar fácilmente, pero el tiempo es demasiado apresurado, lo que aún puede ser un pequeño problema. Cuando se revisa la gramática, revisar
    getCol函数(该函数将终结符和非终结符映射到action和goto表中相应的列),initProduction函数(该函数定义了文法产生式(拓广文法),在本文中有28个产生式),source(输入单词序列),varset(非终结符集合),terminalset(终结符集合)
    

Proceso de análisis SLR (1)

  • Gramática de entrada
  • Encuentra el primer conjunto
  • Encuentra el siguiente conjunto
  • Construir el conjunto de elementos LR (0) DFA
  • Construir Acción e Ir a
  • Analizar de acuerdo con Action y Goto

1. Definición de la estructura de datos principal y funciones básicas:

 Función básica

  1. La función isVariable determina si es un símbolo no terminal

  2. La función isTerminal determina si es terminal

  3. transf (production_set, var) función production_set es un elemento LR (0), intente transferir a través de var (terminal o no terminal)

  4. Función isSameStatus (status1, status2): determina si status1 y status2 son dos elementos LR (0) idénticos

  5. isInPointset (production_set, pointset): # Se usa para verificar si production_set es un punto que ya existe y, si existe, devolver el punto (se usa al generar DFA)

 

 

 

estructura de datos

  1. Las producciones se almacenan por clases, la izquierda y la derecha son listas respectivamente, y el número 'es el número de producción
  2. GraphPoint almacena transferencias DFA, la transferencia es un conjunto de bordes dirigidos, un elemento del conjunto consta de var (terminal o no terminal) y otro GraphPoint

class Production:
    def __init__(self, left, right, number):
        self.left = left
        self.right = right
        self.number = number

class GraphPoint:

    def __init__(self, begin_production, id):
        self.status = begin_production
        self.transfer = []
        self.id = id

    def add_transfer(self, var, graphPoint):
        self.transfer.append([var, graphPoint])

2. Definición gramatical

1. 分析 目标 代码 : int lexicalanalysis () {float a; int b; a = 1,1; b = 2; mientras (b <100) {b = b + 1; a = a + 3;}; if (a> 5) {b = b-1;} else {b = b + 1;}}

2. La entrada del analizador de sintaxis es la secuencia de palabras generada por el analizador léxico del código de destino.


source = [[5, "int", " 关键字"], [1, "lexicalanalysis", " 标识符"], [13, "(", " 左括号"], [14, ")", " 右括号"], [20, "{", " 左大括号"],
          [4, "float", " 关键字"], [1, "a", " 标识符"], [15, ";", " 分号"], [5, "int", " 关键字"], [1, "b", " 标识符"],
          [15, ";", " 分号"], [1, "a", " 标识符"], [12, "=", " 赋值号"], [3, "1.1", " 浮点数"], [15, ";", " 分号"], [1, "b", " 标识符"],
          [12, "=", " 赋值号"], [2, "2", " 整数"], [15, ";", " 分号"], [8, "while", "  关键字"], [13, "(", " 左括号"],
          [1, "b", " 标识符"], [17, "<", " 小于号"], [2, "100", " 整数"], [14, ")", " 右括号"], [20, "{", " 左大括号"],
          [1, "b", " 标识符"], [12, "=", " 赋值号"], [1, "b", " 标识符"], [9, "+", " 加 号"], [2, "1", " 整数"], [15, ";", " 分号"],
          [1, "a", " 标识符"], [12, "=", " 赋值号"], [1, "a", " 标识符"], [9, "+", " 加号"], [2, "3", " 整数"], [15, ";", " 分号"],
          [21, "}", " 右大括号"], [15, ";", " 分号"], [6, "if", " 关键字"], [13, "(", " 左括号"], [1, "a", " 标识符"],
          [16, ">", " 大于号"], [2, "5", " 整数"], [14, ")", " 右括号"], [20, "{", " 左大括号"], [1, "b", " 标识符"],
          [12, "=", " 赋值号"], [1, "b", " 标识符"], [10, "-", " 减号"], [2, "1", " 整数"], [15, ";", " 分号"], [21, "}", " 右大括号"],
          [7, "else", " 关键字"], [20, "{", " 左大括号"], [1, "b", " 标识符"], [12, "=", " 赋值号"], [1, "b", " 标识符"],
          [9, "+", " 加号"], [2, "1", " 整数"], [15, ";", " 分号"], [21, "}", " 右大括号"], [21, "}", " 右大括号"]]

3. Definición gramatical: Hay 28 producciones en la gramática de extensión. La producción No. 0 es para asegurar que el analizador tenga un solo estado de aceptación, y la extensión es la producción.



def initProduction():
    production_list = []
    production = Production(["A1"], ["A"], 0)
    production_list.append(production)
    production = Production(["A"], ["E", "I", "(", ")", "{", "D", "}"], 1)
    production_list.append(production)
    production = Production(["E"], ["int"], 2)
    production_list.append(production)
    production = Production(["E"], ["float"], 3)
    production_list.append(production)
    production = Production(["D"], ["D", ";", "B"], 4)
    production_list.append(production)
    production = Production(["B"], ["F"], 5)
    production_list.append(production)
    production = Production(["B"], ["G"], 6)
    production_list.append(production)
    production = Production(["B"], ["M"], 7)
    production_list.append(production)
    production = Production(["F"], ["E", "I"], 8)
    production_list.append(production)
    production = Production(["G"], ["I", "=", "P"], 9)
    production_list.append(production)
    production = Production(["P"], ["K"], 10)
    production_list.append(production)
    production = Production(["P"], ["K", "+", "P"], 11)
    production_list.append(production)
    production = Production(["P"], ["K", "-", "P"], 12)
    production_list.append(production)
    production = Production(["I"], ["id"], 13)
    production_list.append(production)
    production = Production(["K"], ["I"], 14)
    production_list.append(production)
    production = Production(["K"], ["number"], 15)
    production_list.append(production)
    production = Production(["K"], ["floating"], 16)
    production_list.append(production)
    production = Production(["M"], ["while", "(", "T", ")", "{", "D", ";", "}"], 18)
    production_list.append(production)
    production = Production(["N"], ["if", "(", "T", ")", "{", "D",";", "}", "else", "{", "D", ";","}"], 19)
    production_list.append(production)
    production = Production(["T"], ["K", "L", "K"], 20)
    production_list.append(production)
    production = Production(["L"], [">"], 21)
    production_list.append(production)
    production = Production(["L"], ["<"], 22)
    production_list.append(production)
    production = Production(["L"], [">="], 23)
    production_list.append(production)
    production = Production(["L"], ["<="], 24)
    production_list.append(production)
    production = Production(["L"], ["=="], 25)
    production_list.append(production)
    production = Production(["D"], ["B"], 26)
    production_list.append(production)
    production = Production(["B"], ["N"], 27)
    production_list.append(production)
    return production_list

 

3. Encuentra el primer conjunto

De acuerdo con este algoritmo, el primer conjunto se puede resolver y los pasos 8 y 9 se pueden resolver de manera recursiva.


def getFirst(production_list, varset, terminalset):
    first_dic = {}
    # 用来标记first集是否计算完毕,防止重复计算浪费时间
    done = {}
    for var in varset:
        first_dic[var] = set()
        done[var] = 0
    # 所有终结符的first集是他自身
    for var in terminalset:
        first_dic[var] = {var}
        done[var] = 1
    # print("初始化后的done",done)
    # print("初始化的first_dic",first_dic)
    for var in varset:
        if done[var] == 0:
            # print("计算",var)
            getFirstForVar(var, first_dic, varset, terminalset, done)
            # print("计算完毕",var)
            # print("此时的done", done)
            # print("此时的first_dic", first_dic)
        else:
            pass
    return first_dic


def getFirstForVar(var, first_dic, varset, terminalset, done):
    # 已经推导过直接结束

    if done[var] == 1:
        # print("我已经推导过了吼")
        return

    # 对非终结符求first集合,先看右边第一个元素为终结符
    for production in production_list:
        if var in production.left:
            if isTerminal(production.right[0], terminalset):
                first_dic[var].add(production.right[0])
                # 用null表示空字符
            if production.right[0] == "null":
                # print("出现右侧为空")
                first_dic[var].add("null")
    # 右边第一个元素为非终结符
    for production in production_list:
        if var in production.left:
            if isVariable(production.right[0], varset):
                if var == production.right[0]:
                    continue
                if done[production.right[0]] == 0:
                    getFirstForVar(production.right[0], first_dic, varset, terminalset, done)
                if "null" in first_dic[production.right[0]]:
                    first_dic[production.right[0]].remove("null")
                first_dic[var] = first_dic[var] | first_dic[production.right[0]]
                # print("将 ",production.right[0],"的集合 ",first_dic[production.right[0]],"并入",var,"的集合中",first_dic[var],"中","得到",)
            if isVariable(production.right[0], varset) and len(production.right) > 1:

                index = 1
                count = 1
                while isVariable(production.right[index], varset):
                    index = index + 1
                    count = count + 1
                    if index >= len(production.right):
                        break
                i = 0
                while i < count:
                    getFirstForVar(production.right[i], first_dic, varset, terminalset, done)
                    if "null" in first_dic[production.right[i]]:
                        getFirstForVar(production.right[i + 1], first_dic, varset, terminalset, done)
                        first_dic[var] = first_dic[var] | first_dic[production.right[i + 1]]
                    else:
                        break
                    i = i + 1
    # 完成后置为1
    done[var] = 1

4. Resuelve el siguiente conjunto


Es la idea central del análisis SLR (1) mejorar la capacidad de reconocimiento mediante el uso del siguiente conjunto de símbolos no terminales.

Solo cuando el conjunto de elementos contiene A → α ·, entonces la acción [i, x] = rj, x pertenece a FOLLOW (A) , j es el número de la producción A → α, de esta manera se puede resolver una parte del desplazamiento y la reducción conflicto.

ps: Hay errores en el código. Si aparece complicado ε en la gramática, por ejemplo, si varios símbolos no terminales se presionan continuamente para que estén vacíos, se producirá un error. El motivo del tiempo y la ausencia de ε en mi definición gramatical no resolverán este problema.

 


def getFollow(varset, terminalset, first_dic, production_list):
    follow_dic = {}
    done = {}
    for var in varset:
        follow_dic[var] = set()
        done[var] = 0
    follow_dic["A1"].add("#")
    # for var in terminalset:
    #     follow_dic[var]=set()
    #     done[var] = 0
    for var in follow_dic:
        getFollowForVar(var, varset, terminalset, first_dic, production_list, follow_dic, done)
    return follow_dic


def getFollowForVar(var, varset, terminalset, first_dic, production_list, follow_dic, done):
    if done[var] == 1:
        return
    for production in production_list:
        if var in production.right:
            ##index这里在某些极端情况下有bug,比如多次出现var,index只会返回最左侧的
            if production.right.index(var) != len(production.right) - 1:
                follow_dic[var] = first_dic[production.right[production.right.index(var) + 1]] | follow_dic[var]
            # 没有考虑右边有非终结符但是为null的情况
            if production.right[len(production.right) - 1] == var:
                if var != production.left[0]:
                    # print(var, "吸纳", production.left[0])
                    getFollowForVar(production.left[0], varset, terminalset, first_dic, production_list, follow_dic,
                                    done)
                    follow_dic[var] = follow_dic[var] | follow_dic[production.left[0]]

    done[var] = 1

5. Cree el conjunto de proyectos LR (0) DFA

1. Primero defina una función de CIERRE, que expandirá continuamente el estado de producción en la colección, y finalmente formará un cierre de conjunto de artículos

def CLOSURE (varset, terminalset, production_set, production_list):

algoritmo:

2. Cree DFA. Definición de función

def generateGraph (begin_production_set, varset, terminalset, production_list):

Primero usamos el número de producción 0 para formar el conjunto de elementos LR (0) inicial, generar el nodo inicial (es decir, la clase en la estructura de datos inicial) y ponerlo en un conjunto, cada vez que se toma un nodo del conjunto para usar Cada var pertenece a (V | T) e intenta transferir. Después de que la transferencia es exitosa, el borde dirigido se almacena en la transferencia del nodo. Después de cada transferencia, el conjunto de elementos se juzga si es un conjunto de elementos nuevo. Si es un conjunto de elementos nuevo, Coloque el nuevo conjunto de elementos en el conjunto y el algoritmo se detiene cuando el conjunto está vacío.

 


# 生成状态转移图
def generatingGraph(begin_production_set, varset, terminalset, production_list):
    global id
    CLOSURE(varset, terminalset, begin_production_set, production_list)
    beginPoint = GraphPoint(begin_production_set, id)
    id = id + 1

    # print("从这个状态开始!")
    # print(beginPoint.id)
    # for onepro in beginPoint.status:
    #     print(onepro.number, " ", onepro.left, "->", onepro.right, "  ")

    pointset = [beginPoint]
    set = varset | terminalset
    stack = [beginPoint]
    while len(stack) != 0:
        currentPoint = stack.pop()
        ######
        # print("该点被弹出,进行转移!")
        # print(currentPoint.id)
        # for onepro in currentPoint.status:
        #     print(onepro.number, " ", onepro.left, "->", onepro.right, "  ")

        #####
        for var in set:
            # print("尝试用",var,"进行转移")
            result = transf(currentPoint.status, var)
            if len(result) == 0:
                # print(var,"转移失败!")
                continue
            else:
                # print(var,"可转移!")
                # print("将使用result进行转移!")
                # for onepro in result:
                #     print(onepro.number, " ", onepro.left, "->", onepro.right, "  ")
                # 求出转移后的闭包
                CLOSURE(varset, terminalset, result, production_list)
                nextpoint = isInPointset(result, pointset)
                if nextpoint is None:
                    # print(var,"转移为新状态:")

                    # 新节点压入寻找栈和点集合中,旧节点不能压入
                    nextpoint = GraphPoint(result, id)
                    id = id + 1
                    pointset.append(nextpoint)
                    stack.append(nextpoint)
                    # print(nextpoint.id)
                    # for onepro in nextpoint.status:
                    #     print(onepro.number, " ", onepro.left, "->", onepro.right, "  ")

                currentPoint.add_transfer(var, nextpoint)
                # print("生成一个新状态")
                # for onepro in result:
                #     print(onepro.number," ",onepro.left,"->",onepro.right,"  ")

    return pointset


# 形成闭包
def CLOSURE(varset, terminalset, production_set=[], production_list=[]):
    sizebefore = len(production_list)
    sizeafter = -1

    # 用来测试是不是已经形成闭包,避免进入死循环
    flag = 0
    for production_in_set in production_set:
        if production_in_set.right.index(".") != len(production_in_set.right) - 1:
            if isVariable(production_in_set.right[production_in_set.right.index(".") + 1], varset):
                flag = 1
    if flag == 0:
        return

    while sizeafter != sizebefore:
        for production_in_set in production_set:
            # 点在最右侧就不可能转移
            if (production_in_set.right.index(".") == len(production_in_set.right) - 1):
                continue
            i = production_in_set.right.index(".") + 1;
            # print(i," length",len(production_in_set.right))
            if isTerminal(production_in_set.right[i], terminalset):
                continue;
            templist = []
            for x in production_list:
                # print(i,len(production_in_set.right))
                if x.left[0] == production_in_set.right[i]:
                    y = copy.deepcopy(x)
                    y.right.insert(0, ".")
                    flag = 0
                    for one in production_set:
                        rightflag = 0;
                        if len(one.right) != len(y.right):
                            rightflag = 1
                        else:
                            for j in range(0, len(y.right)):
                                if one.right[j] != y.right[j]:
                                    rightflag = 1
                        if one.left[0] == y.left[0] and rightflag == 0:
                            flag = 1
                    if flag == 0:
                        templist.append(y)
            sizebefore = len(production_set)
            production_set.extend(templist)
            sizeafter = len(production_set)

 

 

6. Construir tablas de acción e ir a

algoritmo:

La idea de (1) y (2) en el algoritmo es similar al control de inundaciones en la red de computadoras. El nodo inicial se coloca en un conjunto, se toma un nodo del conjunto y todos sus bordes dirigidos se eliminan de un nodo, y esto El nodo se marca como atravesado, y todos los nodos que no se han atravesado antes se colocan en el conjunto, y así sucesivamente, hasta que el conjunto está vacío. Algunas de las declaraciones incorrectamente impresas en el código son declaraciones para detectar si hay conflictos. Debido al límite de tiempo de escritura, la mayoría de los conflictos se pueden detectar, pero una pequeña cantidad de conflictos siguen siendo invisibles (Tiankeng).

El algoritmo (3) (4) se puede juzgar atravesando el estado de producción en el conjunto de elementos.


#Cell为Action中的一个元素,do表示动作,which表示数字,如转移的状态或采用归约的产生式序号,done为是否已经走过,类似于洪泛控制的作用
class Cell:
    def __init__(self):
        self.do = -1
        self.which = -1
        self.done = 0

def initActionAndGoto(pointset, varset, terminalset, begin, follow_dic):
    Action = [[Cell() for i in range(len(terminalset))] for j in range(len(pointset))]
    Goto = [[-1 for i in range(len(varset))] for j in range(len(pointset))]
    for point in pointset:
        # 转移状态
        for tran in point.transfer:
            if isVariable(tran[0], varset):
                if Goto[point.id][getCol(tran[0])] != -1:
                    print("出错404")
                Goto[point.id][getCol(tran[0])] = tran[1].id
            else:
                if Action[point.id][getCol(tran[0])].done == 1:
                    print("出错403")
                Action[point.id][getCol(tran[0])].done = 1
                Action[point.id][getCol(tran[0])].do = "S"
                Action[point.id][getCol(tran[0])].which = tran[1].id
        for production in point.status:
            if production.right.index(".") == len(production.right) - 1 and production.left[0] == begin:
                if Action[point.id][getCol("#")].done == 1:
                    print("出错415")
                Action[point.id][getCol("#")].do = "acc"
                Action[point.id][getCol("#")].done = 1
            if production.right.index(".") == len(production.right) - 1 and production.left[0] != begin:
                # 在follow集中才可归约
                for terminal in terminalset:
                    if terminal in follow_dic[production.left[0]]:

                        # 冲突检测
                        if Action[point.id][getCol(terminal)].done == 1:
                            for xx in point.status:
                                print(xx.number, "  ", xx.left, "->", xx.right)
                            print("Action表", point.id, "行", getCol(terminal), "列冲突")
                            print("原本", Action[point.id][getCol(terminal)].do, Action[point.id][getCol(terminal)].which)
                            print("现在", "R", production.number)
                            print("出错416")
                        Action[point.id][getCol(terminal)].do = "R"
                        Action[point.id][getCol(terminal)].done = 1
                        # 采用该产生式归约
                        Action[point.id][getCol(terminal)].which = production.number

    return Action, Goto

 

7. Realizar análisis gramaticales basados ​​en Action y Goto

Idea de algoritmo:

Al principio, la pila de prefijos del patrón de oración y la estación de estado se insertan en los estados # y 0 respectivamente.

ciclo:

Si hay si en la tabla, inserte el primer elemento del búfer en la pila de prefijos de la oración y presione i (estado) en la pila de estados

Si hay ri en la tabla, la expresión i-ésima se usa para la reducción, el número de elementos que aparecen es el número de elementos en el lado derecho de la expresión i, y luego se ve GOTO de acuerdo con el estado de la parte superior de la pila y el símbolo no terminal obtenido por reducción Table, busque el estado actual e inserte el estado actual y los símbolos no terminales obtenidos por el protocolo en la pila, respectivamente.

¡Si la tabla es un error! , Felicitaciones por el error, busque el error (también es posible que su entrada no se ajuste a la gramática actual, el conflicto gramatical también causará esta situación).

Si acc está en la mesa, felicitaciones por el éxito.


# SLR分析开始
def SLR(Action, Goto, source, production_list):
    source.append([0, "#", "结束符"])
    statusstack = [0]
    sentence_stack = ["#"]
    print(source)
    while 1:
        print("*****************************************")
        print("缓冲区剩余元素", source)
        terminal = source.pop(0)

        print("状态栈", statusstack)
        print("句型栈", sentence_stack)
        # 移进
        if Action[statusstack[len(statusstack) - 1]][terminal[0]].do == "S":
            print("动作: 移入操作,从缓冲区中读取",terminal[1],"元素进行移入,并根据Action压入",Action[statusstack[len(statusstack) - 1]][terminal[0]].which,"状态")
            statusstack.append(Action[statusstack[len(statusstack) - 1]][terminal[0]].which)
            sentence_stack.append(terminal[1])
        elif Action[statusstack[len(statusstack) - 1]][terminal[0]].do == "R":
            # 归约
            # 记录归约产生式
            r_production = 0
            for production in production_list:
                if production.number == Action[statusstack[len(statusstack) - 1]][terminal[0]].which:
                    r_production = production
            for i in range(len(r_production.right)):
                statusstack.pop()
                sentence_stack.pop()
            statusstack.append(Goto[statusstack[len(statusstack) - 1]][getCol(r_production.left[0])])
            print("动作: 归约操作,根据Action表利用第",r_production.number,"个产生式归约")
            sentence_stack.append(r_production.left[0])
            source.insert(0, terminal)

        elif Action[statusstack[len(statusstack) - 1]][terminal[0]].do == "acc":

            print("!!!!!!!!!!语义分析完成!!!!!!!!!!!!!!")
            break;
        else:
            print("error 462!");

8. Ejecutar y probar


source = [[5, "int", " 关键字"], [1, "lexicalanalysis", " 标识符"], [13, "(", " 左括号"], [14, ")", " 右括号"], [20, "{", " 左大括号"],
          [4, "float", " 关键字"], [1, "a", " 标识符"], [15, ";", " 分号"], [5, "int", " 关键字"], [1, "b", " 标识符"],
          [15, ";", " 分号"], [1, "a", " 标识符"], [12, "=", " 赋值号"], [3, "1.1", " 浮点数"], [15, ";", " 分号"], [1, "b", " 标识符"],
          [12, "=", " 赋值号"], [2, "2", " 整数"], [15, ";", " 分号"], [8, "while", "  关键字"], [13, "(", " 左括号"],
          [1, "b", " 标识符"], [17, "<", " 小于号"], [2, "100", " 整数"], [14, ")", " 右括号"], [20, "{", " 左大括号"],
          [1, "b", " 标识符"], [12, "=", " 赋值号"], [1, "b", " 标识符"], [9, "+", " 加 号"], [2, "1", " 整数"], [15, ";", " 分号"],
          [1, "a", " 标识符"], [12, "=", " 赋值号"], [1, "a", " 标识符"], [9, "+", " 加号"], [2, "3", " 整数"], [15, ";", " 分号"],
          [21, "}", " 右大括号"], [15, ";", " 分号"], [6, "if", " 关键字"], [13, "(", " 左括号"], [1, "a", " 标识符"],
          [16, ">", " 大于号"], [2, "5", " 整数"], [14, ")", " 右括号"], [20, "{", " 左大括号"], [1, "b", " 标识符"],
          [12, "=", " 赋值号"], [1, "b", " 标识符"], [10, "-", " 减号"], [2, "1", " 整数"], [15, ";", " 分号"], [21, "}", " 右大括号"],
          [7, "else", " 关键字"], [20, "{", " 左大括号"], [1, "b", " 标识符"], [12, "=", " 赋值号"], [1, "b", " 标识符"],
          [9, "+", " 加号"], [2, "1", " 整数"], [15, ";", " 分号"], [21, "}", " 右大括号"], [21, "}", " 右大括号"]]
id = 0
varset = {"A1", "A", "E", "I", "D", "F", "G", "M", "P", "K", "T", "L", "B","N"}
terminalset = {"(", ")", "{", "}", ";", "int", "float", "number", "floating", "while", "if", "else", ">", "<", ">=",
               "<=", "==", "=", "#", "+", "-", "id"}
production_list = initProduction()
first_dic = getFirst(production_list, varset, terminalset)
# for x in first_dic:
#     print(x," : ",first_dic[x])
follow_dic = getFollow(varset, terminalset, first_dic, production_list)
# print("follow:")
# for x in follow_dic:
#     print(x, ":", follow_dic[x])
production = Production(["A1"], [".", "A"], 0)

production_set = [production]
# for x in production_set:
#     print(x.number," ",x.left,"->",x.right,"  ")

pointset = generatingGraph(production_set, varset, terminalset, production_list)


begin = "A1"
Action, Goto = initActionAndGoto(pointset, varset, terminalset, begin, follow_dic)
print("**********************GOTO***********************************")
for i in range(len(Goto)):
    print(i, end=" ")
    for j in range(len(Goto[i])):
        print("%3d" % Goto[i][j], end=" ")
    print("")

print("**********************Action***********************************")
for i in range(len(Action)):
    print("%2d" % i, end=": ")
    for j in range(len(Action[i])):
        if (Action[i][j].done == 0):
            print("error!", end="   ")
        else:
            print("%3s" % Action[i][j].do, "%2d" % Action[i][j].which, end="   ")
    print("")

SLR(Action, Goto, source, production_list)

 

resultado:

Tabla GOTO (parcial): (60 * 14)

Mesa de acción (parcial): 60 * 22

Proceso de protocolo (parcial): 142 veces en total

Comienzo:

 

 

Fin:

 

El principio de compilación de código completo se colocará en el blog.

2020.11.12

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43919437/article/details/109644804
Recomendado
Clasificación