Merge pull request 'refactor: modularize parser and AST components' (#68) from feature/parser-modularization into master

Reviewed-on: #68
This commit is contained in:
saqut 2026-05-27 09:42:42 +03:00
commit aa6400c098
12 changed files with 2033 additions and 1847 deletions

30
prcontext.md Normal file
View File

@ -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.

View File

@ -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 // DİZİN: src/parser/ast.hpp
// KATMAN: Katman 3 — Parser'ın ürettiği, IR'nin tükettiği // 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Ç: // Bu dosya bir AGGREGATOR'dür. Tüm AST düğüm sınıflarını tek bir include
// Kaynak kodun hiyerarşik, anlamsal gösterimi. Her dil yapısı (ifade, // ile kullanılabilir yapar.
// deyim, fonksiyon) bir AST düğümü ile temsil edilir.
// //
// AST DÜĞÜM HİYERARŞİSİ: // AST DÜĞÜM HİYERARŞİSİ:
// ASTNode (soyut taban) // ASTNode (soyut taban) — ast_node.hpp
// ├── ProgramNode : Kök düğüm, tüm üst seviye deklarasyonları tutar // ├── ProgramNode : Kök düğüm — ast_decl.hpp
// ├── FunctionDeclNode : Fonksiyon tanımı (int main() { ... }) // ├── FunctionDeclNode : Fonksiyon tanımı — ast_decl.hpp
// ├── BlockNode : { ... } bloğu, statement listesi // ├── StructDeclNode : struct tanımı — ast_decl.hpp
// ├── VariableDeclNode : Değişken tanımı (int x = 10;) // ├── VariableDeclNode : Değişken tanımı — ast_decl.hpp
// ├── IfStatementNode : if/else // ├── BlockNode : { ... } bloğu — ast_stmt.hpp
// ├── WhileStatementNode : while döngüsü // ├── IfStatementNode : if/else — ast_stmt.hpp
// ├── ForStatementNode : for döngüsü // ├── WhileStatementNode : while — ast_stmt.hpp
// ├── DoWhileStatementNode : do-while döngüsü // ├── ForStatementNode : for — ast_stmt.hpp
// ├── ReturnStatementNode : return [ifade] // ├── DoWhileStatementNode : do-while — ast_stmt.hpp
// ├── BreakStatementNode : break // ├── ReturnStatementNode : return — ast_stmt.hpp
// ├── ContinueStatementNode : continue // ├── BreakStatementNode : break — ast_stmt.hpp
// ├── ExpressionStatementNode: ifade + ; (bir statement olarak) // ├── ContinueStatementNode : continue — ast_stmt.hpp
// ├── BinaryExpressionNode : İkili işlem (a + b, a * b) // ├── ExpressionStatementNode: expression; — ast_stmt.hpp
// ├── LiteralNode : Sabit değer (42, "hello", true) // ├── BinaryExpressionNode : a + b — ast_expr.hpp
// ├── IdentifierNode : Değişken/fonksiyon ismi // ├── LiteralNode : 42, "hello" — ast_expr.hpp
// └── PostfixNode : Son ek işlem (a++, a--) // ├── IdentifierNode : değişken ismi — ast_expr.hpp
// // ├── PostfixNode : a++ — ast_expr.hpp
// TASARIM KARARLARI: // ├── CallExpressionNode : f(x) — ast_expr.hpp
// 1. ASTKind enum + log() + toJson(): Her düğüm kendi tipini bilir, // ├── MemberAccessNode : a.b — ast_expr.hpp
// kendini konsola yazdırabilir ve JSON olarak serileştirebilir. // └── IndexExpressionNode : a[i] — ast_expr.hpp
// 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
// //
// ============================================================================ // ============================================================================
#ifndef SAQUT_AST #ifndef SAQUT_AST
#define SAQUT_AST #define SAQUT_AST
#include <iostream> #include "parser/ast_node.hpp"
#include <sstream> #include "parser/ast_json.hpp"
#include <vector> #include "parser/ast_expr.hpp"
#include "core/location.hpp" #include "parser/ast_stmt.hpp"
#include "parser/token.hpp" #include "parser/ast_decl.hpp"
#include "tools.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 << "<Unknown>\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<ASTNode*>& getChildren() { return children; }
virtual ~ASTNode() = default;
protected:
std::vector<ASTNode*> 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<ASTNode*> 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 #endif // SAQUT_AST

143
src/parser/ast_decl.hpp Normal file
View File

@ -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 <iostream>
#include <sstream>
#include <string>
#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

287
src/parser/ast_expr.hpp Normal file
View File

@ -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 <iostream>
#include <sstream>
#include <string>
#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<ASTNode*> 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

134
src/parser/ast_json.hpp Normal file
View File

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

134
src/parser/ast_node.hpp Normal file
View File

@ -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 <iostream>
#include <sstream>
#include <string>
#include <vector>
#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 << "<Unknown>\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<ASTNode*>& getChildren() { return children; }
virtual ~ASTNode() = default;
protected:
std::vector<ASTNode*> 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

307
src/parser/ast_stmt.hpp Normal file
View File

@ -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 <iostream>
#include <sstream>
#include <string>
#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

File diff suppressed because it is too large Load Diff

View File

@ -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 <iostream>
#include <cstdint>
#include <string>
#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

409
src/parser/parser_core.hpp Normal file
View File

@ -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 <iostream>
#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<NumberToken*>(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

159
src/parser/parser_decl.hpp Normal file
View File

@ -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 <iostream>
#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

322
src/parser/parser_stmt.hpp Normal file
View File

@ -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 <iostream>
#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