240 likes | 437 Views
Ferramentas para a Construção de Compiladores: Lex & Yacc. Disciplina: Compiladores Professor: Marcelo Morandini Monitor: Alysson Neves Bessani Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br. Construção de Compiladores.
E N D
Ferramentas para a Construção de Compiladores: Lex & Yacc Disciplina: Compiladores Professor: Marcelo Morandini Monitor: Alysson Neves Bessani Adaptação: Claudio Cesar de Sá claudio@joinville.udesc.br DIN - UEM
Construção de Compiladores • Analisadores Léxico (scanners), Sintático (parsers), e Semântico, Tabela de Símbolos e Gerador de Código; • Grande volume de código; • Codificação complexa e repetitiva; • Altamente propensa a erros; • Desejável a utilização de ferramentas.
Tipos de Ferramentas • Geradores de analisadores léxicos. Ex: lex, flex, javacc, ... • Geradores de analisadores semânticos. Ex: yacc, bison, javacc, ... • Geradores de geradores de código: Transformam uma LI (linguagem intermediária) em código assembly da máquina alvo.
Lex & Yacc • Ferramentas largamente utilizadas no mundo UNIX; • Lex: gerador de scanners(yylex()); • Yacc: gerador de parsers(yyparse()); • Trabalham juntos na construção de parsers.
Sistema de I/O n lex yylex() “Backend” do Compilador n 1 yacc yyparse() Relação Lex, Yacc, Sistema
Lex • Gerador de scanners; • Pode ser utilizado para reconhecimento de qualquer tipo de expressão regular; • Expressões regulares são transformadas em autômatos; • Para cada expressão regular especificada deve-se definir uma ação (código em C);
Formato do Arquivo Lex declarações %% regras %% subrotinas de apoio
Lex: Declarações • Códigos em C: %{ /* coloque qualquer código em C... */ #define FOO 1 /* ... como defines ou macros ... */ int tokval = 0; /* ... ou variáveis globais */ %} • Abreviações: AB (‘a’|’b’) /* AB é uma abreviação de a|b */
Lex: Regras • Formato básico: <expressão regular 1> <ação 1> <expressão regular 2> <ação 2> ... <expressão regular n> <ação n> • Expressões Regulares: • Definições regulares; • Exemplos: • [abcD]+ (a|b|c|D) (a|b|c|D)* • .\+ ?+
Lex: Regras (cont) • Expressões Regulares(cont): • Exemplos (cont): • {AB} /* abreviação AB */ • Ações: • Código em C; • Variáveis Importantes: • char yytext[]: texto reconhecido pela ER associada a ação; • unsigned int yyleng:tamanho do texto;
Lex: Subrotinas auxiliares • Qualquer função definida em C; • Normalmente utiliza-se esta seção para construção de funções de apoio nas ações; • Este trecho não é alterado no scanner gerado.
Lex: Pequeno Exemplo %{ #include <stdio.h> #include ‘y.tab.h’ /* header que define os tokens */ int numc = 0, idc = 0, tok = 0; %} NUM [0-9] ID [a-zA-Z_$] [a-zA-Z0-9_$]* %% {NUM} {numc++; tok = TNUM; return get_number();} /* continua */
Lex: Pequeno Exemplo (cont) /* continuação */ {ID} {idc++; tok = TID; return do_table();} \+ {return tok = TADD;} - {return tok = TSUB;} %% int get_number(){ return atoi(yytext); } int do_table(){ /* instala o ID na tabela de símbolos ou retorna seu valor corrente */ }
Yacc: Yet Another Compiler-Compiler • Gerador de parsers; • Transforma uma gramática que define uma linguagem em um autômato de pilha que reconhece esta linguagem (implementado em C); • Para cada produção da gramática existe uma ação semântica.
Formato do Arquivo Yacc declarações %% regras de tradução %% subrotinas de apoio
Yacc: Declarações • Códigos em C (de maneira semelhante ao Lex) entre %{ %}; • Definição de tokens: %token T1 T2 T3 ... TN • Definição de regras auxiliares para solução de ambigüidades: • Exemplos: • %right ‘+’ • %start S
Yacc: Regras de Tradução • Semelhantes a definições gramaticais; • Cada símbolo (terminal ou não) tem associado a ele uma pseudo variável; • O símbolo do lado esquerdo tem associado a ele o $$; • A cada símbolo i associa-se um $i; • $i contém o valor do token (retornado por yylex()) se o símbolo i for terminal, caso contrário contém o $$ do não terminal.
Yacc: Regras de Tradução (cont) • As regras são da forma: /* uma gramática definida assim: */ <lado esquerdo> := <alt1>|<alt2>|...|<altN> /* transforma-se na seguinte especificação yacc */ <lado esquerdo>: <alt1> {/*ação semântica 1*/} | <alt2> {/*ação semântica 2*/} ... | <alt3> {/*ação semântica N*/} ;
Yacc: Subrotinas auxiliares • Funções em C que são copiadas para o parser gerado; • Funciona de maneira semelhante as subrotinas auxiliares do Lex; • Se o Lex não for usado para especificação do analisador léxico a função yylex() deve ser implementada aqui.
Yacc: Pequeno Exemplo %{ #define <stdio.h> %} %start init %token TNUM TID TADD TSUB %% init : expr ‘\n’ {printf(‘r: %d’,$1);} ; /* continua */
Yacc: Pequeno Exemplo (cont) /* continuação */ expr : expr TADD expr {$$ = $1 + $3;} | expr TSUB expr {$$ = $1 - $3;} | ‘(’ expr ‘)’ {$$ = $2;} | TNUM %% /*subrotinas em C, se necessário */
Lex & Yacc: Como Utilizar • Arquivos Lex são por convenção terminados com .l e os do Yacc são terminados em .y; • Utilizando o Yacc: • yacc -d <arquivo.y> • Obs: A opção -d faz com que se crie o arquivo .h com a definição dos tokens; • Obs: Use a opção -v para gerar o arquivo y.output, que descreve o autômato de pilha gerado.
Lex & Yacc: Como Utilizar (cont) • Utilizando Lex: • lex <arquivo.l> • Compilando e gerando o parser: • cc -o <programa alvo> lex.yy.c y.tab.c -ly -ll • Obs: lex.yy.c é o scanner gerado pelo lex; • Obs: y.tab.c é o parser gerado pelo yacc; • Obs: y é a biblioteca do yacc e ela deve ser colocada antes da biblioteca do lex (l).
Bibliografia • Aho, Alfred V. et all. Compiladores: Princípios, Técnicas e Ferramentas. Livros Técnicos e Científicos (tradução). 1986. EUA. • Sun Microsystems. Solaris Programing Utilities Guide. 1994. USA. • UNIX Man Pages: lex (1) e yacc (1).