############################################################################## # # metacomp 2.5beta3: a metacompiler for RLL(1) grammars # Copyright (C) 2008 Juan Miguel Vilar and Andrés Marzal # Universitat Jaume I, Castelló (Spain) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Any questions regarding this software should be directed to: # # Juan Miguel Vilar # Departament de Llenguatges i Sistemes Informàtics # Universitat Jaume I # E12071 Castellón (SPAIN) # # email: jvilar@lsi.uji.es # ############################################################################### # # Fichero: analizador.mc # # $Date: 2008-03-14 13:12:37 +0100 (vie, 14 mar 2008) $ # # $Revision: 586 $ # # No hay analizador léxico, se especificará en la entrada % # # Módulos: # import string,re import generador from gramatica import * from tabla import Tabla from errores import errores, avisos # # Variables globales: # T= Tabla() # Tabla de símbolos inicial= None # Símbolo inicial directos= [] # Terminales directos encontrados codusuario=[] # El código del usuario enparentesis=0 # Cierto si estamos dentro de paréntesis _nombre={ "abre" : "un paréntesis abierto", "accion" : "una acción semántica", "asterisco" : "un asterisco", "barra" : "una barra", "cierra" : "un paréntesis cerrado", "codigo" : "un segmento de código", "cruz" : "una cruz", "errordos" : "un tratamiento de error", "especificacion_lexica" : "una especificación léxica", "flecha" : "una flecha", "interrogante" : "un interrogante", "mc_EOF" : "el fin de fichero", "noterminal" : "un símbolo no terminal", "pyc" : "un punto y coma", "terminal" : "un símbolo terminal", "tokenerror" : 'una palabra reservada "error"' } % # # Producción global: # -> @global inicial, codusuario, directos@ @self.G= None@ @self.lexica= None@ @self.codusuario= None@ especificacion_lexica $import analex$ $codigo=analex.ComponenteLexico("codigo")$ $codigo.cod= ""$ codigo @codusuario.append(codigo.cod)@ @tratEOF.l= None@ @Lineas.l= []@ @self.lexica= []@ @for td in directos:@ @ self.lexica.append((td,None,re.escape(td[1:])))@ @self.lexica= self.lexica+especificacion_lexica.esp@ @self.G= Gramatica(T.listanoterminales(), inicial, Lineas.l, tratEOF.l)@ @self.codusuario= codusuario@ ; # # Tratamiento del fin de fichero ausente: # -> @l=[]@ ( errordos @l.append(errordos.id)@ )* @tratEOF.l= l@ ; -> error @errores.append(mc_al.linea(), "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[""]+["errordos"], mc_abandonar)@ @if mc_al.actual.cat=="errordos":@ @ mc_reintentar()@ ; # # Líneas de la gramática: # -> ( noterminal @global inicial@ @nt= T.noterminal(noterminal.id, noterminal.nlinea)@ @if inicial== None:@ @ inicial= nt@ $errores.append(mc_al.linea(), "Después del no terminal, debería venir una flecha")$ flecha @global enparentesis@ @enparentesis= 0@ $errores.append(mc_al.linea(), "Falta un punto y coma.")$ $if mc_al.actual.cat=="flecha":$ $ errores.append(mc_al.linea(), "Creo que he juntado dos reglas.")$ $ mc_al.avanza()$ $else:$ $ mc_al.sincroniza(mc_aceptables[""], mc_abandonar)$ pyc @if ParteDerecha.pd:@ @ Lineas.l.append(Regla(nt, ParteDerecha.pd, noterminal.nlinea))@ @if ParteDerecha.error:@ @ nt.tratamientoError(ParteDerecha.error)@ | codigo @global codusuario@ @codusuario.append(codigo.cod)@ )* ; -> error @errores.append(mc_al.linea(), "Has comenzado una producción de manera extraña, buscaré algún comienzo")@ @mc_al.sincroniza(mc_aceptables[""], mc_abandonar)@ @mc_reintentar@ ; # # Parte derecha: # -> @ParteDerecha.error= None@ @if Alternativa.pd:@ @ l= [Alternativa.pd]@ @else:@ @ l= []@ @ ParteDerecha.error= Alternativa.error@ ( barra @if Alternativa2.pd:@ @ l.append(Alternativa2.pd)@ @else:@ @ if ParteDerecha.error!= None:@ @ avisos.append(mc_al.linea(), "Ya tenía un tratamiento de error; pasaré de este de aquí.")@ @ else:@ @ ParteDerecha.error= Alternativa2.error@ )* @if len(l)== 0:@ @ ParteDerecha.pd= None@ @elif len(l)== 1 and ParteDerecha.error== None:@ @ ParteDerecha.pd= l[0]@ @else:@ @ ParteDerecha.pd= Disyuncion(l, l[0].nl, ParteDerecha.error)@ ; -> error @if mc_al.actual.cat=="codigo":@ @ mensaje= "Parte derecha de la regla incorrecta: ¿te has olvidado del punto y coma? "@ @else:@ @ mensaje= "Parte derecha de la regla incorrecta: esperaba ver "@ @ if len(mc_t)> 1:@ @ coma=""@ @ if not enparentesis:@ @ try:@ @ del(mc_t[mc_t.index("cierra")])@ @ except ValueError:@ @ pass@ @ for i in mc_t[:-1]:@ @ mensaje= mensaje+coma+_nombre[i]@ @ coma=", "@ @ mensaje= mensaje+" o "+_nombre[mc_t[-1]]@ @ else:@ @ mensaje= mensaje+_nombre[mc_t[0]]@ @ mensaje= mensaje + " y he visto "+_nombre[mc_al.actual.cat]@ @errores.append(mc_al.linea(), mensaje)@ @mc_al.sincroniza(mc_siguientes[""], mc_abandonar)@ @ParteDerecha.pd= None@ @ParteDerecha.error= None@ ; # # Alternativas: # -> tokenerror $errores.append(mc_al.linea(),"Después del error debes indicar el tratamiento")$ $mc_al.sincroniza(mc_siguientes[""]+["accion"], mc_abandonar)$ $if mc_al.actual.cat=="accion":$ $ accion= mc_al.actual$ $ mc_al.avanza()$ $else:$ $ accion= None$ accion @Alternativa.pd= None@ @if accion!= None:@ @ Alternativa.error= [accion.id]@ @else:@ @ Alternativa.error= None@ ( accion @Alternativa.error.append(accion2.id)@ )* ; -> @Alternativa.error= None@ @if Elemental.pd!= None:@ @ l= [Elemental.pd]@ @else:@ @ l= []@ ( @if Elemental2.pd!= None:@ @ l.append(Elemental2.pd)@ )* @if len(l)== 0:@ @ Alternativa.pd= None@ @elif len(l)== 1:@ @ Alternativa.pd= Elemental.pd@ @else:@ @ Alternativa.pd= Secuencia(l, l[0].nl)@ ; -> @Alternativa.pd= Vacia(mc_al.linea())@ @Alternativa.error= None@ ; -> error @Alternativa.pd= None@ @Alternativa.error= None@ @if mc_al.actual.cat=="flecha":@ @ errores.append(mc_al.linea(), "He encontrado una flecha en un lugar incorrecto, es posible que te falte un punto y coma previo.")@ @ mc_al.sincroniza(mc_aceptables[""], mc_abandonar)@ @ if mc_al.actual.cat in mc_primeros[""]:@ @ mc_reintentar()@ @else:@ @ mc_error(mc_nt, mc_t)@ ; # # Elementales: # -> noterminal @Elemental.pd= T.noterminal(noterminal.id, noterminal.nlinea)@ ; -> @error= []@ ( errordos @error.append(errordos.id)@ )* terminal @global directos@ @if terminal.directo and terminal.id not in directos:@ @ directos.append(terminal.id)@ @Elemental.pd= Terminal(terminal.id, terminal.directo, error, terminal.nlinea)@ ; -> accion @Elemental.pd= Accion(accion.id, accion.nlinea)@ ; -> abre @global enparentesis@ @par= enparentesis@ @enparentesis= 1@ @Elemental.pd= ParteDerecha.pd@ cierra @enparentesis= par@ ( asterisco @if ParteDerecha.pd:@ @ Elemental.pd= Iteracion(ParteDerecha.pd, abre.nlinea)@ | cruz @if ParteDerecha.pd:@ @ Elemental.pd= Repeticion(ParteDerecha.pd, abre.nlinea)@ | interrogante @if ParteDerecha.pd:@ @ Elemental.pd= Opcional(ParteDerecha.pd, abre.nlinea)@ )? ; % def main(): sys.stderr.write("Este módulo no está preparado para ejecutarse independientemente") sys.exit(1)