refactor: modularize parser and AST components #68
|
|
@ -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.
|
||||
|
|
@ -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 <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#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 << "<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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue