From 03970871dbb403dfe3738a6cd67b93f1236a158b Mon Sep 17 00:00:00 2001 From: saqut Date: Wed, 27 May 2026 10:53:18 +0300 Subject: [PATCH] chore: JsonObject builder, LiteralType enum, token.hpp doc cleanup --- src/parser/ast_json.hpp | 130 ++++++- src/parser/ast_node.hpp | 228 ++++++++++--- src/parser/token.hpp | 739 ++++++++++++++++++++++++++-------------- 3 files changed, 786 insertions(+), 311 deletions(-) diff --git a/src/parser/ast_json.hpp b/src/parser/ast_json.hpp index 45067c5..978af24 100644 --- a/src/parser/ast_json.hpp +++ b/src/parser/ast_json.hpp @@ -3,7 +3,8 @@ // ============================================================================ // // DİZİN: src/parser/ast_json.hpp -// KATMAN: AST — Sadece AST düğümlerinin toJson() metotları için +// KATMAN: Katman 3 — Parser (AST JSON serileştirme) +// AMAÇ: AST düğümlerinin toJson() metotlarında kullanılan builder pattern // BAĞIMLI: Yok (sadece , ) // // AMAÇ: @@ -17,6 +18,15 @@ // obj.add("location", loc.toJson()); // ham JSON gömme // return obj.str(); // +// TASARIM KARARLARI: +// 1. Builder pattern: add() çağrıları zincirlenemez ama okunabilirlik kazanır. +// Zincirleme için: return obj.add("a",1).add("b",2).str() — tercih edilmedi. +// 2. addRaw(): Önceden formatlanmış JSON (alt düğüm çıktısı) gömmek için. +// 3. addArray(): Callback ile dizi oluşturma — C++ lambda'ları sayesinde temiz. +// 4. addIfNotEmpty/addIfNot: Koşullu alanlar — null alanları JSON'da göstermemek için. +// JSON çıktısını temiz tutar. +// 5. JSON_INDENT = 2: Standart JSON girinti (4 değil, 2 okunabilir). +// // ============================================================================ #ifndef SAQUT_AST_JSON @@ -25,7 +35,11 @@ #include #include -// Girinti sabiti (tools.hpp'deki jsonIndent ile uyumlu) +// ============================================================================ +// JSON_INDENT — JSON girinti miktarı (boşluk sayısı) +// ============================================================================ +// tools.hpp'deki jsonIndent() ile uyumlu olmalıdır. +// Her seviyede 2 boşluk içe kaydırılır. #define JSON_INDENT 2 // jsonEscape ve jsonIndent tools.hpp'de tanımlıdır. @@ -34,6 +48,10 @@ // JsonObject — JSON Nesne Builder // ============================================================================ // +// AST düğümlerini JSON formatına dönüştürmek için kullanılır. +// Her çağrıda yeni bir JsonObject oluşturulur, alanlar eklenir ve str() ile +// JSON stringi alınır. +// // KULLANIM: // JsonObject obj(depth); // obj.add("kind", "FunctionDecl"); @@ -46,10 +64,21 @@ // }); // return obj.str(); // +// ÖRNEK ÇIKTI (depth=0): +// { +// "kind": "FunctionDecl", +// "name": "main", +// "returnType": "int", +// "children": [ ... ] +// } +// // ============================================================================ class JsonObject { public: + // JsonObject — Yapıcı + // PARAMETRE: depth — JSON girinti seviyesi (0 = en dış) + // YAN ETKİ: m_ss'e açılış süslü parantezi yazar JsonObject(int depth) : m_indent(jsonIndent(depth)), m_indentInner(jsonIndent(depth + 1)) @@ -57,44 +86,89 @@ public: m_ss << m_indent << "{\n"; } - // String alan ekle (değer tırnak içinde yazılır) + // add() — String alan ekle + // PARAMETRELER: + // key — JSON anahtarı (tırnak içinde yazılır) + // value — string değer (otomatik tırnaklanır ve escape edilir) + // YAN ETKİ: m_hasFields true olur + // ÖRN: obj.add("name", "main") → "name": "main" void add(const std::string& key, const std::string& value) { addRaw(key, "\"" + jsonEscape(value) + "\""); } - // Sayısal alan ekle (değer olduğu gibi yazılır) + // add() — Sayısal alan ekle + // PARAMETRELER: + // key — JSON anahtarı + // value — tamsayı değer (tırnaklanmaz, olduğu gibi yazılır) + // ÖRN: obj.add("line", 42) → "line": 42 void add(const std::string& key, int value) { addRaw(key, std::to_string(value)); } - // Boolean alan ekle + // add() — Boolean alan ekle + // PARAMETRELER: + // key — JSON anahtarı + // value — true/false + // ÖRN: obj.add("isPublic", true) → "isPublic": true void add(const std::string& key, bool value) { addRaw(key, value ? "true" : "false"); } - // Ham JSON değeri ekle (önceden formatlanmış, tırnaklanmamış) + // addRaw() — Ham JSON değeri ekle (önceden formatlanmış) + // PARAMETRELER: + // key — JSON anahtarı + // jsonValue — önceden JSON'a çevrilmiş değer (tırnaklanmaz!) + // KULLANIM: Alt düğüm toJson() çıktısını gömmek için. + // addRaw("location", loc.toJson()); void addRaw(const std::string& key, const std::string& jsonValue) { if (m_hasFields) m_ss << ",\n"; m_ss << m_indentInner << "\"" << jsonEscape(key) << "\": " << jsonValue; m_hasFields = true; } - // Alt nesne ekle (bir alt seviyede JSON nesnesi) + // addNested() — Alt nesne ekle (addRaw alias) + // PARAMETRELER: addRaw ile aynı + // KULLANIM: addRaw ile aynı. Sadece okunabilirlik için. void addNested(const std::string& key, const std::string& nestedJson) { addRaw(key, nestedJson); } - // Koşullu string alan (value boş değilse ekle) + // addIfNotEmpty() — Koşullu string alan + // PARAMETRELER: + // key — JSON anahtarı + // value — string değer (sadece boş DEĞİLSE eklenir) + // KULLANIM: Opsiyonel alanlar için. JSON çıktısını temiz tutar. + // obj.addIfNotEmpty("defaultValue", defaultVal); void addIfNotEmpty(const std::string& key, const std::string& value) { if (!value.empty()) add(key, value); } - // Koşullu sayı alan (value varsayılandan farklıysa ekle) + // addIfNot() — Koşullu sayı alan + // PARAMETRELER: + // key — JSON anahtarı + // value — mevcut değer + // defaultValue — varsayılan değer + // EKLEME KOŞULU: value != defaultValue + // KULLANIM: Varsayılan değerler JSON'da tekrarlanmaz. + // obj.addIfNot("precedence", 0, 14); void addIfNot(const std::string& key, int value, int defaultValue) { if (value != defaultValue) add(key, value); } - // Dizi alanı (callback içinde addItem çağrılır) + // addArray() — Dizi alanı (callback ile) + // PARAMETRELER: + // key — JSON anahtarı + // callback — dizi elemanlarını addItem ile ekleyen lambda/fonksiyon + // KULLANIM: + // obj.addArray("children", [&] { + // for (auto* child : children) + // obj.addItem(child->toJson(depth + 2)); + // }); + // ÖRNEK ÇIKTI: + // "children": [ + // { "kind": "Literal", ... }, + // { "kind": "Identifier", ... } + // ] template void addArray(const std::string& key, Fn callback) { if (m_hasFields) m_ss << ",\n"; @@ -106,7 +180,10 @@ public: m_hasFields = true; } - // Diziye eleman ekle (addArray callback'i içinde kullanılır) + // addItem() — Diziye eleman ekle + // PARAMETRE: itemJson — JSON formatında dizi elemanı + // KULLANIM: Sadece addArray callback'i içinde kullanılır. + // YAN ETKİ: m_hasArrayItem true olur (virgül kontrolü için) void addItem(const std::string& itemJson) { if (m_hasArrayItem) m_ss << ","; // Öğeler m_indentInner'in bir seviye altında (depth + 2) @@ -116,19 +193,36 @@ public: m_hasArrayItem = true; } - // Nesneyi kapat ve string olarak döndür + // str() — JSON nesnesini kapat ve string olarak döndür + // DÖNÜŞ: Tam JSON stringi ({"key": "value", ...}) + // YAN ETKİ: Kapanış süslü parantezini ekler. + // KULLANIM: + // JsonObject obj(depth); + // obj.add("kind", "FunctionDecl"); + // return obj.str(); std::string str() { m_ss << "\n" << m_indent << "}"; return m_ss.str(); } private: - std::ostringstream m_ss; - std::string m_indent; // Bu nesnenin girintisi - std::string m_indentInner; // Bir alt seviye girinti - bool m_hasFields = false; - int m_arrayDepth = 0; // İç içe dizi seviyesi - bool m_hasArrayItem = false; + /* ====== Builder State ====== */ + std::ostringstream m_ss; // JSON çıktısının biriktirildiği string stream + + std::string m_indent; // Bu nesnenin girinti seviyesi (depth * 2 boşluk) + // Örn: depth=0 → "", depth=1 → " " + + std::string m_indentInner; // Bir alt seviye girinti ((depth+1) * 2 boşluk) + // Örn: depth=0 → " ", depth=1 → " " + + bool m_hasFields = false; // Alan eklendi mi? (virgül kontrolü için) + // true ise bir sonraki alandan önce virgül + newline + + int m_arrayDepth = 0; // İç içe dizi seviyesi (şu anda kullanılmıyor, + // ileride çok boyutlu diziler için) + + bool m_hasArrayItem = false; // Diziye eleman eklendi mi? (virgül kontrolü) + // true ise bir sonraki elemandan önce virgül }; #endif // SAQUT_AST_JSON diff --git a/src/parser/ast_node.hpp b/src/parser/ast_node.hpp index e5cc206..3739c70 100644 --- a/src/parser/ast_node.hpp +++ b/src/parser/ast_node.hpp @@ -3,12 +3,23 @@ // ============================================================================ // // DİZİN: src/parser/ast_node.hpp -// KATMAN: Katman 3 — Parser -// BAĞIMLI: core/location.hpp, parser/token.hpp, tools.hpp +// KATMAN: Katman 3 — Parser (Ayrıştırıcı) +// AMAÇ: Tüm AST düğümlerinin taban sınıfını ve temel enum'ları tanımlamak // -// Bu dosya: ASTNode taban sınıfını, ASTKind enum'unu, LiteralType enum'unu -// ve çocuk düğümleri JSON olarak yazdırmak için childrenToJson yardımcısını -// içerir. Diğer tüm düğüm sınıfları bu dosyayı include eder. +// BAĞIMLILIKLAR: +// - core/location.hpp: Kaynak kod konum bilgisi (SourceLocation) +// - parser/token.hpp: Token tipleri (TokenType, ParserToken) +// - tools.hpp: Yardımcı fonksiyonlar (jsonIndent vb.) +// +// MİMARİ KARARLAR: +// 1. ASTNode, tüm düğümlerin ortak davranışını (log, toJson, children) +// tek bir yerde tanımlar. NVI (Non-Virtual Interface) pattern'i. +// 2. virtual log() ve toJson() — her düğüm kendi çıktısını kendisi üretir. +// 3. parent pointer — AST'de yukarı doğru gezinme (ör: sembol çözümleme). +// 4. children vector — aşağı doğru gezinme (ör: tüm düğümleri ziyaret). +// 5. ASTKind enum — switch/case ile tip kontrolü (dynamic_cast yerine). +// Performans: dynamic_cast < switch/case < virtual method çağrısı +// Ama switch/case ile yeni tip eklemek derleyici uyarısı verir (eksik case). // // ============================================================================ @@ -26,43 +37,112 @@ // ============================================================================ // ASTKind — Düğüm Tipi Enum // ============================================================================ +// +// Tüm AST düğüm tiplerini tanımlar. Her düğüm sınıfı bu enum'dan bir değer +// alır. enum class olması sayesinde isim çakışması olmaz (ASTKind::Program). +// +// NEDEN enum class, neden inheritance'daki typeid kullanılmıyor? +// - typeid().name() derleyiciye bağlıdır (g++: "4Program", MSVC: "class Program"). +// - enum class her derleyicide aynıdır, string dönüşümü kolaydır. +// - static_cast ile serileştirilebilir. +// +// ============================================================================ enum class ASTKind { - Program, // Kök düğüm - FunctionDecl, // Fonksiyon tanımı - Block, // { } bloğu - VariableDecl, // Değişken tanımı - BinaryExpression, // İkili işlem (a + b) - UnaryExpression, // Tekli işlem (-a, !a) - Literal, // Sabit değer - Identifier, // İsim referansı - Postfix, // Son ek (a++) - IfStatement, // if/else - ForStatement, // for - WhileStatement, // while - DoWhileStatement, // do-while - ReturnStatement, // return - BreakStatement, // break - ContinueStatement, // continue - ExpressionStatement, // ifade + ; - Call, // Fonksiyon çağrısı f(args) - MemberAccess, // Üye erişimi a.b, a->b - IndexExpression, // Dizi erişimi a[i] - StructDecl, // struct tanımı + /* ====== En üst seviye ====== */ + Program, // Kök düğüm — tüm programı kapsar. + // İçindeki children: FunctionDecl, StructDecl, VariableDecl. + // Tüm .cpp/.sqt dosyası tek bir Program düğümüdür. + + /* ====== Tanımlar (Declarations) ====== */ + FunctionDecl, // Fonksiyon tanımı. + // children: [returnType?], [name], [params...], [body: Block] + // Örn: int main() { ... } + StructDecl, // struct tanımı. + // children: [name], [members: VariableDecl...] + // Örn: struct Point { int x; int y; }; + VariableDecl, // Değişken tanımı. + // children: [type?], [name], [initializer?] + // Örn: int x = 5; veya string name; + + /* ====== Kontrol Akışı (Statements) ====== */ + Block, // { } bloğu — birleşik ifade. + // children: [statements...] + // Kapsam (scope) oluşturur. Yerel değişkenler burada tanımlanır. + IfStatement, // if (koşul) gövde [else gövde]. + // children: [condition], [thenBranch], [elseBranch?] + ForStatement, // for (init; koşul; artım) gövde. + // children: [init?], [condition?], [increment?], [body] + WhileStatement, // while (koşul) gövde. + // children: [condition], [body] + DoWhileStatement, // do gövde while (koşul); + // children: [body], [condition] + ReturnStatement, // return [ifade?]; + // children: [value?] + BreakStatement, // break; + // children: yok. Sadece döngü/switch içinde geçerli. + ContinueStatement, // continue; + // children: yok. Sadece döngü içinde geçerli. + ExpressionStatement, // ifade + noktalı virgül (;) + // children: [expression] + // Örn: x = 5; veya foo(); + + /* ====== İfadeler (Expressions) ====== */ + BinaryExpression, // İkili işlem: sol OP sağ. + // children: [left], [right] + // OP bilgisi: exprType alanında saklanır. + UnaryExpression, // Tekli işlem: OP operand. + // children: [operand] + // prefix (++x) veya postfix (x++) olabilir. + Literal, // Sabit değer: 42, 3.14, "hello", true, null. + // children: yok. Değer düğümün kendi alanında. + Identifier, // İsim referansı: x, PI, main. + // children: yok. İsim string olarak saklanır. + Postfix, // Postfix işlem: operand++. + // children: [operand] + Call, // Fonksiyon/metot çağrısı: f(args). + // children: [callee], [args...] + MemberAccess, // Üye erişimi: a.b veya a->b. + // children: [object], [member] + IndexExpression, // Dizi/indeks erişimi: a[i]. + // children: [object], [index] }; // ============================================================================ // LiteralType — Sabit Değer Alt Tipleri // ============================================================================ +// +// Literal düğümünün hangi türde bir sabit değer taşıdığını belirler. +// uint8_t tabanlı — 256 farklı literal tipi yeterli. +// +// KULLANIM: +// Literal düğümü oluşturulurken tip belirtilir: +// Literal lit(LiteralType::INTEGER, "42"); +// +// ============================================================================ enum class LiteralType : uint8_t { - INTEGER, // Tamsayı (decimal, hex, octal, binary) - FLOAT, // Ondalıklı sayı (3.14, 1e-5) - STRING, // Metin ("hello") - BOOLEAN, // true / false - BOŞ // null + INTEGER, // Tamsayı sabiti: 42, 0xFF, 0b1010, 0777 + // Decimal, hexadecimal (0x), octal (0), binary (0b) desteklenir. + // Tokenizer NumberToken ile iletilir. + FLOAT, // Ondalıklı sayı: 3.14, 1e-5, 2.0f + // Nokta veya üs (e/E) içeren sayılar. + STRING, // Metin sabiti: "merhaba dünya" + // Çift tırnak içinde. Kaçış dizileri (\n, \t, \") desteklenir. + BOOLEAN, // Mantıksal değer: true / false + // KW_TRUE veya KW_FALSE token'ından gelir. + BOŞ // null sabiti (Türkçe "boş"). + // KW_NULL token'ından gelir. Nesne/referans türleri için kullanılır. }; +// ============================================================================ +// literalTypeToString — LiteralType'ı string'e çevir (log için) +// ============================================================================ +// +// PARAMETRE: t — LiteralType enum değeri +// DÖNÜŞ: const char* — insan tarafından okunabilir string +// KARMAŞIKLIK: O(1) — switch/case (derleyici jump table üretir) +// inline const char* literalTypeToString(LiteralType t) { switch (t) { case LiteralType::INTEGER: return "integer"; @@ -79,53 +159,119 @@ inline const char* literalTypeToString(LiteralType t) { // ============================================================================ // // Tüm AST düğümleri bu sınıftan türetilir. Her düğüm: -// - kind: Tipini bilir (ASTKind enum) -// - parent: Ebeveynine işaret eder -// - loc: Kaynak koddaki konumunu bilir -// - log(): Konsola yazdırılabilir -// - toJson: JSON olarak serileştirilebilir +// - kind: ASTKind enum — tipini bilir (switch/case için) +// - parent: Ebeveyn düğüme işaretçi (ağaçta yukarı gezinme) +// - loc: Kaynak koddaki satır/sütun konumu (hata mesajları için) +// - children: Alt düğümler (ağaçta aşağı gezinme) +// - log(): Konsola hiyerarşik yazdırma +// - toJson(): JSON formatında serileştirme +// +// KALITIM: +// Program : ASTNode — Kök düğüm +// FunctionDecl : ASTNode — Fonksiyon tanımı +// BinaryExpression : ASTNode — İkili işlem +// ... (her düğüm tipi ayrı sınıf) +// +// BELLEK YÖNETİMİ: +// Düğümler new ile oluşturulur, delete ile yok edilir. +// Sahiplik: Parser oluşturur, çağıran (main/CLI) yok eder. +// TODO(Büyük yeniden düzenleme): std::unique_ptr ile RAII. // // ============================================================================ class ASTNode { public: - ASTKind kind; - ASTNode* parent = nullptr; - SourceLocation loc; + /* ====== Her düğümün tipi ====== */ + ASTKind kind; // Düğüm tipi (Program, FunctionDecl, ...) + // switch(kind) ile tip kontrolü. + // Set edilir ve bir daha değişmez. + /* ====== Ağaç bağlantıları ====== */ + ASTNode* parent = nullptr; // Ebeveyn düğüm pointerı. + // addChild() tarafından otomatik set edilir. + // Kullanım: semantic analizde kapsam bulma. + // Örn: değişkenin tanımlandığı fonksiyonu bulmak + // için parent->parent->... şeklinde yukarı çıkılır. + + /* ====== Kaynak konumu ====== */ + SourceLocation loc; // Tokenizer'dan gelen satır/sütun bilgisi. + // Hata mesajlarında: "satır 5, sütun 12" + // TODO: Şu anda tüm düğümlerde dolu değil. + + /* ====== Sanal Metotlar ====== */ + + // log() — Düğümü ve alt düğümlerini konsola yazdırır. + // PARAMETRE: indent — girinti seviyesi (her seviyede 2 boşluk artar) + // KULLANIM: ast->log(0); // tüm ağacı yazdır + // KARMAŞIKLIK: O(n) — tüm alt ağacı dolaşır virtual void log(int indent = 0) { (void)indent; std::cout << "\n"; } + // toJson() — Düğümü ve alt düğümlerini JSON formatında döndürür. + // PARAMETRE: indent — JSON girinti seviyesi + // DÖNÜŞ: JSON stringi + // KULLANIM: std::string json = ast->toJson(0); + // KARMAŞIKLIK: O(n) — tüm alt ağacı dolaşır, string birleştirme maliyeti virtual std::string toJson(int indent = 0) { (void)indent; return "{\"kind\":\"Unknown\"}"; } + /* ====== Yardımcı Metotlar ====== */ + + // addChild() — Alt düğüm ekler ve parent pointer'ını set eder. + // PARAMETRE: child — eklenecek alt düğüm (nullptr olmamalı) + // YAN ETKİ: child->parent = this (otomatik) + // KARMAŞIKLIK: O(1) amortize — vector push_back void addChild(ASTNode* child) { children.push_back(child); child->parent = this; } + // getChildren() — Alt düğüm vektörüne erişim. + // DÖNÜŞ: std::vector& — çocuk düğümler listesi + // KARMAŞIKLIK: O(1) — referans döndürür std::vector& getChildren() { return children; } + + // ~ASTNode() — Sanal yıkıcı (polimorfik silme için) + // delete ASTNode* yapıldığında doğru alt sınıf yıkıcısı çağrılır. + // Bu olmazsa türetilmiş sınıfların kaynakları sızdırılır. virtual ~ASTNode() = default; protected: + // children — Alt düğümlerin vektörü. + // protected: doğrudan erişim yerine addChild/getChildren kullanılır. + // Türetilmiş sınıflar erişebilir (ör: log() içinde çocukları gezme). std::vector children; }; // ============================================================================ // childrenToJson — Düğümün çocuklarını JSON array olarak yaz // ============================================================================ - +// +// Bir düğümün tüm alt düğümlerini dolaşır ve her birinin toJson() çıktısını +// virgülle ayrılmış şekilde birleştirir. +// +// PARAMETRELER: +// node — çocukları yazdırılacak düğüm +// depth — JSON girinti seviyesi +// +// DÖNÜŞ: JSON array içeriği (köşeli parantezler HARİÇ) +// +// KULLANIM: +// std::string json = childrenToJson(this, depth + 1); +// +// KARMAŞIKLIK: O(n) — n = çocuk sayısı +// inline std::string childrenToJson(ASTNode* node, int depth) { std::ostringstream ss; std::string in = jsonIndent(depth); auto& ch = node->getChildren(); for (size_t i = 0; i < ch.size(); i++) { ss << ch[i]->toJson(depth); - if (i + 1 < ch.size()) ss << ","; + if (i + 1 < ch.size()) ss << ","; // son elemandan sonra virgül yok ss << "\n"; } return ss.str(); diff --git a/src/parser/token.hpp b/src/parser/token.hpp index d05eee9..bb6d131 100644 --- a/src/parser/token.hpp +++ b/src/parser/token.hpp @@ -1,65 +1,43 @@ // ============================================================================ -// saQut Compiler — Parser Token Tipleri ve Operatör Öncelik Tablosu +// saQut Compiler — Parser Token Tipleri, Operatör Öncelik Tablosu ve ParserToken // ============================================================================ // // DİZİN: src/parser/token.hpp -// KATMAN: Katman 3 — Tokenizer ile Parser arasında köprü -// BAĞIMLI: Tokenizer (src/tokenizer/tokenizer.hpp) -// KULLANAN: AST (src/parser/ast.hpp), Parser (src/parser/parser.hpp) +// KATMAN: Katman 3 — Tokenizer ile Parser Arasında Köprü +// AMAÇ: Tokenizer'ın ham token'larını anlamsal tiplere dönüştürmek, +// operatör öncelik ve birleşme kurallarını merkezi olarak tanımlamak // -// AMAÇ: -// Tokenizer'ın ürettiği ham Token'ları (string tipli) Parser'ın anlayacağı -// anlamsal tiplere (TokenType enum) dönüştürür. Ayrıca operatör önceliğini -// (precedence) ve birleşme yönünü (associativity) merkezi olarak tanımlar. +// BAĞIMLILIKLAR: +// - tokenizer/tokenizer.hpp: Token sınıf hiyerarşisi (Token, NumberToken, vs.) +// - KULLANAN: parser/ast.hpp, parser/parser.hpp // -// Bu dosya, Pratt parser'ın "kalbi"dir — tüm operatör önceliği ve birleşme -// kuralları burada tek bir yerde tanımlanır. +// BU DOSYANIN İÇERDİKLERİ: +// 1. TokenType enum (uint16_t): 100+ token tipi (keyword'ler, operatörler, delimiter'lar) +// 2. KEYWORD_MAP: string → TokenType (keyword çözümleme) +// 3. OPERATOR_MAP: string → TokenType (operatör çözümleme) +// 4. OPERATOR_MAP_REV: TokenType → string (log çıktısı için ters harita) +// 5. OPERATOR_MAP_STRREV: TokenType → string (enum ismi, debug için) +// 6. TokenPrecedence(): Öncelik tablosu (18 seviye, Pratt parser'ın kalbi) +// 7. RightAssociative(): Sağ birleşme kontrolü (atama, üs, ternary) +// 8. ParserToken: Parser'ın kullandığı token yapısı (Token* + TokenType) // -// ADR-002: Neden Merkezi Operatör Öncelik Tablosu? -// Recursive descent parser'larda operatör önceliği, her seviye için ayrı -// bir fonksiyon yazılarak (parseAddExpr, parseMulExpr, ...) kod tekrarına -// neden olur. Yeni bir operatör eklemek için yeni fonksiyon + mevcut -// fonksiyonları değiştirmek gerekir. +// TASARIM KARARLARI (ADR-002): +// Neden TokenType enum'ı burada tanımlı, Tokenizer'da değil? +// -> Tokenizer sadece ham token'lar üretir. Anlamsal tipler Parser'ın işidir. +// -> Tokenizer'ın Tokenizer'ın ham yapısını değiştirmeden yeni diller eklenebilir. // -// Pratt parser'da tüm öncelik bilgisi TEK BİR TABLODA (TokenPrecedence) -// toplanır. Yeni operatör eklemek = tabloya bir satır eklemek. +// Neden uint16_t tabanlı enum? +// -> 65K token tipi fazlasıyla yeterli. 2 byte = bellek tasarrufu. +// -> Her AST düğümünde TokenType saklanabilir (opsiyonel). // -// TASARIM KARARLARI: -// 1. TokenType enum: uint16_t tabanlı. Neden? 65K'dan fazla token tipi -// olmayacak, 2 byte yeterli. Bellek tasarrufu AST'de fark eder. +// Neden dört ayrı map? +// -> unordered_map tek yönlüdür. Her yön için ayrı map gerekir. +// -> OPERATOR_MAP_REV: log çıktısında "+" göstermek için. +// -> OPERATOR_MAP_STRREV: enum ismini string olarak (debug, AST dump). // -// 2. Üç harita (KEYWORD_MAP, OPERATOR_MAP, OPERATOR_MAP_REV, OPERATOR_MAP_STRREV): -// - KEYWORD_MAP: "if" → KW_IF, string'den TokenType'a -// - OPERATOR_MAP: "+" → PLUS, operatör string'inden TokenType'a -// - OPERATOR_MAP_REV: PLUS → "+", log çıktısı için ters harita -// - OPERATOR_MAP_STRREV: PLUS → "PLUS", enum ismini string olarak verir -// Neden dört harita? Çünkü std::unordered_map tek yönlüdür. -// bidirectional_map kütüphanesi kullanılabilirdi ama bağımlılık istemedik. -// -// 3. TokenPrecedence(): 18 seviyeli öncelik sistemi. -// C/C++/Java standartlarına uygun. Yüksek sayı = yüksek öncelik. -// Seviye 18 (en yüksek): üye erişimi (., ->, [], (), ::) -// Seviye 1 (en düşük): virgül (,) -// Seviye 0: önceliksiz (değerler, EOF, vb.) -// -// 4. RightAssociative(): Hangi operatörler sağdan sola birleşir? -// - Atama (=, +=, vb.) -// - Üs alma (**, ^) — matematiksel sağ birleşme: a^b^c = a^(b^c) -// - Ternary (?:) -// Diğer tüm operatörler soldan sağa birleşir. -// -// 5. ParserToken yapısı: -// Token* token: Tokenizer'ın ürettiği Token'a pointer. Değer kopyası -// DEĞİL. Neden pointer? Çünkü Token polimorfik (NumberToken, StringToken, -// vb.) ve değer kopyası object slicing'e neden olur. -// BUG FIX (commit 40579ca): Eskiden Token token (değer) vardı. -// TokenType type: Token'ın anlamsal tipi. -// is() / getPowerOperator() / isRightAssociative(): kolaylık metotları. -// -// BİLİNEN SINIRLAMALAR (TODO): -// TODO: Özel operatörler: ?., ??, |>, >>=, vb. (ileride eklenebilir) -// TODO: Kullanıcı tanımlı operatör önceliği (DSL'ler için) -// TODO: Token konum bilgisi (satır/sütun) ParserToken'a eklenmeli +// Neden bu kadar çok keyword? +// -> saQut hem C/C++ hem Java hem de kendi sözdizimini destekler. +// -> Tüm keyword'ler tek enum'da toplanmıştır. // // ============================================================================ @@ -107,185 +85,334 @@ typedef std::vector TokenList; // NEDEN uint16_t? Bellek optimizasyonu. Her AST düğümü bir TokenType taşır. // Binlerce düğümde 2 byte vs 4 byte fark eder. // +/* ================================================================ + * TokenType — Anlamsal Token Tipleri + * ================================================================ + * + * Tokenizer'ın ürettiği ham token'ları (string tipli) Parser'ın + * anlayacağı anlamsal tiplere dönüştürür. + * + * uint16_t tabanlı — 65K token tipi yeterli. + * Bellek: AST düğümlerinde taşınabilir (2 byte). + * + * KATEGORİLER (öncelik sırasına göre): + * 1. Değerler: IDENTIFIER, NUMBER, STRING, SVR_VOID + * 2. Keyword'ler: KW_IF ... KW_NOEXCEPT (C/C++/Java ortak) + * 3. Operatörler: DOT(18) ... COMMA(1) (Pratt öncelik seviyesi) + * 4. Delimiter'lar: LBRACE, RBRACE, SEMICOLON, vb. + * 5. Özel: END_OF_FILE, UNKNOWN, COMMENT, PREPROCESSOR + * + * ================================================================ */ enum class TokenType : uint16_t { - // --- Değerler ve Tanımlayıcılar --- - IDENTIFIER, // değişken/fonksiyon ismi - NUMBER, // 42, 0xFF, 0b1010, 3.14 - STRING, // "merhaba" - SVR_VOID, // Geçersiz/EOF sinyali (Parser içinde kullanılır) + /* ====== Değerler ve Tanımlayıcılar ====== */ + IDENTIFIER, // Değişken/fonksiyon/sınıf ismi. + // Tokenizer'da IdentifierToken olarak üretilir. + // Örn: x, main, Point, calculateAverage + NUMBER, // Sayısal sabit: 42, 0xFF, 0b1010, 3.14, 1e-5 + // Tokenizer'da NumberToken olarak üretilir. + // .isFloat alanı ile tamsayı/ondalık ayrımı yapılır. + STRING, // Metin sabiti: "merhaba", "selam" + // Tokenizer'da StringToken olarak üretilir. + // Kaçış dizileri (\n, \t, \") tokenizer'da çözülür. + SVR_VOID, // Geçersiz/EOF sinyali. + // Parser içinde kullanılır. Tokenizer ÜRETMEZ. + // currentToken() geçersiz indeks gösterdiğinde döner. - // --- Kontrol Akışı Keyword'leri --- - KW_IF, // if - KW_ELSE, // else - KW_FOR, // for - KW_WHILE, // while - KW_DO, // do - KW_SWITCH, // switch - KW_CASE, // case - KW_DEFAULT, // default - KW_BREAK, // break - KW_CONTINUE, // continue - KW_RETURN, // return + /* ====== Kontrol Akışı Keyword'leri ====== */ + KW_IF, // if (koşullu dal) + // Sözdizimi: if (koşul) gövde [else gövde] + KW_ELSE, // else (if'in alternatif dalı) + // Sözdizimi: if (...) ... else ... + // Parser'da if'ten sonra else opsiyoneldir. + KW_FOR, // for (tekrarlı döngü) + // Sözdizimi: for (init; koşul; artım) gövde + KW_WHILE, // while (koşullu döngü) + // Sözdizimi: while (koşul) gövde + KW_DO, // do (en az bir kez çalışan döngü) + // Sözdizimi: do gövde while (koşul); + KW_SWITCH, // switch (çoklu dal — henüz implemente edilmedi) + KW_CASE, // case (switch dalı — henüz implemente edilmedi) + KW_DEFAULT, // default (switch varsayılan — henüz implemente edilmedi) + KW_BREAK, // break (döngü/switch'ten çık) + // Sadece döngü veya switch içinde geçerlidir. + KW_CONTINUE, // continue (döngünün bir sonraki iterasyonuna geç) + // Sadece döngü içinde geçerlidir. + KW_RETURN, // return (fonksiyondan dön) + // İsteğe bağlı dönüş değeri: return expr; - // --- OOP Keyword'leri --- - KW_CLASS, // class - KW_STRUCT, // struct - KW_INTERFACE, // interface - KW_ENUM, // enum - KW_EXTENDS, // extends - KW_IMPLEMENTS, // implements - KW_NEW, // new - KW_PUBLIC, // public - KW_PRIVATE, // private - KW_PROTECTED, // protected - KW_STATIC, // static - KW_FINAL, // final - KW_ABSTRACT, // abstract + /* ====== OOP Keyword'leri ====== */ + KW_CLASS, // class (sınıf tanımı — Java/C++ tarzı) + KW_STRUCT, // struct (yapı tanımı — C tarzı) + // saQut'ta class ve struct ikisi de desteklenir. + KW_INTERFACE, // interface (soyut tip — Java tarzı) + KW_ENUM, // enum (sabit listesi — C/C++/Java tarzı) + KW_EXTENDS, // extends (kalıtım — Java tarzı) + KW_IMPLEMENTS, // implements (interface gerçekleme — Java tarzı) + KW_NEW, // new (nesne oluşturma — Java/C++ tarzı) + KW_PUBLIC, // public (erişim belirteci) + KW_PRIVATE, // private (erişim belirteci) + KW_PROTECTED, // protected (erişim belirteci — alt sınıflara açık) + KW_STATIC, // static (sınıf üyesi / dosya içi bağlantı) + KW_FINAL, // final (değiştirilemez — Java tarzı) + KW_ABSTRACT, // abstract (soyut sınıf/metot — Java tarzı) - // --- Tip Keyword'leri --- - KW_VOID, // void - KW_BOOL, // bool - KW_INT, // int - KW_FLOAT_TYPE, // float (FLOAT math.h'de tanımlı olabilir, TYPE eki var) - KW_DOUBLE, // double - KW_CHAR, // char - KW_STRING_TYPE, // string + /* ====== Tip Keyword'leri ====== */ + KW_VOID, // void (değer döndürmeyen fonksiyon / tip yok) + // C/C++/Java uyumluluğu için. + KW_BOOL, // bool (mantıksal tip: true/false) + // C++ bool ile aynı. + KW_INT, // int (tamsayı tipi: 32-bit işaretli) + // Varsayılan tamsayı tipi. + KW_FLOAT_TYPE, // float (32-bit ondalıklı sayı) + // FLOAT_MATH hatasından kaçınmak için _TYPE eki. + // math.h'deki float tanımıyla çakışmaz. + KW_DOUBLE, // double (64-bit ondalıklı sayı) + KW_CHAR, // char (8-bit karakter) + // Tek tırnak içindeki karakterler için: 'A' + KW_STRING_TYPE, // string (metin tipi) + // string.h'daki string işlevleriyle çakışmaz. - // --- Literal Keyword'ler --- - KW_TRUE, // true - KW_FALSE, // false - KW_NULL, // null + /* ====== Literal Keyword'ler ====== */ + KW_TRUE, // true (mantıksal doğru sabiti) + // Boolean literal: if (true) { ... } + KW_FALSE, // false (mantıksal yanlış sabiti) + // Boolean literal: while (false) { ... } + KW_NULL, // null (boş referans sabiti) + // Pointer/referans tipleri için: Object obj = null; - // --- İstisna Yönetimi --- - KW_TRY, // try - KW_CATCH, // catch - KW_FINALLY, // finally - KW_THROW, // throw - KW_THROWS, // throws - KW_ASSERT, // assert + /* ====== İstisna Yönetimi ====== */ + KW_TRY, // try (istisna deneme bloğu — Java/C++ tarzı) + // Sözdizimi: try { ... } catch (Ex e) { ... } + KW_CATCH, // catch (istisna yakalama bloğu) + KW_FINALLY, // finally (her durumda çalışan blok — Java tarzı) + KW_THROW, // throw (istisna fırlatma — C++/Java tarzı) + // Sözdizimi: throw new Exception("hata"); + KW_THROWS, // throws (metot imzasında istisna bildirimi — Java) + KW_ASSERT, // assert (debug assertions — C/Java tarzı) - // --- Modül/Paket --- - KW_IMPORT, // import - KW_PACKAGE, // package + /* ====== Modül/Paket ====== */ + KW_IMPORT, // import (modül içe aktarma — Java/Python tarzı) + // Sözdizimi: import java.util.List; + KW_PACKAGE, // package (modül bildirimi — Java tarzı) + // Sözdizimi: package com.saqut.compiler; - // --- C/C++ Ekleri --- - KW_NATIVE, // native (JNI) - KW_SYNCHRONIZED, // synchronized (Java) - KW_VOLATILE, // volatile - KW_TRANSIENT, // transient - KW_CONST, // const - KW_EXTERN, // extern - KW_TYPEDEF, // typedef - KW_SIZEOF, // sizeof - KW_ALIGNOF, // alignof - KW_DECLTYPE, // decltype - KW_AUTO, // auto - KW_CONSTEXPR, // constexpr - KW_NOEXCEPT, // noexcept + /* ====== C/C++ Ekleri ====== */ + KW_NATIVE, // native (yerel kod bildirimi — JNI) + // Java native metotları için. + KW_SYNCHRONIZED, // synchronized (iş parçacığı senkronizasyonu — Java) + KW_VOLATILE, // volatile (derleyici optimizasyonunu engelle — C/C++/Java) + KW_TRANSIENT, // transient (serileştirmeyi atla — Java) + KW_CONST, // const (değişmez değer — C/C++ tarzı) + // Örn: const int MAX = 100; + KW_EXTERN, // extern (harici bağlantı — C/C++ tarzı) + KW_TYPEDEF, // typedef (tip takma adı — C/C++ tarzı) + KW_SIZEOF, // sizeof (tip/boyut sorgulama — C/C++ tarzı) + // Sözdizimi: sizeof(int) veya sizeof x + KW_ALIGNOF, // alignof (hizalama sorgulama — C++11) + KW_DECLTYPE, // decltype (ifade tipi çıkarımı — C++11) + KW_AUTO, // auto (otomatik tip çıkarımı — C++11) + KW_CONSTEXPR, // constexpr (derleme zamanı sabiti — C++11) + KW_NOEXCEPT, // noexcept (istisna fırlatmayan bildirimi — C++11) - // ================================================================ - // Operatörler — Öncelik sırasına göre gruplanmış - // ================================================================ + /* ================================================================ + * Operatörler — Öncelik sırasına göre gruplanmış + * + * Her operatörün yanında Pratt parser öncelik seviyesi yazılıdır. + * Yüksek sayı = daha sıkı bağlanma (önce işlenir). + * + * Seviye 18 (en yüksek): Üye erişimi ve çağrı + * Seviye 17: Postfix ++ -- + * Seviye 16: Unary prefix + - ! ~ + * Seviye 15: Üs alma ** ^ + * Seviye 14: Çarpma/Bölme * / % + * Seviye 13: Toplama/Çıkarma + - + * Seviye 12: Bitsel kaydırma << >> + * Seviye 11: İlişkisel < <= > >= + * Seviye 10: Eşitlik == != + * Seviye 9: Bitsel VE & + * Seviye 8: Bitsel XOR ^ (CARET üs olarak 15'te) + * Seviye 7: Bitsel VEYA | + * Seviye 6: Mantıksal VE && + * Seviye 5: Mantıksal VEYA || + * Seviye 4: Ternary ? + * Seviye 3: Ternary else : + * Seviye 2: Atama = += -= vb. + * Seviye 1 (en düşük): Virgül , + * ================================================================ */ - // Seviye 1 (18): Üye erişimi ve çağrı — En yüksek öncelik - DOT, // . - ARROW, // -> - LBRACKET, // [ - RBRACKET, // ] - LPAREN, // ( - RPAREN, // ) + // Seviye 18: Üye erişimi ve çağrı — En yüksek öncelik + DOT, // . (üye erişimi) — obj.field + // Öncelik 18. En sıkı bağlanan operatör. + ARROW, // -> (pointer üye erişimi) — ptr->field + // C++ tarzı. Öncelik 18. + LBRACKET, // [ (dizi/indeks erişimi başlangıcı) — a[i] + // Açılış köşeli parantez. Öncelik 18. + RBRACKET, // ] (dizi/indeks erişimi bitişi) — a[i] + // Kapanış köşeli parantez. Tek başına kullanılmaz. + LPAREN, // ( (fonksiyon çağrısı/grouping başlangıcı) + // İki anlamı: f(args) çağrı, (expr) gruplama. + // Öncelik 18. + RPAREN, // ) (fonksiyon çağrısı/grouping bitişi) + // Kapanış parantez. Tek başına kullanılmaz. - // Seviye 2 (17): Postfix - PLUS_PLUS, // ++ (postfix) - MINUS_MINUS, // -- (postfix) + // Seviye 17: Postfix — Soldaki ifadeye sonradan uygulanan operatörler + PLUS_PLUS, // ++ (postfix artım) — x++ + // Önce x'in değerini döndür, sonra artır. + // Öncelik 17. Sağ birleşmeli DEĞİL. + MINUS_MINUS, // -- (postfix azaltım) — x-- + // Önce x'in değerini döndür, sonra azalt. + // Öncelik 17. - // Seviye 3 (16): Unary Prefix - PLUS, // + (unary) - MINUS, // - (unary) - BANG, // ! (mantıksal değil) - TILDE, // ~ (bitsel değil) + // Seviye 16: Unary Prefix — Sağındaki ifadeye uygulanan tekli operatörler + PLUS, // + (unary plus / binary toplama) + // Unary: +x (pozitif işareti, genelde etkisiz). + // Binary: a + b (toplama, öncelik 13). + // Hangi anlamda kullanıldığı parse bağlamında belirlenir. + MINUS, // - (unary minus / binary çıkarma) + // Unary: -x (negatif yap). + // Binary: a - b (çıkarma, öncelik 13). + BANG, // ! (mantıksal değil) — !x + // Örn: if (!flag) { ... } + // Sadece prefix. Öncelik 16. + TILDE, // ~ (bitsel değil) — ~x + // Bitwise NOT. Sadece prefix. Öncelik 16. - // Seviye 4 (15): Üs alma - STAR_STAR, // ** (Python tarzı üs) - CARET, // ^ (bazı dillerde üs) + // Seviye 15: Üs alma — Sağ birleşmeli + STAR_STAR, // ** (üs alma) — a ** b = a^b + // Python tarzı. Öncelik 15. Sağ birleşmeli. + // 2 ** 3 ** 2 = 2 ** (3 ** 2) = 512 + CARET, // ^ (üs alma veya bitsel XOR) + // saQut'ta varsayılan: üs alma (öncelik 15). + // C/C++'da XOR (öncelik 8) — bağlama göre değişebilir. - // Seviye 5 (14): Çarpma/Bölme - STAR, // * - SLASH, // / - PERCENT, // % + // Seviye 14: Çarpma/Bölme — Sol birleşmeli + STAR, // * (çarpma) — a * b + // Öncelik 14. + SLASH, // / (bölme) — a / b + // Tamsayı bölmesi: int / int = int. + // Ondalık bölme: float / float = float. + PERCENT, // % (mod alma) — a % b + // Sadece tamsayılar için. - // Seviye 6 (13): Toplama/Çıkarma — PLUS ve MINUS yukarıda (unary + binary) - // Seviye 7 (12): Bitsel kaydırma - LSHIFT, // << - RSHIFT, // >> + // Seviye 13: Toplama/Çıkarma + // PLUS ve MINUS yukarıda tanımlandı (hem unary 16 hem binary 13). + // Pratt parser bağlama göre doğru önceliği kullanır. - // Seviye 8 (11): İlişkisel karşılaştırma - LESS, // < - LESS_EQUAL, // <= - GREATER, // > - GREATER_EQUAL, // >= + // Seviye 12: Bitsel kaydırma + LSHIFT, // << (sola kaydırma) — a << b + // a * 2^b. Öncelik 12. + RSHIFT, // >> (sağa kaydırma) — a >> b + // a / 2^b (işaretli: arithmetic, işaretsiz: logical). - // Seviye 9 (10): Eşitlik - EQUAL_EQUAL, // == - BANG_EQUAL, // != + // Seviye 11: İlişkisel karşılaştırma + LESS, // < (küçüktür) — a < b + // true/false döndürür. + LESS_EQUAL, // <= (küçük eşittir) — a <= b + GREATER, // > (büyüktür) — a > b + GREATER_EQUAL, // >= (büyük eşittir) — a >= b - // Seviye 10 (9): Bitsel VE - AMPERSAND, // & + // Seviye 10: Eşitlik + EQUAL_EQUAL, // == (eşittir) — a == b + // Değer eşitliği. Öncelik 10. + BANG_EQUAL, // != (eşit değildir) — a != b - // Seviye 11 (8): Bitsel XOR — CARET yukarıda (üs veya XOR) + // Seviye 9: Bitsel VE + AMPERSAND, // & (bitsel VE) — a & b + // Bitwise AND. Öncelik 9. - // Seviye 12 (7): Bitsel VEYA - PIPE, // | + // Seviye 8: Bitsel XOR + // ^ (CARET) yukarıda (üs olarak seviye 15'te). + // Gelecekte XOR için ayrı token eklenebilir. - // Seviye 13 (6): Mantıksal VE - AMPERSAND_AMPERSAND, // && + // Seviye 7: Bitsel VEYA + PIPE, // | (bitsel VEYA) — a | b + // Bitwise OR. Öncelik 7. - // Seviye 14 (5): Mantıksal VEYA - PIPE_PIPE, // || + // Seviye 6: Mantıksal VE + AMPERSAND_AMPERSAND, // && (mantıksal VE) — a && b + // Kısa devre (short-circuit): a false ise b değerlendirilmez. + // Öncelik 6. - // Seviye 15 (4): Üçlü koşul (ternary) - TERNARY, // ? - COLON, // : (ternary ve etiket için) + // Seviye 5: Mantıksal VEYA + PIPE_PIPE, // || (mantıksal VEYA) — a || b + // Kısa devre: a true ise b değerlendirilmez. + // Öncelik 5. - // Seviye 16 (3): Atama - EQUAL, // = - PLUS_EQUAL, // += - MINUS_EQUAL, // -= - STAR_EQUAL, // *= - SLASH_EQUAL, // /= - PERCENT_EQUAL, // %= - AMPERSAND_EQUAL, // &= - PIPE_EQUAL, // |= - CARET_EQUAL, // ^= - LSHIFT_EQUAL, // <<= - RSHIFT_EQUAL, // >>= + // Seviye 4: Üçlü koşul (ternary) — Sağ birleşmeli + TERNARY, // ? (ternary if) — a ? b : c + // Öncelik 4. Sağ birleşmeli. + // a ? b : c ? d : e = a ? b : (c ? d : e) + COLON, // : (ternary else / etiket) — ternary'in ikinci kısmı + // Ternary'de öncelik 3 (0 değil!). + // Ayrıca switch/case etiketleri için de kullanılır. - // --- Diğer Semboller --- - LBRACE, // { - RBRACE, // } - SEMICOLON, // ; - COMMA, // , - COLON_COLON, // :: + // Seviye 2: Atama — Sağ birleşmeli + EQUAL, // = (basit atama) — a = b + // Öncelik 2. Sağ birleşmeli. + // a = b = 5 = a = (b = 5) + PLUS_EQUAL, // += (topla ve ata) — a += b → a = a + b + MINUS_EQUAL, // -= (çıkar ve ata) — a -= b → a = a - b + STAR_EQUAL, // *= (çarp ve ata) — a *= b → a = a * b + SLASH_EQUAL, // /= (böl ve ata) — a /= b → a = a / b + PERCENT_EQUAL, // %= (mod al ve ata) — a %= b → a = a % b + AMPERSAND_EQUAL, // &= (bitsel VE ve ata) — a &= b → a = a & b + PIPE_EQUAL, // |= (bitsel VEYA ve ata) — a |= b → a = a | b + CARET_EQUAL, // ^= (XOR ve ata) — a ^= b → a = a ^ b + LSHIFT_EQUAL, // <<= (sola kaydır ve ata) — a <<= b → a = a << b + RSHIFT_EQUAL, // >>= (sağa kaydır ve ata) — a >>= b → a = a >> b - // --- Özel --- - END_OF_FILE, // Dosya sonu - UNKNOWN, // Bilinmeyen karakter - COMMENT, // Yorum (// veya /* */) — şu anda token üretilmez - PREPROCESSOR, // Önişlemci (#) — şu anda kullanılmıyor + /* ====== Diğer Semboller ====== */ + LBRACE, // { (açılış süslü parantez) — blok başlangıcı + // Sözdizimi: { statement1; statement2; } + RBRACE, // } (kapanış süslü parantez) — blok bitişi + SEMICOLON, // ; (noktalı virgül) — ifade sonu belirteci + // C/C++/Java tarzında her ifade ; ile biter. + COMMA, // , (virgül) — ifade ayırıcı + // Örn: int a, b, c; veya f(1, 2, 3) + // Öncelik 1 (en düşük). + COLON_COLON, // :: (kapsam çözümleme) — Class::method + // C++ tarzı. Şu anda sadece token tanımlı, parse yok. + + /* ====== Özel Token'lar ====== */ + END_OF_FILE, // Dosya sonu belirteci. + // Tokenizer dosya sonuna gelindiğinde üretir. + // Parser'ın durma koşuludur. + UNKNOWN, // Bilinmeyen/tanınamayan karakter. + // Tokenizer'ın çözemediği her şey. + // Hata raporlamada kullanılır. + COMMENT, // Yorum token'ı (// veya /* */). + // ŞU ANDA TOKEN ÜRETİLMEZ — tokenizer yorumları atlar. + // Gelecekte belge yorumları (///, /** */) için kullanılabilir. + PREPROCESSOR, // Önişlemci direktifi (#). + // ŞU ANDA KULLANILMIYOR — C önişlemcisi yok. + // Gelecekte #include, #define için. }; // ============================================================================ -// KEYWORD_MAP — Keyword String → TokenType +// KEYWORD_MAP — Keyword String → TokenType Dönüşüm Haritası // ============================================================================ // -// Tokenizer'ın ürettiği KeywordToken'ların token değerini (örn: "if") -// Parser'ın anlayacağı TokenType'a (KW_IF) dönüştürür. +// AMAÇ: Tokenizer'ın ürettiği KeywordToken'ların token değerini (örn: "if") +// Parser'ın anlayacağı TokenType'a (KW_IF) dönüştürür. // -// std::unordered_map: O(1) ortalama arama. const: derleme zamanı sabiti. -// std::string_view: string kopyalamadan kaçınır. +// ANAHTAR: std::string_view — keyword string'i (kopyalanmaz, salt okunur) +// DEĞER: TokenType — Parser'ın anlayacağı anlamsal tip // -// NOT: Bu harita, Tokenizer'daki keywords[] dizisi ile eşleşmelidir. -// Birinde ekleme yapılırsa diğerine de eklenmelidir. +// VERİ YAPISI: std::unordered_map +// - O(1) ortalama arama süresi +// - constexpr: derleme zamanı sabiti (derleyici tabloya gömer) +// - std::string_view: string kopyalamadan kaçınır (performans) +// +// BOYUT: ~60 girdi (tüm keyword'ler) +// NEDEN unordered_map, neden map değil? +// - Arama sıklığı: her token için bir kez +// - unordered_map O(1) vs map O(log n) — fark küçük ama var +// - Sıralı erişim gerekmez +// +// SENKRONİZASYON UYARISI: +// Bu harita, Tokenizer'daki keywords[] dizisi İLE EŞLEŞMELİDİR. +// Birinde ekleme yapılırsa diğerine de eklenmelidir. +// TODO: İki listeyi ortak bir kaynaktan üretecek bir makro/kod üreteci. // inline const std::unordered_map KEYWORD_MAP = { // --- Control flow --- @@ -359,16 +486,30 @@ inline const std::unordered_map KEYWORD_MAP = { }; // ============================================================================ -// OPERATOR_MAP — Operatör/Delimiter String → TokenType +// OPERATOR_MAP — Operatör/Delimiter String → TokenType Dönüşüm Haritası // ============================================================================ // -// Tokenizer'ın ürettiği OperatorToken ve DelimiterToken'ları TokenType'a -// dönüştürür. Her iki token tipi de aynı haritayı kullanır çünkü parser -// seviyesinde delimiter'lar da operatör gibi işlenir. +// AMAÇ: Tokenizer'ın ürettiği OperatorToken ve DelimiterToken'ları TokenType'a +// dönüştürür. Her iki token tipi de aynı haritayı kullanır çünkü +// Parser seviyesinde delimiter'lar da operatör gibi işlenir. // -// SIRALAMA ÖNEMLİ DEĞİL (unordered_map). -// Ama Tokenizer'daki operators[] ve delimiters[] dizilerindeki sıralama -// önemlidir — çok karakterliler önce gelmelidir. +// ANAHTAR: std::string_view — operatör/delimiter string'i (örn: "+", "->", "{") +// DEĞER: TokenType — Parser'ın anlayacağı anlamsal tip +// +// VERİ YAPISI: std::unordered_map +// - O(1) ortalama arama +// - const: derleme zamanı sabiti +// - Boyut: ~40 girdi +// +// NEDEN İKİ AYRI HARİTA DEĞİL (operator + delimiter)? +// - Parser seviyesinde fark yok: {, }, ; hepsi operatör gibi işlenir. +// - Tek harita = tek arama = daha basit kod. +// +// SIRALAMA UYARISI: +// Bu haritada sıralama önemli DEĞİL (unordered_map). +// ANCAK Tokenizer'daki operators[] ve delimiters[] dizilerindeki +// sıralama ÖNEMLİDİR — çok karakterliler önce gelmelidir! +// Örn: "->" önce, "-" sonra kontrol edilmelidir. // inline const std::unordered_map OPERATOR_MAP = { // --- 2 karakterli --- @@ -428,12 +569,21 @@ inline const std::unordered_map OPERATOR_MAP = { }; // ============================================================================ -// OPERATOR_MAP_REV — TokenType → Operatör String (Log için) +// OPERATOR_MAP_REV — TokenType → Operatör String (Log/Görüntüleme İçin) // ============================================================================ // -// AST ağacını konsola yazdırırken (log) TokenType enum değerini insan -// tarafından okunabilir operatör sembolüne dönüştürür. -// Örn: TokenType::PLUS → "+" +// AMAÇ: TokenType enum değerini insan tarafından okunabilir operatör +// sembolüne dönüştürür. Log çıktısı ve hata mesajları için kullanılır. +// +// ANAHTAR: TokenType — enum değeri (örn: TokenType::PLUS) +// DEĞER: std::string_view — operatör sembolü (örn: "+") +// +// KULLANIM: +// auto it = OPERATOR_MAP_REV.find(type); +// if (it != OPERATOR_MAP_REV.end()) std::cout << it->second; +// +// NOT: TokenType::IDENTIFIER, NUMBER, STRING, KW_* ve özel token'lar +// bu haritada YOKTUR (operatör değiller). Onlar için ayrı dönüşüm gerekir. // inline const std::unordered_map OPERATOR_MAP_REV = { {TokenType::ARROW, "->"}, @@ -486,11 +636,24 @@ inline const std::unordered_map OPERATOR_MAP_REV = }; // ============================================================================ -// OPERATOR_MAP_STRREV — TokenType → Enum İsmi (Log için) +// OPERATOR_MAP_STRREV — TokenType → Enum İsmi (Debug/Log İçin) // ============================================================================ // -// AST log çıktısında operatörün enum ismini gösterir. -// Örn: TokenType::PLUS → "PLUS" +// AMAÇ: AST log çıktısında operatörün enum ismini (string olarak) gösterir. +// OPERATOR_MAP_REV'den farkı: sembol yerine enum adı döndürür. +// +// KULLANIM: +// AST dump/debug çıktısı: TokenPrecedence(PLUS) yerine "PLUS(13)" gösterimi. +// +// ANAHTAR: TokenType — enum değeri (örn: TokenType::PLUS) +// DEĞER: std::string_view — enum ismi (örn: "PLUS") +// +// ÖRN: TokenType::PLUS → "PLUS" +// TokenType::PLUS_EQUAL → "PLUS_EQUAL" +// +// NOT: İki harita da (REV ve STRREV) aynı anahtarları içerir ama farklı değerler. +// REV: "+" (operatör sembolü) +// STRREV: "PLUS" (enum ismi) // inline const std::unordered_map OPERATOR_MAP_STRREV = { {TokenType::ARROW, "ARROW"}, @@ -543,40 +706,50 @@ inline const std::unordered_map OPERATOR_MAP_STRREV }; // ============================================================================ -// TokenPrecedence — Operatör Öncelik Tablosu +// TokenPrecedence — Operatör Öncelik Tablosu (Pratt Parser'ın Kalbi) // ============================================================================ // -// Pratt parser'ın kalbi. Her TokenType için bir öncelik seviyesi döndürür. -// Yüksek sayı = daha sıkı bağlanma (daha yüksek öncelik). +// AMAÇ: Her TokenType için bir öncelik seviyesi döndürür. +// Yüksek sayı = daha sıkı bağlanma (önce işlenir). +// +// PARAMETRE: type — sorgulanan token tipi +// DÖNÜŞ: uint16_t — öncelik seviyesi (0-18) +// KARMAŞIKLIK: O(1) — switch/case (derleyici jump table üretir) +// +// KULLANIM: +// uint16_t prec = TokenPrecedence(current.type); +// if (prec >= minPrec) { parseLeftDenotation(left); } // // ÖNCELİK SEVİYELERİ (yüksekten düşüğe): -// 18: Üye erişimi . -> [ ] ( ) +// 18: Üye erişimi . -> [ ] ( ) — En yüksek // 17: Postfix ++ -- -// 16: Unary prefix ! ~ -// 15: Üs alma ** ^ +// 16: Unary prefix ! ~ + - +// 15: Üs alma ** ^ — Sağ birleşmeli // 14: Çarpma/Bölme * / % // 13: Toplama/Çıkarma + - // 12: Bitsel kaydırma << >> // 11: İlişkisel < <= > >= // 10: Eşitlik == != // 9: Bitsel VE & -// 8: Bitsel XOR ^ (üs olarak 15'te de var — bağlama göre) +// 8: Bitsel XOR ^ (şu anda üs olarak 15'te) // 7: Bitsel VEYA | // 6: Mantıksal VE && // 5: Mantıksal VEYA || // 4: Ternary ? // 3: Ternary else : -// 2: Atama = += -= vb. +// 2: Atama = += -= vb. — Sağ birleşmeli // 1: Virgül , // 0: Önceliksiz (değerler, EOF, bilinmeyen) // -// NOT: C/C++'da ^ operatörü bitsel XOR'tur (seviye 8), ama Python'da üs (seviye 15). -// saQut'ta ^ hem üs hem XOR olarak kullanılabilir (AST'de bağlam belirler). -// Şimdilik ^ seviye 15 (üs) olarak ayarlı. +// KARAR: Neden ^ (CARET) seviye 15 (üs) olarak ayarlı? +// - C/C++'da ^ bitsel XOR'tur (seviye 8). +// - Python'da ** üs, ^ XOR'tur. +// - saQut'ta ^ varsayılan olarak üs alma olarak kullanılır. +// - Gelecekte XOR için ayrı token (CARET_CARET ^^) eklenebilir. // -// BUG FIX (commit 438bc0e): Seviye 8'deki ölü kod (CARET için case olmadan -// return 8) temizlendi. CARET zaten seviye 15'te STAR_STAR ile birlikte -// işleniyor. +// BUG FIX (commit 438bc0e): +// Seviye 8'de CARET için ölü kod (case olmadan return 8) vardı. +// Temizlendi. CARET zaten seviye 15'te STAR_STAR ile birlikte işleniyor. // inline uint16_t TokenPrecedence(TokenType type) { switch (type) { @@ -677,18 +850,29 @@ inline uint16_t TokenPrecedence(TokenType type) { } // ============================================================================ -// RightAssociative — Sağdan Sola Birleşme Kontrolü +// RightAssociative — Sağdan Sola Birleşme (Associativity) Kontrolü // ============================================================================ // -// Hangi operatörler sağdan sola birleşir? +// AMAÇ: Bir operatörün sağdan sola mı, yoksa soldan sağa mı birleştiğini +// belirler. Pratt parser'da doğru ağaç yapısını oluşturmak için kritik. +// +// PARAMETRE: type — sorgulanan operatör tipi +// DÖNÜŞ: bool — true: sağ birleşmeli, false: sol birleşmeli +// KARMAŞIKLIK: O(1) — switch/case // // Sağ birleşmeli operatörler (a OP b OP c = a OP (b OP c)): -// - Üs alma: **, ^ (matematiksel: 2^3^2 = 2^(3^2) = 2^9 = 512) -// - Atama: =, +=, -=, vb. (a = b = 5 → a = (b = 5)) -// - Ternary: ?: (a ? b : c ? d : e → a ? b : (c ? d : e)) +// - STAR_STAR (üs alma): 2 ** 3 ** 2 = 2 ** (3 ** 2) = 2^9 = 512 +// (matematiksel kural: üs sağdan sola birleşir) +// - CARET (üs alma): 2 ^ 3 ^ 2 = 2 ^ (3 ^ 2) = 512 +// - EQUAL (atama): a = b = 5 → a = (b = 5) +// (önce b = 5 çalışır, sonra a = b) +// - +=, -=, *=, vb. (birleşik atama): a += b += 5 → a += (b += 5) +// - TERNARY (üçlü koşul): a ? b : c ? d : e → a ? b : (c ? d : e) +// (iç içe ternary'lerde sağdan sola) // // Sol birleşmeli operatörler (a OP b OP c = (a OP b) OP c): -// - Tüm diğerleri: +, -, *, /, ==, &&, vb. +// - Tüm diğerleri: +, -, *, /, ==, &&, ||, vb. +// (a + b + c = (a + b) + c, yani önce a+b, sonuç + c) // inline bool RightAssociative(TokenType type) { switch (type) { @@ -713,52 +897,103 @@ inline bool RightAssociative(TokenType type) { } // ============================================================================ -// ParserToken — Parser'ın Kullandığı Token Yapısı +// ParserToken — Parser'ın Kullandığı Token Yapısı (Köprü) // ============================================================================ // -// Tokenizer'ın ürettiği ham Token ile Parser'ın ihtiyaç duyduğu anlamsal -// tipi (TokenType) bir arada tutar. +// AMAÇ: Tokenizer'ın ürettiği ham Token ile Parser'ın ihtiyaç duyduğu +// anlamsal tipi (TokenType) bir arada tutar. İki katman arasında +// köprü görevi görür. // // ALANLAR: -// token (Token*): Tokenizer'dan gelen orijinal token. Neden pointer? -// Çünkü Token polimorfik bir sınıf hiyerarşisidir. Değer kopyası (Token) -// object slicing'e neden olur — alt sınıf verileri (NumberToken.isFloat, -// StringToken.context) kaybolur. -// BUG FIX (commit 40579ca): Eskiden Token token (değer) tutuyordu. // -// type (TokenType): Token'ın anlamsal tipi. Örn: NUMBER, PLUS, KW_IF. +// token (Token*): +// Tokenizer'dan gelen orijinal token'a pointer. +// Neden pointer, neden değer (Token token) değil? +// +// Çünkü Token polimorfik bir sınıf hiyerarşisidir: +// Token (base) +// +-- NumberToken (isFloat, numberValue alanları) +// +-- StringToken (context alanı) +// +-- IdentifierToken +// +-- OperatorToken +// +-- DelimiterToken +// +-- KeywordToken +// +// Değer kopyası (Token token) OBJECT SLICING'e neden olur: +// NumberToken → Token'a kopyalanırken isFloat, numberValue KAYBOLUR. +// +// BUG FIX (commit 40579ca): +// Eskiden "Token token" (değer) olarak tanımlanmıştı. +// NumberToken.isFloat her zaman false dönüyordu çünkü slicing oluyordu. +// "Token* token" (pointer) olarak değiştirildi. +// +// type (TokenType): +// Token'ın anlamsal tipi. Örn: NUMBER, PLUS, KW_IF. +// Tokeni parselerken parseToken() tarafından atanır. // // METOTLAR: -// is(TokenType): Bu token belirtilen tipte mi? -// is({...}): Bu token listedeki tiplerden biri mi? -// getPowerOperator(): Bu token bir operatör ise önceliğini döndür. -// isRightAssociative(): Bu operatör sağ birleşmeli mi? +// is(TokenType): Tek tip kontrolü (O(1)) +// is(initializer_list): Çoklu tip kontrolü (O(k), k = liste boyutu) +// getPowerOperator(): Öncelik sorgulama (O(1), TokenPrecedence'a yönlendirir) +// isRightAssociative(): Birleşme yönü sorgulama (O(1)) // struct ParserToken { - Token* token = nullptr; // Tokenizer'dan gelen orijinal token - TokenType type = TokenType::SVR_VOID; // Anlamsal tip + /* ====== Alanlar ====== */ - // Tek tip kontrolü + // Tokenizer'dan gelen orijinal token pointer'ı. + // nullptr olabilir mi? Hayır — geçerli bir token her zaman vardır. + // SVR_VOID durumunda token nullptr olabilir (EOF sinyali). + Token* token = nullptr; + + // Token'ın anlamsal tipi. + // Varsayılan: SVR_VOID (geçersiz/başlangıç değeri). + // parseToken() tarafından atanır. + TokenType type = TokenType::SVR_VOID; + + /* ====== Kolaylık Metotları ====== */ + + // is() — Tek tip kontrolü + // PARAMETRE: t — sorgulanan token tipi + // DÖNÜŞ: true — bu token t tipinde + // KARMAŞIKLIK: O(1) + // KULLANIM: if (current.is(TokenType::SEMICOLON)) { ... } bool is(TokenType t) const { return type == t; } - // Çoklu tip kontrolü — örn: is({KW_INT, KW_FLOAT, KW_VOID}) + // is() — Çoklu tip kontrolü + // PARAMETRE: types — kontrol edilecek tipler listesi + // DÖNÜŞ: true — bu token listedeki tiplerden birine aitse + // KARMAŞIKLIK: O(k) — k = liste boyutu + // KULLANIM: + // if (current.is({KW_INT, KW_FLOAT, KW_VOID})) { ... } + // if (current.is({TokenType::SEMICOLON, TokenType::RPAREN})) { ... } bool is(std::initializer_list types) const { for (TokenType t : types) if (type == t) return true; return false; } - // Operatör önceliği (Pratt parser için) + // getPowerOperator() — Operatör önceliği sorgulama (Pratt parser için) + // DÖNÜŞ: uint16_t — öncelik seviyesi (0-18) + // KARMAŞIKLIK: O(1) — TokenPrecedence'a yönlendirir + // KULLANIM: + // uint16_t prec = current.getPowerOperator(); + // while (prec >= minPrec) { ... parseLeftDenotation(left); } uint16_t getPowerOperator() const { return TokenPrecedence(type); } - // Sağ birleşmeli mi? + // isRightAssociative() — Birleşme yönü sorgulama + // DÖNÜŞ: true — sağ birleşmeli (atama, üs, ternary) + // false — sol birleşmeli (toplama, çarpma, vb.) + // KARMAŞIKLIK: O(1) — RightAssociative'a yönlendirir + // KULLANIM: + // bool rightAssoc = current.isRightAssociative(); + // uint16_t nextPrec = rightAssoc ? prec : prec + 1; bool isRightAssociative() const { return RightAssociative(type); } }; -#endif // SAQUT_PARSER_TOKEN +#endif // SAQUT_PARSER_TOKEN \ No newline at end of file