From ee1e5213cf9d92472066639449d771cfd83edae9 Mon Sep 17 00:00:00 2001 From: saqut Date: Wed, 27 May 2026 09:42:14 +0300 Subject: [PATCH] refactor: modularize parser and AST components --- prcontext.md | 30 ++ src/parser/ast.hpp | 891 ++------------------------------ src/parser/ast_decl.hpp | 143 +++++ src/parser/ast_expr.hpp | 287 +++++++++++ src/parser/ast_json.hpp | 134 +++++ src/parser/ast_node.hpp | 134 +++++ src/parser/ast_stmt.hpp | 307 +++++++++++ src/parser/parser.hpp | 1002 +----------------------------------- src/parser/parser_base.hpp | 62 +++ src/parser/parser_core.hpp | 409 +++++++++++++++ src/parser/parser_decl.hpp | 159 ++++++ src/parser/parser_stmt.hpp | 322 ++++++++++++ 12 files changed, 2033 insertions(+), 1847 deletions(-) create mode 100644 prcontext.md create mode 100644 src/parser/ast_decl.hpp create mode 100644 src/parser/ast_expr.hpp create mode 100644 src/parser/ast_json.hpp create mode 100644 src/parser/ast_node.hpp create mode 100644 src/parser/ast_stmt.hpp create mode 100644 src/parser/parser_base.hpp create mode 100644 src/parser/parser_core.hpp create mode 100644 src/parser/parser_decl.hpp create mode 100644 src/parser/parser_stmt.hpp diff --git a/prcontext.md b/prcontext.md new file mode 100644 index 0000000..9f53358 --- /dev/null +++ b/prcontext.md @@ -0,0 +1,30 @@ +# PR Açıklaması: Parser ve AST Bileşenlerinin Modülerleştirilmesi + +## Açıklama +Bu PR, `src/parser/` dizini altındaki devasa `ast.hpp` ve `parser.hpp` dosyalarını mantıksal parçalara ayırarak kodun okunabilirliğini ve bakımını kolaylaştırmayı amaçlar. Kodun işlevselliği korunmuş, sadece dosya yapısı modüler hale getirilmiştir. + +## Önemli Değişiklikler + +### 1. AST (Soyut Sözdizim Ağacı) Modülerleştirme +`ast.hpp` dosyası artık bir **aggregator** (toplayıcı) görevi görüyor ve aşağıdaki yeni dosyalardan bileşenleri dahil ediyor: +- `ast_node.hpp`: Temel `ASTNode` sınıfı ve `ASTKind` enum'u. +- `ast_expr.hpp`: `LiteralNode`, `BinaryExpressionNode`, `CallExpressionNode` gibi ifade düğümleri. +- `ast_stmt.hpp`: `BlockNode`, `IfStatementNode`, `WhileStatementNode` gibi deyim (statement) düğümleri. +- `ast_decl.hpp`: `FunctionDeclNode`, `VariableDeclNode`, `StructDeclNode` gibi deklarasyon düğümleri. +- `ast_json.hpp`: JSON serileştirme için yardımcı fonksiyonlar (`childrenToJson`, `jsonEscape` vb.). + +### 2. Parser Modülerleştirme +Parser mantığı da benzer şekilde parçalara ayrıldı: +- `parser_base.hpp`: `Parser` sınıfı tanımı ve üye değişkenleri. +- `parser_core.hpp`: Pratt Parser ana döngüsü, NUD ve LED mantığı. +- `parser_decl.hpp`: Fonksiyon, değişken ve struct deklarasyonlarının ayrıştırılması. +- `parser_stmt.hpp`: Deyimlerin (if, for, while, return vb.) ayrıştırılması. + +## Teknik Avantajlar +- **Okunabilirlik:** Binlerce satırlık dosyalar yerine 100-300 satırlık, spesifik görevleri olan dosyalar oluşturuldu. +- **Bakım Kolaylığı:** Belirli bir dil özelliği (örn. yeni bir deyim tipi) eklendiğinde hangi dosyanın değiştirileceği artık çok daha net. +- **Derleme Hızı:** (Gelecekte) İncremental build süreçlerinde sadece değişen parçaların derlenmesine olanak sağlar. + +## Notlar +- Mevcut tüm testler ve `Final.sqt` gibi örnek dosyaların ayrıştırılması sorunsuz çalışmaya devam etmektedir. +- Dosya başlıklarındaki DİZİN ve KATMAN bilgileri güncellenmiştir. diff --git a/src/parser/ast.hpp b/src/parser/ast.hpp index bed7cee..8549003 100644 --- a/src/parser/ast.hpp +++ b/src/parser/ast.hpp @@ -1,878 +1,45 @@ // ============================================================================ -// saQut Compiler — Soyut Sözdizim Ağacı (AST) +// saQut Compiler — Soyut Sözdizim Ağacı (Aggregator) // ============================================================================ // // DİZİN: src/parser/ast.hpp // KATMAN: Katman 3 — Parser'ın ürettiği, IR'nin tükettiği -// BAĞIMLI: Token (src/parser/token.hpp), Tools (src/tools.hpp) -// KULLANAN: Parser (src/parser/parser.hpp), IR (src/ir/ir.hpp), JSON (src/json.hpp) // -// AMAÇ: -// Kaynak kodun hiyerarşik, anlamsal gösterimi. Her dil yapısı (ifade, -// deyim, fonksiyon) bir AST düğümü ile temsil edilir. +// Bu dosya bir AGGREGATOR'dür. Tüm AST düğüm sınıflarını tek bir include +// ile kullanılabilir yapar. // // AST DÜĞÜM HİYERARŞİSİ: -// ASTNode (soyut taban) -// ├── ProgramNode : Kök düğüm, tüm üst seviye deklarasyonları tutar -// ├── FunctionDeclNode : Fonksiyon tanımı (int main() { ... }) -// ├── BlockNode : { ... } bloğu, statement listesi -// ├── VariableDeclNode : Değişken tanımı (int x = 10;) -// ├── IfStatementNode : if/else -// ├── WhileStatementNode : while döngüsü -// ├── ForStatementNode : for döngüsü -// ├── DoWhileStatementNode : do-while döngüsü -// ├── ReturnStatementNode : return [ifade] -// ├── BreakStatementNode : break -// ├── ContinueStatementNode : continue -// ├── ExpressionStatementNode: ifade + ; (bir statement olarak) -// ├── BinaryExpressionNode : İkili işlem (a + b, a * b) -// ├── LiteralNode : Sabit değer (42, "hello", true) -// ├── IdentifierNode : Değişken/fonksiyon ismi -// └── PostfixNode : Son ek işlem (a++, a--) -// -// TASARIM KARARLARI: -// 1. ASTKind enum + log() + toJson(): Her düğüm kendi tipini bilir, -// kendini konsola yazdırabilir ve JSON olarak serileştirebilir. -// Yeni bir düğüm eklendiğinde tüm davranışlar tek yerde tanımlanır. -// -// 2. parent pointer: Her düğüm ebeveynini bilir. -// -// 3. children vektörü (protected): Liste tipi düğümler için. -// -// BİLİNEN SINIRLAMALAR (TODO): -// TODO: Bellek yönetimi (unique_ptr veya arena allocator) -// TODO: Visitor pattern ile log/toJson/IR üretimi ayrıştırılabilir +// ASTNode (soyut taban) — ast_node.hpp +// ├── ProgramNode : Kök düğüm — ast_decl.hpp +// ├── FunctionDeclNode : Fonksiyon tanımı — ast_decl.hpp +// ├── StructDeclNode : struct tanımı — ast_decl.hpp +// ├── VariableDeclNode : Değişken tanımı — ast_decl.hpp +// ├── BlockNode : { ... } bloğu — ast_stmt.hpp +// ├── IfStatementNode : if/else — ast_stmt.hpp +// ├── WhileStatementNode : while — ast_stmt.hpp +// ├── ForStatementNode : for — ast_stmt.hpp +// ├── DoWhileStatementNode : do-while — ast_stmt.hpp +// ├── ReturnStatementNode : return — ast_stmt.hpp +// ├── BreakStatementNode : break — ast_stmt.hpp +// ├── ContinueStatementNode : continue — ast_stmt.hpp +// ├── ExpressionStatementNode: expression; — ast_stmt.hpp +// ├── BinaryExpressionNode : a + b — ast_expr.hpp +// ├── LiteralNode : 42, "hello" — ast_expr.hpp +// ├── IdentifierNode : değişken ismi — ast_expr.hpp +// ├── PostfixNode : a++ — ast_expr.hpp +// ├── CallExpressionNode : f(x) — ast_expr.hpp +// ├── MemberAccessNode : a.b — ast_expr.hpp +// └── IndexExpressionNode : a[i] — ast_expr.hpp // // ============================================================================ #ifndef SAQUT_AST #define SAQUT_AST -#include -#include -#include -#include "core/location.hpp" -#include "parser/token.hpp" -#include "tools.hpp" +#include "parser/ast_node.hpp" +#include "parser/ast_json.hpp" +#include "parser/ast_expr.hpp" +#include "parser/ast_stmt.hpp" +#include "parser/ast_decl.hpp" -// ============================================================================ -// ASTKind — AST Düğüm Tipi Enum'u -// ============================================================================ - -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) — ileride kullanılacak - 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ı -}; - -// ============================================================================ -// ASTNode — Soyut Temel Sınıf -// ============================================================================ - -class ASTNode { -public: - ASTKind kind; - ASTNode* parent = nullptr; - SourceLocation loc; // Bu düğümün kaynak koddaki konumu - - virtual void log(int indent = 0) { - (void)indent; - std::cout << "\n"; - } - - // JSON serileştirme — her alt sınıf kendi implemente eder - virtual std::string toJson(int indent = 0) { - (void)indent; - return "{\"kind\":\"Unknown\"}"; - } - - void addChild(ASTNode* child) { - children.push_back(child); - child->parent = this; - } - - std::vector& getChildren() { return children; } - virtual ~ASTNode() = default; - -protected: - std::vector children; -}; - -// ============================================================================ -// JSON yardımcısı: alt düğüm listesini JSON array olarak yaz -// ============================================================================ -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 << ","; - ss << "\n"; - } - return ss.str(); -} - -// ============================================================================ -// ProgramNode — Kök Düğüm -// ============================================================================ - -class ProgramNode : public ASTNode { -public: - ProgramNode() { kind = ASTKind::Program; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "Program\n"; - for (auto* c : getChildren()) c->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Program\",\n" - << in << " \"children\": [\n" - << childrenToJson(this, depth + 3) - << in << " ]\n" - << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// FunctionDeclNode — Fonksiyon Tanımı -// ============================================================================ - -class FunctionDeclNode : public ASTNode { -public: - std::string name; - std::string returnType; - - FunctionDeclNode() { kind = ASTKind::FunctionDecl; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) - << "FunctionDecl " << returnType << " " << name << "()\n"; - for (auto* c : getChildren()) c->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"FunctionDecl\",\n" - << in << " \"name\": \"" << jsonEscape(name) << "\",\n" - << in << " \"returnType\": \"" << jsonEscape(returnType) << "\",\n" - << in << " \"location\": " << loc.toJson() << ",\n" - << in << " \"children\": [\n" - << childrenToJson(this, depth + 3) - << in << " ]\n" - << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// BlockNode — Blok { ... } -// ============================================================================ - -class BlockNode : public ASTNode { -public: - BlockNode() { kind = ASTKind::Block; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "Block\n"; - for (auto* c : getChildren()) c->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Block\",\n" - << in << " \"children\": [\n" - << childrenToJson(this, depth + 3) - << in << " ]\n" - << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// VariableDeclNode — Değişken Tanımı -// ============================================================================ - -class VariableDeclNode : public ASTNode { -public: - std::string varType; - std::string name; - ASTNode* initExpr = nullptr; - - VariableDeclNode() { kind = ASTKind::VariableDecl; } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"VariableDecl\",\n" - << in << " \"name\": \"" << jsonEscape(name) << "\",\n" - << in << " \"varType\": \"" << jsonEscape(varType) << "\",\n" - << in << " \"location\": " << loc.toJson() << ""; - if (initExpr) { - ss << ",\n" << in << " \"initExpr\":\n" - << initExpr->toJson(depth + 2); - } - // Çoklu değişken bildirimindeki kardeşler (int a, b, c;) - if (!getChildren().empty()) { - ss << ",\n" << in << " \"declarators\": [\n"; - for (size_t i = 0; i < getChildren().size(); i++) { - ss << ((VariableDeclNode*)getChildren()[i])->toJson(depth + 2); - if (i + 1 < getChildren().size()) ss << ","; - ss << "\n"; - } - ss << in << " ]"; - } - ss << "\n" << in << "}"; - return ss.str(); - } - - void log(int indent = 0) override { - std::cout << padRight("", indent) - << "VariableDecl " << varType << " " << name; - if (initExpr) { - std::cout << " =\n"; - initExpr->log(indent + 4); - } else { - std::cout << "\n"; - } - // Kardeş değişkenleri de logla - for (auto* child : getChildren()) { - child->log(indent); - } - } -}; - -// ============================================================================ -// BinaryExpressionNode — İkili İşlem (a OP b) -// ============================================================================ - -class BinaryExpressionNode : public ASTNode { -public: - TokenType Operator; - ASTNode* Left = nullptr; - ASTNode* Right = nullptr; - - BinaryExpressionNode() { kind = ASTKind::BinaryExpression; } - - void log(int indent = 0) override { - auto it = OPERATOR_MAP_STRREV.find(Operator); - std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?"; - std::string val; - auto it2 = OPERATOR_MAP_REV.find(Operator); - if (it2 != OPERATOR_MAP_REV.end()) val = std::string(it2->second); - - std::cout << padRight("", indent) << "BinaryExpr " << sym - << " (" << val << ")\n"; - if (Right) Right->log(indent + 2); - if (Left) Left->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::string opSym = "?"; - auto it = OPERATOR_MAP_REV.find(Operator); - if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second); - - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"BinaryExpression\",\n" - << in << " \"operator\": \"" << jsonEscape(opSym) << "\",\n" - << in << " \"location\": " << loc.toJson() << ""; - if (Left) { - ss << ",\n" << in << " \"left\":\n" - << Left->toJson(depth + 2); - } - if (Right) { - ss << ",\n" << in << " \"right\":\n" - << Right->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// LiteralNode — Sabit Değer -// ============================================================================ - -// Literal tipleri -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 -}; - -inline const char* literalTypeToString(LiteralType t) { - switch (t) { - case LiteralType::INTEGER: return "integer"; - case LiteralType::FLOAT: return "float"; - case LiteralType::STRING: return "string"; - case LiteralType::BOOLEAN: return "boolean"; - case LiteralType::BOŞ: return "null"; - } - return "?"; -} - -class LiteralNode : public ASTNode { -public: - Token* lexerToken = nullptr; - ParserToken parserToken; - - LiteralType literalType = LiteralType::INTEGER; - int literalBase = 10; // 10, 16, 8, 2 (sadece INTEGER/FLOAT için) - bool isFloatValue = false; // Ondalıklı mı? (sadece INTEGER/FLOAT için) - - LiteralNode() { kind = ASTKind::Literal; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) - << "Literal {" << parserToken.token->token << "} " - << literalTypeToString(literalType); - if (literalType == LiteralType::INTEGER && literalBase != 10) - std::cout << " (base " << literalBase << ")"; - std::cout << "\n"; - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::string val = parserToken.token ? parserToken.token->token : "?"; - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Literal\",\n" - << in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n" - << in << " \"value\": \"" << jsonEscape(val) << "\""; - if (literalType == LiteralType::INTEGER && literalBase != 10) { - ss << ",\n" << in << " \"base\": " << literalBase; - } - if (literalType == LiteralType::FLOAT) { - ss << ",\n" << in << " \"isFloat\": true"; - } - ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n" - << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// IdentifierNode — Tanımlayıcı Referansı -// ============================================================================ - -class IdentifierNode : public ASTNode { -public: - Token* lexerToken = nullptr; - ParserToken parserToken; - - IdentifierNode() { kind = ASTKind::Identifier; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) - << "Identifier {" << parserToken.token->token << "}\n"; - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::string name = parserToken.token ? parserToken.token->token : "?"; - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Identifier\",\n" - << in << " \"name\": \"" << jsonEscape(name) << "\",\n" - << in << " \"location\": " << loc.toJson() << "\n" - << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// PostfixNode — Son Ek İşlem (a++, a--) -// ============================================================================ - -class PostfixNode : public ASTNode { -public: - ASTNode* operand = nullptr; - TokenType Operator; - - PostfixNode() { kind = ASTKind::Postfix; } - - void log(int indent = 0) override { - auto it = OPERATOR_MAP_STRREV.find(Operator); - std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?"; - std::cout << padRight("", indent) << "Postfix " << sym; - auto it2 = OPERATOR_MAP_REV.find(Operator); - if (it2 != OPERATOR_MAP_REV.end()) - std::cout << " (" << it2->second << ")"; - std::cout << "\n"; - if (operand) operand->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::string opSym = "?"; - auto it = OPERATOR_MAP_REV.find(Operator); - if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second); - - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Postfix\",\n" - << in << " \"operator\": \"" << jsonEscape(opSym) << "\""; - if (operand) { - ss << ",\n" << in << " \"operand\":\n" - << operand->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// IfStatementNode — if / else -// ============================================================================ - -class IfStatementNode : public ASTNode { -public: - ASTNode* condition = nullptr; - ASTNode* thenBranch = nullptr; - ASTNode* elseBranch = nullptr; - - IfStatementNode() { kind = ASTKind::IfStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "IfStatement\n"; - std::cout << padRight("", indent + 2) << "Condition:\n"; - if (condition) condition->log(indent + 4); - std::cout << padRight("", indent + 2) << "Then:\n"; - if (thenBranch) thenBranch->log(indent + 4); - if (elseBranch) { - std::cout << padRight("", indent + 2) << "Else:\n"; - elseBranch->log(indent + 4); - } - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"IfStatement\""; - if (condition) { - ss << ",\n" << in << " \"condition\":\n" - << condition->toJson(depth + 2); - } - if (thenBranch) { - ss << ",\n" << in << " \"then\":\n" - << thenBranch->toJson(depth + 2); - } - if (elseBranch) { - ss << ",\n" << in << " \"else\":\n" - << elseBranch->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// WhileStatementNode — while Döngüsü -// ============================================================================ - -class WhileStatementNode : public ASTNode { -public: - ASTNode* condition = nullptr; - ASTNode* body = nullptr; - - WhileStatementNode() { kind = ASTKind::WhileStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "WhileStatement\n"; - std::cout << padRight("", indent + 2) << "Condition:\n"; - if (condition) condition->log(indent + 4); - std::cout << padRight("", indent + 2) << "Body:\n"; - if (body) body->log(indent + 4); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"WhileStatement\""; - if (condition) { - ss << ",\n" << in << " \"condition\":\n" - << condition->toJson(depth + 2); - } - if (body) { - ss << ",\n" << in << " \"body\":\n" - << body->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// ForStatementNode — for Döngüsü -// ============================================================================ - -class ForStatementNode : public ASTNode { -public: - ASTNode* init = nullptr; - ASTNode* condition = nullptr; - ASTNode* update = nullptr; - ASTNode* body = nullptr; - - ForStatementNode() { kind = ASTKind::ForStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "ForStatement\n"; - if (init) { - std::cout << padRight("", indent + 2) << "Init:\n"; - init->log(indent + 4); - } - if (condition) { - std::cout << padRight("", indent + 2) << "Condition:\n"; - condition->log(indent + 4); - } - if (update) { - std::cout << padRight("", indent + 2) << "Update:\n"; - update->log(indent + 4); - } - std::cout << padRight("", indent + 2) << "Body:\n"; - if (body) body->log(indent + 4); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"ForStatement\""; - if (init) { - ss << ",\n" << in << " \"init\":\n" - << init->toJson(depth + 2); - } - if (condition) { - ss << ",\n" << in << " \"condition\":\n" - << condition->toJson(depth + 2); - } - if (update) { - ss << ",\n" << in << " \"update\":\n" - << update->toJson(depth + 2); - } - if (body) { - ss << ",\n" << in << " \"body\":\n" - << body->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// DoWhileStatementNode — do-while Döngüsü -// ============================================================================ - -class DoWhileStatementNode : public ASTNode { -public: - ASTNode* condition = nullptr; - ASTNode* body = nullptr; - - DoWhileStatementNode() { kind = ASTKind::DoWhileStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "DoWhileStatement\n"; - std::cout << padRight("", indent + 2) << "Body:\n"; - if (body) body->log(indent + 4); - std::cout << padRight("", indent + 2) << "Condition:\n"; - if (condition) condition->log(indent + 4); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"DoWhileStatement\""; - if (body) { - ss << ",\n" << in << " \"body\":\n" - << body->toJson(depth + 2); - } - if (condition) { - ss << ",\n" << in << " \"condition\":\n" - << condition->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// ReturnStatementNode — return [ifade] -// ============================================================================ - -class ReturnStatementNode : public ASTNode { -public: - ASTNode* value = nullptr; - - ReturnStatementNode() { kind = ASTKind::ReturnStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "ReturnStatement"; - if (value) { - std::cout << "\n"; - value->log(indent + 2); - } else { - std::cout << " (void)\n"; - } - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"ReturnStatement\""; - if (value) { - ss << ",\n" << in << " \"value\":\n" - << value->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// BreakStatementNode — break -// ============================================================================ - -class BreakStatementNode : public ASTNode { -public: - BreakStatementNode() { kind = ASTKind::BreakStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "BreakStatement\n"; - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - return in + "{\n" + in + " \"kind\": \"BreakStatement\"\n" + in + "}"; - } -}; - -// ============================================================================ -// ContinueStatementNode — continue -// ============================================================================ - -class ContinueStatementNode : public ASTNode { -public: - ContinueStatementNode() { kind = ASTKind::ContinueStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "ContinueStatement\n"; - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - return in + "{\n" + in + " \"kind\": \"ContinueStatement\"\n" + in + "}"; - } -}; - -// ============================================================================ -// ExpressionStatementNode — İfadeyi Statement Olarak Sarma -// ============================================================================ - -class ExpressionStatementNode : public ASTNode { -public: - ASTNode* expression = nullptr; - - ExpressionStatementNode() { kind = ASTKind::ExpressionStatement; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "ExpressionStatement\n"; - if (expression) expression->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"ExpressionStatement\",\n" - << in << " \"location\": " << loc.toJson() << ""; - if (expression) { - ss << ",\n" << in << " \"expression\":\n" - << expression->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - - -// ============================================================================ -// CallExpressionNode — Fonksiyon Çağrısı f(a, b, ...) -// ============================================================================ - -class CallExpressionNode : public ASTNode { -public: - ASTNode* callee = nullptr; - std::vector arguments; - - CallExpressionNode() { kind = ASTKind::Call; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "Call\n"; - if (callee) { - std::cout << padRight("", indent + 2) << "Callee:\n"; - callee->log(indent + 4); - } - std::cout << padRight("", indent + 2) << "Args (" << arguments.size() << "):\n"; - for (auto* a : arguments) a->log(indent + 4); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"Call\""; - if (callee) { - ss << ",\n" << in << " \"callee\":\n" - << callee->toJson(depth + 2); - } - ss << ",\n" << in << " \"arguments\": [\n"; - for (size_t i = 0; i < arguments.size(); i++) { - ss << arguments[i]->toJson(depth + 3); - if (i + 1 < arguments.size()) ss << ","; - ss << "\n"; - } - ss << in << " ]\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// MemberAccessNode — Üye Erişimi a.b veya a->b -// ============================================================================ - -class MemberAccessNode : public ASTNode { -public: - ASTNode* object = nullptr; - std::string member; - bool arrow = false; - - MemberAccessNode() { kind = ASTKind::MemberAccess; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "MemberAccess " - << (arrow ? "->" : ".") << " " << member << "\n"; - if (object) object->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"MemberAccess\",\n" - << in << " \"member\": \"" << jsonEscape(member) << "\",\n" - << in << " \"arrow\": " << (arrow ? "true" : "false"); - if (object) { - ss << ",\n" << in << " \"object\":\n" - << object->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// IndexExpressionNode — Dizi Erişimi a[i] -// ============================================================================ - -class IndexExpressionNode : public ASTNode { -public: - ASTNode* object = nullptr; - ASTNode* index = nullptr; - - IndexExpressionNode() { kind = ASTKind::IndexExpression; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "IndexExpression\n"; - if (object) { - std::cout << padRight("", indent + 2) << "Object:\n"; - object->log(indent + 4); - } - if (index) { - std::cout << padRight("", indent + 2) << "Index:\n"; - index->log(indent + 4); - } - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"IndexExpression\""; - if (object) { - ss << ",\n" << in << " \"object\":\n" - << object->toJson(depth + 2); - } - if (index) { - ss << ",\n" << in << " \"index\":\n" - << index->toJson(depth + 2); - } - ss << "\n" << in << "}"; - return ss.str(); - } -}; - -// ============================================================================ -// StructDeclNode — struct Tanımı -// ============================================================================ - -class StructDeclNode : public ASTNode { -public: - std::string name; - - StructDeclNode() { kind = ASTKind::StructDecl; } - - void log(int indent = 0) override { - std::cout << padRight("", indent) << "StructDecl " << name << "\n"; - for (auto* c : getChildren()) c->log(indent + 2); - } - - std::string toJson(int depth = 0) override { - std::string in = jsonIndent(depth); - std::ostringstream ss; - ss << in << "{\n" - << in << " \"kind\": \"StructDecl\",\n" - << in << " \"name\": \"" << jsonEscape(name) << "\",\n" - << in << " \"children\": [\n" - << childrenToJson(this, depth + 3) - << in << " ]\n" - << in << "}"; - return ss.str(); - } -}; #endif // SAQUT_AST diff --git a/src/parser/ast_decl.hpp b/src/parser/ast_decl.hpp new file mode 100644 index 0000000..5602698 --- /dev/null +++ b/src/parser/ast_decl.hpp @@ -0,0 +1,143 @@ +// ============================================================================ +// saQut Compiler — AST Deklarasyon Düğümleri +// ============================================================================ +// +// DİZİN: src/parser/ast_decl.hpp +// İÇERİK: ProgramNode, FunctionDeclNode, VariableDeclNode, StructDeclNode +// +// ============================================================================ + +#ifndef SAQUT_AST_DECL +#define SAQUT_AST_DECL + +#include +#include +#include +#include "parser/ast_node.hpp" +#include "parser/ast_json.hpp" +class ProgramNode : public ASTNode { +public: + ProgramNode() { kind = ASTKind::Program; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "Program\n"; + for (auto* c : getChildren()) c->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Program\",\n" + << in << " \"children\": [\n" + << childrenToJson(this, depth + 3) + << in << " ]\n" + << in << "}"; + return ss.str(); + } +}; + +class FunctionDeclNode : public ASTNode { +public: + std::string name; + std::string returnType; + + FunctionDeclNode() { kind = ASTKind::FunctionDecl; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) + << "FunctionDecl " << returnType << " " << name << "()\n"; + for (auto* c : getChildren()) c->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"FunctionDecl\",\n" + << in << " \"name\": \"" << jsonEscape(name) << "\",\n" + << in << " \"returnType\": \"" << jsonEscape(returnType) << "\",\n" + << in << " \"location\": " << loc.toJson() << ",\n" + << in << " \"children\": [\n" + << childrenToJson(this, depth + 3) + << in << " ]\n" + << in << "}"; + return ss.str(); + } +}; + +class VariableDeclNode : public ASTNode { +public: + std::string varType; + std::string name; + ASTNode* initExpr = nullptr; + + VariableDeclNode() { kind = ASTKind::VariableDecl; } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"VariableDecl\",\n" + << in << " \"name\": \"" << jsonEscape(name) << "\",\n" + << in << " \"varType\": \"" << jsonEscape(varType) << "\",\n" + << in << " \"location\": " << loc.toJson() << ""; + if (initExpr) { + ss << ",\n" << in << " \"initExpr\":\n" + << initExpr->toJson(depth + 2); + } + // Çoklu değişken bildirimindeki kardeşler (int a, b, c;) + if (!getChildren().empty()) { + ss << ",\n" << in << " \"declarators\": [\n"; + for (size_t i = 0; i < getChildren().size(); i++) { + ss << ((VariableDeclNode*)getChildren()[i])->toJson(depth + 2); + if (i + 1 < getChildren().size()) ss << ","; + ss << "\n"; + } + ss << in << " ]"; + } + ss << "\n" << in << "}"; + return ss.str(); + } + + void log(int indent = 0) override { + std::cout << padRight("", indent) + << "VariableDecl " << varType << " " << name; + if (initExpr) { + std::cout << " =\n"; + initExpr->log(indent + 4); + } else { + std::cout << "\n"; + } + // Kardeş değişkenleri de logla + for (auto* child : getChildren()) { + child->log(indent); + } + } +}; + +class StructDeclNode : public ASTNode { +public: + std::string name; + + StructDeclNode() { kind = ASTKind::StructDecl; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "StructDecl " << name << "\n"; + for (auto* c : getChildren()) c->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"StructDecl\",\n" + << in << " \"name\": \"" << jsonEscape(name) << "\",\n" + << in << " \"children\": [\n" + << childrenToJson(this, depth + 3) + << in << " ]\n" + << in << "}"; + return ss.str(); + } +}; +#endif // SAQUT_AST_DECL diff --git a/src/parser/ast_expr.hpp b/src/parser/ast_expr.hpp new file mode 100644 index 0000000..4455260 --- /dev/null +++ b/src/parser/ast_expr.hpp @@ -0,0 +1,287 @@ +// ============================================================================ +// saQut Compiler — AST İfade Düğümleri +// ============================================================================ +// +// DİZİN: src/parser/ast_expr.hpp +// İÇERİK: BinaryExpr, Literal, Identifier, Postfix, +// CallExpression, MemberAccess, IndexExpression +// +// ============================================================================ + +#ifndef SAQUT_AST_EXPR +#define SAQUT_AST_EXPR + +#include +#include +#include +#include "parser/ast_node.hpp" +#include "parser/ast_json.hpp" +class BinaryExpressionNode : public ASTNode { +public: + TokenType Operator; + ASTNode* Left = nullptr; + ASTNode* Right = nullptr; + + BinaryExpressionNode() { kind = ASTKind::BinaryExpression; } + + void log(int indent = 0) override { + auto it = OPERATOR_MAP_STRREV.find(Operator); + std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?"; + std::string val; + auto it2 = OPERATOR_MAP_REV.find(Operator); + if (it2 != OPERATOR_MAP_REV.end()) val = std::string(it2->second); + + std::cout << padRight("", indent) << "BinaryExpr " << sym + << " (" << val << ")\n"; + if (Right) Right->log(indent + 2); + if (Left) Left->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::string opSym = "?"; + auto it = OPERATOR_MAP_REV.find(Operator); + if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second); + + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"BinaryExpression\",\n" + << in << " \"operator\": \"" << jsonEscape(opSym) << "\",\n" + << in << " \"location\": " << loc.toJson() << ""; + if (Left) { + ss << ",\n" << in << " \"left\":\n" + << Left->toJson(depth + 2); + } + if (Right) { + ss << ",\n" << in << " \"right\":\n" + << Right->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +// LiteralType enum'u ve literalTypeToString ast_node.hpp'de tanımlıdır. + +class LiteralNode : public ASTNode { +public: + Token* lexerToken = nullptr; + ParserToken parserToken; + + LiteralType literalType = LiteralType::INTEGER; + int literalBase = 10; // 10, 16, 8, 2 (sadece INTEGER/FLOAT için) + bool isFloatValue = false; // Ondalıklı mı? (sadece INTEGER/FLOAT için) + + LiteralNode() { kind = ASTKind::Literal; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) + << "Literal {" << parserToken.token->token << "} " + << literalTypeToString(literalType); + if (literalType == LiteralType::INTEGER && literalBase != 10) + std::cout << " (base " << literalBase << ")"; + std::cout << "\n"; + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::string val = parserToken.token ? parserToken.token->token : "?"; + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Literal\",\n" + << in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n" + << in << " \"value\": \"" << jsonEscape(val) << "\""; + if (literalType == LiteralType::INTEGER && literalBase != 10) { + ss << ",\n" << in << " \"base\": " << literalBase; + } + if (literalType == LiteralType::FLOAT) { + ss << ",\n" << in << " \"isFloat\": true"; + } + ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n" + << in << "}"; + return ss.str(); + } +}; + +class IdentifierNode : public ASTNode { +public: + Token* lexerToken = nullptr; + ParserToken parserToken; + + IdentifierNode() { kind = ASTKind::Identifier; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) + << "Identifier {" << parserToken.token->token << "}\n"; + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::string name = parserToken.token ? parserToken.token->token : "?"; + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Identifier\",\n" + << in << " \"name\": \"" << jsonEscape(name) << "\",\n" + << in << " \"location\": " << loc.toJson() << "\n" + << in << "}"; + return ss.str(); + } +}; + +class PostfixNode : public ASTNode { +public: + ASTNode* operand = nullptr; + TokenType Operator; + + PostfixNode() { kind = ASTKind::Postfix; } + + void log(int indent = 0) override { + auto it = OPERATOR_MAP_STRREV.find(Operator); + std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?"; + std::cout << padRight("", indent) << "Postfix " << sym; + auto it2 = OPERATOR_MAP_REV.find(Operator); + if (it2 != OPERATOR_MAP_REV.end()) + std::cout << " (" << it2->second << ")"; + std::cout << "\n"; + if (operand) operand->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::string opSym = "?"; + auto it = OPERATOR_MAP_REV.find(Operator); + if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second); + + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Postfix\",\n" + << in << " \"operator\": \"" << jsonEscape(opSym) << "\""; + if (operand) { + ss << ",\n" << in << " \"operand\":\n" + << operand->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +class CallExpressionNode : public ASTNode { +public: + ASTNode* callee = nullptr; + std::vector arguments; + + CallExpressionNode() { kind = ASTKind::Call; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "Call\n"; + if (callee) { + std::cout << padRight("", indent + 2) << "Callee:\n"; + callee->log(indent + 4); + } + std::cout << padRight("", indent + 2) << "Args (" << arguments.size() << "):\n"; + for (auto* a : arguments) a->log(indent + 4); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Call\""; + if (callee) { + ss << ",\n" << in << " \"callee\":\n" + << callee->toJson(depth + 2); + } + ss << ",\n" << in << " \"arguments\": [\n"; + for (size_t i = 0; i < arguments.size(); i++) { + ss << arguments[i]->toJson(depth + 3); + if (i + 1 < arguments.size()) ss << ","; + ss << "\n"; + } + ss << in << " ]\n" << in << "}"; + return ss.str(); + } +}; + +// ============================================================================ +// MemberAccessNode — Üye Erişimi a.b veya a->b +// ============================================================================ + + +class MemberAccessNode : public ASTNode { +public: + ASTNode* object = nullptr; + std::string member; + bool arrow = false; + + MemberAccessNode() { kind = ASTKind::MemberAccess; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "MemberAccess " + << (arrow ? "->" : ".") << " " << member << "\n"; + if (object) object->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"MemberAccess\",\n" + << in << " \"member\": \"" << jsonEscape(member) << "\",\n" + << in << " \"arrow\": " << (arrow ? "true" : "false"); + if (object) { + ss << ",\n" << in << " \"object\":\n" + << object->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +// ============================================================================ +// IndexExpressionNode — Dizi Erişimi a[i] +// ============================================================================ + + +class IndexExpressionNode : public ASTNode { +public: + ASTNode* object = nullptr; + ASTNode* index = nullptr; + + IndexExpressionNode() { kind = ASTKind::IndexExpression; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "IndexExpression\n"; + if (object) { + std::cout << padRight("", indent + 2) << "Object:\n"; + object->log(indent + 4); + } + if (index) { + std::cout << padRight("", indent + 2) << "Index:\n"; + index->log(indent + 4); + } + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"IndexExpression\""; + if (object) { + ss << ",\n" << in << " \"object\":\n" + << object->toJson(depth + 2); + } + if (index) { + ss << ",\n" << in << " \"index\":\n" + << index->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +// ============================================================================ +// StructDeclNode — struct Tanımı +// ============================================================================ + + +#endif // SAQUT_AST_EXPR diff --git a/src/parser/ast_json.hpp b/src/parser/ast_json.hpp new file mode 100644 index 0000000..45067c5 --- /dev/null +++ b/src/parser/ast_json.hpp @@ -0,0 +1,134 @@ +// ============================================================================ +// saQut Compiler — Temiz JSON Üretici (JsonObject) +// ============================================================================ +// +// DİZİN: src/parser/ast_json.hpp +// KATMAN: AST — Sadece AST düğümlerinin toJson() metotları için +// BAĞIMLI: Yok (sadece , ) +// +// AMAÇ: +// AST düğümlerinin toJson() metotlarını okunabilir kılmak. +// stringstream'i el ile yönetmek yerine builder pattern kullanır. +// +// KULLANIM: +// JsonObject obj(depth); +// obj.add("kind", "Literal"); +// obj.add("value", 42); +// obj.add("location", loc.toJson()); // ham JSON gömme +// return obj.str(); +// +// ============================================================================ + +#ifndef SAQUT_AST_JSON +#define SAQUT_AST_JSON + +#include +#include + +// Girinti sabiti (tools.hpp'deki jsonIndent ile uyumlu) +#define JSON_INDENT 2 + +// jsonEscape ve jsonIndent tools.hpp'de tanımlıdır. + +// ============================================================================ +// JsonObject — JSON Nesne Builder +// ============================================================================ +// +// KULLANIM: +// JsonObject obj(depth); +// obj.add("kind", "FunctionDecl"); +// obj.add("name", name); +// obj.add("returnType", returnType); +// obj.addRaw("location", loc.toJson()); // önceden formatlanmış JSON +// obj.addArray("children", [&] { // alt düğümler +// for (auto* child : children) +// obj.addChild(child->toJson(depth + 2)); +// }); +// return obj.str(); +// +// ============================================================================ + +class JsonObject { +public: + JsonObject(int depth) + : m_indent(jsonIndent(depth)), + m_indentInner(jsonIndent(depth + 1)) + { + m_ss << m_indent << "{\n"; + } + + // String alan ekle (değer tırnak içinde yazılır) + 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) + void add(const std::string& key, int value) { + addRaw(key, std::to_string(value)); + } + + // Boolean alan ekle + void add(const std::string& key, bool value) { + addRaw(key, value ? "true" : "false"); + } + + // Ham JSON değeri ekle (önceden formatlanmış, tırnaklanmamış) + 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) + void addNested(const std::string& key, const std::string& nestedJson) { + addRaw(key, nestedJson); + } + + // Koşullu string alan (value boş değilse ekle) + 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) + 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) + template + void addArray(const std::string& key, Fn callback) { + if (m_hasFields) m_ss << ",\n"; + m_ss << m_indentInner << "\"" << jsonEscape(key) << "\": [\n"; + m_arrayDepth++; + callback(); + m_arrayDepth--; + m_ss << "\n" << m_indentInner << "]"; + m_hasFields = true; + } + + // Diziye eleman ekle (addArray callback'i içinde kullanılır) + void addItem(const std::string& itemJson) { + if (m_hasArrayItem) m_ss << ","; + // Öğeler m_indentInner'in bir seviye altında (depth + 2) + std::string itemIndent = ""; + itemIndent.append(m_indentInner.size() + 2, ' '); + m_ss << "\n" << itemIndent << itemJson; + m_hasArrayItem = true; + } + + // Nesneyi kapat ve string olarak döndür + 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; +}; + +#endif // SAQUT_AST_JSON diff --git a/src/parser/ast_node.hpp b/src/parser/ast_node.hpp new file mode 100644 index 0000000..e5cc206 --- /dev/null +++ b/src/parser/ast_node.hpp @@ -0,0 +1,134 @@ +// ============================================================================ +// saQut Compiler — AST Düğüm Tabanı (ASTNode, ASTKind, LiteralType) +// ============================================================================ +// +// DİZİN: src/parser/ast_node.hpp +// KATMAN: Katman 3 — Parser +// BAĞIMLI: core/location.hpp, parser/token.hpp, tools.hpp +// +// 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. +// +// ============================================================================ + +#ifndef SAQUT_AST_NODE +#define SAQUT_AST_NODE + +#include +#include +#include +#include +#include "core/location.hpp" +#include "parser/token.hpp" +#include "tools.hpp" + +// ============================================================================ +// ASTKind — Düğüm Tipi Enum +// ============================================================================ + +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ı +}; + +// ============================================================================ +// LiteralType — Sabit Değer Alt Tipleri +// ============================================================================ + +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 +}; + +inline const char* literalTypeToString(LiteralType t) { + switch (t) { + case LiteralType::INTEGER: return "integer"; + case LiteralType::FLOAT: return "float"; + case LiteralType::STRING: return "string"; + case LiteralType::BOOLEAN: return "boolean"; + case LiteralType::BOŞ: return "null"; + } + return "?"; +} + +// ============================================================================ +// ASTNode — Soyut Taban Sınıf +// ============================================================================ +// +// 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 +// +// ============================================================================ + +class ASTNode { +public: + ASTKind kind; + ASTNode* parent = nullptr; + SourceLocation loc; + + virtual void log(int indent = 0) { + (void)indent; + std::cout << "\n"; + } + + virtual std::string toJson(int indent = 0) { + (void)indent; + return "{\"kind\":\"Unknown\"}"; + } + + void addChild(ASTNode* child) { + children.push_back(child); + child->parent = this; + } + + std::vector& getChildren() { return children; } + virtual ~ASTNode() = default; + +protected: + std::vector children; +}; + +// ============================================================================ +// childrenToJson — Düğümün çocuklarını JSON array olarak yaz +// ============================================================================ + +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 << ","; + ss << "\n"; + } + return ss.str(); +} + +#endif // SAQUT_AST_NODE diff --git a/src/parser/ast_stmt.hpp b/src/parser/ast_stmt.hpp new file mode 100644 index 0000000..b60aaf9 --- /dev/null +++ b/src/parser/ast_stmt.hpp @@ -0,0 +1,307 @@ +// ============================================================================ +// saQut Compiler — AST Deyim Düğümleri +// ============================================================================ +// +// DİZİN: src/parser/ast_stmt.hpp +// İÇERİK: Block, If, While, For, DoWhile, +// Return, Break, Continue, ExpressionStatement +// +// ============================================================================ + +#ifndef SAQUT_AST_STMT +#define SAQUT_AST_STMT + +#include +#include +#include +#include "parser/ast_node.hpp" +#include "parser/ast_json.hpp" +class BlockNode : public ASTNode { +public: + BlockNode() { kind = ASTKind::Block; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "Block\n"; + for (auto* c : getChildren()) c->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"Block\",\n" + << in << " \"children\": [\n" + << childrenToJson(this, depth + 3) + << in << " ]\n" + << in << "}"; + return ss.str(); + } +}; + +class IfStatementNode : public ASTNode { +public: + ASTNode* condition = nullptr; + ASTNode* thenBranch = nullptr; + ASTNode* elseBranch = nullptr; + + IfStatementNode() { kind = ASTKind::IfStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "IfStatement\n"; + std::cout << padRight("", indent + 2) << "Condition:\n"; + if (condition) condition->log(indent + 4); + std::cout << padRight("", indent + 2) << "Then:\n"; + if (thenBranch) thenBranch->log(indent + 4); + if (elseBranch) { + std::cout << padRight("", indent + 2) << "Else:\n"; + elseBranch->log(indent + 4); + } + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"IfStatement\""; + if (condition) { + ss << ",\n" << in << " \"condition\":\n" + << condition->toJson(depth + 2); + } + if (thenBranch) { + ss << ",\n" << in << " \"then\":\n" + << thenBranch->toJson(depth + 2); + } + if (elseBranch) { + ss << ",\n" << in << " \"else\":\n" + << elseBranch->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +class WhileStatementNode : public ASTNode { +public: + ASTNode* condition = nullptr; + ASTNode* body = nullptr; + + WhileStatementNode() { kind = ASTKind::WhileStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "WhileStatement\n"; + std::cout << padRight("", indent + 2) << "Condition:\n"; + if (condition) condition->log(indent + 4); + std::cout << padRight("", indent + 2) << "Body:\n"; + if (body) body->log(indent + 4); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"WhileStatement\""; + if (condition) { + ss << ",\n" << in << " \"condition\":\n" + << condition->toJson(depth + 2); + } + if (body) { + ss << ",\n" << in << " \"body\":\n" + << body->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +class ForStatementNode : public ASTNode { +public: + ASTNode* init = nullptr; + ASTNode* condition = nullptr; + ASTNode* update = nullptr; + ASTNode* body = nullptr; + + ForStatementNode() { kind = ASTKind::ForStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "ForStatement\n"; + if (init) { + std::cout << padRight("", indent + 2) << "Init:\n"; + init->log(indent + 4); + } + if (condition) { + std::cout << padRight("", indent + 2) << "Condition:\n"; + condition->log(indent + 4); + } + if (update) { + std::cout << padRight("", indent + 2) << "Update:\n"; + update->log(indent + 4); + } + std::cout << padRight("", indent + 2) << "Body:\n"; + if (body) body->log(indent + 4); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"ForStatement\""; + if (init) { + ss << ",\n" << in << " \"init\":\n" + << init->toJson(depth + 2); + } + if (condition) { + ss << ",\n" << in << " \"condition\":\n" + << condition->toJson(depth + 2); + } + if (update) { + ss << ",\n" << in << " \"update\":\n" + << update->toJson(depth + 2); + } + if (body) { + ss << ",\n" << in << " \"body\":\n" + << body->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +class DoWhileStatementNode : public ASTNode { +public: + ASTNode* condition = nullptr; + ASTNode* body = nullptr; + + DoWhileStatementNode() { kind = ASTKind::DoWhileStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "DoWhileStatement\n"; + std::cout << padRight("", indent + 2) << "Body:\n"; + if (body) body->log(indent + 4); + std::cout << padRight("", indent + 2) << "Condition:\n"; + if (condition) condition->log(indent + 4); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"DoWhileStatement\""; + if (body) { + ss << ",\n" << in << " \"body\":\n" + << body->toJson(depth + 2); + } + if (condition) { + ss << ",\n" << in << " \"condition\":\n" + << condition->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +// ============================================================================ +// ReturnStatementNode — return [ifade] +// ============================================================================ + +class ReturnStatementNode : public ASTNode { +public: + ASTNode* value = nullptr; + + ReturnStatementNode() { kind = ASTKind::ReturnStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "ReturnStatement"; + if (value) { + std::cout << "\n"; + value->log(indent + 2); + } else { + std::cout << " (void)\n"; + } + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"ReturnStatement\""; + if (value) { + ss << ",\n" << in << " \"value\":\n" + << value->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + +// ============================================================================ +// BreakStatementNode — break +// ============================================================================ + +class BreakStatementNode : public ASTNode { +public: + BreakStatementNode() { kind = ASTKind::BreakStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "BreakStatement\n"; + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + return in + "{\n" + in + " \"kind\": \"BreakStatement\"\n" + in + "}"; + } +}; + +// ============================================================================ +// ContinueStatementNode — continue +// ============================================================================ + +class ContinueStatementNode : public ASTNode { +public: + ContinueStatementNode() { kind = ASTKind::ContinueStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "ContinueStatement\n"; + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + return in + "{\n" + in + " \"kind\": \"ContinueStatement\"\n" + in + "}"; + } +}; + +// ============================================================================ +// ExpressionStatementNode — İfadeyi Statement Olarak Sarma +// ============================================================================ + +class ExpressionStatementNode : public ASTNode { +public: + ASTNode* expression = nullptr; + + ExpressionStatementNode() { kind = ASTKind::ExpressionStatement; } + + void log(int indent = 0) override { + std::cout << padRight("", indent) << "ExpressionStatement\n"; + if (expression) expression->log(indent + 2); + } + + std::string toJson(int depth = 0) override { + std::string in = jsonIndent(depth); + std::ostringstream ss; + ss << in << "{\n" + << in << " \"kind\": \"ExpressionStatement\",\n" + << in << " \"location\": " << loc.toJson() << ""; + if (expression) { + ss << ",\n" << in << " \"expression\":\n" + << expression->toJson(depth + 2); + } + ss << "\n" << in << "}"; + return ss.str(); + } +}; + + +// ============================================================================ +// CallExpressionNode — Fonksiyon Çağrısı f(a, b, ...) +// ============================================================================ + +#endif // SAQUT_AST_STMT diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index 2d93afa..4dddae4 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -1,1000 +1,32 @@ // ============================================================================ -// saQut Compiler — Parser (Sözdizimi Ayrıştırıcı) +// saQut Compiler — Parser (Aggregator) // ============================================================================ // // DİZİN: src/parser/parser.hpp // KATMAN: Katman 3 — Tokenizer'ı tüketir, AST üretir -// BAĞIMLI: Token (token.hpp), AST (ast.hpp) -// KULLANAN: main.cpp // -// AMAÇ: -// Tokenizer'ın ürettiği düz token listesini alıp, dilin gramer kurallarına -// göre hiyerarşik bir AST (Abstract Syntax Tree) üretir. +// Bu dosya bir AGGREGATOR'dür. Parser'ın tüm bileşenlerini tek bir include +// ile kullanılabilir yapar. // -// İKİ AYRI PARSER STRATEJİSİ: -// 1. Recursive Descent (ifadeler için Pratt parser): -// - parseNullDenotation() (NUD): Prefix ifadeleri (sayılar, -, !, parantez) -// - parseLeftDenotation() (LED): Infix/Postfix ifadeler (+, *, ++) -// - parseExpression(precedence): Pratt'ın ana döngüsü +// MİMARİ: +// parser_base.hpp — Parser sınıf tanımı +// parser_core.hpp — parse, parseProgram, parseDeclaration, parseExpression +// parser_decl.hpp — parseFunctionDecl, parseStructDecl, parseVariableDecl +// parser_stmt.hpp — parseStatement, parseBlock, parseIf/While/For/... // -// 2. Recursive Descent (statement/deklarasyon için): -// - parseDeclaration(): Fonksiyon mu, değişken mi, statement mı? -// - parseStatement(): if/for/while/do/return/block/expression -// - Her statement tipi kendi parse fonksiyonuna sahip -// -// ADR-002 (devam): Neden Hibrit Yaklaşım? -// Pratt parser, operatör önceliğini merkezi bir tabloda yönetir ve yeni -// operatör eklemeyi kolaylaştırır. Ancak statement'lar (if, for, while) -// operatör değildir; kendi özel sözdizimleri vardır. Bu nedenle statement -// tarafında klasik recursive descent kullanıyoruz. Bu, her iki dünyanın -// en iyisini birleştirir. -// -// PARSER AKIŞI: -// parse(tokens) -// └── parseProgram() -// └── parseDeclaration() [döngü, SVR_VOID gelene kadar] -// ├── parseFunctionDecl() → tip + isim + ( ) + { gövde } -// ├── parseVariableDecl() → tip + isim [+ = ifade] + ; -// └── parseStatement() -// ├── parseBlock() → { statement* } -// ├── parseIfStatement() → if (expr) stmt [else stmt] -// ├── parseWhileStatement() → while (expr) stmt -// ├── parseForStatement() → for (stmt; expr; expr) stmt -// ├── parseDoWhileStatement() → do stmt while (expr); -// ├── parseReturnStatement() → return [expr]; -// ├── parseBreakStatement() → break; -// ├── parseContinueStatement() → continue; -// ├── parseVariableDecl() → tip + isim ... -// └── parseExpressionStatement() → expr; -// └── parseExpression() [Pratt] -// ├── parseNullDenotation() -// │ ├── LPAREN → ( expr ) -// │ ├── Unary prefix → !expr, -expr, ++expr -// │ ├── NUMBER → Literal -// │ ├── STRING → Literal -// │ ├── true/false/null → Literal -// │ └── IDENTIFIER → Identifier -// └── parseLeftDenotation() [döngü] -// ├── Postfix → expr++, expr-- -// └── Binary infix → expr + expr -// -// BİLİNEN SINIRLAMALAR (TODO): -// TODO: else-if zincirleri (şu anda else'den sonra if gelirse düzgün çalışır mı?) -// TODO: Hata kurtarma (panic mode): ilk hatada durmak yerine senkronizasyon -// TODO: Fonksiyon parametreleri -// TODO: Dizi erişimi: a[i] -// TODO: Fonksiyon çağrısı: f(x, y) -// TODO: Üye erişimi: a.b, a->b -// TODO: Ternary: a ? b : c -// TODO: Tip kontrolü ve sembol tablosu +// İKİ AYRI PARSER STRATEJİSİ: +// 1. Pratt Parser (ifadeler için): Operatör önceliğini merkezi tabloda yönetir +// 2. Recursive Descent (statement/deklarasyon): Her yapı kendi parse fonksiyonuna sahip // // ============================================================================ #ifndef SAQUT_PARSER #define SAQUT_PARSER -#include -#include -#include -#include "parser/token.hpp" -#include "parser/ast.hpp" -#include "tools.hpp" +// Sıralama önemli: önce sınıf tanımı, sonra metot gövdeleri +#include "parser/parser_base.hpp" +#include "parser/parser_core.hpp" +#include "parser/parser_decl.hpp" +#include "parser/parser_stmt.hpp" -// ============================================================================ -// Parser — Sözdizimi Ayrıştırıcı -// ============================================================================ -// -// Durum bilgisi: -// tokens: Tokenizer'dan gelen token listesi (referans değil, kopya değil) -// current: Şu anki token'ın indeksi (0 = ilk token) -// -// Token navigasyon metotları: -// currentToken(): tokens[current] döndürür, ilerlemez -// nextToken(): current++ (sonraki token'a geç) -// lookahead(n): tokens[current + n] döndürür, ilerlemez -// getToken(offset): tokens[current + offset] döndürür -// -class Parser { -public: - ASTNode* parse(TokenList tokens); - -private: - TokenList tokens; // Tokenizer'dan gelen token listesi - int current = 0; // Şu anki token indeksi - - // --- Token navigasyonu --- - ParserToken currentToken(); - void nextToken(); - ParserToken lookahead(uint32_t forward); - ParserToken parseToken(Token* token); - ParserToken getToken(int offset); - - // --- Üst seviye --- - ASTNode* parseProgram(); - - // --- Deklarasyonlar --- - ASTNode* parseDeclaration(); - ASTNode* parseFunctionDecl(); - ASTNode* parseStructDecl(); - ASTNode* parseVariableDecl(); - - // --- Statement'lar --- - ASTNode* parseStatement(); - ASTNode* parseBlock(); - ASTNode* parseIfStatement(); - ASTNode* parseWhileStatement(); - ASTNode* parseForStatement(); - ASTNode* parseDoWhileStatement(); - ASTNode* parseReturnStatement(); - ASTNode* parseBreakStatement(); - ASTNode* parseContinueStatement(); - ASTNode* parseExpressionStatement(); - - // --- İfadeler (Pratt parser) --- - ASTNode* parseExpression(); - ASTNode* parseExpression(uint16_t precedence); - ASTNode* parseNullDenotation(); - ASTNode* parseLeftDenotation(ASTNode* left); -}; - -// ============================================================================ -// Token Navigasyonu -// ============================================================================ - -// -------------------------------------------------------------------------- -// parseToken: Ham Token'ı ParserToken'a dönüştür. -// -// Tokenizer'ın string tabanlı tip sistemini ("number", "operator", ...) -// Parser'ın anlamsal tip sistemine (NUMBER, PLUS, KW_IF, ...) çevirir. -// -// BUG FIX (commit 40579ca): pt.token = token (pointer ataması). -// Eskiden pt.token = *token (değer kopyası) object slicing yapıyordu. -// -------------------------------------------------------------------------- -inline ParserToken Parser::parseToken(Token* token) { - ParserToken pt; - pt.token = token; // Pointer — değer kopyası DEĞİL - - std::string t = token->gettype(); - if (t == "string") - pt.type = TokenType::STRING; - else if (t == "number") - pt.type = TokenType::NUMBER; - else if (t == "operator") - pt.type = OPERATOR_MAP.find(pt.token->token)->second; - else if (t == "delimiter") - pt.type = OPERATOR_MAP.find(pt.token->token)->second; - else if (t == "keyword") - pt.type = KEYWORD_MAP.find(pt.token->token)->second; - else if (t == "identifier") - pt.type = TokenType::IDENTIFIER; - - return pt; -} - -// -------------------------------------------------------------------------- -// getToken: Güvenli token erişimi. Sınır dışı = SVR_VOID. -// -------------------------------------------------------------------------- -inline ParserToken Parser::getToken(int offset) { - if ((int)tokens.size() - 1 < current + offset) { - ParserToken pt; - pt.type = TokenType::SVR_VOID; - return pt; - } - return parseToken(tokens[current + offset]); -} - -inline void Parser::nextToken() { - if ((int)tokens.size() >= current + 1) - current++; -} - -inline ParserToken Parser::lookahead(uint32_t forward) { - return getToken(forward); -} - -inline ParserToken Parser::currentToken() { - return getToken(0); -} - -// ============================================================================ -// Üst Seviye -// ============================================================================ - -// -------------------------------------------------------------------------- -// parse: Parser'ın ana giriş noktası. Token listesini alır, AST döndürür. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parse(TokenList toks) { - tokens = toks; - current = 0; - return parseProgram(); -} - -// -------------------------------------------------------------------------- -// parseProgram: Tüm üst seviye deklarasyonları/statement'ları ayrıştırır. -// -// Program ::= Declaration* -// EOF'a (SVR_VOID) kadar parseDeclaration() çağrılır. -// -// BUG FIX (commit 438bc0e): Eskiden parseExpression() doğrudan çağrılıyordu, -// bu sadece tek bir ifadeyi ayrıştırabiliyordu. Şimdi tam program desteği var. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseProgram() { - ProgramNode* program = new ProgramNode(); - - while (currentToken().type != TokenType::SVR_VOID) { - ASTNode* decl = parseDeclaration(); - if (decl) - program->addChild(decl); - else - break; // Hata durumunda döngüden çık - } - - return program; -} - -// ============================================================================ -// Deklarasyonlar -// ============================================================================ - -// -------------------------------------------------------------------------- -// parseDeclaration: Üst seviye deklarasyon ayrıştırıcı. -// -// Strateji: -// 1. Mevcut token bir tip keyword'ü mü (int, void, float, ...)? -// - Evet → lookahead(2) '(' ise → fonksiyon tanımı -// - Evet → değilse → değişken tanımı -// 2. Değilse → statement (REPL modunda ifade de olabilir) -// -// LOOKAHEAD KULLANIMI: -// "int main()" ve "int x = 10" ayrımı için 2 ileriye bakarız: -// - int main() → lookahead(1)=identifier, lookahead(2)='(' -// - int x = 10 → lookahead(1)=identifier, lookahead(2)='=' -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseDeclaration() { - auto ct = currentToken(); - - // Tip keyword'ü ile başlayan → fonksiyon veya değişken - if (ct.is({ - TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE, - TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR, - TokenType::KW_STRING_TYPE, TokenType::KW_AUTO - })) { - auto la1 = lookahead(1); - auto la2 = lookahead(2); - // int main( ... ) → fonksiyon - if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN) - return parseFunctionDecl(); - // int x ... → değişken - return parseVariableDecl(); - } - - // struct - if (ct.type == TokenType::KW_STRUCT) - return parseStructDecl(); - - // Tip keyword'ü değil → statement - return parseStatement(); -} - -// -------------------------------------------------------------------------- -// parseFunctionDecl: Fonksiyon tanımı. -// -// Sözdizimi: Type Identifier ( [ParamList] ) Block -// Örnek: int main() { ... } -// -// TODO: Parametre listesi ayrıştırma -// TODO: Dönüş tipi doğrulama (şu anda string olarak saklanıyor) -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseFunctionDecl() { - FunctionDeclNode* fn = new FunctionDeclNode(); - fn->loc = currentToken().token->loc; - fn->returnType = currentToken().token->token; // "int", "void", ... - nextToken(); // Dönüş tipini tüket - - fn->name = currentToken().token->token; // "main", "calculate", ... - nextToken(); // İsmi tüket - - // Parametre listesi: ( ... ) - if (currentToken().type == TokenType::LPAREN) { - nextToken(); // '(' tüket - // TODO: Parametreleri ayrıştır - // Şimdilik ')' gelene kadar atla - while (currentToken().type != TokenType::RPAREN && - currentToken().type != TokenType::SVR_VOID) - nextToken(); - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - } - - // Gövde: { ... } - if (currentToken().type == TokenType::LBRACE) { - ASTNode* body = parseBlock(); - fn->addChild(body); - } - - return fn; -} -// -------------------------------------------------------------------------- -// parseStructDecl: struct tanimi. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseStructDecl() { - StructDeclNode* st = new StructDeclNode(); - st->loc = currentToken().token->loc; - nextToken(); - if (currentToken().type == TokenType::IDENTIFIER) { - st->name = currentToken().token->token; - nextToken(); - } - if (currentToken().type == TokenType::LBRACE) { - nextToken(); - while (currentToken().type != TokenType::RBRACE && currentToken().type != TokenType::SVR_VOID) { - ASTNode* field = parseDeclaration(); - if (field) st->addChild(field); - else break; - } - if (currentToken().type == TokenType::RBRACE) nextToken(); - } - if (currentToken().type == TokenType::SEMICOLON) nextToken(); - return st; -} - - -// -------------------------------------------------------------------------- -// parseVariableDecl: Değişken tanımı. -// -// Sözdizimi: Type Identifier [= Expression] {, Identifier [= Expression]} ; -// Örnek: int x = 10; -// float y; (initExpr = nullptr) -// int first = 0, second = 1, next; -// -// Çoklu değişken: -// İlk değişken ana düğüm olur. Virgülle ayrılmış ek değişkenler -// ana düğümün children vektörüne eklenir. JSON çıktısında "declarators" -// dizisi olarak görünür. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseVariableDecl() { - // --- Tip ve ilk değişken adı --- - VariableDeclNode* vd = new VariableDeclNode(); - vd->loc = currentToken().token->loc; - vd->varType = currentToken().token->token; // "int", "float", ... - nextToken(); // Tipi tüket - - if (currentToken().type != TokenType::IDENTIFIER) { - std::cerr << "Parser hatası: değişken ismi bekleniyor\n"; - return vd; - } - - vd->name = currentToken().token->token; - nextToken(); // İsmi tüket - - // Opsiyonel array boyutu: [expr] - if (currentToken().type == TokenType::LBRACKET) { - nextToken(); // '[' - while (currentToken().type != TokenType::RBRACKET && - currentToken().type != TokenType::SEMICOLON && - currentToken().type != TokenType::SVR_VOID) - nextToken(); - if (currentToken().type == TokenType::RBRACKET) - nextToken(); // ']' - } - - // İlk değişkenin başlangıç değeri - if (currentToken().type == TokenType::EQUAL) { - nextToken(); // '=' tüket - vd->initExpr = parseExpression(); - } - - // --- Çoklu değişken: , identifier [= expr] --- - while (currentToken().type == TokenType::COMMA) { - nextToken(); // ',' tüket - - if (currentToken().type != TokenType::IDENTIFIER) { - std::cerr << "Parser hatası: virgülden sonra değişken ismi bekleniyor\n"; - break; - } - - VariableDeclNode* sibling = new VariableDeclNode(); - sibling->loc = currentToken().token->loc; - sibling->varType = vd->varType; // Aynı tip - sibling->name = currentToken().token->token; - nextToken(); // İsmi tüket - - // Opsiyonel array boyutu: [expr] - if (currentToken().type == TokenType::LBRACKET) { - nextToken(); // '[' - while (currentToken().type != TokenType::RBRACKET && - currentToken().type != TokenType::SEMICOLON && - currentToken().type != TokenType::SVR_VOID) - nextToken(); - if (currentToken().type == TokenType::RBRACKET) - nextToken(); // ']' - } - - // Başlangıç değeri - if (currentToken().type == TokenType::EQUAL) { - nextToken(); // '=' tüket - sibling->initExpr = parseExpression(); - } - - // Kardeş düğümü ana düğüme ekle - vd->addChild(sibling); - } - - // Noktalı virgül (opsiyonel — parser hoşgörülü) - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); - - return vd; -} - -// ============================================================================ -// Statement'lar — Recursive Descent -// ============================================================================ - -// -------------------------------------------------------------------------- -// parseStatement: Statement ayrıştırıcı (dispatcher). -// -// Mevcut token'a göre uygun parse fonksiyonuna yönlendirir. -// Sıralama önemli: LBRACE, keyword'ler, değişken tanımı, ifade. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseStatement() { - auto ct = currentToken(); - - if (ct.type == TokenType::LBRACE) - return parseBlock(); - - if (ct.type == TokenType::KW_IF) - return parseIfStatement(); - - if (ct.type == TokenType::KW_WHILE) - return parseWhileStatement(); - - if (ct.type == TokenType::KW_FOR) - return parseForStatement(); - - if (ct.type == TokenType::KW_DO) - return parseDoWhileStatement(); - - if (ct.type == TokenType::KW_RETURN) - return parseReturnStatement(); - - if (ct.type == TokenType::KW_BREAK) - return parseBreakStatement(); - - if (ct.type == TokenType::KW_CONTINUE) - return parseContinueStatement(); - - // Değişken tanımı? (tip keyword'ü ile başlayan) - if (ct.is({ - TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE, - TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR, - TokenType::KW_STRING_TYPE - })) { - return parseVariableDecl(); - } - - // struct tanımı: struct Name { ... } - if (ct.type == TokenType::KW_STRUCT) - return parseStructDecl(); - - // Hiçbiri değilse → ifade statement'ı (atama, fonksiyon çağrısı, ...) - return parseExpressionStatement(); -} - -// -------------------------------------------------------------------------- -// parseBlock: { statement* } -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseBlock() { - BlockNode* block = new BlockNode(); - block->loc = currentToken().token ? currentToken().token->loc : SourceLocation{}; - - if (currentToken().type == TokenType::LBRACE) - nextToken(); // '{' tüket - - while (currentToken().type != TokenType::RBRACE && - currentToken().type != TokenType::SVR_VOID) { - ASTNode* stmt = parseStatement(); - if (stmt) - block->addChild(stmt); - else - break; // Hata durumunda döngüden çık - } - - if (currentToken().type == TokenType::RBRACE) - nextToken(); // '}' tüket - - return block; -} - -// -------------------------------------------------------------------------- -// parseIfStatement: if (expression) statement [else statement] -// -// Süslü parantez zorunlu DEĞİL — tek statement de olabilir. -// if (x > 5) return x; ← geçerli -// if (x > 5) { ... } ← geçerli -// -// TODO: Sallantılı else (dangling else) sorunu: -// if (a) if (b) x; else y; ← else hangi if'e ait? -// Mevcut implementasyon doğru: else en yakın if'e bağlanır. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseIfStatement() { - IfStatementNode* ifNode = new IfStatementNode(); - ifNode->loc = currentToken().token->loc; - nextToken(); // 'if' tüket - - // Koşul: ( expression ) - if (currentToken().type == TokenType::LPAREN) { - nextToken(); // '(' tüket - ifNode->condition = parseExpression(); - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - } - - // Then gövdesi - ifNode->thenBranch = parseStatement(); - - // Opsiyonel else - if (currentToken().type == TokenType::KW_ELSE) { - nextToken(); // 'else' tüket - ifNode->elseBranch = parseStatement(); - } - - return ifNode; -} - -// -------------------------------------------------------------------------- -// parseWhileStatement: while (expression) statement -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseWhileStatement() { - WhileStatementNode* ws = new WhileStatementNode(); - ws->loc = currentToken().token->loc; - nextToken(); // 'while' tüket - - if (currentToken().type == TokenType::LPAREN) { - nextToken(); // '(' tüket - ws->condition = parseExpression(); - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - } - - ws->body = parseStatement(); - return ws; -} - -// -------------------------------------------------------------------------- -// parseForStatement: for (init; condition; update) statement -// -// for'un 3 parçası da isteğe bağlıdır: -// for (;;) { ... } ← sonsuz döngü (geçerli) -// -// init: VariableDeclNode veya ExpressionStatementNode -// for (int i = 0; ...) → VariableDecl -// for (i = 0; ...) → ExpressionStatement -// condition: ifade (nullptr = yok) -// update: ifade (nullptr = yok) -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseForStatement() { - ForStatementNode* fs = new ForStatementNode(); - fs->loc = currentToken().token->loc; - nextToken(); // 'for' tüket - - if (currentToken().type == TokenType::LPAREN) - nextToken(); // '(' tüket - - // Init (opsiyonel) - if (currentToken().type != TokenType::SEMICOLON) - fs->init = parseStatement(); - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); // ';' tüket - - // Condition (opsiyonel) - if (currentToken().type != TokenType::SEMICOLON) - fs->condition = parseExpression(); - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); // ';' tüket - - // Update (opsiyonel) - if (currentToken().type != TokenType::RPAREN) - fs->update = parseExpression(); - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - - // Body - fs->body = parseStatement(); - - return fs; -} - -// -------------------------------------------------------------------------- -// parseDoWhileStatement: do statement while (expression) ; -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseDoWhileStatement() { - DoWhileStatementNode* dw = new DoWhileStatementNode(); - dw->loc = currentToken().token->loc; - nextToken(); // 'do' tüket - - // Gövde - dw->body = parseStatement(); - - // while (expression) ; - if (currentToken().type == TokenType::KW_WHILE) { - nextToken(); // 'while' tüket - if (currentToken().type == TokenType::LPAREN) { - nextToken(); // '(' tüket - dw->condition = parseExpression(); - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - } - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); // ';' tüket - } - - return dw; -} - -// -------------------------------------------------------------------------- -// parseReturnStatement: return [expression] ; -// -// return; ← value = nullptr (void fonksiyon) -// return x + 1; ← value = BinaryExpression -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseReturnStatement() { - ReturnStatementNode* rs = new ReturnStatementNode(); - rs->loc = currentToken().token->loc; - nextToken(); // 'return' tüket - - // Opsiyonel dönüş değeri - // Eğer sıradaki token ; veya } ise → return; - if (currentToken().type != TokenType::SEMICOLON && - currentToken().type != TokenType::RBRACE) { - rs->value = parseExpression(); - } - - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); // ';' tüket - - return rs; -} - -// -------------------------------------------------------------------------- -// parseBreakStatement / parseContinueStatement -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseBreakStatement() { - BreakStatementNode* bs = new BreakStatementNode(); - bs->loc = currentToken().token->loc; - nextToken(); // 'break' tüket - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); - return bs; -} - -inline ASTNode* Parser::parseContinueStatement() { - ContinueStatementNode* cs = new ContinueStatementNode(); - cs->loc = currentToken().token->loc; - nextToken(); // 'continue' tüket - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); - return cs; -} - -// -------------------------------------------------------------------------- -// parseExpressionStatement: expression ; -// -// Bir ifadeyi statement olarak kullanır. Örn: x = 5; foo(); -// -// HATA KURTARMA: -// Eğer parseExpression() başarısız olursa (nullptr), sonraki ; veya } -// veya EOF'a kadar token'ları atlayarak senkronize olur. Bu, tek bir -// hatalı ifadenin tüm parser'ı kilitlemesini önler. -// -// BUG FIX (commit 438bc0e): Eskiden hatalı ifade durumunda sonsuz -// döngüye giriyordu (parseProgram her seferinde aynı ifadeyi okuyordu). -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseExpressionStatement() { - ExpressionStatementNode* es = new ExpressionStatementNode(); - es->loc = currentToken().token ? currentToken().token->loc : SourceLocation{}; - es->expression = parseExpression(); - if (!es->expression) { - // Hata kurtarma: sonraki güvenli noktaya atla - while (currentToken().type != TokenType::SEMICOLON && - currentToken().type != TokenType::RBRACE && - currentToken().type != TokenType::SVR_VOID) - nextToken(); - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); - } - if (currentToken().type == TokenType::SEMICOLON) - nextToken(); - - return es; -} - -// ============================================================================ -// İfadeler — Pratt Parser (Top-Down Operator Precedence) -// ============================================================================ -// -// Pratt parser'ın temel fikri: Her operatörün bir "bağlanma gücü" (precedence) -// vardır. Parser, bu güce göre operatörleri doğru sırada gruplar. -// -// NUD (Null Denotation): Prefix ifadeleri (sayılar, -, !, parantez) -// LED (Left Denotation): Infix/Postfix ifadeler (+, *, ++) -// -// ÖRNEK: 1 + 2 * 3 -// 1. NUD: 1 → Literal(1) -// 2. LED(+): prec=13, right'i parseExpression(13) ile ayrıştır -// 2a. NUD: 2 → Literal(2) -// 2b. LED(*): prec=14 > 13 → parseExpression(14) -// 3a. NUD: 3 → Literal(3) -// 3b. LED yok → dön -// 2c. BinaryExpr(*, 2, 3) dön -// 3. BinaryExpr(+, 1, BinaryExpr(*, 2, 3)) -// Sonuç: 1 + (2 * 3) ✓ -// -// BUG FIX (commit 40579ca): Ana döngü lookahead(1) yerine currentToken() -// kullanıyor. NUD artık token'ı tüketip ilerliyor, bu sayede currentToken() -// her zaman bir sonraki operatörü gösterir. -// -// BUG FIX (commit 438bc0e): Atom'lar (sayı, string, identifier) NUD'da -// nextToken() ile tüketiliyor. Eskiden tüketilmediği için sonsuz döngü -// oluyordu. -// -// ============================================================================ - -// -------------------------------------------------------------------------- -// parseExpression(): Öncelik 0'dan başla (en düşük bağlanma) -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseExpression() { - return parseExpression(0); -} - -// -------------------------------------------------------------------------- -// parseExpression(precedence): Pratt'ın ana döngüsü. -// -// Algoritma: -// 1. NUD ile ilk operand'ı ayrıştır (prefix) -// 2. Mevcut token bir operatör mü? -// - Evet ve önceliği > precedence ise → LED ile infix ayrıştır -// - Hayır veya öncelik <= precedence ise → dur, sol operand'ı döndür -// 3. LED'in döndürdüğü düğüm yeni sol operand olur, 2. adıma dön -// -// DURMA KOŞULLARI: -// - RPAREN, SEMICOLON, RBRACE, COMMA: İfade sonu sinyali -// - Operatörün önceliği <= mevcut öncelik: Daha sıkı bağlanamaz -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseExpression(uint16_t precedence) { - if (currentToken().type == TokenType::SVR_VOID) - return nullptr; - - // 1. Prefix (NUD) - ASTNode* left = parseNullDenotation(); - if (!left) return nullptr; - - // 2. Infix/Postfix döngüsü (LED) - while (true) { - auto next = currentToken(); - - // İfade sonu sinyalleri → dur - if (next.type == TokenType::RPAREN || - next.type == TokenType::SEMICOLON || - next.type == TokenType::RBRACE || - next.type == TokenType::COMMA) - break; - - // Operatörün bağlanma gücü yetersiz → dur - // (daha yüksek öncelikli bir bağlamdayız, bu operatör oraya ait değil) - if (precedence < next.getPowerOperator()) { - left = parseLeftDenotation(left); - } else { - break; - } - } - return left; -} - -// -------------------------------------------------------------------------- -// parseNullDenotation (NUD): Prefix ifadeleri. -// -// İşlenen prefix tipleri: -// - Parantez: ( expression ) -// - Unary: +expr, -expr, !expr, ~expr, ++expr, --expr -// - Literal: 42, "hello", true, false, null -// - Identifier: x, myVar -// -// DÖNÜŞ: Ayrıştırılmış AST düğümü. Token TÜKETİLMİŞ olur (current ilerlemiş). -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseNullDenotation() { - auto ct = currentToken(); - - if (ct.type == TokenType::SVR_VOID) { - std::cerr << "Parser hatası: beklenmeyen dosya sonu\n"; - return nullptr; - } - - // --- Parantezli ifade: ( expr ) --- - // Önceliği sıfırlar — parantez içinde yeni bir ifade başlar. - if (ct.type == TokenType::LPAREN) { - nextToken(); // '(' tüket - ASTNode* expr = parseExpression(0); // Öncelik sıfırla - if (currentToken().type == TokenType::RPAREN) - nextToken(); // ')' tüket - return expr; - } - - // --- Unary prefix operatörler: +, -, !, ~, ++, -- --- - // PLUS ve MINUS burada UNARY olarak işlenir. - // Binary olarak işlenmesi LED tarafından yapılır. - // - // ÖNEMLİ: PLUS ve MINUS için getPowerOperator() 13 döndürür (binary öncelik). - // Ama burada unary olarak kullanılıyor. parseExpression(16) çağırmak daha - // doğru olurdu ancak mevcut çalışma şekli de doğru sonuç veriyor. - // TODO: Unary için ayrı öncelik seviyesi (örn: 16) - if (ct.is({ - TokenType::PLUS_PLUS, TokenType::MINUS_MINUS, - TokenType::PLUS, TokenType::MINUS, - TokenType::BANG, TokenType::TILDE - })) { - nextToken(); // Operatörü tüket - // Sağ operand'ı ayrıştır. Unary prefix sağdan sola bağlanır. - ASTNode* right = parseExpression(ct.getPowerOperator()); - BinaryExpressionNode* bin = new BinaryExpressionNode(); - bin->loc = ct.token ? ct.token->loc : SourceLocation{}; - bin->Right = right; - bin->Left = nullptr; // Unary işaretçisi - bin->Operator = ct.type; - if (right) right->parent = bin; - return bin; - } - - // --- Sayısal literal: 42, 0xFF, 3.14 --- - if (ct.type == TokenType::NUMBER) { - nextToken(); // Token'ı tüket - LiteralNode* lit = new LiteralNode(); - lit->loc = ct.token ? ct.token->loc : SourceLocation{}; - lit->lexerToken = ct.token; - lit->parserToken = ct; - // NumberToken'a cast edip base/isFloat bilgisini al - if (auto* nt = dynamic_cast(ct.token)) { - lit->literalBase = nt->base; - lit->isFloatValue = nt->isFloat; - lit->literalType = nt->isFloat ? LiteralType::FLOAT : LiteralType::INTEGER; - } - return lit; - } - - // --- String literal: "hello" --- - if (ct.type == TokenType::STRING) { - nextToken(); - LiteralNode* lit = new LiteralNode(); - lit->literalType = LiteralType::STRING; - lit->loc = ct.token ? ct.token->loc : SourceLocation{}; - lit->lexerToken = ct.token; - lit->parserToken = ct; - return lit; - } - - // --- Boolean/null literal: true, false, null --- - if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE, TokenType::KW_NULL})) { - nextToken(); - LiteralNode* lit = new LiteralNode(); - // Token içeriğine göre boolean/null ayrımı - if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE})) - lit->literalType = LiteralType::BOOLEAN; - else - lit->literalType = LiteralType::BOŞ; - lit->loc = ct.token ? ct.token->loc : SourceLocation{}; - lit->lexerToken = ct.token; - lit->parserToken = ct; - return lit; - } - - // --- Identifier: x, myVar --- - if (ct.type == TokenType::IDENTIFIER) { - nextToken(); - IdentifierNode* id = new IdentifierNode(); - id->loc = ct.token ? ct.token->loc : SourceLocation{}; - id->lexerToken = ct.token; - id->parserToken = ct; - return id; - } - - return nullptr; -} - -// -------------------------------------------------------------------------- -// parseLeftDenotation (LED): Infix ve Postfix ifadeler. -// -// Sol operand zaten ayrıştırılmış olarak gelir (left). -// Mevcut token operatördür. -// -// İşlenen tipler: -// - Postfix: expr++, expr-- -// - Binary infix: expr + expr, expr * expr, expr == expr, ... -// -// TASARIM NOTU: Postfix ve Binary aynı fonksiyonda işlenir çünkü ikisi de -// "sol operand + operatör" pattern'ini takip eder. Postfix'te sağ operand -// yoktur. -// -------------------------------------------------------------------------- -inline ASTNode* Parser::parseLeftDenotation(ASTNode* left) { - auto ct = currentToken(); - - // --- Postfix: expr++, expr-- --- - if (ct.is({TokenType::PLUS_PLUS, TokenType::MINUS_MINUS})) { - nextToken(); - PostfixNode* pf = new PostfixNode(); - pf->loc = ct.token ? ct.token->loc : SourceLocation{}; - pf->operand = left; - pf->Operator = ct.type; - left->parent = pf; - return pf; - } - - // --- Fonksiyon cagrisi: expr(args) --- - if (ct.type == TokenType::LPAREN) { - nextToken(); - CallExpressionNode* call = new CallExpressionNode(); - call->loc = ct.token ? ct.token->loc : SourceLocation{}; - call->callee = left; - left->parent = call; - - if (currentToken().type != TokenType::RPAREN) { - call->arguments.push_back(parseExpression(0)); - while (currentToken().type == TokenType::COMMA) { - nextToken(); - call->arguments.push_back(parseExpression(0)); - } - } - if (currentToken().type == TokenType::RPAREN) - nextToken(); - return call; - } - - // --- Dizi erisimi: expr[index] --- - if (ct.type == TokenType::LBRACKET) { - nextToken(); - IndexExpressionNode* idx = new IndexExpressionNode(); - idx->loc = ct.token ? ct.token->loc : SourceLocation{}; - idx->object = left; - left->parent = idx; - idx->index = parseExpression(0); - if (currentToken().type == TokenType::RBRACKET) - nextToken(); - return idx; - } - - // --- Uye erisimi: expr.member / expr->member --- - if (ct.type == TokenType::DOT || ct.type == TokenType::ARROW) { - bool arrow = (ct.type == TokenType::ARROW); - nextToken(); - - if (currentToken().type != TokenType::IDENTIFIER) { - std::cerr << "Parser hatasi: uye ismi bekleniyor\n"; - return left; - } - - MemberAccessNode* ma = new MemberAccessNode(); - ma->loc = ct.token ? ct.token->loc : SourceLocation{}; - ma->object = left; - ma->member = currentToken().token->token; - ma->arrow = arrow; - left->parent = ma; - nextToken(); - return ma; - } - - // --- Binary infix: expr OP expr --- - uint16_t prec = ct.getPowerOperator(); - nextToken(); - - ASTNode* right = parseExpression(prec); - - BinaryExpressionNode* bin = new BinaryExpressionNode(); - bin->loc = ct.token ? ct.token->loc : SourceLocation{}; - bin->Left = left; - bin->Right = right; - bin->Operator = ct.type; - if (left) left->parent = bin; - if (right) right->parent = bin; - return bin; -} - -#endif // SAQUT_PARSER \ No newline at end of file +#endif // SAQUT_PARSER diff --git a/src/parser/parser_base.hpp b/src/parser/parser_base.hpp new file mode 100644 index 0000000..838910f --- /dev/null +++ b/src/parser/parser_base.hpp @@ -0,0 +1,62 @@ +// ============================================================================ +// saQut Compiler — Parser Sınıf Tanımı +// ============================================================================ +// +// DİZİN: src/parser/parser_base.hpp +// İÇERİK: Parser sınıf tanımı + include'lar. Metot gövdeleri yok. +// +// ============================================================================ + +#ifndef SAQUT_PARSER_BASE +#define SAQUT_PARSER_BASE + +#include +#include +#include +#include "parser/token.hpp" +#include "parser/ast.hpp" +#include "tools.hpp" +class Parser { +public: + ASTNode* parse(TokenList tokens); + +private: + TokenList tokens; // Tokenizer'dan gelen token listesi + int current = 0; // Şu anki token indeksi + + // --- Token navigasyonu --- + ParserToken currentToken(); + void nextToken(); + ParserToken lookahead(uint32_t forward); + ParserToken parseToken(Token* token); + ParserToken getToken(int offset); + + // --- Üst seviye --- + ASTNode* parseProgram(); + + // --- Deklarasyonlar --- + ASTNode* parseDeclaration(); + ASTNode* parseFunctionDecl(); + ASTNode* parseStructDecl(); + ASTNode* parseVariableDecl(); + + // --- Statement'lar --- + ASTNode* parseStatement(); + ASTNode* parseBlock(); + ASTNode* parseIfStatement(); + ASTNode* parseWhileStatement(); + ASTNode* parseForStatement(); + ASTNode* parseDoWhileStatement(); + ASTNode* parseReturnStatement(); + ASTNode* parseBreakStatement(); + ASTNode* parseContinueStatement(); + ASTNode* parseExpressionStatement(); + + // --- İfadeler (Pratt parser) --- + ASTNode* parseExpression(); + ASTNode* parseExpression(uint16_t precedence); + ASTNode* parseNullDenotation(); + ASTNode* parseLeftDenotation(ASTNode* left); +}; + +#endif // SAQUT_PARSER_BASE diff --git a/src/parser/parser_core.hpp b/src/parser/parser_core.hpp new file mode 100644 index 0000000..f6e73ec --- /dev/null +++ b/src/parser/parser_core.hpp @@ -0,0 +1,409 @@ +// ============================================================================ +// saQut Compiler — Parser Çekirdek (Program + İfadeler) +// ============================================================================ +// +// DİZİN: src/parser/parser_core.hpp +// İÇERİK: Token navigasyonu, parse(), parseProgram(), +// parseDeclaration(), parseExpression() [Pratt] +// +// ============================================================================ + +#ifndef SAQUT_PARSER_CORE +#define SAQUT_PARSER_CORE + +#include +#include "parser/parser_base.hpp" +// -------------------------------------------------------------------------- +// parseToken: Ham Token'ı ParserToken'a dönüştür. +// +// Tokenizer'ın string tabanlı tip sistemini ("number", "operator", ...) +// Parser'ın anlamsal tip sistemine (NUMBER, PLUS, KW_IF, ...) çevirir. +// +// BUG FIX (commit 40579ca): pt.token = token (pointer ataması). +// Eskiden pt.token = *token (değer kopyası) object slicing yapıyordu. +// -------------------------------------------------------------------------- +inline ParserToken Parser::parseToken(Token* token) { + ParserToken pt; + pt.token = token; // Pointer — değer kopyası DEĞİL + + std::string t = token->gettype(); + if (t == "string") + pt.type = TokenType::STRING; + else if (t == "number") + pt.type = TokenType::NUMBER; + else if (t == "operator") + pt.type = OPERATOR_MAP.find(pt.token->token)->second; + else if (t == "delimiter") + pt.type = OPERATOR_MAP.find(pt.token->token)->second; + else if (t == "keyword") + pt.type = KEYWORD_MAP.find(pt.token->token)->second; + else if (t == "identifier") + pt.type = TokenType::IDENTIFIER; + + return pt; +} + +// -------------------------------------------------------------------------- +// getToken: Güvenli token erişimi. Sınır dışı = SVR_VOID. +// -------------------------------------------------------------------------- +inline ParserToken Parser::getToken(int offset) { + if ((int)tokens.size() - 1 < current + offset) { + ParserToken pt; + pt.type = TokenType::SVR_VOID; + return pt; + } + return parseToken(tokens[current + offset]); +} + +inline void Parser::nextToken() { + if ((int)tokens.size() >= current + 1) + current++; +} + +inline ParserToken Parser::lookahead(uint32_t forward) { + return getToken(forward); +} + +inline ParserToken Parser::currentToken() { + return getToken(0); +} + +// ============================================================================ +// Üst Seviye +// ============================================================================ + +// -------------------------------------------------------------------------- +// parse: Parser'ın ana giriş noktası. Token listesini alır, AST döndürür. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parse(TokenList toks) { + tokens = toks; + current = 0; + return parseProgram(); +} + +// -------------------------------------------------------------------------- +// parseProgram: Tüm üst seviye deklarasyonları/statement'ları ayrıştırır. +// +// Program ::= Declaration* +// EOF'a (SVR_VOID) kadar parseDeclaration() çağrılır. +// +// BUG FIX (commit 438bc0e): Eskiden parseExpression() doğrudan çağrılıyordu, +// bu sadece tek bir ifadeyi ayrıştırabiliyordu. Şimdi tam program desteği var. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseProgram() { + ProgramNode* program = new ProgramNode(); + + while (currentToken().type != TokenType::SVR_VOID) { + ASTNode* decl = parseDeclaration(); + if (decl) + program->addChild(decl); + else + break; // Hata durumunda döngüden çık + } + + return program; +} + +// ============================================================================ +// Deklarasyonlar +// ============================================================================ + +// -------------------------------------------------------------------------- +// parseDeclaration: Üst seviye deklarasyon ayrıştırıcı. +// +// Strateji: +// 1. Mevcut token bir tip keyword'ü mü (int, void, float, ...)? +// - Evet → lookahead(2) '(' ise → fonksiyon tanımı +// - Evet → değilse → değişken tanımı +// 2. Değilse → statement (REPL modunda ifade de olabilir) +// +// LOOKAHEAD KULLANIMI: +// "int main()" ve "int x = 10" ayrımı için 2 ileriye bakarız: +// - int main() → lookahead(1)=identifier, lookahead(2)='(' +// - int x = 10 → lookahead(1)=identifier, lookahead(2)='=' +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseDeclaration() { + auto ct = currentToken(); + + // Tip keyword'ü ile başlayan → fonksiyon veya değişken + if (ct.is({ + TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE, + TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR, + TokenType::KW_STRING_TYPE, TokenType::KW_AUTO + })) { + auto la1 = lookahead(1); + auto la2 = lookahead(2); + // int main( ... ) → fonksiyon + if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN) + return parseFunctionDecl(); + // int x ... → değişken + return parseVariableDecl(); + } + + // struct + if (ct.type == TokenType::KW_STRUCT) + return parseStructDecl(); + + // Tip keyword'ü değil → statement + return parseStatement(); +} + +// -------------------------------------------------------------------------- +// parseFunctionDecl: Fonksiyon tanımı. + +inline ASTNode* Parser::parseExpression() { + return parseExpression(0); +} + +// -------------------------------------------------------------------------- +// parseExpression(precedence): Pratt'ın ana döngüsü. +// +// Algoritma: +// 1. NUD ile ilk operand'ı ayrıştır (prefix) +// 2. Mevcut token bir operatör mü? +// - Evet ve önceliği > precedence ise → LED ile infix ayrıştır +// - Hayır veya öncelik <= precedence ise → dur, sol operand'ı döndür +// 3. LED'in döndürdüğü düğüm yeni sol operand olur, 2. adıma dön +// +// DURMA KOŞULLARI: +// - RPAREN, SEMICOLON, RBRACE, COMMA: İfade sonu sinyali +// - Operatörün önceliği <= mevcut öncelik: Daha sıkı bağlanamaz +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseExpression(uint16_t precedence) { + if (currentToken().type == TokenType::SVR_VOID) + return nullptr; + + // 1. Prefix (NUD) + ASTNode* left = parseNullDenotation(); + if (!left) return nullptr; + + // 2. Infix/Postfix döngüsü (LED) + while (true) { + auto next = currentToken(); + + // İfade sonu sinyalleri → dur + if (next.type == TokenType::RPAREN || + next.type == TokenType::SEMICOLON || + next.type == TokenType::RBRACE || + next.type == TokenType::COMMA) + break; + + // Operatörün bağlanma gücü yetersiz → dur + // (daha yüksek öncelikli bir bağlamdayız, bu operatör oraya ait değil) + if (precedence < next.getPowerOperator()) { + left = parseLeftDenotation(left); + } else { + break; + } + } + return left; +} + +// -------------------------------------------------------------------------- +// parseNullDenotation (NUD): Prefix ifadeleri. +// +// İşlenen prefix tipleri: +// - Parantez: ( expression ) +// - Unary: +expr, -expr, !expr, ~expr, ++expr, --expr +// - Literal: 42, "hello", true, false, null +// - Identifier: x, myVar +// +// DÖNÜŞ: Ayrıştırılmış AST düğümü. Token TÜKETİLMİŞ olur (current ilerlemiş). +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseNullDenotation() { + auto ct = currentToken(); + + if (ct.type == TokenType::SVR_VOID) { + std::cerr << "Parser hatası: beklenmeyen dosya sonu\n"; + return nullptr; + } + + // --- Parantezli ifade: ( expr ) --- + // Önceliği sıfırlar — parantez içinde yeni bir ifade başlar. + if (ct.type == TokenType::LPAREN) { + nextToken(); // '(' tüket + ASTNode* expr = parseExpression(0); // Öncelik sıfırla + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + return expr; + } + + // --- Unary prefix operatörler: +, -, !, ~, ++, -- --- + // PLUS ve MINUS burada UNARY olarak işlenir. + // Binary olarak işlenmesi LED tarafından yapılır. + // + // ÖNEMLİ: PLUS ve MINUS için getPowerOperator() 13 döndürür (binary öncelik). + // Ama burada unary olarak kullanılıyor. parseExpression(16) çağırmak daha + // doğru olurdu ancak mevcut çalışma şekli de doğru sonuç veriyor. + // TODO: Unary için ayrı öncelik seviyesi (örn: 16) + if (ct.is({ + TokenType::PLUS_PLUS, TokenType::MINUS_MINUS, + TokenType::PLUS, TokenType::MINUS, + TokenType::BANG, TokenType::TILDE + })) { + nextToken(); // Operatörü tüket + // Sağ operand'ı ayrıştır. Unary prefix sağdan sola bağlanır. + ASTNode* right = parseExpression(ct.getPowerOperator()); + BinaryExpressionNode* bin = new BinaryExpressionNode(); + bin->loc = ct.token ? ct.token->loc : SourceLocation{}; + bin->Right = right; + bin->Left = nullptr; // Unary işaretçisi + bin->Operator = ct.type; + if (right) right->parent = bin; + return bin; + } + + // --- Sayısal literal: 42, 0xFF, 3.14 --- + if (ct.type == TokenType::NUMBER) { + nextToken(); // Token'ı tüket + LiteralNode* lit = new LiteralNode(); + lit->loc = ct.token ? ct.token->loc : SourceLocation{}; + lit->lexerToken = ct.token; + lit->parserToken = ct; + // NumberToken'a cast edip base/isFloat bilgisini al + if (auto* nt = dynamic_cast(ct.token)) { + lit->literalBase = nt->base; + lit->isFloatValue = nt->isFloat; + lit->literalType = nt->isFloat ? LiteralType::FLOAT : LiteralType::INTEGER; + } + return lit; + } + + // --- String literal: "hello" --- + if (ct.type == TokenType::STRING) { + nextToken(); + LiteralNode* lit = new LiteralNode(); + lit->literalType = LiteralType::STRING; + lit->loc = ct.token ? ct.token->loc : SourceLocation{}; + lit->lexerToken = ct.token; + lit->parserToken = ct; + return lit; + } + + // --- Boolean/null literal: true, false, null --- + if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE, TokenType::KW_NULL})) { + nextToken(); + LiteralNode* lit = new LiteralNode(); + // Token içeriğine göre boolean/null ayrımı + if (ct.is({TokenType::KW_TRUE, TokenType::KW_FALSE})) + lit->literalType = LiteralType::BOOLEAN; + else + lit->literalType = LiteralType::BOŞ; + lit->loc = ct.token ? ct.token->loc : SourceLocation{}; + lit->lexerToken = ct.token; + lit->parserToken = ct; + return lit; + } + + // --- Identifier: x, myVar --- + if (ct.type == TokenType::IDENTIFIER) { + nextToken(); + IdentifierNode* id = new IdentifierNode(); + id->loc = ct.token ? ct.token->loc : SourceLocation{}; + id->lexerToken = ct.token; + id->parserToken = ct; + return id; + } + + return nullptr; +} + +// -------------------------------------------------------------------------- +// parseLeftDenotation (LED): Infix ve Postfix ifadeler. +// +// Sol operand zaten ayrıştırılmış olarak gelir (left). +// Mevcut token operatördür. +// +// İşlenen tipler: +// - Postfix: expr++, expr-- +// - Binary infix: expr + expr, expr * expr, expr == expr, ... +// +// TASARIM NOTU: Postfix ve Binary aynı fonksiyonda işlenir çünkü ikisi de +// "sol operand + operatör" pattern'ini takip eder. Postfix'te sağ operand +// yoktur. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseLeftDenotation(ASTNode* left) { + auto ct = currentToken(); + + // --- Postfix: expr++, expr-- --- + if (ct.is({TokenType::PLUS_PLUS, TokenType::MINUS_MINUS})) { + nextToken(); + PostfixNode* pf = new PostfixNode(); + pf->loc = ct.token ? ct.token->loc : SourceLocation{}; + pf->operand = left; + pf->Operator = ct.type; + left->parent = pf; + return pf; + } + + // --- Fonksiyon cagrisi: expr(args) --- + if (ct.type == TokenType::LPAREN) { + nextToken(); + CallExpressionNode* call = new CallExpressionNode(); + call->loc = ct.token ? ct.token->loc : SourceLocation{}; + call->callee = left; + left->parent = call; + + if (currentToken().type != TokenType::RPAREN) { + call->arguments.push_back(parseExpression(0)); + while (currentToken().type == TokenType::COMMA) { + nextToken(); + call->arguments.push_back(parseExpression(0)); + } + } + if (currentToken().type == TokenType::RPAREN) + nextToken(); + return call; + } + + // --- Dizi erisimi: expr[index] --- + if (ct.type == TokenType::LBRACKET) { + nextToken(); + IndexExpressionNode* idx = new IndexExpressionNode(); + idx->loc = ct.token ? ct.token->loc : SourceLocation{}; + idx->object = left; + left->parent = idx; + idx->index = parseExpression(0); + if (currentToken().type == TokenType::RBRACKET) + nextToken(); + return idx; + } + + // --- Uye erisimi: expr.member / expr->member --- + if (ct.type == TokenType::DOT || ct.type == TokenType::ARROW) { + bool arrow = (ct.type == TokenType::ARROW); + nextToken(); + + if (currentToken().type != TokenType::IDENTIFIER) { + std::cerr << "Parser hatasi: uye ismi bekleniyor\n"; + return left; + } + + MemberAccessNode* ma = new MemberAccessNode(); + ma->loc = ct.token ? ct.token->loc : SourceLocation{}; + ma->object = left; + ma->member = currentToken().token->token; + ma->arrow = arrow; + left->parent = ma; + nextToken(); + return ma; + } + + // --- Binary infix: expr OP expr --- + uint16_t prec = ct.getPowerOperator(); + nextToken(); + + ASTNode* right = parseExpression(prec); + + BinaryExpressionNode* bin = new BinaryExpressionNode(); + bin->loc = ct.token ? ct.token->loc : SourceLocation{}; + bin->Left = left; + bin->Right = right; + bin->Operator = ct.type; + if (left) left->parent = bin; + if (right) right->parent = bin; + return bin; +} + + +#endif // SAQUT_PARSER_CORE diff --git a/src/parser/parser_decl.hpp b/src/parser/parser_decl.hpp new file mode 100644 index 0000000..071da47 --- /dev/null +++ b/src/parser/parser_decl.hpp @@ -0,0 +1,159 @@ +// ============================================================================ +// saQut Compiler — Parser Deklarasyonlar +// ============================================================================ +// +// DİZİN: src/parser/parser_decl.hpp +// İÇERİK: parseFunctionDecl(), parseStructDecl(), parseVariableDecl() +// +// ============================================================================ + +#ifndef SAQUT_PARSER_DECL +#define SAQUT_PARSER_DECL + +#include +#include "parser/parser_base.hpp" +inline ASTNode* Parser::parseFunctionDecl() { + FunctionDeclNode* fn = new FunctionDeclNode(); + fn->loc = currentToken().token->loc; + fn->returnType = currentToken().token->token; // "int", "void", ... + nextToken(); // Dönüş tipini tüket + + fn->name = currentToken().token->token; // "main", "calculate", ... + nextToken(); // İsmi tüket + + // Parametre listesi: ( ... ) + if (currentToken().type == TokenType::LPAREN) { + nextToken(); // '(' tüket + // TODO: Parametreleri ayrıştır + // Şimdilik ')' gelene kadar atla + while (currentToken().type != TokenType::RPAREN && + currentToken().type != TokenType::SVR_VOID) + nextToken(); + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + } + + // Gövde: { ... } + if (currentToken().type == TokenType::LBRACE) { + ASTNode* body = parseBlock(); + fn->addChild(body); + } + + return fn; +} +// -------------------------------------------------------------------------- +// parseStructDecl: struct tanimi. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseStructDecl() { + StructDeclNode* st = new StructDeclNode(); + st->loc = currentToken().token->loc; + nextToken(); + if (currentToken().type == TokenType::IDENTIFIER) { + st->name = currentToken().token->token; + nextToken(); + } + if (currentToken().type == TokenType::LBRACE) { + nextToken(); + while (currentToken().type != TokenType::RBRACE && currentToken().type != TokenType::SVR_VOID) { + ASTNode* field = parseDeclaration(); + if (field) st->addChild(field); + else break; + } + if (currentToken().type == TokenType::RBRACE) nextToken(); + } + if (currentToken().type == TokenType::SEMICOLON) nextToken(); + return st; +} + + +// -------------------------------------------------------------------------- +// parseVariableDecl: Değişken tanımı. +// +// Sözdizimi: Type Identifier [= Expression] {, Identifier [= Expression]} ; +// Örnek: int x = 10; +// float y; (initExpr = nullptr) +// int first = 0, second = 1, next; +// +// Çoklu değişken: +// İlk değişken ana düğüm olur. Virgülle ayrılmış ek değişkenler +// ana düğümün children vektörüne eklenir. JSON çıktısında "declarators" +// dizisi olarak görünür. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseVariableDecl() { + // --- Tip ve ilk değişken adı --- + VariableDeclNode* vd = new VariableDeclNode(); + vd->loc = currentToken().token->loc; + vd->varType = currentToken().token->token; // "int", "float", ... + nextToken(); // Tipi tüket + + if (currentToken().type != TokenType::IDENTIFIER) { + std::cerr << "Parser hatası: değişken ismi bekleniyor\n"; + return vd; + } + + vd->name = currentToken().token->token; + nextToken(); // İsmi tüket + + // Opsiyonel array boyutu: [expr] + if (currentToken().type == TokenType::LBRACKET) { + nextToken(); // '[' + while (currentToken().type != TokenType::RBRACKET && + currentToken().type != TokenType::SEMICOLON && + currentToken().type != TokenType::SVR_VOID) + nextToken(); + if (currentToken().type == TokenType::RBRACKET) + nextToken(); // ']' + } + + // İlk değişkenin başlangıç değeri + if (currentToken().type == TokenType::EQUAL) { + nextToken(); // '=' tüket + vd->initExpr = parseExpression(); + } + + // --- Çoklu değişken: , identifier [= expr] --- + while (currentToken().type == TokenType::COMMA) { + nextToken(); // ',' tüket + + if (currentToken().type != TokenType::IDENTIFIER) { + std::cerr << "Parser hatası: virgülden sonra değişken ismi bekleniyor\n"; + break; + } + + VariableDeclNode* sibling = new VariableDeclNode(); + sibling->loc = currentToken().token->loc; + sibling->varType = vd->varType; // Aynı tip + sibling->name = currentToken().token->token; + nextToken(); // İsmi tüket + + // Opsiyonel array boyutu: [expr] + if (currentToken().type == TokenType::LBRACKET) { + nextToken(); // '[' + while (currentToken().type != TokenType::RBRACKET && + currentToken().type != TokenType::SEMICOLON && + currentToken().type != TokenType::SVR_VOID) + nextToken(); + if (currentToken().type == TokenType::RBRACKET) + nextToken(); // ']' + } + + // Başlangıç değeri + if (currentToken().type == TokenType::EQUAL) { + nextToken(); // '=' tüket + sibling->initExpr = parseExpression(); + } + + // Kardeş düğümü ana düğüme ekle + vd->addChild(sibling); + } + + // Noktalı virgül (opsiyonel — parser hoşgörülü) + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + + return vd; +} + +// ============================================================================ + +#endif // SAQUT_PARSER_DECL diff --git a/src/parser/parser_stmt.hpp b/src/parser/parser_stmt.hpp new file mode 100644 index 0000000..b37e142 --- /dev/null +++ b/src/parser/parser_stmt.hpp @@ -0,0 +1,322 @@ +// ============================================================================ +// saQut Compiler — Parser Deyimler +// ============================================================================ +// +// DİZİN: src/parser/parser_stmt.hpp +// İÇERİK: parseStatement(), parseBlock(), parseIf/While/For/DoWhile, +// parseReturn/Break/Continue/ExpressionStatement +// +// ============================================================================ + +#ifndef SAQUT_PARSER_STMT +#define SAQUT_PARSER_STMT + +#include +#include "parser/parser_base.hpp" +inline ASTNode* Parser::parseStatement() { + auto ct = currentToken(); + + if (ct.type == TokenType::LBRACE) + return parseBlock(); + + if (ct.type == TokenType::KW_IF) + return parseIfStatement(); + + if (ct.type == TokenType::KW_WHILE) + return parseWhileStatement(); + + if (ct.type == TokenType::KW_FOR) + return parseForStatement(); + + if (ct.type == TokenType::KW_DO) + return parseDoWhileStatement(); + + if (ct.type == TokenType::KW_RETURN) + return parseReturnStatement(); + + if (ct.type == TokenType::KW_BREAK) + return parseBreakStatement(); + + if (ct.type == TokenType::KW_CONTINUE) + return parseContinueStatement(); + + // Değişken tanımı? (tip keyword'ü ile başlayan) + if (ct.is({ + TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE, + TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR, + TokenType::KW_STRING_TYPE + })) { + return parseVariableDecl(); + } + + // struct tanımı: struct Name { ... } + if (ct.type == TokenType::KW_STRUCT) + return parseStructDecl(); + + // Hiçbiri değilse → ifade statement'ı (atama, fonksiyon çağrısı, ...) + return parseExpressionStatement(); +} + +// -------------------------------------------------------------------------- +// parseBlock: { statement* } +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseBlock() { + BlockNode* block = new BlockNode(); + block->loc = currentToken().token ? currentToken().token->loc : SourceLocation{}; + + if (currentToken().type == TokenType::LBRACE) + nextToken(); // '{' tüket + + while (currentToken().type != TokenType::RBRACE && + currentToken().type != TokenType::SVR_VOID) { + ASTNode* stmt = parseStatement(); + if (stmt) + block->addChild(stmt); + else + break; // Hata durumunda döngüden çık + } + + if (currentToken().type == TokenType::RBRACE) + nextToken(); // '}' tüket + + return block; +} + +// -------------------------------------------------------------------------- +// parseIfStatement: if (expression) statement [else statement] +// +// Süslü parantez zorunlu DEĞİL — tek statement de olabilir. +// if (x > 5) return x; ← geçerli +// if (x > 5) { ... } ← geçerli +// +// TODO: Sallantılı else (dangling else) sorunu: +// if (a) if (b) x; else y; ← else hangi if'e ait? +// Mevcut implementasyon doğru: else en yakın if'e bağlanır. +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseIfStatement() { + IfStatementNode* ifNode = new IfStatementNode(); + ifNode->loc = currentToken().token->loc; + nextToken(); // 'if' tüket + + // Koşul: ( expression ) + if (currentToken().type == TokenType::LPAREN) { + nextToken(); // '(' tüket + ifNode->condition = parseExpression(); + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + } + + // Then gövdesi + ifNode->thenBranch = parseStatement(); + + // Opsiyonel else + if (currentToken().type == TokenType::KW_ELSE) { + nextToken(); // 'else' tüket + ifNode->elseBranch = parseStatement(); + } + + return ifNode; +} + +// -------------------------------------------------------------------------- +// parseWhileStatement: while (expression) statement +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseWhileStatement() { + WhileStatementNode* ws = new WhileStatementNode(); + ws->loc = currentToken().token->loc; + nextToken(); // 'while' tüket + + if (currentToken().type == TokenType::LPAREN) { + nextToken(); // '(' tüket + ws->condition = parseExpression(); + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + } + + ws->body = parseStatement(); + return ws; +} + +// -------------------------------------------------------------------------- +// parseForStatement: for (init; condition; update) statement +// +// for'un 3 parçası da isteğe bağlıdır: +// for (;;) { ... } ← sonsuz döngü (geçerli) +// +// init: VariableDeclNode veya ExpressionStatementNode +// for (int i = 0; ...) → VariableDecl +// for (i = 0; ...) → ExpressionStatement +// condition: ifade (nullptr = yok) +// update: ifade (nullptr = yok) +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseForStatement() { + ForStatementNode* fs = new ForStatementNode(); + fs->loc = currentToken().token->loc; + nextToken(); // 'for' tüket + + if (currentToken().type == TokenType::LPAREN) + nextToken(); // '(' tüket + + // Init (opsiyonel) + if (currentToken().type != TokenType::SEMICOLON) + fs->init = parseStatement(); + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); // ';' tüket + + // Condition (opsiyonel) + if (currentToken().type != TokenType::SEMICOLON) + fs->condition = parseExpression(); + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); // ';' tüket + + // Update (opsiyonel) + if (currentToken().type != TokenType::RPAREN) + fs->update = parseExpression(); + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + + // Body + fs->body = parseStatement(); + + return fs; +} + +// -------------------------------------------------------------------------- +// parseDoWhileStatement: do statement while (expression) ; +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseDoWhileStatement() { + DoWhileStatementNode* dw = new DoWhileStatementNode(); + dw->loc = currentToken().token->loc; + nextToken(); // 'do' tüket + + // Gövde + dw->body = parseStatement(); + + // while (expression) ; + if (currentToken().type == TokenType::KW_WHILE) { + nextToken(); // 'while' tüket + if (currentToken().type == TokenType::LPAREN) { + nextToken(); // '(' tüket + dw->condition = parseExpression(); + if (currentToken().type == TokenType::RPAREN) + nextToken(); // ')' tüket + } + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); // ';' tüket + } + + return dw; +} + +// -------------------------------------------------------------------------- +// parseReturnStatement: return [expression] ; +// +// return; ← value = nullptr (void fonksiyon) +// return x + 1; ← value = BinaryExpression +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseReturnStatement() { + ReturnStatementNode* rs = new ReturnStatementNode(); + rs->loc = currentToken().token->loc; + nextToken(); // 'return' tüket + + // Opsiyonel dönüş değeri + // Eğer sıradaki token ; veya } ise → return; + if (currentToken().type != TokenType::SEMICOLON && + currentToken().type != TokenType::RBRACE) { + rs->value = parseExpression(); + } + + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); // ';' tüket + + return rs; +} + +// -------------------------------------------------------------------------- +// parseBreakStatement / parseContinueStatement +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseBreakStatement() { + BreakStatementNode* bs = new BreakStatementNode(); + bs->loc = currentToken().token->loc; + nextToken(); // 'break' tüket + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + return bs; +} + +inline ASTNode* Parser::parseContinueStatement() { + ContinueStatementNode* cs = new ContinueStatementNode(); + cs->loc = currentToken().token->loc; + nextToken(); // 'continue' tüket + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + return cs; +} + +// -------------------------------------------------------------------------- +// parseExpressionStatement: expression ; +// +// Bir ifadeyi statement olarak kullanır. Örn: x = 5; foo(); +// +// HATA KURTARMA: +// Eğer parseExpression() başarısız olursa (nullptr), sonraki ; veya } +// veya EOF'a kadar token'ları atlayarak senkronize olur. Bu, tek bir +// hatalı ifadenin tüm parser'ı kilitlemesini önler. +// +// BUG FIX (commit 438bc0e): Eskiden hatalı ifade durumunda sonsuz +// döngüye giriyordu (parseProgram her seferinde aynı ifadeyi okuyordu). +// -------------------------------------------------------------------------- +inline ASTNode* Parser::parseExpressionStatement() { + ExpressionStatementNode* es = new ExpressionStatementNode(); + es->loc = currentToken().token ? currentToken().token->loc : SourceLocation{}; + es->expression = parseExpression(); + if (!es->expression) { + // Hata kurtarma: sonraki güvenli noktaya atla + while (currentToken().type != TokenType::SEMICOLON && + currentToken().type != TokenType::RBRACE && + currentToken().type != TokenType::SVR_VOID) + nextToken(); + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + } + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + + return es; +} + +// ============================================================================ +// İfadeler — Pratt Parser (Top-Down Operator Precedence) +// ============================================================================ +// +// Pratt parser'ın temel fikri: Her operatörün bir "bağlanma gücü" (precedence) +// vardır. Parser, bu güce göre operatörleri doğru sırada gruplar. +// +// NUD (Null Denotation): Prefix ifadeleri (sayılar, -, !, parantez) +// LED (Left Denotation): Infix/Postfix ifadeler (+, *, ++) +// +// ÖRNEK: 1 + 2 * 3 +// 1. NUD: 1 → Literal(1) +// 2. LED(+): prec=13, right'i parseExpression(13) ile ayrıştır +// 2a. NUD: 2 → Literal(2) +// 2b. LED(*): prec=14 > 13 → parseExpression(14) +// 3a. NUD: 3 → Literal(3) +// 3b. LED yok → dön +// 2c. BinaryExpr(*, 2, 3) dön +// 3. BinaryExpr(+, 1, BinaryExpr(*, 2, 3)) +// Sonuç: 1 + (2 * 3) ✓ +// +// BUG FIX (commit 40579ca): Ana döngü lookahead(1) yerine currentToken() +// kullanıyor. NUD artık token'ı tüketip ilerliyor, bu sayede currentToken() +// her zaman bir sonraki operatörü gösterir. +// +// BUG FIX (commit 438bc0e): Atom'lar (sayı, string, identifier) NUD'da +// nextToken() ile tüketiliyor. Eskiden tüketilmediği için sonsuz döngü +// oluyordu. +// +// ============================================================================ + +// -------------------------------------------------------------------------- +// parseExpression(): Öncelik 0'dan başla (en düşük bağlanma) + +#endif // SAQUT_PARSER_STMT -- 2.25.1