Spaces:
Running
Running
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()}") | |