Proje İçeriğinin anlatımı
Projemiz Lexer, Parse ve interpreter olarak 3 kısımdan meydana gelmektedir. Lexer ve parse işlemini EvalExp.jj isimli dosyamızın içerinde yaptıracağız. Bu dosya bir JavaCC emirlerinin bulunduğu dosyamızdır. Parse ağacının oluşturulması için AST.java uzantılı içerisinde class larımızın olduğu java dosyamız mevcuttur. Daha sonra interpreter işleminin gerçekleştirilmesi için EvalVisitor.java uzantılı dosyamız bulunmaktadır. Şimdi Lexical analiz işlemini yapan jj uzantılı dosyamız içeriginde biraz bilgi verelim.
Bu dosyamız içerisinde Programmımızın main işlemini yerine getiren kod blogumuz vardır.Bu kısım PARSER_BEGIN(EvalExp) ile başlar ve PARSER_END(EvalExp) ile biter. EvalExp olarak tanımladığımız isim ise bizim JavaCC tarafından oluşturulacak olan, main dosyasının yer aldığı bir başlama java uzantılı dosya oluştururur.
Yukarıdaki kod parçası Expr isimli text dosyasından Parser için giriş denklemini alır.
Text dosyamız içerisine “sin” şeklinde bir ifade girdiğimizde bunun tanınması lazım. Dolayısıyla biz token olarak sin ifadesini yazmamız gerekmektedir. Aynı şekilde “+,*,\,cos” vb. gibi tokenlarımızı da TOKEN: diye başlayarak yazmamız gerekmektedir. Örnek aşağıdaki gibidir.
Şimdi tokenlarımızı da tanıdıktan sonra işlem parse işlemine gelmiştir. Bunun için bizim bir CFG yazmamız gerekmektedir ve bunun doğrultusunda javaCC notasyonunda bu gramerimizi yazmamız gerekmektedir. Gramer yapımızı yukarıda vermiştik. Şimdi JavaCC notasyonunda nasıl yazılacağından bahsedeyim.
Parse işlemimize başladığımızda bizim her zaman için bir başlangıç kısmımız bulunmaktadır. Bende Parse metodu ile buna başladım bu kod aşağıdaki gibidir.
Yukarıdaki koddan da anlaşılacağı gibi içerisinde başka bir method çağırılmaktadır. expr() metodu çağırılmaktadır. Bu şekilde bir toplama işlemi yaptığında bile parse() ile başlamalı ve bir ağaç yapısı şeklinde aşağıya doğru dallanmalıdır. Örneğin toplama ve çıkarma bir kısımda yapılabilir. Çarpma ve bölme bunun alt seviyesinde yer almalıdır. Gramerimizden de anlaşılacağı gibi bu işlem bu şekilde devam eder. Aşağıda sin içinde bir örnek gösterilmiştir. Sin ağaç yapımızda en altta yer almaktadır.
Yukarıdaki örnekte gördüğümüz gibi parse işlemimizin tamamlanması için classlarımızın oluşturulması lazım. Bu classlar içerine bizim değerlerimiz yazılır. Mesala bir sin(30) işlemi yaptığımızda 30 değeri bizim classımız içerine yazılır ve değerimiz bu classlarımız içerisinde yer alır. Aşağıda örnek olarak sin classımız gösterilmiştir.
Right isimli değişkenimiz değerimize setlenir. Ancak burada da gördüğümüz gibi right değişkenimiz bir double sayı değil Exp dir. Bunun anlamı right değişkenimiz sadece bir sayi değilde bir işlemde olabilir. Yani sin(e^4+2*3) şeklinde bir ifadede olabilir. İşte bunun için exp olarak tanımlanmıştır. Sin de parantez içi ayrı bir şekilde hesaplanır ve bize bir sayi döner. Bu işlemi sağlayan ise accept metodudur. Accept metodu ile visit metoduna paremetre aktarılır ve aşırı yüklenmiş visit metodunda “this” ifadesine karşılık gelen kısım alınarak bir ağaç mantığı ile işlemimiz yapılır.
Visit metodundan bahsetmişken son işlemimiz olan yani interpreter olan bu kısıma da girelim. Visit metodları aşırı yüklenmiştir ve EvalVisitor isimli classımızın içindedir. Visitor işlemiminin ilk çağırıldığı kısım EvalExp.jj dosyamızın başlangıç kısmıdır anlattığım main kısmında çağırıyoruz. Parse işlemimiz bittikten sonra yorumlayıcımız çağırılır. ev.visit şeklinde aşağıdaki gibi çağırılır.
Parse işleminden artık ifadelerimizin her biri yorumlanarak sonuç elde edilir. Örneğin “sin” için aşağıdaki visit metodu görülmektedir. Sin içerisinde ki değer b değişkenine atılır ve hesaplama işlemi yapılır. Burada gördügünüz gibi accept metodundan dönen sonuç alınır.
Yukarıda da anlattığım gibi sin içerinde toplama gibi bir çok işlemimizde olabilir. Bunun için accept ile bütün işlemler yapılır ve sonuç dönderilir.Java kütüphanesinin math.sin hazır fonksiyonu kullanılır. Ancak bu radyan cinsinden hesaplama yaptığı için bizim bunu dereceye çevirmemiz lazım. Dolayısıyla b*Math.PI\180 işlemi ile radyan değerimiz dereceye çevrilmiş olur.
Visit metodunun da icrasından sonra artık bizim son sonucumuzu ekrana bastırarak projemizi bitirebiliriz.
Projemizde ek olarak denklem içerisinde bilinmeyen bir değer de bulunabilir. Mesela sin(x) gibi bir ifade bulunabilir. Burada biz x değerini bir dosyadan okuruz.
Dosyadan oluduktan sonra lexical,parser ve interpreter kısımlarımızın her birine sin için anlatılanlar gibi ekleriz. X değerimiz denklem fonksiyonunda yerine yazılır ve işlemlerimiz bu şekilde tamamlanır.