Академический Документы
Профессиональный Документы
Культура Документы
Teora de Compiladores
RESUMEN
INTRODUCCION
En 1946 se desarroll el primer ordenador digital. Pronto los primeros usuarios de estos
ordenadores descubrieron la ventaja de escribir sus programas mediante claves ms
fciles de recordar que esos cdigos numricos; al final, todas esas claves juntas se
traducan manualmente a Lenguaje Mquina. Estas claves constituyen los llamados
lenguajes ensambladores, que se generalizaron en cuanto se dio el paso decisivo de
hacer que las propias mquinas realizaran el proceso mecnico de la traduccin. A este
trabajo se le llama ensamblar el programa.
En el caso particular de que el lenguaje a traducir es un lenguaje de alto nivel y el
lenguaje traducido de bajo nivel, se emplea el trmino compilador.
La tarea de realizar un compilador no fue fcil. El primer compilador de FORTRAN tard
18 aos-persona en realizarse y era muy sencillo. Este desarrollo del FORTRAN estaba
muy influenciado por la mquina objeto en la que iba a ser implementado. Como un
ejemplo de ello tenemos el hecho de que los espacios en blanco fuesen ignorados, debido
a que el perifrico que se utilizaba como entrada de programas (una lectora de tarjetas
perforadas) no contaba correctamente los espacios en blanco.
Paralelamente al desarrollo de FORTRAN en Amrica, en Europa surgi una corriente
ms universitaria, que pretenda que la definicin de un lenguaje fuese independiente de
la mquina y en donde los algoritmos se pudieran expresar de forma ms simple.
En 1969, el lenguaje fue revisado y llev a una nueva versin que se llam ALGOL 60.
Junto a este desarrollo en los lenguajes, tambin se iba avanzando en la tcnica de
compilacin. En 1958, Strong y otros proponan una solucin al problema de que un
compilador fuera utilizable por varias mquinas objeto.
En 1975, con la aparicin de LEX surge el concepto de un generador automtico de
analizadores lxicos a partir de expresiones regulares, basado en el sistema operativo
UNIX. A partir de los trabajos de Chomsky ya citados, se produce una sistematizacin de
la sintaxis de los lenguajes de programacin, y con ello un desarrollo de diversos mtodos
de anlisis sintctico.
A mitad de la dcada de los 60, Knuth define las gramticas LR y describe la construccin
de una tabla cannica de parser LR. Por otra parte, el uso por primera vez de un parsing
descendente recursivo tuvo lugar en el ao 1961. En el ao 1968 se estudian y definen
las gramticas LL as como los parsers predictivos.
En los primeros lenguajes (FORTRAN y ALGOL 60) los tipos posibles de los datos eran
muy simples, y la comprobacin de tipos era muy sencilla.
En la actualidad, el proceso de la compilacin ya est muy asentado. Un compilador es
una herramienta bien conocida, dividida en diversas fases. Algunas de estas fases se
pueden generar automticamente (analizador lxico y sintctico) y otras requieren una
mayor atencin por parte del escritor de compiladores (las partes de traduccin y
generacin de cdigo).
De todas formas, y en contra de lo que quiz pueda pensarse, todava se estn llevando a
cabo varias vas de investigacin en este fascinante campo de la compilacin.
MARCO TEORICO
1. COMPILADOR
Tambin llamado traductor, es cualquier programa que toma como entrada un texto escrito
en un lenguaje, llamado fuente y da como salida otro texto en un lenguaje, denominado
objeto.
En el caso de que el lenguaje fuente sea un lenguaje de programacin de alto nivel y el
objeto sea un lenguaje de bajo nivel (ensamblador o cdigo de mquina), a dicho
traductor se le denomina compilador.
La mejor informacin sobre los errores por parte del compilador as como una mayor
velocidad de ejecucin del cdigo resultante hizo que poco a poco se impusieran los
compiladores.
Hoy en da, y con el problema de la memoria prcticamente resuelto, se puede hablar de
un gran predominio de los compiladores frente a los intrpretes, aunque intrpretes como
los incluidos en los navegadores de Internet para interpretar el cdigo JVM de Java son la
gran excepcin.
Un compilador no es un programa que funciona de manera aislada, sino que necesita de
otros programas para conseguir su objetivo.
1.1)
PARTES DE UN COMPILADOR
Alternativamente, las fases descritas para las tareas de anlisis y sntesis se pueden
agrupar en Front-end y Back-end:
Esta divisin permite que el mismo Back End se utilice para generar el cdigo mquina de
varios lenguajes de programacin distintos y que el mismo Front End que sirve para
analizar el cdigo fuente de un lenguaje de programacin concreto sirva para generar
cdigo mquina en varias plataformas distintas. Suele incluir la generacin y optimizacin
del cdigo dependiente de la mquina.
El cdigo que genera el Back End normalmente no se puede ejecutar directamente, sino
que necesita ser enlazado por un programa enlazador (linker)
2. INTERPRETES VS COMPILADORES
3. TIPOS DE COMPILADORES
4. ESTRUCTURA DE UN COMPILADOR
5. ANALISIS LXICO
Lee caracteres uno a uno y forma grupos de caracteres con alguna relacin entre
s (tokens).
Cada token es una secuencia de caracteres tratados como una unica entidad.
6. ANALISIS SINTCTICO
7. ANALISIS SEMNTICO
Comprueba que lo que el significado de lo que se va leyendo es vlido.
8. GESTION DE ERRORES
Se utiliza en todas las fases, pero especialmente en las de anlisis sintctico y semntico.
Es una tarea difcil:
Un error puede ocultar otros.
Un error puede provocar una avalancha de otros.
Importante tener un buen manejo de errores:
Que detecte todos los errores.
Que no deje de compilar al detectar el primer error.
FASE DE ANALISIS
9.2)
FASE DE SINTESIS
Esta fase se lleva a cabo una vez que el mdulo de anlisis ha verificado que el cdigo
fuente es correcto.
La informacin recogida en el mdulo de anlisis y almacenada en la tabla de smbolos
se emplea en la fase de sntesis para la generacin del cdigo objeto.
Abarca la generacin de cdigo intermedio, y en el caso de los compiladores, la
generacin de cdigo y la optimizacin del mismo.
9.3)
AGRUPAMIENTO DE FASES
Front-end: depende del lenguaje fuente, independiente del lenguaje objeto.
Back-end: depende del lenguaje objeto y es independiente del lenguaje fuente.
12. JFLEX
JFLEX es un generador de analizador lxico para java1 escrito en Java, fue desarrollado
por Elliot Berk Universidad de Princeton. Generador de programas java diseado para
procesamiento lxico, Parte de un conjunto de reglas lxicas. JFlex produce un programa
llamado Yylex que reconoce las cadenas que cumplen dichas reglas.
a | b Unin
a b Concatenacin
a* Repeticin 0 o N veces
a+ Repeticin 1 o N veces (= a a*)
a? Opcionalidad
!a Negacin
~a Cualquier cosa que termine
"+" |
"-" |
"*" |
"/" |
"^" |
"(" |
")" { return (int) yycharat(0); }
/* newline */
{NL} { return Parser.NL; }
/* float */
{NUM} { yyparser.yylval = new ParserVal(Double.parseDouble(yytext()));
return Parser.NUM; }
/* whitespace */
[ \t]+ { }
\b
/* error fallback */
[^] { System.err.println("Error: unexpected character '"+yytext()+"'"); return -1; }
Calcy.y
%{
import java.io.*;
%}
%token NL
/* newline */
%token <dval> NUM /* a number */
%type <dval> exp
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
/* negation--unary minus */
/* exponentiation
*/
%%
input: /* empty string */
| input line
;
line:
NL
{ if (interactive) System.out.print("Ingrese su operacin: "); }
| exp NL { x=$1 + "";
if(x.equals("Infinity"))System.out.println(" Indeterminado ");
else System.out.println(" = " + x );
if (interactive) System.out.print("Ingrese su operacin: "); }
;
exp:
NUM
{ $$ = $1; }
| exp '+' exp
{ $$ = $1 + $3; }
| exp '-' exp
{ $$ = $1 - $3; }
| exp '*' exp
{ $$ = $1 * $3; }
| exp '/' exp
{ $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp
{ $$ = Math.pow($1, $3); }
| '(' exp ')'
{ $$ = $2; }
;
%%
private Yylex lexer;
String x;
private int yylex () {
int yyl_return = -1;
try {
yylval = new ParserVal(0);
yyl_return = lexer.yylex();
}
catch (IOException e) {
System.err.println("IO error :"+e);
}
return yyl_return;
}
public void yyerror (String error) {
System.err.println ("Error: " + error);
}
public void yyerrork (String error) throws Exception {
System.err.println ("Error: " + error);
throw new Exception("Error Exception");
}
public Parser(Reader r) {
lexer = new Yylex(r, this);
}
static boolean interactive;
public static void main(String args[]) throws IOException {
System.out.println("BYACC/Java with JFlex Calculator Demo");
Parser yyparser;
if ( args.length > 0 ) {
// parse a file
yyparser = new Parser(new FileReader(args[0]));
}
else {
// interactive mode
//System.out.println("[Quit with CTRL-D]");
System.out.print("Ingrese su operacn: ");
interactive = true;
yyparser = new Parser(new InputStreamReader(System.in));
}
yyparser.yyparse();
if (interactive) {
System.out.println();
System.out.println("Ingrese una operacion!!!!!!");
}
}
Calculadora.Java
import java.io.*;
public class Parser
{
boolean yydebug;
//do I want debug output?
int yynerrs;
//number of errors so far
int yyerrflag;
//was there an error?
int yychar;
//the current working character
void debug(String msg)
{
if (yydebug)
System.out.println(msg);
}
final static int YYSTACKSIZE = 500; //maximum stack size
int statestk[] = new int[YYSTACKSIZE]; //state stack
int stateptr;
int stateptrmax;
//highest index of stackptr
int statemax;
//state when highest index reached
final void state_push(int state)
{
try {
stateptr++;
statestk[stateptr]=state;
}
catch (ArrayIndexOutOfBoundsException e) {
int oldsize = statestk.length;
int newsize = oldsize * 2;
int[] newstack = new int[newsize];
System.arraycopy(statestk,0,newstack,0,oldsize);
statestk = newstack;
statestk[stateptr]=state;
}
}
final int state_pop()
{
return statestk[stateptr--];
}
final void state_drop(int cnt)
{
stateptr -= cnt;
}
final int state_peek(int relative)
{
return statestk[stateptr-relative];
}
final boolean init_stacks()
{
stateptr = -1;
val_init();
return true;
}
void dump_stacks(int count)
{
int i;
System.out.println("=index==state====value= s:"+stateptr+" v:"+valptr);
for (i=0;i<count;i++)
System.out.println(" "+i+" "+statestk[i]+"
"+valstk[i]);
System.out.println("======================");
}
String yytext;//user variable to return contextual strings
ParserVal yyval; //used to return semantic vals from action routines
ParserVal yylval;//the 'lval' (result) I got from yylex()
ParserVal valstk[];
int valptr;
void val_init()
{
valstk=new ParserVal[YYSTACKSIZE];
yyval=new ParserVal();
yylval=new ParserVal();
valptr=-1;
}
void val_push(ParserVal val)
{
if (valptr>=YYSTACKSIZE)
return;
valstk[++valptr]=val;
}
ParserVal val_pop()
{
if (valptr<0)
return new ParserVal();
return valstk[valptr--];
}
void val_drop(int cnt)
{
int ptr;
ptr=valptr-cnt;
if (ptr<0)
return;
valptr = ptr;
}
ParserVal val_peek(int relative)
{
int ptr;
ptr=valptr-relative;
if (ptr<0)
return new ParserVal();
return valstk[ptr];
}
//#### end semantic value section ####
public final static short NL=257;
public final static short NUM=258;
public final static short NEG=259;
public final static short YYERRCODE=256;
final static short yylhs[] = {
-1,
0, 0, 2, 2, 1, 1, 1, 1, 1, 1,
1, 1,
};
final static short yylen[] = {
2,
0, 2, 1, 2, 1, 3, 3, 3, 3, 2,
3, 3,
};
final static short yydefred[] = {
1,
0, 3, 5, 0, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0, 0, 12, 0, 0, 0,
0,};
final static short yydgoto[] = {
1, 6, 7,};
final static short yysindex[] = {
0, -40, 0, 0, -39, -39, -1, 0, -92,
0,
-39, -39, -39, -39, -39, 0, -30, -30, -92, -92, -92,};
final static short yyrindex[] = {
0, 0, 0, 0, 0, 0, 0, 0, -34,
0,
0, 0, 0, 0, 0, 0, -10, -5, -27, -20, -13,};
final static short yygindex[] = {
0, 54, 0,};
0,
6,
0,
,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"'('","')'","'*'","'+'"
,null,"'-'",null,"'/'",null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"'^'",null,null,null
,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nul
l,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null
,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nul
l,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null
,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nul
l,null,null,null,null,null,null,null,null,null,null,"NL","NUM","NEG",
};
final static String yyrule[] = {
"$accept : input",
"input :",
"input : input line",
"line : NL",
"line : exp NL",
"exp : NUM",
"exp : exp '+' exp",
"exp : exp '-' exp",
"exp : exp '*' exp",
"exp : exp '/' exp",
"exp : '-' exp",
"exp : exp '^' exp",
"exp : '(' exp ')'",
};
//#line 65 "calcy.y"
private Yylex lexer;
String x;
private int yylex () {
int yyl_return = -1;
try {
yylval = new ParserVal(0);
yyl_return = lexer.yylex();
}
catch (IOException e) {
System.err.println("IO error :"+e);
}
return yyl_return;
}
public void yyerror (String error) {
System.err.println ("Error: " + error);
}
public void yyerrork (String error) throws Exception {
System.err.println ("Error: " + error);
String yys;
int yyparse()
{
boolean doaction;
init_stacks();
yynerrs = 0;
yyerrflag = 0;
yychar = -1;
//impossible char forces a read
yystate=0;
//initial state
state_push(yystate); //save it
val_push(yylval); //save empty value
while (true) //until parsing is done, either correctly, or w/error
{
doaction=true;
if (yydebug) debug("loop");
//#### NEXT ACTION (from reduction table)
for (yyn=yydefred[yystate];yyn==0;yyn=yydefred[yystate])
{
if (yydebug) debug("yyn:"+yyn+" state:"+yystate+" yychar:"+yychar);
if (yychar < 0)
//we want a char?
{
yychar = yylex(); //get next token
if (yydebug) debug(" next yychar:"+yychar);
//#### ERROR CHECK ####
if (yychar < 0) //it it didn't work/error
{
yychar = 0;
//change it to default string (no -1!)
if (yydebug)
yylexdebug(yystate,yychar);
}
}//yychar<0
yyn = yysindex[yystate]; //get amount to shift by (shift index)
if ((yyn != 0) && (yyn += yychar) >= 0 &&
yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
{
if (yydebug)
debug("state "+yystate+", shifting to state "+yytable[yyn]);
//#### NEXT STATE ####
yystate = yytable[yyn];//we are in a new state
state_push(yystate); //save it
val_push(yylval);
//push our lval as the input for next rule
yychar = -1;
//since we have 'eaten' a token, say we need another
if (yyerrflag > 0) //have we recovered an error?
--yyerrflag;
//give ourselves credit
doaction=false;
//but don't process yet
break; //quit the yyn=0 loop
}
yyn = yyrindex[yystate]; //reduce
if ((yyn !=0 ) && (yyn += yychar) >= 0 &&
else
//discard this token
{
if (yychar == 0)
return 1; //yyabort
if (yydebug)
{
yys = null;
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
if (yys == null) yys = "illegal-symbol";
debug("state "+yystate+", error recovery discards token "+yychar+" ("+yys+")");
}
yychar = -1; //read another
}
}//end error recovery
}//yyn=0 loop
if (!doaction) //any reason not to proceed?
continue;
//skip action
yym = yylen[yyn];
//get count of terminals on rhs
if (yydebug)
debug("state "+yystate+", reducing "+yym+" by rule "+yyn+" ("+yyrule[yyn]+")");
if (yym>0)
//if count of rhs not 'nil'
yyval = val_peek(yym-1); //get current semantic value
switch(yyn)
{
//########## USER-SUPPLIED ACTIONS ##########
case 3:
//#line 46 "calcy.y"
{ if (interactive) System.out.print("Ingrese su operacin: "); }
break;
case 4:
//#line 47 "calcy.y"
{ x=val_peek(1).dval + "";
if(x.equals("Infinity"))System.out.println(" Indeterminado ");
else System.out.println("El resultado es: = " + x );
if (interactive) System.out.print("Ingrese su operacion: "); }
break;
case 5:
//#line 54 "calcy.y"
{ yyval.dval = val_peek(0).dval; }
break;
case 6:
//#line 55 "calcy.y"
{ yyval.dval = val_peek(2).dval + val_peek(0).dval; }
break;
case 7:
//#line 56 "calcy.y"
{ yyval.dval = val_peek(2).dval - val_peek(0).dval; }
break;
case 8:
//#line 57 "calcy.y"
{ yyval.dval = val_peek(2).dval * val_peek(0).dval; }
break;
case 9:
//#line 58 "calcy.y"
{ yyval.dval = val_peek(2).dval / val_peek(0).dval; }
break;
case 10:
//#line 59 "calcy.y"
{ yyval.dval = -val_peek(0).dval; }
break;
case 11:
//#line 60 "calcy.y"
{ yyval.dval = Math.pow(val_peek(2).dval, val_peek(0).dval); }
break;
case 12:
//#line 61 "calcy.y"
{ yyval.dval = val_peek(1).dval; }
break;
//#line 473 "Parser.java"
//########## END OF USER-SUPPLIED ACTIONS ##########
}//switch
//#### Now let's reduce... ####
if (yydebug) debug("reduce");
state_drop(yym);
//we just reduced yylen states
yystate = state_peek(0); //get new state
val_drop(yym);
//corresponding value drop
yym = yylhs[yyn];
//select next TERMINAL(on lhs)
if (yystate == 0 && yym == 0)//done? 'rest' state and at first TERMINAL
{
if (yydebug) debug("After reduction, shifting from state 0 to state "+YYFINAL+"");
yystate = YYFINAL;
//explicitly say we're done
state_push(YYFINAL);
//and save it
val_push(yyval);
//also save the semantic value of parsing
if (yychar < 0)
//we want another character?
{
yychar = yylex();
//get next character
if (yychar<0) yychar=0; //clean, if necessary
if (yydebug)
yylexdebug(yystate,yychar);
}
if (yychar == 0)
//Good exit (if lex returns 0 ;-)
break;
//quit the loop--all DONE
}//if yystate
else
//else not done yet
{
//get next state and push, for next yydefred[]
yyn = yygindex[yym];
//find out where to go
if ((yyn != 0) && (yyn += yystate) >= 0 &&
yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
yystate = yytable[yyn]; //get new state
else
yystate = yydgoto[yym]; //else go to new defred
CONCLUSIONES
Este trabajo nos ayudo a comprender como es la creacin de un compilador, ya que en l
se detallan todas y cada una de las partes que involucran a este.
REFERENCIAS
http://www.cc.uah.es/ie/docencia/ProcesadoresDeLenguaje/ProcesadoresDeLengu
ajeTema1_3xpagina.pdf
http://www.iua.upf.es/~rramirez/PL2/L02comp.pdf
http://www.willydev.net/descargas/prev/Compila.pdf
http://www.escet.urjc.es/~procesal/transp/Tema2-AnalizadorLexico-JFlex.pdf