Miroslav Beneš Dušan Kolář Lexikální analýza Miroslav Beneš Dušan Kolář
Rozhraní lexikálního analyzátoru Lexikální analýza M. Beneš, D. Kolář: Lexikální analýza
Úkoly Čtení zdrojového textu Sestavování symbolů Odstranění mezer a poznámek Normalizace symbolů (velká/malá písmena, spec. znaky, ...) Interpretace direktiv překladače Uchovávání informací pro hlášení chyb Zobrazení protokolu o překladu Lexikální analýza
Proč řešit lexikální analýzu samostatně? Jednodušší návrh překladače Konvence pro mezery a poznámky Vyšší efektivita Specializované algoritmy Lepší přenositelnost Zvláštnosti vstupní abecedy ??( = [ Lexikální analýza
Základní pojmy Lexém – slovo nad abecedou Kategorie symbolů – identifikátor, číslo, relační operátor, levá závorka, ... Atributy symbolu – řetězec, hodnota, kód operátoru, ... Reprezentace symbolu – dvojice (kategorie, atribut) Lexikální analýza
Příklady lexikálních symbolů Lexikální analýza
Reprezentace symbolů // kategorie symbolů enum Symbol { IdSym, NumSym, RelOpSym, DotSym, ... }; // kategorie operátorů enum Oper { LthOp, GthOp, LeqOp, ... }; // atributy symbolů union LexAttr { char* id; int num; Oper relop; ... }; // reprezentace lexikálního symbolu struct Token { Symbol sym; // kategorie LexAttr attr; // atribut Lexikální analýza
Problémy se zdrojovým jazykem Pevný/volný formát (FORTRAN) 12 X=7 * +12*K C poznámka Zpracování mezer (FORTRAN, Basic) DO5I=1.25 / DO5I=1,25 Klíčová slova (PL/I) IF THEN THEN THEN=ELSE; ELSE ELSE=THEN Lexikální analýza
Příklad 1 INTEGER FUNCTIONA 2 PARAMETER(A=6,B=2) 3 IMPLICIT CHARACTER*(A-B)(A-B) 4 INTEGER FORMAT(10),IF(10),DO9E1 5 100 FORMAT(4H)=(3) 6 200 FORMAT(4 )=(3) 7 DO9E1=1 8 DO9E1=1,2 9 IF(X)=1 ... Lexikální analýza
Příklad (pokr.) 10 IF(X)H=1 11 IF(X)300,200 12 300 CONTINUE 13 END C this is a comment $FILE(1) 14 END Lexikální analýza
Specifikace symbolů Popis běžným jazykem ‘identifikátor je posloupnost písmen a číslic začínající písmenem’ Regulární (lineární) gramatika I -> p X X -> p X | c X | p | c Regulární výrazy a definice p (p | c)* Lexikální analýza
Specifikace symbolů Graf přechodů konečného automatu (syntaktický graf) Lexikální analýza
Specifikace symbolů Lexikální symboly lze obvykle popsat regulárními jazyky (typ 3) Co nedokážeme popsat? Zanořené konstrukce (závorky) Opakované konstrukce {wcw|w{a,b}*} Zadaný počet opakování nHa1a2…an (FORTRAN) Lexikální analýza
Regulární výrazy nad RE označuje {} (prázdný řetězec) Je-li a, pak a označuje {a} Je-li a,b,c,…, pak [abc…] označuje množinu {a, b, c, …} [aeiouy] [a-zA-Z] [^0-9] – všechno kromě [0-9] Lexikální analýza
Regulární výrazy Jsou-li s, t reg. výrazy označující jazyky L(s) a L(t), pak (s) | (t) L(s) L(t) (s) (t) L(s) L(t) (s)* (L(s))* (s)+ (L(s))+ = L(s) (L(s))* (s)? L(s) {} (s) L(s) Lexikální analýza
Příklad [A-Z]([A-Z]|[0-9])* [A-Z][A-Z0-9]* [0-9]+.[0-9]+(E[-+]?[0-9]+)? | [0-9]+E[-+]?[0-9]+ Lexikální analýza
Regulární definice Pojmenované regulární výrazy d1 -> r1 d2 -> r2 ... dn -> rn různá reg. výrazy nad jména {d1, d2,…, di-1} Lexikální analýza
Regulární definice Použití: konstruktory lex. analyzátorů letter -> [A-Za-z] digit -> [0-9] id -> letter (letter | digit)* Použití: konstruktory lex. analyzátorů Lexikální analýza
Konečné automaty (Q, , f, q0, F) - vstupní abeceda Q – konečná množina stavů - vstupní abeceda f – přechodová funkce q0 – počáteční stav F – množina koncových stavů f: Q x ( {e}) -> 2Q rozšířený NKA f: Q x -> Q DKA Lexikální analýza
Konečné automaty desítkové číslo šestnáctkové číslo Lexikální analýza
Konečné automaty NKA Lexikální analýza
Konečné automaty deterministický konečný automat Lexikální analýza
Algoritmy pro transformaci Reg. gramatika ↔ konečný automat korespondence pravidel gramatiky a přechodové funkce Reg. výraz → konečný automat skládání primitivních KA, převod na DKA, minimalizace stromová reprezentace důležité pro konstruktory lex. analyzátorů Lexikální analýza
Algoritmy pro transformaci Konečný automat → reg. výraz soustava algebraických rovnic X = a X + b X = a* b derivace reg. výrazu Lexikální analýza
Konečný automat pro lexikální analýzu Zpracování začíná vždy prvním dosud nezpracovaným znakem ze vstupu Zpracování končí, je-li automat v koncovém stavu a pro další vstupní znak již neexistuje žádný přechod (maximal match): 123 není 12 následované 3 Není-li v nekoncovém stavu přechod možný, vrací se automat do posledního dosaženého koncového stavu nebo je chyba: < <= << 1. 1.2 1..5 Lexikální analýza
Speciální případy akce po přijetí symbolu klíčová slova samostatný koncový stav pro každou kategorii výpočet hodnot atributů z lexému klíčová slova koncový stav pro každé klíčové slovo – mnoho stavů obvykle jako id, pak následuje rozlišení tabulkou klíč. slov Lexikální analýza
Speciální případy komentáře znakové řetězce uzavřená cesta procházející poč. stavem diagnostika – neukončený komentář dokumentační komentář – Javadoc zanořené komentáře znakové řetězce escape sekvence ‘\n’ ukončení řádku v řetězci je obvykle chyba Unicode Lexikální analýza
Implementace lexikálního analyzátoru Přímá Efektivita na úkor složitosti návrhu Stav je reprezentován pozicí v programu Simulace konečného automatu Vhodné spíš pro konstruktory Využití konstruktoru Snadná modifikovatelnost Především v počátečních fázích implementace Lexikální analýza
Přímá implementace char text[256]; int leng, ival; int lex(void) { int ch; START: while((ch=getchar())==‘ ‘) ; /* odstranění mezer */ Lexikální analýza
Přímá implementace if( isalpha(ch) ) { leng = 0; do { text[leng++] = ch; } while( isalnum(ch=getchar()) ); text[leng] = ‘\0’; ungetc(ch,stdin); return(IDENT); } Lexikální analýza
Přímá implementace else if( isdigit(ch) ) { ival = 0; do { ival = 10*ival+(ch-’0’); } while( isdigit(ch=getchar()) ); ungetc(ch,stdin); return(NUM); } Lexikální analýza
Přímá implementace else if (ch==‘{‘) { while( (ch=getchar())!=‘}’ && ch!=EOF); if( ch==EOF ) { error(“Missing end of comment”); return(EOF); } goto START; else return(ch); /* ostatní znaky */ Lexikální analýza
Přímá implementace getchar() ungetc() čte znaky ze vstupu udržuje aktuální číslo řádku kopie zdrojového textu do protokolu správa vyrovnávacích pamětí makrogenerátor (např. C, C++) ungetc() vrací zpět jeden nebo více znaků Java: java.io.PushbackInputStream Lexikální analýza
Implementace konečného automatu Tabulka + Přechodová funkce + Interpret výhodné jako výstup konstruktoru Přímý přepis do programu Lexikální analýza
Implementace konečného automatu static int state; int next(int newstate) { state = newstate; return getchar(); } int lex(void) { int ch = next(0); Lexikální analýza
Implementace konečného automatu for(;;) switch(state) { case 0: if (ch==‘ ‘) ch = next(0); else if( isalpha(ch) ) { leng = 0; text[leng]=ch; ch = next(1); } Lexikální analýza
Implementace konečného automatu /* case 0: */ else if (isdigit(ch)) { ival = ch-’0’; ch = next(2); } else if (ch==‘{‘) ch = next(3); else return(ch); break; Lexikální analýza
Implementace konečného automatu case 1: if (isalnum(ch)) { text[++leng] = ch; ch = next(1); } else { text[++leng] = ‘\0’; unget(ch,stdin); return(IDENT); break; Lexikální analýza
Implementace konečného automatu Lexikální analýza
Implementace konečného automatu case 3: if (ch==EOF) { error(“Missing end of comment”); return(EOF); } else if (ch==‘}‘) ch = next(0); else ch = next(3); break; Lexikální analýza
Konstruktor LEX / FLEX %{ #include <stdlib.h> #define IDENT 256 #define NUM 257 int yyival; %} Lexikální analýza
Konstruktor LEX / FLEX space [ \t\n] ws {space}+|\{[^}]*\} letter [A-Za-z] digit [0-9] id {letter}({letter}|{digit})* number {digit}+ %% Lexikální analýza
Konstruktor LEX / FLEX {ws} {/* no action, no return */} {id} return(IDENT); {number} { yyival=atoi(yytext); return(NUM); } . return(yytext[0]); Lexikální analýza