Escolar Documentos
Profissional Documentos
Cultura Documentos
41
Especificação da gramática
O arquivo de entrada para o yacc, que por convenção recebe a extensão .y,
é estruturado em três seções. Como na definição de arquivos lex, essas três
seções –– definições, regras da gramática e código do usuário –– são
separadas pelos símbolos %%.
define que uma expressão entre parênteses (o lado direito do operador) pode
ser reduzido simplesmente a uma expressão (o símbolo não-terminal do lado
esquerdo).
<S> ::= A
<S> ::= B
equivale a
<S> ::=
<S> ::= a
que equivale a
<S> ::= a*
equivale a
<S> ::=
<S> ::= a<S>
|a|aa|aaa|aaaa|.....
43
equivale a
simb : exp ;
Porém, pelo menos uma expansão para esse símbolo deve ser não-
recursiva:
expr : IDENT ;
Expansões para a cadeia vazia podem ser definidas; por convenção e para
tornar mais clara a definição, essa expansão é destacada na forma de um
comentário C:
44
retv : /* empty */
| expr
;
%start expr
Tokens que são representados por um único caractere, como '+' ou ';', não
precisam ser declarados e podem ser usados dessa forma (como constantes
do tipo caractere em C) nas expansões; os demais tokens precisam ser
explicitamente declarados. Para tanto, a declaração token pode ser utilizada,
como em
%token IDENT
%left OP
%right OP
%nonassoc OP
Se nenhuma ação for definida para uma produção, a ação semântica padrão
-- { $$ = $1; } é assumida.
%{
#define YYSTYPE double
%}
%union {
int ival;
double fval;
}
Análise Semântica
In function 'f1':
...: invalid operands to binary %
a = x - '0';
int a;
int *p;
a expressão
a = p;
Porém, se o programador indicar que sabe que está fazendo uma conversão
"perigosa'' através do operador de molde,
a = (int) p;
c << x;
Outro exemplo de erro detectado pela análise semântica, neste caso pela
verificação de fluxo de controle, é ilustrado pelo código
In function 'f2':
...: break statement not within loop or switch
...: continue statement not within a loop
ou seja, ele reconhece que o comando break só pode ser usado para
quebrar a seqüência de um comando de iteração (within loop) ou para indicar
o fim de um case (within switch). Da mesma forma, um comando continue
só pode ser usado em um comando de iteração.
void f3(int k) {
struct {
int a;
float a;
} x;
float x;
switch (k) {
case 0x31: x.a = k;
case '1': x = x.a;
}
}
50
In function 'f3':
...: duplicate member 'a'
...: previous declaration of 'x'
...: duplicate case value
Geração de Código
Código intermediário