🚀 Programlama Dili Geliştirme & Yazılım Dili Teorisi
Programlama dilleri, insanlar tarafından yazılabilen ve bilgisayarlar tarafından yorumlanabilen biçimsel dillerdir. İnsan dillerindeki gibi programlama dillerinde de sözdizim ve anlambilim vardır. Sözdizim, programlama dilinin yazım kurallarını; anlambilim ise sözdizime göre şekillenen cümleyi anlama sürecini kapsar. Programlama dilleri, genellikle Context-Free Grammar (Bağlamdan Bağımsız Dilbilgisi) dilbilgisi türüne göre geliştirilirler. Bunun en önemli sebebi CFG’nin programlama için en yeterli dilbilgisi türü olmasıdır. Çoğu programlama dili if, while, for, function gibi iç içe bloklar içerir. CFG bu sisteme en uygun çözümleri sunan grammar türüdür. Programlama dili paradigmaları vardır. Bunlar Nesne Yönelimli, Fonksiyonel, Prosedürel vb.dir. Bir dil, bu paradigmaların bir veya birkaçını destekleyecek şekilde tasarlanabilir.
Kodun Yürütülmesi
Bir programlama dilinin yürütme mekanizması, o dili işlevsel hale getiren ana yapıdır. Interpreter ve Compiler, programlama dillerinin yürütme mekanizmasının geliştirilmesindeki ana iki yaklaşımıdır. Bunlarla birlikte JIT (Just-In-Time), AOT (Ahead-Of-Time) + JIT gibi hibrit çözümlemeler de bulunmaktadır. Modern dillerde yaklaşım genellikle performans, taşınabilirlik, esneklik dengesi gözetilerek seçilir.
Interpreter (Yorumlayıcı Tabanlı)
Kod satır satır okunur ve çalıştırılır. Derlenmiş bir dosya oluşturmaz, doğrudan kaynak koduyla birlikte çalışır.
Genellikle AST’yi anlık olarak yorumlar ve çalıştırılması için yorumlayıcının platformda kurulu olması gerekir.
AST her çalışma anında tekrardan yorumlandığı için minik performans sorunları ortaya çıkartabilir. Hızlı geliştirme döngüsüne sahiptir.
Hatalar çalışma zamanında ortaya çıkar. Interpreter dillere örnek olarak Python (CPython), Ruby ve PHP’nin bazı modelleri verilebilir.
Kodun yürütülme algoritması genelde:
Lexer -> Parser -> Yürütme
şeklinde işler.
Compiler (Derleyici Tabanlı)
Kod, önceden makine koduna veya başka bir hedef dile — bazense önce hedef dile, sonra makine koduna — derlenir. Platformlara özgü çıktılar verebilir. Bu da ortaya çıkan dosyanın daha sonra işletim sistemi tarafından çalıştırılabilir olmasını sağlar. AST’yi çalıştırma zamanından önce yorumladığı için yazılan kod yürütüldükten sonra compiler’a ihtiyaç duyulmaz.
Hatalar derlenme aşamasında ortaya çıkar. Compiler dillere örnek olarak C, C++, Rust, Go, Pascal verilebilir.
Kodun yürütülme algoritması genelde:
Lexer -> Parser -> Generating code
şeklinde işler.
Yürütme Mimarisi: Ana Katmanlar
Yürütme mekanizmaları genelde şu üç temel katmandan oluşur:
- Sözdizim Analizi (Lexer)
- Grammar Analizi, Anlambilim & AST Oluşturma (Parser)
- Yürütme / Code Generation
Ek olarak, bazı yürütme algoritmalarında farklı katmanlar da bulunabilir.
Lexical Layer (Lexer Katmanı)
Lexer katmanında, yazılan kodun içeriği satır satır; dilin syntax (sözdizim) kurallarına göre mantıksal ayrımlarda bulunulup, kodun içeriği token’lara bölünür.
Örnek:
char Ad[] = “Zeynep”
→ [“char”, “Ad[]”, “Zeynep”] olarak bölünür.
Parser Layer (Ayrıştırıcı Katmanı)
Parser katmanı, lexer’dan gelen token’ları ve işlevlerini tanıyarak AST (Soyut Sözdizimi Ağacı) oluşturma işini yapar.
Genellikle lexer’dan gelen ilk token, o kodun AST’deki türünü belirler.
Örnek token listesi:
[“char”, “Ad[]”, “Zeynep”]
AST
├── Tür: Değişken
├── Tip: Yazı
├── Ad: Ad
└── İçerik: “Zeynep”
Type Systems (Tür/Tip Sistemleri)
Statik – Dinamik Tip Kontrolü (Type Checking)
Statik: Önceden tipi belirlenerek, farklı tiplerde derlenme/yorumlanma aşamasında hata çıkartan türdür. Optimizasyonu dinamiğe kıyasla daha iyidir. Örnek diller: C, C++, Java, Rust, Go
int x = “merhaba”; // Derleyici hata verir
Dinamik: Tipi belirlenmeden, esnek yapıya sahip tip kontrol türüdür. Örnek diller: Python, JavaScript, Ruby
x = “merhaba”
x = 42 # Sorun yok; tipi değişebilir
Type Inference (Tip Çıkarımı)
Derlenme/yorumlanma aşamasında açıkça belirtilmeyen tiplerin çıkarımını otomatik yapan yapıdır. Hem statik tipli hem de daha kısa kod yazmayı mümkün kılar.
let x = 5;
x = “abc”; // HATA! Çünkü x bir kez int oldu, değişemez.
Strong – Weak Typing (Güçlü-Zayıf Tipleme)
Strong Typing: Farklı türler arasında otomatik veya sessiz dönüşüm olmaz. Tip hataları ciddidir. Örnek: Python, Java, Rust
“3” + 3 # HATA: string ile integer toplanamaz
Weak Typing: Farklı türler arasında otomatik dönüşüm olabilir. Bu dönüşümler bazen beklenmeyen sonuçlara yol açabilir. Örnek: JavaScript, PHP
“3” + 3 // “33” olur (otomatik string’e çevirir)
Dil Geliştirilirken Dikkat Edilmesi Gerekenler
Dil Evrimi ve Versiyonlama
Programlama dili yayınlandıktan sonra da güncellemeler verilecekse, özellikle dilin standartları geliştirilmesi bitmeden yayınlanması, sonraki sürümlerde ana kodların yorumlanamaz/bozuk yorumlanır hale gelmesine neden olabilir. Bu halde ilk kararlı sürüm çıkana kadar dilin “Deneysel Dil” sınıfında değerlendirilmesi en mantıklısıdır. Eğer standartlar değişecek olmasına rağmen dil yayınlanacaksa, programcı tarafından seçilebilir versiyon olması da işe yarayabilecek bir çözüm yoludur.
Paket Deposu Geliştirme
Bir dil sadece ana yapısından oluşmaz; aynı zamanda içerisinde ek kütüphaneler de vardır.
Kütüphanelere gelecek güncellemeleri yönetme kolaylığı için en mantıklı çözüm bir paket yöneticisi yapmaktır. Bu sayede, programlama dilinde eski versiyonu kullananların da kütüphanelere erişimi mümkün olur.
Bir yanıt yazın