Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1. Introducción
Su primera tarea es implementar un lexer (o escáner) para Mini-Lua, que convertirá un flujo de entrada de caracteres en un
flujo de tokens. Si bien estos programas a menudo se escriben mejor con un generador de lexer (por ejemplo, ML-Lex o
Flex), para esta tarea escribirás un escáner desde cero.
Los identificadores en Mini-Lua pueden ser cualquier cadena de letras, dígitos y guion bajo, sin comenzar con un dígito.
Los identificadores distinguen entre mayúsculas y minúsculas (por ejemplo, foo es diferente de Foo). Los siguientes
identificadores están reservados como palabras clave:
Tenga en cuenta que estas son las palabras clave de Lua; repeat y until que estén reservados en Mini-Lua, pero no
son usadas.
Mini-Lua también tiene una colección de delimitadores y operadores, que son los siguientes:
Los números en Mini-Lua son enteros y sus literales están escritos usando notación decimal (sin signo).
Los literales de cadena están delimitados por la coincidencia de comillas dobles y pueden contener las siguientes
secuencias de escape tipo C:
Un carácter en una cadena literal también puede especificarse por su valor numérico usando la secuencia de escape
"\ddd", donde ddd es una secuencia de tres dígitos decimales. Las cadenas en Lua pueden contener cualquier valor de 8
bits, incluidos ceros incrustados, que se pueden especificar como "\000".
Los comentarios comienzan en cualquier lugar fuera de una cadena con un guión doble ( -- ). Si el texto inmediatamente
después de -- es diferente de [[ , el comentario es un comentario corto, que se extiende hasta el final de la línea. De lo
contrario, es un comentario largo, que corre hasta el correspondiente ]] . Los comentarios largos pueden abarcar varias
líneas y pueden contener pares [[ / ]] anidados.
Los espacios en blanco son cualquier secuencia de espacios no vacíos (código ASCII 32), tabuladores horizontales o
verticales (VT, HT), nueva página (FF) o retornos de carro (CR). Cualquier otro carácter no imprimible debe tratarse como un
error.
In [ ]: import re
from .errors import error
In [ ]: NAME_PAT = re.compile('[a-zA-Z_][a-zA-Z0-9_]*')
FLOAT_PAT = re.compile(r'(\d+\.\d*)|(\d*\.\d+)')
INT_PAT = re.compile(r'\d+')
TWO_CHAR = {
'<=' : 'LE',
'>=' : 'GE',
'==' : 'EQ',
'~=' : 'NE',
}
ONE_CHAR = {
'+' : 'PLUS',
'-' : 'MINUS',
'*' : 'TIMES',
'/' : 'DIVIDE',
'^' : 'POWER',
'=' : 'ASSIGN',
'<' : 'LT',
'>' : 'GT',
'(' : 'LPAREN',
')' : 'RPAREN',
'{' : 'LBRACE',
'}' : 'RBRACE',
',' : 'COMMA',
';' : 'SEMI',
}
In [ ]: KEYWORDS = {
'and', 'break', 'do', 'else', 'elseif',
'end', 'false', 'for', 'function', 'if',
'in', 'local', 'nil', 'not', 'or',
'repeat', 'return', 'then', 'true', 'until', 'while'
}
class Token:
def __init__(self, type, value, lineno):
self.type = type
self.value = value
self.lineno = lineno
def __repr__(self):
return f'Token({self.type!r}, {self.value!r}, {self.lineno})'
def tokenize(text):
index = 0 # Posición actual
lineno = 1
# Comentarios Cortos
In [ ]: def main(argv):
if len(argv) != 2:
raise SystemExit(f'Usage: {argv[0]} filename')
with open(argv[1]) as file:
for tok in tokenize(file.read()):
print(tok)
if __name__ == '__main__':
import sys
main(sys.argv)
In [ ]: # errors.py
#
# Soporte de manejo de errores del compilador.
#
# Una de las partes más importantes (y molestas) de escribir un compilador
# es la notificación confiable de los mensajes de error al usuario. Este
# archivo debería consolidar algunas funciones básicas de manejo de errores
# en un solo lugar. Facilite la notificación de errores. Facilite la
# búsqueda de errores.
# Podría expandir esto para que sea más poderoso más adelante
_errors_detected = 0
def errors_detected():
return _errors_detected
def clear_errors():
global _errors_detected
_errors_detected = 0