def test_lex_01_reserved_words(self): gLexer = gSLLexer() #lex.runmain(data = "and archivo caso const constantes desde eval fin\n" #"hasta inicio lib libext matriz mientras not or\n" #"paso programa ref registro repetir retorna si\n" #"sino sub subrutina tipos var variables vector\n") run_import("lex_01_reserved_words") result = sys.stdout.getvalue() self.assert_(check_expected(result, #self.assertEquals(result, "(AND,'and',1,0)\n" "(ARCHIVO,'archivo',1,4)\n" "(CASO,'caso',1,12)\n" "(CONSTANTES,'const',1,17)\n" "(CONSTANTES,'constantes',1,23)\n" "(DESDE,'desde',1,34)\n" "(EVAL,'eval',1,40)\n" "(FIN,'fin',1,45)\n" "(HASTA,'hasta',2,49)\n" "(INICIO,'inicio',2,55)\n" "(LIB,'lib',2,62)\n" "(LIBEXT,'libext',2,66)\n" "(MATRIZ,'matriz',2,73)\n" "(MIENTRAS,'mientras',2,80)\n" "(NOT,'not',2,89)\n" "(OR,'or',2,93)\n" "(PASO,'paso',3,96)\n" "(PROGRAMA,'programa',3,101)\n" "(REF,'ref',3,110)\n" "(REGISTRO,'registro',3,114)\n" "(REPETIR,'repetir',3,123)\n" "(RETORNA,'retorna',3,131)\n" "(SI,'si',3,139)\n" "(SINO,'sino',4,142)\n" "(SUBRUTINA,'sub',4,147)\n" "(SUBRUTINA,'subrutina',4,151)\n" "(TIPOS,'tipos',4,161)\n" "(VARIABLES,'var',4,167)\n" "(VARIABLES,'variables',4,171)\n" "(VECTOR,'vector',4,181)\n") )
def gSLParser(debug): DEBUG = debug # Funciones utilitarias def print_debug(mensaje): # Para saber el nombre de la funcion en la que estamos function_name = inspect.stack()[1][3] if DEBUG: print "gSL DEBUG >> Funcion: ", function_name, ">" , mensaje # Establecemos las precedencias y asociatividad precedence = ( ('left','S_MAS','S_MENOS'), ('left','S_MULT','S_DIV'), ('right','U_S_MENOS','U_S_MAS'), ) # Diccionario que contiene los identificadores que vamos encontrando identificadores = { } def p_start(p): """ start : PROGRAMA IDENTIFICADOR body | body """ astree = Module( body = []) # Antes que nada se agregan los tipos de datos predefinidos tipos_predefinidos = [ Assign(targets = [Name(id = 'cadena', ctx = Store())], value = Str(s = '')), Assign(targets = [Name(id = 'numerico', ctx = Store())], value = Num(n = 0)), Assign(targets = [Name(id = 'logico', ctx = Store())], value = Name( id = 'True', ctx = Load())) ] astree.body = astree.body + tipos_predefinidos if len(p) == 4: # guardar ID del programa astree.body.append(Expr(value=Str(s=p[2]))) # guardar las instrucciones del cuerpo if (p[3] != []): print_debug(p[3]) astree.body = astree.body + p[3] print_debug("Nombre del programa: " + p[2]) print_debug("Tabla de simbolos: " + str(identificadores)) elif len (p) == 2: # guardar las instrucciones del cuerpo if (p[1] != []): astree.body = astree.body + p[1] print_debug("Nombre del programa: sin nombre definido") astree = fix_missing_locations(astree) p[0] = astree print_debug(dump(astree)) def p_body(p): """ body : declaration_list body_statements | declaration_list body_statements subrutine_list """ # guardar las instrucciones del cuerpo p[0] = p[1] + p[2] if len(p) == 4: p[0] = p[0] + p[3] def p_declaration_list(p): """ declaration_list : declaration_list declaration | declaration """ if len(p) == 3: if p[2] == None or p[2] == []: p[0] = p[1] else: p[0] = p[1] + p[2] if len(p) == 2: if p[1] == None or p[1] == []: p[0] = [] else: p[0] = p[1] for ass in p[0]: print_debug("declaraciones: "+ dump(ass)) def p_body_statements(p): """ body_statements : INICIO statement_list FIN """ print_debug("Cuerpo principal") p[0] = p[2] def p_statement_list(p): """ statement_list : statement_list statement | statement """ if len(p) == 2: print_debug("Instruccion: " + str(p[1])) if len(p) == 3: p[0] = p[1] + [p[2]] if len(p) == 2: if p[1] == None or p[1] == []: p[0] = [] else: p[0] = [p[1]] def p_empty_statement(p): """ statement : empty """ #p[0] = p[1] #"asf" def p_subrutine_list(p): """ subrutine_list : subrutine_list subrutine | subrutine """ if len(p) == 3: p[0] = p[1] + [p[2]] if len(p) == 2: p[0] = [p[1]] def p_subrutine(p): """ subrutine : subrutine_signature declaration_list body_statements """ # Asignar al ambito secundario, registrar signature #p[0] = [] def p_subrutine_signature(p): """ subrutine_signature : function_signature | procedure_signature """ #p[0] = [] def p_function_signature(p): """ function_signature : SUBRUTINA IDENTIFICADOR PAREN_I parameters_list PAREN_D RETORNA IDENTIFICADOR """ # XXX Recordar el manejo de la instruccion "retorna" # XXX Falta lista de parametros print_debug("Funcion creada: " + p[2]) print_debug("Funcion retorna: " + p[6]) #p[0] = [] def p_procedure_signature(p): """ procedure_signature : SUBRUTINA IDENTIFICADOR PAREN_I parameters_list PAREN_D """ print_debug("Procedimiento creado: " + p[2]) print_debug("Parametros: " + str(p[4])) # XXX Falta lista de parametros #p[0] = [] def p_parameters_list(p): """ parameters_list : parameters_list PUNTO_Y_COMA parameters_item | parameters_item """ #p[0] = [] def p_parameters_item(p): """ parameters_item : reference_optional variables_item | empty """ #p[0] = [] def p_reference_optional(p): """ reference_optional : REF | empty """ #p[0] = [] def p_declaration(p): """ declaration : VARIABLES variables_item_list | TIPOS tipos_item_list | CONSTANTES constantes_item_list | empty """ if len(p) == 3: print_debug("Declaracion: " + p[1]) p[0] = p[2] def p_variables_item_list(p): """ variables_item_list : variables_item_list variables_item | variables_item """ # Agregar a la tabla de simbolos, inicializar if len(p) == 3: p[0] = p[1] + [p[2]] if len(p) == 2: p[0] = [p[1]] def p_variables_item(p): """ variables_item : id_list DOS_PUNTOS IDENTIFICADOR """ print_debug("Tipo de la variable: (" + p[3] + ")") #XXX Controlar que IDENTIFICADOR sea un tipo de dato id_list = [] for var_id in p[1]: id_list.append(Name(id = var_id, ctx = Store())) p[0] = Assign(targets = id_list, value = Name(id = p[3], ctx = Load())) def p_tipos_item_list(p): """ tipos_item_list : tipos_item_list tipos_item | tipos_item """ #p[0] = [] def p_tipos_item(p): """ tipos_item : IDENTIFICADOR DOS_PUNTOS IDENTIFICADOR """ print_debug("Tipo definido por usuario: (" + p[1] +":"+ p[3] + ")") #p[0] = [] def p_constantes_item_list(p): """ constantes_item_list : constantes_item_list constantes_item | constantes_item """ # Agregar a la tabla de simbolos, inicializar def p_constantes_item(p): """ constantes_item : IDENTIFICADOR S_ASIGNACION IDENTIFICADOR | IDENTIFICADOR S_ASIGNACION NUMERO | IDENTIFICADOR S_ASIGNACION CADENA """ # XXX El segundo IDENTIFICADOR en la primera produccion debe ser # necesariamente otra constante (incluyendo constantes predefinidas # tales como TRUE y FALSE print_debug("Constante definida por usuario: (" + str(p[1]) +":"+ str(p[3]) + ")") #p[0] = [] def p_id_list(p): """ id_list : id_list COMA IDENTIFICADOR | IDENTIFICADOR """ if len(p) == 4: p[0] = [p[3]] + p[1] elif len(p) == 2: p[0] = [p[1]] identificadores[p[1]] = 0 # Define e inicializa print_debug( "Lista IDs: (" + str(p[0]) + ")") def p_empty(p): """ empty : """ #p[0] = [] pass def p_statement_assign(p): 'statement : IDENTIFICADOR S_ASIGNACION expression' try: p[0] = identificadores[p[1]] # El ID debe estar previamente definido identificadores[p[1]] = p[3] print_debug(p[1] + ' <- ' + str(p[3])) except LookupError: print_debug("'%s' no está definido'" % p[1]) raise NameError("'%s' no está definido" % p[1]) p[0] = Assign(targets=[Name(id=p[1], ctx=Store())], value=p[3]) def p_statement_subrutine_call(p): 'statement : subrutine_call' p[0] = p[1] def p_subrutine_call(p): 'subrutine_call : IDENTIFICADOR PAREN_I arguments_list PAREN_D' print_debug("Llamada a subrutina: " + p[1] + ", argumentos: " + str(p[3])) # Si no se reciben argumentos, pasar lista vacía if p[3] == [None]: p[3] = [] p[0] = Expr(value = Call(func = Name(id = p[1], ctx=Load()), args = p[3], keywords=[], starargs=None, kwargs=None)) print_debug(dump(p[0])) def p_arguments_list(p): """arguments_list : arguments_list COMA argument | argument """ if len(p) == 4: p[0] = p[1] + [p[3]] elif len(p) == 2: p[0] = [p[1]] def p_argument(p): """ argument : expression | empty """ p[0] = p[1] def p_expression_binop(p): '''expression : expression S_MAS expression | expression S_MENOS expression | expression S_MULT expression | expression S_DIV expression''' if p[2] == '+' : p[0] = BinOp(left=p[1], op=Add(), right=p[3]) elif p[2] == '-': p[0] = BinOp(left=p[1], op=Sub(), right=p[3]) elif p[2] == '*': p[0] = BinOp(left=p[1], op=Mult(), right=p[3]) elif p[2] == '/': p[0] = BinOp(left=p[1], op=Div(), right=p[3]) def p_expression_uminus(p): 'expression : S_MENOS expression %prec U_S_MENOS' p[0] = UnaryOp(op=USub(), operand=p[2]) def p_expression_uplus(p): 'expression : S_MAS expression %prec U_S_MAS' p[0] = UnaryOp(op=UAdd(), operand=p[2]) def p_expression_group(p): 'expression : PAREN_I expression PAREN_D' p[0] = p[2] def p_expression_numero(p): 'expression : NUMERO' p[0] = Num(n=p[1]) def p_expression_identificador(p): 'expression : IDENTIFICADOR' try: p[0] = identificadores[p[1]] except LookupError: print("Identificador no está definido: '%s'" % p[1]) p[0] = 0 p[0] = Name(id=p[1], ctx=Load()) def p_expression_subrutine_call(p): "expression : subrutine_call" p[0] = -1 # XXX Por el momento se asigna -1 para ver el efecto que tien en las expresiones def p_error(t): print("Syntax error at '%s'" % t.value) # Build and return the parser from gSLLexer import gSLLexer, tokens import ply.yacc as yacc gLexer = gSLLexer() return yacc.yacc()