hoc1b: sinal negativo e make
Esta página descreve os arquivos do diretório etapa1b/.
Explicação do programa
Uma das vantagens de usar o yacc/bison é que a definição de alto nível da gramática facilita mudar ou acrescentar novos recursos à linguagem que estamos desenvolvendo.
Para incorporar o sinal de número negativo, será preciso apenas mais duas linhas de código. O código-fonte completo está em hoc1b.y
(link).
Mudanças na gramática
A primeira mudança é acresecentar a declaração do token NEGATIVO
que vai representar o operador também conhecido como unary minus (menos unário).
%token NUMERO
%left '+' '-' /* associatividade esquerda */
%left '*' '/' /* associatividade esquerda, maior precedência */
%left NEGATIVO /* hoc1b */
Colocar NEGATIVO
por último dá a precedência mais alta para esse sinal.
A próxima mudança é incluir uma nova forma nas regras sintáticas de expr
:
expr: NUMERO { $$ = $1; }
| '-' expr %prec NEGATIVO { $$ = -$2; } /* hoc1b */
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
/* etc... */
A 2ª linha estabelece que a forma '-' expr
terá precedência alta (%prec NEGATIVO
), e seu valor será o negativo da expressão ($$ = -$2
). A forma da 4ª linha (expr '-' expr
) continuará sendo usada quando o sinal '-'
aparecer entre duas expressões.
Construir e testar
Use yacc
para gerar o código em C, compile, e teste:
$ yacc hoc1b.y
$ cc y.tab.c -o hoc1b
$ ./hoc1b < testes.hoc
4
-7
37.777778
100.4
Para testar o sinal de negativo, incluí a linha -3 - 4
em testes.hoc
. Por isso, o resultado -7.
Agora vamos ver como automatizar a construção do programa.
Introdução a make
Toda vez que fazemos uma alteração em um arquivo .y
, temos que rodar yacc
e depois cc
. É inconveniente, mas o pior fazer é uma mudança no arquivo .y
, esquecer um desses passos e ficar testando um executável que não foi atualizado, como já aconteceu comigo.
É fácil criar um script no shell para rodar esses comandos, mas é melhor usar a ferramenta make
, pois ela foi projetada para construir programas, processa arquivos .y
automaticamente, e evita realizar passos desnecessários — por exemplo, não executa o compilador se o arquivo-fonte hoc.y
não foi tocado.
Se você executar o comando make hoc1b
no diretório etapa1b/
, verá esta saída:
$ make hoc1b
yacc hoc1b.y
mv -f y.tab.c hoc1b.c
cc -c -o hoc1b.o hoc1b.c
cc hoc1b.o -o hoc1b
rm hoc1b.o hoc1b.c
Observe os comandos executados por make
:
yacc
para processarhoc1b.y
e gerary.tab.c
;mv
para renomeary.tab.c
parahoc1b.c
;cc
para compilarhoc1b.c
e gerar o arquivo-objetohoc1b.o
;cc
para montar o executávelhoc1b
a partir dehoc1b.o
;rm
para apagarhob1b.o
ehob1b.c
.
Se você rodar make hoc1b
de novo, make
não faz nada além de avisar que o executável hoc1b
já está atualizado:
$ make hoc1b
make: 'hoc1b' is up to date.
Toda essa lógica e muito mais está embutida no make
.
Veremos depois como criar um Makefile
para configurar as ações do make
.
Voltar para o índice de páginas.