• Nie Znaleziono Wyników

Wykład 14 (5-06-14): Wykład 4 (lex/flex, yacc/bison)

N/A
N/A
Protected

Academic year: 2021

Share "Wykład 14 (5-06-14): Wykład 4 (lex/flex, yacc/bison)"

Copied!
73
0
0

Pełen tekst

(1)

PARADYGMATY  I  JĘZYKI  

PROGRAMOWANIA  

lex/flex  i  yacc/bison  

w-­‐4  (2014)  

(2)

 

Skaner  

 

Parser  

 

Analizator  

semantyki  

 

 

Optymizator  

Generator  

 

kodu  

Kompilator  

 

 

faza  wstępna  

faza  końcowa  

faza  postkońcowa  

(3)

lexer/scanner  

 

 

¨

Analiza  

leksykalna  

¤

proces  zamiany  ciągów  znaków  na  ciąg  tokenów  

x  =  4  –  3*2  

LEKSEM            TOKEN

 

 x

           ZMIENNA  

 =                                  PRZYPISANIE  

 4                                  LICZBA  

 -­‐                                    O_MINUS  

 3                                  LICZBA  

 *                                  O_MUL  

 2                                  LICZBA  

3  

(4)

4

 

parser  

¨

Analiza  

syntaktyczna  

¤

analiza  ciągów  tokenów  (leksemów);  ich  struktura  

gramatyczna;  błędy  składni  

^

 

=  

x  

-­‐  

4  

*  

3  

2  

x  =  4  –  3*2  

LEKSEM            TOKEN

 

 x

           ZMIENNA  

 =                                  PRZYPISANIE  

 4                                  LICZBA  

 -­‐                                    O_MINUS  

 3                                  LICZBA  

 *                                  O_MUL  

 2                                  LICZBA  

4  

(5)

double  

a  =  "napis";

 

er

r

or:  

i

n

c

omp

a

t

i

ble

 

types

 i

n  

i

ni

ti

al

iza

t

i

on

 

Kod:  

Błąd  analizy  

semantycznej:  

Analizator  semantyki  

¨

Analiza  

semantyczna  

¤

znaczenie  

n 

np.  sprawdzanie  typów,  wiązanie  obiektów,  etc.  

(6)

Optymalizator  

¨

zmniejszenie/zwiększenie  pewnych  własności  

programu  wynikowego    

¨

np.  przyspieszenie  programu  

(7)

   

x  =  a  +  b  *  c

 

Generator  kodu  

¨

Generacja  kodu  

¨

proces,  w  którym  kompilator  zamienia  program  

źródłowy  na  wykonywalny,  maszynowy  

load c!

mul b!

add a!

store x !

(8)

   

lex/flex  &  yacc/bison  

(9)

lex/flex  

¨

lex  

¤

narzędzie  do  budowy  analizatorów  leksykalnych  

¤

M.E.  Lesk  i  E.  Schmidt  (Lex  –  A  Lexical  Analyzer  

Generator)  

¤

obecnie  rzadko  używany  

¨

flex  (fast  lexical  analyzer  generator)  

¤

Open  source  (darmowy)  

(10)

yacc/bison  

¨

yacc  

¤

narzędzie  do  tworzenia  analizatorów  syntaktycznych  

(S.C.  Johnson.  Yacc:  Yet  Another  Compiler-­‐Compiler)  

¤

wygenerowany  parser  potrzebuje  analizatroa  

leksykalnego  

¤

obecnie  rzadko  używany  

 

¨

bison  

¤

Open  source  (darmowy)  

(11)

L

ex

/Fl

e

x  

(

*

.l  

skrypt

)  

Ya

(

*.

cc

y

 

/Bis

s

krypt

o

)  

n  

...związek  z  kompilacją  

 

Skaner  

 

Parser  

 

Analizator  

semantyki  

 

 

Optymizator  

Generator  

 

kodu  

faza  wstępna  

faza  końcowa  

faza  postkońcowa  

(12)

Schemat  działania  

KOD  ŹRODŁOWY  

a  =  b  +  c  *  d  

WZORCE  

lex/flex  

GRAMATYKA  

yacc/bison  

ANALIZA  

LEKSYKALNA  

ANALIZA  

SYNTAKTYCZNA  

^

 

=  

id1  

+  

id2  

*  

id3  

id4  

KOD  ASEMB.  

========  

load                id3  

mul                    id4  

add                  id2  

store                id1        

yylex()  

yyparse()  

12  

(13)

Schemat  działania  

skrypt.l  

skrypt.y  

lex  |  flex  

yacc  |  bison  

skrypt.lex.c  

skrypt.tab.c  

a.out  

kod  parsera  

kod  skanera  

wejście  

wyjście  

13  

(14)

lex  

*.l  skrypt  

lex.yy.c

 

 

Jak  działa  flex?  

¨

Flex używa skryptu

*

.l

do generowania

skanera

¨

skaner:

¤

czyta plik wejściowy (i

n

put

file

)

¤

przetwarza plik na ciąg tokenów

¤

tokeny przekazuje do parsera

(15)

Jak  działa  flex?  

%{ #include <stdio.h> %} %% begin printf("Started\n"); hello printf("Hello!\n"); thanks printf(”Welcome\n"); end printf("Stopped\n"); %% $ flex exampleA.l! $ gcc -o exampleA lex.yy.c –lfl! $ ./exampleA! begin! Started! hello! Hello!! end! Stopped! thanks! Welcome! hello thanks! Hello!! Welcome!

Skrypt  dla  flex-­‐a:  

KOMPILACJA  i  WYKONANIE  

(16)

Tokenizacja  

%{ #include <stdio.h> #include <y.tab.h> %} %%

begin return BEGIN; hello return HELLO; thanks return THANKS;

end return END;

%%

 

Zamiast  drukowania  

(printf(...))  

dokonujemy  identyfikacji  

TOKENU    

i  zwracamy  jego  nazwę.  

 

Nazwa  ta  będzie  używana  

przez  program  yacc,  do  

opisu  gramatyki.  

 

(17)

Wyrażenia  regularne  

/*

sekcja definicji

*/

%{

#include <stdio.h>

%}

%%

/*

sekcja reguł

*/

[a-z]

printf("Lowercase_word\n");

[A-Z]

printf("Uppercase_word\n");

[a-zA-Z]

printf("Word\n");

[0-9]

printf("Integer\n");

[0-9.]

printf("Float\n");

";"

printf("Semicolon\n");

"("

printf(”Left_parentheses\n");

")"

printf(”Right_parentheses\n");

%%

17  

(18)

Format  reguł  flex-­‐a  

¨

dopasuj  tekst  z  wejścia  do  wzorców  (

REGEX

)  

¨

zwracaj  typ  tokenów  (

TOKEN_TYPE

)  

¨

Format:  

!

REGEX

!

{ /* Kod */!

!

!return

T

OKEN

_TYP

E

;!

!}!

!…!

(19)

Reguły  flex-­‐a  

¨ 

 Flex dopasowuje

tokeny o największej długości

¤ 

Wejście:

abc  

¤ 

Reguła:

[a-­‐z]+

 

¤ 

Token:

abc(nie

 

"a"

 

i  nie

 

"ab”)

 

¨ 

F

l

ex używa zasady:

pierwsza

dobra

r

eguła

¤ 

wejście:

jeden  

¤ 

Reguła_1:

"jeden”

 

 

{  printf("Hello,");  

¤ 

Reguła_2

:

[a-­‐zA-­‐z]+

 

 

{  printf  ("World!");  }  

àWyjście: Hello, (nie “World!”)

 

(20)

Wymiana  danych  

¨ 

yytext    -­‐    przechowuje  wartość  przeczytaną  przez  lex    

¨ 

yyval        -­‐    jest  używana  do  wymiany  wartości  między  lex  a  yacc  

¨ 

Przykład  

[0-9] yyval = atoi(yytext); return NUMBER;

¨ 

Tutaj  pod  yyval  została  wstawiona  wartość  otrzymana  z  konwersji  

napisu  wejściowego,  dopasowanego  do  wyrażenia  regularnego,  która  

pierwotnie  została  zapisana  w  zmiennej  yytext. Prócz  tego  zwrócony  

został  typ  wartości  (NUMBER)  –  w  ten  sposób  yacc  dowie  o  typie  i  może  

go  używać    we  własnych  definicjach.  

(21)

Wymiana  danych  

¨

definicje  tokenów  –  metoda  podstawowa  

¨

inne  informacje  

¨

YYSTYPE  (lex  i  yacc:  definicje)    

 

%{

#define YYSTYPE double

%}

¨

lex:  deklaracje  

 

extern YYSTYPE yyval;

¨

yacc:  deklaracje  

 

YYSTYPE yyval;

(22)

Ogólny  skrypt  lex-­‐a  

plik  skryptu  dla  lex-­‐a:  

 

/**

sekcja definicji

**/!

...!

%%!

/**

sekcja reguł

**/!

...!

%%!

/** Sekcja

kodu C kopiowanego dosłownie

**/!

...

 

(23)

calc1.l  

!

/*

sekcja definicji

*/!

%{!

#include <

stdlib.h

>!

#include <stdio.h>!

#include "calc1.h"!

void yyerror(char*);!

extern int yylval;!

%}!

(24)

calc1.l  

!

/*

sekcja definicji

*/!

%{!

#include <

stdlib.h

>!

#include <stdio.h>!

#include "calc1.h"!

void yyerror(char*);!

extern int yylval;!

%}!

nagłówek  calc1.h  

(25)

calc1.l  

!

/*

sekcja definicji

*/!

%{!

#include <

stdlib.h

>!

#include <stdio.h>!

#include "calc1.h"!

void yyerror(char*);!

extern int yylval;!

%}!

nagłówek  funkcji  błędów  

(26)

calc1.l  

!

/*

sekcja definicji

*/!

%{!

#include <

stdlib.h

>!

#include <stdio.h>!

#include "calc1.h"!

void yyerror(char*);!

extern int yylval;!

%}!

zmienna  “komunikacyjna”,  zewnętrzna  

(27)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

(28)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

wyrażenia  regularne,  wzorce  

(29)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

puste  znaki  

(30)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

cyfry;  jedna  lub  więcej  

(31)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

zwracana  nazwa  tokenu  

(32)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

jeden  znak;    operator  

(33)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

kropka  oznacza  dowolny  znak  (nie  \n)  

(34)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

reakcja  na  “kropkę”  

(35)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

przekazywana  zmienna  i  jej  zawartość  

(36)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

przekazywany  typ  tokenu  

(37)

calc1.l  

/*

sekcja reguł

*/!

%%!

[ \t]+ ;!

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

[-+*/] {return *yytext;}!

"(" {return *yytext;}!

")" {return *yytext;}!

\n {return *yytext;}!

. {char msg[25]; sprintf(msg,"%s <%s>",!

"invalid character",yytext); yyerror(msg);}!

!

funkcja  błędów  

(38)

   

yacc/bison  

(39)

Jak  działa  bison?  

¨

Bison

używa skryptu z pliku *.y

¨

Parser czyta ciąg tokenów i próbuje

zidentyfikować struktury gramatyczne

zgodnie ze specyfikacją

bison

 

nazwa  .y  

 

nazwa.tab.c

 

nazwa.parse.c

 

39  

(40)

Gramatyka  

¨

Gramatyka  

¤

zbiór  reguł  formalnych  dla  napisów  z  danego  języka.  

Reguły  opisują  zasady  tworzenia  napisów  (tokenów)  

ze  znaków  zgodnie  z  zadaną  składnią  

(41)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE

:      

3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

41  

(42)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

42  

(43)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

Startujemy  z  lewej  

strony.Widzimy,  że  

mamy  id.  

43  

(44)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

id  jest  wyrażeniem  

(45)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

Parser  wie,  że  3  jest  

wyrażeniem.  W  

dalszych  próbach  

oprze  się  na  

następnym  znaczniku.  

(46)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

Produkcja  z  plus  

pasuje  bo  jest  to  

następny  token  z  

wejścia.  

(47)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

Przesuwamy  się  do  

następnego  tokenu,  

który  jest  id,  a  więc  

jest  wyrażeniem  (E)  

 

(48)

Prosty  przykład  

 

   Leksem  Token  

   3

 

 LICZBA  

   +

 

 O_PLUS  

   2

 

 LICZBA  

   -­‐

 

 O_MINUS  

   1

 

 LICZBA  

 

     WEJŚCIE:      3  +  2  –  1  

     E  =>  E  +  E    

               |  E  –  E      

               |  E  *  E  

               |  E  /  E    

               |  id  

           Gramatyka  

 

Wiemy,  że  E  +  E  to  wyrażenie  (E).  

Powtarzamy  proces  aż  do  

wyczerpania  możliwości  ...  

 

(49)

Gramatyka  i  format  yacc  

¨ 

Gramatyka  G  =  {{E,  I},  T,  P,  E}  

1. 

E => I!

2. 

E => E + E!

3. 

E => E * E!

4. 

E => ( E )!

5. 

I => a!

6. 

I => b!

7. 

I => Ia!

8. 

I = Ib!

9. 

I = I0!

10. 

I => I1!

! T  =  {+,  *,  (,  ),  a,  b,  0,  1}  =  s.  terminalne   P  =  {produkcje:  1-­‐  10},  E  start  

¨ 

Format  programu  yacc  

!

Exp : Id {...}!

| Exp ‘+’ Exp {...}!

| Exp ‘*’ Exp {...}!

| ‘(‘ Exp ‘)’ {...}!

;!

Id : ‘a’ {...}!

| ‘b’ {...}!

| Id ‘a’ {...}!

| Id ‘0’ {...}!

| Id ‘1’ {...}!

;!

  49  

(50)

calc1.y  

!

!

/*

sekcja definicji

*/!

%{!

#include <stdlib.h>!

#include <stdio.h>!

int yylex(void);!

#include "calc1.h"!

%}!

%token INTEGER!

50  

(51)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }! 51  

(52)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

reguły  gramatyczne  

52  

(53)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

akcje  

53  

(54)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

Kolejność  operacji  zapewnia    

kolejność  produkcji:  najpierw  

plus/minus  co  oznacza,  że  mulex  

jest  realizowane  jako  pierwsze.  

Można  deklarować  

łączność  działań:  

 

%left PLUS MINUS! %right NOT!

!

etc.  

(55)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

zwykły  wydruk;  informacja  

(56)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

specjalne  zmienne  

przechowujące  dopasowane  

wyrażenia  “z  prawej”  strony    

produkcji  

   $1          $2                $3  

(57)

calc1.y  

%% /* sekcja REGUŁ */! program:! line program! | line! line:! expr ’\n’ { printf("%d\n",$1); }! | ’n’! expr:! expr ’+’ mulex { $$ = $1 + $3; }! | expr ’-’ mulex { $$ = $1 - $3; }! | mulex { $$ = $1; }! mulex:! mulex ’*’ term { $$ = $1 * $3; }! | mulex ’/’ term { $$ = $1 / $3; }! | term { $$ = $1; }! term:! ’(’ expr ’)’ { $$ = $2; }! | INTEGER { $$ = $1; }!

“obliczona”  lewa  strona  

produkcji  i  umieszczana  

 na  stosie  

(58)

calc1.y  

/*

sekcja kodu C

*/!

%%!

void yyerror(char *s)!

{!

fprintf(stderr,"%s\n",s);!

return;!

}!

int main(void)!

{!

/*yydebug=1;*/!

yyparse();!

return 0;!

}!

“wywołanie  głównej  funkcji  

parsera  

(59)

calc1.y  

/*

sekcja kodu C

*/!

%%!

void yyerror(char *s)!

{!

fprintf(stderr,"%s\n",s);!

return;!

}!

int main(void)!

{!

/*yydebug=1;*/!

yyparse();!

return 0;!

}!

definicja  funkcji  błędów  

59  

(60)

Praktyka  

¨ 

uruchomić yacc/bison na pliku skryptowym

z definicjami

¨ 

uruchomić lex/flex na pliku definicji

syntaktycznych

¨ 

skompilować żródło wygenerowane przez yacc

¨ 

skompilować plik wygenerowany przez lex/flex

¨ 

skompilować inne potrzebne pliki

¨ 

połączyć wszystkie wynikowe pliki w plik

wykonywalny

 

(61)

Przykład:  poprawianie  tekstu  

lex/flex:  Usuwanie  zbędnych  pustych  linii,  wielokrotnych  spacji,  spacji   przed  znakami  przestankowymi  takimi  jak    .,?!  itd.    

/**  definicje  **/   punct    [,.;:!?]   text    [a-­‐zA-­‐Z]   %%   /**  reguły  **/   ”)””  ”+/{punct}    {printf(”)”);}   ”)”/{text}                        {printf(”)  ”);}  

{text}+”  ”+/”)”    {while  (yytext[yyleng-­‐1]==’  ’)  yyleng-­‐-­‐;  ECHO;}  

({punct}|{text}+)/”(”  {ECHO;  printf(”  ”);}  

”(””  ”+/{text}          {while  (yytext[yyleng-­‐1]==’  ’)  yyleng-­‐-­‐;  ECHO;}  

{text}+"  "+/{punct}          {while  (yytext[yyleng-­‐1]==’  ’)  yyleng-­‐-­‐;  ECHO;}  

ˆ”  ”+                            ;   ”  ”+                                        {printf(”  ”);}   .                                              {ECHO;} \n/\n\n                                  ;   \n   {ECHO;} 61  

(62)

Kalkulator  (flex)[3]  

%{!

#include <stdlib.h>!

#include "calc.tab.h"!

%}!

NUMBER [0-9]+!

OP

![+-/*]!

%%!

{NUMBER}

!{ yylval.value = !

!strtol(yytext, 0, 10); return NUMBER; }!

({OP}|\n) !{ return yytext[0]; }!

.

!

!{ ; }!

 

(63)

Praktyka  -­‐  makefile  

YFLAGS != -d # header files! PROGRAM = calc!

OBJS != $(PROGRAM).tab.o lex.yy.o # + inne ! SRCS != $(PROGRAM).tab.c lex.yy.c # + inne! CC != gcc!

all: $(PROGRAM)! .c.o: $(SRCS)!

!$(CC) -c $*.c -o $@ -O! $(PROGRAM).tab.c: $(PROGRAM).y!

!bison $(YFLAGS) $(PROGRAM).y! lex.yy.c: $(PROGRAM).l!

!flex $(PROGRAM).l! calc: $(OBJS)!

!$(CC) $(OBJS) -o $@ -ll -lm!

clean:; !rm -f $(OBJS) core *~ \#* *.o $(PROGRAM) \! !y.* lex.yy.* $(PROGRAM).tab.*!

 

(64)

Literatura  

 

 

1.  Lesk,  Schmidt.  

Lex  –  A  Lexical  Analyzer  Generator.  

2.  Johnson.  Yacc  –  Yet  another  compiler-­‐compiler.  

3.  T.  Niemann.  LEX  &  YACC  TUTORIAL  (epaperpress.com)  

4.  M.  Landwehr.  Flex/bison  tutorial.  

(  hGp://www.capsl.udel.edu/courses/cpeg421/2012/slides/)  

5.  www/developerworks/aix/tutorials/au_lexyacc  

6.  Flex/Bison  Tutorial.    Aaron  Myles  Landwehr  <aron+ta@udel.edu>  

 

 

(65)

Pytania  i  dyskusja  

¨

?  

65  

(66)

na  wszelki  wypadek...  

Dodatki  

(67)

Kalkulator  

Zadanie  1.  

Używając  programów  lex/flex  oraz  yacc/bison  napisać  program  

prostego  kalkulatora  z  odwróconą  notacją  polską,  z  działaniami  +,-­‐,*,/.  

 

Zadanie  2.  

Niech  T={0,  1,  (,  ),  +,  *,  !,  e}  oznacza  zbiór  symboli  terminalnych.  

Zaprojektować    CFG  (context  free  grammar),  która  generuje  wyrażenia  

regularne  nad  alfabetem  {0,1}.  (Patrz:  HopcroR,  Rozdział  5.  G={V,  T,  P,  S},  

gdzie  V  jest  zbiorem  zmiennych,  T  oznacza  symbole  terminalne,  P  jest  

zbiorem  produkcji,  S  jest    symbolem  startowym).  

 

Zadanie  3.  

Rozważyć  CFG  zdefiniowaną  produkcjami:  

 

 S  =>  aSbS  |  bSaS  |  ε.  

Udowodnić,  że  język  L(G)  jest  zbiorem  wszystkich  napisów  o  równej  liczbie  

symboli  a  i  b.  

 

(68)

calc.l  [4]  

%{  

#define  YYSTYPE  double   #include  "calc.tab.h"   #include  <math.h>   extern  double  yylval;   %}  

D    [0-­‐9.]   %%  

[  \t]    {  ;  }  

log  return  LOG;   pi    return  PIVAL;   sin    return  SIN;   cos    return  COS;   tan    return  TAN;   and    return  AND;  

not    return  NOT;   xor    return  XOR;   or    return  OR;   reg    return  REGA;   ans    return  ANS;   fix    return  FIX;     sci    return  SCI;   eng    return  ENG;   const    return  CONST;   bintodec    return  BINTODEC;   dectobin    return  DECTOBIN;  

{D}+  {  sscanf(  yytext,  "%lf",  &yylval  );  return   NUMBER  ;  }  

[a-­‐zA-­‐Z_]+    return  IDENT;   "["    return  OPENREG;   "]"    return  CLOSEREG;    

(69)

calc.l  [4]  cd.  

"<<" !return LEFTSHIFT;! ">>" !return RIGHTSHIFT;! "++" !return INC;! "--" !return DEC;! "+" !return PLUS;! "-" !return MINUS;! "~" !return UNARYMINUS;! "/" !return DIV;! "*" !return MUL;! "^" !return POW;! "!” !return FACT;! (" !return OPENBRACKET;! ")" !return CLOSEBRACKET;! "%" !return MOD;! ! !

"^^" !return XOR;!

"(" !return OPENBRACKET;!

")" !return CLOSEBRACKET;!

"%" !return MOD;!

"^^" !return XOR;!

"!!" !return NOT;!

"=" !return ASSIGN;!

"&&" !return LAND;!

"||" !return OR;!

"|" !return IOR;!

"&" !return AND;!

"~~" !return COMPLEMENT;!

"\n" !return EOLN;!

!

(70)

Metaznaki  wzorców  

Metaznak  

 

 

 

Dopasowanie  

   

.  

 

 

 dowolny  znak  oprócz  nowej

   

\n  

 

 

 newline      

*  

 

 

 zero  lub  więcej  kopii  poprzedniego  wyrażenia  

+  

 

 

 jedna  lub  więcej  kopii  poprzedniego  wyrażenia  

?  

 

 

 zero  lub  jedna  kopia  poprzedniego  wyrażenia  

^  

 

 

 początek  linii

   

$  

 

 

 koniec  linii

   

a|b  

 

 

 a  lub  b      

(ab)+    

 

 jedna  lub  więcej  kopii  ab  (grupowanie)  

   

"a+b"    

 

 literał  "a+b”  

   

[]  

 

 

 klasa  znaków

   

(71)

Przykłady  regexp  i  dopasowań  

Wzorzec   Dopasowanie  

abc   abc  

abc*   ab  abc  abcc  abccc  ...  

abc+   abc  abcc  ...  

a(bc)+   abc  abcbc  abcbcbc  ...   a(bc)?   a  abc  abcbc  ...  

[a-­‐z]   dowolna  litera  a,  b,  ...,z   [-­‐az]   -­‐  lub  a  lub  z  

[a-­‐zA-­‐Z0-­‐9]+   jeden  lub  więcej  znaków  alfanumerycznych   [  \t\n]+   biały  znak  (odstęp,  tabulator,  nowa  linia)   [^ab]   wszystko  oprócz  a,  b  

[a^b]   a  lub  ^  lub  b   [a|b]   a  lub  |  lub  b  

a|b   a  lub  b  

(72)

Redukcja  produkcji  

 

 

 

 E  =>  E  *  E  (r2)    

       =>  E  *  z    (r3)    

       =>  E  +  E  *  z  

 (r1)    

       =>  E  +  y  *  z  

 (r3)    

       =>  x  +  y  *  z  

 (r3)  

 

   

 

   1        .  x  +  y  *  z    shig      2        x  .  +  y  *  z    reduce(r3)      3        E  .  +  y  *  z    shig    

 4        E  +  .  y  *  z    shig    

 5        E  +  y  .  *  z    reduce(r3)      6        E  +  E  .  *  z    shig    

 7        E  +  E  *  .  z    shig    

 8        E  +  E  *  z  .    reduce(r3)    

 9        E  +  E  *  E  .    reduce(r2)  emit  mulhply     10    E  +  E  .    reduce(r1)  emit  add    

11    E  .      accept    

gramatyka  

operacje  na  stosie  

72  

(73)

 za  tydzień  ...  !?

 

 

73  

Cytaty

Powiązane dokumenty

• ochrona autentyczności obrazu (ukryty obraz pełni rolę znaku wodnego (watermark)), w tym przypadku konieczną własnością obrazu ukrytego jest (poza odpornością na

5 Zmiany wymuszenia radiacyjnego (a) oraz temperatury powierzchni ziemi (b) w przypadku kilku gazów cieplarnianych.. Zauważmy, że w przypadku gazów atmosferycznych mających krótki

Despite abundant observational evidence for changes in the energy balance over the past decades1–3 , the formal detection of climate warming and its attribution to human influence

magnetyczny, co oznacza, że gdy spin neutronu jest skierowany w górę, to linie pola magnetycznego w środku dipola są skierowane w dół. strzałka symbolizuje rzut spinu na kierunek

Zbiór M reprezentuje zbiór metod naleŜących do wszystkich klas, zbiór A reprezentuje zbiór atrybutów wszystkich klas, natomiast R jest zbiorem krawędzi, które

wybranych baz danych 6 baz danych.. Wykaz obiektów stanowiących treść mapy zasadniczej jest określony w załączniku nr 5 do rozporządzenia. Specyfikacja pojęciowego

Jeśli opcja Word alignment jest włączona, to pole bit1, pole nienazwane o szerokości 5 oraz pole bity2_10 są pamiętane w pierwszym słowie, pole bit_11 zaczyna się w drugim

Elementy fizyki