Bir önceki yazıda dilimizi a = 1 , print() gibi ifadeleri ayrıştırabilecek şekile getirmiştik. Şimdi matematiksel ifadeleri işlem önceliğini dikkate alarak ayrıştıracağız. Aşağıda 2 + 5 * 4 şeklindeki bir ifadenin olası 2 farklı sonucunu göreceksiniz.
Bu ifadede önce 2 ve 5 i toplaması yanlış sonuçlar doğuracaktır. Çünkü çarpma işleminin toplamaya göre önceliği vardır. Bu yüzden işlem yukarıdaki 2.şekildeki gibi yapılmalıdır. Yani önce 5 ve 4 çarpılıp 2 ile toplanacak.
Bunu önlemek için ise biz bu dilde shunting-yard algoritmasını kullanacağız. Algoritma ile ilgili daha detaylı bilgiyi wikipedia sayfasından bulabilirsiniz.
Shunting-yard algoritması infix gösterimdeki bir ifadeyi postfix gösterime dönüştürmemizi sağlar. Örnek gösterirsek;
infix notasyon : 1 + 2 * 4
postfix notasyon : 1 2 4 * +
Burada postfix notasyonda işlecin sayılardan sonra geldiğini görüyorsunuz. Her işleç kendisinden bir önceki ve iki önceki operand yani sayı ile işleme giriyor ve sonucu bu sayı ve operandların yerine yazılıyor ve sonuç bulunuyor. Örnek verirsek;
- adım 1 2 4 * +
- adım 1 8 +
- adım 9
Algoritmanın en basit hali şu şekilde işliyor;
- Token oku
- Token sayı ise çıktı ver.
- Token operatör ise
- Eğer operatör stack içerisinde operatör var ise ve bu operatör okunan operatörden daha az işlem önceliğine sahip ise operatör stacktaki operatörü oradan alıp çıktı ver.
- Operatörü stacke ekle.
- Eğer okunacak operatör yok ise stackteki bütün operatörleri son eklenenden başlayarak çıktı ver.
Burada karmaşa olmasın daha basit bir anlatım olsun diye parantezleri dahil etmedim. İlerleyen zamanlarda bunları da dile dahil edeceğiz.
Şimdi kodumuzu yazalım. Öncelikle stack içerisinde tutacağımız operatör bilgilerini içeren yapımızı oluşturalım.
Daha sonra aşağıda işaretli olan satırları Parser’ımıza ekliyoruz. Burada işlem önceliğimizi tutacağımız tabloyu oluşturuyoruz.
Çarpma ve bölmenin daha yüksek işlem önceliği olduğu için onlara daha büyük rakamlar verdik. Ve şimdi matematiksel ifadeleri yakalayacak olan fonksiyonumuzu tanımlıyoruz. Ben fonksiyona calcIt adını verdim.
IL yapısı kullanacağımız için sadece operatör stack tanımladım. Wikipedia sayfasında veya başka kaynaklarda algoritma için birde output stack görebilirsiniz. Şimdi geriye sadece sistemizdeki birkaç getIt fonksiyonunu calcIt ile değiştirmek kaldı. Bir önceki yazımdaki eksik kodu tamamlamak adına Parse fonksiyonu içerisinde aşağıdaki işaretli satırları ve
Ayrıca getIt fonksiyonu içerisindeki kodları da aşağıdaki şekilde değiştirmeliyiz. Aksi halde bir önceki yazımdaki hatamdan dolayı getFunction’dan düzgün bir şekilde IL çıktısı verilmeyecektir.
ve getFunction içerisinde aşağıdaki satırı calcIt olarak değiştirmek yetecektir.
Ben test için
a = 1 * 2 + 2 * 3 * 4 * 5 + 6;
kodunu yazdım ve aşağıdaki çıktıyı verdi.
Program has started
load 1
push
load 2
times
push
load 2
push
load 3
push
load 4
push
load 5
times
times
times
push
load 6
plus
plus
define 'a'
Artık matematiksel ifadelerimizi de rahatlıkla ayrıştırabiliyoruz tek yapmamız gereken writeln şeklinde çıktı vermek yerine IL çıktısı vermek olacaktır. Bir sonraki yazıda IL çıktısı verebilmek için nesnelerimizi oluşturacağız ve sonrasına ise IL sınıfımızı yazacağız.
Projeyi indirmek için: Make Your Own Language – 3