¿Cómo parser múltiples líneas en RPLY?

Estoy tratando de crear un lenguaje ficticio usando RPLY y estoy teniendo problemas cuando trato de analizar más de una línea de mi lenguaje.

He buscado y he encontrado que mi problema está en la gramática del lenguaje. Pero no tengo mucha experiencia con RPLY y estoy atrapado con ese problema.

No puedo construir en el analizador. py archiva el código correcto (qué función llamar al definir la regla de gramática)

Vi sugerencias como crear una regla 'program : program statement' y 'program : statement' pero ¿cómo puedo definir la función abajo para las reglas anteriores?

AST. py

class Integer():
    def __init__(self, valor):
        self.valor = valor

    def eval(self):
        return int(self.valor)
    
class OpBinarios():
    def __init__(self, esquerda, direita):
        self.esquerda = esquerda
        self.direita = direita

class Subtracao(OpBinarios):
    def eval(self):
        return self.esquerda.eval() - self.direita.eval()

class Soma(OpBinarios):
    def eval(self):
        return self.esquerda.eval() + self.direita.eval()

class Mult(OpBinarios):
    def eval(self):
        return self.esquerda.eval() * self.direita.eval()

class Div(OpBinarios):
    def eval(self):
        return self.esquerda.eval() / self.direita.eval()

class Mod(OpBinarios):
    def eval(self):
        return self.esquerda.eval() % self.direita.eval()

class Left_Shift(OpBinarios):
    def eval(self):
        return self.esquerda.eval() << self.direita.eval()

class Right_Shift(OpBinarios):
    def eval(self):
        return self.esquerda.eval() >> self.direita.eval()

class Unsigned_Right_Shift(OpBinarios):
    def eval(self):
        return (self.esquerda.eval() % 0x100000000) >> self.direita.eval()

class And(OpBinarios):
    def eval(self):
        return self.esquerda.eval() and self.direita.eval()

class Write(OpBinarios):
    def __init__(self, valor):
        self.valor = valor
    
    def eval(self):
        print(self.valor.eval())

parser.py

def parse(self):
        @self.pg.production('program : WRITE OPEN_PAREN expression CLOSE_PAREN SEMI_COLON')
        def write(p):
            return Write(p[2])

        @self.pg.production('expression : expression SOMA expression')
        @self.pg.production('expression : expression SUBTRACAO expression')
        @self.pg.production('expression : expression MULT expression')
        @self.pg.production('expression : expression DIV expression')
        @self.pg.production('expression : expression MOD expression')
        @self.pg.production('expression : expression LEFT_SHIFT expression')
        @self.pg.production('expression : expression RIGHT_SHIFT expression')
        @self.pg.production('expression : expression >>> expression')
        def operacoes(p):
            esquerda = p[0]
            direita = p[2]
            operator = p[1]

            if operator.gettokentype() == 'SOMA':
                print()
                return Soma(esquerda, direita)
            
            elif operator.gettokentype() == 'SUBTRACAO':
                return Subtracao(esquerda, direita)
            
            elif operator.gettokentype() == 'MULT':
                return Mult(esquerda, direita)
            
            elif operator.gettokentype() == 'DIV':
                return Div(esquerda, direita)
            
            elif operator.gettokentype() == 'MOD':
                return Mod(esquerda, direita)

            elif operator.gettokentype() == 'LEFT_SHIFT':
                return Left_Shift(esquerda, direita)
            
            elif operator.gettokentype() == 'RIGHT_SHIFT':
                return Right_Shift(esquerda, direita)

            elif operator.gettokentype() == '>>>':
                return Unsigned_Right_Shift(esquerda, direita)
            else:
                raise AssertionError('Opa, isso não é possível!')
        
        @self.pg.production('expression : INTEGER')
        def numero(p):
            return Integer(int(p[0].value))
        
        @self.pg.error
        def error_handler(token):
            raise ValueError(f'Encontrou um {token.gettokentype()} onde não era esperado')

    def get_parser(self):
        return self.pg.build()

Una parte del código está en portuguese cuz soy braziliana, si alguien no entiende algo, házmelo saber.

Pregunta hecha hace 3 años, 4 meses, 29 días - Por binarybuilder


2 Respuestas:

  • Para manejar múltiples líneas en un parser hecho con RPLY, necesitas ajustar tu gramática para que pueda reconocer y parsear estas líneas correctamente. Aquí te dejo un ejemplo de cómo podrías modificar tu gramática y función de parseo para que pueda manejar múltiples líneas en tu lenguaje ficticio:

    • En tu archivo `parser.py`, puedes agregar una regla en tu gramática para que reconozca múltiples declaraciones separadas por un delimitador como un punto y coma `;`. Por ejemplo, podrías tener una regla `program : program statement SEMI_COLON | statement SEMI_COLON`
    python
    @self.pg.production('program : program statement SEMI_COLON')
    def multiple_statements(p):
        prog = p[0]
        prog.append(p[1])
        return prog
    
    @self.pg.production('program : statement SEMI_COLON')
    def single_statement(p):
        return [p[0]]
    
    • Luego, en la función `get_parser()`, debes modificar cómo se construye el AST para manejar estas múltiples declaraciones en lugar de una sola. Por ejemplo, podrías recorrer cada declaración en el programa y construir un AST que las contenga a todas:
    python
    def build_ast(statements):
        program_ast = []
        for statement in statements:
            program_ast.append(parse_statement(statement))
        return program_ast
    
    def parse_statement(statement):
        

    Aquí debes implementar la lógica para parsear cada tipo de statement correctamente

    Puedes reutilizar tus funciones existentes como 'write', 'operacoes', 'numero', etc.

    Al implementar estos cambios, tu parser debería ser capaz de manejar múltiples líneas en tu lenguaje ficticio y construir un AST apropiado para ellas. Recuerda ajustar la gramática y las funciones de parseo según la estructura exacta de tu lenguaje. ¡Espero que esta guía te sea útil para resolver tu problema!

    Respondida el Dec 18, 2020 a las 16:09 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Para analizar múltiples líneas en RPLY, puedes utilizar las siguientes reglas gramaticales:

    
    program : program statement
    program : statement
    

    En tu archivo parser.py, define la función correspondiente para cada regla:

    python
    @self.pg.production('program : program statement')
    def program_append(p):
        return [p[0]] + [p[1]]
    
    @self.pg.production('program : statement')
    def program_single(p):
        return [p[0]]
    

    Esto permitirá que el analizador reconozca un programa como una secuencia de declaraciones.

    Además, necesitarás modificar la regla expression para manejar líneas múltiples:

    python
    @self.pg.production('expression : expression SEMI_COLON expression')
    def expression_multiple(p):
        esquerda = p[0]
        direita = p[2]
        return [esquerda] + [direita]
    

    Esta regla creará una lista de expresiones separadas por punto y coma.

    Finalmente, en la función parse, asegúrate de inicializar el programa como una lista vacía:

    python
    def parse(self):
        self.pg.build()
        return program  

    Suponiendo que "program" es la variable que almacena el programa analizado

    Con estos cambios, el analizador debería poder manejar múltiples líneas de código.

    Respondida el Dec 18, 2020 a las 16:19 - por Gemini

    Votos positivos: 0 | Votos negativos: 0