[Ileri Seviye Python] Haydi bir Interpreter Yazalim [BOLUM 1] (Ar-Ge) //Easyly

BufGix

Uzman üye
7 Ağu 2015
1,089
2
Phobos/Space
Hiç düşündünüz mü, Python 3 + 2 yazdiğımızda 5 olarak sonucu nasıl bize gösteriyor.

Yada yazdığımız kodlar nasil bir sıra halinde yürütülüyor.
Veya "8 + "yazdığımızda python nasıl bize Invalid syntax hatası veriyor.


Bazı arkadaşların, "Amaaan nasıl yapıyorsa yapıyor işte" dediğini duyar gibiyim. Bu arkadaşlar geri tuşuna basıp konudan ayrılabilirler. Nasıl yaptığını merak edenler ise okumaya devam etsinler.


"Derleyicilerin nasıl çalıştığını bilmiyorsanız, bilgisayarların nasıl çalıştığını bilmiyorsunuz.Derleyicilerin nasıl çalıştığını bildiğinizden % 100 emin değilseniz, nasıl çalıştığını bilmiyorsunuzdur. ”*- Steve Yegge


Interpreter(Yorumlayıcı) veya Compiler(Derleyici)'in amacı, bir kaynak programı bazı üst düzey dilde başka bir formata çevirmektir. Interpreter ile Compiler arasındakı fark ise ; Compilerler kaynak kodu makine diline çevirirken, Interpreter ise makine diline çevirmeden işlemleri yürütür.



Neden bir Interpreter(veya Compiler) yazayım ki? Cünkü:
* Bir interpreter(veya compiler) yazmak,birlikte kullanmaniz gereken cok fazla teknik bilgiye ve beceriye sahip olmaniz gerekir. Bir interpreter(veya compiler) yazmak, bu becerilerinizi gerliştireceği icin daha iyi bir yazılımcı olmanizi sağlar.
* Her seyin kontrolünü eline almak, bilgisayari anlamak için
* Kendi eşsiz programlama dilinizi oluşturmak için

interpreter(veya compilerin) yazmayı deneyebilirsiniz.


"Aman tanrım! Başlıkta Iler Seviye yazıyor. Kesin anlayamam" derseniz hata edersiniz. Aşağida yazilan bütün kodları Pyhton Nesne Tabanlı Programlamaya kadar geldim diyen herkez anlayabılır.


---- Hadi Başlayalım ----

Dilerseniz hesap makinesi olarak bilinen, aritmatik ifadelerin bir interpreter'ini yazarak başlayalim. Hedefimiz oldukça minimalist "4+8" gibi iki tane tek haneli tam sayının birbirine eklenmesini sağlamak.

Kod:
[FONT="Courier New"][COLOR="WHITE"]
INTEGER, PLUS, EOF = 'INTEGER', 'PLUS', 'EOF'

#EOF: End Of File
#verilen ifadenin sonuna gelip gelmedigimizi kontrol edecegiz


[COLOR="CYAN"]class[/COLOR] Token(object):
    """
    Her gecerli parcacik icin olusacak Token [COLOR="CYAN"]class[/COLOR]i
    """
    [COLOR="CYAN"]def[/COLOR] __init__([COLOR="CYAN"]self[/COLOR], type, value):
        ## Tur: INTEGER, PLUS veya EOF
        [COLOR="CYAN"]self[/COLOR].type = type
        
        #Token degeri: 1,2,3,4,5,6... '+' gibi
        [COLOR="CYAN"]self[/COLOR].value = value
        
    [COLOR="CYAN"]def[/COLOR] __str__([COLOR="CYAN"]self[/COLOR]):
        [COLOR="CYAN"]return [/COLOR]'Token(type = {}, value = {})'.[COLOR="CYAN"]for[/COLOR]mat([COLOR="CYAN"]self[/COLOR].type, [COLOR="CYAN"]self[/COLOR].value)
    
    [COLOR="CYAN"]def[/COLOR] __str__([COLOR="CYAN"]self[/COLOR]):
        [COLOR="CYAN"]return [/COLOR][COLOR="CYAN"]self[/COLOR].__str__()
[/COLOR][/FONT]


Simdi bir Inperpreter classi yazalim.
Kod:
[FONT="Courier New"][COLOR="WHITE"]
Kod:
       
[COLOR="CYAN"]class[/COLOR] Interpreter(object):
    [COLOR="CYAN"]def[/COLOR] __init__([COLOR="CYAN"]self[/COLOR], text):
        [COLOR="CYAN"]self[/COLOR].text = text    #Gelen string
        [COLOR="CYAN"]self[/COLOR].pos = 0        #Bir nevi imlec, karakterlein yerlerini belirlemek icin
        [COLOR="CYAN"]self[/COLOR].current_token =[COLOR="ORANGE"] None [/COLOR] #token ornegi
        
    [COLOR="CYAN"]def[/COLOR] error([COLOR="CYAN"]self[/COLOR]):
        raise Exception('Error parsing input')  #Eger hatali kullanim olursa
        
    [COLOR="CYAN"]def[/COLOR] getNextToken([COLOR="CYAN"]self[/COLOR]):
        """
        Lexer: bu kod verilen degerin ([COLOR="CYAN"]self[/COLOR].text)[COLOR="CYAN"] in [/COLOR]parcalanmasindan sorumludur.
        Tokenlerine ayirir.
        """
        text = [COLOR="CYAN"]self[/COLOR].text
        
        
        #text[COLOR="CYAN"] in [/COLOR]sonuna geldiginde
        # Token End of File i dondur
        [COLOR="CYAN"]if [/COLOR][COLOR="CYAN"]self[/COLOR].pos > len(text) - 1:
            [COLOR="CYAN"]return [/COLOR]Token(EOF, None)
         
         
        #Su an hangi karakterle islem yapiyoruz [COLOR="CYAN"]self[/COLOR].pos a gore bul   
        current_char = text[[COLOR="CYAN"]self[/COLOR].pos]
        
        
        #Eger suanki karalter bir sayi ise
        #Integer tipli bir token olustur
        #[COLOR="CYAN"]self[/COLOR].pos degerini 1 arttir ki diger karaktere gecebilsin
        #sonra token nesnesini dondur
        [COLOR="CYAN"]if [/COLOR]current_char.isdigit():
            token = Token(INTEGER, int(current_char))
            [COLOR="CYAN"]self[/COLOR].pos += 1
            [COLOR="CYAN"]return [/COLOR]token
        
        [COLOR="CYAN"]if [/COLOR]current_char == '+':
            token = Token(PLUS, '+')
            [COLOR="CYAN"]self[/COLOR].pos += 1
            [COLOR="CYAN"]return [/COLOR]token
        
        #hicbir kosula girmez ise
        [COLOR="CYAN"]self[/COLOR].error()
        
    [COLOR="CYAN"]def[/COLOR] eat([COLOR="CYAN"]self[/COLOR], token_type):
    """
    Gecerli bir tip degeri (Integer, plus)ile gelen tip degerini karsilastir eger eslesirse tokeni 'ye' :) ve yeni tokeni esitle.
    eger eslesmez ise hata mesaji goster.
    """    
        [COLOR="CYAN"]if [/COLOR][COLOR="CYAN"]self[/COLOR].current_token.type == token_type:
            [COLOR="CYAN"]self[/COLOR].current_token = [COLOR="CYAN"]self[/COLOR].getNextToken()
        else:
            [COLOR="CYAN"]self[/COLOR].error()
        
    [COLOR="CYAN"]def[/COLOR] expr([COLOR="CYAN"]self[/COLOR]):
        #EXPR INTEGER -- PLUS -- INTEGER
        
        #Ilk tokenimizi alalim
        [COLOR="CYAN"]self[/COLOR].current_token = [COLOR="CYAN"]self[/COLOR].getNextToken()
        
        
        #Gecerli tokenin tek haneli bir tamsayi olmasini bekliyoruz
        left = [COLOR="CYAN"]self[/COLOR].current_token
        [COLOR="CYAN"]self[/COLOR].eat(INTEGER)
        
        #Tokenin + isareti olmasini bekliyoruz
        op = [COLOR="CYAN"]self[/COLOR].current_token
        [COLOR="CYAN"]self[/COLOR].eat(PLUS)
        
        #Tokenin tamsayi olmasini bekliyoruz
        right = [COLOR="CYAN"]self[/COLOR].current_token
        [COLOR="CYAN"]self[/COLOR].eat(INTEGER)
        
        
        #Son olarak iki tokenin value degerlerini topluyoruz.
        [COLOR="CYAN"]return [/COLOR]left.value + right.value
        
[COLOR="CYAN"]def[/COLOR] main():
    [COLOR="CYAN"]while[/COLOR] [COLOR="GREEN"]True[/COLOR]:
        text = raw_input('Interpreter> ')
        
        [COLOR="CYAN"]if [/COLOR]not text:
            continue
        interpreter = Interpreter(text)
        result = interpreter.expr()
        [COLOR="CYAN"]print[/COLOR] result

main()

[/COLOR][/FONT]


Aslinda kodda herşeyi acikladim. Ama kısaca özetlemek gerekirse.

* Bir Token classi olusturduk bu class tip ve degerleri tutyor

* Interpreter in icindeki eat methodu bir nevi kontrol islemi yaptik eger gelen karakter istedigimiz tipte degilse hata mesajiyla uyariyor.

* expr ile solaki sayiyi, oparetoru ve sagdaki sayıyı buluyoruz ve topluyoruz.


* getNextToken() bir Lexerdır yani amacı gelen text deki bizim icin uygun parcalari ayirmaktir. Bu isleme "Sözcüksel Analiz" denir.

Yazdigimiz Lexer soyle çalisiyor.










Ayrica yazdığımız mukemmel Interpretrimizin doğru çalışması için bazı kurallara uyulması gerekir:
* Sadece tek haneli sayilarin yazilmasi gerekir.
* Sadece tek aritmatik islem yapabiliyor :(
* Ve aralarda boşluk olmayacak.

Diğer yazımda bunlarin cözümlerini yapacağız.

Kod:
[FONT="Courier New"]Interpreter> 3+4 
Token(type=INTEGER, value = 3)
Token(type=PLUS, value = '+')
Token(type=INTEGER, value = 4)
7 
Interpreter> 3+5 
Token(type=INTEGER, value = 3)
Token(type=PLUS,value = '+')
Token(type=INTEGER, value = 5)
8 
Interpreter> 3+9 
Token(type=INTEGER, value = 3)
Token(type=PLUS, value = '+')
Token(type=INTEGER, value = 9)
12 
Interpreter>[/FONT]



Eveeet. Bugünlük benden bu kadar. Sinavlarimdan vakit buldukça bu seriye devam edeceğim.


Kaynak:
https://ruslanspivak.com/
(Mukemmel bir blog. Okumanizi tavsiye ederim.)

 
Son düzenleme:

ihan3t

Kadim Üye
7 Şub 2012
5,018
24
Eline sağlık, bu tarz konuların artması dileğiyle.

Gelecek konularda BNF (backus naur form) gibi konularada değinip bir dilin nasıl oluşturulacağı ile ilgili bilgilerde vermen, derleyiciyi/interpreterı neye göre oluşturacağı hakkında fikir verir insanlara.
 

BufGix

Uzman üye
7 Ağu 2015
1,089
2
Phobos/Space
Eline sağlık, bu tarz konuların artması dileğiyle.

Gelecek konularda BNF (backus naur form) gibi konularada değinip bir dilin nasıl oluşturulacağı ile ilgili bilgilerde vermen, derleyiciyi/interpreterı neye göre oluşturacağı hakkında fikir verir insanlara.

Onerilerinizi dikkate alacagım. Tesekkurler :)
 
Son düzenleme:
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.