yacc
-Yet Another Compiler Compiler- Produz um analisador ascendente para uma gramática
- Pode ser usado para produzir compiladores para várias linguagens
- Pascal, C, C++, …
- Outros usos
- bc (calculadora)
- eqn & pic (formatadores para troff)
- Verificar a sintaxe SQL
- Lex
- bison – versão livre da GNU
- Contém três seções
- Definições (em C, incluído no início da saída)
- Regras (Especificação da Gramática)
- Código (em C, incluído no fim da saída)
- Sintaxe
Definições %% Regras %% Código Suplementar
- Contém a gramática
- Exemplo
expr : expr '+' term | term; term : term '*' factor | factor; factor : '(' expr ')' | ID | NUM;
- Contém a definição de tokens, símbolo inicial
- Exemplo
%{ #include <stdio.h> #include <stdlib.h> %} %token ID NUM /* notar a declaração dos tokens */ %start expr
- Flex produz uma função
yylex()
- Bison produz uma função
yyparse()
- Flex e Bison: concebidos para interagirem
- yyparse() chama yylex() para obter um token
- Duas opções
- Ou implementamos manualmente yylex()
- Ou utilizamos Flex diretamente (melhor opção)
- Supondo os arquivos
- scanner.l com as especificações de tokens em lex
- parser.y com a gramática em yacc
\vfill
- Ordem de passos possível para construir o analisador
bison -d parser.y flex scanner.l gcc -c lex.yy.c y.tab.c gcc -o parser lex.yy.o y.tab.o -lfl
\vfill
- scanner.l deve incluir na seção de definições
#include "y.tab.h"
- As regras da gramática
- Podem ser recursivas tanto a esquerda quanto a direita
- Não podem ser ambíguas
- Usa um parser ascendente LALR(1)
- Solicita um token
- Empilha
- Redução?
- Sim → reduz usando a regra correspondente
- Não → lê outro token na entrada
- Não pode olhar mais que um token de lookahead
bison -v parser.y
gera a tabela de estados
%{
#include <stdio.h>
#include "y.tab.h"
%}
id [_a-zA-Z][_a-zA-Z0-9]*
wspc [ \t\n]+
semi [;]
comma [,]
%%
int { return INT; }
char { return CHAR; }
float { return FLOAT; }
{comma} { return COMMA; }
{semi} { return SEMI; }
{id} { return ID;}
{wspc} {;}
%{
#include <stdio.h>
#include <stdlib.h>
%}
%start line
%token CHAR, COMMA, FLOAT, ID, INT, SEMI
%%
decl : type ID list { printf("Success!\n"); } ;
list : COMMA ID list | SEMI;
type : INT | CHAR | FLOAT;
%%
- Notem uma ação para a regra \texttt{decl}
- Cada regra pode ter \alert{ações} (semânticas)
- Exemplo
E: E '+' E { $$ = $1 + $3; } | INT_LIT { $$ = INT_VAL; };
- \texttt{\$n} é o atributo do n-ésimo símbolo na regra
- O default é que os atributos sejam do tipo inteiro
- Pode-se mudar o tipo através da diretiva
%token<...> /* com o tipo do token */ %type<...> /* tipo do não-terminal, com %union */
%union {
char* nome;
int inteiro;
node* no;
}
%token<nome> IDF /* IDF terá atributo de tipo char* */
%type<no> E /* E terá atributo de tipo node* */
%%
E: E '+' E { $$ = create_node($1, $3, "plus"); }
| IDF { $$ = create_leaf($1); };