DISUSUN OLEH : KELOMPOK 3 1. Reza Aditya Patrawayu (123040132) 2. Hanura Eka Santika (123040125) 3. Wulan Purwanti (123040129) 4. Nia Juniati (123040139)
FAKULTAS TEKNIK JURUSAN TEKNIK INFORMATIKA UNIVERSITAS PASUNDAN 2013
Parser Analisis syntax atau parser (penguraian) adalah suatu bagian paling penting dalam sebuah compiler. Bagian ini mengambil inti penting bagian syntactic dari aliran input . Sebagian catatan awal, penganalisis syntax bekerja bertahap sebelum fase analisis lexical. Penganalisis lexical menentukan token yang terdapat pada aliran input berikutnya dan kembali ke parser untuk diperiksa lagi. Penganalisis syntax memperhatikan susunan token agar memungkinkan untuk disesuaikan dengan struktur bahasa pemrograman . Pada bab ini, kita akan memahami tentang fase analisis syntax. Pertama, kita akan membahas aturan uraian dan cara menguraikan dengan singkat. Berdasarkan pada kompleksitas cara parser, disini ada beberapa algoritma parser yang secara luas dibagi atas cara top-down dan bottom-up. Dalam tiap kategori, disana terdapat beberapa parser seperti parser secara predictive (berulang dan tidak berulang), shift-reduce (operator precedence, parser LR), dan lainnya. Kita akan perlahan melihat ke dalam susunan awal parser dengan yang sederhana seperti parser secara predictive sampai yang kompleks seperi parser LR.
Aturan Parser Parser dilihat dari urutan pengembalian token oleh penganalisis lexical dan ekstraksi konstruksi tampilan bahasa secara berurutan. Dengan demikian, aturan penguaraian adalah dua tahapan : 1. Untuk mengidentifikasi konstruksi bahasa ditampilkan pemberian input terhadap program. Jika parser menentukan input adalah sesuai, maka output yang ditampilakan berupa parse tree (pohon faktor). 2. Jika inputan adalah data tidak benar, maka parser menyatakan adanya deteksi kesalahan syntax pada input. Pada keadaan ini, pohon faktor tidak bisa dihasilkan.
Error Handling Error handling (penanganan kesalahan) adalah suatu bagian penting pada sebuah kompiler modern. Kompiler dengan kemampuan error handling yang tidak baik tidak akan diterima oleh pengguna, bahkan walaupun itu dapat menghasilkan kode yang benar untuk program yang baik sekalipun. Tantangan yang paling besar disini adalah menebak kesalahan yang mungkin dilakukan programmer dan datang dengan cara menunjukan kesalahan itu secara tepat serta caranya yang tidak lebih dari satu. Ini seharusnya menjadi catatan bagi para perancang bahasa yang tidak menyediakan informasi tentang kesalahan, ini adalah tugas bagi para perancang compiler untuk menyediakan ini. Secara umum terjadiny kesalahan (error) dalam suatu program dapat diklasifikasikan dalam empat kategori sebagai berikut : 1. Lexical error- Ini merupakan kesalahan yang utamanya terletak pada kesalahan ejaan dan kebetulan masukannya berupa istilah asing. Sebagai contoh $, jika bahasa yang digunakan tidak sesuai dengan itu. Kesalahan ini kebanyakan tertangkap oleh Lexical analyzer. 2. Syntatic error- Ini merupakan kesalahan tata bahasa, seperti tidak sesuainya tanda kurung pada tampilan aritmatika, penyususunan ill-formed, dll. Kesalahan ini sering terjadi pada program. Sebuah parser seharusnya mampu untuk menangkap adanya kesalahan dengn efisien. 3. Semantic error Ini merupakan kesalahan yang disebabkan oleh variable underfined, tidak sesuainya operands dan operator, dll. Kesalahan ini bisa ditangkap lewat pengenalan beberapa pengujian ekstra selama parsing (penguraian). 4. Logical error Ini merupakan kesalahan seperti tak terbatasnya loop (perulangan). Di sini tidak ada jalan lain untuk mengetahui adanya kesalahan logika secara otomatis. Bagaimanapun, melakukan debugging mungkin dapat membantu programmer untuk mengetahui adanya kesalahan . Dengan demikian, sebuah tantangan yang penting dari tahap analysis syntax ini adalah untuk mendeteksi kesalahn syntax. Bagaimanapun tidak seorangpun menyukai compiler yang berhenti setelah pendeteksian kesalahan pertama karena mungkin masih banyak kesalahan yang ada. Jika semua atau sebagian besar kesalahan dapat dilaporkan ke pengguna dalam satu waktu, pengguna dapat memeriksanya dan mengiririm kembali untuk dikompilasi. Laporan suatu kesalahan pada suatu waktu dibutuhkan iterasi dalam jumlah yang besar. Tetapi, pada sebagian besar bentuk, adanya kesalahan pada aliran input menjadi ujung dari sebuah parser untuk sebuah keadaan erroneous, dari sini tidak dapat melakukan pemmrosesan lebih jauh sebelum pekerjaan ini dibatalkan. Caranya terlibat dalam pemrosesan Strategi ini melibatkan proses pengetahuan secara luas sebagai error-recovery strategies. Yang membedakan dari strategi recovery, disebutkan dengan baik sebagai berikut: 1. Panic mode 2. Phrase level 3. Error production 4. Global correction Panic mode recovery. Dalam bentuk ini, parser mengesampingkan jumlah token yang cukup untuk dicapai dalam sebuah kedaan turun pada sebuah pendeteksian kesalahan. Satu set token menandai pada akhir konstruksi bahasa yang didefinisikan untuk membuat sebuah synchronizing set. Sebagai contoh yang identik pada sinkronisasi token adalah semicolon, closing brace, end, dll, yang mana sering digunakan untuk mengakhiri kalimat atau mengeblock. Teknik ini termasuk efektif karena setiap parser memperhatikan sebuah sinkronosasi token, dan dampaknya sebelum kesalahan syntax terjadi sanagat besar kemungkinan dapat dilampaui. Walaupun, itu akan melewatkan sedikit banyak token dalam sebuah proses, yang mungkin mengenali beberapa kesalahan yang tidak asli lagi.
Phrase level recovery. Dalam bentuk ini, parser membuat koreksi local dari input untuk mendeteksi kesalahan. Jadi, hasil keluaran input memberikan susunan bahasa yang baik. Sebagai contoh dalam kategori ini termasuk mengganti koma dengan semicolon, menyelipkan karakter yang hilang, dst. Bagaimanapun juga, menyelipkan karakter baru dapat terselesaikan dengan baik sehimgga kesalahan yang asing tidak dikenali dan juga penguraian algoritma dapat diproses tanpa masalah.
Error production.Ini meliputi modifikasi pada susunan bahasa yang mengandung keadaan error. Dalam bentuk ini , compiler mendesain sebuah ide yang sangat baik tentang tipe error yang mungkin terjadi sehingga dia dapat memodifikasi susunan bahasa yang tidak sesuai. Adanya kesalahan input program disini, error production akan membuat penambahan sehingga tercipta kesesuaaian pada susunan bahasa yang baru. Global correction. Ini merupakan bentuk yang hampir mendekati bentuk teoritikal. Masalahnya, disini dapat menjadi sebuah keadaan yang mengikuti : Memberikan aliran input x yang tidak benar pada sebuah grammar G, menemukan aliran input lain berupa y yang bisa diterima oleh G, sehingga jumlah token yang menjadi berubah untuk diganti dari x ke y adalah minimum. Untuk mendekati keadaan yang digambarkan diatas membutuhkan biaya yang sangat mahal, dan untuk membuat program melalui cara error recovery mungkin tidak menjadi apa yang dpikirkan programmer pada awalnya. Sebelum lanjut ke pembahasan berikutnya pada parser, kita membutuhkan pengetahuan konsep yang sedikit mendasar dan cara penulisan yang digunakan untuk menggambarkan grammar (susunan bahasa).
Grammar Sebuah susunan bahasa dapat didefinisikan sebagai 4 tuple <V N , V T , P, S>, dimana VN adalah satu set simbol tidak berbatas yang digunakan untuk menuliskan sebuah grammar, VT adalah satu set yang berbatas (artinya, ini adalah satu set kata yang digunakan dalam bahasa), P adalah satu set aturan produksi dan S VN adalah sebuah symbol tak berbatas yang khusus untuk memanggilstart symbol pada sebuah grammar. Sebuah string dari bahasa yang digunakan berasal dari S dengan menerapkan production rulesdari P. Aturan yang diterapkan pada string perantara terdiri dari urutan dari simbol milik ke V N U V T . Jika terjadi kesesuaian dari sisi kiri pada aturan tertentu dapat ditemukan pula terjadi dalam string,ke mungkinan diganti dengan yang kesesuaian dari sisi kanan. Dengan itu, production rules menentukan bagaimana urutan dari terminal dan simbol nonterminal dapat digantikan oleh beberapa urutan lainnya. Grammar yang dipilih untuk scanner adalah Regular Grammar (RG) sedangkan untuk parser adalah Grammar Context Free (CFG). Penting diketahui perbedaan cara pandang RG dengan CFG terhadap sebuah token yang mengalir antara scanner dan parser. Bagi RG (scanner) sebuah token (kecuali reserve word) adalah sebuah kalimat dimana setiap karakter pembentuk token tersebut adalah simbol terminal. Sebaliknya bagi CFG (parser) sebuah token adalah sebuah simbol terminal dimana sederetan tertentu token akan membentuk sebuah kalimat. a. Pola umum CFG : A , A Vn, (Vn | Vt)* b. Sifat ambigu (ambiguity) Sebuah kalimat adalah ambigu jika terdapat lebih dari satu pohon sintaks yang dapat dibentuk oleh kalimat tersebut. Secara gramatikal kalimat ambigu dihasilkan oleh grammar ambigu yaitu grammar yang mengandung beberapa produksi dengan ruas kiri yang sama sedangkan dua atau lebih ruas kanan-nya mempunyai string terkiri (prefix) yang sama. Misalnya, memperhatikan tata bahasa 5 aSbS | bSaS | Untuk string "abab", kita memiliki dua kalimat pohon faktor yang berbeda seperti dalam Gambar dibawah ini. Sebuah contoh klasik dari grammar yang ambigu adalah if -then- else dibangun dari banyak bahasa pemograman. Sebagian besar bahasa punya keduanya if - then dan if -then-else dari versi pernyataan. Dengan aturan tata bahasa sebagai berikut
c. Sifat rekursi kiri (left recursion) : Sebuah grammar dikatakan bersifat rekursi kiri jika untuk sebuah simbol nonterminal A terdapat derivasi non hampa A =>=>A. Produksi berbentuk A A disebut produksi yang bersifat immediate left recursion. Sebuah immediate left recursion terjadi dalam sebuah nonterminal A yang mempunyai production rule dalam bentuk AAI. Sebuah immediate left recursion dapat dihilangkan dengan memperkenalkan symbol nonterminal yang baru, disebut A yang dimodifikasi oleh tata bahasa.Aturan tata bahasa AAI dimodifikasi sebagai,
A A A A I Oleh sebab itu, aturan A A1 I A2 I I Am I 1 I 2 I I 3 dapat dimodifikasi dengan,
A 1A I 2A II nA A 1A I 2A I I mA I
Contoh 3.2 Pertimbangan sesuai dengan tata bahasa left-recursion untuk ekspresi aritmatik
E E + T I T T T*F I F F (E) I id
Hilangkan immediate laft recursion dari aturan modifikasi sesuai tata bahasa sebagai berikut,
E TE E +TE I T FT T *FT I F (E) I id Bagaimanapun, bahkan jika mungkin tidak ada immediate left recursion, sejumlah production rules mungkin akan beraksi bersama untuyk memberikan general left recursion. Sebagai contoh, dengan mempertimbangkan tata bahasa,
S Aa A Sb I c Disini, S adalah left recursion, karena S Aa Sba. Bentuk general left recursion dapat digantikan dengan mengikuti algoritma. Algoritma menjamin tata bahasa tetap bekerja tanpa berputar. Dengan demikian, ini bukanya tidak mungkin berasal dari nonterminal, disebut A, mulai dari dirinya sendiri dan tidak ada hasil .
Algorithm eliminate_left_recursion 1. Menyusun nonterminal menjadi beberapa bentuk yan disebut A1 , A2, ., Am. 2.Untuk i = 1 to m do Untuk j = 1 to i 1 do Untuk setiap produksi Ai Aj dan Aj 1 I 2 IIk Diganti Ai Aj oleh Aj 1 I 2 IIk 3.Hilangkan immediate left recursion dari semua produksi
Sebagai contoh, dengan mempertimbangkan tata bahasa, S Aa ASb I c Dengan memerintahkan nonterminal menjadi S, A. Untuk i = 1. Aturan S Aa dilalui, sejak ini maka immediate left recursion tidak ada. Untuk i = 2. A Sb I c demodifikasi sebagai berikut, A Aab I c yang mempunyai immediate left recursion dan karenanya dieliminasi oleh modifikasi aturan sebagai berikut,
A cA A abA I
Predictive Parser Predictive Parser akan digunakan untuk mengimplementasikan Penganalisa Sintaks (Parser). Berikut ini adalah model dari Predictive Parser. INPUT . a + b . $
Stack X Predictive Parsing OUTPUT Y Program (P3) Z
$ Parsing Table M
Input : rangkaian token dan diakhiri dengan tanda $. Stack : berisi simbol grammar (V atau V ). Pada keadaan awal stack hanya berisi $ dan(symbol awal).
Parsing Table M : array 2 dimensi M(A,a), dimana A adalah symbol nonterminal dan a adalah simbol terminal (token) atau sibol $. Nilai M(A,a) adalah : sebuah produksi A a atau tanda-tanda kesalahan (keduanya akan dibahas kemudian). Predictive Parsing Program (P3) : sebuah program yang mengendalikan parser berdasar-kan nilai A dan a. Sifat dan tanggapan P3 terhadap simbol A (pada stack) dan a (pada input) : 1. Jika A = a = $ : parser berhenti dan memberitahukan bahwa kerja parser telah selesai tanpa ditemukan kesalahan sintaks. 2. Jika A = a $ : parser akan mengeluarkan A dari stack, dan selanjutnya membaca token berikutnya. 3. Jika A Vt , A a : terjadi kesalahan sintaks, dan selanjutnya akan dipanggil routine penanganan kesalahan (error handler). 4. Jika A Vn UVW maka parser akan mengganti A dengan WVU (yaitu dengan U berada di puncak Stack). Jika M(A,a) berisi tanda-tanda kesalahan maka parser akan memang- gil Error_Handler routine.
Parsing Table M Parsing Table M dibentuk berdasarkan dua fungsi yang berhubungan dengan suatu tata bahasa. Kedua fungsi tersebut adalah First(X), X e (V N |V T ) dan Follow(Y), Y e V N . First(X) adalah himpunan simbol terminal yang merupakan simbol pertama dari X atau merupakan simbol pertama dari simbol-simbol yang dapat diturunkan dari X. Follow(Y) adalah himpunan simbol terminal yang dapat muncul tepat di sebelah kanan Y melalui nol atau lebih derivasi. Ketentuan selengkapnya tentang First(X) dan Follow(Y) adalah sebagai berikut. a. First(X) a1. Jika X e V T maka First(X) = {X} a2. Jika terdapat X ao maka a e First(X). Jika X c maka c e First(X) a3. Jika X Y 1 Y 2 ...Y k maka First(Y 1 ) c First(X). Jika ternyata Y 1 dapat men-derivasi c (sehingga c e First(Y 1 )) maka First(Y 2 ) juga subset dari First(X). Jelaslah jika semua First(Y i ) mengandung c , i = 1, 2, ..., n, maka semua elemen First(Y i ) adalah juga elemen First(X).
b. Follow(X) b1. Jika X = S = simbol awal maka $ e Follow(S) b2. Jika X oY|, | = c , maka {First(|) - {c}} c Follow(Y) b3. Jika 1. X oY atau 2. X oY| dimana c e First(|) maka Follow(X) c Follow(Y)
Contoh : Diketahui himpunan produksi : 1. E TE, 2. E +TE|c , 3. T FT, 4. T *FT|c , 5. F (E)|id Fisrt : ^ dari (5) dengan aturan (a2) : First(F) = {(, id} ^ dari (3) dengan aturan (a3) : First(T) = First(F) dari (1) dengan aturan (a3) : First(E) = Fisrt(T) sehingga : First(E) = Fisrt(T) = First(F) = {(, id} ^ dari(2) dengan aturan (a2) : First(E) = {+, c} ^ dari (4) dengan aturan (a2) : First(T) = {*, c} Follow : ^ dari(1) dengan aturan (b1) : $ e Follow(E) karena E = simbol awal, dari (5) dengan aturan (b2) dan (a1) : ) e Follow(E) sehingga : Follow(E) = {$, )} ^ dari(1) dengan aturan (b3.1) X oY : Follow(E) c Follow(E) sehingga Follow(E) = {$, )} ^ dari(1) (dan (2)) dengan aturan (b2) : {First(E) - {c}} = {+} c Follow(T) dari(1) dan aturan (b3.2) X oY|, o = c : Follow(E) = {$, )}c Follow(T) sehingga : Follow(T) = {$, ), +} ^ dari(3) dengan aturan(b3.1) : X oY : Follow(T) c Follow(T) sehingga : Follow(T) = {$, ), +} ^ dari(4) dengan aturan (b2) : {First(T) - {c}} = {*} c Follow(F) dari(3) dengan aturan(b3.2) X oY|, o = c : Follow(T) c Follow(F) sehingga : Follow(F) = {$, ), +,*} Singkatnya : First(E) = Fisrt(T) = First(F) = {(, id} First(E) = {+, c} First(T) = {*, c} Follow(E) = Follow(E) ={$, )} Follow(T) = Follow(T) = {$, ), +,*} Follow(F) = {$, ), +,*}
Dengan kedua fungsi First(X) dan Follow(X) di atas maka Parsing Table M disusun melalui algoritma berikut : Algoritma Parsing_Table 1. for setiap produksi A o do begin 1a . for setiap a e First(o) do M(A, a) = A o 1b. if c e First(o) then for setiap b e Follow(A) do M(A, b) = A o 1c. if (c e First(o)) and ($e Follow(A) then M(A, $) = A o end 2. if M(A, a) = blank then M(A, a) = error
Jika algoritma di atas diterapkan kepada grammar : 1. E TE, 2. E +TE|c , 3. T FT, 4. T *FT|c , 5. F (E)|id Maka : ^ E TE Karena : First(TE) = Fisrt(T) = {(, id} maka menurut (1a) : M(E, () = M(E, id) = E TE ^ E +TE Karena : + e FIRST(+TE) maka menurut aturan (1a) : M(E, +) = E +TE ^ E c Karena : c e FIRST(E) dan {), $) c Follow(E) maka menurut aturan (1b) : M(E, )) = M(E, $) = E c ^ T FT Karena : First(FT) = First(F) = {(, id) maka menurut aturan (1a) : M(T, () = M(T, id) = T FT ^ T *FT Karena : * e First(*FT) maka menurut aturan (1a) : M(T, *) = T *FT ^ T c Karena : c e First(T) dan {+, ), $) c Follow(T) maka menurut aturan (1b) : M(T, +) = M(T, )) = M(T, $) = T c ^ F id Karena : id e First(F) maka menurut aturan (1a) : M(F, id) = F id ^ F (E) Karena : ( e First(F) maka menurut aturan (1a) : M(F, () = F (E) Akhirnya diperoleh tabel berikut :
Non Simbol Input Terminal id + * ( ) $ E E TE error error E TE error error E error E +TE error error E c E c T T FT error error T FT error error T error T c T *FT error T c T c F F id error error F (E) error error
Berikut ini ditunjukkan tabulasi aksi yang dilakukan predictive parser berdasarkan parser table M di atas terhadap rangkaian token : id + id * id : Stack Input Output Keterangan $E id + id * id $ E = simbol awal, M(E, id) = E TE ganti E dengan TE, T di top of stack $ET id + id * id $ E TE M(T, id) = T FT (ganti T dengan FT) $ETF id + id * id $ T FT M(F, id) = F id (ganti F dengan id) $ETid id + id * id $ F id top of stack = left most input : drop them ! $ET + id * id $ M(T, +) = T c (ganti T dengan c ) $E + id * id $ T c M(E, +) = E +TE (ganti E dg. TE) $ET+ + id * id $ E +TE top of stack = left most input : drop them ! $ET id * id $ M(T, id) = T FT (ganti T dengan FT) $ETF id * id $ T FT M(F, id) = F id (ganti F dengan id) $ETid id * id $ F id top of stack = left most input : drop them ! $ET * id $ M(T, *) = T *FT (ganti T dg. *FT ) $ETF* * id $ T c top of stack = left most input : drop them ! $ETF id $ M(F, id) = F id (ganti F dengan id) $ETid id $ F id top of stack = left most input : drop them ! $ET $ M(T, $) = T c (ganti T dengan c ) $E $ T c M(E, $) = E c (ganti E dengan c ) $ $ E c top of stack = left most input = $ : finish !! rangkaian token : id + id * id sesuai sintaks
DAFTAR PUSTAKA http://ifengineer07.wordpress.com/2009/07/09/bab-iii-syntax-analysis/ di akses 25/11/13 7.15 PM