SlideShare una empresa de Scribd logo
1 de 20
Descargar para leer sin conexión
 Reseña Histórica
Los primeros lenguajes de programación surgieron de la idea de Charles Babagge, la cual se le
ocurrió a este hombre a mediados del siglo XIX. Era un profesor matemático de la universidad de
Cambridge e inventor inglés, que al principio del siglo XIX predijo muchas de las teorías en que se
basan los actuales ordenadores. Consistía en lo que él denominaba la maquina analítica, pero que
por motivos técnicos no pudo construirse hasta mediados del siglo XX. Con él colaboro Ada Lovedby,
la cual es considerada como la primera programadora de la historia, pues realizo programas para
aquélla supuesta máquina de Babagge, en tarjetas perforadas. Como la maquina no llego nunca a
construirse, los programas de Ada, lógicamente, tampoco llegaron a ejecutarse, pero si suponen un
punto de partida de la programación, sobre todo si observamos que en cuanto se empezó a
programar, los programadores utilizaron las técnicas diseñadas por Charles Babagge, y Ada, que
consistían entre otras, en la programación mediante tarjetas perforadas. A pesar de ello, Ada ha
permanecido como la primera programadora de la historia. Se dice por tanto que estos dos genios
de antaño, se adelantaron un siglo a su época, lo cual describe la inteligencia de la que se hallaban
dotados.
En 1823 el gobierno Británico lo apoyo para crear el proyecto de una máquina de diferencias, un
dispositivo mecánico para efectuar sumas repetidas. Pero Babagge se dedicó al proyecto de la
máquina analítica, abandonando la máquina de diferencias, que se pudiera programar con tarjetas
perforadas, gracias a la creación de Charles Jacquard (francés). Este hombre era un fabricante de
tejidos y había creado un telar que podía reproducir automáticamente patrones de tejidos, leyendo
la información codificada en patrones de agujeros perforados en tarjetas de papel rígido. Entonces
Babagge intento crear la máquina que se pudiera programar con tarjetas perforadas para efectuar
cualquier cálculo con una precisión de 20 dígitos. Pero la tecnología de la época no bastaba
parahacer realidad sus ideas. Si bien las ideas de Babagge no llegaron a materializarse de forma
definitiva, su contribución es decisiva, ya que los ordenadores actuales responden a un esquema
análogo al de la máquina analítica. En su diseño, la máquina constaba de cinco unidades básicas: 1)
Unidad de entrada, para introducir datos e instrucciones; 2) Memoria, donde se almacenaban datos
y resultados intermedios; 3) Unidad de control, para regular la secuencia de ejecución de las
operaciones; 4) Unidad Aritmético-Lógica, que efectúa las operaciones; 5) Unidad de salida,
encargada de comunicar al exterior los resultados. Charles Babbage, conocido como el "padre de la
informática" no pudo completar en aquella época la construcción del computador que había
soñado, dado que faltaba algo fundamental: la electrónica. El camino señalado de Babbage, no fue
nunca abandonado y siguiéndolo, se construyeron los primeros computadores.
Cuando surgió el primer ordenador, el famoso ENIAC (Electronic Numerical Integrator And
Calculator), su programación se basaba en componentes físicos, o sea, que se programaba,
cambiando directamente el Hardware de la máquina, exactamente lo que sé hacia era cambiar
cables de sitio para conseguir así la programación de la máquina. La entrada y salida de datos se
realizaba mediante tarjetas perforadas.
 Diseño y construcción de un compilador.
En el proceso de construcción de compiladores se integran muchos conceptos diferentes de las
Ciencias de la Computación:
 Algoritmos de búsqueda.
 Árboles, Hashing.
 Programación modular.
 Lenguaje Assembly.
Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases
correspondientes al Análisis léxico (que consiste en la descomposición del programa fuente en
componentes léxicos), Análisis sintáctico (agrupación de los componentes léxicos en frases
gramaticales) y Análisis semántico (comprobación de la validez semántica de las sentencias
aceptadas en la fase de Análisis Sintáctico).
Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar
formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata
de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener
un código lo más eficiente posible).
 Las herramientas Flex y Bison.
Son herramientas para el desarrollo de lenguaje, flex sirve para construir analizadores léxicos, esta
herramienta genera código en c que puede ser compilado. Bison es la herramienta encargada de la
generación de analizadores sintácticos, es una herramienta compatible con YACC, también genera
código en C o C++ y puede ser fácilmente integrado con Flex.
 Que es flex
El Flex define las reglas de reconocimiento de símbolos (Tokens) a partir de expresiones regulares.
Cuando un Token es reconocido por uno de estos patrones de agrupamiento se le define una acción,
por lo general esta acción es devolver el Tipo y el valor (lexema). El Flex cuando se utiliza combinado
con el Bison, utiliza las definiciones de los Tokens realizadas en el Bison para la comunicación entre
ellos
 Como se instala Flex y Bison
1. Descarga el software disponible en el sitio de la cátedra.
2. Instalar el software en la unidad C: (para explicar a partir del punto 4 se tendrá como
hipótesis de que flex y bison han sido instalados en la ruta: C:GnuWin32 donde
contiene una subcarpeta llamada bin donde se encuentran los programas respectivos)
3. Flex y bison son aplicaciones de consola, por lo que se deberá entrar al Símbolo del
sistema y tipear líneas de comando para ejecutar Flex. Una alternativa es crear un
archivo de proceso por lotes (*.bat) que contenga las líneas de comando para la
ejecución de Flex y Bison y/o la compilación del archivo generado.
4. Si deseas que flex y bison se integren al conjunto de variables del entorno (esto te va a
permitir llamar a flex/bison desde cualquier ubicación en la línea de comandos) debes
hacer lo siguiente:
o Clic derecho en “Mi PC”.
o Selecciona “Propiedades”
o Clic en la pestaña “Opciones Avanzadas”
o Presiona el botón “Variables de entorno”
o En la ventana de variables de entorno, ubicarse en la sección “Variables del sistema”
luego haz clic en PATH y luego en el botón “Modificar” (si no está hacer clic en
“Nueva” y agregar PATH)
o En la nueva ventana, escribir la ruta completa al directorio “bin” de la aplicación
flex/bison. Si existe otro valor, separarlos con comas.
o Aceptar los cambios y luego reiniciar el sistema operativo.
5. Si deseas instalar un compilador de C como MinGwin, deberás integrar la ruta de acceso al
compilador a las variables de entorno para facilitar la llamada al programa. Por ejemplo si
se instaló MingWin en “C:Mingw” y dentro de la carpeta “bin” se encuentra “gcc.exe” que
es el ejecutable, entonces de deberá agregar (análogo a los pasos anteriores) lo siguiente:
6. Cuando tengas listo podrás llamar a flex/bison desde el símbolo del sistema sin necesidad
de ubicarte en la carpeta donde ha sido instalado flex/bison.
 Patrones en flex
Los patrones en la entrada se escriben utilizando un conjunto extendido de expresiones regulares.
Estas son:
`x'
empareja el caracter `x'
`.'
cualquier caracter (byte) excepto una línea nueva
`[xyz]'
una "clase de caracteres"; en este caso, el patrón empareja una `x', una `y', o una `z'
`[abj-oZ]'
una "clase de caracteres" con un rango; empareja una `a', una `b', cualquier letra desde la `j' hasta
la `o', o una `Z'
`[^A-Z]'
una "clase de caracteres negada", es decir, cualquier caracter menos los que aparecen en la clase.
En este caso, cualquier caracter EXCEPTO una letra mayúscula.
`[^A-Zn]'
cualquier caracter EXCEPTO una letra mayúscula o una línea nueva
`r*'
cero o más r's, donde r es cualquier expresión regular
`r+'
una o más r's
`r?'
cero o una r (es decir, "una r opcional")
`r{2,5}'
donde sea de dos a cinco r's
`r{2,}'
dos o más r's
`r{4}'
exactamente 4 r's
`{nombre}'
la expansión de la definición de "nombre" (ver más abajo)
`"[xyz]"foo"'
la cadena literal: [xyz]"foo
`x'
si x es una `a', `b', `f', `n', `r', `t', o `v', entonces la interpretación ANSI-C de x. En otro caso, un literal
`x' (usado para indicar operadores tales como `*')
`0'
un caracter NUL (código ASCII 0)
`123'
el caracter con valor octal 123
`x2a'
el caracter con valor hexadecimal 2a
`(r)'
empareja una R; los paréntesis se utilizan para anular la precedencia (ver más abajo)
`rs'
la expresión regular r seguida por la expresión regular s; se denomina "concatenación"
`r|s'
bien una r o una s
`r/s'
una r pero sólo si va seguida por una s. El texto emparejado por s se incluye cuando se determina si
esta regla es el "emparejamiento más largo", pero se devuelve entonces a la entrada antes que se
ejecute la acción. Así que la acción sólo ve el texto emparejado por r. Este tipo de patrones se llama
"de contexto posterior". (Hay algunas combinaciones de r/s que flex no puede emparejar
correctamente. See section Deficiencias / Errores, las notas a cerca del "contexto posterior
peligroso".)
`^r'
una r, pero sólo al comienzo de una línea (es decir, justo al comienzo del análisis, o a la derecha
después de que se haya analizado una línea nueva).
`r$'
una r, pero sólo al final de una línea (es decir, justo antes de una línea nueva). Equivalente a "r/n".
Fíjese que la noción de flex de una "línea nueva" es exáctamente lo que el compilador de C utilizado
para compilar flex interprete como `n'; en particular, en algunos sistemas DOS debe filtrar los r's
de la entrada used mismo, o explícitamente usar r/rn para "r$".
`<s>r'
una r, pero sólo en la condición de arranque s (See section Condiciones de arranque, para una
discusión sobre las condiciones de arranque)
`<s1,s2,s3>r'
lo mismo, pero en cualquiera de las condiciones de arranque s1, s2, o s3
`<*>r'
una r en cualquier condición de arranque, incluso una exclusiva.
`<<EOF>>'
un fin-de-fichero
`<s1,s2><<EOF>>'
un fin-de-fichero en una condición de arranque s1 ó s2
 Emparejamiento de la entrada
El escáner asocia las cadenas ingresadas que concuerden con los patrones de caracteres guardados.
Si encuentra más de un emparejamiento, toma el que empareje más texto (para reglas de contexto
posterior, se incluye la longitud de la parte posterior, incluso si se devuelve a la entrada). Si
encuentra dos o más emparejamientos de la misma longitud, se escoge la regla listada en primer
lugar en el fichero de entrada de flex.
Una vez que se determina el emparejamiento, el texto correspondiente al emparejamiento
(denominado el token) está disponible en el puntero a caracter global yytext, y su longitud en la
variable global entera yyleng. Entonces la acción correspondiente al patrón emparejado se ejecuta,
y entonces la entrada restante se analiza para otro emparejamiento.
Si no se encuentra un emparejamiento, entonces se ejecuta la regla por defecto: el siguiente
caracter en la entrada se considera reconocido y se copia a la salida estándar. Así, la entrada válida
más simple de flex es:
%%
que genera un escáner que simplemente copia su entrada (un caracter a la vez) a la salida.
 Condiciones de arranque
Las condiciones de arranque se declaran en la (primera) sección de definiciones de la entrada
usando líneas sin sangrar comenzando con `%s' ó `%x' seguida por una lista de nombres. Lo primero
declara condiciones de arranque inclusivas, lo último condiciones de arranque exclusivas. Una
condición de arranque se activa utilizando la acción BEGIN. Hasta que se ejecute la próxima
acción BEGIN, las reglas con la condición de arranque dada estarán activas y las reglas con otras
condiciones de arranque estarán inactivas. Si la condición de arranque es inclusiva, entonces las
reglas sin condiciones de arranque también estarán activas. Si es exclusiva, entonces sólamente las
reglas calificadas con la condición de arranque estarán activas.
 Variables disponibles para el usuario
Esta sección resume los diferentes valores disponibles al usuario en las acciones de la regla.
 `char *yytext' apunta al texto del token actual. Este puede modificarse pero no alargarse
(no puede añadir caracteres al final). Si aparece la directiva especial `%array' en la primera
sección de la descripción del analizador, entonces yytext se declara en su lugar como `char
yytext[YYLMAX]', donde YYLMAX es la definicion de una macro que puede redefinir en la
primera sección si no le gusta el valor por defecto (generalmente 8KB). El uso
de `%array'produce analizadores algo más lentos, pero el valor de yytext se vuelve inmune
a las llamadas a `input()' y `unput()', que potencialmente destruyen su valor
cuando yytext es un puntero a caracter. El opuesto de `%array' es `%pointer', que se
encuentra por defecto. Usted no puede utilizar `%array' cuando genera analizadores como
clases de C++ (la bandera `-+').
 `int yyleng' contiene la longitud del token actual.
 `FILE *yyin' es el fichero por el que flex lee por defecto. Este podría redefinirse pero hacerlo
solo tiene sentido antes de que el análisis comience o después de que se haya encontrado
un EOF. Cambiándolo en medio del análisis tendrá resultados inesperados ya que flex utiliza
buffers en su entrada; use `yyrestart()' en su lugar. Una vez que el análisis termina debido a
que se ha visto un fin-de-fichero, puede asignarle a yyin el nuevo fichero de entrada y
entonces llamar al analizador de nuevo para continuar analizando.
 `void yyrestart( FILE *new_file )' podría ser llamada para que yyin apunte al nuevo fichero
de entrada. El cambio al nuevo fichero es inmediato (cualquier entrada contenida en el
buffer previamente se pierde). Fíjese que llamando a `yyrestart()' con yyin como argumento
de esta manera elimina el buffer de entradda actual y continúa analizando el mismo fichero
de entrada.
 `FILE *yyout' es el fichero sobre el que se hacen las acciones `ECHO'. Este puede ser
reasignado por el usuario.
 YY_CURRENT_BUFFER devuelve un handle YY_BUFFER_STATE al buffer actual.
 YY_START devuelve un valor entero correspondiente a la condición de arranque actual.
Posteriormente puede usar este valor con BEGIN para retornar a la condición de arranque.
 Compilación y ejecución en flex de un programa.
Al ejecutar el comando flex nombre_fichero_fuente se creará un fichero en C llamado
“lex.yy.c”. Si se compila este fichero con la instrucción “gcc lex.yy.c –lfl –o
nombre_ejecutable” (-lfl indica enlazar con la biblioteca de flex) se obtendrá como resultado un
fichero ejecutable llamado nombre_ejecutable).
Una vez se ha creado el fichero ejecutable se puede ejecutar directamente. Flex esperará que se
introduzca
texto por la entrada estándar (teclado) y lo analizará cada vez que se pulse el retorno de carro. Para
terminar con el análisis normalmente hay que pulsar <CTRL>-D. Para poder probarlo con entradas
más
largas, lo más sencillo es crear archivos de texto y usar redirecciones para que el ejecutable lea estos
ficheros como entrada a analizar. Por ejemplo si hemos creado un analizador llamado prueba1 y un
fichero de texto con datos para su análisis, llamado entrada.txt, podemos ejecutar $prueba1 <
entrada.txt.
Si se quiere ejecutar algún código al final de un análisis de Flex (para mostrar resultados por ejemplo)
hay
al menos dos opciones:
%%
reglas...
8
Introducción a Flex y Bison
%%
main() {
yylex();
código a ejecutar al final del análisis
}
o bien
%%
reglas...
%%
yywrap() {
código a ejecutar al final del análisis
return 1;
}
 Introducción a Bison
Bison es un generador de analizadores sintácticos de tipo LALR(1) se distribuye bajo licencia GNU y
genera automáticamente código fuente C en base de una gramática libre de contexto.
 Símbolos terminales y no terminales
Los símbolos terminales de la gramática se denominan en Bison tokens y deben declararse en la
sección de definiciones. Por convención se suelen escribir los tokens en mayúsculas y los símbolos
no terminales en minúsculas. 10 Introducción a Flex y Bison Los nombres de los símbolos pueden
contener letras, dígitos (no al principio), subrayados y puntos. Los puntos tienen sentido únicamente
en no-terminales. Hay tres maneras de escribir símbolos terminales en la gramática. Aquí se
describen las dos más usuales:
• Un token declarado se escribe con un identificador, de la misma manera que un
identificador en C. Por convención, debería estar todo en mayúsculas. Cada uno de estos
nombres debe definirse con una declaración de %token.
• Un token de carácter se escribe en la gramática utilizando la misma sintaxis usada en C
para las constantes de un carácter; por ejemplo, ‘+’ es un tipo de token de carácter. Un tipo
de token de carácter no necesita ser declarado a menos que necesite especificar el tipo de
datos de su valor semántico, asociatividad, o precedencia. Por convención, un token de
carácter se utiliza únicamente para representar un token consistente en ese carácter en
particular.
 Sintaxis de las reglas gramaticales (producciones)
Una regla gramatical de Bison tiene la siguiente forma general: resultado: componentes... ; donde
resultado es el símbolo no terminal que describe esta regla y componentes son los diversos símbolos
terminales y no terminales que están reunidos por esta regla. Por ejemplo, exp: exp ‘+’ exp ; dice
que dos agrupaciones de tipo exp, con un token ‘+’ en medio, puede combinarse en una agrupación
mayor de tipo exp. Los espacios en blanco en las reglas son significativos únicamente para separar
símbolos. Puede añadir tantos espacios en blanco extra como desee. Distribuidas en medio de los
componentes pueden haber acciones que determinan la semántica de la regla. Una acción tiene el
siguiente aspecto: {sentencias en C} Normalmente hay una única acción que sigue a los
componentes. Se pueden escribir por separado varias reglas para el mismo resultado o pueden
unirse con el caracter de barra vertical ‘|’ así: resultado: componentes-regla1... | componentes-
regla2... ... ; Estas aún se consideran reglas distintas incluso cuando se unen de esa manera. Si los
componentes en una regla están vacíos, significa que resultado puede concordar con la cadena vacía
(en notación formal sería ε). Por ejemplo, aquí aparece cómo definir una secuencia separada por
comas de cero o más agrupaciones exp: expseq: /* vacío */ | expseq1 ;
 Declaraciones en Bison
La sección de declaraciones de Bison de una gramática de Bison define los símbolos utilizados en la
formulación de la gramática y los tipos de datos de los valores semánticos. Todos los nombres de
tokens (pero no los tokens de carácter literal simple tal como ‘+’ y ‘*’) se deben declarar. Los
símbolos no terminales deben ser declarados si necesita especificar el tipo de dato a utilizar para
los valores semánticos.
 Precedencia de operadores
Use las declaraciones %left, %right o %nonassoc para declarar un token y especificar su precedencia
y asociatividad, todo a la vez. Estas se llaman declaraciones de precedencia.
La sintaxis de una declaración de precedencia es la misma que la de %token: bien
%left símbolos... o
%left símbolos...
Y realmente cualquiera de estas declaraciones sirve para los mismos propósitos que %token. Pero
además, estos especifican la asociatividad y precedencia relativa para todos los símbolos:
• La asociatividad de un operador op determina cómo se anidan los usos de un operador repetido:
si ‘x op y op z’ se analiza agrupando x con y primero o agrupando y con z primero. %left especifica
asociatividad por la izquierda (agrupando x con y primero) y %right especifica asociatividad por la
derecha (agrupando y con z primero). %nonassoc especifica no asociatividad, que significa que ‘x op
y op z’ se considera como un error de sintaxis.
• La precedencia de un operador determina cómo se anida con otros operadores. Todos los tokens
declarados en una sola declaración de precedencia tienen la misma precedencia y se anidan
conjuntamente de acuerdo a su asociatividad. Cuando dos tokens declarados asocian declaraciones
de diferente precedencia, la última en ser declarada tiene la mayor precedencia y es agrupada en
primer lugar
 Funcionamiento del analizador
El fuente de Bison se convierte en una función en C llamada yyparse. Aquí describimos las
convenciones de interfaz de yyparse y las otras funciones que éste necesita usar. Tenga en cuenta
que el analizador utiliza muchos identificadores en C comenzando con ‘yy’ e ‘YY’ para propósito
interno. Si utiliza tales identificadores (a parte de aquellos descritos en el manual) en una acción o
en código C adicional en el archivo de la gramática, es probable que se encuentre con problemas.
La Función del Analizador yyparse:
Se llama a la función yyparse para hacer que el análisis comience. Esta función lee tokens, ejecuta
acciones, y por último retorna cuando se encuentre con el final del fichero o un error de sintaxis del
que no puede recuperarse. Usted puede también escribir acciones que ordenen a yyparse retornar
inmediatamente sin leer más allá. El valor devuelto por yyparse es 0 si el análisis tuvo éxito (el
retorno se debe al final del fichero). El valor es 1 si el análisis falló (el retorno es debido a un error
de sintaxis).
La Funcion del Analizador Léxico yylex:
La función del analizador léxico, yylex, reconoce tokens desde el flujo de entrada y se los devuelve
al analizador. Bison no crea esta función automáticamente; usted debe escribirla de manera que
yyparse pueda llamarla. En programas simples, yylex se define a menudo al final del archivo de la
gramática de Bison. En programas un poco más complejos, lo habitual es crear un programa en Flex
que genere automáticamente esta función y enlazar Flex y Bison.
2 Ejemplos de la creación de un compilador utilizando Flex y Bison.
Calculadora
Ejemplo Flex y Bison
Vamos a realizar un ejemplo de una calculadora sencilla que reconocerá las principales
operaciones aritmética (+,-,* y /).
Abrimos un editor de texto y pegamos el siguiente código que será nuestro scanner
/*****************
Definiciones
Se colocan las cabeceras, variables y expresiones regulares
********************/
%{
#include <stdio.h>
#include <stdlib.h>
#include "sintactico.tab.h"
int linea=0;
%}
/*
Creamos todas las expresiones regulares
Creamos la definición llamada DIGITO, podemos acceder esta definición
usando {DIGITO}*/
DIGITO [0-9]
NUMERO {DIGITO}+("."{DIGITO}+)?
%%
/***************
Reglas
*****************/
/* Creamos las reglas que reconocerán las cadenas que acepte
Nuestro scanner y retornaremos el token a bison con la
funcion return. */
{NUMERO} {yylval.real=atof(yytext); return(NUMERO);}
"=" {return(IGUAL);}
"+" {return(MAS);}
"-" {return(MENOS);}
";" {return(PTOCOMA);}
"*" {return(POR);}
"/" {return(DIV);}
"(" {return(PAA);}
")" {return(PAC);}
"n" {linea++;}
[trf] {}
" " {}
/* Si en nuestra entrada tiene algún caracter que no pertenece a
las reglas anteriores, se genera un error léxico */
. {printf("Error lexico en linea %d",linea);}
%%
/*
Código de Usuario
Aquí podemos realizar otras funciones, como por ejemplo ingresar
símbolos a nuestra tabal de símbolos o cualquier otra accione
del usuario.
Todo lo que el usuario coloque en esta sección se copiara al
archvi lex.yy.c tal y como esta.
*/
Guardamos el archivo como lexico.l. Luego creamos un nuevo archivo y colocamos el siguiente
código.
%{
/********************
Declaraciones en C
**********************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
extern int yylex(void);
extern char *yytext;
extern int linea;
extern FILE *yyin;
void yyerror(char *s);
%}
/************************
Declaraciones de Bison
*************************/
/* Especifica la coleccion completa de tipos de datos para poder usar
varios tipos de datos en los terminales y no terminales*/
%union
{
float real;
}
/* Indica la produccion con la que inicia nuestra gramatica*/
%start Exp_l
/* Especificacion de termines, podemos especificar tambien su tipo */
%token <real> NUMERO
%token MAS
%token MENOS
%token IGUAL
%token PTOCOMA
%token POR
%token DIV
%token PAA
%token PAC
/* No Terminales, que tambien podemos especificar su tipo */
%type <real> Exp
%type <real> Calc
%type <real> Exp_l
/* Definimos las precedencias de menor a mayor */
%left MAS MENOS
%left POR DIV
%%
/**********************
Reglas Gramaticales
***********************/
Exp_l: Exp_l Calc
|Calc
;
Calc : Exp PTOCOMA {printf ("%4.1fn",$1)}
;
/* con el símbolo de $$ asignamos el valor semántico de toda
la acción de la derecha y se la asignamos al no terminal de
la izquierda, en la siguiente regla, se la asigna a Exp.
Para poder acceder al valor de los terminales y no terminales del lado
derecho usamos el símbolo $ y le concatenamos un numero que representa
la posición en la que se encuentra es decir si tenemos
A --> B NUMERO C
Si queremos usar le valor que tiene el no terminal B usamos $1, si queremos
usar el valor que tiene NUMERO usamos $2 y así sucesivamente.
*/
Exp : NUMERO {$$=$1;}
|Exp MAS Exp {$$=$1+$3;}
|Exp MENOS Exp {$$=$1-$3;}
|Exp POR Exp {$$=$1*$3;}
|Exp DIV Exp {$$=$1/$3;}
|PAA Exp PAC {$$=$2;}
;
%%
/********************
Codigo C Adicional
**********************/
void yyerror(char *s)
{
printf("Error sintactico %s",s);
}
int main(int argc,char **argv)
{
if (argc>1)
yyin=fopen(argv[1],"rt");
else
yyin=stdin;
yyparse();
return 0;
}
Guardamos este archivo con el nombre sintáctico.y y con eso ya tenemos nuestro scanner y
nuestro parser terminado. Para compilar estos archivos usamos los comandos
Compilando sintactico.y
~> bison -d sintactico.y
El parámetro –d, crea el fichero t.tab.h, que contiene los identificadores de los tokens de bison
usados por flex
Compilando lexico.l
~> flex lexico.l
Compilando arhivos generados y crear ejecutable
~> cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm
Esto nos genera un ejecutable llamado analizador.
Muchas veces necesitamos modificar nuestro archivo sintáctico.y o lexico.l y tenemos que compilar
todo cada vez que hacemos un cambio, para no estar escribiendo los comandos cada vez que
realizamos un cambio, crearemos un script, que al ejecutarlo realizara todos los comandos de
compilación. Para eso creamos un nuevo archivo en blanco y escribimos
#!/bin/bash
bison -d sintactico.y
flex lexico.l
cc lex.yy.c sintactico.tab.c -o analizador -lfl –lm
Guardamos este archivo con cualquier nombre, por ejemplo compilar.sh. Ahora cambiaremos las
propiedades de este archivo para poder ejecutar. Le damos clic derecho sobre este archivo y en la
pestaña permisos elegimos la opción de “Permitir ejecutar el archivo como un programa”, cerramos
esa ventana.
Para poder compilar, desde consola nos ubicamos donde se encuentra este archivo .sh y
escribimos
./compilar.sh
Esto nos genera nuestro ejecutable que podemos correr para poder probar nuestra
calculadora. Para ejecutar este ejemplo usamos el comando
./analizador
Ingresamos algunas expresiones y el resultado que obtenemos es:
Ejemplo 2
Ante la siguiente entrada a =12+2*cos(3.14) ; La salida debe ser: El valor del identificador a es 10.
Fichero léxico_solo.l
%{
/* Ejemplo para una pequeña calculadora que permite
trabajar con numeros enteros y reales con las operaciones
básicas de suma, resta, producto, division y trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
int nlines=0;
%}
DIGITO [0-9]
ID [a-zA-Z][a-zA-Z0-9_]*
%%
{DIGITO}+ {printf("Encontrado TKN_NUM_ENTERO: %d",atoi(yytext));}
{DIGITO}+"."{DIGITO}+ {printf("Encontrado TKN_NUM_REAL: %f",atof(yytext));}
"=" {printf("Encontrado TKN_ASIGN: %s",yytext);}
";" {printf("Encontrado TKN_PTOCOMA: %s",yytext);}
"*" {printf("Encontrado TKN_MULT: %s",yytext);}
"/" {printf("Encontrado TKN_DIV: %s",yytext);}
"+" {printf("Encontrado TKN_MAS: %s",yytext);}
"-" {printf("Encontrado TKN_MENOS: %s",yytext);}
"(" {printf("Encontrado TKN_PAA: %s",yytext);}
")" {printf("Encontrado TKN_PAC: %s",yytext);}
"cos" {printf("Encontrado TKN_COS: %s",yytext);}
"sen" {printf("Encontrado TKN_SEN: %s",yytext);}
{ID} {printf("Encontrado TKN_ID: %s",yytext);}
"n" {nlines++;}
%%
void main(int argc,char **argv)
{
if (argc>1)
yyin=fopen(argv[1],"rt");
else
yyin=stdin;
yylex();
printf("nNumero lineas analizadas: %dn", nlines);
}
/* para compilar
flex lexico.l
cc lex.yy.c -o milex -lfl -lm
*/
Fichero léxico.l (versión a enlazar con Bison)
%{
/* Ejemplo para una pequeña calculadora que permite trabajar
con las operaciones básicas de suma, resta, producto, division y
trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include "sintactico.tab.h"
int nlines=0;
%}
DIGITO [0-9]
ID [a-zA-Z][a-zA-Z0-9_]*
%%
{DIGITO}+("."{DIGITO}+)? {//printf("Encontrado TKN_NUM: %fn",atof(yytext));
yylval.real=atof(yytext);
return(TKN_NUM);}
"=" {//printf("Encontrado TKN_ASIGN: %sn",yytext);
return(TKN_ASIGN);}
";" {//printf("Encontrado TKN_PTOCOMA: %sn",yytext);
return(TKN_PTOCOMA);}
"*" {//printf("Encontrado TKN_MULT: %sn",yytext);
return(TKN_MULT);}
"/" {//printf("Encontrado TKN_DIV: %sn",yytext);
return(TKN_DIV);}
"+" {//printf("Encontrado TKN_MAS: %sn",yytext);
return(TKN_MAS);}
"-" {//printf("Encontrado TKN_MENOS: %sn",yytext);
return(TKN_MENOS);}
"(" {//printf("Encontrado TKN_PAA: %sn",yytext);
return(TKN_PAA);}
")" {//printf("Encontrado TKN_PAC: %sn",yytext);
return(TKN_PAC);}
"cos" {//printf("Encontrado TKN_COS: %sn",yytext);
return(TKN_COS);}
"sen" {//printf("Encontrado TKN_SEN: %sn",yytext);
return(TKN_SEN);}
{ID} {//printf("Encontrado TKN_ID: %sn",yytext);
return(TKN_ID);}
"n" {nlines++;}
.
%%
/********
Para el lexico solo
void main(int argc,char **argv)
{
if (argc>1)
yyin=fopen(argv[1],"rt");
else
yyin=stdin;
yylex();
printf("nNumero lineas analizadas: %dn", nlines);
}
*******/
/* para compilar
flex lexico.l
cc lex.yy.c -o milex -lfl -lm
*/
Fichero sintactico.y (Bison)
%{
/* Ejemplo para una pequeña calculadora que permite trabajar
con numeros enteros y reales con las operaciones básicas de
suma, resta, producto, division y trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
extern int yylex(void);
extern char *yytext;
extern int nlines;
extern FILE *yyin;
void yyerror(char *s);
%}
%union
{
float real;
}
%start Calculadora
%token <real> TKN_NUM
%token TKN_ASIGN
%token TKN_PTOCOMA
%token TKN_MULT
%token TKN_DIV
%token TKN_MAS
%token TKN_MENOS
%token TKN_PAA
%token TKN_PAC
else
yyin=stdin;
yyparse();
printf("FIN del Analisis. Entrada CORRECTAn");
printf("Numero lineas analizadas: %dn", nlines);
return 0;
}
/* para compilar
bison -d sintactico.y
flex lexico.l
cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm
*/

Más contenido relacionado

La actualidad más candente

Archivos de Cabecera.
Archivos de Cabecera.Archivos de Cabecera.
Archivos de Cabecera.
Luis Stifler
 
Codigo intermedio
Codigo intermedioCodigo intermedio
Codigo intermedio
Emanuel Gs
 
Actividad 2 Analizador léxico, sintáctico y semántico
Actividad 2 Analizador léxico, sintáctico y semántico Actividad 2 Analizador léxico, sintáctico y semántico
Actividad 2 Analizador léxico, sintáctico y semántico
maryr_
 

La actualidad más candente (20)

Tutorial C
Tutorial CTutorial C
Tutorial C
 
Archivos de Cabecera.
Archivos de Cabecera.Archivos de Cabecera.
Archivos de Cabecera.
 
Generación código intermedio 2
Generación código intermedio 2Generación código intermedio 2
Generación código intermedio 2
 
GENERACION DE CODIGO INTERMEDIO
GENERACION DE CODIGO INTERMEDIOGENERACION DE CODIGO INTERMEDIO
GENERACION DE CODIGO INTERMEDIO
 
Codigo intermedio
Codigo intermedioCodigo intermedio
Codigo intermedio
 
Generacion codigomaquina
Generacion codigomaquinaGeneracion codigomaquina
Generacion codigomaquina
 
Ficheros de cabecera
Ficheros de cabecera Ficheros de cabecera
Ficheros de cabecera
 
Flex y Bison
Flex y BisonFlex y Bison
Flex y Bison
 
Santaella u5 Lenguaje C++
Santaella u5 Lenguaje C++Santaella u5 Lenguaje C++
Santaella u5 Lenguaje C++
 
Flex bison
Flex bisonFlex bison
Flex bison
 
Código intermedio
Código intermedioCódigo intermedio
Código intermedio
 
Actividad 2 Analizador léxico, sintáctico y semántico
Actividad 2 Analizador léxico, sintáctico y semántico Actividad 2 Analizador léxico, sintáctico y semántico
Actividad 2 Analizador léxico, sintáctico y semántico
 
Tutorial C
Tutorial CTutorial C
Tutorial C
 
Usando flex en Windows
Usando flex en WindowsUsando flex en Windows
Usando flex en Windows
 
Compiladores
CompiladoresCompiladores
Compiladores
 
Código intermedio
Código intermedioCódigo intermedio
Código intermedio
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 
Tutorial Flex y Bison
Tutorial Flex y BisonTutorial Flex y Bison
Tutorial Flex y Bison
 
ESTRUCTURA BASICA PARA C++
ESTRUCTURA BASICA PARA C++ESTRUCTURA BASICA PARA C++
ESTRUCTURA BASICA PARA C++
 
Estructuras básicas para C++
Estructuras básicas para C++Estructuras básicas para C++
Estructuras básicas para C++
 

Similar a Flex y bison

Herramientas flex y bison
Herramientas flex y bisonHerramientas flex y bison
Herramientas flex y bison
alexisdario
 
Trabajo compiladores ivan bolaños
Trabajo compiladores ivan bolañosTrabajo compiladores ivan bolaños
Trabajo compiladores ivan bolaños
Iván Bolaños
 
Pontificia universidad católica del ecuador flex y bison
Pontificia universidad católica del ecuador flex y bisonPontificia universidad católica del ecuador flex y bison
Pontificia universidad católica del ecuador flex y bison
Gabriel Solano
 

Similar a Flex y bison (20)

COMPILADORES
COMPILADORESCOMPILADORES
COMPILADORES
 
Fyb
FybFyb
Fyb
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 
Flex y Bison
Flex y BisonFlex y Bison
Flex y Bison
 
FLEX Y BISON
FLEX Y BISONFLEX Y BISON
FLEX Y BISON
 
Conceptos Básicos acerca de Procesadores de Lenguajes
Conceptos Básicos acerca de Procesadores de LenguajesConceptos Básicos acerca de Procesadores de Lenguajes
Conceptos Básicos acerca de Procesadores de Lenguajes
 
Investigacion Flex Y Bison
Investigacion Flex Y BisonInvestigacion Flex Y Bison
Investigacion Flex Y Bison
 
Herramientas flex y bison
Herramientas flex y bisonHerramientas flex y bison
Herramientas flex y bison
 
Taller de flex y bison
Taller de flex y bisonTaller de flex y bison
Taller de flex y bison
 
Compiladores - Flex y Bison
Compiladores - Flex y BisonCompiladores - Flex y Bison
Compiladores - Flex y Bison
 
Flex y Byson
Flex y BysonFlex y Byson
Flex y Byson
 
Trabajo compiladores ivan bolaños
Trabajo compiladores ivan bolañosTrabajo compiladores ivan bolaños
Trabajo compiladores ivan bolaños
 
Flex bison
Flex bisonFlex bison
Flex bison
 
Edison caicedo
Edison caicedoEdison caicedo
Edison caicedo
 
Flex y Bison
Flex y Bison Flex y Bison
Flex y Bison
 
Pontificia universidad católica del ecuador flex y bison
Pontificia universidad católica del ecuador flex y bisonPontificia universidad católica del ecuador flex y bison
Pontificia universidad católica del ecuador flex y bison
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 
Flex y bison
Flex y bisonFlex y bison
Flex y bison
 

Más de Alvaro Cedeño

Más de Alvaro Cedeño (20)

Analisis del ciclo de vida de los conejos y zorros
Analisis del ciclo de vida de los conejos y zorrosAnalisis del ciclo de vida de los conejos y zorros
Analisis del ciclo de vida de los conejos y zorros
 
Diseño de simulación
Diseño de simulación Diseño de simulación
Diseño de simulación
 
Elementos que garantizan el éxito de un modelo de simulación
Elementos que garantizan el éxito de un modelo de simulaciónElementos que garantizan el éxito de un modelo de simulación
Elementos que garantizan el éxito de un modelo de simulación
 
Ventajas y desventajas de simulación
Ventajas y desventajas de simulaciónVentajas y desventajas de simulación
Ventajas y desventajas de simulación
 
Taller analisis semantico
Taller analisis semanticoTaller analisis semantico
Taller analisis semantico
 
Fases de los compiladores
Fases de los compiladoresFases de los compiladores
Fases de los compiladores
 
Historia de los lenguajes fortran h, pascal, c
Historia de los lenguajes fortran h, pascal, c Historia de los lenguajes fortran h, pascal, c
Historia de los lenguajes fortran h, pascal, c
 
Instalación de mingw-w64 y compilación hola mundo fortran
Instalación de mingw-w64 y compilación hola mundo fortranInstalación de mingw-w64 y compilación hola mundo fortran
Instalación de mingw-w64 y compilación hola mundo fortran
 
Compiladores manuales
Compiladores manualesCompiladores manuales
Compiladores manuales
 
Emulador de ensamblador EMU8086
 Emulador de ensamblador EMU8086 Emulador de ensamblador EMU8086
Emulador de ensamblador EMU8086
 
Instalacion Decompiladores VB Decompiler Lite 10.8 y dotPeek 2018
Instalacion Decompiladores VB Decompiler Lite 10.8 y dotPeek 2018Instalacion Decompiladores VB Decompiler Lite 10.8 y dotPeek 2018
Instalacion Decompiladores VB Decompiler Lite 10.8 y dotPeek 2018
 
Lenguajes de programacion y mas
Lenguajes de programacion y masLenguajes de programacion y mas
Lenguajes de programacion y mas
 
Lenguajes de programacion
Lenguajes de programacionLenguajes de programacion
Lenguajes de programacion
 
Mapa conceptual
Mapa conceptualMapa conceptual
Mapa conceptual
 
Medios de transmisión
Medios de transmisiónMedios de transmisión
Medios de transmisión
 
Historia de shannon
Historia de shannonHistoria de shannon
Historia de shannon
 
Códigos lineales
Códigos linealesCódigos lineales
Códigos lineales
 
Entropia
EntropiaEntropia
Entropia
 
Entropia de la informacion 2
Entropia de la informacion 2Entropia de la informacion 2
Entropia de la informacion 2
 
Historia teoría de la comunicación
Historia teoría de la comunicaciónHistoria teoría de la comunicación
Historia teoría de la comunicación
 

Último

TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
jlorentemartos
 

Último (20)

Posición astronómica y geográfica de Europa.pptx
Posición astronómica y geográfica de Europa.pptxPosición astronómica y geográfica de Europa.pptx
Posición astronómica y geográfica de Europa.pptx
 
Sesión de clase APC: Los dos testigos.pdf
Sesión de clase APC: Los dos testigos.pdfSesión de clase APC: Los dos testigos.pdf
Sesión de clase APC: Los dos testigos.pdf
 
TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
TEMA 14.DERIVACIONES ECONÓMICAS, SOCIALES Y POLÍTICAS DEL PROCESO DE INTEGRAC...
 
Desarrollo y Aplicación de la Administración por Valores
Desarrollo y Aplicación de la Administración por ValoresDesarrollo y Aplicación de la Administración por Valores
Desarrollo y Aplicación de la Administración por Valores
 
La Evaluacion Formativa SM6 Ccesa007.pdf
La Evaluacion Formativa SM6  Ccesa007.pdfLa Evaluacion Formativa SM6  Ccesa007.pdf
La Evaluacion Formativa SM6 Ccesa007.pdf
 
Revista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdfRevista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdf
 
Los dos testigos. Testifican de la Verdad
Los dos testigos. Testifican de la VerdadLos dos testigos. Testifican de la Verdad
Los dos testigos. Testifican de la Verdad
 
activ4-bloque4 transversal doctorado.pdf
activ4-bloque4 transversal doctorado.pdfactiv4-bloque4 transversal doctorado.pdf
activ4-bloque4 transversal doctorado.pdf
 
Los avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtualesLos avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtuales
 
FICHA PROYECTO COIL- GLOBAL CLASSROOM.docx.pdf
FICHA PROYECTO COIL- GLOBAL CLASSROOM.docx.pdfFICHA PROYECTO COIL- GLOBAL CLASSROOM.docx.pdf
FICHA PROYECTO COIL- GLOBAL CLASSROOM.docx.pdf
 
PLAN LECTOR 2024 integrado nivel inicial-miercoles 10.pptx
PLAN LECTOR 2024  integrado nivel inicial-miercoles 10.pptxPLAN LECTOR 2024  integrado nivel inicial-miercoles 10.pptx
PLAN LECTOR 2024 integrado nivel inicial-miercoles 10.pptx
 
Tema 10. Dinámica y funciones de la Atmosfera 2024
Tema 10. Dinámica y funciones de la Atmosfera 2024Tema 10. Dinámica y funciones de la Atmosfera 2024
Tema 10. Dinámica y funciones de la Atmosfera 2024
 
SISTEMA RESPIRATORIO PARA NIÑOS PRIMARIA
SISTEMA RESPIRATORIO PARA NIÑOS PRIMARIASISTEMA RESPIRATORIO PARA NIÑOS PRIMARIA
SISTEMA RESPIRATORIO PARA NIÑOS PRIMARIA
 
ACRÓNIMO DE PARÍS PARA SU OLIMPIADA 2024. Por JAVIER SOLIS NOYOLA
ACRÓNIMO DE PARÍS PARA SU OLIMPIADA 2024. Por JAVIER SOLIS NOYOLAACRÓNIMO DE PARÍS PARA SU OLIMPIADA 2024. Por JAVIER SOLIS NOYOLA
ACRÓNIMO DE PARÍS PARA SU OLIMPIADA 2024. Por JAVIER SOLIS NOYOLA
 
Feliz Día de la Madre - 5 de Mayo, 2024.pdf
Feliz Día de la Madre - 5 de Mayo, 2024.pdfFeliz Día de la Madre - 5 de Mayo, 2024.pdf
Feliz Día de la Madre - 5 de Mayo, 2024.pdf
 
Procedimientos para la planificación en los Centros Educativos tipo V ( multi...
Procedimientos para la planificación en los Centros Educativos tipo V ( multi...Procedimientos para la planificación en los Centros Educativos tipo V ( multi...
Procedimientos para la planificación en los Centros Educativos tipo V ( multi...
 
PLAN DE REFUERZO ESCOLAR MERC 2024-2.docx
PLAN DE REFUERZO ESCOLAR MERC 2024-2.docxPLAN DE REFUERZO ESCOLAR MERC 2024-2.docx
PLAN DE REFUERZO ESCOLAR MERC 2024-2.docx
 
Louis Jean François Lagrenée. Erotismo y sensualidad. El erotismo en la Hist...
Louis Jean François Lagrenée.  Erotismo y sensualidad. El erotismo en la Hist...Louis Jean François Lagrenée.  Erotismo y sensualidad. El erotismo en la Hist...
Louis Jean François Lagrenée. Erotismo y sensualidad. El erotismo en la Hist...
 
Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024
 
La Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración AmbientalLa Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración Ambiental
 

Flex y bison

  • 1.  Reseña Histórica Los primeros lenguajes de programación surgieron de la idea de Charles Babagge, la cual se le ocurrió a este hombre a mediados del siglo XIX. Era un profesor matemático de la universidad de Cambridge e inventor inglés, que al principio del siglo XIX predijo muchas de las teorías en que se basan los actuales ordenadores. Consistía en lo que él denominaba la maquina analítica, pero que por motivos técnicos no pudo construirse hasta mediados del siglo XX. Con él colaboro Ada Lovedby, la cual es considerada como la primera programadora de la historia, pues realizo programas para aquélla supuesta máquina de Babagge, en tarjetas perforadas. Como la maquina no llego nunca a construirse, los programas de Ada, lógicamente, tampoco llegaron a ejecutarse, pero si suponen un punto de partida de la programación, sobre todo si observamos que en cuanto se empezó a programar, los programadores utilizaron las técnicas diseñadas por Charles Babagge, y Ada, que consistían entre otras, en la programación mediante tarjetas perforadas. A pesar de ello, Ada ha permanecido como la primera programadora de la historia. Se dice por tanto que estos dos genios de antaño, se adelantaron un siglo a su época, lo cual describe la inteligencia de la que se hallaban dotados. En 1823 el gobierno Británico lo apoyo para crear el proyecto de una máquina de diferencias, un dispositivo mecánico para efectuar sumas repetidas. Pero Babagge se dedicó al proyecto de la máquina analítica, abandonando la máquina de diferencias, que se pudiera programar con tarjetas perforadas, gracias a la creación de Charles Jacquard (francés). Este hombre era un fabricante de tejidos y había creado un telar que podía reproducir automáticamente patrones de tejidos, leyendo la información codificada en patrones de agujeros perforados en tarjetas de papel rígido. Entonces Babagge intento crear la máquina que se pudiera programar con tarjetas perforadas para efectuar cualquier cálculo con una precisión de 20 dígitos. Pero la tecnología de la época no bastaba parahacer realidad sus ideas. Si bien las ideas de Babagge no llegaron a materializarse de forma definitiva, su contribución es decisiva, ya que los ordenadores actuales responden a un esquema análogo al de la máquina analítica. En su diseño, la máquina constaba de cinco unidades básicas: 1) Unidad de entrada, para introducir datos e instrucciones; 2) Memoria, donde se almacenaban datos y resultados intermedios; 3) Unidad de control, para regular la secuencia de ejecución de las operaciones; 4) Unidad Aritmético-Lógica, que efectúa las operaciones; 5) Unidad de salida, encargada de comunicar al exterior los resultados. Charles Babbage, conocido como el "padre de la informática" no pudo completar en aquella época la construcción del computador que había soñado, dado que faltaba algo fundamental: la electrónica. El camino señalado de Babbage, no fue nunca abandonado y siguiéndolo, se construyeron los primeros computadores. Cuando surgió el primer ordenador, el famoso ENIAC (Electronic Numerical Integrator And Calculator), su programación se basaba en componentes físicos, o sea, que se programaba, cambiando directamente el Hardware de la máquina, exactamente lo que sé hacia era cambiar cables de sitio para conseguir así la programación de la máquina. La entrada y salida de datos se realizaba mediante tarjetas perforadas.
  • 2.  Diseño y construcción de un compilador. En el proceso de construcción de compiladores se integran muchos conceptos diferentes de las Ciencias de la Computación:  Algoritmos de búsqueda.  Árboles, Hashing.  Programación modular.  Lenguaje Assembly. Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases correspondientes al Análisis léxico (que consiste en la descomposición del programa fuente en componentes léxicos), Análisis sintáctico (agrupación de los componentes léxicos en frases gramaticales) y Análisis semántico (comprobación de la validez semántica de las sentencias aceptadas en la fase de Análisis Sintáctico). Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener un código lo más eficiente posible).  Las herramientas Flex y Bison. Son herramientas para el desarrollo de lenguaje, flex sirve para construir analizadores léxicos, esta herramienta genera código en c que puede ser compilado. Bison es la herramienta encargada de la generación de analizadores sintácticos, es una herramienta compatible con YACC, también genera código en C o C++ y puede ser fácilmente integrado con Flex.  Que es flex El Flex define las reglas de reconocimiento de símbolos (Tokens) a partir de expresiones regulares. Cuando un Token es reconocido por uno de estos patrones de agrupamiento se le define una acción, por lo general esta acción es devolver el Tipo y el valor (lexema). El Flex cuando se utiliza combinado con el Bison, utiliza las definiciones de los Tokens realizadas en el Bison para la comunicación entre ellos  Como se instala Flex y Bison 1. Descarga el software disponible en el sitio de la cátedra. 2. Instalar el software en la unidad C: (para explicar a partir del punto 4 se tendrá como hipótesis de que flex y bison han sido instalados en la ruta: C:GnuWin32 donde contiene una subcarpeta llamada bin donde se encuentran los programas respectivos) 3. Flex y bison son aplicaciones de consola, por lo que se deberá entrar al Símbolo del sistema y tipear líneas de comando para ejecutar Flex. Una alternativa es crear un archivo de proceso por lotes (*.bat) que contenga las líneas de comando para la ejecución de Flex y Bison y/o la compilación del archivo generado.
  • 3. 4. Si deseas que flex y bison se integren al conjunto de variables del entorno (esto te va a permitir llamar a flex/bison desde cualquier ubicación en la línea de comandos) debes hacer lo siguiente: o Clic derecho en “Mi PC”. o Selecciona “Propiedades” o Clic en la pestaña “Opciones Avanzadas” o Presiona el botón “Variables de entorno” o En la ventana de variables de entorno, ubicarse en la sección “Variables del sistema” luego haz clic en PATH y luego en el botón “Modificar” (si no está hacer clic en “Nueva” y agregar PATH) o En la nueva ventana, escribir la ruta completa al directorio “bin” de la aplicación flex/bison. Si existe otro valor, separarlos con comas. o Aceptar los cambios y luego reiniciar el sistema operativo. 5. Si deseas instalar un compilador de C como MinGwin, deberás integrar la ruta de acceso al compilador a las variables de entorno para facilitar la llamada al programa. Por ejemplo si se instaló MingWin en “C:Mingw” y dentro de la carpeta “bin” se encuentra “gcc.exe” que es el ejecutable, entonces de deberá agregar (análogo a los pasos anteriores) lo siguiente: 6. Cuando tengas listo podrás llamar a flex/bison desde el símbolo del sistema sin necesidad de ubicarte en la carpeta donde ha sido instalado flex/bison.  Patrones en flex Los patrones en la entrada se escriben utilizando un conjunto extendido de expresiones regulares. Estas son: `x' empareja el caracter `x' `.' cualquier caracter (byte) excepto una línea nueva `[xyz]' una "clase de caracteres"; en este caso, el patrón empareja una `x', una `y', o una `z' `[abj-oZ]' una "clase de caracteres" con un rango; empareja una `a', una `b', cualquier letra desde la `j' hasta la `o', o una `Z' `[^A-Z]' una "clase de caracteres negada", es decir, cualquier caracter menos los que aparecen en la clase. En este caso, cualquier caracter EXCEPTO una letra mayúscula. `[^A-Zn]' cualquier caracter EXCEPTO una letra mayúscula o una línea nueva `r*'
  • 4. cero o más r's, donde r es cualquier expresión regular `r+' una o más r's `r?' cero o una r (es decir, "una r opcional") `r{2,5}' donde sea de dos a cinco r's `r{2,}' dos o más r's `r{4}' exactamente 4 r's `{nombre}' la expansión de la definición de "nombre" (ver más abajo) `"[xyz]"foo"' la cadena literal: [xyz]"foo `x' si x es una `a', `b', `f', `n', `r', `t', o `v', entonces la interpretación ANSI-C de x. En otro caso, un literal `x' (usado para indicar operadores tales como `*') `0' un caracter NUL (código ASCII 0) `123' el caracter con valor octal 123 `x2a' el caracter con valor hexadecimal 2a `(r)' empareja una R; los paréntesis se utilizan para anular la precedencia (ver más abajo) `rs' la expresión regular r seguida por la expresión regular s; se denomina "concatenación"
  • 5. `r|s' bien una r o una s `r/s' una r pero sólo si va seguida por una s. El texto emparejado por s se incluye cuando se determina si esta regla es el "emparejamiento más largo", pero se devuelve entonces a la entrada antes que se ejecute la acción. Así que la acción sólo ve el texto emparejado por r. Este tipo de patrones se llama "de contexto posterior". (Hay algunas combinaciones de r/s que flex no puede emparejar correctamente. See section Deficiencias / Errores, las notas a cerca del "contexto posterior peligroso".) `^r' una r, pero sólo al comienzo de una línea (es decir, justo al comienzo del análisis, o a la derecha después de que se haya analizado una línea nueva). `r$' una r, pero sólo al final de una línea (es decir, justo antes de una línea nueva). Equivalente a "r/n". Fíjese que la noción de flex de una "línea nueva" es exáctamente lo que el compilador de C utilizado para compilar flex interprete como `n'; en particular, en algunos sistemas DOS debe filtrar los r's de la entrada used mismo, o explícitamente usar r/rn para "r$". `<s>r' una r, pero sólo en la condición de arranque s (See section Condiciones de arranque, para una discusión sobre las condiciones de arranque) `<s1,s2,s3>r' lo mismo, pero en cualquiera de las condiciones de arranque s1, s2, o s3 `<*>r' una r en cualquier condición de arranque, incluso una exclusiva. `<<EOF>>' un fin-de-fichero `<s1,s2><<EOF>>' un fin-de-fichero en una condición de arranque s1 ó s2
  • 6.  Emparejamiento de la entrada El escáner asocia las cadenas ingresadas que concuerden con los patrones de caracteres guardados. Si encuentra más de un emparejamiento, toma el que empareje más texto (para reglas de contexto posterior, se incluye la longitud de la parte posterior, incluso si se devuelve a la entrada). Si encuentra dos o más emparejamientos de la misma longitud, se escoge la regla listada en primer lugar en el fichero de entrada de flex. Una vez que se determina el emparejamiento, el texto correspondiente al emparejamiento (denominado el token) está disponible en el puntero a caracter global yytext, y su longitud en la variable global entera yyleng. Entonces la acción correspondiente al patrón emparejado se ejecuta, y entonces la entrada restante se analiza para otro emparejamiento. Si no se encuentra un emparejamiento, entonces se ejecuta la regla por defecto: el siguiente caracter en la entrada se considera reconocido y se copia a la salida estándar. Así, la entrada válida más simple de flex es: %% que genera un escáner que simplemente copia su entrada (un caracter a la vez) a la salida.  Condiciones de arranque Las condiciones de arranque se declaran en la (primera) sección de definiciones de la entrada usando líneas sin sangrar comenzando con `%s' ó `%x' seguida por una lista de nombres. Lo primero declara condiciones de arranque inclusivas, lo último condiciones de arranque exclusivas. Una condición de arranque se activa utilizando la acción BEGIN. Hasta que se ejecute la próxima acción BEGIN, las reglas con la condición de arranque dada estarán activas y las reglas con otras condiciones de arranque estarán inactivas. Si la condición de arranque es inclusiva, entonces las reglas sin condiciones de arranque también estarán activas. Si es exclusiva, entonces sólamente las reglas calificadas con la condición de arranque estarán activas.  Variables disponibles para el usuario Esta sección resume los diferentes valores disponibles al usuario en las acciones de la regla.  `char *yytext' apunta al texto del token actual. Este puede modificarse pero no alargarse (no puede añadir caracteres al final). Si aparece la directiva especial `%array' en la primera sección de la descripción del analizador, entonces yytext se declara en su lugar como `char yytext[YYLMAX]', donde YYLMAX es la definicion de una macro que puede redefinir en la primera sección si no le gusta el valor por defecto (generalmente 8KB). El uso de `%array'produce analizadores algo más lentos, pero el valor de yytext se vuelve inmune a las llamadas a `input()' y `unput()', que potencialmente destruyen su valor cuando yytext es un puntero a caracter. El opuesto de `%array' es `%pointer', que se encuentra por defecto. Usted no puede utilizar `%array' cuando genera analizadores como clases de C++ (la bandera `-+').  `int yyleng' contiene la longitud del token actual.  `FILE *yyin' es el fichero por el que flex lee por defecto. Este podría redefinirse pero hacerlo solo tiene sentido antes de que el análisis comience o después de que se haya encontrado
  • 7. un EOF. Cambiándolo en medio del análisis tendrá resultados inesperados ya que flex utiliza buffers en su entrada; use `yyrestart()' en su lugar. Una vez que el análisis termina debido a que se ha visto un fin-de-fichero, puede asignarle a yyin el nuevo fichero de entrada y entonces llamar al analizador de nuevo para continuar analizando.  `void yyrestart( FILE *new_file )' podría ser llamada para que yyin apunte al nuevo fichero de entrada. El cambio al nuevo fichero es inmediato (cualquier entrada contenida en el buffer previamente se pierde). Fíjese que llamando a `yyrestart()' con yyin como argumento de esta manera elimina el buffer de entradda actual y continúa analizando el mismo fichero de entrada.  `FILE *yyout' es el fichero sobre el que se hacen las acciones `ECHO'. Este puede ser reasignado por el usuario.  YY_CURRENT_BUFFER devuelve un handle YY_BUFFER_STATE al buffer actual.  YY_START devuelve un valor entero correspondiente a la condición de arranque actual. Posteriormente puede usar este valor con BEGIN para retornar a la condición de arranque.  Compilación y ejecución en flex de un programa. Al ejecutar el comando flex nombre_fichero_fuente se creará un fichero en C llamado “lex.yy.c”. Si se compila este fichero con la instrucción “gcc lex.yy.c –lfl –o nombre_ejecutable” (-lfl indica enlazar con la biblioteca de flex) se obtendrá como resultado un fichero ejecutable llamado nombre_ejecutable). Una vez se ha creado el fichero ejecutable se puede ejecutar directamente. Flex esperará que se introduzca texto por la entrada estándar (teclado) y lo analizará cada vez que se pulse el retorno de carro. Para terminar con el análisis normalmente hay que pulsar <CTRL>-D. Para poder probarlo con entradas más largas, lo más sencillo es crear archivos de texto y usar redirecciones para que el ejecutable lea estos ficheros como entrada a analizar. Por ejemplo si hemos creado un analizador llamado prueba1 y un fichero de texto con datos para su análisis, llamado entrada.txt, podemos ejecutar $prueba1 < entrada.txt. Si se quiere ejecutar algún código al final de un análisis de Flex (para mostrar resultados por ejemplo) hay al menos dos opciones: %% reglas... 8 Introducción a Flex y Bison
  • 8. %% main() { yylex(); código a ejecutar al final del análisis } o bien %% reglas... %% yywrap() { código a ejecutar al final del análisis return 1; }  Introducción a Bison Bison es un generador de analizadores sintácticos de tipo LALR(1) se distribuye bajo licencia GNU y genera automáticamente código fuente C en base de una gramática libre de contexto.  Símbolos terminales y no terminales Los símbolos terminales de la gramática se denominan en Bison tokens y deben declararse en la sección de definiciones. Por convención se suelen escribir los tokens en mayúsculas y los símbolos no terminales en minúsculas. 10 Introducción a Flex y Bison Los nombres de los símbolos pueden contener letras, dígitos (no al principio), subrayados y puntos. Los puntos tienen sentido únicamente en no-terminales. Hay tres maneras de escribir símbolos terminales en la gramática. Aquí se describen las dos más usuales: • Un token declarado se escribe con un identificador, de la misma manera que un identificador en C. Por convención, debería estar todo en mayúsculas. Cada uno de estos nombres debe definirse con una declaración de %token. • Un token de carácter se escribe en la gramática utilizando la misma sintaxis usada en C para las constantes de un carácter; por ejemplo, ‘+’ es un tipo de token de carácter. Un tipo de token de carácter no necesita ser declarado a menos que necesite especificar el tipo de datos de su valor semántico, asociatividad, o precedencia. Por convención, un token de carácter se utiliza únicamente para representar un token consistente en ese carácter en particular.
  • 9.  Sintaxis de las reglas gramaticales (producciones) Una regla gramatical de Bison tiene la siguiente forma general: resultado: componentes... ; donde resultado es el símbolo no terminal que describe esta regla y componentes son los diversos símbolos terminales y no terminales que están reunidos por esta regla. Por ejemplo, exp: exp ‘+’ exp ; dice que dos agrupaciones de tipo exp, con un token ‘+’ en medio, puede combinarse en una agrupación mayor de tipo exp. Los espacios en blanco en las reglas son significativos únicamente para separar símbolos. Puede añadir tantos espacios en blanco extra como desee. Distribuidas en medio de los componentes pueden haber acciones que determinan la semántica de la regla. Una acción tiene el siguiente aspecto: {sentencias en C} Normalmente hay una única acción que sigue a los componentes. Se pueden escribir por separado varias reglas para el mismo resultado o pueden unirse con el caracter de barra vertical ‘|’ así: resultado: componentes-regla1... | componentes- regla2... ... ; Estas aún se consideran reglas distintas incluso cuando se unen de esa manera. Si los componentes en una regla están vacíos, significa que resultado puede concordar con la cadena vacía (en notación formal sería ε). Por ejemplo, aquí aparece cómo definir una secuencia separada por comas de cero o más agrupaciones exp: expseq: /* vacío */ | expseq1 ;  Declaraciones en Bison La sección de declaraciones de Bison de una gramática de Bison define los símbolos utilizados en la formulación de la gramática y los tipos de datos de los valores semánticos. Todos los nombres de tokens (pero no los tokens de carácter literal simple tal como ‘+’ y ‘*’) se deben declarar. Los símbolos no terminales deben ser declarados si necesita especificar el tipo de dato a utilizar para los valores semánticos.  Precedencia de operadores Use las declaraciones %left, %right o %nonassoc para declarar un token y especificar su precedencia y asociatividad, todo a la vez. Estas se llaman declaraciones de precedencia. La sintaxis de una declaración de precedencia es la misma que la de %token: bien %left símbolos... o %left símbolos... Y realmente cualquiera de estas declaraciones sirve para los mismos propósitos que %token. Pero además, estos especifican la asociatividad y precedencia relativa para todos los símbolos: • La asociatividad de un operador op determina cómo se anidan los usos de un operador repetido: si ‘x op y op z’ se analiza agrupando x con y primero o agrupando y con z primero. %left especifica asociatividad por la izquierda (agrupando x con y primero) y %right especifica asociatividad por la derecha (agrupando y con z primero). %nonassoc especifica no asociatividad, que significa que ‘x op y op z’ se considera como un error de sintaxis. • La precedencia de un operador determina cómo se anida con otros operadores. Todos los tokens declarados en una sola declaración de precedencia tienen la misma precedencia y se anidan conjuntamente de acuerdo a su asociatividad. Cuando dos tokens declarados asocian declaraciones
  • 10. de diferente precedencia, la última en ser declarada tiene la mayor precedencia y es agrupada en primer lugar  Funcionamiento del analizador El fuente de Bison se convierte en una función en C llamada yyparse. Aquí describimos las convenciones de interfaz de yyparse y las otras funciones que éste necesita usar. Tenga en cuenta que el analizador utiliza muchos identificadores en C comenzando con ‘yy’ e ‘YY’ para propósito interno. Si utiliza tales identificadores (a parte de aquellos descritos en el manual) en una acción o en código C adicional en el archivo de la gramática, es probable que se encuentre con problemas. La Función del Analizador yyparse: Se llama a la función yyparse para hacer que el análisis comience. Esta función lee tokens, ejecuta acciones, y por último retorna cuando se encuentre con el final del fichero o un error de sintaxis del que no puede recuperarse. Usted puede también escribir acciones que ordenen a yyparse retornar inmediatamente sin leer más allá. El valor devuelto por yyparse es 0 si el análisis tuvo éxito (el retorno se debe al final del fichero). El valor es 1 si el análisis falló (el retorno es debido a un error de sintaxis). La Funcion del Analizador Léxico yylex: La función del analizador léxico, yylex, reconoce tokens desde el flujo de entrada y se los devuelve al analizador. Bison no crea esta función automáticamente; usted debe escribirla de manera que yyparse pueda llamarla. En programas simples, yylex se define a menudo al final del archivo de la gramática de Bison. En programas un poco más complejos, lo habitual es crear un programa en Flex que genere automáticamente esta función y enlazar Flex y Bison. 2 Ejemplos de la creación de un compilador utilizando Flex y Bison. Calculadora Ejemplo Flex y Bison Vamos a realizar un ejemplo de una calculadora sencilla que reconocerá las principales operaciones aritmética (+,-,* y /). Abrimos un editor de texto y pegamos el siguiente código que será nuestro scanner /***************** Definiciones Se colocan las cabeceras, variables y expresiones regulares ********************/ %{ #include <stdio.h> #include <stdlib.h> #include "sintactico.tab.h" int linea=0; %} /*
  • 11. Creamos todas las expresiones regulares Creamos la definición llamada DIGITO, podemos acceder esta definición usando {DIGITO}*/ DIGITO [0-9] NUMERO {DIGITO}+("."{DIGITO}+)? %% /*************** Reglas *****************/ /* Creamos las reglas que reconocerán las cadenas que acepte Nuestro scanner y retornaremos el token a bison con la funcion return. */ {NUMERO} {yylval.real=atof(yytext); return(NUMERO);} "=" {return(IGUAL);} "+" {return(MAS);} "-" {return(MENOS);} ";" {return(PTOCOMA);} "*" {return(POR);} "/" {return(DIV);} "(" {return(PAA);} ")" {return(PAC);} "n" {linea++;} [trf] {} " " {} /* Si en nuestra entrada tiene algún caracter que no pertenece a las reglas anteriores, se genera un error léxico */ . {printf("Error lexico en linea %d",linea);} %% /* Código de Usuario Aquí podemos realizar otras funciones, como por ejemplo ingresar símbolos a nuestra tabal de símbolos o cualquier otra accione del usuario. Todo lo que el usuario coloque en esta sección se copiara al archvi lex.yy.c tal y como esta. */ Guardamos el archivo como lexico.l. Luego creamos un nuevo archivo y colocamos el siguiente código. %{ /******************** Declaraciones en C **********************/ #include <stdio.h>
  • 12. #include <stdlib.h> #include <math.h> extern int yylex(void); extern char *yytext; extern int linea; extern FILE *yyin; void yyerror(char *s); %} /************************ Declaraciones de Bison *************************/ /* Especifica la coleccion completa de tipos de datos para poder usar varios tipos de datos en los terminales y no terminales*/ %union { float real; } /* Indica la produccion con la que inicia nuestra gramatica*/ %start Exp_l /* Especificacion de termines, podemos especificar tambien su tipo */ %token <real> NUMERO %token MAS %token MENOS %token IGUAL %token PTOCOMA %token POR %token DIV %token PAA %token PAC /* No Terminales, que tambien podemos especificar su tipo */ %type <real> Exp %type <real> Calc %type <real> Exp_l /* Definimos las precedencias de menor a mayor */ %left MAS MENOS %left POR DIV %% /********************** Reglas Gramaticales ***********************/ Exp_l: Exp_l Calc |Calc ; Calc : Exp PTOCOMA {printf ("%4.1fn",$1)} ; /* con el símbolo de $$ asignamos el valor semántico de toda la acción de la derecha y se la asignamos al no terminal de la izquierda, en la siguiente regla, se la asigna a Exp. Para poder acceder al valor de los terminales y no terminales del lado
  • 13. derecho usamos el símbolo $ y le concatenamos un numero que representa la posición en la que se encuentra es decir si tenemos A --> B NUMERO C Si queremos usar le valor que tiene el no terminal B usamos $1, si queremos usar el valor que tiene NUMERO usamos $2 y así sucesivamente. */ Exp : NUMERO {$$=$1;} |Exp MAS Exp {$$=$1+$3;} |Exp MENOS Exp {$$=$1-$3;} |Exp POR Exp {$$=$1*$3;} |Exp DIV Exp {$$=$1/$3;} |PAA Exp PAC {$$=$2;} ; %% /******************** Codigo C Adicional **********************/ void yyerror(char *s) { printf("Error sintactico %s",s); } int main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else yyin=stdin; yyparse(); return 0; } Guardamos este archivo con el nombre sintáctico.y y con eso ya tenemos nuestro scanner y nuestro parser terminado. Para compilar estos archivos usamos los comandos Compilando sintactico.y ~> bison -d sintactico.y El parámetro –d, crea el fichero t.tab.h, que contiene los identificadores de los tokens de bison usados por flex Compilando lexico.l ~> flex lexico.l Compilando arhivos generados y crear ejecutable ~> cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm Esto nos genera un ejecutable llamado analizador. Muchas veces necesitamos modificar nuestro archivo sintáctico.y o lexico.l y tenemos que compilar todo cada vez que hacemos un cambio, para no estar escribiendo los comandos cada vez que
  • 14. realizamos un cambio, crearemos un script, que al ejecutarlo realizara todos los comandos de compilación. Para eso creamos un nuevo archivo en blanco y escribimos #!/bin/bash bison -d sintactico.y flex lexico.l cc lex.yy.c sintactico.tab.c -o analizador -lfl –lm Guardamos este archivo con cualquier nombre, por ejemplo compilar.sh. Ahora cambiaremos las propiedades de este archivo para poder ejecutar. Le damos clic derecho sobre este archivo y en la pestaña permisos elegimos la opción de “Permitir ejecutar el archivo como un programa”, cerramos esa ventana. Para poder compilar, desde consola nos ubicamos donde se encuentra este archivo .sh y escribimos ./compilar.sh Esto nos genera nuestro ejecutable que podemos correr para poder probar nuestra calculadora. Para ejecutar este ejemplo usamos el comando ./analizador Ingresamos algunas expresiones y el resultado que obtenemos es:
  • 15. Ejemplo 2 Ante la siguiente entrada a =12+2*cos(3.14) ; La salida debe ser: El valor del identificador a es 10. Fichero léxico_solo.l %{ /* Ejemplo para una pequeña calculadora que permite trabajar con numeros enteros y reales con las operaciones básicas de suma, resta, producto, division y trigonometricas como el seno y el coseno */ #include <stdio.h> #include <stdlib.h> int nlines=0; %} DIGITO [0-9] ID [a-zA-Z][a-zA-Z0-9_]* %% {DIGITO}+ {printf("Encontrado TKN_NUM_ENTERO: %d",atoi(yytext));} {DIGITO}+"."{DIGITO}+ {printf("Encontrado TKN_NUM_REAL: %f",atof(yytext));} "=" {printf("Encontrado TKN_ASIGN: %s",yytext);} ";" {printf("Encontrado TKN_PTOCOMA: %s",yytext);} "*" {printf("Encontrado TKN_MULT: %s",yytext);}
  • 16. "/" {printf("Encontrado TKN_DIV: %s",yytext);} "+" {printf("Encontrado TKN_MAS: %s",yytext);} "-" {printf("Encontrado TKN_MENOS: %s",yytext);} "(" {printf("Encontrado TKN_PAA: %s",yytext);} ")" {printf("Encontrado TKN_PAC: %s",yytext);} "cos" {printf("Encontrado TKN_COS: %s",yytext);} "sen" {printf("Encontrado TKN_SEN: %s",yytext);} {ID} {printf("Encontrado TKN_ID: %s",yytext);} "n" {nlines++;} %% void main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else yyin=stdin; yylex(); printf("nNumero lineas analizadas: %dn", nlines); } /* para compilar flex lexico.l cc lex.yy.c -o milex -lfl -lm */ Fichero léxico.l (versión a enlazar con Bison) %{ /* Ejemplo para una pequeña calculadora que permite trabajar con las operaciones básicas de suma, resta, producto, division y trigonometricas como el seno y el coseno */ #include <stdio.h>
  • 17. #include <stdlib.h> #include "sintactico.tab.h" int nlines=0; %} DIGITO [0-9] ID [a-zA-Z][a-zA-Z0-9_]* %% {DIGITO}+("."{DIGITO}+)? {//printf("Encontrado TKN_NUM: %fn",atof(yytext)); yylval.real=atof(yytext); return(TKN_NUM);} "=" {//printf("Encontrado TKN_ASIGN: %sn",yytext); return(TKN_ASIGN);} ";" {//printf("Encontrado TKN_PTOCOMA: %sn",yytext); return(TKN_PTOCOMA);} "*" {//printf("Encontrado TKN_MULT: %sn",yytext); return(TKN_MULT);} "/" {//printf("Encontrado TKN_DIV: %sn",yytext); return(TKN_DIV);} "+" {//printf("Encontrado TKN_MAS: %sn",yytext); return(TKN_MAS);} "-" {//printf("Encontrado TKN_MENOS: %sn",yytext); return(TKN_MENOS);} "(" {//printf("Encontrado TKN_PAA: %sn",yytext); return(TKN_PAA);} ")" {//printf("Encontrado TKN_PAC: %sn",yytext); return(TKN_PAC);} "cos" {//printf("Encontrado TKN_COS: %sn",yytext); return(TKN_COS);} "sen" {//printf("Encontrado TKN_SEN: %sn",yytext);
  • 18. return(TKN_SEN);} {ID} {//printf("Encontrado TKN_ID: %sn",yytext); return(TKN_ID);} "n" {nlines++;} . %% /******** Para el lexico solo void main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else yyin=stdin; yylex(); printf("nNumero lineas analizadas: %dn", nlines); } *******/ /* para compilar flex lexico.l cc lex.yy.c -o milex -lfl -lm */ Fichero sintactico.y (Bison) %{ /* Ejemplo para una pequeña calculadora que permite trabajar con numeros enteros y reales con las operaciones básicas de suma, resta, producto, division y trigonometricas como el seno y el coseno */ #include <stdio.h> #include <stdlib.h>
  • 19. #include <math.h> extern int yylex(void); extern char *yytext; extern int nlines; extern FILE *yyin; void yyerror(char *s); %} %union { float real; } %start Calculadora %token <real> TKN_NUM %token TKN_ASIGN %token TKN_PTOCOMA %token TKN_MULT %token TKN_DIV %token TKN_MAS %token TKN_MENOS %token TKN_PAA %token TKN_PAC else yyin=stdin; yyparse(); printf("FIN del Analisis. Entrada CORRECTAn"); printf("Numero lineas analizadas: %dn", nlines); return 0; } /* para compilar
  • 20. bison -d sintactico.y flex lexico.l cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm */