06. PERANCANGAN SCANNER - Teknik Kompilasi.zip

  06. PERANCANGAN SCANNER

  1. Bahasa Sumber

  Bahasa adalah kumpulan kalimat. Kalimat adalah rangkaian kata. Kata

  ƒ

  adalah unit terkecil dari komponen bahasa yang tidak bisa dipisahkan lagi.

  

ƒ Kalimat-kalimat : ‘Seekor kucing memakan seekor tikus.’ dan ‘Budi

menendang sebuah bola.’ adalah dua contoh kalimat lengkap Bahasa Indonesia.

  ‘A cat eats a mouse’ dan ‘Budi kick a ball.’ adalah dua contoh kalimat

  ƒ lengkap Bahasa Inggeris.

ƒ ‘if a2 < 9.0 then b2 := a2+a3;’ dan ‘for i := start to finish do A[i] :=

  B[i]*sin(i*pi/16.0).’ adalah dua contoh kalimat lengkap dalam Bahasa Pemrograman Pascal.

  Dalam bahasa pemrograman, kalimat lebih dikenal sebagai ekspresi

  ƒ sedangkan kata sebagai token.

  Perancangan sebuah bahasa harus memperhatikan tiga aspek berikut : 1. spesifikasi leksikal, misalnya setiap kata harus tersusun atas huruf mati dan huruf hidup yang disusun bergantian, atau setiap token harus dimulai dengan huruf dan selanjutnya boleh diikuti oleh huruf atau angka,

  2. spesifikasi sintaks, misalnya setiap kalimat mengikuti pola subyek-

  predikat-obyek atau ekspresi for_do mengikuti pola for-identifier-:=- identifier-to-identifier-do-ekspresi.

  3. aturan-aturan semantik, misalnya kata yang mendahului kata kerja haruslah kata benda yang menggambarkan sesuatu yang hidup dan berkaki, atau operasi perkalian hanya bisa dilakukan antara dua operan dengan tipe yang sama.

  Pada rancangan bahasa di atas, perhatikan hal-hal berikut. Kita tidak bisa mengganti kata Budi dengan 2udi sebagaimana kita tidak bisa mengganti token start dengan ?tart. Kita juga tidak bisa merubah susunan kata-kata menjadi Budi sebuah menendang bola sebagaimana kita tidak boleh merubah susunan token menjadi 9.0 if < a2 then b2:= a2. Demikian pula kita tidak boleh mengganti kata Budi dengan lemari sebagaimana kita tidak boleh mengganti B[i]*sin(i*pi/16.0) dengan B*sin(i*pi/16.0).

  Dalam spesifikasi leksikal biasanya digunakan grammar regular (GR) dalam bentuk ekspresi regular (ER). Sebagai contoh pola token identifier ditentukan oleh grammar regular berikut :

  I → aAbA...zAab...z,

  A → aAbA...zA0A1A...9Aab...z01...9 yang ekuivalen dengan ekspresi regular berikut :

  I = (ab...z)( ab...z01...9)* = huruf(hurufangka)* Dalam spesifikasi sintaks biasanya digunakan context free grammar (CFG). Sebagai contoh ekspresi if-then E adalah :

  E → if L then,

  L → IOA, I = huruf(hurufangka)*,

  O → <=><=>=,

  A →01...9.

  Algoritma Scanning

  Scanner diimplementasikan dengan Automata Hingga Deterministik

  ƒ (AHD). ƒ Sebagai contoh,

  scanner (yaitu AHD) untuk mengenali identifier adalah :

  • Algoritma scanning adalah algoritma yang digunakan untuk menentukan token dalam analisis leksikal.
  • Contoh kasus penyusunan algoritma scanning yang disusun dari sebuah diagram transisi sebuah automata hingga adalah sebagai berikut:
  • Diagram transisi ini menggambarkan pola sebuah bahasa yang terdiri dari token <, <=, =, >=, >, ( ), (, ), +, -, *, /, :=, identifier, ; , keyword, konstanta, literal (yang diapit oleh apostrof).
  • Baris komentar, yang dimulai dengan /* dan diakhiri dengan */, dan blank, diabaikan, dan diartikan semata-mata sebagai pemisah Token.
  • Busur berlabel "NOT" mendahului sebuah karakter, menunjukkan

  bahwa semua karakter input selain dari karakter tadi, akan mengikuti transisi.

  • Busur berlabel "ERROR" menunjukkan bahwa suatu karakter adalah invalid (tidak berlaku), ditemukan dalam program sumber. Karakter ini bukan merupakan suatu Token yang manapun, kecuali jika ia terdapat di dalam komentar, atau dalam lateral.
  • Stata 5, 6, dan 7 digunakan untuk mengenali Token <, <=, dan <>. Jika bukan karakter = atau > mengikuti karakter <, maka Akseptor akan berakhir pada Stata Akhir 5, ini menunjukkan bahwa Token < telah terkenali. Dalam hal ini Token <= atau <> akan dikenali juga. Token <= bila Akseptor berakhir di Stata 6, atau Token <> bila berakhir di Stata 7.
  • Dengan cara yang sama, masing- masing Stata 2, 3, dan 4 digunakan untuk mengidentifikasi komentar dan Token /. Semua karakter sesudah tanda /* sampai dengan karakter yang diikuti oleh */ merupakan isi dari komentar. Komentar tidak akan dikirim sebagai Token. Dan selanjutnya kembali ke Stata Awal.
  • Stata 19 dan 22 digunakan berturut- turut untuk mengenali identifier dan konstanta integer. Identifier dimulai dengan sebuah huruf dan diikuti sejumlah karakter alfanumerik. Konstanta merupakan sebarisan digit, yang dianggap satu Token sampai suatu karakter non numerik terbaca.
  • Stata 20 dan 21 mengidentifikasi untai literal. Ia dimulai dan diakhiri dengan tanda apostrof ( ' ), dengan Stata Akhir 21 menunjukkan akhir
dari literal. Dua tanda apostrof yang berturutan dapat digunakan untuk menyatakan sebuah karakter dalam untai. Bila hal ini terjadi maka transisi dari Stata 21 ke Stata 20 terjadi. Dari diagram transisi suatu “automata hingga” tersebut di atas yang menggambarkan suatu bahasa pemrograman tertentu, dapat disusun sebuah algoritma scanning sebagai berikut ; (Prosedur disusun dari beberapa sub-prosedur atau Function misalnya; POS, GET_CHAR, KEYWORD, LOOKAHEAD, dll.

  • POS digunakan untuk memberikan nomor "entry" atau nomor pada tabel simbol yang memberikan label pada setiap token.
  • GET_CHAR(PROGRAM) digunakan untuk mendapatkan karakter input berikutnya dari program sumber.
  • LOOKAHEAD adalah variabel logika yang menunjukkan apakah simbol lookahead dalam CHAR sudah digunakan sebelumnya. Harga "false" menyatakan bahwa simbol lookahead itu belum dipergunakan.
  • CHAR menyatakan karakter yang pada saat itu tengah disidik(diperiksa) dalam untaian karakter sumber.
  • INSERT(STRING, type) digunakan untuk memasukkan Token yang diberikan, STRING(jika perlu), dan tipenya (sebagai contoh: konstanta, literal, atau nama variabel).
  • KEYWORD(STRING) digunakan untuk menentukan apakah argumennya adalah keyword, dan jika benar akan dikirimkan bilangan penyajian internal dari Token ini, dan jika bukan maka 0 (nol).
  • Variabel local STRING mengandung Token aktual berisi nama variabel, literal, atau konstanta. Terakhir, variabel DIVISION, LEQ, NEQ, GEQ, GTN, EQ, LEFT, RIGHT, ADDITION, SUBTRACTION, MULTIPLICATION, ASSIGNMENT, SEMICOLON, LITERAL,

  IDENTIFIER dan CONSTANT, berisi bilangan penyajian internal dari Token /, <=, <>, <, >=, >, =, (, ), +, -, *, :=, ;, literal, identifier, dan konstanta.

  Algoritmanya dapat dituliskan sbb. 1. (Inisialisasi)

  POS

  ←

  2. (Mendapatkan karakter pertama) if not LOOKAHEAD then CHAR GET_CHAR (PROGRAM)

  ←

  LOOKAHEAD false 3. (Ulangi sampai sebuah Token diketemukan)

  Repeat langkah 4 while true 4. (Statemen CASE untuk menentukan Token berikut) select by (CHAR) case ' ' :

  (scan dan abaikan blank)

  ←

  CHAR GET_CHAR(PROGRAM) case '/' :

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = '*' (scan dan abaikan komentar) then Repeat while true

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = '*' (scan dan abaikan komentar) then Repeat while CHAR = '*'

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = '/'

  ←

  then CHAR GET_CHAR(PROGRAM) Exit loop

  ←

  else LOOKAHEAD true

  ←

  TOKEN DIVISION ( / ) Return case '<' :

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = '='

  ←

  then TOKEN LEQ ( <= ) else if CHAR = '>'

  ←

  then TOKEN NEQ ( <> )

  ←

  else LOOKAHEAD true

  ←

  TOKEN LTN ( < ) Return case '>' :

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = '=' then TOKEN GEQ ( >= )

  ←

  else LOOKAHEAD true

  ←

  TOKEN GTN ( > ) Return case '=' : ( = )

  ←

  TOKEN EQ Return case '(' : ( ) )

  ←

  TOKEN LEFT Return case ')' : ( ) )

  ←

  TOKEN RIGHT Return case '+' : ( + )

  ←

  TOKEN ADDITION Return case '-' : ( = )

  ←

  TOKEN SUBTRACTION Return case ':' :

  ←

  TOKEN GET_CHAR(PROGRAM) if CHAR = '='

  ←

  then TOKEN ASSIGNMENT ( := ) Return else

  ←

  CHAR GET_CHAR(PROGRAM) write ('UNKNOWN TOKEN'':''', CHAR,'IN SOURCE STRING') case ';' : ( ; )

  ←

  TOKEN SEMICOLON Return case '' '' : ( literal )

  ←

  STRING ' '

  Repeat while true

  ←

  CHAR GET_CHAR(PROGRAM) if CHAR = ''''

  ←

  then CHAR GET_CHAR(PROGRAM) if CHAR ''''

  ←

  then LOOKAHEAD true

  ←

  POS

  INSERT(STRING, LITERAL)

  ←

  TOKEN LITERAL Return

  ←

  STRING STRING.CHAR Default: if CHAR >= 'A' dan CHAR <= 'Z'

  ←

  then STRING CHAR (identifier)

  ←

  CHAR GET_CHAR Repeat while (CHAR >= 'A' AND CHAR <= 'Z') or (CHAR >= '0' AND <= '9')

  ←

  STRING STRING.CHAR

  ←

  CHAR GET_CHAR

  ←

  LOOKAHEAD true if KEYWORD(STRING) > 0

  ←

  then TOKEN KEYWORD(STRING) Return

  ←

  POS

  INSERT(STRING,IDENTIFIER)

  ←

  TOKEN

  IDENTIFIER Return if CHAR >= '0' and CHAR <= '9' (konstanta)

  ←

  then STRING CHAR

  ←

  CHAR GET_CHAR(PROGRAM) Repeat while CHAR >= '0' and CHAR <= '9'

  ←

  STRING STRING.CHAR

  ←

  CHAR GET_CHAR(PROGRAM)

  ←

  LOOKAHEAD true

  ←

  POS

  INSERT(STRING,CONSTANT)

  ←

  TOKEN CONSTANT Return write ('ERROR-UNKNOWN CHARACTER', CHAR.IN SOURCE

  STRING')

  ←

  CHAR GET_CHAR(PROGRAM) Keterangan: 1. Langkah 1 menginisialisasi harga function POS dengan harga nol.

  Function POS disiapkan untuk menyimpan harga tabel dari suatu identifier, konstanta, ataupun literal dalam langkah 4.

  2. Langkah 2 memperoleh simbol input saat itu, jika LOOKAHEAD tidak digunakan pada pemanggilan terdahulu dari scan.

  3. Langkah 3 menjalankan langkah 4 berulang-ulang. Karena komentar dan blank diabaikan dalam proses scanning, langkah 4 pasti berulang dalam kasus seperti itu.

  4. Langkah 4 menggunakan Statemen Case bercabang tergantung dari harga karakter saat itu tengah disidik. Ia secara khusus menjalankan potongan algoritma, yang menyebabkan transisi Stata hingga Akseptor.

  3. Membaca Program Sumber

  type Text_Pos = record {posisi penunjuk karakter} Row_Numb : word; {baris ke-, bisa ribuan baris/program_sumber} Char_Numb : byte; {karakter ke-, maksimum 255 karakter/baris} end; var Now_Pos : Text_Pos; {posisi sekarang}

  Line : string; {baris yang sedang diproses} End_of_line : byte; {posisi akhir baris yang sedang diproses} procedure Next_Character(var Ft : text); {baca karakter berikutnya pada

   program_sumber}

  begin with Now_Pos do {coba tebak, apa itu perintah with ... do ?} begin if Char_Numb = End_of_line then begin

  List_Line;

  {menampilkan kembali baris yang telah

   dibaca, beserta errornya}

  Next_Line(Ft); {membaca baris berikutnya}

  Row_Numb := Row_Numb + 1; Char_Numb := 1 end else

  Char_Numb := Char_Numb + 1; character := Line[Char_Numb] end end; procedure List_Line; begin write(Now_Pos.Row_Numb : 3, ‘ ‘); writeln(Line);

  

List_Error; {menampilkan kesalahan-kesalahan yang terjadi pada

suatu baris}

  End procedure Next_Line(Ft : text); begin readln(Ft, Line);

  End_of_line := length(Line) + 1: Line := Line + #32; {karakter spasi} end;

  Simulasi DFA Simulasi DFA dimaksudkan untuk mengenali token.

  type Token_Kind = record tipe : byte; nilai : byte end; var Token : array[0..Max_State] of Token_Kind;

  Found_Token : Token_Kind; {token yang ditemukan} Tok_Pos : Text_Pos; {posisi token dalam program sumber} procedure Next_Token(var Ft : text); {digunakan untuk mengenali sebuah

  token}

  var state1, state2 : shortint; begin state1 := 0; Tok_Pos := Now_Pos; repeat state2 := Next_State(state1, character); if state2 <> -1 then {-1 bersesuaian dengan x pada tabel transisi} begin state1 := state2;

  

Next_Character(Ft); {baca karakter berikut pada program

sumber, di antaranya menghasilkan nilai baru untuk Now_Pos}

  end; until state2 = -1;

  Act_for_Token(state1);

  end; procedure Act_for_Token(state : shortint); var Tok_Length : byte;

  Err : integer; begin

  Current_Token(Token[state].tipe, Token[state].nilai);

  Tok_Length := Now_Pos.Char_Numb - Tok_Pos.Char_Numb; case Token[state].tipe of 0 : Error(‘Token tidak dikenal!’, Tok_Pos); 27 : Id := copy(Line, Tok_Pos.Char_Num, Tok_Length); 28 : val(copy(Line, Tok_Pos.Char_Num, Tok_Length), IN, Err); 29 : val(copy(Line, Tok_Pos.Char_Num, Tok_Length), RN, Err); end end;

  catatan :

  copy(string, start, length) mengembalikan substring

  ƒ

  val(string_value, number_variable, error_flag) :

  ƒ

  jika string value = ‘137’ maka number variable = 137 dan error flag = 0 jika string value = ‘string’ maka number variable = 137 dan error flag ≠ 0

  Token.tipe ฀ {1, 2, 3, ..., 26} dimisalkan bernilai pasti, sehingga tidak

  ƒ

  perlu penanganan lebih lanjut procedure Current_Token(tipe, nilai : byte); begin

  Found_Token.tipe := tipe; Found_Token.nilai := nilai; end;

LATIHAN SOAL

  1. Misalkan a dan b adalah simbol input. Buatlah sebuah AHD (Automata Hingga Deterministik) M yang hanya menerima untaian karakter yang mengandung sejumlah genap a. (Contohnya untai aababab atau aa dapat diterima, sedangkan untai ababa atau abbb tidak diterima).

  2. Buatlah sebuah Automata Hingga Deterministik dengan simbol input a,b, yang hanya dapat menerima untai karakter yang mengandung sejumlah b yang habis dibagi 3. (Petunjuk: dibutuhkan 3 Stata)

  3. Buatlah sebuah Automata Hingga Deterministik M dengan simbol input a dan b, yang hanya dapat menerima untai karakter yang mengandung sejumlah genap a dan sejumlah b yang habis dibagi 3.

  4. Misalkan M1(K , V , Z , q , f ) dan M2(K , V , Z , s , f ) adalah dua

1 T

  1

  1

  2 T

  2

  2

  buah Automata Hingga Deterministik dengan himpunan simbol input V yang sama. Misalkan L(M1) dan L(M2) berturut-turut adalah

  T

  himpunan untai yang dapat diterima oleh M1 dan M2. Buatlah sebuah Automata Hingga Deterministik N dengan himpunan simbol input V

  T

  yang dapat menerima L(M1) IRISAN L(M2), yakni untai yang dapat diterima baik oleh M1 dan M2.