chore: JsonObject builder, LiteralType enum, token.hpp doc cleanup

This commit is contained in:
saqut 2026-05-27 10:53:18 +03:00
parent 9a013c53d4
commit 03970871db
3 changed files with 786 additions and 311 deletions

View File

@ -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 <string>, <sstream>)
//
// 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 <string>
#include <sstream>
// 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<typename Fn>
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

View File

@ -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<uint16_t> 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 << "<Unknown>\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<ASTNode*>& — çocuk düğümler listesi
// KARMAŞIKLIK: O(1) — referans döndürür
std::vector<ASTNode*>& 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<ASTNode*> 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();

View File

@ -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<Token*> 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<string_view, TokenType>
// - 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<std::string_view, TokenType> KEYWORD_MAP = {
// --- Control flow ---
@ -359,16 +486,30 @@ inline const std::unordered_map<std::string_view, TokenType> 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<string_view, TokenType>
// - 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<std::string_view, TokenType> OPERATOR_MAP = {
// --- 2 karakterli ---
@ -428,12 +569,21 @@ inline const std::unordered_map<std::string_view, TokenType> 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<TokenType, std::string_view> OPERATOR_MAP_REV = {
{TokenType::ARROW, "->"},
@ -486,11 +636,24 @@ inline const std::unordered_map<TokenType, std::string_view> 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<TokenType, std::string_view> OPERATOR_MAP_STRREV = {
{TokenType::ARROW, "ARROW"},
@ -543,40 +706,50 @@ inline const std::unordered_map<TokenType, std::string_view> 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,49 +897,100 @@ 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<TokenType> 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);
}