PL: Interpreter

Interpreter (Yorumlayıcı olarak Türkçeleştirilebilir) kaynak kodunu satır satır işleten yazılım türüne verilen addır.

Külyutmaz Külyutmaz   Külyutmaz 2.1 Gül ile beraber JAVA'da geliştirdiğimiz yorumlayıcıdır. Ödevde bize verilen dilin kurallarına uygun her şeyi kabul ederken, kurallara aykırı hiçbir şeyi kabul etmemekte, kısaca kül yutmamaktadır. Sonuçta, verilen işlemi yorumlayarak (interpreting) bir tam sayı (integer) üretmektedir.

JAVA’nın String Tokenizer nesnesi metnimizi tokenlarına istediğimiz gibi ayırmayı beceremediği için, tüm metni harf harf analiz ederek kendimiz ayırmaktayız.

“;” gelene kadarki tüm karakterler bir kodun parçasıdır. İster bir satıra 30 kod yazın, ister 30 satıra bir kod, program için fark etmeyecektir. Ayrıca TAB (\t) karakterini de kullanabilirsiniz. Program yazım hatası (syntax error) yaptığınız durumda size takıldığı satır ve sütun numaralarını verecektir. Hatanızı yakınlarda bir yerlerde aramalısınız.

Programın ekrana yazacağı çıktı result değişkenine atanmalıdır. Değişkenlerin 32 karakter sınırlı ve büyük küçük harf duyarlı oldukları unutulmamalıdır.

Daha ayrıntılı açıklamalar projenin raporunda bulunabilir.

Ödev kontrolünde kullanılan dosyalar ödevin çözümü içerisinde yer almaktadır. Daha çılgın dosyaları çalıştırmak sizin hayal gücünüze kalmış. 😃

Kaynak kodunu sadece örnek almak ve fikir edinmek amacıyla kullanabilirsiniz. Kaynak kodunu indirmek istemezseniz, bir kopyasına aşağıdan ulaşabilirsiniz.

Dipnot: Bu proje Recursive Descent Parsing kullanmamaktadır. Kullandımız metodu kendimiz geliştirdik ve gayet etkin olduuna inanıyoruz. Belki literatürde adı vardır, bilmiyoruz.

Programdaki algoritmanın çalışma mantığını raporda bulabilirsiniz. (Zaten RDP'ye oldukça yakın.)

Külyutmaz 2.1

ColRow.java ```java public class ColRow { /* yalnızca satır sütun bilgisi tutuluyor... */ int col; int row; public ColRow(int row, int col) { this.row = row; this.col = col; } }


*ColRowChar.java* ```java
 public class ColRowChar { /* satır sütun bilgisinin dısında bunun hangi karaktere ait oldugu bilgisi tutuluyor...*/ int col; int row; char c; public ColRowChar(ColRow cr, char c) { this.row = cr.row; this.col = cr.col; this.c = c; } }

CString.java ```java import java.util.Vector;

public class CString {

private Vector<ColRow> colrow = new Vector<ColRow>();

private String str = new String(); private int index = 0;

public void addChar(char chaR, int row, int col) { /* Gelen karakteri row coloumn degerleriyle stringe ekliyor... */ str = str + chaR; colrow.add(index, new ColRow(row, col)); index++; }

public void addChar(ColRowChar crc) { /* * ColRowChar sınıfından gelen karakteri row coloumn degerletiyle * stringe ekliyor... */ str = str + crc.c; colrow.add(index, new ColRow(crc.row, crc.col)); index++; }

public int length() { /* string uzunlugunu döndürüyor... */ return str.length(); }

public char charAt(int i) { /* Belirtilen indexteki karakteri döndürüyor... */ return str.charAt(i); }

/* * Bundan sonraki metodlar için ColRow nesnesi türetilerek satır sütun * bilgileri okunuyor.. */

public int rowAt(int i) { /* * Belirtilen indexteki karakterin kaçıncı satıra ait oldugu bilgisi * döndürülüyor... */ ColRow temp = colrow.elementAt(i); return temp.row; }

public int colAt(int i) { /* * Belirtilen indexteki karakterin kaçıncı sütuna ait oldugu bilgisi * döndürülüyor... */ ColRow temp = colrow.elementAt(i); return temp.col; }

public ColRowChar everythingAt(int i) { /* * Belirtilen indexteki karakterin kaçıncı satır&sütuna ait oldugu * bilgisi ve hangi karaktere ait oldugu döndürülüyor... */ return new ColRowChar(colrow.elementAt(i), str.charAt(i)); }

public String toString() { /* Stringi döndürüyor... */ return str; }

public CString concat(CString s1, CString s2) { /* Stringlerde ;Cstring tipi için concat işlemini sağlıyor... */

for (int i = 0; i < s2.length(); i++) { s1.addChar(s2.everythingAt(i)); } return s1; } }


*ErrHandler.java* ```java
 public class ErrHandler {

public void addError(String message, int row, int col) { System.out.println(message + " Line: " + row + " Column: " + col); System.exit(0); } }

Main.java ```java import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import javax.swing.JOptionPane;

public class Main {

public static ErrHandler e = new ErrHandler(); public static VariableManager vm = new VariableManager();

public static void main(String[] args) { int lineNumber = 1; int columnNumber = 1;

System.out.println("Külyutmaz 2.1"); System.out.println("05-06-7699 Umut BENZER"); System.out.println("05-06-7670 Gül DELİORMAN\n");

CString girdi = new CString(); String path; path = JOptionPane.showInputDialog("Dosya yolunu giriniz:"); if (path == null) { e.addError("I/O Error. User cancelled.", -1, -1); } try { final BufferedReader in = new BufferedReader(new FileReader(path)); String txt = null; /* * Dosyadan bilgiler satır satır okunurken hangi sırada okundugu= * column ! ve kaçıncı satıra ait oldugu bilgisi= line !, yeni * string sınıfından olusan stringe ekleniyor / while ((txt = in.readLine()) != null) { for (int i = 0; i < txt.length(); i++) { girdi.addChar(txt.charAt(i), lineNumber, columnNumber); columnNumber++; } girdi.addChar('\n', lineNumber, columnNumber); columnNumber = 1; lineNumber++; } in.close(); } catch (final IOException a) { e.addError("I/O Error. Check path for file. (" + path + ")", -1, -1); } / girdi = <olduğu gibi metin dosyası satır sonu falan da var. */ statements(girdi); if (vm.isVariableExists("result")) { System.out.println("Result: " + vm.getVariableValue("result")); } else { e.addError("Variable result is not defined.", -1, -1); } }

public static boolean statements(CString input) { CString one_word = new CString(); for (int i = 0; i < input.length(); i++) { /* Toplam koddaki harf sayısı kadar dönüver / / Bu kısımda komut komut ayrıştırırız. */ if (input.charAt(i) == ';') { boolean status = false; for (int ii = 0; ii < one_word.length(); ii++) { if (!(one_word.charAt(ii) == '\t' || one_word.charAt(ii) == '\n' || one_word.charAt(ii) == ' ')) { status = true; } } if (!status) { e.addError("Unexpected character ';'. A proper statement nexpected? expected. 😃", input.rowAt(i),input.colAt(i) + 1); } assignment(one_word); one_word = new CString(); // Elimizdekini sıfırlama yolu! } else { one_word.addChar(input.everythingAt(i)); } } for (int i = 0; i < one_word.length(); i++) { if (!(one_word.charAt(i) == ' ' || one_word.charAt(i) == '\t' || one_word.charAt(i) == '\n')) { e.addError("';' exptected at the end of the line.", one_word.rowAt(one_word.length() - 1), one_word.colAt(one_word.length() - 1)); } } return true; }

public static void assignment(CString one_word) { /* Bu kısımda sağ sol ayrıştırıyoruz! / CString temp = new CString(); CString left = new CString(); CString right = new CString(); boolean equal = false; int ass_cord = 0; for (int x = 0; x < one_word.length(); x++) { / * Bir satır gezilir ve sağ ve sol değişkenlerine napılır? * ayrıştırılır. */ if (one_word.charAt(x) == ':' && one_word.length() > x+1 && one_word.charAt(x + 1) == '=') { ass_cord = x; equal = true; left = temp;

temp = new CString(); x++; /* := iki karakter olduğu için. */ } else { temp.addChar(one_word.everythingAt(x)); } } right = temp; if (equal) { boolean status = false; if (left.length() > 0) { for (int i = 0; i < left.length(); i++) { if (!(left.charAt(i) == ' ' || left.charAt(i) == '\t' || left.charAt(i) == '\n')) { status = true; } } } if (!status) { e.addError("Identifer expected on the left side of assignment operator.",one_word.rowAt(ass_cord),one_word.colAt(ass_cord)); } status = false; if (right.length() > 0) { for (int i = 0; i < right.length(); i++) { if (!(right.charAt(i) == ' ' || right.charAt(i) == '\t' || right.charAt(i) == '\n')) { status = true; } } } if (!status) { e.addError("An operation excpected on the right side of assignment operator.",one_word.rowAt(ass_cord) + 1,one_word.colAt(ass_cord) + 1); } is_variable(left); vm.addVariable(varName(left), nexpr(right)); } else { e.addError("Assigment operator ':=' exptected.", one_word.rowAt(one_word.length() - 1), one_word.colAt(one_word.length() - 1)); } }

public static String varName(CString coming) { CString data = new CString();

boolean started = false; boolean finished = false; for (int i = 0; i < coming.length(); i++) { if (!started) { if (!(coming.charAt(i) == '\t' || coming.charAt(i) == '\n' || coming.charAt(i) == ' ')) { started = true; } } if (started && !finished) { if (coming.charAt(i) == '\t' || coming.charAt(i) == '\n'|| coming.charAt(i) == ' ') { finished = true; } else { data.addChar(coming.everythingAt(i)); } } if (started && finished) { if (!(coming.charAt(i) == '\t' || coming.charAt(i) == '\n' || coming.charAt(i) == ' ')) { e.addError("Unexpected character '" + coming.charAt(i) + "'.", coming.rowAt(i), coming.colAt(i)); } } }

return data.toString(); }

public static int nexpr(CString in) {

/* İşlem önceliksizine göre ayırmak lazım / / Önce +/- * Sonra * * Sonra () / / TOPLA ÇIKAR / CString left = new CString(); CString right = new CString(); int count = 0; int last_pos = 0; for (int i = 0; i < in.length(); i++) { if (in.charAt(i) == '(') { count++; } if (in.charAt(i) == ')') { count--; } if (count < 0) { e.addError("Paratesis mismatch.", in.rowAt(i), in.colAt(i)); } if (count == 0) { if (in.charAt(i) == '+' || in.charAt(i) == '-') { last_pos = i; } } } if (last_pos > 0) { for (int i = 0; i < last_pos; i++) { left.addChar(in.everythingAt(i)); } if (in.charAt(last_pos) == '+') { boolean status = false; for (int ii = last_pos+1; ii < in.length(); ii++) { if (!(in.charAt(ii) == '\t' || in.charAt(ii) == '\n' || in.charAt(ii) == ' ')) { status = true; } right.addChar(in.everythingAt(ii)); } if (!status) { e.addError("Number or variable expected on the right side of +.", in.rowAt(in.length()-1),in.colAt(in.length()-1)); } return safeAdd(nexpr(left), nexpr(right)); } if (in.charAt(last_pos) == '-') { boolean negativeNumber = true; if (left.length() != 0) { for (int ii = 0; ii<left.length();ii++) { if (!(left.charAt(ii) == ' ' || left.charAt(ii) == '\t' || left.charAt(ii) == '\n')) { negativeNumber = false; } } } if (!negativeNumber) { boolean status = false; for (int ii = last_pos+1; ii < in.length(); ii++) { if (!(in.charAt(ii) == '\t' || in.charAt(ii) == '\n' || in.charAt(ii) == ' ')) { status = true; } right.addChar(in.everythingAt(ii)); } if (!status) { e.addError("Number or variable expected on the right side of -.", in.rowAt(in.length()-1),in.colAt(in.length()-1)); } return safeSubtract(nexpr(left), nexpr(right)); } } } / ÇARP / left = new CString(); right = new CString(); count = 0; last_pos = 0; for (int i = 0; i < in.length(); i++) { if (in.charAt(i) == '(') { count++; } if (in.charAt(i) == ')') { count--; } if (count < 0) { e.addError("Paratesis mismatch.", in.rowAt(i), in.colAt(i)); } if (count == 0) { if (in.charAt(i) == '') { last_pos = i; } } } if (last_pos > 0) { for (int i = 0; i < last_pos; i++) { left.addChar(in.everythingAt(i)); } boolean status = false; for (int ii = last_pos+1; ii < in.length(); ii++) { if (!(in.charAt(ii) == '\t' || in.charAt(ii) == '\n' || in.charAt(ii) == ' ')) { status = true; } right.addChar(in.everythingAt(ii)); } if (!status) { e.addError("Number or variable expected on the right side of *.", in.rowAt(in.length()-1),in.colAt(in.length()-1)); } status = false; for (int ii = 0; ii < left.length(); ii++) { if (!(left.charAt(ii) == '\t' || left.charAt(ii) == '\n' || left.charAt(ii) == ' ')) { status = true; } } if (!status) { e.addError("Number or variable expected on the left side of .", in.rowAt(in.length()-1),in.colAt(in.length()-1)); } return safeMultiple(nexpr(left), nexpr(right)); } / PARANTEZ / right = new CString(); for (int i = 0; i < in.length(); i++) { if (in.charAt(i) == '(') { for (int ii = i; ii < in.length(); ii++) { right.addChar(in.everythingAt(ii)); } CString temp = inParant(right); if (temp.length() == 0) { e.addError("Variable or constant expected inside the paranthesis.", in.rowAt(in.length()-1), in.colAt(in.length()-1)); } return nexpr(temp); } } / SAYI YA DA VERİEYBIL */ CString data = new CString();

boolean started = false; boolean finished = false; for (int i = 0; i < in.length(); i++) { if (!started) { if (!(in.charAt(i) == '\t' || in.charAt(i) == '\n' || in.charAt(i) == ' ')) { started = true; } } if (started && !finished) { if (in.charAt(i) == '\t' || in.charAt(i) == '\n' || in.charAt(i) == ' ') { finished = true; } else { data.addChar(in.everythingAt(i)); } } if (started && finished) { if (!(in.charAt(i) == '\t' || in.charAt(i) == '\n' || in.charAt(i) == ' ')) { e.addError("Unexpected character '" + in.charAt(i) + "'.", in.rowAt(i), in.colAt(i)); } } } if (!started) { e.addError("Unexpected character '" + in.charAt(in.length()-1) + "'. Constant or variable expected.", in.rowAt(in.length()-1), in.colAt(in.length()-1)); } if (is_numeric(data.charAt(0)) || data.charAt(0) == '-') { if (is_integer(data)) { /* Höm, demek ki bu bi sayı. */ return Integer.parseInt(data.toString()); } else { for (int j = 1; j < data.length(); j++) { if (!is_numeric(data.charAt(j))) { e.addError("Unexpected character " + data.charAt(j) + ". Expecting numeric value.", data.rowAt(j), data.colAt(j)); } } e.addError("Constant value out of bounds.", data.rowAt(0), data.colAt(0)); } }

is_variable(data); /* Hayır, değişken. */ if (!vm.isVariableExists(data.toString())) { e.addError("Variable used before it was initialized.", data.rowAt(0), data.colAt(0)); } return vm.getVariableValue(data.toString()); } public static CString inParant(CString in) { boolean started = false; boolean finished = false; CString data = new CString(); int count = 0; for (int i = 0; i < in.length(); i++) { if (!started) { if (in.charAt(i) == '(') { started = true; } else if (!(in.charAt(i) == '\t' || in.charAt(i) == '\n' || in.charAt(i) == ' ')) { e.addError("Unexpected character '" + in.charAt(i) + "'. '(' expected.", in.rowAt(i), in.colAt(i)); } } else if (started && !finished) { if (in.charAt(i) == ')') { if (count == 0) { finished = true; continue; } else { data.addChar(in.everythingAt(i)); count--; } } else if (in.charAt(i) == '(') { count++; data.addChar(in.everythingAt(i)); } else { data.addChar(in.everythingAt(i)); } } else if (started && finished) { if (!(in.charAt(i) == '\t' || in.charAt(i) == '\n' || in.charAt(i) == ' ')) { e.addError("Unexpected character '" + in.charAt(i) + "'.", in.rowAt(i), in.colAt(i)); } } } if (!started) { e.addError("'(' expected. Parantesis mismatch.", in.rowAt(0), in.colAt(0)); } return data; }

/** * Gönderilen Stringin geçerli bir variable olup olmadığını bulur * * @param suspect * @return boolean */ public static boolean is_variable(CString suspect) { boolean started = false; boolean finished = false; int count = 0; for (int i = 0; i < suspect.length(); i++) { if (!started) { if (is_character(suspect.charAt(i))) { started = true; } else if (!(suspect.charAt(i) == '\t' || suspect.charAt(i) == '\n' || suspect.charAt(i) == ' ')) { e.addError("Unexpected character '" + suspect.charAt(i) + "' in variable name.", suspect.rowAt(i), suspect.colAt(i)); return false; } } if (started && !finished) { count++; if (count > 32) { e.addError("Variable name larger than 32 characters.", suspect.rowAt(i), suspect.colAt(i)); return false; } if (!is_character(suspect.charAt(i))) { finished = true; } } if (started && finished) { if (!(suspect.charAt(i) == '\t' || suspect.charAt(i) == '\n' || suspect.charAt(i) == ' ')) { e.addError("Unexpected character '" + suspect.charAt(i) + "' in variable name.", suspect.rowAt(i), suspect.colAt(i)); return false; } } } return true; }

public static boolean is_character(char in) { if (!(in == 'A' || in == 'B' || in == 'C' || in == 'D' || in == 'E' || in == 'F' || in == 'G' || in == 'Ğ' || in == 'H' || in == 'I' || in == 'İ' || in == 'J' || in == 'K' || in == 'L' || in == 'M' || in == 'N' || in == 'O' || in == 'Ö' || in == 'P' || in == 'R' || in == 'S' || in == 'Ş' || in == 'T' || in == 'U' || in == 'Ü' || in == 'V' || in == 'Y' || in == 'Z' ||

in == 'a' || in == 'b' || in == 'c' || in == 'd' || in == 'e' || in == 'f' || in == 'g' || in == 'ğ' || in == 'h' || in == 'ı' || in == 'i' || in == 'j' || in == 'k' || in == 'l' || in == 'm' || in == 'n' || in == 'o' || in == 'ö' || in == 'p' || in == 'r' || in == 's' || in == 'ş' || in == 't' || in == 'u' || in == 'ü' || in == 'v' || in == 'y' || in == 'z' || in == '_')) return false; return true; }

/** * Gönderilen karakterin rakam olup olmadığını bulur. * * @param in * @return boolean */ public static boolean is_numeric(char in) { if (!(in == '1' || in == '2' || in == '3' || in == '4' || in == '5' || in == '6' || in == '7' || in == '8' || in == '9' || in == '0')) return false; return true; }

public static boolean is_integer(CString data) { try { Integer.parseInt(data.toString()); return true; } catch (NumberFormatException nfe) { return false; } } public static int safeAdd(final int x, final int y) { final int z = x + y; if (x > 0) { if (y > 0 && z < 0) e.addError("Overflow adding " + x + " + " + y + "!",-1,-1); } else if (y < 0 && z > 0) e.addError("Overflow adding " + x + " + " + y + "!",-1,-1); return z; }

public static int safeMultiple(final int x, final int y) { final int z = x * y; if (x > 0) { if (y > 0 && z < 0) e.addError("Overflow multiplying " + x + " with " + y + "!",-1,-1); } else if (y < 0 && z < 0) e.addError("Overflow multiplying " + x + " with " + y + "!",-1,-1); return z; } public static int safeSubtract(final int x, final int y) { final int z = x - y; if (x > 0) { if (y < 0 && z < 0) e.addError("Overflow subtracting " + x + " + " + y + "!",-1,-1); } else if (y > 0 && z > 0) e.addError("Overflow subtracting " + x + " + " + y + "!",-1,-1); return z; } }


*VariableManager.java* ```java
 import java.util.Hashtable;

public class VariableManager { Hashtable<String,Integer> vm = new Hashtable<String,Integer>(); public void addVariable(String name, int value) { vm.put(name, value); } public boolean isVariableExists(String name) { return vm.containsKey(name); } public int getVariableValue(String string) { return vm.get(string); } }