Generování syntaktických analyzátoru
Transkript
A Tutorial Generovánı́ syntaktických analyzátorů George J. Klir Jan Konečný State University of New York (SUNY) Binghamton, New York 13902, USA [email protected] Palacky University, Olomouc, Czech Republic ! prepared for International Centre for Information and Uncertainty, Palacky University, Olomouc ! ! ! J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 1 / 28 lex & yacc Nástroje pro psanı́ programů, které zpracovávajı́ (transformujı́) strukturované vstupy. Dva hlavnı́ požadavky na takové programy: rozdělenı́ vstupu do smysluplných jednotek. nalezenı́ vztahů mezi těmi jednotkami. lex je nástroj pro vytvářenı́ lexikálnı́ch analyzátorů (též lexerů). yacc (Yet Another Compiler Compiler) je nástroj pro vytvářenı́ syntaktických analyzátorů (též parserů). J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 2 / 28 Lex Struktura vstupnı́ho souboru: sekce definic %% sekce pravidel %% sekce C kódu Výstupem je kód v C sekce definic definuje makra a importuje hlavičkové soubory v C. Též je možno psát sem jakýkoli kód v C. sekce pravidel spojuje regulárnı́ výrazy s kódem v C. Když je rozpoznán text odpovidajı́cı́ regulárnı́mu výrazu, je spuštěn odpovı́dajı́cı́ kód. sekce C kódu obsahuje libovolný kód v C, J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 3 / 28 Prvnı́ easy example: Example Specifikace pro desetinná čı́sla %% [\n\t ] ; -?(([0-9]+)|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { printf("number\n"); } . ECHO; %% main() { yylex(); } J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 4 / 28 Prvnı́ easy example: Example (cont.) Překlad: > lex first.l > cc lex.yy.c -o first -ll Spuštěnı́: .65ea12 number eanumber J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 5 / 28 Počı́tánı́ slov Vytvořı́me program na počı́tánı́ slov, podobný UNIXovému programu wc. Definičnı́ sekce: %{ unsigned charCount = 0, wordCount = 0, lineCount = 0; %} word [^ \t\n]+ eol \n Sekce pravidel: %% {word} { wordcount++; charcount += yyleng; } {eol} { charcount++; linecount++; } . charcount++; J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 6 / 28 Sekce C kódu: main() { yylex(); printf("%d %d %d\n", lineCount, wordcount, charcount); } nedělá to nic zvláštnı́ho, jen využı́vá toho, že lex defaultně čte ze standardnı́ho vstupu. pokud bychom to chtěli vylepšit. . . J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 7 / 28 main(argc,argv) int argc ; char **argv; { if (argc > 1) { FILE *file; file = fopen(argv[l], "r"); if (!file) { fprintf(stderr,"could not open %s\n",argv[1]); exit(1); } yyin = file; } yylex(); printf("%d %d %d\n",charCount, wordCount, linecount); return 0; } J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 8 / 28 Parsovánı́ přı́kazové řádky % { unsigned verbose; char *progName; % } %% -h | "-?"| -help { printf("usage is: %s [-help | -h | -? ]" "[-verbose | -v] [(-file | -f) filename]\n", progName); } -v | -verbose { printf ("verbose mode is on\n"); verbose = 1; } J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 9 / 28 %% main(argc, argv) int argc; char **argv; { progName = *argv; yylex(); } Problém: tohle ale ještě nečte z přı́kazové řádky, ale ze vstupu. Řešenı́: můžeme předefinovat funkce input a unput, aby zacházely s argv. Problém: ještě nemáme -file <filename>. Řešenı́: lex umožňuje použı́t alternativnı́ počátečnı́ stavy a zahrnout tak kontextovou závislost. J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 10 / 28 Generátor syntaktických analyzátorů vstup: gramatika (LL(1), LR(1), SLR, LALR(1)) výstup: syntaktický analyzátor – rozhoduje platná slova gramatiky. Prvnı́ co zkusı́me: statement → NAME = expr expr → NUMBER | expr + NUMBER | expr - NUMBER J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 11 / 28 Shift/Reduce Parsing; trocha velmi zjednodušené teorie Generátor podle gramatiky vytvořı́ množinu stavů, každý z nich odpovı́dá možné pozici v jednom nebo vı́ce částečně parsovaného pravidla. Parser čte tokeny: pokud token neukončuje pravidlo, uložı́me ho na zásobnı́k a přesuneme se jiného stavu =shift, přesun, symboly na zasobnı́ku tvořı́ pravou stranu pravidla, popnem je, a pushnem levou stranu pravida =redukce. při redukci je spuštěn odpovı́dajı́cı́ kousek kódu =akce. http://vychodil.inf.upol.cz/publications/white-papers/lalr.pdf J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 12 / 28 Vstup pro yacc vstup má stejnou strukturu jako vstup lexu. Sekce definic %token NAME NUMBER Sekce pravidel %% statement: NAME ’=’ expr | expr ; expr: expr ’+’ NUMBER | expr ’-’ NUMBER | NUMBER ; J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 13 / 28 Hodnoty symbolů a akce každý symbol má hodnotu neterminálnı́ symboly majı́ hodnotu vytvořenou kódem v parseru (ve skutečných parserech různé datové typy ⇒ union typedef YYSYTYPE). Defaultně je vše int. Kdykoli parser redukuje, spustı́ uživatelský kód asociovaný k pravidlu – akce. Akce se odkazuje na hodnoty symbolů na pravé straně jako $1, $2. . . a nastavuje hodnotu symbolu na levé straně přes $$. J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 14 / 28 Sekce pravidel (s doplněnými akcemi) statement: NAME ’=’ expr | expr { printf("= %d\n",$1); } ; expr: expr ’+’ NUMBER { $$ = $1 + $3; } | expr ’-’ NUMBER { $$ = $1 - $3; } | NUMBER { $$ = $1; } ; J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 15 / 28 Lexer Abychom mohli vyzkoušet náš parser, potřebujeme mu dodat tokeny. %{ #include "y.tab.h" extern int yylval; %} %% [0-9]+ { yylval = atoi(yytext) ; return NUMBER;} [ \t] ; /* ignore whitespace */ \n return 0; /* logical EOF */ . return yytext[0]; %% J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 16 / 28 > yacc -d calc.y > lex calc.1 > cc -c calc y.tab.c lex.yy.c -ly -ll > calc 99+12 = 111 > calc 2 + 3-14+33 = 24 > calc 100 + -50 syntax error J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 17 / 28 Aritmetické výrazy a nejednoznačnost expr: expr ’+’ expr { $$ = $1 + $3; } | expr ’-’ expr { $$ = $1 -$3; } | expr ’*’ expr { $$ = $1 * $3; } | expr ’/’ expr { if ($3 == 0) yyerror( "divide by zero") ; else $$ = $1 / $3; } | ’-’ expr { $$ = -$2; } | ’(’ expr ’)’ { $$ = $2; } | NUMBER { $$ = $1; } J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 18 / 28 Ta gramatika má ale problém – nejednoznačnost. Example Parsujeme ”2+3*4”: 2 přesuň NUMBER E redukce E → NUMBER E+ přesuň + E+3 přesuň NUMBER E+E redukce E → NUMBER ’ Ted můžeme přesunout ’*’ a později redukovat přes pravidlo E→E*E nebo rovnou redukovat E→E+E Neřekli jsme, který operátor má přednost, ani nic o asociativitě. J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 19 / 28 Mohli bychom to řešit přı́mo v gramatice: expr: expr ’+’ mlexp | expr ’-’ mlexp | mlexp ; mlexp: mlexp ’*’ primary | mlexp ’/’ primary | primary ; primary: ’(’ expr ’)’ | ’-’ primary | NUMBER ; J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 20 / 28 Můžeme to ale dodat explicitně %left ’+’ ’-’ %left ’*’ ’/’ %nonassoc UMINUS J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 21 / 28 statement: NAME ’=’ expr | expr { printf ("= %d\n", $1) ; } expr: expr ’+’ expr { $$ = $1 + $3; } | expr ’-’ expr { $$ = $1 -$3; } | expr ’*’ expr { $$ = $1 * $3; } | expr ’/’ expr { if ($3 == 0) yyerror("divide by zero"); else $$ = $1 / $3;} | ’-’ expr %prec UMINUS { $$ = -$2; } | ’(’ expr ’)’ { $$ = $2; } | NUMBER { $$ = $1; } ; %% J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 22 / 28 Proměnné a typované tokeny (a vı́ce vyhodnocovaných výrazů) %{ double vbltable[26]; %} %union { double dval; int vblno; } %token <vblno> NAME %token <dval> NUMBER %left ’+’ ’-’ %left ’*’ ’/’ %nonassoc UMINUS %type <dval> expression %% J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 23 / 28 statement-list: statement ’\n’ | statement-list statement ’\n’ statement: NAME ’=’ expr { vbltable[$l] = $3; } | expr { printf ("= %g\n", $1) ; } expr: · · · | NAME { $$ = vbltable[$1]; } ; J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 24 / 28 %{ #include <y.tab.h> #include <math.h> extern double vbltable[26]; %} %% ([0-9]+)|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { yylval.dval=atof(yytext); return NUMBER; } [ \t]; [a-z] { yylval.vblno = yytext[0] - ’a’; return NAME; } "$" { return 0; /* end of input */ } \n | . return yytext[0]; %% J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 25 / 28 v souboru y.tab.h: #define NAME 257 #define NUMBER 258 #define UMINUS 259 typedef union { double dval; int vblno; } YYSTYPE; extern YYSTYPE yylval; Proto uvádı́me %token <vblno> NAME %token <dval> NUMBER %type <dval> expression J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 26 / 28 Jak to ještě můžem vylepšit libovolná jména pro proměnné. funkce (sqrt, log, exp) DOMACÍ UKOL ... J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 27 / 28 Chcete vědět vı́c? Bison manual: http://www.gnu.org/software/bison/manual/bison.pdf LALR Gramatiky (VV) http://vychodil.inf.upol.cz/publications/white-papers/lalr.pdf lex & yacc, 2nd Edition By Doug Brown, John Levine, Tony Mason, Publisher: O’Reilly Media Released: October 1992 J. Konečný (DAMOL) Generovánı́ syntaktických analyzátorů 12. května 2014 28 / 28
Podobné dokumenty
13 FormalniPřeklad
3 entries saved by goto default
Optimizer space used: input 40/12000, output 218/12000
218 table entries, 204 zero
maximum spread: 257, maximum offset: 42
13 FormalniPřeklad
9/600 distinct lookahead sets
4 extra closures
14 shift entries, 1 exceptions
7 goto entries
3 entries saved by goto default
Optimizer space used: input 40/12000, output 218/12000
218 table entries...
Moduly a namespace
−> LexBuffer<’cty> −> Ast.Expr
try Parser.start (Lexer.tokenize) lexbuf
with e −> let pos = lexbuf.StartPos
failwithf "Error at line %d col %d: %s" pos.Line pos.Column e.Message
JSON Schema v praxi - Zdroják
textovém souboru (vhodné např. k verzování), jehož obsah je v nezávislém, standardním formátu (řádka knihoven pro různé jazyky). Můžeme tak bez problémů
tuto „specifikaci“ pro data přijímaná naším ...
Fakulta jaderná a fyzikáln¥ inºenýrská
je nutná nová instalace stabilizace polohy plazmatu. Teoretická £ást této práce
obsahuje rovnice pro horizontální a vertikální ur£ení polohy plazmatu a koecientu asymetrie. Dále je tu odvozena Gra...
Cvicení - Geocomputation
Většinou se první probírají množiny, které se ale špatně popisují bez znalosti proměnných a výroků. Obejít se bez proměnných a množin u výroků nebo množin u proměnných také nejde. Začínáme ...
Program, jeho syntax a sémantika - Vilem Vychodil
Doporučená literatura:
Sperber M., Dybvig R., Flatt M., Van Straaten A., Findler R., Matthews J.:
Revised6 Report on the Algorithmic Language Scheme.
Journal of Functional Programming 19(S1)2009, 1...