PRIMER COMMIT
This commit is contained in:
555
interprete.py
Normal file
555
interprete.py
Normal file
@@ -0,0 +1,555 @@
|
||||
"""
|
||||
Intérprete de zaplang usando ANTLR4 (visitor pattern).
|
||||
Incluye funciones IO integradas: imprimir, imprimirln, leer, leerEnt, leerFlot.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import math
|
||||
from antlr4 import *
|
||||
from antlr4.error.ErrorListener import ErrorListener
|
||||
|
||||
from zaplangLexer import zaplangLexer
|
||||
from zaplangParser import zaplangParser
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Señales de control de flujo
|
||||
# ─────────────────────────────────────────────
|
||||
class RetornarSenal(Exception):
|
||||
def __init__(self, valor): self.valor = valor
|
||||
|
||||
class FinSenal(Exception): pass # break
|
||||
class InterrupSenal(Exception): pass # continue
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Entorno (scoping)
|
||||
# ─────────────────────────────────────────────
|
||||
class Entorno:
|
||||
def __init__(self, padre=None):
|
||||
self.vars = {}
|
||||
self.padre = padre
|
||||
|
||||
def definir(self, nombre, valor):
|
||||
self.vars[nombre] = valor
|
||||
|
||||
def obtener(self, nombre):
|
||||
if nombre in self.vars:
|
||||
return self.vars[nombre]
|
||||
if self.padre:
|
||||
return self.padre.obtener(nombre)
|
||||
raise NameError(f"Variable no definida: '{nombre}'")
|
||||
|
||||
def asignar(self, nombre, valor):
|
||||
if nombre in self.vars:
|
||||
self.vars[nombre] = valor
|
||||
return
|
||||
if self.padre:
|
||||
self.padre.asignar(nombre, valor)
|
||||
return
|
||||
raise NameError(f"Variable no definida: '{nombre}'")
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Funciones IO integradas
|
||||
# ─────────────────────────────────────────────
|
||||
def _procesar_cadena(s):
|
||||
"""Interpreta secuencias de escape en cadenas."""
|
||||
return s.encode('raw_unicode_escape').decode('unicode_escape')
|
||||
|
||||
FUNCIONES_IO = {
|
||||
# imprimir(val, ...) → imprime sin salto de línea
|
||||
"imprimir": lambda args: print(*[_fmt(a) for a in args], end=""),
|
||||
# imprimirln(val, ...) → imprime con salto de línea
|
||||
"imprimirln": lambda args: print(*[_fmt(a) for a in args]),
|
||||
# leer() → lee una línea como cadena
|
||||
"leer": lambda args: input(),
|
||||
# leerEnt() → lee un entero
|
||||
"leerEnt": lambda args: int(input()),
|
||||
# leerFlot() → lee un flotante
|
||||
"leerFlot": lambda args: float(input()),
|
||||
# leerCarac() → lee un carácter
|
||||
"leerCarac": lambda args: input()[0] if input() else '\0',
|
||||
# longitud(s) → len de cadena
|
||||
"longitud": lambda args: len(str(args[0])),
|
||||
}
|
||||
|
||||
def _fmt(v):
|
||||
if isinstance(v, bool): return "verdadero" if v else "falso"
|
||||
if isinstance(v, float) and v == int(v): return str(int(v))
|
||||
return str(v)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Visitor / Intérprete
|
||||
# ─────────────────────────────────────────────
|
||||
class Interprete:
|
||||
def __init__(self):
|
||||
self.global_env = Entorno()
|
||||
self.funciones = {} # nombre → ctx de declaracionFuncion
|
||||
self._registrar_io()
|
||||
|
||||
def _registrar_io(self):
|
||||
"""Registra las funciones IO como callables nativos."""
|
||||
for nombre, fn in FUNCIONES_IO.items():
|
||||
self.funciones[nombre] = fn # callable nativo
|
||||
|
||||
# ── Entrada principal ──────────────────────────────────────
|
||||
def ejecutar(self, arbol):
|
||||
self.visitar_unidad(arbol, self.global_env)
|
||||
|
||||
def visitar_unidad(self, ctx, env):
|
||||
for decl in ctx.declaracionExterna():
|
||||
self.visitar_declaracion_externa(decl, env)
|
||||
# Buscar y ejecutar main
|
||||
if "main" not in self.funciones:
|
||||
raise RuntimeError("No se encontró la función 'main'")
|
||||
self.llamar_funcion("main", [], env)
|
||||
|
||||
def visitar_declaracion_externa(self, ctx, env):
|
||||
if ctx.declaracionFuncion():
|
||||
self.registrar_funcion(ctx.declaracionFuncion())
|
||||
elif ctx.declaracionVariable():
|
||||
self.visitar_decl_variable(ctx.declaracionVariable(), env)
|
||||
elif ctx.declaracionEstruct():
|
||||
pass # extensible
|
||||
elif ctx.declaracionEnum():
|
||||
self.visitar_decl_enum(ctx.declaracionEnum(), env)
|
||||
|
||||
# ── Funciones ──────────────────────────────────────────────
|
||||
def registrar_funcion(self, ctx):
|
||||
nombre = ctx.identificadorFuncion().Identificador().getText()
|
||||
self.funciones[nombre] = ctx
|
||||
|
||||
def llamar_funcion(self, nombre, args, env):
|
||||
fn = self.funciones.get(nombre)
|
||||
if fn is None:
|
||||
raise RuntimeError(f"Función no definida: '{nombre}'")
|
||||
# Nativa (IO)
|
||||
if callable(fn) and not hasattr(fn, 'listaParametros'):
|
||||
return fn(args)
|
||||
# Definida en zaplang
|
||||
local = Entorno(self.global_env)
|
||||
params = fn.listaParametros()
|
||||
if params:
|
||||
param_list = params.declaracionParametro()
|
||||
for i, param in enumerate(param_list):
|
||||
pnombre = param.Identificador().getText()
|
||||
valor = args[i] if i < len(args) else None
|
||||
local.definir(pnombre, valor)
|
||||
try:
|
||||
self.visitar_bloque(fn.bloque(), local)
|
||||
except RetornarSenal as r:
|
||||
return r.valor
|
||||
return None
|
||||
|
||||
# ── Bloque y sentencias ────────────────────────────────────
|
||||
def visitar_bloque(self, ctx, env):
|
||||
if ctx.LlaveIzq():
|
||||
for dv in ctx.declaracionVariable():
|
||||
self.visitar_decl_variable(dv, env)
|
||||
for sent in ctx.sentencia():
|
||||
self.visitar_sentencia(sent, env)
|
||||
else:
|
||||
self.visitar_sentencia(ctx.sentencia(), env)
|
||||
|
||||
def visitar_sentencia(self, ctx, env):
|
||||
if ctx.sentenciaCompuesta():
|
||||
inner = Entorno(env)
|
||||
for s in ctx.sentenciaCompuesta().sentencia():
|
||||
self.visitar_sentencia(s, inner)
|
||||
elif ctx.sentenciaDeclaracion():
|
||||
self.visitar_decl_variable(ctx.sentenciaDeclaracion().declaracionVariable(), env)
|
||||
elif ctx.sentenciaExpresion():
|
||||
se = ctx.sentenciaExpresion()
|
||||
if se.expresion():
|
||||
self.visitar_expresion(se.expresion(), env)
|
||||
elif ctx.sentenciaSeleccion():
|
||||
self.visitar_seleccion(ctx.sentenciaSeleccion(), env)
|
||||
elif ctx.sentenciaIteracion():
|
||||
self.visitar_iteracion(ctx.sentenciaIteracion(), env)
|
||||
elif ctx.sentenciaSalto():
|
||||
self.visitar_salto(ctx.sentenciaSalto(), env)
|
||||
|
||||
# ── Declaración de variables ───────────────────────────────
|
||||
def visitar_decl_variable(self, ctx, env):
|
||||
for init_var in ctx.inicializadorVariable():
|
||||
nombre = init_var.Identificador().getText()
|
||||
if init_var.inicializadorArreglo():
|
||||
items = []
|
||||
la = init_var.inicializadorArreglo().listaInitializers()
|
||||
if la:
|
||||
for ae in la.asignacionExpresion():
|
||||
items.append(self.visitar_asignacion(ae, env))
|
||||
env.definir(nombre, items)
|
||||
elif init_var.inicializador():
|
||||
val = self.visitar_asignacion(
|
||||
init_var.inicializador().asignacionExpresion(), env)
|
||||
env.definir(nombre, val)
|
||||
elif init_var.ConstanteEntera():
|
||||
tamaño = int(init_var.ConstanteEntera().getText())
|
||||
env.definir(nombre, [None] * tamaño)
|
||||
else:
|
||||
env.definir(nombre, None)
|
||||
|
||||
# ── Enum ───────────────────────────────────────────────────
|
||||
def visitar_decl_enum(self, ctx, env):
|
||||
contador = 0
|
||||
for en in ctx.listaEnumeradores().enumerador():
|
||||
nombre = en.Identificador().getText()
|
||||
if en.ConstanteEntera():
|
||||
contador = int(en.ConstanteEntera().getText())
|
||||
env.definir(nombre, contador)
|
||||
self.global_env.definir(nombre, contador)
|
||||
contador += 1
|
||||
|
||||
# ── Selección ──────────────────────────────────────────────
|
||||
def visitar_seleccion(self, ctx, env):
|
||||
if ctx.Si():
|
||||
cond = self.visitar_expresion(ctx.expresion(), env)
|
||||
sentencias = ctx.sentencia()
|
||||
if cond:
|
||||
self.visitar_sentencia(sentencias[0], Entorno(env))
|
||||
elif len(sentencias) > 1:
|
||||
self.visitar_sentencia(sentencias[1], Entorno(env))
|
||||
elif ctx.Caso():
|
||||
# switch-like: caso bul { caso X: ... pordef: ... }
|
||||
val_bul = self.visitar_expresion(ctx.expresion(), env) if ctx.expresion() else None
|
||||
ejecutando = False
|
||||
for etiqueta in ctx.casoEtiqueta():
|
||||
val = self.visitar_constante(etiqueta.constanteExpresion(), env)
|
||||
if val == val_bul or ejecutando:
|
||||
ejecutando = True
|
||||
try:
|
||||
for s in etiqueta.sentencia():
|
||||
self.visitar_sentencia(s, env)
|
||||
except FinSenal:
|
||||
return
|
||||
if ctx.etiquetaPorDef() and ejecutando is False:
|
||||
try:
|
||||
for s in ctx.etiquetaPorDef().sentencia():
|
||||
self.visitar_sentencia(s, env)
|
||||
except FinSenal:
|
||||
pass
|
||||
|
||||
# ── Iteración ──────────────────────────────────────────────
|
||||
def visitar_iteracion(self, ctx, env):
|
||||
if ctx.Mientras():
|
||||
while self.visitar_expresion(ctx.expresion()[0], env):
|
||||
try:
|
||||
self.visitar_sentencia(ctx.sentencia(), Entorno(env))
|
||||
except FinSenal:
|
||||
break
|
||||
except InterrupSenal:
|
||||
continue
|
||||
elif ctx.Por():
|
||||
# Gramática: Por ( sentenciaExpresion? ; expresion? ; expresion? ) sentencia
|
||||
# sentenciaExpresion ya tiene su propio ';', luego viene ';' cond ';' paso
|
||||
loop_env = Entorno(env)
|
||||
# init: sentenciaExpresion opcional (tiene su ';')
|
||||
se = ctx.sentenciaExpresion()
|
||||
if se and se.expresion():
|
||||
self.visitar_expresion(se.expresion(), loop_env)
|
||||
# cond y paso: expresion(0) y expresion(1) — pueden ser None
|
||||
exprs = ctx.expresion()
|
||||
cond_expr = exprs[0] if len(exprs) > 0 else None
|
||||
paso_expr = exprs[1] if len(exprs) > 1 else None
|
||||
while True:
|
||||
if cond_expr is not None and not self.visitar_expresion(cond_expr, loop_env):
|
||||
break
|
||||
try:
|
||||
self.visitar_sentencia(ctx.sentencia(), Entorno(loop_env))
|
||||
except FinSenal:
|
||||
break
|
||||
except InterrupSenal:
|
||||
pass
|
||||
if paso_expr:
|
||||
self.visitar_expresion(paso_expr, loop_env)
|
||||
|
||||
# ── Salto ─────────────────────────────────────────────────
|
||||
def visitar_salto(self, ctx, env):
|
||||
if ctx.Retornar():
|
||||
val = self.visitar_expresion(ctx.expresion(), env) if ctx.expresion() else None
|
||||
raise RetornarSenal(val)
|
||||
elif ctx.Fin():
|
||||
raise FinSenal()
|
||||
elif ctx.Interrup():
|
||||
raise InterrupSenal()
|
||||
|
||||
# ── Expresiones ────────────────────────────────────────────
|
||||
def visitar_expresion(self, ctx, env):
|
||||
# expresion: asignacionExpresion | expresion Coma asignacionExpresion
|
||||
# En el árbol: puede haber asignacionExpresion() como hijo único o múltiples
|
||||
if hasattr(ctx, 'asignacionExpresion') and ctx.asignacionExpresion() is not None:
|
||||
ae = ctx.asignacionExpresion()
|
||||
val = self.visitar_asignacion(ae, env)
|
||||
# Si hay expresion hija (caso con coma), procesarla primero
|
||||
if ctx.expresion():
|
||||
val = self.visitar_expresion(ctx.expresion(), env)
|
||||
val = self.visitar_asignacion(ae, env)
|
||||
return val
|
||||
return None
|
||||
|
||||
def visitar_asignacion(self, ctx, env):
|
||||
if ctx.expresionCondicional():
|
||||
return self.visitar_condicional(ctx.expresionCondicional(), env)
|
||||
# Asignación
|
||||
lhs = ctx.expresionUnaria()
|
||||
op = ctx.operadorAsignacion().getText()
|
||||
rhs = self.visitar_asignacion(ctx.asignacionExpresion(), env)
|
||||
nombre, idx = self._resolver_lvalue(lhs, env)
|
||||
if idx is not None:
|
||||
arr = env.obtener(nombre)
|
||||
viejo = arr[idx]
|
||||
arr[idx] = self._aplicar_op_asign(op, viejo, rhs)
|
||||
else:
|
||||
viejo = None
|
||||
try: viejo = env.obtener(nombre)
|
||||
except: pass
|
||||
env.asignar(nombre, self._aplicar_op_asign(op, viejo, rhs))
|
||||
return rhs
|
||||
|
||||
def _aplicar_op_asign(self, op, viejo, nuevo):
|
||||
if op == '=': return nuevo
|
||||
if op == '+=': return (viejo or 0) + nuevo
|
||||
if op == '-=': return (viejo or 0) - nuevo
|
||||
if op == '*=': return (viejo or 0) * nuevo
|
||||
if op == '/=': return (viejo or 0) / nuevo
|
||||
if op == '%=': return (viejo or 0) % nuevo
|
||||
if op == '&=': return int(viejo or 0) & int(nuevo)
|
||||
if op == '|=': return int(viejo or 0) | int(nuevo)
|
||||
if op == '^=': return int(viejo or 0) ^ int(nuevo)
|
||||
if op == '<<=': return int(viejo or 0) << int(nuevo)
|
||||
if op == '>>=': return int(viejo or 0) >> int(nuevo)
|
||||
return nuevo
|
||||
|
||||
def _resolver_lvalue(self, ctx_unaria, env):
|
||||
"""Devuelve (nombre, índice_o_None)."""
|
||||
pf = ctx_unaria.expresionPostfija()
|
||||
if pf and pf.expresionPostfija() and pf.CorcheteIzq():
|
||||
nombre = pf.expresionPostfija().expresionPrimaria().Identificador().getText()
|
||||
idx = int(self.visitar_expresion(pf.expresion(), env))
|
||||
return nombre, idx
|
||||
elif pf and pf.expresionPrimaria() and pf.expresionPrimaria().Identificador():
|
||||
return pf.expresionPrimaria().Identificador().getText(), None
|
||||
return None, None
|
||||
|
||||
def visitar_condicional(self, ctx, env):
|
||||
val = self.visitar_logica_o(ctx.expresionLogicaO(), env)
|
||||
if ctx.Pregunta():
|
||||
if val:
|
||||
return self.visitar_expresion(ctx.expresion(), env)
|
||||
else:
|
||||
return self.visitar_condicional(ctx.expresionCondicional(), env)
|
||||
return val
|
||||
|
||||
def visitar_logica_o(self, ctx, env):
|
||||
items = ctx.expresionLogicaY()
|
||||
val = self.visitar_logica_y(items[0], env)
|
||||
for i in range(1, len(items)):
|
||||
if val: return True
|
||||
val = self.visitar_logica_y(items[i], env)
|
||||
if len(items) == 1:
|
||||
return val # no convertir a bool si es expresión simple
|
||||
return bool(val)
|
||||
|
||||
def visitar_logica_y(self, ctx, env):
|
||||
items = ctx.expresionIgualacion()
|
||||
val = self.visitar_igualacion(items[0], env)
|
||||
for i in range(1, len(items)):
|
||||
if not val: return False
|
||||
val = self.visitar_igualacion(items[i], env)
|
||||
if len(items) == 1:
|
||||
return val
|
||||
return bool(val)
|
||||
|
||||
def visitar_igualacion(self, ctx, env):
|
||||
val = self.visitar_relacional(ctx.expresionRelacional(0), env)
|
||||
ops = [t.getText() for t in ctx.getChildren()
|
||||
if hasattr(t, 'getText') and t.getText() in ('==', '!=')]
|
||||
for i, op in enumerate(ops):
|
||||
r = self.visitar_relacional(ctx.expresionRelacional(i + 1), env)
|
||||
val = (val == r) if op == '==' else (val != r)
|
||||
return val
|
||||
|
||||
def visitar_relacional(self, ctx, env):
|
||||
val = self.visitar_desplaz(ctx.expresionDesplazamiento(0), env)
|
||||
ops = [t.getText() for t in ctx.getChildren()
|
||||
if hasattr(t, 'getText') and t.getText() in ('<', '>', '<=', '>=')]
|
||||
for i, op in enumerate(ops):
|
||||
r = self.visitar_desplaz(ctx.expresionDesplazamiento(i + 1), env)
|
||||
if op == '<': val = val < r
|
||||
elif op == '>': val = val > r
|
||||
elif op == '<=': val = val <= r
|
||||
elif op == '>=': val = val >= r
|
||||
return val
|
||||
|
||||
def visitar_desplaz(self, ctx, env):
|
||||
val = self.visitar_aditiva(ctx.expresionAditiva(0), env)
|
||||
ops = [t.getText() for t in ctx.getChildren()
|
||||
if hasattr(t, 'getText') and t.getText() in ('<<', '>>')]
|
||||
for i, op in enumerate(ops):
|
||||
r = self.visitar_aditiva(ctx.expresionAditiva(i + 1), env)
|
||||
val = (int(val) << int(r)) if op == '<<' else (int(val) >> int(r))
|
||||
return val
|
||||
|
||||
def visitar_aditiva(self, ctx, env):
|
||||
val = self.visitar_mult(ctx.expresionMultiplicativa(0), env)
|
||||
ops = [t.getText() for t in ctx.getChildren()
|
||||
if hasattr(t, 'getText') and t.getText() in ('+', '-')]
|
||||
for i, op in enumerate(ops):
|
||||
r = self.visitar_mult(ctx.expresionMultiplicativa(i + 1), env)
|
||||
val = val + r if op == '+' else val - r
|
||||
return val
|
||||
|
||||
def visitar_mult(self, ctx, env):
|
||||
val = self.visitar_unaria(ctx.expresionUnaria(0), env)
|
||||
ops = [t.getText() for t in ctx.getChildren()
|
||||
if hasattr(t, 'getText') and t.getText() in ('*', '/', '%')]
|
||||
for i, op in enumerate(ops):
|
||||
r = self.visitar_unaria(ctx.expresionUnaria(i + 1), env)
|
||||
if op == '*': val = val * r
|
||||
elif op == '/':
|
||||
val = val // r if isinstance(val, int) and isinstance(r, int) else val / r
|
||||
elif op == '%': val = val % r
|
||||
return val
|
||||
|
||||
def visitar_unaria(self, ctx, env):
|
||||
if ctx.operadorUnario():
|
||||
op = ctx.operadorUnario().getText()
|
||||
inner = ctx.expresionUnaria()
|
||||
if op == '-': return -self.visitar_unaria(inner, env)
|
||||
if op == '+': return +self.visitar_unaria(inner, env)
|
||||
if op == '!': return not self.visitar_unaria(inner, env)
|
||||
if op == '~': return ~int(self.visitar_unaria(inner, env))
|
||||
if op == '++':
|
||||
nombre, idx = self._resolver_lvalue(inner, env)
|
||||
v = self._get_lvalue(nombre, idx, env) + 1
|
||||
self._set_lvalue(nombre, idx, v, env)
|
||||
return v
|
||||
if op == '--':
|
||||
nombre, idx = self._resolver_lvalue(inner, env)
|
||||
v = self._get_lvalue(nombre, idx, env) - 1
|
||||
self._set_lvalue(nombre, idx, v, env)
|
||||
return v
|
||||
if op == '&': return self.visitar_unaria(inner, env) # simplificado
|
||||
if op == '*': return self.visitar_unaria(inner, env) # simplificado
|
||||
return self.visitar_postfija(ctx.expresionPostfija(), env)
|
||||
|
||||
def _get_lvalue(self, nombre, idx, env):
|
||||
v = env.obtener(nombre)
|
||||
return v[idx] if idx is not None else v
|
||||
|
||||
def _set_lvalue(self, nombre, idx, val, env):
|
||||
if idx is not None:
|
||||
env.obtener(nombre)[idx] = val
|
||||
else:
|
||||
env.asignar(nombre, val)
|
||||
|
||||
def visitar_postfija(self, ctx, env):
|
||||
# Llamada a función
|
||||
if ctx.expresionPostfija() and ctx.ParenIzq():
|
||||
nombre_fn = ctx.expresionPostfija().expresionPrimaria().Identificador().getText()
|
||||
args = []
|
||||
if ctx.listaArgumentos():
|
||||
for ae in ctx.listaArgumentos().asignacionExpresion():
|
||||
args.append(self.visitar_asignacion(ae, env))
|
||||
return self.llamar_funcion(nombre_fn, args, env)
|
||||
# Índice arreglo
|
||||
if ctx.expresionPostfija() and ctx.CorcheteIzq():
|
||||
arr = self.visitar_postfija(ctx.expresionPostfija(), env)
|
||||
idx = int(self.visitar_expresion(ctx.expresion(), env))
|
||||
return arr[idx]
|
||||
# Acceso miembro
|
||||
if ctx.expresionPostfija() and ctx.Punto():
|
||||
obj = self.visitar_postfija(ctx.expresionPostfija(), env)
|
||||
campo = ctx.Identificador().getText()
|
||||
return obj.get(campo)
|
||||
# Postfix ++/--
|
||||
if ctx.expresionPostfija() and ctx.MasMas():
|
||||
nombre, idx = self._resolver_lvalue_pf(ctx.expresionPostfija(), env)
|
||||
v = self._get_lvalue(nombre, idx, env)
|
||||
self._set_lvalue(nombre, idx, v + 1, env)
|
||||
return v
|
||||
if ctx.expresionPostfija() and ctx.MenosMenos():
|
||||
nombre, idx = self._resolver_lvalue_pf(ctx.expresionPostfija(), env)
|
||||
v = self._get_lvalue(nombre, idx, env)
|
||||
self._set_lvalue(nombre, idx, v - 1, env)
|
||||
return v
|
||||
return self.visitar_primaria(ctx.expresionPrimaria(), env)
|
||||
|
||||
def _resolver_lvalue_pf(self, ctx_pf, env):
|
||||
if ctx_pf.expresionPrimaria() and ctx_pf.expresionPrimaria().Identificador():
|
||||
return ctx_pf.expresionPrimaria().Identificador().getText(), None
|
||||
return None, None
|
||||
|
||||
def visitar_primaria(self, ctx, env):
|
||||
if ctx.Identificador():
|
||||
return env.obtener(ctx.Identificador().getText())
|
||||
if ctx.constanteExpresion():
|
||||
return self.visitar_constante(ctx.constanteExpresion(), env)
|
||||
if ctx.CadenaLiteral():
|
||||
raw = ctx.CadenaLiteral().getText()[1:-1] # quitar comillas
|
||||
return raw.replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r')
|
||||
if ctx.expresion():
|
||||
return self.visitar_expresion(ctx.expresion(), env)
|
||||
return None
|
||||
|
||||
def visitar_constante(self, ctx, env):
|
||||
if ctx.ConstanteEntera():
|
||||
txt = ctx.ConstanteEntera().getText()
|
||||
return int(txt, 0)
|
||||
if ctx.ConstanteFlotante():
|
||||
return float(ctx.ConstanteFlotante().getText())
|
||||
if ctx.ConstanteCaracteres():
|
||||
c = ctx.ConstanteCaracteres().getText()[1:-1]
|
||||
return ord(c.encode('raw_unicode_escape').decode('unicode_escape'))
|
||||
if ctx.Verdadero():
|
||||
return True
|
||||
if ctx.Falso():
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Error listener
|
||||
# ─────────────────────────────────────────────
|
||||
class ErrorZap(ErrorListener):
|
||||
def syntaxError(self, recognizer, offendingSymbol, line, col, msg, e):
|
||||
raise SyntaxError(f"[Línea {line}:{col}] {msg}")
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Punto de entrada
|
||||
# ─────────────────────────────────────────────
|
||||
def ejecutar_archivo(ruta):
|
||||
with open(ruta, 'r', encoding='utf-8') as f:
|
||||
codigo = f.read()
|
||||
|
||||
flujo = InputStream(codigo)
|
||||
lexer = zaplangLexer(flujo)
|
||||
lexer.removeErrorListeners()
|
||||
lexer.addErrorListener(ErrorZap())
|
||||
|
||||
tokens = CommonTokenStream(lexer)
|
||||
parser = zaplangParser(tokens)
|
||||
parser.removeErrorListeners()
|
||||
parser.addErrorListener(ErrorZap())
|
||||
|
||||
arbol = parser.unidadTraduccion()
|
||||
interprete = Interprete()
|
||||
interprete.ejecutar(arbol)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Uso: python interprete.py <archivo.zap>")
|
||||
sys.exit(1)
|
||||
try:
|
||||
ejecutar_archivo(sys.argv[1])
|
||||
except SyntaxError as e:
|
||||
print(f"Error de sintaxis: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user