Você está na página 1de 22

Lex & Yacc

Lex
Lex: O lex é um gerador de analisador
léxico. O seu propósito e transformar
uma série de símbolos em tokens.
O mesmo recebe uma especificação
num arquivo de extensão .l, contendo o
conjunto de expressões regulares que
deve reconhecer e as ações
associadas a cada token reconhecido.
Estrutura

Um programa lex é dividido em três partes,


separadas pelos símbolos %%

declarações
%%
regras de tradução
%%
procedimentos auxiliares
Estrutura
Primeira parte do arquivo lex: declarações

• Na seção de declarações são feitas as declarações


de variáveis definições e inclusões de arquivos
entre %{ %}
• Podemos definir expressões regulares para
notações non-terminais
notação regular_expression
• Esta notação pode acontecer tanto na primeira
parte do arquivo quanto na segunda, desde que seja
feita entre { }
Example:

%{
#include "calc.h"
#include <stdio.h>
#include <stdlib.h>
%}
/* Regular expressions */
/* ------------------- */

white [\t\n ]+
letter [A-Za-z]
digit10 [0-9] /* base 10 */
digit16 [0-9A-Fa-f] /* base 16 */
identifier {letter}(_|{letter}|{digit10})*
int10 {digit10}+
exponant [eE][+-]?{int10}
real {int10}("."{int10})?{exponant}?
Regular expressions
x the "x" character
. any character except \n
[xyz] either x, y or z
[^bz] any character, except b and z
[a-z] any character between a and z
[^a-z] any character, except those between a and z
R* zero R or more; R can be any regular expression
R+ one R or more
R? one or zero R (that is an optional R)
R{2,5} 2 to 5 R
R{2,} 2 R or more
R{2} exactly 2 R
{NOTION} expansion of NOTION, that as been defined above in the
file
\0 ASCII 0 character
\123 the caracter which ASCII code is 123, in octal
\x2A the caracter which ASCII code is 2A, in hexadecimal
RS R followed by S
R|S R or S
R/S R, only if followed by S
^R R, only at the beginning of a line
R$ R, only at the end of a line
<<EOF>> end of file
Estrutura
Segunda parte do arquivo lex: regras de tradução

• Algumas especificação pode ser estrita nesta parte


do arquivo entre %{ }% Esta especificação será
colocada no inicio da função yylex(), que é a função
que reconhece os tokens e retorna um número
inteiro
• regras de tradução tem a sintaxe exp_regular
ação, se a ação não for especificada o token
reconhecido será utilizado. Se a ação tiver mais de
uma instrução ou for utilizada mais de uma linha,
deve estar entre { }.
Comentários

Linhas de comentários podem acontecer na


segunda parte do arquivo na sessão de ações
entre // /* */.

A variável yytext armazena os tokens


reconhecidos pelas expressões regulares.
Esta variável e composta de uma tabela de
caractere com o comprimento armazenado
na variável yyleng.
Estrutura
Terceira parte do arquivo lex: procedimentos auxiliares

• Aqui será inserido código de programação


necessário para suprir suas necessidades de
programação. Se nada for inserido o lex
considerará o código abaixo:

main() Compilar:
{
yylex();
}
Exercício lex ex1.l
%{
int nline;
%}

%%

ciro printf("\n Ciro Meneses Santos");


. printf("\n Erro: entrada = %s ",yytext);
\n { ++nline; printf("\n Nova linha"); }

%%

int main() {
yylex();
printf("\nFim de programa de %d linha ",nline );
}
%{
Exercício lex ex2.l
int i,qt =0; int vetor[10];
%}
digit [0-9]
%%
{digit}+ { if( insere(atoi(yytext)) )
printf("\n TOKEN: Numero ");
else printf("\nCORE DUMP overflow" );}
%%
int main() {
yylex();
for(i=0; i< 10; i++)
printf("\nItem [%d] = %d ",i,vetor[i]);
printf("\nFim de programa" );
}
int insere(int x) {
if( qt < 10 ){
vetor[qt] = x; qt++; return(1);
}
else
return (0); }
Yacc

Yacc: o yacc é um gerador de analisador


sintático LALR para GLC. O yacc recebe
um texto com a descrição de uma
gramática com ações semânticas e gera
um reconhecedor sintático
correspondente.
Estrutura
Um programa yacc é dividido em três partes,
separadas pelos símbolos %%

declarações
%%
regras de tradução
%%
procedimentos auxiliares
Estrutura

Primeira parte do arquivo yacc: declarações

• Na seção de declarações são feitas as declarações


de variáveis definições e inclusões de arquivos
entre %{ }%
• Declarações dos tokens utilizados pelo yacc
%token keyword
• Terminal que utiliza %union
• Prioridades de operadores
• Regra para inicialização %start
Estrutura
Segunda parte do arquivo yacc: regras da gramática

• Produções das regras da linguagem:

nonterminal_notion : body_1 { semantical_action_1 }


| body_2 { semantical_action_2 }
| ... { ... }
| body_n { semantical_action_n }
;
Estrutura

Terceira parte do arquivo yacc: procedimentos auxiliares

• #include "lex.yy.c“ onde está definida a


função yylex().

• Aqui será inserido código de programação


necessário para suprir suas necessidades de
programação. Deve incluir a função main() que deve
chamar yyparse() e yyerror()

Compilar:
Exercício lex & yacc ex3.l
/* expecificacao (f)lex para subconjunto Pascal */
%{
#include "y.tab.h"
%}
ID [A-Za-z][A-Za-z0-9]*
%%
"begin" { return tBEGIN; }
"end" { return tEND; }
":=" { return tASSIGN; }
{ID} { return tIDENTIFIER; }
[0-9]+ { return tNUMBER; }
[ \n\t] /* ignora expacos em branco */
. { return *yytext; }
%%
Exercício lex & yacc ex3.y
/* expecificacao (y)acc para subconjunto Pascal */
%{
#include <stdio.h>
%}

%token tBEGIN
%token tEND
%token tASSIGN
%token tIDENTIFIER
%token tNUMBER
%left '+'
%left '-'
%start inicio
Exercício grammer ex3.y
%%
statement : tIDENTIFIER tASSIGN expression
| ;
inicio : tBEGIN stt tEND ;
stt : statement '.'
| statement ';' stt ;
expression : tNUMBER
| tIDENTIFIER
| expression '+' expression
| expression '-' expression
;
%%
int main () {
yyparse(); }
int yyerror(char *s) {
fprintf(stderr, "%s\n",s); }
#include "lex.yy.c"
Exercício lex & yacc ex4.l
/* expecificacao (f)lex para subconjunto Pascal */
%{
#include "y.tab.h"
%}
ID [A-Za-z][A-Za-z0-9]*
%%
"integer" { return tINTEGER; }
"var" { return tVAR; }
"program" { return tPROGRAM; }
"then" { return tTHEN; }
"if" { return tIF; }
"begin" { return tBEGIN; }
"end" { return tEND; }
":=" { return tASSIGN; }
{ID} { return tID; }
[0-9]+ { return tNUM; }
[ \n\t] /* ignora expacos em branco */
. { return *yytext; }
%%
Exercício lex & yacc ex4.y
/* expecificacao (y)acc para subconjunto Pascal */
%{
#include <stdio.h>
%}
%token tPROGRAM
%token tVAR
%token tINTEGER
%token tTHEN
%token tIF
%token tBEGIN
%token tEND
%token tASSIGN
%token tID
%token tNUM
%left '+'
%left '-'
%start inicio
Exercício grammer ex3.y
%%
inicio : tPROGRAM tID ";" blocoVar blocoPrincipal ;
blocoVar : tVAR blocoId ":" tINTEGER ";" | ;
blocoId : tID | blocoId ',' tID ;
blocoPrincipal : tBEGIN blocoCorpo tEND ;
blocoCorpo : comando | blocoCorpo comando | ;
comando : blocoIF | blocoSt ;
blocoIF : if | blocoIF if ;
if : tIF "(" blocoCond ")" tTHEN tBEGIN blocoSt tEND ;
blocoSt : statement | blocoSt ";" statement ;
blocoCond : ident condicao ident ;
ident : tNUM | tID ;
condicao : ">" | "<" ;
statement : tID tASSIGN expression | ;
expression : tNUM | tID| expression '+' expression ;
%%
#include "lex.yy.c"
int main () {
yyparse(); }
int yyerror(char *s) {
fprintf(stderr,"%s ERRO: Linha %d TOKEN: %s \n",s,yylineno,yytext);
}

Você também pode gostar