Grammar for access to properties and calls to embedded functions

21 views Asked by At

I'm writing a grammar for a small interpreter in PLY. The part I am working on and where I am having problems is the one that refers to expressions, since this can contain both access to properties and calls to embedded functions for a vector data type and "native" data types, in addition to calls to functions.

I have the following rules:

1. To access an attribute/attributes of an "object"

def p_acceso_atributo_rec(p):
    'acceso_atrib : acceso_atrib PUNTO ID'


def p_acceso_atributo(p):
    'acceso_atrib : ID PUNTO ID'

For example:

person.email
person.address.street

2. To access embedded vector functions or variables of native types

In this case, there are certain "native" functions of the language, for example, toString, toUpperCase, toLowerCase, and certain vector properties, such as length.


def p_expr_llamda_funcion(p):
    'expresion : llamada_funcion_obj'

def p_call_embedded_func(p):
    'llamada_funcion_ob : expresion PUNTO embedded_func PAREN_APERTURA PAREN_CIERRE'

def p_embedded_func_names(p):
    '''
    embedded_func : TO_STRING
                  | TO_UPPER_CASE
                  | TO_LOWER_CASE
    '''

In this case, the problem is that I should be able to call such functions in "literals" too, for example:

true.toString()

100.57.toString()

For that reason I have put expresion instead of ID in the rule.

However, I am not able to recognize an entry like this:

const flag : boolean = true;
console.log("valor true: ", flag.toString());

And a syntax error occurs:

Syntax error at token '.', line 2, column 9

I can't find the problem. Any suggestions?

The complete code is as follows:


import re

from ply import *

import ply.yacc as yacc


reserved = {
    # DATA TYPES
    'number': 'NUMBER',
    'float': 'FLOAT',
    'string': 'STRING',
    'boolean': 'BOOLEAN',
    'char': 'CHAR',
    'null': 'NULL',
    # VARIABLES
    'var': 'VAR',
    'const': 'CONST',
    # EMBEDDED FUNCTIONS
    'parseInt': 'PARSE_INT',
    'parseFloat': 'PARSE_FLOAT',
    'toString': 'TO_STRING',
    'toLowerCase': 'TO_LOWER_CASE',
    'toUpperCase': 'TO_UPPER_CASE',
    'typeof': 'TYPE_OF',
    # VECTOR FUNCTIONS
    'push': 'PUSH',
    'pop': 'POP',
    'indexOf': 'INDEX_OF',
    'join': 'JOIN',
    'length': 'LENGTH',
}

tokens = list(reserved.values()) + [
    'ID',
    'LIT_NUMBER',
    'LIT_FLOAT',
    'LIT_STRING',
    'LIT_BOOLEAN',
    'LIT_CHAR',
    'ASIGNACION',
    'PUNTO',
    'DOS_PUNTOS',
    'PUNTO_COMA',
    'COMA',
    'PLUS',
    'MENOS',
    'MULTI',
    'DIV',
    'MOD',
    'INCREMENTO',
    'DECREMENTO',
    'PAREN_APERTURA',
    'PAREN_CIERRE',
    'LLAVE_APERTURA',
    'LLAVE_CIERRE',
    'CORCHETE_APERTURA',
    'CORCHETE_CIERRE',
    'IGUAL',
    'DIFERENTE',
    'MENOR_QUE',
    'MAYOR_QUE',
    'MENOR_IGUAL',
    'MAYOR_IGUAL',
    'AND',
    'OR',
    'NOT',
    'INTERROGACION',
    'FLECHA',
]

t_ASIGNACION = r'='
t_PUNTO = r'\.'
t_DOS_PUNTOS = r':'
t_PUNTO_COMA = r';'
t_COMA = r','
t_PLUS = r'\+'
t_MENOS = r'-'
t_MULTI = r'\*'
t_DIV = r'/'
t_MOD = r'%'
t_INCREMENTO = r'\+='
t_DECREMENTO = r'-='
t_PAREN_APERTURA = r'\('
t_PAREN_CIERRE = r'\)'
t_LLAVE_APERTURA = r'{'
t_LLAVE_CIERRE = r'}'
t_CORCHETE_APERTURA = r'\['
t_CORCHETE_CIERRE = r'\]'
t_IGUAL = r'=='
t_DIFERENTE = r'!='
t_MENOR_QUE = r'<'
t_MAYOR_QUE = r'>'
t_MENOR_IGUAL = r'<='
t_MAYOR_IGUAL = r'>='
t_AND = r'&&'
t_OR = r'\|\|'
t_NOT = r'!'
t_INTERROGACION = r'\?'
t_FLECHA = r'->'


def t_LIT_FLOAT(t):
    r'([1-9][0-9]*|0)\.[0-9]+'
    try:
        t.value = float(t.value)
    except ValueError:
        t.value = 0.0
    return t


def t_LIT_NUMBER(t):
    r'[1-9]\d*|0'
    try:
        t.value = int(t.value)
    except ValueError:
        t.value = 0
    return t


def t_LIT_BOOLEAN(t):
    r'true|false'
    try:
        if t.value == 'true':
            t.value = True
        elif t.value == 'false':
            t.value = False
    except ValueError:
        t.value = False
    return t


def t_LIT_STRING(t):
    r'"([^\\"]|(\\.))*?"'
    t.value = t.value[1:-1]
    return t


def t_LIT_CHAR(t):
    r"'([^\\']|(\\.))'"
    t.value = t.value[1:-1]
    return t


def t_ID(t):
    r'[a-zA-Z_][a-zA-Z0-9_]*'
    t.type = reserved.get(t.value, 'ID')
    return t


def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)


def t_COMENTARIO_ML(t):
    r'/\*(.|\n)*?\*/'
    t.lexer.lineno += t.value.count('\n')


def t_COMENTARIO_UL(t):
    r'(//.*?(\n|$))'


t_ignore = ' \t'


def find_column(input_text, lexpos):
    last_cr = input_text.rfind('\n', 0, lexpos)
    if last_cr < 0:
        last_cr = 0
    column = (lexpos - last_cr) + 1
    return column


def t_error(t):
    print(f'Carácter no reconocido: "{t.value[0]}"')
    t.lexer.skip(1)


lexer = lex.lex(reflags=re.UNICODE | re.VERBOSE)

precedence = (
    ('left', 'OR'),
    ('left', 'AND'),
    ('left', 'IGUAL', 'DIFERENTE'),
    ('left', 'MENOR_QUE', 'MAYOR_QUE', 'MENOR_IGUAL', 'MAYOR_IGUAL'),
    ('left', 'PLUS', 'MENOS'),
    ('left', 'MULTI', 'DIV', 'MOD'),
    ('right', 'NOT', 'UMENOS'),
    ('right', 'CORCHETE_APERTURA'),
)


def p_axioma(p):
    'axioma : instrucciones_glob'
    p[0] = p[1]


def p_instrucciones_glob_rec(p):
    'instrucciones_glob : instrucciones_glob instruccion'
    if p[1] is None:
        p[1] = []
    if p[2] is not None:
        p[1].append(p[2])
    p[0] = p[1]


def p_instrucciones_glob(p):
    'instrucciones_glob : '


def p_instruccion(p):
    '''
    instruccion : declaracion PUNTO_COMA
                | asignacion PUNTO_COMA
                | llamada_funcion PUNTO_COMA
    '''
    p[0] = p[1]


def p_declaracion(p):
    'declaracion : VAR ID DOS_PUNTOS tipo_dato'


def p_declaracion_valor(p):
    'declaracion : VAR ID DOS_PUNTOS tipo_dato ASIGNACION expresion'


def p_declaracion_const(p):
    'declaracion : CONST ID DOS_PUNTOS tipo_dato ASIGNACION expresion'


def p_declaracion_vect(p):
    'declaracion : VAR ID DOS_PUNTOS tipo_dato CORCHETE_APERTURA CORCHETE_CIERRE ASIGNACION CORCHETE_APERTURA lista_expr CORCHETE_CIERRE'


def p_declaracion_vect_const(p):
    'declaracion : CONST ID DOS_PUNTOS tipo_dato CORCHETE_APERTURA CORCHETE_CIERRE ASIGNACION CORCHETE_APERTURA lista_expr CORCHETE_CIERRE'


def p_declaracion_vect_copia(p):
    'declaracion : VAR ID DOS_PUNTOS tipo_dato CORCHETE_APERTURA CORCHETE_CIERRE ASIGNACION ID'


def p_declaracion_vect_copia_const(p):
    'declaracion : CONST ID DOS_PUNTOS tipo_dato CORCHETE_APERTURA CORCHETE_CIERRE ASIGNACION ID'


def p_declaracion_interface(p):
    'declaracion : VAR ID DOS_PUNTOS ID ASIGNACION LLAVE_APERTURA def_atributos LLAVE_CIERRE'


def p_def_atributos_rec(p):
    'def_atributos : def_atributos ID DOS_PUNTOS expresion PUNTO_COMA'
    if p[1] is None:
        p[1] = []
    p[1].append((p[2], p[4]))
    p[0] = p[1]


def p_def_atributos(p):
    'def_atributos : ID DOS_PUNTOS expresion PUNTO_COMA'
    p[0] = [(p[1], p[3])]


def p_acceso_atributo_rec(p):
    'acceso_atrib : acceso_atrib PUNTO ID'


def p_acceso_atributo(p):
    'acceso_atrib : ID PUNTO ID'


def p_lista_atrib_rec(p):
    'lista_atrib : lista_atrib ID DOS_PUNTOS tipo_interface PUNTO_COMA'


def p_lista_atrib(p):
    'lista_atrib : ID DOS_PUNTOS tipo_interface PUNTO_COMA'


def p_tipo_interface_u(p):
    'tipo_interface : ID'


def p_tipo_interface(p):
    'tipo_interface : tipo_dato'


def p_asignacion(p):
    'asignacion : ID ASIGNACION expresion'


def p_asignacion_incr(p):
    'asignacion : ID INCREMENTO expresion'


def p_asignacion_decr(p):
    'asignacion : ID DECREMENTO expresion'


def p_asignacion_vect_matriz(p):
    'asignacion : ID lista_acceso ASIGNACION expresion '


def p_llamada_funcion_instr(p):
    'llamada_funcion : ID PAREN_APERTURA lista_expr PAREN_CIERRE'


def p_call_embedded_func(p):
    'llamada_funcion_obj : expresion PUNTO embedded_func PAREN_APERTURA PAREN_CIERRE'


def p_embedded_func_names(p):
    '''
    embedded_func : TO_STRING
                  | TO_UPPER_CASE
                  | TO_LOWER_CASE
    '''


def p_lista_instr_bloque_rec(p):
    'lista_instr_bloque : lista_instr_bloque instr_bloque'
    if p[1] is None:
        p[1] = []
    if p[2] is not None:
        p[1].append(p[2])
    p[0] = p[1]


def p_lista_instr_bloque(p):
    'lista_instr_bloque : '


def p_instr_bloque(p):
    '''
    instr_bloque : declaracion PUNTO_COMA
                 | asignacion PUNTO_COMA
                 | llamada_funcion PUNTO_COMA
    '''
    p[0] = p[1]


def p_tipo_dato(p):
    '''
    tipo_dato : NUMBER
              | FLOAT
              | CHAR
              | BOOLEAN
              | STRING
    '''


def p_lista_expr_rec(p):
    'lista_expr : expresion'
    p[0] = [p[1]]


def p_lista_expr(p):
    'lista_expr : lista_expr COMA expresion'
    if p[1] is None:
        p[1] = [p[3]]
    else:
        p[1].append(p[3])
    p[0] = p[1]


def p_lista_expr_vacia(p):
    'lista_expr : '
    p[0] = []


def p_expresion_binaria(p):
    '''
    expresion : expresion PLUS expresion
              | expresion MENOS expresion
              | expresion MULTI expresion
              | expresion DIV expresion
              | expresion MOD expresion
              | expresion IGUAL expresion
              | expresion DIFERENTE expresion
              | expresion MENOR_QUE expresion
              | expresion MAYOR_QUE expresion
              | expresion MENOR_IGUAL expresion
              | expresion MAYOR_IGUAL expresion
              | expresion AND expresion
              | expresion OR expresion
    '''


def p_expr_agrupada(p):
    'expresion : PAREN_APERTURA expresion PAREN_CIERRE'


def p_expresion_unaria(p):
    '''
    expresion : MENOS expresion %prec UMENOS
              | NOT expresion
    '''


def p_expr_id(p):
    'expresion : ID'


def p_expr_acceso_vect_mat(p):
    'expresion : ID lista_acceso'


def p_expr_llamda_funcion(p):
    'expresion : llamada_funcion_obj'


def p_lista_acceso_dims_rec(p):
    'lista_acceso : lista_acceso CORCHETE_APERTURA expresion CORCHETE_CIERRE'


def p_acceso_dim(p):
    'lista_acceso : CORCHETE_APERTURA expresion CORCHETE_CIERRE'


def p_expresion_literal(p):
    'expresion : literal'


def p_expresion_llamada_func(p):
    'expresion : ID PAREN_APERTURA lista_expr PAREN_CIERRE'


def p_expr_parse_int(p):
    'expresion : PARSE_INT PAREN_APERTURA expresion PAREN_CIERRE'


def p_expr_parse_float(p):
    'expresion : PARSE_FLOAT PAREN_APERTURA expresion PAREN_CIERRE'


def p_expr_type_of(p):
    'expresion : TYPE_OF expresion'


def p_expr_acceso_atributo(p):
    'expresion : acceso_atrib'


def p_literal(p):
    '''
    literal : LIT_NUMBER
            | LIT_FLOAT
            | LIT_CHAR
            | LIT_BOOLEAN
            | LIT_STRING
    '''


def p_error(p):
    if p:
        print(f'Error sintáctico: {p.type}')
        print("Syntax error at token '%s', line %s, column %s" % (
            p.value, p.lineno, find_column(p.lexer.lexdata, p.lexpos)))
        parser.errok()
    else:
        print('Syntax error at EOF')


parser = yacc.yacc(debug=True)

if __name__ == '__main__':
    archivo_entrada = open('Embebidas.olc')

    entrada = archivo_entrada.read()

    lexer.input(entrada)

    instrucciones = parser.parse(entrada)
0

There are 0 answers