8. kodutöö: AKTK interpretaator
Olles kirjutanud grammatika ja loonud AST-i, oleme lõpuks jõudnud nii kaugele, et saame hakata käivitama AKTK programme! Hetkel piirdume interpreteerimisega, milleks on vaja implementeerida järgnev klass:
package week8; public class AktkInterpreter { public static void run(String program) { throw new UnsupportedOperationException(); } }
Kodutöö mall on kursuse repos. Ette on antud abiklass week8.AktkInterpreterBuiltins
, mis sisaldab AKTK "standardteeki", st. neid funktsioone, mis on kõigile AKTK programmidele alati kättesaadavad.
See ülesanne on meil tegelikult järjekordne eksami alusosa ülesanne. Ta on aga natuke suurem keel ja siin peab muutujate skoopidega arvestama. Selleks aga arendasime praktikumides sellise väärtuskeskkonna, mis programmi struktuuriga arvestab.
Vihjed
- Programmi lähtekoodist on kõigepealt vaja saada selle AST.
- AST-i läbimiseks/väärtustamiseks oleme lisanud
AstVisitor
liidese. - Kuna avaldiste väärtusteks võivad olla nii täisarvud kui ka sõned, siis väärtustava visitor-i tagastustüübiks sobib
Object
. Väärtuse puudumisel saab tagastadanull
. - Pane tähele, et AKTK abstraktne süntaksipuu ühtlustab tavapärased infiksoperaatsioonid ja harilikud funktsiooni väljakutsed ühe nimetaja alla (
FunctionCall
) — interpreteerimisel tuleks neil vahet teha. Selle tarvis on klassiFunctionCall
lisatud abimeetodidisComparisonOperator
jaisArithmeticOperation
— kui need meetodid tagastavadfalse
, on tegemist hariliku funktsiooniväljakutsega. - Toetatud peaks olema järgmised operaatorid:
- Unaarne miinus täisarvudel.
- Binaarsed aritmeetilised operaatorid täisarvudel.
- Binaarne liitmine sõnedel.
- Võrdlusoperaatorid nii täisarvudel kui ka sõnedel.
- Binaarsete operaatorite argumendid peavad olema sama tüüpi, st ei pea toetama sõne ja täisarvu liitmist või võrdlemist.
- Muutujatega töötamiseks on vaja väärtuskeskkonda.
- Kuigi AKTK programmides võib (aga ei pruugi!) esineda muutujate jms tüüpe, võib neid hetkel ignoreerida ja alati lähtuda väärtuste endi tüüpidest.
- Sisseehitatud funktsioone on kõige paindlikum käivitada reflection-i abil. Näiteks järgneva koodiga saab
AktkInterpreterBuiltins
klassist sõne kujul oleva nime ja argumentide tüüpide järgi leida vastava meetodi ning selle soovitud argumentidel käivitada ja tagastatud väärtuse saada:try { Integer argument = 42; Method method = AktkInterpreterBuiltins.class .getDeclaredMethod("print", new Class<?>[]{argument.getClass()}); Object returnValue = method.invoke(null, new Object[]{argument}); } catch (Exception e) { throw new RuntimeException(e); }
Rohkem infot: https://docs.oracle.com/javase/tutorial/reflect/. - If ja while lause tingimuses loeme tõeseks nullist erinevaid täisarve ja vääraks kõike muud (st täisarv 0, sõne või
null
). - Võib eeldada, et kõik funktsioonid on defineeritud globaalses skoobis, st funktsioone skoopima ei pea.
- Sisseehitatud funktsioonide korral tuleb arvestada üledefineerimisega (overloading), sest
print
funktsiooni saab kasutada nii arvulise kui ka tekstilise argumendiga. AKTK-s defineeritud funktsioonide korral üledefineerimist toetada pole vaja. - AKTK funktsioonide
return
-lausete lihtsamaks implementeerimiseks võib eeldada, et tagastamine toimub alati funktsiooni lõpus. See tähendab, et pole vaja käsitleda olukorda, kusreturn
-lause katkestab funktsiooni keha poole pealt.
Video juhuks, kui jääd alustamisega hätta: AktkInterpreter-i algus.