Sp u4

Page 1

Anรกlisis Sintรกctico M.C. Juan Carlos Olivares Rojas


Agenda

• Introducción a las Gramáticas libres de contexto y árboles de derivación. • Diagramas de sintaxis. • Precedencia de operadores. • Analizador sintáctico.

– Analizador descendente (LL). – Analizador ascendente(LR, LALR).


Agenda

• Administración de tablas de símbolos • Manejo de errores sintácticos y su recuperación • Generadores de código sintácticos: Yacc, Bison

para

analizadores


Introducción a las GICs y Árboles de Derivación

• Todo lenguaje posee una serie de reglas para describir los programas fuentes (sintaxis). • Un analizador sintáctico implementa estas reglas haciendo uso de GICs (Gramáticas Independientes del Contexto).


Gramáticas

• Son un formalismo matemático que permite decidir si una cadena pertenece a un lenguaje dado. • Se define como la cuarteta G= (N, Σ, S, P), en donde N es el conjunto de símbolos terminales, Σ es conjunto de símbolos terminales, S es el símbolo inicial (S pertenece a N) y P es un cojuntode reglas de producción.


Gramáticas

• Los símbolos no terminales (N) son aquellos que pueden seguir derivando en otros; mientras que los terminales el proceso finaliza allí. • Las reglas de producción siguen el formato: αβdonde α y βpertenecen a N y Σen cualquier forma.


Reglas de Producción

• Son las reglas que permiten decidir si la cadena pertenece a un lenguaje y la estructura que lleva: • • • •

SA | aB Bε AaA | bC Cε

• S Genera cadenas del lenguaje a*b u a


Tipos de gramáticas

• Las gramáticas más sencillas son las gramáticas regulares, debido a que no presentan anomalías de ningún tipo. Desafortunadamente este tipo de gramáticas no permiten expresar todos los lenguajes posibles y en especial los humanos por lo que se necesitan otros tipos de gramáticas. • Las más utilizadas en informáticas son las libres del contexto.


Gramáticas Regulares

• Son las que se forman a través de Autómatas Finitos Deterministas y Expresiones regulares. No presentan ambiguedades. • Sus reglas de producción son del tipo: αβ donde α pertenece a N y β pertenece a (Σ)* N?


GICs

• Son aquellas G cuya reglas de producción son de la forma: αβ, en donde αpertenece a N y βpertenece (N u Σ)* • Las ventajas de uso de GICs son:

– Proporcionan una estructura sintáctica precisa y fácil de comprender. – Proporciona al lenguaje fuente una estructura adecuada para la generación del código. – Por medio de las GICs es fácil construir analizadores sintácticos.


GICs

• Hay que revisar que la gramática no sea inherentemente ambigua para poder eliminar esa ambigüedad o rediseñar la gramática sin anomalías. • Algunas formas de eliminar esa ambigüedad es utilizando técnicas como algoritmos CYK y las formas normales de Chomsky(FNCh) y Greibach(FNG).


Ejemplo de GICs

• Expresiones válidas en lenguajes C: • expr  (expr) | - expr | expr op expr | VAR | NUM • Error sintáctico: cuando la secuencia de componentes léxicos no puede ser generada por la gramática del lenguaje fuente.


Ejemplos de GICs

• Declaración de variables en C: • • • •

Decl TIPO listavar PYC listavarvar | var COMA listavar varID | ASTER var dimensionCI ENTERO CD | CI ENTERO CD dimension


Gramática de un if

• prop if expr then prop | if expr then prop else prop | ε • exprtermino oprel termino | termino • termino id | num • oprel  < |>|=|<=|<>|>=| • idletra (letra | digito)*


Gramática de un if

• num digito+ digito+)?

(.digito+)?

• Eb delim+ • Delim blanco | tab | linenueva

(E(+|-)?


Jerarquía de Chomsky

• Las otras dos gramáticas en las cuales clasificó Chomsky (GR tipo 3, GIC tipo 2) son las gramáticas sensible al contexto (tipo 1, donde | α| < |β|, donde α y β pertenecen a (Σ u N)* salvo ε) y las gramáticas del tipo 0 o sin restricciones, las cuales sus reglas de producción pueden ser de cualquier tipo.


Árboles de Derivación

• Es la representación gráfica de la derivación de una cadena. • Se crea utilizando el símbolo inicial como la raíz, los símbolos N representan nodos del árbol y los símbolos Σ las hojas del árbol. • A través de los árboles de derivación se puede verificar la sintaxis de un lenguaje así como comprobar el significado de las palabras.


Árboles de Derivación

• Si para la misma cadena existen dos o más árboles de derivación la gramática es ambigua.


BNF

• La Forma Backus-Naur es una metasintaxis; es decir, una sintaxis para representar sintaxis. • Es un estándar para representar lenguajes. • Los paréntesis triangulares < y > sirven para indicar los símbolos no terminales. • La barra vertical | para representar Ó


BNF

• La doble flecha  indica las derivaciones • ::= indica las producciones • [] indican elementos opcionales • {} indican términos repetitivos


BNF

<postal-address> ::= <name-part> <street-address> <zip-part> <name-part> ::= <personal-part> <last-name> <opt-jr-part> <EOL> | <personal-part> <namepart> <personal-part> <initial> "."

::=

<first-name>

|


BNF

• <street-address> <street-name> <EOL>

::=

<house-num> <opt-apt-num>

• <zip-part> ::= <town-name> <state-code> <ZIP-code> <EOL> • <opt-jr-part> ::= "Sr." <roman-numeral> | ""

|

"Jr."

"," |


EBNF

• Extended Backus Naur Form es una metasintaxis ampliamente utilizada que mejora a su antecesor BNF. • Ha cambiado la forma de realizar la especificación de las reglas de producción de la gramática. • La motivación para usar EBNF radica que con BNF los elementos repetitivos necesitan de más reglas de producción para trabajar.


EBNF

• Las reglas de producción pueden contener espacios. • Los símbolos terminales se representan con comillas dobles (“”) cuando representan un símbolo del alfabeto y comillas simples (‘’) para representar cadenas • El operador de producción ahora es el símbolo de igual (=)


EBNF

• Se recomienda escribir los terminales en minúsculas.

símbolos

no

• Cada regla de producción termina con el símbolo de punto y com (;). • El operador | indica una alternativa de regla de producción.


EBNF

digito sin cero = “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9”; digito = “0” | digito sin cero • Las comas (,) sirven para separar tanto terminales como no terminales de las reglas de producción. • Las llaves ({}) indican elementos repetitivos (operador estrella: *)


EBNF

natural = digito sin cero, {digito}; • Los corchetes ([]) se manejan para elementos auxiliares. • entero = “0” | [“-”], natural • Entre símbolos de interrogación (?) se pueden poner símbolos especiales.


EBNF

• Un espacio en blanco se define como: espacio = ? US-ASCII character 32 ?; • Se pueden poner comentarios con los símbolos (* comentario *) • Los paréntesis “(” y “)” se utilizan para agrupar símbolos. El símbolo “-” sirve para expresar excepciones.


EBNF

• Se utiliza “*” para indicar repeticion, por ejemplo • regla = “A”; • repetición = 3 * aa, “B”; • Si se deriva la regla de producción repetición la cadena generada sería: AAAB


EBNF

• Se pueden anidar operadores como *, {} y [] para lograr cualquier tipo de repetición. • Tanto BNF como EBNF pueden determinar cualquier tipo de gramática, sencillamente EBNF permite simplificar y tener menos ambigüedad en la metasintaxis.


Diagramas de Sintaxis

• Es otra forma (al igual que los árboles de derivación) de especificar gramáticas de cualquier tipo en especial de tipo 2. • La característica de este esquema es que permite ver las derivaciones al instante de que ocurren. • Es una forma visual de representar la gramática de un lenguaje.


Diagramas de Sintaxis


Precedencia de Operadores

• La precedencia de operadores es de vital importancia en el proceso de análisis sintáctico ya que nos representará la forma en que debe construirse el árbol de derivación. • En aritmética existen prioridades, por ejemplo: * y / tienen preferencia sobre + y -. () indican la máxima prioridad.


Precedencia de Operadores

• La instrucción a = b + c / 2 en la mayoría de los lenguajes no se evalúa de la forma a = (b + c) /2, sino de la forma a = b + (c/2) • La forma de evaluación depende de cómo se construyan los operadores, ya sea en infijo, postfijo o prefijo. • Las operaciones se realizan de abajo hacia arriba.


Precedencia de Operadores

• Podría pensarse que esta parte corresponde a la parte semántica dado que el resultado de las operaciones depende del orden. Al hablar de orden se hace referencia al aspecto sintáctico y gramatical. • Las reglas gramaticales de mayor prioridad deben de definirse primero. • ¿Cómo se diferencia el operador “-” binario del unario?


Tarea

• UML es el lenguaje de modelado unificado. Tiene la característica principal de ser visual y extensible. • Al ser un lenguaje formal debe de contener una estructura bien definida, en este caso vocabulario (alfabeto) bien definido y reglas gramaticales para definir el orden o sintaxis de los elementos así como una semántica o significado propio.


Tarea

• Realizar un trabajo de investigación que contenga la definición de una gramática visual y sus características. • Además, se debe de investigar de un diagrama UML en particular (versión 2.0 o superior) los elementos de léxico, sintaxis y semántica. • Se deberá preseleccionar (orden en que lleguen los correos) el tipo de diagrama.


Tarea

• La tarea se entregará el martes 3 de noviembre. • La tarea es individual. • Se recomienda consultar libros de UML sólo se deberá tener cuidado de encontrar como la sintaxis y semántica del documento (se puede utilizar una herramienta de diagramación pero quizás no cumpla con el estándar).


Analizador Sintáctico

• Un analizador sintáctico (Parser) es un programa que reconoce si una o varias cadenas de caracteres forman parte de un determinado lenguaje. • Los lenguajes habitualmente reconocidos por los analizadores sintácticos son los lenguajes libres de contexto.


Analizador Sintáctico

• Los analizadores sintácticos fueron extensivamente estudiados durante la década de 1970, detectándose numerosos patrones de funcionamiento en ellos, cosa que permitió la creación de programas generadores de analizadores sintácticos a partir de una especificación de la sintaxis del lenguaje, tales como YACC, GNU bison y javacc.


Análisis Sintáctico Es el proceso de determinar si una cadena dada puede ser generada por una gramática.

• Los analizadores sintácticos de lenguajes de programación suele hacerse de izquierda a derecha, viendo un componente léxico a la vez.


Anรกlisis Sintรกctico


Análisis Sintáctico

• Los analizadores pueden clasificarse dependiendo de la forma en como se construyen los nodos del árbol de derivación sintáctico: ascendentes y descendentes. • El análisis sintáctico impone una estructura jerárquica. • Sea la expresion: id1 := id2 + id3 * 60


Anรกlisis Sintรกctico

โ ข Dicha expresiรณn queda expresada en un รกrbol sintรกctico de la siguiente forma: := id1 + id2 * id3 60


Tipos de Analizadores Sintácticos • LL (left toleft) leen la cadena de izquierda a derecha y derivan por la izquierda • LR (lefttoright) • • • •

SaA AaBbC Bb Cc


Analizador Descendente

• Existen diferentes métodos de análisis sintáctico. La mayoría caen en una de dos categorías: ascendentes y descendentes. Los ascendentes construyen el árbol desde las hojas hacia la raíz. Los descendentes lo hacen en modo inverso. • Un analizador ampliamente utilizado es el llamado de análisis predictivo descendente recursivo que


Analizador Descendente

• Derivación izquierda:

• SAaaBbCaabbCaabbc(1234) • SaAaaBbaaBbcaabbc(3421) • LL(k) traductores “top-down” • Un análisis anticipado de k caracteres (predictivo de caracteres)


Analizador Descendente

• SaS | cA • AbA | cB | ε • BcB |a | ε

• Construir la cadena acbb: • SaS o ScA; al anticipar el primer símbolo.


Analizador Descendente


Administración de la Tabla de Símbolos

• La tabla de símbolos se crea durante la fase de análisis léxico a través de los componentes léxicos, pero en el proceso de análisis sintáctico sufren algunas modificaciones. • Generalmente se agregan valores de tipo y significado para el análisis sintáctico.


Manejo de errores sintácticos y su recuperación • Si los traductores tuvieran que procesar programas correctas el proceso de implantación se simplificaría mucho. • ¿Cómo debe de responder un compilador de pascal a un código Fortran? • Ningún método de recuperación de errores resuelve todos los problemas


Tipos de Errores

• Léxicos: como escribir mal un identificador, palabra clave u operador. • Sintácticos: como una expresión aritmética con paréntesis no equilibrados. • Semánticos: como un operador aplicado a un operando incompatible. • Lógicos: como una llamada infinitamente recursiva.


Tipos de Errores

• La mayoría de los errores se centra en la fase de análisis sintáctico. • El manejador de errores debe: • Informar la presencia de errores con claridad y exactitud. • Brindar una posible solución al problema.


Administrador de Errores

• Recuperar de cada error con la suficiente rapidez como para detectar errores posibles. • No debe retrasar de manera significativa el procesamiento de programas correctos. • Debe indicar la línea del error y algún mensaje informativo


Estrategia de Recuperación de Errores • Modo Pánico • Nivel de Frase • Producciones de error • Corrección global


Recuperación en Modo Pánico

• Es el más sencillo de implantar.

• El analizador sintáctico desecha componentes léxicos hasta encontrar un carácter de sincronización. Estos caracteres son el punto y como (;) entre otros. • En C/Java es muy común este tipo de errores.


Recuperación en Modo Pánico

int a.b,c; struct c { …. }

main() { int a; }


Recuperación a nivel de frase

• Esta técnica utiliza una corrección de caracteres adyacentes, ya sea por inserción, eliminación o intercambio. • Esta técnica permite sustituir “,” por “;”, etc. Son traductores que corrigen errores. • Desafortunadamente para muchos casos no aplican por lo que no se utilizan demasiados.


Producción de Errores

• Se pueden generar gramáticas para generar producciones de error y así de esta forma seguir con el proceso. • La dificultad radica en el sentido de encontrar esas reglas gramaticales para generar error. En algunos casos sería inclusiva más extensa que la gramática del propio lenguaje. • for(i<3, a<10; i++)


Corrección Global

• Idealmente, sería recomendable que un traductor hiciera el mínimo de cambios para procesar una entrada inválida. Este algoritmo genera menores costos globales para realizar cambios. • El problema radica en que el implementar estas estrategias son muy costosas en tiempo y espacio.


Generadores de Analizadores Sintácticos: YACC & Bison • YACC (YET ANOTHER COMPILERCOMPILER): es una herramienta que nos permite validar lenguajes a través de la especificación de reglas gramaticales. • Esta fuertemente relacionado con Lex para la identificación de caracteres extraños.


YACC

• La forma de trabajar con yacc es la siguiente: • Analizador.y (#include“lex.yy.c”)  bison  analizador.c (y.tab.c)  gcc analizador • $gcc analizador.c –o analizador –lfl • Se necesita modificar el valor de retorno en el analizador léxico para trabajar de manera conjunta.


Estructura de un programa en YACC/BISON

%{ Declaraciones globales C }% Declaraciones bison

%% Gramáticas Nombre:prod1|prod2|…|prodn; %% Código auxiliar C


Consejos

• Todo lexema debe ser un entero: • #define VAR 200 (256) • return (VAR); • Gramática vacía: prod1| prod2| ; • Es sumamente sensible a los separadores.


Consejos

• Yacc no es una herramienta que se caracterice por optimizar gramáticas. Por lo tanto, se pueden presentar algunos problemas de ambigüedad: • Reduce/Reduceambigüedad infinita • Shift/Reduce • A continuación se muestran algunos ejemplos de Yacc.


Analizador.lex

%{ #include“ytab.h” }% sp [\n\r\t] if [i][f] %% {if} {return(IF);} “(” {return(PI); } . return(ERROR); %%


ytab.h

• /*Se deben colocar todos los tokens*/ • #define IF 1 • #define


• • • • • • • • •

Analizador.y

%{ #include“lex.yy.c” }% %token IF PI PD LLI LLD %token ID NUM OPREL OPLOG %% programa: linea programa | ; Linea: iflinea | ; if: ifPI condicionPD LLI campo LLD ;


Analizador.y

• .: {printf(“Error sintáctico”);} • • • • • •

%% main(intargc, char*argv[]) { FILE *f = fopen(argv[1], “r”); yyin= f; while(yyparse()); fclose(f); }


Compilación con Yacc

• $flexanalizador.lex • $bisonanalizador.y

• $gccanalizador.c –o analizador –lfl • yytextcomponente léxico • yyinflujo de entrada • yylinenolínea de error


Manejo de errores con Yacc

• %% yyerror() { • printf(“Error sintáctico yylineno); • }

en

%dlinea”,

• En general, el manejo de errores se realiza de forma trivial. De lo contrario tendría que ser más específico.


CUP

• Es el generador de analizadores sintácticos más populares para Java. • Al igual que con lex, los archivos de JLEX deben de modificarse para poder trabajar en conjunto. • Se deben devolver valores de la clase sym, además de incluir la biblioteca de cup. A continuación se muestra un ejemplo de un analizador sintáctico de expresiones.


CUP

import java_cup.runtime.SymbolFactory; %% %cup %class Scanner %{ public Scanner(java.io.InputStream SymbolFactory sf){ this(r); this.sf=sf; }

r,


CUP

private SymbolFactory sf; %} %eofval{ return sf.newSymbol("EOF",sym.EOF); %eofval} %% ";" { return sf.newSymbol("Semicolon",sym.SEMI); } "+" { return sf.newSymbol("Plus",sym.PLUS); } "*" { return


CUP

sf.newSymbol("Times",sym.TIMES); } "(" { return sf.newSymbol("Left Bracket",sym.LPAREN); } ")" { return sf.newSymbol("Right Bracket",sym.RPAREN); } [0-9]+ { return sf.newSymbol("Integral Number",sym.NUMBER, new Integer(yytext())); } [ \t\r\n\f] { /* ignore white space. */ } . { System.err.println("Illegal character: "+yytext()); }


CUP

• En cup se definen las gramáticas en una sintaxis muy similar a BNF. • El archivo define algunas secciones para código auxiliar y definición de terminales y no terminales. • Para compilar se debe de incluir en el path la ruta de la biblioteca de cup. El archivo generado por cup se denomina parser.java y sym.java que se compilan con el lexer.java


CUP

import java_cup.runtime.*; parser code {: public static void main(String args[]) throws Exception { SymbolFactory sf = new DefaultSymbolFactory(); if (args.length==0) new parser(new Scanner(System.in,sf),sf).parse(); else new parser(new Scanner(new java.io.FileInputStream(args[0]),sf),sf).par se();


• } • :}

CUP

• terminal SEMI, PLUS, TIMES, LPAREN, RPAREN; • terminal Integer NUMBER; • non terminal expr_list, expr_part; • non terminal Integer expr; • precedence left PLUS; • precedence left TIMES;


CUP

expr_list ::= expr_list expr_part | expr_part; expr_part ::= expr:e {: System.out.println(" = "+e+";"); :} SEMI; expr ::= NUMBER:n {: RESULT=n; :} | expr:l PLUS expr:r {: RESULT=new Integer(l.intValue() + r.intValue()); :} | expr:l TIMES expr:r {: RESULT=new Integer(l.intValue()


CUP

* r.intValue()); :} | LPAREN expr:e RPAREN {: RESULT=e; :} ;


• Escrito: 70%

Examen

• Próxima unidad se juntará análisis sintáctico y semántico del ensamblador de Java. • Etiquetas para unidad 5: aconst_null, aload, bipush, breakpoint, cmpgd, cmpldconst, iadd, iaload, iand, iastore, iconst, idiv, if_acmpeq, if_acmpne, if_icmpeq, if_icmpge, if_icmpgt, if_icmple,


Examen

• if_icmplt, if_icmpne, ifeq, ifge, ifgt, ifle, iflt, ifne, ifnonnull, ifnull, iinc, iload, iload_<n>, imul, ineg, ishl, ishr, istore, istore_<n>, isub, iushr, ixor, jsr, jsr_w.


Pendientes

โ ข Prรกctica 9: viernes programa para reconocer if en yacc/cup.


Referencias

• Aho, Sethi, Ullman. Compiladores Principios, técnicas y herramientas Ed. Addison Wesley. • Beck,. Software de Sistemas, Introducción a la programación de Sistemas Ed. AddisonWesley Iberoamericana. • Kenneth C. Louden. Construcción de compiladores Principios y práctica. Ed. Thomson.


Referencias

• EBNF, Wikipedia la Enciclopedia Libre, http://www.wikipedia.org/ Recuperado en octubre de 2007.


多Preguntas?


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.