3. Hafta

Giriş

Bu hafta, değişkenlerin tutulması olayını çözdüm. Artık değişkenleri bir hash table da tutuyorum. Değişkenlerin genel tipinde de ilerledim. Dili Türkçe programlama dili yapmaya karar verdim. Gramer üzerine bir kaç denemem oldu. Her an karar vermem gereken tasarım sorunlarının ortaya çıkacağını fark ettim.

Değişken Tipi

Genel değişken tipi, bir union ve bir type dan oluşan bir struct. Bu versiyon 1. Daha kullanıcı tanımlı veri tiplerini , yada herhangi bir fonksiyonu içinde tutamıyor.

struct value_t{
  int type;
  union{
    char* sval;
    double dval; 
    int ival; 
  }
}
Yukarıdaki yapıdaki en güzel kısım oradaki union. Union C'de özel bir yapı. İçerisindeki en büyük veri tipi kadar yer kaplıyor. Yani yukarıdaki union 8 byte yer kaplayacak. Aynı verileri olan bir struct 20 byte(alignment hariç) yer kaplayacaktı. Ve bu unionlardan ,doğal olarak, bir seferde sadece bir veri okunabiliyor. int type objenin tipini tutacak. Tipi de şöyle tanımladım şimdilik;

enum{
  V_IDENT= 0, 
  v_INT,
  V_DOUBLE,
  V_STR,
  V_CHAR,
  V_OBJ,
  V_BOOL
};

value_t dildeki genel bütün değişkenler için ortak bir tip konumunda bulunuyor. Tanımlanan bir double , bir string yada bir integer value_t tipinin bir objesinde saklanacak. Ve oradan işlem yapılacak.

Örneğin kullanıcı 32 + 2.2 gibi bir ifade girdiğinde, en başta 32 için bir value_t sonra 2.2 için bir value_t oluşturulacak.Bu değişkenler arasındaki işlemler için ayrı ayrı fonksiyonlar yazdım. Bu işlemler; toplama, çıkarma, çarpma, ve, veya, büyüktür, küçüktür vs.

Bu işlemleri yazarken en büyük sıkıntı bu değişkenleri tipleri. Örneğin; "omer" şeklindeki bir string ile, 5 şeklindeki bir integerın toplanması. Bu gibi durumlar için yukarıdaki fonksiyonlar bir çok tip kontrolü bulundurmak zorunda kaldılar.

struct value_t*
value_t_add(struct value_t* v1, struct value_t* v2){
        struct value_t* temp = NULL;

        if(v_isint(v1) && v_isint(v2)){
                int t = (v1->ival + v2->ival);
                temp = value_t_create(V_INT, (void*)&t);
        }else if(v_isint(v1) && v_isdouble(v2)){
                double t = (v2->dval + v1->ival);
                temp = value_t_create(V_DOUBLE, (void*)&t);
        }else if(v_isdouble(v1) && v_isint(v2)){
                double t = (v1->dval + v2->ival);
                temp = value_t_create(V_DOUBLE, (void*)&t);
        }else if(v_isdouble(v1) && v_isdouble(v2)){
                double t = (v1->dval + v2->dval);
                temp = value_t_create(V_DOUBLE, (void*)&t);
        }else{
                fprintf(stderr, "'+' operatörü için yanlış tip.\n");
        }
        return temp;
}

v_isint , v_isdouble gibi macrolarla beslediğim bu fonksiyon, iki value_t arasındaki toplama işlemini gerçekleştiriyor.

Değişkenlerin Tutulması

Değişkenleri tutmak için bir hash table oluşturdum. Hash table key-value ikilileri için oluşturulmuş bir veri yapısı. Kendisi bir çok şekilde implement edilebilir. Ben bir dizi liste kullanarak implement ettim.
Bir tane hash fonksiyonu var. Bu fonksiyon genellikle bir karakter dizisi alıp bellirli aralıkta rastgele bir sayı -bir key- veriyor. Bu keyi index olarak kullanıp, elemanı oraya koyuyoruz.
Şöyle tanımlanabilir.

struct list_node{
    struct list_node* next;
    char* name;
    struct value_t* value;
};
Hash table üzerinde genelde tanımlanabilecek 3 tane yöntem var; insert , lookup , delete . Bu fonksiyonların tanımları şöyle;


void table_insert(struct list_node**, const char*, struct value_t *);

int table_delete(struct list_node**, const char*);

struct value_t* table_lookup(struct list_node**, const char *);

Türkçe karakterler

Programlama dilinin Türkçe yapmaya karar verdikten sonra, Türkçe karakterleri 'flex' ve 'bison' da nasıl kullanacağımı düşünmeye başladım. Öğrendiğim kadarıyla flex "1-byte" karakterlere bakıyor. Ve "1-byte" lık karakter setleri var. Türkçe için iso-8859-9 adlı standart, türkçe karakterleri "1-byte" içerisinde tanımlıyor.

Bu bir byte olayı çok önemli, çünkü şimdi unicode kullanayım desen, 1-bytetan fazla yer kaplayacak. Onun için C'de char kullanmak yerine wchar_t falan kullanmak gerekecek, bunların yanı sıra 'flex' ve 'bison' unicode 'u desteklemiyor.
Sonuç olarak iso-8859-9 karakter setini kullanmak, işleri bayağı bir kolaylaştırıyor.

Dil Tasarımına Yönelik Bazı Kararlar

Bir programlama dilinin bir amacı, bir de kullanılacağı yer belirtilmelidir. Yani yazılacak dilin diğerlerinden bir farkı olmalıdır.
Python is a programming language that lets you work quickly and integrate systems more effectively.
Lua is a lightweight, multi-paradigm programming language designed primarily for embedded systems and clients.
Ruby is a dynamic, open source programming language with a focus on simplicity and productivity.
Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.
Hepsinin bir olayı var. Ben de dilin adı sanı tarzı olayı hakkında biraz düşündüm. Bir kere Türkçe olacak. Öğrenmesi kolay olacak. Birinin ilk programlama dili olabilecek. Adını şu sıralar Oddo diye düşünüyorum. Böyle ilk söylenilen kelimeler gibi kolay babında. Lua-Python karışımı gibi bir şey olacak.

Lua, değişkenleri sıralı hashtable lar içerisinde saklıyor. Her scopun bir hash table'ı var. Ve o hash table lar için local yazarak bir değişken oluşturuluyor. Ben de Oddo da aynı şeyi düşünüyorum -şu an bildiğim başka bir alternatifinin olmamasının da etkisiyle-.
Bir üst alma fonksiyonu dilde şöyle yazılacak:

yordam üstü(a,b)
 yerel sonuç = 1
 iken (b > 0) yap
  sonuç = sonuç * a
  b = b - 1
 son
 dön sonuç
son

Bazı anahtar kelimeleri değişebilirim. Ama ortalama buna benzer bir grameri olacak.
Bayağı hata barından şekliyle yazdığım grameri şöyle:

gramer.y

%token ISE YEREL YAP SON BASKA YINELE EKADAR IKEN UZRE DON DEVAM BIRAK
%token TANIMLAYICI SABIT KALIPKELIME SAGKAYDIR SOLKAYDIR VE YADA YS
%token SINIF YORDAM
%token BE KE EE ED
%start program

%%


atom
                                                : TANIMLAYICI
                                                | KALIPKELIME
                                                |  SABIT
                                                | '(' ifade ')'
                                                ;

kosul_ifadesi
                                                : atom '>' ifade
                                                | atom '<' ifade
                                                | atom BE  ifade
                                                | atom KE  ifade
                                                | atom EE  ifade
                                                | atom ED  ifade
                                                ;

mantiksal_ifade
                                                : kosul_ifadesi
                                                | atom VE mantiksal_ifade
                                               | atom YADA mantiksal_ifade
                                                ;

ifade
                                                : mantiksal_ifade
                                                | atom '+' ifade
                                                | atom '-' ifade
                                                | atom '/' ifade
                                                | atom '*' ifade
                                                | '-' atom
                                                | atom
                                                ;


tanimlar
                                                : fonk_tanimi
                                                | sinif_tanimi
                                                ;


akisdegistirenler
                                                : DON
                                                | DEVAM
                                          | BIRAK
                                                ;



secme_demeci
                                                : ISE mantiksal_ifade YAP demec  SON
                                                | ISE mantiksal_ifade YAP demec BASKA demec SON
                                                ;

dongu_demeci
                                                : IKEN  mantiksal_ifade YAP demec SON
                                                | UZRE  atama_ifadesi ',' atom ',' atom  YAP demec SON
                                                | YINELE demec EKADAR '(' mantiksal_ifade ')'
                                                ;


arg_list
                                                : TANIMLAYICI
                                                | TANIMLAYICI ',' arg_list
                                                ;

ilk_arg_list
                                                : TANIMLAYICI '=' ifade
                                                | TANIMLAYICI '=' ifade ',' ilk_arg_list
                                                ;

fonk_tanimi
                                          : YORDAM TANIMLAYICI '(' arg_list ')' demec SON
                                                ;

sinif_tanimi
                                                : SINIF TANIMLAYICI SON
                                                | SINIF TANIMLAYICI '(' arg_list ')' SON
                                                | SINIF TANIMLAYICI '(' ilk_arg_list ')' SON
                                                ;


sonsal_ifade
                                                :       /* bos */
                                                | TANIMLAYICI
                                                | sonsal_ifade '[' ifade ']'
                                                | sonsal_ifade '.' TANIMLAYICI
                                                ;


liste_ifadesi
                                                : '{' atom_list '}'
                                                ;


atom_list
                                                :
                                                | atom
                                                | atom ',' atom_list
                                                ;

fonk_cagri
                                                : TANIMLAYICI '(' atom_list ')'
                                                ;

atama_ifadesi
                                                : sonsal_ifade
                                                | atama_ifadesi '=' ifade
                                                | atama_ifadesi '=' liste_ifadesi
                                                | atama_ifadesi '=' fonk_cagri
                                                ;

basit_demec
                                                : atama_ifadesi
                                                | secme_demeci
                                                | dongu_demeci
                                                ;

birlesik_demec
                                                : YAP SON
                                                | YAP birlesik_demec SON
                                                | basit_demec
                                                ;

demec
                                                : akisdegistirenler
                                                | tanimlar
                                                | basit_demec
                                                | birlesik_demec
                                                ;

komut                           :
                                                | demec ';'

                                                ;

program
                                                : komut program
                                                | komut
                                                ;


%%

Bu grameri yazarken kavramları türkçeleştirme konusunda bayağı bir sıkıntı yaşadım.

SONUÇ

Önümüzdeki günlerde biraz ALES falan çalışacağım gibi duruyor. Bu olaya ne kadar bakarım bilmiyorum. Ama son yaptıklarım, bu işi yapabileceğimi gösterdi diyebilirim.

Yorumlar

Bu blogdaki popüler yayınlar

NFA, DFA, Regex, CFG, PDA

Lex ve Yacc-2

Lex ve Yacc