next up previous contents
Next: Desenvolvimento de uma aplicação Up: Geradores de analisadores sintáticos Previous: Especificação da gramática   Sumário

Manipulação das sentenças reconhecidas

Reconhecer que uma seqüência de símbolos é uma sentença válida em uma gramática é parte essencial do processo de compilação, porém pouco uso teria se simplesmente uma indicação de validade fosse retornada sem nenhuma possibilidade de manipulação adicional das expressões. No caso de yacc, essa possibilidade está associada à definição de ações semânticas.

Uma ação semântica em yacc é definida através de um bloco de expressões em C associado à definição de produções para um símbolo não-terminal:

  symb  :  expansão    { ação }  ;

A definição do corpo da ação pode conter referências aos valores semânticos de cada um dos símbolos da produção. O valor semântico de um token está associado a um valor associado ao símbolo, que pode ser por exemplo um valor numérico de uma constante ou a string associada a um identificador.

O valor semântico do token pode ser referenciado na expressão C através de pseudo-variáveis com nome $$ i$, onde $ i$ determina a posição do token na expansão. A variável $$ referencia o valor semântico resultante para o símbolo sendo definido. Por exemplo,

  expr  :  expr '+' expr
           { $$ = $1 + $3 }
        ;
atribui à expressão reduzida o valor semântico que é a soma dos valores semânticos do primeiro e do terceiro componentes da expansão, que estão separados pelo segundo componente, '+'.

Se nenhuma ação for definida para uma produção, a ação semântica padrão -- { $$ = $1; } é assumida.

O tipo associado a valores semânticos é definido pela macro YYSTYPE, que é inicialmente definida como int. Para modificar esse padrão, pode-se modificar essa definição através de uma declaração C na primeira seção do arquivo que define a gramática, como por exemplo

  %{
   #define  YYSTYPE  double
  %}

Em aplicações que necessitem manipular tokens com diferentes tipos de valores semânticos, a declaração union deve ser utilizada para definir quais são os tipos de valores possíveis. Por exemplo, em uma aplicação que manipula valores inteiros e reais a seguinte declaração estaria presente:

  %union {
     int    ival;
     double fval;
  }
Essa declaração determina que a coleção de tipos de valores permitidos é composta por valores com nome ival ou fval, respectivamente para valores inteiros e reais -- no código C, uma união (ver Seção C.2.4) será criada. Esses mesmos nomes são utilizados para qualificar a definição de tokens da gramática, como em
  %token <ival>  INTEGER
  %token <fval>  REAL

Quando uma coleção de tipos de valores é utilizada, é preciso determinar também qual o tipo para o símbolo não-terminal para o qual a expressão está sendo reduzida. Para esse fim, yacc define a declaração type:

  %type <fval> expr


next up previous contents
Next: Desenvolvimento de uma aplicação Up: Geradores de analisadores sintáticos Previous: Especificação da gramática   Sumário
Ivan L. M. Ricarte 2003-02-14