from typing import List, Tuple, Any Token = Tuple[str, str] FUNCTIONS = { "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", "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" } TYPES = {"int", "float", "boolean"} class Parser: def __init__(self, tokens: List[Token]): self.tokens = tokens self.pos = 0 self.ast = [] def current(self) -> Token: return self.tokens[self.pos] if self.pos < len(self.tokens) else ("EOF", "") def match(self, expected_type: str) -> Token: if self.current()[0] == expected_type: tok = self.current() self.pos += 1 return tok raise SyntaxError(f"Se esperaba {expected_type} pero se encontró {self.current()}") def parse(self): while self.current()[0] != "EOF": self.ast.append(self.instruction()) return self.ast def instruction(self) -> Any: token = self.current() if token[0] in TYPES: return self.declaration() elif token[0] == "IF": return self.if_statement() elif token[0] == "WHILE": return self.while_statement() elif token[0] in FUNCTIONS: return self.function_call() elif token[0] == "IDENTIFIER": return self.assignment() else: raise SyntaxError(f"Instrucción no válida: {token}") def declaration(self): tipo = self.match(self.current()[0])[0] nombre = self.match("IDENTIFIER")[1] self.match("SEMICOLON") return {"type": "declaration", "var": nombre, "datatype": tipo} def assignment(self): ident = self.match("IDENTIFIER")[1] self.match("ASSIGN") expr = self.expression() self.match("SEMICOLON") return {"type": "assign", "var": ident, "value": expr} def if_statement(self): self.match("IF") self.match("OPEN_PAREN") condition = self.expression() self.match("CLOSE_PAREN") self.match("THEN") self.match("OPEN_BRACE") body = [] while self.current()[0] != "CLOSE_BRACE": body.append(self.instruction()) self.match("CLOSE_BRACE") return {"type": "if", "condition": condition, "body": body} def while_statement(self): self.match("WHILE") self.match("OPEN_PAREN") condition = self.expression() self.match("CLOSE_PAREN") self.match("THEN") self.match("OPEN_BRACE") body = [] while self.current()[0] != "CLOSE_BRACE": body.append(self.instruction()) self.match("CLOSE_BRACE") return {"type": "while", "condition": condition, "body": body} def function_call(self): func_name = self.current()[0] self.match(func_name) 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" } 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" } if func_name in funciones_con_argumento: if self.current()[0] != "OPEN_PAREN": raise SyntaxError(f"La función '{func_name}' requiere un argumento entre paréntesis.") self.match("OPEN_PAREN") arg = self.expression() self.match("CLOSE_PAREN") self.match("SEMICOLON") return {"type": "function", "name": func_name, "arg": arg} elif func_name in funciones_sin_argumento: if self.current()[0] == "OPEN_PAREN": raise SyntaxError(f"La función '{func_name}' no debe llevar argumentos ni paréntesis.") self.match("SEMICOLON") return {"type": "function", "name": func_name, "arg": None} else: raise SyntaxError(f"Función '{func_name}' no reconocida o mal definida.") def expression(self): left = self.term() while self.current()[0] in ("PLUS", "MINUS", "EQUAL", "NOT_EQUAL", "GREATER", "LESS", "AND", "OR"): op = self.match(self.current()[0])[0] right = self.term() left = {"type": "binop", "op": op, "left": left, "right": right} return left def term(self): token_type, token_value = self.current() if token_type == "IDENTIFIER": return {"type": "var", "value": self.match("IDENTIFIER")[1]} elif token_type in ("INT", "FLOAT"): return {"type": "num", "value": self.match(token_type)[1]} elif token_type in ("TRUE", "FALSE"): return {"type": "bool", "value": self.match(token_type)[0]} elif token_type == "STRING": return {"type": "string", "value": self.match("STRING")[1]} elif token_type == "OPEN_PAREN": self.match("OPEN_PAREN") expr = self.expression() self.match("CLOSE_PAREN") return expr else: raise SyntaxError(f"Expresión inválida: {self.current()}")