Senast Idag Exempel: Lava Exempel: Lava Förbättring av if

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.”