Poznajemy generator analizatorów leksykalnych dla naszego języka programowania. Może to obejmować Flex (C/C++), Alex (Haskell), ewentualnie JFlex (Java) i inne generatory.
W programie napisanym na poprzednim laboratorium, analizator leksykalny zamieniamy na wygenerowany przy pomocy odpowiedniego generatora.
Omawiamy przykład analizatora stworzonego przy uzyciu Flexa, np.
%{ // #include "exp.tab.h" /* Definiuje leksemy, np. NUM */ #define NUM '9' int yylval; %} %option noyywrap %% [0-9]+ { yylval = atoi( yytext ) ; return (int)NUM; } . { return (int)(yytext[0]); } \n { return (int)'\n'; } %% int main() { int lexem; while(lexem=yylex()) { ... } return 0; }
Uruchamianie:
flex -o lexer.c lexer.l
Wygenerowany plik (tu: lexer.c) zawiera funkcję yylex()
, której kolejne wywołania dają kolejne leksemy (0 dla EOF jeśli nie ma innych wytycznych)
Omawiamy przykład, np.
%% %class Scanner %type Symbol %unicode %line %{ StringBuffer string = new StringBuffer(); // Leksemy są klasy Symbol, zdefiniowanej poza tym plikiem private Symbol symbol(int type) { return new Symbol(type, yyline, -1); } private Symbol symbol(int type, Object value) { return new Symbol(type, yyline, -1, value); } %} WhiteSpace = (LineTerminator | [ \t\f]) DecIntLiteral = 0 | [1-9][0-9]* %% (0|[1-9][0-9]*) { return symbol(sym.NUM, new Integer(yytext())); } {WhiteSpace} { } . { System.out.println("Unexpected character:"+yytext());}
Z tej specyfikacji JFlex wygeneruje klasę (tu: Scanner) zawierającą kod leksera. Konstruktor tej klasy bierze jako argument klasy java.io.Reader
reprezentujący strumień wejściowy. Kolejne wywołania metody yylex()
z tej klasy dają kolejne leksemy (null dla EOF w tym wypadku)
Omawiamy przykład, np.
{ module CalcLex(alexScanTokens) where import CalcToken(Token(..)) } %wrapper "basic" $digit = 0-9 tokens :- $white+ ; -- whitespace "--".* ; -- comment $digit+ {\s -> Int (read s)} [\=\+\-\*\/\(\)] {\s -> Sym (head s)}
Przykład uzycia:
$ alex CalcLex.x $ ghci CalcLex.hs GHCi, version 6.12.1... Ok, modules loaded: CalcLex, CalcTokens. *CalcLex> alexScanTokens "let x = 1 in x +x" [Let,Var "x",Sym '=',Int 1,In,Var "x",Sym '+',Var "x"]