10. 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 week10; public class AktkInterpreter { public static void run(String program) { // TODO: käivita antud AKTK kood } }
Kodutöö mall on avalikus repos. Etteantud on abiklass week10.AktkInterpreterBuiltins
, mis sisaldab AKTK "standardteeki", st. neid funktsioone, mis on kõigile AKTK programmidele alati kättesaadavad.
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. - 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 vääraks täisarvu 0 ja tõeseks kõiki muid täisarve.
- 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. - Kui jääd hätta AKTK funktsioonide
return
-lausete implementeerimisega, siis ühe võimalusena uuri, kuidas toimub funktsioonist väärtuse väljaandmine Pascalis.