Parser - Statement
Evet, son bıraktığımızda, Parser'ımız expression'ları parse edebiliyordu. Ancak, henüz tek bir expression parse edebiliyoruz. Bu yazıda, statement'ları nasıl parse edeceğimize değineceğiz.
Önce statement (beyan) nedir, ona biraz değinelim. Statement, expression'dan bir üst kategori diyebiliriz. Her expression, aynı
zamanda bir statement olabilir. Ancak, her statement bir expression olamaz. Mesela, programlama dillerindeki if
sözcüğü bir statement
tanımlar, ama if
statement'ı bir expression diyemeyiz.
Statement'ları parse edebilmek için, statement başlatan sembollerimize özel bir std
metodu tanımlayacağız. Örneğin, if statement
yapmak için gerekli olan sembolü, sembol tablosuna ekleyelim:
Tahmin edeceğiniz gibi, bunlar _prepareSymTable
metodunun içine gidiyor.
ifStatement
, önce, bir expression alıp bunu ilk ögesi olarak ayarlıyor. Daha sonra, bir ":" ve bir "NEWLINE" sembolü ilerledikten
sonra, ikinci elemanını bulmak için Parser metodunun Block
metodunu çağırıyor.
|
def Block(self):
|
|
self._advance(["INDENT"])
|
|
stmts = self.Statements()
|
|
self._advance(["DEDENT"])
|
|
return stmts
|
Bu, Parser
sınıfının bir metodu olacak. Önce bir indent ilerliyor, sonra bir statement listesi alıyor, sonra bir dedent daha
ilerleyip, statement listesini döndürüyor. Ben, Python gibi, indentation tabanlı block'lar yapmak istedim. Siz isterseniz block'larınızı
"{" ile başlatıp, "}" ile bitirebilirsiniz.
|
def Statements(self):
|
|
statements = []
|
|
while True:
|
|
if self.token.id in ["END","DEDENT"]:
|
|
break
|
|
s = self.Statement()
|
|
if s:
|
|
statements.append(s)
|
|
return statements
|
Çok açıklayacak birşey yok, END veya DEDENT görene kadar, bir statement parse edip, bunları listeye koyup gönderiyoruz.
|
def Statement(self):
|
|
t = self.token
|
|
if t.beginStatement:
|
|
self._advance()
|
|
return t.std()
|
|
ex = self.Expression(0)
|
|
self._advance(["NEWLINE","END","DEDENT"])
|
|
return ex
|
Eğer, geçerli token bir statement başlangıcıysa, onun std metodunun sonucunu döndürüyoruz, eğer değilse, bir expression parse edip, sonra bir "NEWLINE", "END" veya "DEDENT" ilerleyip, sonucu döndürüyoruz. Eğer expression parse edildiğinde geçerli token bunlardan bir tanesi değilse, bu okuduğumuz girdi, bizim yazım kurallarımıza uygun değil demek. Bir diğer deyişle, SyntaxError.
Şimdi, şunu parse etmeyi deneyelim:
if yasar: a = a + 12 else: a = 12 b = 25
Test etmek için kullandığımız kodlar:
Ve sonuç:
parse result: [(if (NAME yasar) [(= (NAME a) (+ (NAME a) (NUMBER 12)))] [(= (NAME a) (NUMBER 12)), (= (NAME b) (NUMBER 25))])]
Bundan sonra?
Bundan sonrası size kalmış. Yeni dil kuralları ekleyin, yeni operatörler tanımlayın, artık canınız ne çekerse.
Peki ya ondan sonra?
Son olarak, elde ettiğiniz parse tree'i kullanılabilecek bir veri türüne çevirebilir veya bir yorumlayıcı yazarak çalıştırabilirsiniz.
İsterseniz makine koduna derleyin, ister başka bir programlama diline derleyin, isterseniz JSON yapın, ister html'e dönüştürün, isterseniz grafiğini çizin, böyle oklar falan olsun, artık keyfinize göre takılın.
Ben bunları aslında kafamda bir proje var, onun için yazdım. Eğer vakit bulup o aşamaya gelirsem, onu da blog'dan yazarım.