Parser - Yardımcı Fonksiyonlar
Python ile parser yapımı yazısı, kullanacağımız algoritmayı tanıtmak üzerineydi. Bu yazıda ise, Parser yapmakta kullanacağımız yardımcı fonksiyon ve sınıflara değineceğiz.
Parser Sınıfı
|
class Parser(object):
|
|
def __init__(self, queue):
|
|
self._q = queue
|
|
self._sym = {}
|
|
self._prepareSymTable()
|
|
self.token = self._nextToken()
|
Parser sınıfı, bir Queue objesi alıyor. Token'lerimizi bu Queue üzerinden okuyacağız. Bu Queue'e, daha önceki yazılarda yazmış olduğumuz Lexer sınıfı tokenleri koyacak.
Parser sınıfının _sym
adında bir sembol tablosu var. _prepareSymTable
Parser'ın tanıdığı sembolleri bu tabloya ekleyecek.
Bu metodu daha sonra inceleyeceğiz.
_nextToken
ise, daha sonraki token'i almak için kullanılıyor. Ancak, bir sonraki token'e ilerlemek için, bu metot
yerine, aşağıdaki _advance
metodunu kullanacağız.
_nextToken
, Queue'den bir token alıyor. Parser'ın bulunduğu satırı, Lexer'dan gelen bilgiye göre güncelliyor. Daha sonra,
sembol tablosundan o token'e karşılık gelen sınıfı bulup, yeni bir örneğini oluşturuyor. Eğer, o anki token bir literal ise,
literal'in değerini ayarlayıp, sembolü gönderiyor.
_advance
ise, opsiyonel olarak bir idlist
argümanı alıyor. Eğer bu argüman verildiyse, ve şu anki token idlist içerisinde
değilse, ParseError veriyor. Bunun kullanımını daha sonra göreceğiz. Bunun dışında, eğer token sırası bitmişse, hiçbirşey yapmıyor.
Sıra geldi, sembol tablomuzun oluşturulmasına. Sembol tablomuza koyacağımız her sembol için, tek tek yeni sınıf oluşturmak yerine, temel sembol sınıfı oluşturacağız. Diğer semboller bunun uzantısı olacak.
id
, "NUMBER", "FLOAT" gibi, o tokenin tipini gösteren bir string. value
literaller tarafından kullanılacak, o tokenin değerini
gösteriyor. first
, second
, third
değikenleri, birkaç kısımdan oluşan sembollerin kısımlarını göstermek için kullanılacak. Örneğin,
"+" sembolünün sol ve sağ tarafları, first
ve second
değişkenlerine atanacak. parent
, bu sembolün ait olduğu Parser objesini gösteriyor.
beginStatement
ise, bu sembolün bir statement başlatıp başlatmadığını gösteriyor. Henüz bir statement parse etmeye başlamadık, ama
başladığımız zaman kullanacağız bu değişkeni.
Şimdi de, factory rolünü üstlenecek metoda bir bakalım:
Bu metodun yaptığı az çok belli, çok üstünde durmayacağım. Özetle, eğer sembol önceden oluşturulmuşsa, sembol tablosundan döndürüyor, aksi halde yeni bir sembol oluşturup, tabloya ekleyip onu döndürüyor.
Artık, _prepareSymTable
ne yapıyor bakabiliriz. Bu metodun işi, Parser'ın tanıdığı tüm sembolleri, sembol tablosuna
eklemek. Önce, 4 işlem sembollerini ekleyelim:
Şaka, şaka... Böyle ekliycez:
Evet, literallerimizi de ekleyelim:
|
def literal(id):
|
|
self._symbol(id).nud = lambda self: self
|
|
|
|
for l in ["NUMBER","FLOAT","NAME","STRING"]:
|
|
literal(l)
|
Evet, böylece, şimdiye kadar kullandığımız sembolleri sembol tablosuna eklemiş olduk. Daha statement'lara girmediğimiz için, henüz onların sembollerini tabloya eklemedim. Onu da bir sonraki yazıda yapacağız.