4
1 Compiladores Análise sintática Bottom-Up YACC 2 YACC Yet Another Compiler Compiler Produz um parser bottom-up para uma dada gramática Usado para produzir compiladores para Pascal, C, C++ entre outras Além disso, foi usado no desenvolvimento de: bc - calculadora eqn & pic verificador de sintaxe SQL – Lex bison: Versão GNU 3 YACC Seqüência básica operacional a . o u t Arquivo contendo gramática desejada no formato yacc programa programa yacc yacc programa fonte C criado pelo yacc Compilador Compilador C Programa executável que faz a análise sintática da gramática descrita em parse.y g r a m . y y . t a b . c yacc gcc / cc 4 Exemplo 1 2 + 3 4 LEX LEX N U M P L U S N U M YACC YACC e x p r : : = e x p r + t e r m | t e r m t e r m : : = t e r m * f a c t o r | f a c t o r f a c t o r : : = ' ( ' e x p r ' ) ' | n u m | i d e x p r t e r m e x p r t e r m + f a c t o r n u m f a c t o r n u m Válido álido! n u m [ 0 - 9 ] + 5 Formato do arquivo YACC D e f i n i ç õ e s % % R e g r a s % % C ó d i g o S u p l e m e n t a r 6 Seções de Regras Normalmente escritas como segue: e x p r : e x p r ' + ' t e r m | t e r m ; t e r m : t e r m ' * ' f a c t o r | f a c t o r ; f a c t o r : ' ( ' e x p r ' ) ' | I D | N U M ;

Compiladores Lex Bison

Embed Size (px)

Citation preview

Page 1: Compiladores Lex Bison

1

Compiladores

Análise sintática Bottom-Up

YACC

2

YACC

• Yet Another Compiler Compiler

• Produz um parser bottom-up para uma dada gramática

• Usado para produzir compiladores para Pascal, C, C++ entre outras

• Além disso, foi usado no desenvolvimento de:

– bc - calculadora

– eqn & pic

– verificador de sintaxe SQL

– Lex

• bison: Versão GNU

3

YACCSeqüência básica operacional

a.out

Arquivo contendo gramática

desejada no formato yacc

programa programa yaccyacc

programa fonte C criado pelo yacc

Compilador Compilador CC

Programa executável que faz a

análise sintática da gramática

descrita em parse.y

gram.y

y.tab.c

yacc

gcc / cc

4

Exemplo

12 + 34

LEXLEX

NUM PLUS NUM

YACCYACC

expr ::= expr + term | term

term ::= term * factor | factor

factor ::= '(' expr ')' | num | id

expr

termexpr

term

+

factor num

factor

num

VVálidoálido!!

num [0-9]+

5

Formato do arquivo YACC

Definições

%%

Regras

%%

Código Suplementar

6

Seções de Regras

• Normalmente escritas como segue:

expr : expr '+' term

| term

;

term : term '*' factor

| factor

;

factor : '(' expr ')'

| ID

| NUM

;

Page 2: Compiladores Lex Bison

7

Seção de Definições

%{

#include <stdio.h>

#include <stdlib.h>

%}

%token ID NUM

%start expr

8

Obs:

• lex/flex produz uma função yylex()

• yacc produz uma função yyparse()

• yyparse espera chamar uma yylex

• Como conseguir yylex?

– Escrever sua própria!

– Usar lex/flex

9

int yylex()

{

if(it's a num)

return NUM;

else if(it's an id)

return ID;

else if(parsing is done)

return 0;

else if(it's an error)

return -1;

}

Construindo yylex

10

lex & yacc

cccc

lex.yy.clex.yy.c

y.tab.cy.tab.c

a.outa.out

11

Exemplo

• Suponha um arquivo lex scanner.l e um arquivo yacc chamado decl.y.

• Passo a serem feitos ...

yacc -d decl.y

lex scanner.l

gcc -c lex.yy.c y.tab.c

gcc -o parser lex.yy.o y.tab.o -ll

Nota: scanner deve incluir na seção de definições:

#include "y.tab.h" 12

YACC

• As regras podem ser recursivas

• As regras não podem ser ambíguas*

• Usa um parser bottom up Shift/Reduce -LALR(1)

– Solicita um token

– Empilha

– Redução ?

• Sim: reduz usando a regras correspondente

• Não: pega outro token

• Yacc não pode olhar mais que um token de

lookahead

• yacc -v gram.y gera a tabela de estados, em

y.output

Page 3: Compiladores Lex Bison

13

Exemplo scanner.lscanner.l

%{

#include <stdio.h>

#include "parser.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} {;}

scanner.l

14

Exemploparser.yparser.y

parser.y

%{

#include <stdio.h>

#include <stdlib.h>

%}

%token CHAR COMMA FLOAT

%token ID INT SEMI

%%

decl : type ID list

{ printf("Sucesso!\n"); } ;

list : COMMA ID list

| SEMI

;

type : INT | CHAR | FLOAT

;

%%

parser.y (cont.)

extern FILE *yyin;

main() {

do {

yyparse();

} while(!feof(yyin));

}

yyerror(char *s) {

/* Nada definido */

}

15

Exemplo

Execução$> bison -d parser.y

$> cat parser.tab.h

...

# define CHAR 257

# define COMMA 258

# define FLOAT 259

# define ID 260

# define INT 261

# define SEMI 262

...

$> flex parser.y

$> gcc parser.tab.c lex.yy.c -lfl

Gera:� parser.tab.c� parser.tab.h

Gera:� lex.yy.c

16

A volta do atributo

• Cada símbolo tem um valor associado (atributo)

– Poder uma quantidade numérica no caso de um

número (42)

– Pode ser um ponteiro para um string ("Hello, World!")

– Pode ser um ponteiro para uma tabelas de símbolos

no caso de uma variável

• Quando usando lex junto com o Yacc , coloca-

se o valor em yylval

– Em situações complexas, yylval é uma union

• Típico código lex:

[0-9]+ {yylval = atoi(yytext); return NUM}

17

Definindo Valores

expr : expr '+' termo { $$ = $1 + $3; }

| termo { $$ = $1; }

;

termo : termo '*' fator { $$ = $1 * $3; }

| fator { $$ = $1; }

;

fator : '(' expr ')' { $$ = $2; }

| ID

| NUM

;

18

Resolução de Conflitos

1. Default:

– Shift-Reduce: Escolhe o shift

– Reduce-Reduce: Escolhe a regra que aparece primeiro

2. Especificação de regras de precedências:

• definida pelo usuário

E : E '+' E |

E '-' E |

E '*' E |

E '/' E |

E '=' E |

'(' E ')' |

INTEGER;

precedência

%token INTEGER%right '='%left '+' '-'%left '*' '/'%%

Page 4: Compiladores Lex Bison

19

Exemplos

5+3+2 (5+3)+2

5*3*2 (5*3)*2

5+3*2 5+(3*2)

a=5+3 a=(5+3)

a=b=c=3+5 a=(b=(c=(3+5)))

%token INTEGER%right '='%left '+' '-'%left '*' '/'%%

20

Resolução de Conflitos

Especificação de regras de precedências:

• mudança explícita de precedência ( %prec )

E : E '+' E |

E '-' E |

E '*' E |

E '/' E |

E '=' E |

'(' E ')' |

-E %prec UMINUS |

INTEGER;

%token INTEGER%right '='%left '+' '-'%left '*' '/'%nonassoc UMINUS%%

Precedência

21

Conceitos adicionais

• Yacc permite que símbolos tenham múltiplos tipos de valores

%union {

double dval;

int vblno;

}

• Tabelas de símbolos são usadas para guardar informações sobre tipos:– nomes

– tipos

– valores,

– etc

• TS podem ser implementadas de diversas formas. 22

Resumo

• Escrever um compilador é difícil e requer tempo e esforço

• Scanners e parsers podem ser construídos por métodos automáticos

Regras LéxicasRegras Léxicas

GraGramáticamática

SemSemânticaântica

CompilCompiladorador

ScannerScanner

------------------

ParserParser

------------------

GeradorGerador

CódigoCódigo

4

4

23

Bibliografia

• Livro do dragão: Seção 4.9

• Bison Project Homepage www.gnu.org/software/bison

• Thomas Niemann: A Compact Guide to Lex & Yacc

• C. Donnelly, R. Stallman: Bison - the YACC-compatible Parser Generator