Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Grammatikexempel Syntaxanalys Senast DCG i Prolog Verktyg för Java Avslutning Idag • Grammatiker Intro • Ändliga automater med stack • Grammatikexempel • Backus-Naur-form (BNF), notation för • Att generera syntaxanalysatorer grammatiker • Exempel för Newick-träd • Rekursiv medåkning (recursive descent) • Lexikal analys • DCG i Prolog Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java • Lex/Yacc i C/C++ • Lite om JFlex/CUP för Java Avslutning Intro Grammatikexempel Exempel: Lava Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Exempel: Lava program → headers stmnt_list stmnt_list → statement | stmnt_list S EMI C OLON statement statement → B EGIN stmnt_list E ND | assignment | while_statement | if_statement | ... assignment → VARIABLE A SSIGN expression while_statement → W HILE bool_expr D O statement if_statement → I F bool_expr T HEN statement E LSE statement | I F bool_expr T HEN statement Problem: Grammatiken kräver ”extra lookahead” Terminaler: S EMI C OLON, B EGIN, E ND Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Förbättring av if-satsen Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Att generera syntaxanalysatorer if_statement → I F bool_expr T HEN statement else_clause else_clause → E LSE statement | parserGenerator :: BNF → kod → parser • Syfte: Att automatisera tråkig programmering Kvarstående problem: Hur tolkas if (x>y) then if (x>z) then runTests() else runSimpleTests() Grammatiken är tvetydig. Intro Grammatikexempel Syntaxanalys DCG i Prolog • Minskar risken för syntax-buggar • Lättare för andra att arbeta med koden • Kan få snabb parser: Verktyg ofta väloptimerade Verktyg för Java Avslutning Intro Grammatikexempel Varför inte rekursiv medåkning? Syntaxanalys DCG i Prolog Verktyg för Java Ny grammatikklass: LR(k ) • LR(k ) är läsning vänster-till-höger, och • Rekursiv medåkning kan vara bästa alternativet • RM är för LL(k )-parsers: Läs vänster-till-höger, vänsterhärledning, k ”lookahead”. • Exv ANTLR genererar rekursiv medåkning. • Prediktiv grammatik kan vara en begränsning. • • • • högerhärledning. Styrka: LL ⊂ LR ”LR-parser hittar fel tidigare.” Jobbigt att implementera LR-parser för hand: Behöver verktyg. (Implementeras som en ändlig automat med stack.) Bra på vänsterrekursion, högerrekursion riskerar ineffektivitet (“många element på stacken”). Avslutning Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Parsergeneratorer Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning DCG för syntaxanalysatorer i Prolog • DCG: Definite Clause Grammar • Syntax för produktioner: • • Brett fält Många verktyg: Vi tittar på de enkla • • • • DCG i Prolog JFlex och CUP för Java • • • Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Exempel: Newickträd Huvud --> Kropp. Atomer är terminaler. Syntaktiskt socker för Prolog-satser Utnyttjar Prologs backtracking för syntaxanalysen Klarar av godtycklig kontextfri grammatik. ”Killer feature”: Jobbar åt båda hållen! Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Newickträd i DCG Vi hade: newick → tree semiColon semiColon → SemiColon | tree → Leaf | LeftParen tree Comma tree RightParen • Nu: använd DCG • Givet lista av atomer, bygg trädstruktur. • Först lexikal analys: ASCII ⇒ terminaler • Sen: Låt DCG tolka listan Terminaler är Leaf, LeftParen, RightParen, Comma och SemiColon. Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Lexikal analys: mål Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Hjälpande kod 1 openParen). closeParen). comma). space). semicolon). Verktyg för Java Avslutning Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Hjälpande kod 2 -- Här kommer en viktig symbol lex([C|S], [Symbol|Terminals]) :char2symbol(C, Symbol), lex(S, Terminals). char2symbol(40, char2symbol(41, char2symbol(44, char2symbol(32, char2symbol(59, DCG i Prolog lex([], []). -- Ta bort mellanslag lex([32|S], Terminals) :lex(S, Terminals). -- Här kommer en viktig symbol lex([C|S], [Symbol|Terminals]) :char2symbol(C, Symbol), lex(S, Terminals). -- Ett ord: lagra som sammansatt term lex(S, [w(Symbol)|Terminals]) :firstWord(S, W, NextS), atom_codes(Symbol, W), lex(NextS, Terminals). Hur skriva lex? Grammatikexempel Syntaxanalys Lexikal analysator | ?- atom_codes(’(mus, (apa, jag));’, L), lex(L, Syms). L = [40,109,117,115,44,32,40,97,112,97|...], Syms = [openParen,w(mus),comma,openParen, w(apa),comma,w(jag),closeParen, closeParen,semicolon] ? n no | ?- Intro Grammatikexempel % % % % % ’(’ ’)’ ’,’ ’ ’ ’;’ -- Ett ord: lagra som sammansatt term lex(S, [w(Symbol)|Terminals]) :firstWord(S, W, NextS), atom_codes(Symbol, W), lex(NextS, Terminals). firstWord([X|Xs], W, Next) :firstWordI([X|Xs], W, Next), length(W, L), L>1. firstWordI([],[],[]). firstWordI([C|S], [], [C|S]) :\+ character(C). --Eget predikat. Rätt Ascii? firstWordI([C|S], [C|RestOfWord], Next) :character(C), --Eget predikat. Rätt Ascii? firstWordI(S, RestOfWord, Next). Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Grammatikexempel Syntaxanalys Syntaxanalysatorn Observationer --> --> --> --> [semicolon]. []. leaf. [openParen], tree, [comma], tree, [closeParen]. --> [w(X)]. leaf Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning • Syntaxanalysatorn kortare än lexern • Inget slutresultat: samlar inte ihop någon data! • newick ger syntaxkoll. Intro Grammatikexempel DCG igen, med datastruktur leaf(X) Intro Grammatikexempel tree(T), semi. [semicolon]. []. leaf(X), {L = l(X)}. [openParen], tree(T1), [comma], tree(T2), [closeParen]. --> [w(X)]. DCG i Prolog Verktyg för Java Avslutning Intro Grammatikexempel Syntaxanalys Expansion av DCG-produktioner Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Verktyg för Java Avslutning DCG i Prolog Verktyg för Java Avslutning DCG för er newick --> tree, semi. semi --> [semicolon]. semi --> []. Översättning till predikat newick(In, Out) :tree(In, Remaining), semi(Remaining, Out). semi(In, Out) :’C’(In, semicolon, Out). semi(In, Out) :Out = In. ’C’([X|Terminals], X, Terminals). Intro DCG i Prolog | ?- parseTree(T). |: (mus, (gris, sapiens)); T = b(l(mus),b(l(gris),l(sapiens))) ? yes | ?- newick(b(l(apa), l(mus)), L, []). L = [openParen,w(apa),comma,w(mus), closeParen,semicolon] ? n L = [openParen,w(apa),comma,w(mus), closeParen] ? n no | ?- --> --> --> --> --> Syntaxanalys Syntaxanalys Exempelkörning igen % Unifiera X till träd läst från stdin: parseTree(X) :read_line(T), lex(T, Symbols), newick(X, Symbols, []). newick(T) semi semi tree(L) tree(b(T1,T2)) Avslutning | ?- atom_codes(’(mus, (apa, jag));’, L), lex(L, Syms), newick(Syms, []). L = [40,109,117,115,44,32,40,97,112,97|...], Syms = [openParen,w(mus),comma,openParen, w(apa),comma,w(jag),closeParen, closeParen,semicolon] ? n no | ?- DCG newick --> tree, semi. Intro Verktyg för Java Provkörning BNF newick → tree semiColon semiColon → SemiColon | tree → Leaf | LeftParen tree Comma tree RightParen semi semi tree tree DCG i Prolog • Används i S3 • Mycket smidig syntaxanalysator • Alla kontextfria grammatiker • Kan hantera tvetydiga grammatiker. Bra? Dåligt? Avslutning Intro Grammatikexempel Generera en lexer med JFlex Syntaxanalys DCG i Prolog Verktyg för Java Avslutning JFlex-exempel (otestat) import java.lang.System; import java_cup.runtime.Symbol; • Läser enkel specifikation: genererar en lexer • Härstammar från Unix-verktyget lex. • Idé: Ange reguljära uttryck och vad de ska generera för terminal. \w+@\w+.com { return new Symbol(sym.EMAIL);} • Kan användas utan grammatik. String → String %% %cup %class Lexer • • • STR = \w+ WHITE = [ \t\n]+ • • %% • "(" { ")" { , { ";" { {STR} { {WHITE} return return return return return { } (new (new (new (new (new Symbol(sym.LEFTPAREN)); } Symbol(sym.RIGHTPAREN)); } Symbol(sym.COMMA)); } Symbol(sym.SEMICOLON)); } Symbol(sym.NAME, yytext())); } Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Grammatikexempel Java CUP Intro Syntaxanalys DCG i Prolog Verktyg för Java Java CUP • CUP: Constructor of Useful Parsers • Infil beskriver en BNF • CUP härstammar från Unix-klassikern • Kan krydda BNF med actions Yacc/Bison. Yacc: Yet Another Compiler-Compiler • Tydligare syntax, ”äkta” BNF • Genererar LALR-parser, en algoritm för LR • Implementeras som en automat med stack • Utfil definierar parser klass med metoden Grammatikexempel Syntaxanalys DCG i Prolog Avslutning Verktyg för Java Avslutning parse • Definierar gränssnitt för lexikal analys. • Skriv egen lexer • Använd JFlex • Tag klassen Scanner Intro Cup-grammatik: Början Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Cup-grammatik: Slutet import java_cup.runtime.*; /* Newick grammar */ newick ::= tree semicolon; /* Declare the terminals */ terminal LEFTPAREN; terminal RIGHTPAREN; terminal COMMA; terminal SEMICOLON; terminal String NAME; // Ett värde följer med terminalen semicolon ::= SEMICOLON | ; tree ::= leaf | LEFTPAREN tree COMMA tree RIGHTPAREN ; /* Declare non-terminals */ non terminal Tree newick; // Dessa variabler ges ett värde non terminal Tree tree; non terminal Tree leaf; non terminal semicolon; leaf ::= NAME; ... Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Grammatikexempel Lägg till semantik i CUP Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Lab SYx2: Java CUP och JFlex • Engelska meningar för tänkt äventyrsspel • Start: • En lexer • En CUP-grammatik • Lite Java-kod Förstår primitiva meningar: “go north.” • Uppgifter: • Utöka lexern • Små justeringar på grammatiken • Större ändring: Konjunktioner “Go north, go west, and go north.” DCG i Prolog Verktyg för Java Avslutning Användning /* Början på filen är oförändrad */ newick ::= tree:t semicolon {: RESULT = t :} ; semicolon ::= SEMICOLON | ; tree ::= leaf:t {: RESULT = t; :} | LEFTPAREN tree:t1 COMMA tree:t2 RIGHTPAREN {: RESULT = new Branch(t1, t2); :} ; leaf ::= NAME:l {: RESULT = new Leaf(l); :} ; Intro Syntaxanalys • Newick.cup ⇒ Newick.java, sym,java • lexer.lex ⇒ Lexer.java • Huvudprogram, ungefär: public static void main(String args[]) throws Exception { Lexer lex = new Lexer(System.in); Newick parser = new Newick(lex); Tree t = parser.parse(); } Avslutning Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Sammanfattning om CUP • Gammal god Yacc-tradition, snygg implementation • Svagheter: • Mycket att skriva • Felhantering sker ej enkelt • Avlusning svårt? • Klassisk svårighet: “shift/reduce-konflikter” Symptom på tvetydig grammatik. Men var? Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Intro Slutligen om syntaxanalysgeneratorer Syntaxanalys DCG i Prolog Verktyg för Java Avslutning • Från Chalmers kommer BNFC. BNF Converter: Multilingual front-end generation from labelled BNF grammars. Genererar kod för • • • • C, via Flex och Bison C++, via Flex och Bison Haskell, via Happy Java, via JFlex och CUP • BNFC ger dig datastrukturer, lexer, testfall, och listan växer. Grammatikexempel Syntaxanalys BNFC: parsers i många språk • Parsergenerator i Haskell: Happy • ANTLR genererar parsers för • Java • C och C# • Objective C • Python • Ruby • Perl • Ada95 Intro Grammatikexempel Makefile, mm. DCG i Prolog Verktyg för Java Mer att läsa Avslutning Intro Grammatikexempel Syntaxanalys DCG i Prolog Verktyg för Java Avslutning Kurser • DH2418 Språkteknologi • Andrew Appel: Modern compiler implementation in C • Andrew Appel: Modern compiler implementation in Java • Andrew Appel: Modern compiler implementation in ML • Aho, Sethi, Ullman: Compilers: Principles, Techniqes and Tools ”Kursen i språkteknologi är en kurs som behandlar språkteknologi med fokus på text.” • ID1215 Kompilatorer och exekveringsmiljöer ”Kursen behandlar tekniker för implementation av programmeringsspråk.” • DD2488 Kompilatorkonstruktion ”Den största uppgiften i kursen är att skriva en hel kompilator för ett litet men kraftfullt programspråk.”