Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
otros:compilers [2009/11/07 18:13] alfred |
otros:compilers [2020/05/09 09:25] (actual) |
||
|---|---|---|---|
| Línea 1: | Línea 1: | ||
| ====== Compiladores ====== | ====== Compiladores ====== | ||
| Para crear un compilador necesitamos un analizador léxico (o //scanner//) analiza el texto, y un analizador sintáctico (o //parser//) el que analiza la estructura del texto y realiza las acciones necesarias según esta. El analizador léxico recorre el texto y va pasando las porciones útiles (//tokens//) al parser, este actuará según la estructura en la que estén colocados los tokens. | Para crear un compilador necesitamos un analizador léxico (o //scanner//) analiza el texto, y un analizador sintáctico (o //parser//) el que analiza la estructura del texto y realiza las acciones necesarias según esta. El analizador léxico recorre el texto y va pasando las porciones útiles (//tokens//) al parser, este actuará según la estructura en la que estén colocados los tokens. | ||
| - | * Para Java el creador de analizadores léxicos se llama [[#jflex|JFlex]] y el creador de parsers [[#cup|CUP]]. Estas son herramientas a las que se les pasa código y, a partir de este, generan el analizador o el parser. | + | * Para Java el creador de analizadores léxicos se llama [[#jflex|JFlex]] y el creador de parsers [[#cup|CUP]]. Estas son herramientas a las que se les pasa código y, a partir de este, generan el analizador o el parser. |
| + | * Los nombrados anteriormente son versiones de los primeros creadores Lex y Yacc. | ||
| + | * Actualmente existen otros generadores de parsers como son [[http://www.gnu.org/software/bison/|Bison]], [[http://www.antlr.org/|ANTLR]]... | ||
| ===== JFlex ===== | ===== JFlex ===== | ||
| Línea 171: | Línea 173: | ||
| ===== CUP ===== | ===== CUP ===== | ||
| + | |||
| Línea 221: | Línea 224: | ||
| ; | ; | ||
| </code> | </code> | ||
| - | Donde las correspondencias son... | + | Donde los elementos que aparecen son denominados **símbolos** y sus correspondencias son... |
| * PROGRAMA: El programa en sí. | * PROGRAMA: El programa en sí. | ||
| * VARBLOCK: Al bloque de definición de variables. | * VARBLOCK: Al bloque de definición de variables. | ||
| Línea 252: | Línea 255: | ||
| El árbol sería el siguiente: \\ \\ \\ | El árbol sería el siguiente: \\ \\ \\ | ||
| {{otros:compilers:arbol.png?500|}} \\ \\ | {{otros:compilers:arbol.png?500|}} \\ \\ | ||
| - | Siendo los elementos terminales los que están en las ramas del árbol (paréntesis, números, signos...) y los no terminales los que están en el tronco (código, igualdad, operación...). | + | Siendo los **símbolos terminales** los elementos que están en las ramas del árbol (paréntesis, números, signos...) y los símbolos** no terminales** los elementos que están en el tronco (código, igualdad, operación...). |
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| ==== Instalación, uso y combinación con JFlex ==== | ==== Instalación, uso y combinación con JFlex ==== | ||
| + | * [[http://www2.cs.tum.edu/projects/cup/]] | ||
| + | * {{otros:compilers:java_cup_v10k.zip|CUP}} | ||
| + | Descomprimimos el archivo del CUP, nos aparecerá una carpeta denominada java_cup_v10k, esa es la carpeta que deberemos agregar como ''external class folder'' en eclipse (desde la misma ventana desde donde agregamos el jar del JFlex) y desde esa carpeta será desde donde ejecutemos el comando: ''java java_cup.Main nuestro_fichero.cup''. Donde nuestro fichero es el código CUP que programemos. Este comando generará dos ficheros\clases que tendremos que agregar a nuestro proyecto: | ||
| + | * ''parser.java'' donde estará el código del parser. | ||
| + | * ''sym.java'' donde se definirán todos los símbolos. | ||
| + | Para que JFlex sea compatible con CUP debemos agregar a las instrucciones de generación el parámetro ''%cup''. \\ | ||
| + | Cuando combinamos los códigos generados por JFlex y CUP el que lanza el analizador léxico ahora es la misma clase parser. El siguiente código sería un ejemplo de inicio de parseo: | ||
| + | <code java> | ||
| + | parser p = null; | ||
| + | Yylex lex = null; | ||
| + | try { | ||
| + | if (args.length == 0) { | ||
| + | System.out.println("Llegint des de l' stream d'entrada: "); | ||
| + | lex = new Yylex(System.in); | ||
| + | } else { | ||
| + | System.out.println("Llegint des del fitxer: " + new java.io.File(args[0]).getAbsolutePath()); | ||
| + | lex = new Yylex(new java.io.FileReader(args[0])); | ||
| + | } | ||
| + | p = new parser(lex); | ||
| + | p.parse(); | ||
| + | catch ... | ||
| + | </code> | ||
| + | Dentro del código JFlex tendremos que retornar objetos ''Symbol'', el constructor de estos, entre otras cosas, recibe un tipo de simbolos (de la lista de símbolos en el archivo ''sym.java'' generado), dos objetos (el left y el right) que luego podremos recoger y el valor. En el siguiente ejemplo cuando se encuentra una definción ".code" se envia que es un símbolo del tipo ''STARTCODE'', el número de línea (como objeto left), nada (como objeto right), y el texto (por si se necesita): | ||
| + | <code> | ||
| + | ".code" { return new Symbol(sym.STARTCODE, yyline + 1, 0, yytext()); } | ||
| + | </code> | ||
| + | {{otros:compilers:flex_and_cup.tar.gz|Aquí}} un par de ejemplos. | ||
| + | |||
| + | |||
| + | |||
| ==== Código ==== | ==== Código ==== | ||
| + | El código CUP se estructura de la siguiente forma: | ||
| + | - Código Java de fuera de la clase (tipo imports...). | ||
| + | - Código interno de la clase parser y que podrá ser accedido desde el código generado entre: ''parser code {: :}'' | ||
| + | - El action code, entre: ''action code {: :}'' | ||
| + | - El código que define la gramática. | ||
| + | El código que define la gramática comienza con la definición de los nombres de símbolos terminales y no terminales: | ||
| + | <code> | ||
| + | terminal WORD, COMA, NUMBER, DOSPUNTOS, CORCHIZQ, CORCHDER; | ||
| + | terminal STARTPROGRAM, ENDPROGRAM, STARTCODE, ENDCODE, STARTDECVAR, ENDDECVAR, STARTMACRO, ENDMACRO, STARTDECMACRO, ENDDECMACRO; | ||
| + | terminal COMANDO, REGISTRO, TIPO; | ||
| + | nonterminal programa, name, bloccodi, codi, liniacodi, blocvariables, blocmacros, decvars, valor, macro, decmacros, etiqueta; | ||
| + | nonterminal memaddr, operando1, operando2; | ||
| + | </code> | ||
| + | Luego la creación de la gramática se haría con la estructura explicada anteriormente, pero con la siguiente sintaxis: | ||
| + | <code> | ||
| + | PROGRAMA ::= VARBLOCK FUNCBLOCK CODEBLOCK | ||
| + | | VARBLOCK CODEBLOCK | ||
| + | ; | ||
| + | </code> | ||
| + | Además podemos incluir código y leer los tokens pasados por el analizador léxico, por ejemplo podemos leer el contenido de cada token (agregando '':nombre_variable'' tras su definición) o acceder a los objetos left y right con ''nleft'' y ''nright''. | ||
| + | <code> | ||
| + | DEF_FUNC ::= NOMFUNC ID:w PAR_IZQ PAR_DER CORCH_IZQ CODE_BODY CORCH_DER | ||
| + | {: | ||
| + | System.out.println("Se ha definido una función llamada: " + w.toString() + " en linea:" + nleft); | ||
| + | :} | ||
| + | | ... | ||
| + | </code> | ||
| + | |||
| + | En el ejemplo de la documentación encontramos la definición de la gramática siguiente: | ||
| + | <code> | ||
| + | expr_list ::= expr_list expr_part | ||
| + | | expr_part | ||
| + | ; | ||
| + | |||
| + | expr_part ::= expr:e | ||
| + | {: System.out.println("= " + e); :} | ||
| + | ; | ||
| + | |||
| + | expr ::= expr:e1 PLUS expr:e2 | ||
| + | {: RESULT = new Integer(e1.intValue() + e2.intValue()); :} | ||
| + | | expr:e1 MINUS expr:e2 | ||
| + | {: RESULT = new Integer(e1.intValue() - e2.intValue()); :} | ||
| + | | expr:e1 TIMES expr:e2 | ||
| + | {: RESULT = new Integer(e1.intValue() * e2.intValue()); :} | ||
| + | | expr:e1 DIVIDE expr:e2 | ||
| + | {: RESULT = new Integer(e1.intValue() / e2.intValue()); :} | ||
| + | | expr:e1 MOD expr:e2 | ||
| + | {: RESULT = new Integer(e1.intValue() % e2.intValue()); :} | ||
| + | | NUMBER:n | ||
| + | {: RESULT = n; :} | ||
| + | | MINUS expr:e | ||
| + | {: RESULT = new Integer(0 - e.intValue()); :} | ||
| + | | LPAREN expr:e RPAREN | ||
| + | {: RESULT = e; :} | ||
| + | ; | ||
| + | </code> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Notas ===== | ||
| + | * La herramienta de Python para generar analizadores léxicos y sintácticos es la denominada PLY (que se encuentra [[http://www.dabeaz.com/ply/index.html|aquí]]), su nombre viene de //Python Lex Yacc//. | ||
| - | ===== Compiladores con Python ===== | ||
| - | ===== Compiladores con .NET ===== | ||