5. kodutöö: Käsitsi lekser
Varsti alustame me kodutööde sarja, mille käigus on vaja luua erinevaid komponente ühe väljamõeldud keele translaatorile. Seda keelt nimetame me nimega AKTK (st. AKT keel). Tegemist on lihtsa imperatiivse, üldotstarbelise programmeerimisekeelega. Seda keelt tahame arendada töövahendiga ANTLR, aga selle pimesi kasutamine on väga ohtlik. ANTLR lubab ühes failis spetsifitseerida nii lekseri kui ka parseri, aga nad käituvad erinevatel põhimõtetel.
ANTLRi tööpõhimõtte arusaamiseks implementeerime kõigepealt käsitsi lekseri ja parseri. Seejuures on lekseri implementeerimine palju piinarikkam, aga edasi lähevad meil asjad lihtsamaks. Antud kodutöös tuleb siis implementeerida lekser AKTK jaoks. Ülesande põhi on kursuse repos, kus tuleks lõpuni implementeerida AktkHandwrittenLexer klass paketis week5.
Selle kodutöö eesmärk on nüüd pigem aru saada, kuidas asjad töötavad. Siin on üsna palju tehnilist mäkerdamist ja selle lõpuni tööle saamine ei ole kõige olulisem. Pigem on siin oluline aru saada järgmisest:
- Lekseri töö tulemuseks on lekseemide jada! See tööjaotus lekseri ja parseri vahel on oluline.
- Katsu tõesti mõttega jälgida, kuidas maskeerimistähtede lugemine peab töötama.
- Lõpuks on ka hea teada, kuidas päriselt lekserit kirjutatakse! (Mõned näited: Java, gcc ja clang).
NB! Käsitsi kirjutades ei pea lõplikku automaati simuleerima. Tähthaaval identifikaatorite ja võtmesõnade vahel eristamine teeb koodi väga raskesti hallatavaks. Lihtsam on neid samamoodi käsitleda ja siis võrrelda võtmesõnadega, vt. näide lekseri slaidide lõpus.
AKTK programmides võivad esineda:
- võtmesõnad
if
,while
javar
; - märgita täisarvuliteraalid (nt.
3
või34
); - sõneliteraalid (nt.
"kala"
või"Ta ütles \"Jah!\""
);- selgituseks -- langkriipsuga tähistatakse teatud erisümboleid:
\n
tähistab reavahetust\t
tähistab tabulaatorit\"
tähistab jutumärki\\
tähistab langkriipsu
- Pane tähele, et kui tekstfailis on kirjas sõneliteraal
"a\nb"
, siis on tegemist nelja tähega ehk järgmine tähtede massiiv['a', '\\', 'n', 'b']
. Me tahame sellest saada sõne kolmest tähest koosnev sõne:['a', '\n', 'b']
.
- selgituseks -- langkriipsuga tähistatakse teatud erisümboleid:
- muutuja nimed (nt.
kala
);- muutuja nime esimene sümbol peab olema täht (kasuta
Character.isLetter
) või allkriips, edasi võib tulla ka numbreid;
- muutuja nime esimene sümbol peab olema täht (kasuta
- operaatorid
+
,-
,*
,/
; - sulud (
(
,)
); - kommentaarid (ühe- ja mitmerealised, nagu Javas);
- lekseemide vahel võivad olla tühisümbolid (reavahetus, tühik ja tabulaator).
Lekseri poolt genereeritava lekseemide jada lõpus peaks olema lekseem tüübiga EOF
. Kommentaare ja tühisümboleid peab lekser ignoreerima, nendele vastavaid lekseeme ei ole ette nähtud.
Lekseemide kujutamiseks on mõeldud klass AktkToken
ja selle sees olev enum AktkToken.Type
. AktkToken.data
kohta käivad eeldused on kirjas Type
-i juures.
Kokkuvõte
- Esitada tuleb AktkHandwrittenLexer klass.
- Soovitus: kui sa kõiki lekseemide tüüpe ei oska tuvastada, siis tee need, mida oskad. Testid lähevad järjest raskemaks.
- Tokeni juurde võib, aga ei pea, lisama info selle kohta, kus lekseem failis paikneb. See on meil ainult ühes testis (üheksas test), mis kontrollib, kas asukoht on seal määratud või mitte.
- Viimane test kontrollib, et vaatad sisendit läbi enam-vähem lineaarselt ja liiga palju edasi-tagasi ei hüppa. Üldiselt oleme niimoodi õpetanud teid mõtlema (nii olekumasinate kui ka kalalekseri näitel), seega see test ei tohiks probleeme valmistada.
Video juhuks, kui jääd alustamisega hätta: AktkHandwrittenLexer-i algus.