Grundläggande datalogi - Övning 9 Björn Terelius January 30, 2009
Ett formellt språk är en (oftast oändlig) mängd strängar. Språket definieras av en syntax som är en samling regler för hur man får bilda giltiga strängar. Om syntaxen inte är alltför komplicerad kan den beskrivas i BNF (). Till exempel definieras syntaktiskt giltiga kemiska formler av <formel> ::= <mol> \n <mol> ::= <group> <group><mol> <group> ::= <atom> <atom><num> (<mol>)<num> <atom> ::= <LETTER> <LETTER><letter> <LETTER> ::= A B C... Z <letter> ::= a b c... z <num> ::= 2 3 4...
Syntaxanalys/parsning ska: undersöka om strängen är giltig översätta strängen till intern representation (ofta ett träd) Ofta kan man i stort sett mekaniskt konstruera en parser från grammatiken genom att för varje symbol skriva en inläsningsfunktion som rekursivt anropar de inläsningsfunktioner som specificeras i grammatiken. Den här formen av parsning kallas rekursiv medåkning (recursive descent).
Betrakta följande enkla grammatik för en viss sorts satser. <Mening> ::= <Sats>. <Sats><Konj><Mening> <Sats> ::= <Subj> <Pred> <Subj> ::= JAG DU <Pred> ::= VET TROR <Konj> ::= ATT OCH Vilka av följande meningar är korrekta (enligt syntaxen) DU VET. DU TROR ATT DU VET DU VET OCH JAG VET. JAG OCH DU TROR ATT JAG VET.
De 5 omskrivningsreglerna behöver var sin inläsningsfunktion. För <Mening> kan den t.ex. se ut på följande sätt: def read_mening(q): read_sats(q) if q.peek()=='.' q.get() else: read_konj(q) read_mening(q) Hur ser de andra funktionerna ut?
Den bruna gladan är ovanlig i Sverige, men häckar emellanåt i Skåne. Lätet är ett skriande HYHYHYHYHIHYYYYY som består av ett eller flera HY, följt av ett HIH och noll eller flera Y. 1. Skriv en syntax för den bruna gladans skri. 2. Beskriv kortfattat hur ett program som kontrollerar syntaxen i ett fågelskri kan fungera.
Lösning 1. <skri> ::= <start><mitt> <start><mitt><slut> <start> ::= HY HY <start> <mitt> ::= HIH <slut> ::= Y Y <slut> 2. Skapa en funktion för varje icke-slutsymbol i grammatiken ovan. Tjuvkika på nästa tecken (eller två tecken i start) för att avgöra vilken funktion som ska anropas i de fall då det finns flera alternativ.
För att göra en Dagobertmacka lägger man en brödskiva i botten, sen lägger man på ett eller två pålägg, sen en brödskiva till, följt av ett eller två pålägg, följt av en brödskiva och så vidare (alltid ett eller två pålägg mellan brödskivorna). Allra överst ska det vara en brödskiva. Mackan kan bli hur stor som helst! *om+f+bj* är ett exempel på en liten macka med ost, marmelad, fisk, banan, och jordnötssmör. Brödskivorna representeras av * (mörkt bröd) och + (ljust bröd) och för påläggen tar vi bara med begynnelsebokstaven. Här är ett förslag på en syntax för Dagobertmackor <macka> ::= <bröd><pålägg><bröd> <pålägg>::= abcdefghijklmnopqrstuvwxyz
Tala om vad som är fel med syntaxen! Mackan kan bara ha två bröd, så den kan inte bli hur stor som helst Mackan kan bara ha ett pålägg mellan bröden Det finns ingen definition av <bröd> <pålägg> är hela alfabetet istället för en godtycklig bokstav i alfabetet
Det har gjorts olika utvidgningar av BNF som tillåter en mer kompakt representation av en grammatik. Utvidgningar som baseras på reguljära uttryck använder oftast konventionen att <symbol>? betyder 0 eller 1 förekomst av <symbol> <symbol>* betyder 0 eller flera förekomster av <symbol> <symbol>+ betyder 1 eller flera förekomster av <symbol> Utvidgningar som baseras på Wirth s notation använder istället [ <symbol> ] betyder 0 eller 1 förekomst av <symbol> { <symbol> } betyder 0 eller flera förekomster av <symbol>
Hur undviker man buggar? 1. Tänk igenom vad funktionen ska göra. Vad ska den ta för indata och vad ska den ta för utdata? 2. Strukturera koden och använd tydliga variabelnamn. 3. Kommentera koden. Om koden är tydlid behövs inga kommentarer om vad koden gör, men däremot hur och varför. 4. Kan algoritmen bevisas vara korrekt för alla giltiga indata?
Hur hittar man buggar i programmet? 1. Testa enkla indata med kända utdata. 2. Om det olika delar av koden körs beroende på indata, testa någon representant för varje fall. 3. Testa indata som är nära gränsen för det tillåtna. 4. Testa ogiltiga indata. Vad händer?
Vad gör man när man hittat ett testfall som misslyckas? 1. Försök hitta det enklaste/minsta testfallet som visar buggen. 2. Om koden och testfallet är tillräckligt enkla man exekvera koden i huvudet eller på papper. När går det fel? 3. Använd spårutskrifter. Hur förändras de aktuella variablerna? 4. Binärsök. Är allt ok halvvägs genom koden? 5. Bryt ner programmet till mindre funktioner och testa varje funktion för sig.