|
Derleyici Tasarımı
|
librdesc'in çözümü:
librdesc GitHub repository: https://github.com/metwse/rdesc/
librdesc online documentation: https://metwse.github.io/rdesc/
O zaman librdesc'i indirerek başlayalım:
Tabii proje taslağını kullanıyorsanız librdesc otomatik indirilecek. Ancak tavsiyem yine de sisteme kurmanızdır, böylece tüm metin editörlerinin librdesc fonksiyonlarını görüp uygun önerilerde bulunabilir.
Kendi stack implementasyonunu kullanıp CST kuran bu parser'ı çalıştırmak için, kütüphanenin rule_macros.h başlığındaki makroları kullanacağız.
Önceki sayfalarda sonsuz döngüye girmemek için gramerimizi mecburen right-recursive olarak tasarlamıştık. Şimdi bu right-recursive yapıyı _REST isimli yardımcı nonterminal'lerle ifade edelim. Anlaşılırlığı artırmak için gramerimizi sadece çıkarma (-), çarpma (*) ve sayılardan (INT) oluşacak şekilde sadeleştirelim:
Önceki gramer yapımızı librdesc ile kullanmanın önünde bir engel yoktu, ancak librdesc'in bazı özelliklerini kullanabilmek için şimdiden bu değişikliği yaptık. Bir sonraki bölümde bu tercihi yapma nedenimizi detaylandıracağız.
Gramer için gerekli declaration'ları header'da yapalım:
Grameri, formal gösterimine neredeyse birebir benzeyen bir tabloya dönüştürmek için, librdesc'in sağladığı makroları kullanacağız. Spagetti gibi birbirini çağıran fonksiyonlar yok!
r(...): Production rule'ı başlatır.alt: Production rule alternatiflerini (|) ayırır.EPSILON: Production rule'ın boş (ε) geçilebileceğini belirtir.Sonrasında, bu tabloyu kullanarak struct rdesc oluşturuyoruz:
Bu kadar! Tokenizer ile (token_id, seminfo) ikilisini üretiyorduk, şimdilik hard-coded birkaç tokeni rdesc'e gönderip test edelim:
rdesc_pump(), pompalama sonrasında kuralın tamamlanıp tamamlanmamasına göre RDESC_CONTINUE ve RDESC_READY döner. rdesc, kuralı match ettikten sonra ekrana yazdıralım:
Bu CST'yi, left-associative çıkarma işlemine sahip olacak şekilde döndürmek için rdesc_flip_left() çağırmamız yeterli:
rdesc_flip_left() sonrası elimizde Left-Associative, matematiksel olarak doğru bir CST var. Sıradaki adım bu ağacı traverse etmek ve değerleri hesaplamak. Artık parsing ile evaluation'ı birbirinden tam olarak ayırmış olacağız.
Ayrıca, rdesc_dump_cst() fonksiyonuna verdiğimiz node_printer()'ın tanımını tek bir node'ı traverse etme örneği olarak verebiliriz, bir sonraki aşama olan Tree-Walk Interpreter'da bu tarz şeyler yapacağız:
Biraz librdesc'in derinliklerine inelim: librdesc Detayları.