760 likes | 933 Views
TRADUCTOR EDT CON ANTLR. EDT: Gramática proporcionada. Vamos a realizar un traductor EDT para la siguiente gramática:. EDT: Gramática proporcionada. a ::= e ; a | λ e ::= t e1 e1 ::= OPSUMA t e1 | OPRESTA t e1 | λ t ::= f t1 t1 ::= OPMULT f t1 | OPDIV f t1 | λ
E N D
EDT: Gramática proporcionada • Vamos a realizar un traductor EDT para la siguiente gramática:
EDT: Gramática proporcionada • a ::= e ; a | λ • e ::= t e1 • e1 ::= OPSUMA t e1 | OPRESTA t e1 | λ • t ::= f t1 • t1 ::= OPMULT f t1 | OPDIV f t1 | λ • f ::= '(' e ')' | NUMERO • Esta gramática permite reconocer expresiones aritméticas, cuyo resultado es de tipo numérico.
EDT: Gramática proporcionada • Como podemos observar en la gramática, todos los operadores tienen una asociatividad a izquierdas y que los factores poseen mayor preferencia que los términos. • La complejidad de esta gramática radica en el problema en que los dos operandos de todas las expresiones binarias se encuentran en producciones distintas.
EDT: Primera aproximación • Dada la gramática proporcionada, voy a realizar una gramática atribuida que permite reconocer expresiones aritméticas y dar su valor.
EDT: Primera aproximación • a ::= e ; a | λ
EDT: Primera aproximación • a ::= e {imprime (e.valor);} ; a | λ En el axioma simplemente imprimimos el valor de e (expresión).
EDT: Primera aproximación e ::= t {e1.operando1 = t.valor;} e1 {e.valor = e1.valor;} e1 tiene un atributo heredado que es operando1 y que adquiere el valor que tenga el término, para transmitir ese valor a los hijos del árbol. Tenemos que añadir la acción semántica {e.valor = e1.valor} para que el resultado de evaluar e1 se asigne al valor de e.
EDT: Primera aproximación • e1´ ::= OPSUMA t {e1´´.operando1 = e1´.operando1 + t.valor;} e1´´ {e1´.valor = e1´´.valor;} | OPRESTA t e1 | λ El operando 1 de e1´´ es el valor del operando1 que ha sido heredado del padre más el valor de t que ha sido reconocido en ese momento. Finalmente se le asigna a e1´ el valor de haber evaluado e1´´.
EDT: Primera aproximación • e1´ ::= OPSUMA t {e1´´.operando1 = e1´.operando1 + t.valor;} e1´´ {e1´.valor = e1´´.valor;} | OPRESTA t {e1´´.operando1 = e1´.operando1 + t.valor;} e1´´ {e1´.valor = e1´´.valor;} | λ Con la resta sucede igual que con la suma.
EDT: Primera aproximación • e1´ ::= OPSUMA t {e1´´.operando1 = e1´.operando1 + t.valor;} e1´´ {e1´.valor = e1´´.valor;} | OPRESTA t {e1´´.operando1 = e1´.operando1 + t.valor;} e1´´ {e1´.valor = e1´´.valor;} | λ{e1´.valor = e1´.operando1;} En el caso de la producción λ, como no tenemos otro término para sumarlo o restarlo, simplemente lo que hacemos es asignar al valor de e1, el valor del atributo heredado del padre (e1´.operando1).
EDT: Primera aproximación t ::= f {t1.operando1 = f.valor;} t1 {t.valor = t1.valor;} t1 tiene un atributo heredado que es operando1 y que adquiere el valor que tenga el factor, para transmitir ese valor a los hijos del árbol. Tenemos que añadir la acción semántica {t.valor=t1.valor} para que el resultado de evaluar t1 se asigne al valor de t.
EDT: Primera aproximación • t1´ ::= OPMULT t {t1´´.operando1 = t1´.operando1 * t.valor;} t1´´ {e1´.valor = e1´´.valor;} | OPDIV t e1 | λ El operando 1 de e1´´ es el valor del operando1 que ha sido heredado del padre más el valor de t que ha sido reconocido en ese momento. Finalmente se le asigna a e1´ el valor de haber evaluado e1´´.
EDT: Primera aproximación • t1´ ::= OPMULT t {t1´´.operando1 = t1´.operando1 * t.valor;} t1´´ {t1´.valor = t1´´.valor;} | OPDIV t {t1´´.operando1 = t1´.operando1 / t.valor;} t1´´ {t1´.valor = t1´´.valor;} | λ Con la división sucede igual que con la multiplicación.
EDT: Primera aproximación • t1´ ::= OPMULT t {t1´´.operando1 = t1´.operando1 * t.valor;} t1´´ {t1´.valor = t1´´.valor;} | OPDIV t {t1´´.operando1 = t1´.operando1 / t.valor;} t1´´ {t1´.valor = t1´´.valor;} | λ{t1´.valor = t1´.operando1;} En el caso de la producción λ, como no tenemos otro término para multiplicarlo o dividirlo, simplemente lo que hacemos es asignar al valor de t1, el valor del atributo heredado del padre (t1´.operando1).
ANTLR: Traductor EDT • Vamos a ver cómo se resuelve con ANTLR un traductor EDT para la gramática presentada. • Primeramente vamos a hacer el árbol de derivaciones para una determinada cadena de entrada, y sobre este árbol vamos a ir aplicando las acciones semánticas y viendo el valor de los atributos y el código asociado a ANTLR.
Código ANTLR • Al código ANTLR que resuelve la EDT es el siguiente: axioma: a; a : e SEMICOLON { System.out.println("\n\nReconocida expresion aritmetica. Valor final: " + $e.valExp); } a | ; /* Reglas expresiones aritméticas */ e returns [int valExp = 0]: t e1 [$t.val] {$valExp=$e1.val;};
Código ANTLR e1 [int op1] returns [int val = 0]: OPSUMA op2=t { int valor1 = op1; int valor2 = $op2.val; $val = valor1+valor2 ; } r=e1 [$val] {$val = $r.val;} | OPRESTA op2=t { int valor1 = op1; int valor2 = $op2.val; $val = valor1-valor2 ; } r=e1 [$val] {$val = $r.val;} | {$val = $op1;}; t returns [int val = 0]: f t1 [$f.valNum] {$val=$t1.valor;} ;
Código ANTLR t1 [int op1] returns [int valor = 0] : OPMULT op2=f { int valor1 = op1; int valor2 = $op2.valNum; $valor = valor1*valor2 ; } s=t1 [$valor] {$valor = $s.valor;} | OPDIV op2=f { int valor1 = op1; int valor2 = $op2.valNum; $valor = valor1/valor2 ; } s=t1 [$valor] {$valor = $s.valor;} | {$valor = $op1;};
Código ANTLR f returns [int valNum = 0]: | '(' e {$valNum = $e.valExp;} ')' | num=NUMERO {$valNum=Integer.parseInt($num.text);} ;
Árbol de derivaciones • Ahora vamos a hacer el árbol de derivaciones para la cadena: 345+(3*46-5)*2; El resultado de evaluar esta expresión aritmética nos tiene que dar 611.