Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Grammatikexempel
Syntaxanalys
Senast
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
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
Lex och Yacc
Verktyg för Java
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
| ...
• Lex/Yacc i C/C++
• Lite om JFlex/CUP för Java
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Exempel: Lava
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
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Förbättring av if-satsen
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Att generera syntaxanalysatorer
if_statement → I F bool_expr T HEN statement
else_clause
else_clause → E LSE statement
| • Syfte: Att automatisera tråkig
programmering
• Minskar risken för syntax-buggar
• Lättare för andra att arbeta med koden
• Kan få snabb parser: Verktyg ofta
väloptimerade
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
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Grammatikexempel
Varför inte rekursiv medåkning?
• 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”.
• LL-grammatik kan vara en begränsning
• Vänsterrekursion kan bli farligt:
IntList ::= IntList COMMA Int
| Int
Skriv om för att undvika!
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Alternativ till LL(k)
• LR(k) är läsning vänster-till-höger, och
•
•
•
•
högerhärledning.
Jobbigt att implementera för hand: Behöver
verktyg
Implementeras som en ändlig automat med
stack
Klarar rekursioner säkrare
Högerrekursion riskerar ineffektivitet
(många element på stacken)
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Kompilatorkonstruktion
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
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
• Lex/Yacc för C/C++
• Cup för Java
•
•
•
•
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Exempel: Newickträd i DCG
Avslutning
Intro
Huvud --> Kropp.
Syntaktiskt socker för Prolog-satser
Utnyttjar Prologs backtracking för
syntaxanalysen
Begränsning på grammatiken?
”Killer feature”: Jobbar åt båda hållen!
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Lexikal analysator
lex([], []).
newick
→ tree semiColon
semiColon → SemiColon
| tree
→ Leaf
| LeftParen tree Comma
tree RightParen
Terminaler är Leaf, LeftParen, RightParen,
Comma och SemiColon.
-- Ta bort mellanslag
lex([32|S], Terminals) :- % Oj, alla mellanslag!
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),
name(Symbol, W),
lex(NextS, Terminals).
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Grammatikexempel
Hjälpande kod 1
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Hjälpande kod 2
-- Ett ord: lagra som sammansatt term
lex(S, [w(Symbol)|Terminals]) :firstWord(S, W, NextS),
name(Symbol, W),
lex(NextS, Terminals).
-- Här kommer en viktig symbol
lex([C|S], [Symbol|Terminals]) :char2symbol(C, Symbol),
lex(S, Terminals).
firstWord([X|Xs], W, Next) :firstWordI([X|Xs], W, Next), length(W, L), L>1.
char2symbol(40,
char2symbol(41,
char2symbol(44,
char2symbol(32,
char2symbol(59,
Intro
Grammatikexempel
Syntaxanalys
openParen).
closeParen).
comma).
space).
semicolon).
DCG i Prolog
%
%
%
%
%
’(’
’)’
’,’
’ ’
’;’
Lex och Yacc
Verktyg för Java
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).
Avslutning
Intro
Grammatikexempel
Syntaxanalysatorn
BNF newick
→ tree semiColon
semiColon → SemiColon
| tree
→ Leaf
| LeftParen tree Comma
tree RightParen
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Provkörning
| ?- name(’(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.
semi
semi
tree
tree
leaf
-->
-->
-->
-->
[semicolon].
[].
leaf.
[openParen], tree, [comma],
tree, [closeParen].
--> [w(X)].
Avslutning
Observationer
• Syntaxanalysatorn kortare än lexern
• Inget slutresultat: samlar inte ihop någon
data!
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
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
Lex och Yacc
Verktyg för Java
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Grammatikexempel
Expansion av DCG-produktioner
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
DCG för er
newick --> tree, semi.
semi
--> [semicolon].
semi
--> [].
Översättning till predikat
• Bra för labben.
newick(In, Out) :tree(In, Remaining),
semi(Remaining, Out).
semi(In, Out) :’C’(In, semicolon, Out).
semi(In, Out) :Out = In.
• Mycket smidig syntaxanalysator
’C’/3 plockar X från In:
’C’([X|Terminals], X, Terminals).
Avslutning
| ?- parseTree(T).
|: (lasse, (hubba, nisse));
T = b(l(lasse),b(l(hubba),l(nisse))) ?
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 stdin:
parseTree(X) :read_line(T), lex(T, Symbols),
newick(X, Symbols, []).
newick(T)
semi
semi
tree(L)
tree(b(T1,T2))
Grammatikexempel
• Kan hantera tvetydiga grammatiker. Bra?
Dåligt?
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Grammatikexempel
Lex och Yacc
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Lexer för Newickträd i Lex
%%
%%
Avdelare
Användardefinierade funktioner
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Lexer för Newickträd i Lex
%{
/* Include symbols from parser,
generated by yacc/bison
*/
#include ”newick.h”
/* Some supporting C code here */
%}
...
%%
{WHITE}
\(
\)
\:
,
\;
{STR}
%%
... (mera här)
Avslutning
Regler av formen
RegEx
{ <C-kod> return <en symbol>}
Andra delen:
/* RegEx for valid leaf names */
STR
[a-zA-Z0-9\-\_/+*#!\%&?\.]+
WHITE
[ \t\n]+
Verktyg för Java
Avdelare
Första delen:
/* Handle tree comments sensible */
%x comment
Lex och Yacc
%{
C-definitioner hamnar här
%}
Diverse deklarationer för lex
• GNU har egna varianter: Flex och Bison
• (F)Lex: En ”scanner”.
• Infil beskriver terminaler
• Utfil definierar funktionen yylex.
• Kan definiera ett helt eget program.
• Yacc/Bison:
• ”Yet Another Compiler-Compiler”
• Infil beskriver en grammatik med actions
• Utfil definierar funktionen yyparse
• Använder yylex (kan skrivas av dig)
• Genererar LALR-parsers, variant av LR
• Implementeras som en automat med stack
Grammatikexempel
DCG i Prolog
Generellt format för (F)Lex
• Klassiska Unix-verktyg
Intro
Syntaxanalys
\[
/* Do nothing */
{ return LEFT_PAREN; }
{ return RIGHT_PAREN; }
{ return COLON; }
{ return COMMA; }
/* Why bother? */
{ yytree_lval.str = strdup(yytext);
return STRING; }
{ BEGIN(comment); }
/* Special state to read comments in */
<comment>\] { BEGIN(INITIAL); }
<comment>. /* eat comment */
%%
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Allmänt format för yacc/bison
else_statement : ELSE statement
| /* nothing */
;
%% Avdelare
Användardefinierade funktioner
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Andra delen av Bisongrammatiken
%%
tree : leaf { $$ = $1; } /* En ”action” */
| LEFT_PAREN tree
COMMA tree RIGHT_PAREN
{ $$ = new_branch($2, $4); } /*”action”*/
;
leaf : STRING
{ $$ = new_node($1);} /* Mer ”action” */
;
%%
/* Even more C functions */
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
%{
/* Here comes quite a few C declarations */
%}
/* More Bison/C declarations */
/* Deklarera terminaler */
%token
LEFT_PAREN
%token
RIGHT_PAREN
%token
SEMICOLON
%token
COMMA
%token <str> STRING
Regler som BNF-liknande uttryck
if_statement : IF bool_expr THEN
else_statement
Grammatikexempel
Syntaxanalys
Första delen av Bisongrammatiken
%{
C-definitioner hamnar här
%}
Diverse deklarationer för bison
%% Avdelare
Intro
Grammatikexempel
Intro
/* Semantik för variabler: mytree är en typ */
%type <mytree> tree
%type <mytree> leaf
%%
...(mera
här)
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Koppla ihop flex och bison
> flex newick.l
> bison newick.y
> ls
lex.yy.c
newick.l
newick.y
newick.tab.c
Genererat:
lexikal analysator: Funktionen yylex i
lex.yy.c
syntaxanalysator: Funktionen yyparse i
newick.tab.c
Läs från stdin med mytree = yyparse();
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Allmänt om Lex/Yacc
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
• Mycket att skriva
• JFlex bygger på JLex som bygger på Lex.
• Struligt!
• JFlex använder samma konstruktioner
• Viktigt: Får ej vara vänsterrekursiv.
• CUP: Constructor of Useful Parsers
• Du implementerar felhantering själv!
• CUP liknar Yacc
• Svårt att debugga.
• Tydligare syntax, ”äkta” BNF
• Projektet lever!
• CUP är ej (?) installerat på CSC, men lätt
Grammatikexempel
Syntaxanalys
DCG i Prolog
Avslutning
I Java: JFlex och CUP
att ladda ner och testa.
• Modernt: Stöd för C++
Intro
Grammatikexempel
Lex och Yacc
Verktyg för Java
Läs Newickträd i Java: Början
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
/* Declare the terminals */
terminal
LEFTPAREN;
terminal
RIGHTPAREN;
terminal
COMMA;
terminal
SEMICOLON;
terminal String NAME;
// Ett värde följer med terminalen
/* Declare non-terminals */
non terminal Tree newick; // Dessa variabler ges ett värde
non terminal Tree tree;
non terminal Tree leaf;
non terminal
semicolon;
Verktyg för Java
Läs Newickträd i Java: Slutet
import java_cup.runtime.*;
/* Prepare your lexer! (JFlex or your own class) */
init with {: scanner.init(); :};
scan with {: return scanner.next_token(); :};
Lex och Yacc
/* Newick grammar */
newick ::= tree semicolon;
semicolon ::= SEMICOLON
|
;
tree ::= leaf
| LEFTPAREN tree
COMMA
tree
RIGHTPAREN
;
leaf ::= NAME;
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Intro
Användning
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Lägg till semantik i CUP
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); :}
;
• Skapa parser kod med
java -cp java-cup-11a.jar java_cup.Main newick.cup
• Två nya klassfiler: sym.java och
parser.java
• Användning:
parser newickparser = new parser(new my_scanner())
• Scanner är ett enkelt interface som du
implementerar eller får från JFlex.
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Sammanfattning om CUP
Avslutning
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Avslutning
Slutligen om syntaxanalysgeneratorer
• Yacc/CUP i Haskell: Happy
• Gammal god Yacc-tradition, snygg
implementation
• Delar vissa nackdelar:
• Mycket att skriva
• Felhantering sker ej enkelt
• Är avlusning svårt?
• Använd gärna i lab 6 — på egen hand!
• 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 JLex och CUP
• BNFC ger dig datastrukturer, lexer, testfall,
Makefile, mm.
Intro
Grammatikexempel
Syntaxanalys
DCG i Prolog
Lex och Yacc
Verktyg för Java
Mer att läsa, mer att plugga
• 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
Kurser
• 2D1418 Språkteknologi
• 2D1375 Programspråksimplementation
Avslutning