Administrivia Arild Fines Studentassistent for INF5110 Tok INF5110 våren 2004 Ingen tradisjonelle gruppetimer Veiledning over epost og/eller ved treffetid arild.fines@broadpark.no 03/02/2005 1
Lex/Flex Automatisk generering av scannere INF 5110-2005 03/02/2005 Institutt for informatikk 2
Hva er lex? Lex er en scanner generator En scanner gjør om en tekstfil til en strøm av tokens Lex er ikke en scanner i seg selv Lex genererer C kode som utfører scanningen C-koden må kompileres og linkes på normalt vis Lex brukes ofte med en parser generator, som oftest yacc/bison Lex ble originalt skrevet som en partner til yacc 03/02/2005 3
Hva er flex? Lex er standard på kommersielle unix-systemer Lex er påkrevd av Posix-standarden Lex er ikke åpen kildekode Flex er et gratis alternativ til lex Alt i denne forelesningen gjelder både for lex og flex 03/02/2005 4
Hvordan brukes lex? Brukeren setter opp regler for hvordan de forskjellige tokens ser ut i en tekstfil Denne filen har tradisjonelt filendingen.l Denne filen blir så konvertert til C-kode av lex flex o lexer.c lexer.l C-koden kompileres og linkes med resten av kompilatoren på normalt vis 03/02/2005 5
Lex-filer Strukturen er som følger: definitions %% rules %% code definitions inneholder deklarasjoner av gjenbrukbare regulære uttrykk DIGIT [0-9] ID [a-z][a-z0-9]* Kan også inneholde blokker med #include statements %{ #include yytab.h %} 03/02/2005 6
Lex-filer(forts) rules er den viktigste delen Inneholder regulære uttrykk og C-kode som utføres når disse uttrykkene matches C-koden brukes ofte til å kommunisere med parseren(yacc) Eks: "false" { return FALSE; } "true" { return TRUE; } {letter}({letter} {digit}){0,15} { yylval.text = strdup(yytext); return NAME; } Dersom det ikke er noen action blir tokenet forkastet code -seksjonen er for hjelperutiner og en evt main() funksjon 03/02/2005 7
Eksempel(stjålet fra flex-manualen) %{ #include <math.h> %} DIGIT [0-9] ID [a-z][a-z0-9]* %% {DIGIT}+ { printf( "An integer: %s (%d)\n", yytext, atoi( yytext ) ); } {DIGIT}+"."{DIGIT}* { printf( "A float: %s (%g)\n", yytext, atof( yytext ) ); } if then begin end { printf( "A keyword: %s\n", yytext ); } {ID} printf( "An identifier: %s\n", yytext ); %% int main( int argc, char** argv) { yyin = fopen( argv[1], r ); yylex(); } 03/02/2005 8
Implementasjon Brukeren definerer et sett med regulære definisjoner Og tilhørende aksjoner som utføres når en definisjon blir matchet Lex gjør om disse til NFA-er Disse kombineres til én stor NFA Gjerne ved bruk av Thompson-konstruksjon Denne konverteres til en DFA ved bruk av subset construction Lex generer så C-kode som implementerer denne DFAen DFAen er vanligvis tabell-drevet Den genererte C-koden er gjerne stygg Har ikke så mye å si man skal ikke redigere denne direkte Så lenge C-kompilatoren skjønner den, er alt bra 03/02/2005 9
Generert kode switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yy_hold_char; yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 21 "lexer.l" { yylval.real = atof( yytext ); return NUMBER; } YY_BREAK case 2: YY_RULE_SETUP #line 22 "lexer.l" { return REAL; } YY_BREAK case 3: YY_RULE_SETUP #line 23 "lexer.l" { return BOOL; } YY_BREAK case 4: YY_RULE_SETUP #line 24 "lexer.l" { return PROC; } 03/02/2005 10
Mer generert kode static yyconst short int yy_chk[176] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 23, 15, 15, 25, 25, 26, 29, 23, 32, 38, 38, 58, 138, 26, 32, 39, 29, 39, 39, 57, 64, 64, 57, 75, 105, 106, 58, 75, 105, 106, 124, 137, 124, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 123, 102, 99, 98, 96, 92, 88, 87, 86, 83, 81, 80, 79, 78, 77, 76, 74, 72, 71, 70, 69, 68, 62, 61, 60, 59, 54, 51, 50, 49, 47, 46, 45, 42, 35, 34, 33, 31, 30, 28, 27, 24, 22, 20, 19, 18, 16, 14, 12, 9, 5, 3, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; 03/02/2005 11
Bruk av lex med yacc Lex ble designet til å fungere bra sammen med yacc Yacc kaller yylex() hver gang den trenger et nytt token Lex definerer yylex(): Finner en rule som matcher input Utfører en action assosiert med den regelen: "if" { return IF; } Yacc definerer også en global variabel yylval som kan brukes til å formidle ytterligere informasjon: {real} { yylval.real = atof( yytext ); return NUMBER; } 03/02/2005 12
Lex og yacc(forts) Man kan bruke opsjonen d til yacc/bison for å generere en header fil med alle %tokens i Yacc-fila I parser.y: %token PLUSOP MINUSOP MULTOP DIVIDEOP POWEROP ASSIGN %token OR AND NOT LT LTEQ GT GTEQ NOTEQ EQ I lexer.l: %{ #include y.tab.h %} //... "=" { return EQ; } "+" { return PLUSOP; } "-" { return MINUSOP; } 03/02/2005 13
Spyrgesmål? INF 5110-2005 03/02/2005 Institutt for informatikk 14