class AnalizadorSemantico: def __init__(self, ast): self.ast = ast self.tabla_simbolos = {} self.errores = [] def analizar(self): for nodo in self.ast: self.analizar_instruccion(nodo) return { "variables_declaradas": self.tabla_simbolos, "errores_semanticos": self.errores } def analizar_instruccion(self, nodo): tipo = nodo["type"] if tipo == "declaration": var = nodo["var"] dtype = nodo["datatype"] if var in self.tabla_simbolos: self.errores.append(f"Variable '{var}' ya fue declarada.") else: self.tabla_simbolos[var] = dtype elif tipo == "assign": if nodo["var"] not in self.tabla_simbolos: self.errores.append(f"Variable '{nodo['var']}' usada sin declarar.") return tipo_valor = self.analizar_expresion(nodo["value"]) tipo_var = self.tabla_simbolos[nodo["var"]] if tipo_valor != tipo_var and tipo_valor != "error": self.errores.append(f"Tipo incompatible en asignación a '{nodo['var']}': {tipo_var} = {tipo_valor}") elif tipo in ("if", "while"): tipo_cond = self.analizar_expresion(nodo["condition"]) if tipo_cond != "boolean": self.errores.append( f"La condición de '{tipo}' debe ser tipo boolean, no '{tipo_cond}'" ) for instr in nodo["body"]: self.analizar_instruccion(instr) elif tipo == "function": self.validar_funcion(nodo["name"], nodo["arg"]) else: self.errores.append(f"Instrucción no reconocida: {nodo}") def analizar_expresion(self, expr): tipo = expr["type"] if tipo == "num": return "float" if "." in expr["value"] else "int" elif tipo == "var": nombre = expr["value"] if nombre not in self.tabla_simbolos: self.errores.append(f"Variable '{nombre}' usada sin declarar.") return "error" return self.tabla_simbolos[nombre] elif tipo == "binop": tipo_izq = self.analizar_expresion(expr["left"]) tipo_der = self.analizar_expresion(expr["right"]) if tipo_izq != tipo_der: self.errores.append(f"Tipos incompatibles: {tipo_izq} y {tipo_der}") return "error" if expr["op"] in ("EQUAL", "NOT_EQUAL", "GREATER", "LESS"): return "boolean" return tipo_izq elif tipo == "bool": return "boolean" elif tipo == "string": return "string" else: self.errores.append(f"Expresión no válida: {expr}") return "error" def validar_funcion(self, nombre, arg): funciones_sin_argumento = { "ACTIVATE_ALARM", "ACTIVATE_SENSOR", "BREAK", "CHARGE_BATTERY", "CHECK_BATTERY", "CLOSE_DOOR", "CONTINUE", "DEACTIVATE_ALARM", "DEACTIVATE_SENSOR", "DECREASE_SPEED", "DOWNLOAD", "REBOOT", "READ_SENSOR", "RESET", "RESUME", "REVERSE", "SHUTDOWN", "SHUT_OFF", "START", "STOP", "STOP_IMMEDIATELY", "TOGGLE_LIGHT", "TURN_DOWN", "TURN_LEFT", "TURN_RIGHT", "TURN_UP", "UNLOCK", "LOG", "INIT", "LOCK", "LOW_BATTERY", "OPEN_DOOR", "PAUSE" } funciones_con_argumento = { "CALIBRATE", "COPY_FILE", "DELETE_FILE", "MOVE_BACKWARD", "MOVE_FORWARD", "MOVE_TO", "PRINT", "RENAME_FILE", "ROTATE", "SAVE_FILE", "SCAN", "SET", "SET_SPEED", "UPLOAD", "UPLOAD_FILE", "WAIT" } if nombre in funciones_sin_argumento: if arg is not None: self.errores.append(f"La función '{nombre}' no debe tener argumentos.") elif nombre in funciones_con_argumento: if arg is None: self.errores.append(f"La función '{nombre}' requiere un argumento.") else: self.analizar_expresion(arg) else: self.errores.append(f"Función '{nombre}' no reconocida.")