Föreläsning 7: Syntaxanalys

Relevanta dokument
Föreläsning 7: Syntaxanalys

Reguljära uttryck Grammatiker Rekursiv nedåkning Allmänna kontextfria grammatiker. Syntaxanalys. Douglas Wikström KTH Stockholm

DD1361 Programmeringsparadigm. Formella Språk & Syntaxanalys. Per Austrin

DD1361 Programmeringsparadigm. Formella Språk & Syntaxanalys. Per Austrin

Inlämningsuppgift MiniPlotter

Alfabeten, strängar och språk. String

i=1 c i = B och c i = a i eller c i = b i för 1 i n. Beskriv och analysera en algoritm som löser detta problem med hjälp av dynamisk programmering.

DD1361 Programmeringsparadigm. Formella Språk & Syntaxanalys. Per Austrin

Grundläggande datalogi - Övning 9

Dynamisk programmering

Programkonstruktion och Datastrukturer

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Programmering för språkteknologer II. OH-serie: Ändliga automater. reguljära uttryck i Java. Deterministiska ändliga automater

Föreläsning 8 - del 1: Objektorienterad programmering (forts.) - Exempel

Grammatik. BNF-grammatik

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Föreläsning 1: Dekomposition, giriga algoritmer och dynamisk programmering

Idag: Reguljära språk Beskrivs av Reguljära uttryck DFA Grammatik

Föreläsning 2 5/6/08. Reguljära uttryck 1. Reguljära uttryck. Konkatenering och Kleene star. Några operationer på språk

11. Reguljära uttryck och grammatiker

Definition. Mängden av reguljära uttryck på alfabetet Σ definieras av. om α och β är reguljära uttryck så är (α β) ett reguljärt uttryck

11. Reguljära uttryck och grammatiker

Tentamen i Algoritmer & Datastrukturer i Java

Algoritmanalys. Genomsnittligen behövs n/2 jämförelser vilket är proportionellt mot n, vi säger att vi har en O(n) algoritm.

Dynamisk programmering

Tentamen i Grundläggande Programvaruutveckling, TDA548

public static void mystery(int n) { if (n > 0){ mystery(n-1); System.out.print(n * 4); mystery(n-1); } }

(Man brukar säga att) Java är... Denna föreläsning. Kompilering av Java. Historik: Java. enkelt. baserat på C/C++ Allmänt om Java

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

Tentamen OOP

Att deklarera och att använda variabler. Föreläsning 10. Synlighetsregler (2) Synlighetsregler (1)

Föreläsning 9: Turingmaskiner och oavgörbarhet. Turingmaskinen. Den maximalt förenklade modell för beräkning vi kommer använda är turingmaskinen.

DAB760: Språk och logik

Föreläsning 5: Grafer Del 1

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Tentamen Programmeringsteknik II Skrivtid: Hjälpmedel: Java-bok (vilken som helst) Skriv läsligt! Använd inte rödpenna!

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

FÖRELÄSNING 2, TDDC74, VT2018 BEGREPP PROBLEMLÖSNING MED HJÄLP AV FALLANALYS PROBLEMLÖSNING MED HJÄLP AV REKURSION

Övning 5 - Tillämpad datalogi 2013

Objektorienterad modellering och diskreta strukturer. 13. Problem. Sven Gestegård Robertz. Datavetenskap, LTH

DD1361 Programmeringsparadigm. Carina Edlund

Datorlingvistisk grammatik

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren att du har förstått dessa även om detaljer kan vara felaktiga.

Lösningsförslag till exempeltenta 2

10. Mängder och språk

Algoritmer, datastrukturer och komplexitet

Algoritmer, datastrukturer och komplexitet

Grundläggande logik och modellteori

Idag. Javas datatyper, arrayer, referenssemantik. Arv, polymorfi, typregler, typkonvertering. Tänker inte säga nåt om det som är likadant som i C.

Programmering för Språkteknologer II. Innehåll. Associativa datastrukturer. Associativa datastrukturer. Binär sökning.

Kompilatorer och interpretatorer

"if"-satsen. Inledande programmering med C# (1DV402)

Kontextfria grammatiker

Tentamen TEN1 HI

Tentamen, Algoritmer och datastrukturer

Föreläsning 5 Innehåll

Automatateori (2) Idag: Sammanhangsfria språk. Dessa kan uttryckas med Grammatik PDA

I ett program hantera man ofta samlingar av objekt av samma typ.

Föreläsning 3. Stack

Introduktion till Datalogi DD1339. Föreläsning 2 22 sept 2014

729G09 Språkvetenskaplig databehandling

Datalogi I, grundkurs med Java 10p, 2D4112, Fiktiv tentamen, svar och lösningar och extra kommentarer till vissa uppgifter 1a) Dividera förs

Parsing med Recursive Descent, Avbildningsklasser. Syntaxdiagram. Syntaxdiagram och kodning expression. Betrakta följande uttryck

Föreläsning 11: Beräkningsgeometri

Föreläsning 11: Rekursion

TENTAMEN: Algoritmer och datastrukturer. Läs detta!

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Lösningsförslag till exempeltenta 1

DAI2 (TIDAL) + I2 (TKIEK)

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

Parsning. TDP007 Konstruktion av datorspråk Föreläsning 6. Peter Dalenius Institutionen för datavetenskap

Datastrukturer i kursen. Föreläsning 8 Innehåll. Träd rekursiv definition. Träd

Funktionell programmering DD1361

Algoritmer, datastrukturer och komplexitet

if (n==null) { return null; } else { return new Node(n.data, copy(n.next));

Föreläsning 5 Innehåll. Val av algoritm och datastruktur. Analys av algoritmer. Tidsåtgång och problemets storlek

Tänk på följande: Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Tentamen Datastrukturer (DAT037)

PROMETHEUS. Ett typat, objektorienterat programmeringsspråk av Tim Andersson.

Föreläsning 7-8 Innehåll

Sökning och sortering

Föreläsning 4. Kö Implementerad med array Implementerad med länkad lista Djup kontra bredd Bredden först mha kö

Tentamen Datastrukturer, DAT037 (DAT036)

Programmering A. Johan Eliasson

Programmering för språkteknologer II, HT2011. Rum

Algoritmanalys. Inledning. Informationsteknologi Malin Källén, Tom Smedsaas 1 september 2016

Tentamen Programmeringsteknik II Inledning. Anmälningskod:

Rekursion och induktion för algoritmkonstruktion

Programmering II (ID1019) :00-11:00

Föreläsning 7+8: NP-problem. Begreppet effektiv algoritm är alltså synonymt med går i polynomisk tid i den här kursen. Är detta en rimlig uppdelning?

Omtentamen för TDA540 Objektorienterad Programmering. Institutionen för Datavetenskap CTH HT-16, TDA540. Dag: , Tid:

Föreläsning 11 Datastrukturer (DAT037)

D0010E. Hello world! Nedräkning. Sågtand. Övningsuppgifter i Eclipse. Skapa ett program som skriver ut "Hello world" på skärmen.

Föreläsning 6 Innehåll. Rekursion. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursiv problemlösning. Rekursion. Rekursivt tänkande:

1 Uppgift 1. a) Skapar ett Company-objekt med hjälp av den överlagrade konstruktorn. Du kan själv välja värden på instansvariablerna.

Föreläsning 3: Booleans, if, switch

Syntaktisk parsning (Jurafsky & Martin kapitel 13)

Rekursiva algoritmer sortering sökning mönstermatchning

Transkript:

DD2458, Problemlösning och programmering under press Föreläsning 7: Syntaxanalys Datum: 2007-10-30 Skribent(er): Erik Hammar, Jesper Särnesjö Föreläsare: Mikael Goldmann Denna föreläsning behandlade syntaxanalys. Syntaxanalys handlar om att utvinna hierarkisk data som är lagrad i ett linjärt format. Exempel på detta är programmeringsoch markupspråk, naturliga språk, kemiska formler m.m. Analysen kan delas in i två delar. Dels lexikal analys, som omvandlar indata till en sträng av tokens, och dels syntaxanalys, som bygger upp ett träd från strängen av tokens. För naturliga språk kan man säga att lexikal analys handlar om orden i en textsträng, och syntaxanalys om meningsbyggnaden. 1 Ett exempel I detta exempel ska vi beräkna molekylvikten för en molekyl, givet dess kemiska formel och en lista med atomvikter. Molekylen vi använder är nitroglycerin, som har formeln C 3 H 5 (NO 3 ) 3. Atomvikterna för atomerna i molekylen hittar man i tabell 1. Atom Vikt H 1 C 12 N 14 O 16 Tabell 1: Atomvikter Molekylvikten är alltså 12 3+1 5+(14+16 3) 3 = 227. Men hur skriver man ett program som räknar ut detta givet en godtycklig kemisk formel? 2 Lexikal analys Den lexikala analysen för vårt exempel är tämligen enkel. C 3 H 5 (NO 3 ) 3 kommer här att skrivas som "C3H5(NO3)3$", där $ betyder slut på indata". Vi kommer alltså att använda de tokens som visas i tabell 2. Alla tokens har en typ, och vissa tokens (atom och num) kommer även att ha ett värde. Med andra ord kommer indata att översättas till följande sträng av tokens: atom(c), num(3), atom(h), num(5), lpar, atom(n), atom(o), num(3), rpar, num(3), $. Vi kan nu analysera dessa tokens med en kontextfri grammatik. 1

2 DD2458 Popup HT 2007 atom En atom. Skrivs som en versal följt av noll eller en gemener. num Ett positivt heltal. rpar En högerparentes. lpar En vänsterparentes. $ Slut på indata. Tabell 2: Tokens 3 Kontextfria grammatiker En kontextfri grammatik består av en mängd slutsymboler Σ (som exakt matchar den lexikala analysens tokens), en mängd ickeslutsymboler Γ, en startsymbol <s> Γ, samt en mängd av regler. Slutsymbolerna ligger i löven för syntaxträden som grammatiken beskriver och går ej att expandera ytterligare. Ickeslutsymboler ligger i inre noder och expanderas till slutsymboler. Reglerna är på formen VL ::= HL,därVL består av exakt en ickeslutsymbol och HL består av ett godtyckligt antal slutsymboler eller ickeslutsymboler. Idéen är att alla strängar som grammatiken beskriver går att skapa genom att utgå från <s>och skriva om i ett eller flera steg med hjälp av reglerna. Molekylerna i exemplet går att beskriva med följande grammatik: <start> ::= $ ::= ::= ::= num ::= ::= lpar < molekyl > rpar ::= atom Om vi tillämpar denna grammatik på den sträng av tokens som den lexikala analysen gav oss får vi syntaxträdet i figur 1. Vi kommer dock inte att bygga trädet explicit i detta exempel. För att beräkna molekylvikten ska vi använda rekursiv medåkning. 4 Syntaxanalys 4.1 Rekursiv medåkning Rekursiv medåkning, eller recursive descent, är ett sätt att analysera en sträng av tokens i linjär tid. Rekursiv medåkning fungerar endast för de grammatiker där det är tillräckligt att man betraktar ett ändligt antal kommande tokens, s.k. LL(k)-grammatiker. Lyckligtvis är vår exempelgrammatik en LL(1)-grammatik, så vi behöver endast kolla på ett token i taget.

Syntaxanalys 3 <start> $ atom "C" num "3" atom "H" num "5" num "3" lpar rpar atom N" Figur 1: Syntaxträd atom Ö" num "3"

4 DD2458 Popup HT 2007 Tanken är att man skapar funktioner för ickeslutsymbolerna i grammatiken, som anropar varandra rekursivt. Alltså ska en funktion a matcha exakt de tokens som bygger upp en sträng som kan genereras av regeln <a>. I vår implementation förutsätter vi att det finns två funktioner, peektoken, som returnerar aktuellt token i listan, samt nexttoken, som flyttar fram läspekaren till nästa token. Vi förutsätter också att tokens har attributen type och val, samt att vikt[x] är atomvikten för x. start() (1) v molekyl() (2) t peektoken() (3) if t.type =$ (4) return v (5) else (6) ERROR! molekyl() (1) v multi() (2) t peektoken() (3) if t.type {$,rpar} (4) return v (5) else (6) return v + molekyl() multi() (1) v singel() (2) t peektoken() (3) if t.type = num (4) v v t.val (5) nexttoken() (6) return v

Syntaxanalys 5 singel() (1) t peektoken() (2) if t.type = atom (3) nexttoken() (4) return vikt[t.val] (5) else if t.type = lpar (6) nexttoken() (7) v molekyl() (8) t peektoken() (9) if t.type = rpar (10) nexttoken() (11) return v (12) else (13) ERROR! (14) else (15) ERROR! 4.2 Cocke-Younger-Kasamis algoritm Alla grammatiker går ej att verifiera med rekursiv medåkning. Vi ska därför titta på Cocke-Younger-Kasamis algoritm, som fungerar för alla grammatiker som är skrivna på Chomsky-normalform. Detta innebär att alla regler är skrivna på någon av följande former, där <a>, <b>och <c>är ickeslutsymboler (som inte behöver vara distinkta) och x är en slutsymbol: <a> ::= x <a> ::= <b><c> Alla kontextfria grammatiker går att beskriva på Chomsky-normalform. Exempelvis kan reglerna för skrivas om på följande vis: ::= atom ::= <a><b> <a> ::= lpar <b> ::= <c> <c> ::= rpar Frågan vi vill besvara är huruvida en viss grammatik kan generera en given sträng x 1..x n. Om grammatiken är skriven på Chomsky-normalform kan problemet delas upp i delproblem som avgör om en regel <a i > kan generera delsträngen x j..x j+k 1.

6 DD2458 Popup HT 2007 Det visar sig att dynamisk programmering är väl lämpat för att lösa detta problem. Vi använder en kub, gen, med booleska värden, där gen[i, j, k] är sann om och endast om <a i > kan generera x j..x j+k 1. Svaret vi söker kommer att finnas i gen[1, 1,n]. En snabb implementation av Cocke-Younger-Kasamis algoritm använder rekursion och memoisering (algoritmen nedan är en botten-upp-implementation). Algoritmens tidskomplexitet är dock Θ(n 3 ) i värsta fall, där n är antalet tecken i strängen som ska kontrolleras (under antagandet att grammatiken har konstant storlek), till skillnad från rekursiv medåkning, som går i linjär tid. Den bör därför endast användas om grammatiken kräver det. Cocke-Younger-Kasami(x 1..x n ) (1) gen[i, j, k] false i, j, k (2) for i =1to r (3) for j =1to n (4) if <a i >::= x j is a rule (5) gen[i, j, 1] true (6) for k =2to n (7) for j =1to n k +1 (8) for l =1to k 1 (9) foreach rule <a i >::=< a s >< a t > (10) if gen[s, j, l] and gen[t, j + l, k l] (11) gen[i, j, k] true 5 Reguljära uttryck Reguljära uttryck är strängar som beskriver mängder av strängar. De har sin grund i formell språkteori, men används även i många verktyg och programmeringsspråk. Reguljära uttryck definieras över något ändligt alfabet Σ, såsom bokstäverna A-Z, ASCII eller Unicode, och går att definiera med tre operationer på en mängd konstanter. Konstanterna är samtliga tecken i Σ samt tecknet ɛ, som representerar en tom sträng. Operationerna är alternering, som matchar något av två mönster, konkatenering, som matchar ett mönster följt av ett annat, samt Kleene-slutning, som matchar noll eller fler förekomster av ett mönster. Detta summeras i tabell 3, där R är ett reguljärt uttryck och L R mängden av strängar som R beskriver. Notera att R i för Kleene-slutningar betyder i repetitioner av mönstret R. De flesta implementationer av reguljära uttryck definierar ytterligare operationer. Dessa operationer tenderar att vara syntaktiskt sockersom gör det mycket bekvämare att skriva reguljära uttryck, men som inte låter uttrycken beskriva fler grammatiker, och som går att definiera med de tre redan nämnda operationerna. I tabell 4 ges ett par exempel på vanliga sådana operationer.

Syntaxanalys 7 Betydelse R L R tom sträng ɛ {ɛ} något tecken x Σ x {x} alternering (R 1 ) (R 2 ) L R1 L R2 konkatenering (R 1 )(R 2 ) {ab a L R1,b L R2 } Kleene-slutning (R) L ɛ L R L R 2 L R 3... Tabell 3: Reguljära uttryck Betydelse Uttryck Ekvivalent uttryck a, b, eller c [abc] a b c något tecken mellan a och f, inklusivt [a-f] a b c d e f minst en förekomst av a a+ aa* högst en förekomst av a a? ɛ a Tabell 4: Exempel på utökad syntax för reguljära uttryck 5.1 Reguljära uttryck som ändliga automater Reguljära uttryck går även att beskriva som ändliga automater, där tillståndsövergångar representerar matchningar av ɛ alternativt x Σ. Man kan sedan bygga upp en automat som matchar ett reguljärt uttryck genom att kombinera automater som motsvarar de tre operationerna. Dessa tre automater går att definiera som i figur 2-4, där A, A1 och A2 är godtyckliga automater. in A1 out A2 Figur 2: Alternering

8 DD2458 Popup HT 2007 in A1 A2 out Figur 3: Konkatenering in A out Figur 4: Kleene-slutning 5.2 Reguljära uttryck i Java Javas standardbibliotek innehåller en implementation av reguljära uttryck, i paketet java.util.regex. Nedan följer ett exempel på hur man kan använda dem: import java.util.regex.pattern; import java.util.regex.matcher; import java.util.scanner; public class pat2 { public static void main(string[] as) { // Beskriver en atom String atom = "[A-Z][a-z]?"; // Beskriver höger- och vänsterparentes String paren = "[()]"; // Beskriver positivt heltal String number = "[1-9][0-9]*";

Syntaxanalys 9 } } String s = as[0]; // Skapa det reguljära uttrycket ( atom paren number ) Matcher m = Pattern.compile(atom + " " + paren + " " + number).matcher(s); // Hitta nästa delsträng som matchar det reguljära uttrycket int pos = 0; while(m.find(pos)) { // Skriv ut delsträngen System.out.println(m.group()); pos = m.end(); } 5.3 Reguljära uttryck i C/C++ Reguljära uttryck finns ej i standardbiblioteken för C eller C++. De kommer dock sannolikt att finnas med i nästa standard av C++, som har arbetsnamnet C++0x.