def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro): c = code.empty() if traza=="t": ( c / ("mc_traza('> Analizando %s\\n')" % self.regla()) / "mc_dentro_traza()" ) if garantizados== self.primeros(): # Sólo tenemos garantías si g= garantizados # coinciden al principio y else: # en cada vuelta g= None ( c / "while True:" // self.pd.genera_codigo_interno(pizda, orden, siguientesPadre, g, traza, esPuro) / ("if %s: break" % _test_no_set(self.primeros())) ) if traza=="t": ( c / "mc_fuera_traza()" / ("""mc_traza('< Fin de %s\\n')""" % self.regla()) ) c / ("if not %s:" % _test_set(self.missiguientes)) if traza: c // "mc_traza('Error, no encontramos ninguno de los siguientes\\n')" c // ("mc_error('%s',%s)" % (self.mi_nt, _set_strlista(self.misaceptables))) return c
def diccionarios(gramatica): # Diccionarios de primeros, siguientes, aceptables y anulables: c = code.empty() c / "mc_primeros = {" for nt in gramatica.noterminales: pr = ", ".join([repr(p) for p in nt.primeros()]) c // ("'%s' : [%s]," % (nt, pr)) c / "}" c / "mc_siguientes = {" for nt in gramatica.noterminales: pr = ", ".join([repr(p) for p in nt.siguientes()]) c // ("'%s' : [%s]," % (nt, pr)) c / "}" c / "mc_aceptables = {" for nt in gramatica.noterminales: pr = ", ".join([repr(p) for p in nt.aceptables()]) c // ("'%s' : [%s]," % (nt, pr)) c / "}" c / "mc_anulables = {" for nt in gramatica.noterminales: c // ("'%s' : %s," % (nt, nt.anulable())) c / "}" return c
def mc_analiza_Compilador(self, Compilador): mc_al = self.mc_al if not mc_al.actual.cat == u'especificacion_lexica': mc_error('<Compilador>', [u'especificacion_lexica']) tratEOF = tratEOF1 = Atributos() Lineas = Lineas1 = Atributos() Compilador.abandonar = True especificacion_lexica = especificacion_lexica1 = especificacion_lexica_ = mc_al.actual mc_al.avanza() if mc_al.actual.cat == u'codigo': codigo = codigo1 = codigo_ = mc_al.actual mc_al.avanza() else: import analex codigo = analex.ComponenteLexico("codigo", mc_al.linea()) codigo.cod = code.empty() Lineas.codusuario = codigo.cod tratEOF.codigo = None self.mc_analiza_tratEOF(tratEOF1) tratEOF_ = tratEOF1 Lineas.l = [] self.mc_analiza_Lineas(Lineas1) Lineas_ = Lineas1 Compilador.abandonar = False lexica = [(td, None, REParser.stringAsRE(td[1:])) for td in directos] lexica += especificacion_lexica.esp Compilador.lexica = lexica if Lineas.inicial is None: Compilador.G = None else: Compilador.G = Gramatica(T.listanoterminales(), Lineas.inicial, Lineas.l, tratEOF.codigo) codusuario = Lineas.codusuario Compilador.codusuario = codusuario
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro ): cuerpo = code.empty() if traza == "t": cuerpo / ("""mc_traza('Reconocido el terminal "%s"\\n')""" % self.nombre) elif traza == "A": ( cuerpo / (u"""mc_traza('("%s"\\n')""" % repr(self.nombre.replace('"','""'))[2:-1]) / u"""mc_traza(' "lexema: %s"\\n' % mc_al.actual.lexema.replace('"','""'))""" / u"""mc_traza(u' "línea: %d"\\n' % mc_al.actual.nlinea)""" / """mc_traza(')\\n')""" ) #'<- para el font-lock if not esPuro and not self.directo: n= self.nombre+_gestion_orden(orden, self.nombre) if orden[self.nombre]== 1 and pizda.nombre!= self.nombre: cuerpo / ("%s = %s = %s_ = mc_al.actual" % (self.nombre, n, self.nombre)) else: cuerpo / ("%s = %s_ = mc_al.actual" % (n, self.nombre)) cuerpo / "mc_al.avanza()" if traza=="t": cuerpo / u"""mc_traza(u'Leído el terminal "%s"\\n' % self.mc_al.actual)""" if garantizados and len(garantizados)==1 and self.nombre in garantizados: c = cuerpo else: c = ( code.sentence("if mc_al.actual.cat == u'%s':" % self.nombre) // cuerpo % "else:" ).code() # Si no, tenemos un _CodeControl y los siguientes van mal if traza: c // ("""mc_traza('Error no es un "%s"\\n')""" % self.nombre) if not self.error: c // ("mc_error('%s', [u'%s'])" % (pizda, self.nombre)) else: c // self.error return c
def mc_analiza_tratEOF(self, tratEOF): mc_al = self.mc_al self.mc_reintento.append(True) mc_reintentar = self.mc_reintentar while self.mc_reintento[-1]: self.mc_reintento[-1] = False try: if not mc_al.actual.cat in [ u'codigo', 'errordos', 'mc_EOF', 'noterminal' ]: mc_error('<tratEOF>', [u'codigo', 'errordos', 'mc_EOF', 'noterminal']) c = None while mc_al.actual.cat == u'errordos': errordos = errordos1 = errordos_ = mc_al.actual mc_al.avanza() if c is None: c = code.empty() c.addBrother(errordos_.codigo) if not mc_al.actual.cat in [u'codigo', 'mc_EOF', 'noterminal']: mc_error('<tratEOF>', [u'codigo', 'errordos', 'mc_EOF', 'noterminal']) tratEOF.codigo = c except mc_error_sintaxis, (mc_nt, mc_t): errores.append( mc_al.linea(), u"Al código inicial no le sigue el comienzo de una regla ni un tratamiento de error. Voy a saltar entrada hasta que encuentre algo." ) mc_al.sincroniza(mc_primeros["<Lineas>"] + ["errordos"], mc_abandonar) if mc_al.actual.cat == "errordos": mc_reintentar()
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizado, traza, esPuro): c= code.empty() if traza=="t": c / u"mc_traza('Reconocida una cadena vacía\\n')" elif traza=="A": c / """mc_traza('("")\\n')""" return c
def genera_excepciones(): # Las excepciones y algunas funciones auxiliares: return (code.empty() / "class mc_error_sintaxis(Exception): pass" / "class mc_error_noEOF(Exception): pass" / "class mc_error_abandonar(Exception): pass" / "def mc_error(nt, esp):" // "raise mc_error_sintaxis, (nt, esp)" % "def mc_abandonar():" // "raise mc_error_abandonar")
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro): """Genera la parte del código de esta pdcha. pizda: parte izquierda de la regla que se está tratando ordenT: diccionarios para controlar la numeración de terminales y no terminales. siguientesPadre: conjunto de terminales que son siguientes del padre de la parte derecha. garantizados: conjunto de terminales que pueden llegar a este punto. Son siempre aceptables. None si no se sabe. traza: formato de la traza ("A" arbol, "t" traza). esPuro: cierto si se está generando un analizador sintáctico puro.""" return code.empty()
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro): c=code.empty() g= garantizados if traza=="t": ( c / ("mc_traza('> Analizando %s\\n')" % self.regla()) / "mc_dentro_traza()") for i in self.l: c / i.genera_codigo_interno(pizda, orden, i.siguientes(), g, traza, esPuro) if not isinstance(i,Vacia): g= None if traza=="t": ( c / "mc_fuera_traza()" / ("mc_traza('< Fin de %s\\n')" % self.regla()) ) return c
def genera_puro(gram, traza): c = code.empty() # El analizador sintáctico: (c / "class AnalizadorSintactico:" // "def __init__(self, entrada, entorno = None):" // "self.mc_al = AnalizadorLexico(entrada)" / "self.mc_al.avanza()" / "try:" // ("self.mc_analiza_%s()" % gram.inicial.nombre) / "if self.mc_al.actual.cat != 'mc_EOF':" // "raise mc_error_noEOF" % None % "except mc_error_sintaxis, (nt,esp):" // "self.mc_error = True" / "self.mc_lineaError = self.mc_al.actual.nlinea" / "self.mc_ntError = nt" / "self.mc_tError = self.mc_al.actual" / "self.mc_esperado = esp" % "except mc_error_noEOF:" // "self.mc_error = True" / "self.mc_lineaError = self.mc_al.actual.nlinea" / "self.mc_ntError = None" / "self.mc_tError = self.mc_al.actual" / "self.mc_esperado = ['mc_EOF']" % "else:" // "self.mc_error = False") # Código de los no terminales: for nt in gram.noterminales: c // nt.genera_codigo(traza, True) return c
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro): c = code.empty() primeros= self.pd.primeros() if traza=="t": c / ("mc_traza('> Analizando %s\\n')" % self.regla()) ( c / ("if %s:" % _test_set(primeros)) // self.pd.genera_codigo_interno(pizda, orden, siguientesPadre, primeros, traza, esPuro) ) if garantizados == None or garantizados < siguientesPadre | primeros: celif = code.sentence("elif %s:" % _test_no_set(siguientesPadre)) if traza: celif / u"mc_traza(u'Error, no podemos asumir que esté vacía.\\n')" celif / ("mc_error('%s', %s)" % (pizda, _set_strlista(primeros|siguientesPadre))) if traza=="t": ( c / "else:" // u"mc_traza(u'Se supone que ha generado la cadena vacía\\n')" ) return c
def genera_sintactico(gram, traza, codificacion): c = code.empty() # La clase para los atributos: c / "class Atributos: pass" # Preparamos el tratamiento del error cuando hay entrada tras EOF if gram.noEOF: # Si se trata el error noEOF tratEOF = code.sentence("mc_al = self.mc_al") / gram.noEOF else: tratEOF = (code.sentence( u"sys.stderr.write((u'Error no tratado en línea %%d:\\n' %% self.mc_al.actual.nlinea).encode('%s'))" % codificacion ) / "sys.stderr.write('He encontrado entrada donde esperaba ver el final del fichero\\n')" / "sys.exit(1)") # El analizador sintáctico: (c / "class AnalizadorSintactico:" // "def __init__(self, entrada, entorno = None):" // "self.mc_entorno = entorno" / "self.mc_al = AnalizadorLexico(entrada)" / "self.mc_al.avanza()" / "self.mc_reintento = [True]" / "mc_reintentar = self.mc_reintentar" / "while self.mc_reintento[-1]:" // "self.mc_reintento[-1] = False" / ("self.%s = Atributos()" "" % gram.inicial.nombre) / "try:" // ("self.mc_analiza_%s(self.%s)" "" % (gram.inicial.nombre, gram.inicial.nombre)) / "if self.mc_al.actual.cat != 'mc_EOF':" // "raise mc_error_noEOF" % None % "except mc_error_sintaxis, (nt, esp):" // u"sys.stderr.write('Error no tratado en línea %d:\\n' % self.mc_al.actual.nlinea)" / (u"sys.stderr.write((u'Estaba analizando la expansión del no terminal %%s y he encontrado\\n el terminal %%s.\\n' %% (nt, self.mc_al.actual)).encode('%s'))" % codificacion) / "if len(esp)==1:" // (u"sys.stderr.write((u'Sólo valía un %%s.\\n' %% mc_pretty_cat(esp[0])).encode('%s'))" % codificacion) % "else:" // (u"sys.stderr.write((u'Tendría que haber sido uno de los siguientes: %%s.\\n' %% ','.join(map(mc_pretty_cat,esp))).encode('%s'))" % codificacion) % "sys.exit(1)" % "except mc_error_noEOF:" // tratEOF % "except mc_error_abandonar:" // "pass" % None % None % "def mc_reintentar(self):" // "self.mc_reintento[-1] = True") # Código de los no terminales: for nt in gram.noterminales: c // nt.genera_codigo(traza) return c
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro): c = code.empty() if traza=="t": ( c / ("mc_traza('> Analizando %s\\n')" % self.regla()) / "mc_dentro_traza()" ) ( c / ("while %s:" % _test_set(self.pd.primeros())) // self.pd.genera_codigo_interno(pizda, orden, siguientesPadre, self.pd.primeros(), traza, esPuro) ) if traza=="t": ( c / "mc_fuera_traza()" / ( "mc_traza('< Fin de %s\\n')" % self.regla()) ) c / ("if not %s:" % _test_set(self.missiguientes)) if traza: c // "mc_traza('Error, no encontramos ninguno de los siguientes\\n')" c // ("mc_error('%s',%s)" % (self.mi_nt, _set_strlista(self.misaceptables))) return c
def toCode(self, name, isMethod=False): if isMethod: header = code.sentence("def %s(self, i, s):" % name) else: header = code.sentence("def %s(i, s):" % name) q = self.getInitial() if q is None: return (header // "return False").code() body = code.sentence("q = %s" % q) if self.isFinal(q): (body / ("uf = %d" % q) / "ufi = i") else: (body / "uf = None" / "ufi = None") loop = (code.sentence("while i <= len(s):") // "if i == len(s):" // "c = ''" % "else:" // "c = s[i]").code() body / loop stateActions = [] for q in self.states: action = code.empty() if self.isFinal(q): action / ("uf = %s" % self.info[q]) / "ufi = i" if q in self.movements: intervals = [] for (cClass, end) in self.movements[q]: intervals += [(interval[0], interval[1], code.sentence("q = %d" % end)) for interval in cClass.toIntervals()] intervals.sort() testChar = code.intervalSearch(intervals, "c", "break", lambda c: unichr(ord(c) - 1)) else: testChar = "break" action / testChar stateActions.append(action) (loop // code.binarySearch(stateActions, "q") / "i += 1") body / "return (uf, ufi)" return header // body
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizados, traza, esPuro ): cuerpo = code.empty() if traza=="t": ( cuerpo / ("mc_traza('> Analizando %s\\n')" % self.regla()) / "mc_dentro_traza()" ) # No podemos hacer caso de las garantías si hay tratamiento de error; # no sabemos dónde se puede haber sincronizado. if garantizados and (esPuro or not self.traterror): g= garantizados.copy() else: g= None el = "" for opcion in self.l: aceptables= opcion.primeros() if opcion.anulable(): aceptables= aceptables|siguientesPadre if g!= None: r= aceptables.intersection(g) else: r= aceptables interno = opcion.genera_codigo_interno(pizda, orden, siguientesPadre, r, traza, esPuro) if r: if g== None or len(r)< len(g): # Caso normal: los aceptables son menos que los garantizados ( cuerpo / (el+"if %s:" % _test_set(r)) // interno ) el="el" elif len(r)== len(g): if el== "": # Esta alternativa se lo lleva todo y no hemos visto ninguna otra cuerpo / interno else: # Estamos en la última alternativa ( cuerpo / "else:" // interno ) if g: g.difference_update(r) if g== None: # Puede que haya un error en la entrada cuerpo / "else:" if traza: cuerpo // "mc_traza('Error, no hay ninguna alternativa aceptable.\\n')" cuerpo // ("mc_error('%s', %s)" % (pizda, _set_strlista(self.misaceptables))) if traza=="t": ( cuerpo / "mc_fuera_traza()" /("mc_traza('< Fin de %s\\n')" % self.regla()) ) if self.traterror and not esPuro: c = ( code.sentence("self.mc_reintento.append(True)") / "mc_reintentar= self.mc_reintentar" / "while self.mc_reintento[-1]:" // "self.mc_reintento[-1]= False" / "try:" // cuerpo % "except mc_error_sintaxis, (mc_nt, mc_t):" // self.traterror ) c / "self.mc_reintento.pop()" else: c= cuerpo return c
def genera_codigo_interno(self, pizda, orden, siguientesPadre, garantizado, traza, esPuro): if esPuro: return code.empty() else: return self.cod
def genera_analizador(gram, elexica, codusuario, traza, salida, codificacion, analex, tipoAnalizador): c = code.empty() # Preámbulo (c / "#!/usr/bin/env python" / ("# -*- coding: %s -*-" % codificacion) / u"# Este código ha sido generado por metacomp, versión 3.0beta5" / "import sys") if traza == "t" or traza == "A": (c / "sangrado_traza = 0" / "def mc_traza(l):" // ("sys.stderr.write((sangrado_traza*' '+l).encode('%s'))" % codificacion) % "def mc_dentro_traza():" // "global sangrado_traza" / "sangrado_traza += 2" % "def mc_fuera_traza():" // "global sangrado_traza" / "sangrado_traza -= 2") c / genera_excepciones() # Analizador léxico: if not analex: c / genera_analex(elexica, codificacion) else: c / ("from %s import AnalizadorLexico" % analex) # El código del usuario: c / u"# Código de usuario" c / codusuario if tipoAnalizador == "normal": # Los primeros y siguientes: c / diccionarios(gram) # El sintáctico: c / genera_sintactico(gram, traza, codificacion) # La llamada a main: (c / "if __name__ == '__main__':" // "try:" // "mc_main = main" % "except NameError:" // "def mc_main():" // "AnalizadorSintactico(sys.stdin)" % None % "mc_main()") elif tipoAnalizador == "puro": # Los primeros y siguientes: c / diccionarios(gram) # El sintáctico: c / genera_puro(gram, traza) # La llamada a main: (c / "if __name__=='__main__':" // "try:" // "mc_main = main" % "except NameError:" // "def mc_main():" // "A = AnalizadorSintactico(sys.stdin)" / "if not A.mc_error:" // u"print 'La entrada no tiene errores sintácticos.'" % "else:" // u"print 'Hay un error de sintaxis en la línea %d, provocado por el componente\\n\\t%s' % ( A.mc_lineaError, A.mc_tError)" / "if A.mc_ntError != None:" // "print 'y detectado al intentar analizar en no terminal %s.' % A.mc_ntError" % "else:" // "print 'y detectado cuando se esperaba el fin de la entrada.'" % None % None % None % "mc_main()") elif tipoAnalizador == "lexico": # Si sólo generamos el léxico: (c / "if __name__=='__main__':" // "try:" // "mc_main = main" % "except NameError:" // "def mc_main():" // "A = AnalizadorLexico(sys.stdin)" / "comp = A.avanza()" / "while comp.cat != 'mc_EOF':" // "print A.actual" / "comp = A.avanza()" % None % None % "mc_main()") else: sys.stderr.write("Error interno.\n") sys.stderr.write( "Se ha especificado un tipo de analizador distinto de normal, puro y léxico.\n" ) sys.exit(1) salida.write(unicode(c).encode(codificacion))
def genera_analex(esplex, codificacion): """Genera un analizador léxico a partir de la especificación léxica. Esta es una lista de tuplas con categoría, función de tratamiento y expresión regular.""" c = code.empty() # # Función auxiliar para escribir las categorías inmediatas # (c / "def mc_pretty_cat(cat):" // "if cat is None or cat[0]!='!':" // "return cat" % "else:" // "return '\"%s\"' % cat[1:]") # # Clase ComponenteLexico # (c / "class ComponenteLexico:" // "def __init__(self, cat, lexema, nlinea):" // "self.cat = cat" / "self.lexema = lexema" / "self.nlinea = nlinea" % "def __str__(self):" // "s = ['%s: %s' % (repr(k), repr(v)) for k, v in self.__dict__.items() if k != 'cat']" / "if s:" // "return '%s (%s)' % (mc_pretty_cat(self.cat), ', '.join(s))" % "else:" // "return mc_pretty_cat(self.cat)") # # Clase AnalizadorLexico: # (c / "class AnalizadorLexico:" // "def __init__(self, entrada):" // "if isinstance(entrada, basestring):" // "if isinstance(entrada, unicode):" // "self.l = entrada" % "else:" // ("self.l = entrada.decode('%s')" % codificacion) % None % "else:" // "try:" // "ll = entrada.readlines()" % "except:" // u"sys.stderr.write('Error: no he podido leer la entrada ¿es un fichero?\\n')" / "sys.exit(1)" % ("ll = [ l.decode('%s') for l in ll]" % codificacion) / "self.l = ''.join(ll)" / "entrada.close()" % "self.nlactual = 1" / "self.actual = ComponenteLexico(None, None, 0)" / "try:" // "self.error_lexico = error_lexico" % "except NameError:" // "self.error_lexico = self._error_lexico" % "self.i = 0") # Tratamiento por defecto del error léxico: (c // "def _error_lexico(self, linea_error, cars):" // (u"sys.stderr.write((u'Error léxico no tratado en línea %%d: No esperaba %%s.\\n' %% (linea_error, repr(cars))).encode('%s'))" % codificacion) / "sys.exit(1)") # Método línea: (c // "def linea(self):" // "return self.actual.nlinea") # Método sincroniza: (c // "def sincroniza(self, sincr, enEOF = mc_abandonar):" // "while self.actual.cat not in sincr and self.actual.cat != 'mc_EOF':" // "self.avanza()" % "if self.actual.cat =='mc_EOF' and not 'mc_EOF' in sincr:" // "enEOF()") # Método avanza: (c // "def avanza(self):" // "if self.i >= len(self.l):" // "self.actual = ComponenteLexico('mc_EOF', '', self.nlactual)" / "return self.actual" % "carsError, lineaError = [], 0" / "while 1:" // "(info, ni) = self.analiza(self.i, self.l)" / "if not info is None:" // "nl = self.nlactual" / "if carsError:" // "self.error_lexico(lineaError, ''.join(carsError))" / "self.nlactual += carsError.count('\\n')" / "carsError, lineaError = [], 0" % "cat, ff = info" / "lexema = self.l[self.i:ni]" / "self.i = ni" / "self.nlactual += lexema.count('\\n')" / "componente = ComponenteLexico(cat, lexema, nl)" / "if ff:" // "ff(componente)" % "if not componente.cat is None:" // "self.actual = componente" / "return componente" % "continue" % "else:" // "if self.i >= len(self.l):" // "if carsError:" // "self.error_lexico(lineaError, ''.join(carsError))" / "self.nlactual += carsError.count('\\n')" % "self.actual = ComponenteLexico('mc_EOF', '', self.nlactual)" / "return self.actual" % "if lineaError == 0: lineaError = self.nlactual" / "carsError.append(self.l[self.i])" / "self.i += 1" % None % "return self.actual") allEr = OrNode([ Concatenation(er, Category(CategoryInfo(n, cat, ff))) for n, (cat, ff, er) in enumerate(esplex) ]) c // re2a.re2a(allEr).toCode("analiza", True) return c
def mc_analiza_Elemental(self, Elemental): mc_al = self.mc_al if not mc_al.actual.cat in [ u'abre', 'accion', 'errordos', 'noterminal', 'terminal' ]: mc_error('<Elemental>', [u'abre', 'accion', 'errordos', 'noterminal', 'terminal']) if mc_al.actual.cat == u'noterminal': noterminal = noterminal1 = noterminal_ = mc_al.actual mc_al.avanza() Elemental.pd = T.noterminal(noterminal.id, noterminal.nlinea) elif mc_al.actual.cat in [u'errordos', 'terminal']: error = None while mc_al.actual.cat == u'errordos': errordos = errordos1 = errordos_ = mc_al.actual mc_al.avanza() if error == None: error = code.empty() error.addBrother(errordos.codigo) if not mc_al.actual.cat == u'terminal': mc_error('<Elemental>', [u'errordos', 'terminal']) if mc_al.actual.cat == u'terminal': terminal = terminal1 = terminal_ = mc_al.actual mc_al.avanza() else: mc_error('<Elemental>', [u'terminal']) global directos if terminal.directo and terminal.id not in directos: directos.update((terminal.id, )) Elemental.pd = Terminal(terminal.id, terminal.directo, error, terminal.nlinea) elif mc_al.actual.cat == u'accion': accion = accion1 = accion_ = mc_al.actual mc_al.avanza() Elemental.pd = Accion(accion.codigo, accion.nlinea) else: ParteDerecha = ParteDerecha1 = Atributos() abre = abre1 = abre_ = mc_al.actual mc_al.avanza() global enparentesis par = enparentesis enparentesis = True self.mc_analiza_ParteDerecha(ParteDerecha1) ParteDerecha_ = ParteDerecha1 Elemental.pd = ParteDerecha.pd if mc_al.actual.cat == u'cierra': cierra = cierra1 = cierra_ = mc_al.actual mc_al.avanza() else: mc_error('<Elemental>', [u'cierra']) enparentesis = par if mc_al.actual.cat in [u'asterisco', 'cruz', 'interrogante']: if mc_al.actual.cat == u'asterisco': asterisco = asterisco1 = asterisco_ = mc_al.actual mc_al.avanza() if ParteDerecha.pd: Elemental.pd = Iteracion(ParteDerecha.pd, abre.nlinea) elif mc_al.actual.cat == u'cruz': cruz = cruz1 = cruz_ = mc_al.actual mc_al.avanza() if ParteDerecha.pd: Elemental.pd = Repeticion(ParteDerecha.pd, abre.nlinea) else: interrogante = interrogante1 = interrogante_ = mc_al.actual mc_al.avanza() if ParteDerecha.pd: Elemental.pd = Opcional(ParteDerecha.pd, abre.nlinea)
def avanza(self): if self.finfichero: self.actual = ComponenteLexico("mc_EOF", self.nlactual) return self.actual if self.esprimera: self.esprimera = 0 return self.lee_especificacion_lexica() while True: c = self.nuevo_caracter() if c == "": # Fin de fichero self.nlactual = self.nlfichero self.actual = ComponenteLexico("mc_EOF", self.nlactual) return self.actual elif c == ' ' or c == '\t' or c == '\r': # Nos cargamos el espacio en blanco pass elif c == '#': # Comentario while c != '\n' and c != "": c = self.nuevo_caracter() self.devuelve(c) elif c == '\n': # Nueva línea self.nlfichero = self.nlfichero + 1 elif c == '<': # Posible no terminal id = u'' self.nlactual = self.nlfichero while True: c = self.nuevo_caracter() if c in letters or c == "_": id = id + c elif c == '>': self.actual = ComponenteLexico("noterminal", self.nlactual) self.actual.id = id if iskeyword(id): errores.errores.append( self.nlactual, "El no terminal %s coincide con una palabra reservada de Python." % id) if id[-1] == "_": errores.errores.append( self.nlactual, "Un no terminal no puede terminar en _") return self.actual else: self.devuelve(c) if id == '': errores.errores.append( self.nlactual, u"El carácter < sólo puede utilizarse para no terminales." ) break errores.errores.append( self.nlactual, u"El no terminal %s no tiene el símbolo > al final" % id) self.actual = ComponenteLexico("noterminal", self.nlactual) self.actual.id = id return self.actual elif c in letters or c == "_": # Terminal lexema = c self.nlactual = self.nlfichero self.actual = ComponenteLexico("terminal", self.nlactual) self.actual.directo = False while True: c = self.nuevo_caracter() if c in letters or c == "_": lexema = lexema + c else: self.devuelve(c) if lexema == "error": self.actual = ComponenteLexico( "tokenerror", self.nlactual) elif iskeyword(lexema): errores.errores.append( self.nlactual, u"Vaya, el identificador %s ya está reservado por Python." % lexema) if lexema[-1] == "_": errores.errores.append( self.nlactual, u"Un identificador de categoría léxica no puede terminar en _" ) self.actual.id = lexema return self.actual elif c == '"': # Terminal directo lexema = "!" self.nlactual = self.nlfichero self.actual = ComponenteLexico("terminal", self.nlactual) self.actual.directo = True while True: c = self.nuevo_caracter() if c == '"': self.actual.id = lexema return self.actual elif c in [" ", "\t", "\n"]: errores.errores.append( self.nlactual, 'He encontrado un terminal directo no terminado, asumire que es "%s"' % lexema[1:]) self.devuelve(c) self.actual.id = lexema return self.actual lexema = lexema + c elif c == "@": # Posible acción self.nlactual = self.nlfichero lexema = "" self.actual = ComponenteLexico("accion", self.nlactual) escape = False while True: c = self.nuevo_caracter() lexema = lexema + c if c == "@": if escape: escape = False else: self.actual.codigo = code.sentence(lexema[:-1]) return self.actual elif c == "\\": escape = True elif c == "" or c == "\n": errores.errores.append( self.nlactual, u"La acción semántica que empieza en esta línea no está terminada." ) self.actual.codigo = code.empty() if c == "\n": self.devuelve(c) return self.actual else: escape = False elif c == "$": # Error dos self.nlactual = self.nlfichero lexema = "" self.actual = ComponenteLexico("errordos", self.nlactual) escape = False while 1: c = self.nuevo_caracter_avanzando() lexema = lexema + c if c == "$": if escape: escape = False else: self.actual.codigo = code.sentence(lexema[:-1]) return self.actual elif c == "\\": escape = True elif c == "" or c == "\n": errores.errores.append( self.nlactual, u"El tratamiento de error de tipo dos de esta línea no está terminado." ) self.actual.codigo = code.empty() if c == "\n": self.devuelve(c) return self.actual else: escape = False elif c == "%": # Código self.nlactual = self.nlfichero lexema = "" self.actual = ComponenteLexico("codigo", self.nlactual) finlinea = False while True: c = self.nuevo_caracter_avanzando() lexema = lexema + c if (c == "%" and finlinea) or c == "": if c == "%": lexema = lexema[:-1] # Quitamos el último % codigo = [code.sentence(s) for s in lexema.split("\n")] codigo = reduce(lambda c, s: c.addBrother(s), codigo) self.actual.cod = codigo return self.actual finlinea = c == "\n" elif c == "-": # Posible flecha c = self.nuevo_caracter() if c == ">": self.nlactual = self.nlfichero self.actual = ComponenteLexico("flecha", self.nlactual) return self.actual else: errores.errores.append( self.nlfichero, u"He encontrado un triste y solitario guión.") self.devuelve(c) elif c == ";": # Punto y coma self.nlactual = self.nlfichero self.actual = ComponenteLexico("pyc", self.nlactual) return self.actual elif c == "*": # Asterisco self.nlactual = self.nlfichero self.actual = ComponenteLexico("asterisco", self.nlactual) return self.actual elif c == "+": # Cruz self.nlactual = self.nlfichero self.actual = ComponenteLexico("cruz", self.nlactual) return self.actual elif c == "?": # Interrogante self.nlactual = self.nlfichero self.actual = ComponenteLexico("interrogante", self.nlactual) return self.actual elif c == "|": # Barra self.nlactual = self.nlfichero self.actual = ComponenteLexico("barra", self.nlactual) return self.actual elif c == "(": # Abre paréntesis self.nlactual = self.nlfichero self.actual = ComponenteLexico("abre", self.nlactual) return self.actual elif c == ")": # Cierra paréntesis self.nlactual = self.nlfichero self.actual = ComponenteLexico("cierra", self.nlactual) return self.actual else: errores.errores.append( self.nlfichero, u"He encontrado el carácter %s y no sé que hacer con él." % c)
def genera_codigo(self, traza, esPuro= False): """ Genera el código de la regla. traza: genera código para escribir la traza (arbol: "A" o traza: "t"). esPuro: si cierto genera un analizador puro (sin acciones semánticas). """ if esPuro: c = code.sentence("def mc_analiza_%s(self):" % self.nombre) else: c = code.sentence("def mc_analiza_%s(self, %s):" % (self.nombre,self.nombre)) # La traza: if traza=="t": ( c // (u"mc_traza('> %s %%s\\n' %% self.mc_al.actual)" % self) / "mc_dentro_traza()" ) elif traza=="A": ( c // (u"mc_traza(u'(\"%s\" \"línea: %%d\"\\n' %% self.mc_al.actual.nlinea)" % self) / "mc_dentro_traza()" ) # Hacemos accesible el analizador léxico: c // "mc_al = self.mc_al" # Cuerpo del analizador cuerpo = code.sentence("if not %s:" % _test_set(self.misaceptables)) if traza: cuerpo // (u'mc_traza(u"Error, no se encuentra ningún elemento aceptable para %s.\\n")' % self) cuerpo // ("mc_error('%s', %s)" % (self, _set_strlista(self.misaceptables))) cadif= "if" for n, regla in enumerate(self.reglasizda): aceptables= regla.dcha.primeros() if regla.dcha.anulable(): aceptables|= self.siguientes() # Cuerpo de la regla cuerpoRegla = code.empty() if traza=="t": # Si hay traza cuerpoRegla / ("mc_traza('Aplico regla: '+" + `regla.regla()` + "+'\\n')") if not esPuro: # Generamos los atributos y los alias: orden= {} for s in regla.simbolos: _gestion_orden(orden, s.nombre) if isinstance(s, NoTerminal): nto= s.nombre+`orden[s.nombre]` if orden[s.nombre]== 1 and s!= self: cuerpoRegla / ("%s = %s = Atributos()" % (s.nombre, nto)) else: cuerpoRegla / ("%s = Atributos()" % nto) # Generamos el código de la regla: cuerpoRegla / regla.dcha.genera_codigo_interno(self, {}, self.siguientes(), aceptables, traza, esPuro) if len(self.reglasizda)> 1: # Si hay más de una posibilidad, hay que poner una guarda if n == len(self.reglasizda)-1: cuerpo / "else:" else: cuerpo / (cadif+ " %s:" % _test_set(aceptables)) cadif="elif" cuerpo // cuerpoRegla else: cuerpo / cuerpoRegla # No sangramos si sólo hay una posibilidad # Más traza, para avisar de que nos vamos if traza=="t": ( cuerpo / "mc_fuera_traza()" / (u"mc_traza('< %s\\n')" % self) ) elif traza=="A": ( cuerpo / "mc_fuera_traza()" / "mc_traza(')\\n')" ) # Comprobamos el tratamiento de errores: if self.traterror and not esPuro: ( c // "self.mc_reintento.append(True)" / "mc_reintentar= self.mc_reintentar" / "while self.mc_reintento[-1]:" // "self.mc_reintento[-1]= False" / "try:" // cuerpo % "except mc_error_sintaxis, (mc_nt, mc_t):" // self.traterror % None % "self.mc_reintento.pop()" ) else: c // cuerpo return c