ExprLang.java
.
Setiap parser pasti punya kode inisialisasi, kode inisialisasi ini akan
sama untuk aneka jenis bahasa, sehingga tidak akan dijelaskan lagi di
bagian berikutnya.public static void main(String argv[]) throws Exception { ExprLexer lex = new ExprLexer(new ANTLRFileStream(argv[0])); CommonTokenStream tokens = new CommonTokenStream(lex); ExprParser g = new ExprParser(tokens); ExprParser.prog_return r = g.prog(); CommonTree ct = (CommonTree)r.getTree(); }Baris pertama dalam sebuah fungsi main membuat sebuah lexer (dalamkasus ini
ExprLexer
), yang fungsinya memecah string menjadi bagian-bagiannya (menjadi INT, '*', '+', '-', dsb). Baris kedua membuat object CommonTokenStream
yang diberikan ke parser (ini adalah sebuah adapter, Anda tidak perlu
mengetahui internalnya kecuali ingin mengubah kode ANTLR). Baris ketiga
adalah bagian untuk mengkonstruksi parser, dan baris ke empat adalah
baris yang penting, baris di mana proses parsing itu sendiri dipanggil:ExprParser.prog_return r = g.prog();Kita meminta nilai kembalian parser dimulai dari aturan
prog
. Setelah itu kita bisa mendapatkan Tree (AST) dengan menggunakan r.getTree()
. Tree yang kita pakai adalah Tree standar bawaan ANTLR, jadi kita memakai CommonTree
. Setelah memiliki root dari tree, kita bisa mengevaluasi ekspresi dengan mudah. Saya tidak akan menjelaskan semua method milik CommonTree
, penjelasan lengkap ada di dokumentasinya di:http://www.antlr.org/api/Java/classorg_1_1antlr_1_1runtime_1_1tree_1_1_common_tree.html
Method-method yang akan saya pakai adalah:
getChildren
, getChilCount
, getChild
, getType
, dan getText
. Berikut ini penjelasan singkatnya:- Method
getChildren
untuk mendapatkan List of children yang bisa diiterasi menggunakan format loop Java (for (Tree x: e.getChildren()) {}
). Sebagai catatan, Anda akan melihat banyak casting tipe Object keCommonTree
, ketika ANTLR ditulis, Java 1.5 belum dirilis, sehingga fitur Generic milik Java belum dipakai. Mereka saat ini sudah mulai beralih ke JDK 1.5. - Method
getChildCount
digunakan untuk mendapatkan jumlah anak. Berguna untuk menentukan apakah misalnya pernyataanif
memilikielse
atau tidak. - Method
getChild
digunakan untuk mendapatkan anak ke-n. - Method
getType
digunakan untuk mendapatkan konstanta integer tipe node. Nilainya terdefinisi (tidak nol) jika node tersebut diberi nama dibagian tokens. Hasil kembalian method ini bisa dibandingkan dengan konstanta integer yang dihasilkan ANTLR dalam formatNamaGrammarLexer.KONSTANTA
(dalam contoh ini misalnyaExprLexer.INT
) - Method
getText
digunakan untuk mendapatkan teks node (misalnya node+
akan memiliki teks+
). Ketika nanti node variabel diperkenalkan,getText
bisa digunakan untuk mendapatkan nama variabel.
evaluateExprList
, method ini hanya akan memanggil evaluateExpression
yang tugasnya adalah mengevaluasi ekspresi itu sendiri.void evaluateExprList(CommonTree exprlist) { for (Object e: exprlist.getChildren()) { System.out.println("Result: " + evaluateExpression((CommonTree)e)); } }Kalau kita lihat dari gambar AST yang dihasilkan oleh Antlr, misalnya pohon ini:
kita melihat bahwa ada suatu node dengan nama EXPRESSION yang tidak terlalu berguna untuk saat ini. Gunanya hanyalah agar terlihat bahwa node di bawahnya adalah sebuah ekspresi. Saya sengaja membuat node ini untuk pengembangan versi berikutnya, di mana setiap baris belum tentu berisi ekspresi. Kita hanya perlu melewati node itu dengan mengambil anaknya yang pertama.
int evaluateExpression(CommonTree expr) { debug("Evaluate Expression "+expr.getText()); return evaluateExpr((CommonTree)expr.getChild(0)) ; }Fungsi
evaluateExpr
adalah fungsi yang melakukan komputasi. Ini sangat mudah, karena pada dasarnya hanya ada dua kasus: INTEGER, dan OPERATOR.Pertama, jika isi node adalah integer, maka hasilnya adalah nilai integer itu sendiri (di Java kita memakai
Integer.parseInt
untuk mengubah string menjadi integer)if (expr.getType()==ExprLexer.INT) { return Integer.parseInt(expr.getText()); }Kedua, jika isi node adalah operator ('+' atau '-' atau '*') berarti nilai ekspresi adalah nilai anak pertama dioperasikan (ditambah/dikurang/dikali) dengan anak kedua:
if (expr.getText().equals("+")) { return evaluateExpr((CommonTree)expr.getChild(0)) + evaluateExpr((CommonTree)expr.getChild(1)); } if (expr.getText().equals("-")) { return evaluateExpr((CommonTree)expr.getChild(0)) - evaluateExpr((CommonTree)expr.getChild(1)); } if (expr.getText().equals("*")) { return evaluateExpr((CommonTree)expr.getChild(0)) * evaluateExpr((CommonTree)expr.getChild(1)); }
Sumber : Yohan.es
0 komentar:
Post a Comment