 
 
 
 
 
 
 
 
 
 










 
yapp asegurese
de seguir los siguientes consejos:
Z a una variable que representa el concepto ``lista de parámetros'',
llámela ListaDeParametros.
%token. De esta manera
el lector de su programa se dará cuenta rápidamente que dichos identificadores
no se corresponden con variables sintácticas. Por la misma razón,
si se trata de terminales
asociados con caracteres o cadenas no es tan necesario que los declare, 
a menos que, 
como en el ejemplo de la calculadora para '+' y '*',
sea necesario asociarles una
precedencia.
-v para producir
el fichero .output conteniendo información detallada sobre
los conflictos y el autómata. Cuando haya un conflicto shift-reduce
no resuelto busque en el fichero el estado implicado y 
vea que LR(0) items 
 y
y 
 entran en conflicto.
 entran en conflicto.
yapp
el conflicto se produce ante un terminal  ,
es porque
,
es porque 
 y
 y
 . Busque las causas por las que esto ocurre 
y modifique su gramática con vistas a eliminar la presencia
del terminal
. Busque las causas por las que esto ocurre 
y modifique su gramática con vistas a eliminar la presencia
del terminal  en uno de los dos conjuntos implicados
o bien establezca reglas de prioridad entre los terminales
implicados que resuelvan el conflicto.
 en uno de los dos conjuntos implicados
o bien establezca reglas de prioridad entre los terminales
implicados que resuelvan el conflicto.
 y
 
y  
 , el programa
, el programa
yapp contabiliza un error por cada terminal 
 . Por esta razón,
si hay 16 elementos en
. Por esta razón,
si hay 16 elementos en 
 ,
el analizador
,
el analizador yapp informará de la existencia
de 16 conflictos shift-reduce,
cuando en realidad se trata de uno sólo. No desespere, 
los conflictos ``auténticos'' suelen
ser menos de los que yapp anuncia.
%{ y %}. Estos delimitadores
deberán aparecer en una línea aparte. Por ejemplo:
%{
our contador = 0;
%}
%token NUM
...
%%
yydebug => 0x1F en la llamada al analizador.
yapp 
pasará a rechazar una gramatica aparentemente correcta.
yapp: Cada vez que 
el analizador sintáctico necesita un nuevo terminal para decidir que regla de
producción se aplica, llama al analizador léxico, el cuál deberá retornar el siguiente
terminal. La estrategia es diferente de la utilizada en el ejemplo
usado para el lenguaje Tutu en el capítulo 
4. Allí generabamos en una primera fase
la lista de terminales. Aquí los terminales se generan  de uno en uno
y cada vez que se encuentra uno nuevo se retorna al analizador sintáctico.
La ventaja que tiene este método es que permite colaborar al analizador sintáctico
y al analizador léxico para ``dinámicamente'' modificar la conducta 
del análisis léxico. Por ejemplo en los compiladores del lenguaje C
es común hacer que el analizador léxico cuando descubre un identificador que 
previamente ha sido declarado como identificador de tipo (mediante 
el uso de typedef) retorne un terminal TYPENAME 
diferente del terminal ID
que caracteriza a los identificadores. Para ello, el analizador
sintáctico, cuando detecta una tal declaración, ``avisa'' al analizador 
léxico para que modifique su conducta. El analizador sintáctico volverá
a avisarlo cuando la declaración del identificador como
identificador de tipo salga de ámbito y pierda
su especial condición.  
yapp el analizador sintáctico espera que el analizador
léxico devuelva de cada vez una pareja formada por dos escalares.
El primer escalar es la cadena que designa el terminal. A diferencia
de la habitual costumbre yacc de codificar los terminales
como enteros, en yapp se suelen codificar como cadenas.
La segunda componente de la pareja es el atributo asociado con el terminal.
Si el atributo es un atributo complejo que necesitas representar
mediante un hash o un vector, lo mejor es hacer que esta componente
sea una referencia al objeto describiendo el atributo.
El analizador léxico le indica al sintáctico la
finalización de la entrada enviándole la pareja 
('',undef) formada por la palabra vacía con atributo undef.
s
(véase el ejemplo de la sección 
7.1), en cuyo caso la entrada procesada
es retirada de la cadena leída.
En los no destructivos utilizamos el operador
de emparejamiento m. Véase 
el ejemplo de analizador léxico en
la sección 8.28
(concretamente la subrutina scanner en la 
línea 20 del fichero useinherited.pl)
yapp para producir
árboles para las expresiones en infijo. Supongamos que olvidamos
introducir una prioridad explícita al terminal '=':
$ cat -n Infixtree_conflict.yp
 1  #
 2  # Infixtree.yp
 3  #
 4
 5  %{
 6  use Data::Dumper;
 7  %}
 8  %left   '-' '+'
 9  %left   '*' '/'
10  %left   NEG
11
12  %%
13  input:  #empty
14          |   input line
15  ;
16
17  line:     '\n'         { $_[1] }
18          | exp '\n'     { print Dumper($_[1]); }
19          | error '\n'   { $_[0]->YYErrok }
20  ;
21
22  exp:        NUM
23          |   VAR                 { $_[1] }
24          |   VAR '=' exp         { bless [$_[1], $_[3]], 'ASSIGN' }
25          |   exp '+' exp         { bless [$_[1], $_[3] ], 'PLUS'}
26          |   exp '-' exp         { bless [$_[1], $_[3] ], 'MINUS'}
27          |   exp '*' exp         { bless [$_[1], $_[3]], 'TIMES' }
28          |   exp '/' exp         { bless [$_[1], $_[3]], 'DIVIDE' }
   ....
en este caso al compilar encontraremos conflictos:
$ yapp -v -m Infixtree Infixtree_conflict.yp 4 shift/reduce conflictsEn tal caso lo que debemos hacer es editar el fichero
.output.
El comienzo del fichero es como sigue:
$ cat -n Infixtree_conflict.output 1 Warnings: 2 --------- 3 4 shift/reduce conflicts 4 5 Conflicts: 6 ---------- 7 Conflict in state 11 between rule 13 and token '-' resolved as reduce. 8 Conflict in state 11 between rule 13 and token '*' resolved as reduce. ...Tal y como indica la expresión ...
resolved as ...,
las líneas como la 7, la 8 y siguientes se refieren a conflictos resueltos.
Mas abajo encontraremos información sobre 
la causa de nuestros conflictos no resueltos:
    ...
26  Conflict in state 23 between rule 11 and token '/' resolved as reduce.
27  State 25 contains 4 shift/reduce conflicts
Lo que nos informa que los conflictos 
ocurren en el estado 25 ante 4 terminales
distintos. Nos vamos a la parte del fichero 
en la que aparece la información relativa al estado 25. Para ello,
como el fichero es grande, buscamos por la cadena adecuada.
En vi buscaríamos por /^State 25. Las líneas
correspondientes contienen:
291 State 25: 292 293 exp -> VAR '=' exp . (Rule 8) 294 exp -> exp . '+' exp (Rule 9) 295 exp -> exp . '-' exp (Rule 10) 296 exp -> exp . '*' exp (Rule 11) 297 exp -> exp . '/' exp (Rule 12) 298 299 '*' shift, and go to state 16 300 '+' shift, and go to state 13 301 '-' shift, and go to state 12 302 '/' shift, and go to state 15 303 304 '*' [reduce using rule 8 (exp)] 305 '+' [reduce using rule 8 (exp)] 306 '-' [reduce using rule 8 (exp)] 307 '/' [reduce using rule 8 (exp)] 308 $default reduce using rule 8 (exp)El comentario en la línea 308 (
$default ...)
indica que por defecto, ante cualquier
otro terminal que no sea uno de los explícitamente listados, 
la acción a tomar por el analizador será reducir por la regla 8.
Una revisión a la numeración de la gramática, al comienzo
del fichero .output nos permite ver cuál
es la regla 8:
29 Rules:
30 ------
31 0:  $start -> input $end
32 1:  input -> /* empty */
33 2:  input -> input line
34 3:  line -> '\n'
35 4:  line -> exp '\n'
36 5:  line -> error '\n'
37 6:  exp -> NUM
38 7:  exp -> VAR
39 8:  exp -> VAR '=' exp
40 9:  exp -> exp '+' exp
41 10: exp -> exp '-' exp
42 11: exp -> exp '*' exp
43 12: exp -> exp '/' exp
44 13: exp -> '-' exp
45 14: exp -> '(' exp ')'
Efectivamente, es la regla de asignación exp -> VAR '=' exp.
El conflicto aparece por que los terminales 
* + - / están en el conjunto FOLLOW(exp)
y también cabe esperarlos respectivamente 
en las reglas 9, 10, 11 y 12 ya que el estado 
25 contiene:
294 exp -> exp . '+' exp (Rule 9) 295 exp -> exp . '-' exp (Rule 10) 296 exp -> exp . '*' exp (Rule 11) 297 exp -> exp . '/' exp (Rule 12)
Estamos ante un caso en el que se aplica el consejo número
8.
Los items de la forma
 , son los
de la forma
, son los
de la forma exp -> exp . '+' exp, etc.
El item de la forma 
 es en este caso
 
es en este caso exp -> VAR '=' exp.
En efecto, en una expresión como a = 4 + 3 se produce
una ambiguedad. ¿Debe interpretarse como (a = 4) + 3?
¿O bien como a = (4 + 3)?. La primera interpretación
corresponde a reducir por la regla 8. La segunda a desplazar al
estado 13.  En este ejemplo, el conflicto
se resuelve haciendo que tenga prioridad el desplazamiento,
dando menor prioridad al terminal = que a los 
terminales * + - /.
yapp aplique 
las reglas por defecto?
 
 
 
 
 
 
 
 
 
 










