refactor: modularize parser and AST components
This commit is contained in:
parent
c354d0b434
commit
ee1e5213cf
|
|
@ -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
|
// DİZİN: src/parser/ast.hpp
|
||||||
// KATMAN: Katman 3 — Parser'ın ürettiği, IR'nin tükettiği
|
// KATMAN: Katman 3 — Parser'ın ürettiği, IR'nin tükettiği
|
||||||
// BAĞIMLI: Token (src/parser/token.hpp), Tools (src/tools.hpp)
|
|
||||||
// KULLANAN: Parser (src/parser/parser.hpp), IR (src/ir/ir.hpp), JSON (src/json.hpp)
|
|
||||||
//
|
//
|
||||||
// AMAÇ:
|
// Bu dosya bir AGGREGATOR'dür. Tüm AST düğüm sınıflarını tek bir include
|
||||||
// Kaynak kodun hiyerarşik, anlamsal gösterimi. Her dil yapısı (ifade,
|
// ile kullanılabilir yapar.
|
||||||
// deyim, fonksiyon) bir AST düğümü ile temsil edilir.
|
|
||||||
//
|
//
|
||||||
// AST DÜĞÜM HİYERARŞİSİ:
|
// AST DÜĞÜM HİYERARŞİSİ:
|
||||||
// ASTNode (soyut taban)
|
// ASTNode (soyut taban) — ast_node.hpp
|
||||||
// ├── ProgramNode : Kök düğüm, tüm üst seviye deklarasyonları tutar
|
// ├── ProgramNode : Kök düğüm — ast_decl.hpp
|
||||||
// ├── FunctionDeclNode : Fonksiyon tanımı (int main() { ... })
|
// ├── FunctionDeclNode : Fonksiyon tanımı — ast_decl.hpp
|
||||||
// ├── BlockNode : { ... } bloğu, statement listesi
|
// ├── StructDeclNode : struct tanımı — ast_decl.hpp
|
||||||
// ├── VariableDeclNode : Değişken tanımı (int x = 10;)
|
// ├── VariableDeclNode : Değişken tanımı — ast_decl.hpp
|
||||||
// ├── IfStatementNode : if/else
|
// ├── BlockNode : { ... } bloğu — ast_stmt.hpp
|
||||||
// ├── WhileStatementNode : while döngüsü
|
// ├── IfStatementNode : if/else — ast_stmt.hpp
|
||||||
// ├── ForStatementNode : for döngüsü
|
// ├── WhileStatementNode : while — ast_stmt.hpp
|
||||||
// ├── DoWhileStatementNode : do-while döngüsü
|
// ├── ForStatementNode : for — ast_stmt.hpp
|
||||||
// ├── ReturnStatementNode : return [ifade]
|
// ├── DoWhileStatementNode : do-while — ast_stmt.hpp
|
||||||
// ├── BreakStatementNode : break
|
// ├── ReturnStatementNode : return — ast_stmt.hpp
|
||||||
// ├── ContinueStatementNode : continue
|
// ├── BreakStatementNode : break — ast_stmt.hpp
|
||||||
// ├── ExpressionStatementNode: ifade + ; (bir statement olarak)
|
// ├── ContinueStatementNode : continue — ast_stmt.hpp
|
||||||
// ├── BinaryExpressionNode : İkili işlem (a + b, a * b)
|
// ├── ExpressionStatementNode: expression; — ast_stmt.hpp
|
||||||
// ├── LiteralNode : Sabit değer (42, "hello", true)
|
// ├── BinaryExpressionNode : a + b — ast_expr.hpp
|
||||||
// ├── IdentifierNode : Değişken/fonksiyon ismi
|
// ├── LiteralNode : 42, "hello" — ast_expr.hpp
|
||||||
// └── PostfixNode : Son ek işlem (a++, a--)
|
// ├── IdentifierNode : değişken ismi — ast_expr.hpp
|
||||||
//
|
// ├── PostfixNode : a++ — ast_expr.hpp
|
||||||
// TASARIM KARARLARI:
|
// ├── CallExpressionNode : f(x) — ast_expr.hpp
|
||||||
// 1. ASTKind enum + log() + toJson(): Her düğüm kendi tipini bilir,
|
// ├── MemberAccessNode : a.b — ast_expr.hpp
|
||||||
// kendini konsola yazdırabilir ve JSON olarak serileştirebilir.
|
// └── IndexExpressionNode : a[i] — ast_expr.hpp
|
||||||
// Yeni bir düğüm eklendiğinde tüm davranışlar tek yerde tanımlanır.
|
|
||||||
//
|
|
||||||
// 2. parent pointer: Her düğüm ebeveynini bilir.
|
|
||||||
//
|
|
||||||
// 3. children vektörü (protected): Liste tipi düğümler için.
|
|
||||||
//
|
|
||||||
// BİLİNEN SINIRLAMALAR (TODO):
|
|
||||||
// TODO: Bellek yönetimi (unique_ptr veya arena allocator)
|
|
||||||
// TODO: Visitor pattern ile log/toJson/IR üretimi ayrıştırılabilir
|
|
||||||
//
|
//
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#ifndef SAQUT_AST
|
#ifndef SAQUT_AST
|
||||||
#define SAQUT_AST
|
#define SAQUT_AST
|
||||||
|
|
||||||
#include <iostream>
|
#include "parser/ast_node.hpp"
|
||||||
#include <sstream>
|
#include "parser/ast_json.hpp"
|
||||||
#include <vector>
|
#include "parser/ast_expr.hpp"
|
||||||
#include "core/location.hpp"
|
#include "parser/ast_stmt.hpp"
|
||||||
#include "parser/token.hpp"
|
#include "parser/ast_decl.hpp"
|
||||||
#include "tools.hpp"
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ASTKind — AST Düğüm Tipi Enum'u
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
enum class ASTKind {
|
|
||||||
Program, // Kök düğüm
|
|
||||||
FunctionDecl, // Fonksiyon tanımı
|
|
||||||
Block, // { } bloğu
|
|
||||||
VariableDecl, // Değişken tanımı
|
|
||||||
BinaryExpression, // İkili işlem (a + b)
|
|
||||||
UnaryExpression, // Tekli işlem (-a, !a) — ileride kullanılacak
|
|
||||||
Literal, // Sabit değer
|
|
||||||
Identifier, // İsim referansı
|
|
||||||
Postfix, // Son ek (a++)
|
|
||||||
IfStatement, // if/else
|
|
||||||
ForStatement, // for
|
|
||||||
WhileStatement, // while
|
|
||||||
DoWhileStatement, // do-while
|
|
||||||
ReturnStatement, // return
|
|
||||||
BreakStatement, // break
|
|
||||||
ContinueStatement, // continue
|
|
||||||
ExpressionStatement, // ifade + ;
|
|
||||||
Call, // Fonksiyon çağrısı f(args)
|
|
||||||
MemberAccess, // Üye erişimi a.b, a->b
|
|
||||||
IndexExpression, // Dizi erişimi a[i]
|
|
||||||
StructDecl, // struct tanımı
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ASTNode — Soyut Temel Sınıf
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ASTNode {
|
|
||||||
public:
|
|
||||||
ASTKind kind;
|
|
||||||
ASTNode* parent = nullptr;
|
|
||||||
SourceLocation loc; // Bu düğümün kaynak koddaki konumu
|
|
||||||
|
|
||||||
virtual void log(int indent = 0) {
|
|
||||||
(void)indent;
|
|
||||||
std::cout << "<Unknown>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON serileştirme — her alt sınıf kendi implemente eder
|
|
||||||
virtual std::string toJson(int indent = 0) {
|
|
||||||
(void)indent;
|
|
||||||
return "{\"kind\":\"Unknown\"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
void addChild(ASTNode* child) {
|
|
||||||
children.push_back(child);
|
|
||||||
child->parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ASTNode*>& getChildren() { return children; }
|
|
||||||
virtual ~ASTNode() = default;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector<ASTNode*> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// JSON yardımcısı: alt düğüm listesini JSON array olarak yaz
|
|
||||||
// ============================================================================
|
|
||||||
inline std::string childrenToJson(ASTNode* node, int depth) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
auto& ch = node->getChildren();
|
|
||||||
for (size_t i = 0; i < ch.size(); i++) {
|
|
||||||
ss << ch[i]->toJson(depth);
|
|
||||||
if (i + 1 < ch.size()) ss << ",";
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ProgramNode — Kök Düğüm
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ProgramNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ProgramNode() { kind = ASTKind::Program; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "Program\n";
|
|
||||||
for (auto* c : getChildren()) c->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Program\",\n"
|
|
||||||
<< in << " \"children\": [\n"
|
|
||||||
<< childrenToJson(this, depth + 3)
|
|
||||||
<< in << " ]\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// FunctionDeclNode — Fonksiyon Tanımı
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class FunctionDeclNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
std::string returnType;
|
|
||||||
|
|
||||||
FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent)
|
|
||||||
<< "FunctionDecl " << returnType << " " << name << "()\n";
|
|
||||||
for (auto* c : getChildren()) c->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"FunctionDecl\",\n"
|
|
||||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
|
||||||
<< in << " \"returnType\": \"" << jsonEscape(returnType) << "\",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << ",\n"
|
|
||||||
<< in << " \"children\": [\n"
|
|
||||||
<< childrenToJson(this, depth + 3)
|
|
||||||
<< in << " ]\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// BlockNode — Blok { ... }
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class BlockNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
BlockNode() { kind = ASTKind::Block; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "Block\n";
|
|
||||||
for (auto* c : getChildren()) c->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Block\",\n"
|
|
||||||
<< in << " \"children\": [\n"
|
|
||||||
<< childrenToJson(this, depth + 3)
|
|
||||||
<< in << " ]\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// VariableDeclNode — Değişken Tanımı
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class VariableDeclNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
std::string varType;
|
|
||||||
std::string name;
|
|
||||||
ASTNode* initExpr = nullptr;
|
|
||||||
|
|
||||||
VariableDeclNode() { kind = ASTKind::VariableDecl; }
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"VariableDecl\",\n"
|
|
||||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
|
||||||
<< in << " \"varType\": \"" << jsonEscape(varType) << "\",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << "";
|
|
||||||
if (initExpr) {
|
|
||||||
ss << ",\n" << in << " \"initExpr\":\n"
|
|
||||||
<< initExpr->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
// Çoklu değişken bildirimindeki kardeşler (int a, b, c;)
|
|
||||||
if (!getChildren().empty()) {
|
|
||||||
ss << ",\n" << in << " \"declarators\": [\n";
|
|
||||||
for (size_t i = 0; i < getChildren().size(); i++) {
|
|
||||||
ss << ((VariableDeclNode*)getChildren()[i])->toJson(depth + 2);
|
|
||||||
if (i + 1 < getChildren().size()) ss << ",";
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
ss << in << " ]";
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent)
|
|
||||||
<< "VariableDecl " << varType << " " << name;
|
|
||||||
if (initExpr) {
|
|
||||||
std::cout << " =\n";
|
|
||||||
initExpr->log(indent + 4);
|
|
||||||
} else {
|
|
||||||
std::cout << "\n";
|
|
||||||
}
|
|
||||||
// Kardeş değişkenleri de logla
|
|
||||||
for (auto* child : getChildren()) {
|
|
||||||
child->log(indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// BinaryExpressionNode — İkili İşlem (a OP b)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class BinaryExpressionNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
TokenType Operator;
|
|
||||||
ASTNode* Left = nullptr;
|
|
||||||
ASTNode* Right = nullptr;
|
|
||||||
|
|
||||||
BinaryExpressionNode() { kind = ASTKind::BinaryExpression; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
auto it = OPERATOR_MAP_STRREV.find(Operator);
|
|
||||||
std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?";
|
|
||||||
std::string val;
|
|
||||||
auto it2 = OPERATOR_MAP_REV.find(Operator);
|
|
||||||
if (it2 != OPERATOR_MAP_REV.end()) val = std::string(it2->second);
|
|
||||||
|
|
||||||
std::cout << padRight("", indent) << "BinaryExpr " << sym
|
|
||||||
<< " (" << val << ")\n";
|
|
||||||
if (Right) Right->log(indent + 2);
|
|
||||||
if (Left) Left->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::string opSym = "?";
|
|
||||||
auto it = OPERATOR_MAP_REV.find(Operator);
|
|
||||||
if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second);
|
|
||||||
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"BinaryExpression\",\n"
|
|
||||||
<< in << " \"operator\": \"" << jsonEscape(opSym) << "\",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << "";
|
|
||||||
if (Left) {
|
|
||||||
ss << ",\n" << in << " \"left\":\n"
|
|
||||||
<< Left->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (Right) {
|
|
||||||
ss << ",\n" << in << " \"right\":\n"
|
|
||||||
<< Right->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// LiteralNode — Sabit Değer
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Literal tipleri
|
|
||||||
enum class LiteralType : uint8_t {
|
|
||||||
INTEGER, // Tamsayı (decimal, hex, octal, binary)
|
|
||||||
FLOAT, // Ondalıklı sayı (3.14, 1e-5)
|
|
||||||
STRING, // Metin ("hello")
|
|
||||||
BOOLEAN, // true / false
|
|
||||||
BOŞ // null
|
|
||||||
};
|
|
||||||
|
|
||||||
inline const char* literalTypeToString(LiteralType t) {
|
|
||||||
switch (t) {
|
|
||||||
case LiteralType::INTEGER: return "integer";
|
|
||||||
case LiteralType::FLOAT: return "float";
|
|
||||||
case LiteralType::STRING: return "string";
|
|
||||||
case LiteralType::BOOLEAN: return "boolean";
|
|
||||||
case LiteralType::BOŞ: return "null";
|
|
||||||
}
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
class LiteralNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
Token* lexerToken = nullptr;
|
|
||||||
ParserToken parserToken;
|
|
||||||
|
|
||||||
LiteralType literalType = LiteralType::INTEGER;
|
|
||||||
int literalBase = 10; // 10, 16, 8, 2 (sadece INTEGER/FLOAT için)
|
|
||||||
bool isFloatValue = false; // Ondalıklı mı? (sadece INTEGER/FLOAT için)
|
|
||||||
|
|
||||||
LiteralNode() { kind = ASTKind::Literal; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent)
|
|
||||||
<< "Literal {" << parserToken.token->token << "} "
|
|
||||||
<< literalTypeToString(literalType);
|
|
||||||
if (literalType == LiteralType::INTEGER && literalBase != 10)
|
|
||||||
std::cout << " (base " << literalBase << ")";
|
|
||||||
std::cout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::string val = parserToken.token ? parserToken.token->token : "?";
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Literal\",\n"
|
|
||||||
<< in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n"
|
|
||||||
<< in << " \"value\": \"" << jsonEscape(val) << "\"";
|
|
||||||
if (literalType == LiteralType::INTEGER && literalBase != 10) {
|
|
||||||
ss << ",\n" << in << " \"base\": " << literalBase;
|
|
||||||
}
|
|
||||||
if (literalType == LiteralType::FLOAT) {
|
|
||||||
ss << ",\n" << in << " \"isFloat\": true";
|
|
||||||
}
|
|
||||||
ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// IdentifierNode — Tanımlayıcı Referansı
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class IdentifierNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
Token* lexerToken = nullptr;
|
|
||||||
ParserToken parserToken;
|
|
||||||
|
|
||||||
IdentifierNode() { kind = ASTKind::Identifier; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent)
|
|
||||||
<< "Identifier {" << parserToken.token->token << "}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::string name = parserToken.token ? parserToken.token->token : "?";
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Identifier\",\n"
|
|
||||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << "\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PostfixNode — Son Ek İşlem (a++, a--)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class PostfixNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* operand = nullptr;
|
|
||||||
TokenType Operator;
|
|
||||||
|
|
||||||
PostfixNode() { kind = ASTKind::Postfix; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
auto it = OPERATOR_MAP_STRREV.find(Operator);
|
|
||||||
std::string sym = (it != OPERATOR_MAP_STRREV.end()) ? std::string(it->second) : "?";
|
|
||||||
std::cout << padRight("", indent) << "Postfix " << sym;
|
|
||||||
auto it2 = OPERATOR_MAP_REV.find(Operator);
|
|
||||||
if (it2 != OPERATOR_MAP_REV.end())
|
|
||||||
std::cout << " (" << it2->second << ")";
|
|
||||||
std::cout << "\n";
|
|
||||||
if (operand) operand->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::string opSym = "?";
|
|
||||||
auto it = OPERATOR_MAP_REV.find(Operator);
|
|
||||||
if (it != OPERATOR_MAP_REV.end()) opSym = std::string(it->second);
|
|
||||||
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Postfix\",\n"
|
|
||||||
<< in << " \"operator\": \"" << jsonEscape(opSym) << "\"";
|
|
||||||
if (operand) {
|
|
||||||
ss << ",\n" << in << " \"operand\":\n"
|
|
||||||
<< operand->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// IfStatementNode — if / else
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class IfStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* condition = nullptr;
|
|
||||||
ASTNode* thenBranch = nullptr;
|
|
||||||
ASTNode* elseBranch = nullptr;
|
|
||||||
|
|
||||||
IfStatementNode() { kind = ASTKind::IfStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "IfStatement\n";
|
|
||||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
|
||||||
if (condition) condition->log(indent + 4);
|
|
||||||
std::cout << padRight("", indent + 2) << "Then:\n";
|
|
||||||
if (thenBranch) thenBranch->log(indent + 4);
|
|
||||||
if (elseBranch) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Else:\n";
|
|
||||||
elseBranch->log(indent + 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"IfStatement\"";
|
|
||||||
if (condition) {
|
|
||||||
ss << ",\n" << in << " \"condition\":\n"
|
|
||||||
<< condition->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (thenBranch) {
|
|
||||||
ss << ",\n" << in << " \"then\":\n"
|
|
||||||
<< thenBranch->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (elseBranch) {
|
|
||||||
ss << ",\n" << in << " \"else\":\n"
|
|
||||||
<< elseBranch->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// WhileStatementNode — while Döngüsü
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class WhileStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* condition = nullptr;
|
|
||||||
ASTNode* body = nullptr;
|
|
||||||
|
|
||||||
WhileStatementNode() { kind = ASTKind::WhileStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "WhileStatement\n";
|
|
||||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
|
||||||
if (condition) condition->log(indent + 4);
|
|
||||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
|
||||||
if (body) body->log(indent + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"WhileStatement\"";
|
|
||||||
if (condition) {
|
|
||||||
ss << ",\n" << in << " \"condition\":\n"
|
|
||||||
<< condition->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (body) {
|
|
||||||
ss << ",\n" << in << " \"body\":\n"
|
|
||||||
<< body->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ForStatementNode — for Döngüsü
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ForStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* init = nullptr;
|
|
||||||
ASTNode* condition = nullptr;
|
|
||||||
ASTNode* update = nullptr;
|
|
||||||
ASTNode* body = nullptr;
|
|
||||||
|
|
||||||
ForStatementNode() { kind = ASTKind::ForStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "ForStatement\n";
|
|
||||||
if (init) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Init:\n";
|
|
||||||
init->log(indent + 4);
|
|
||||||
}
|
|
||||||
if (condition) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
|
||||||
condition->log(indent + 4);
|
|
||||||
}
|
|
||||||
if (update) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Update:\n";
|
|
||||||
update->log(indent + 4);
|
|
||||||
}
|
|
||||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
|
||||||
if (body) body->log(indent + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"ForStatement\"";
|
|
||||||
if (init) {
|
|
||||||
ss << ",\n" << in << " \"init\":\n"
|
|
||||||
<< init->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (condition) {
|
|
||||||
ss << ",\n" << in << " \"condition\":\n"
|
|
||||||
<< condition->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (update) {
|
|
||||||
ss << ",\n" << in << " \"update\":\n"
|
|
||||||
<< update->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (body) {
|
|
||||||
ss << ",\n" << in << " \"body\":\n"
|
|
||||||
<< body->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// DoWhileStatementNode — do-while Döngüsü
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class DoWhileStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* condition = nullptr;
|
|
||||||
ASTNode* body = nullptr;
|
|
||||||
|
|
||||||
DoWhileStatementNode() { kind = ASTKind::DoWhileStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "DoWhileStatement\n";
|
|
||||||
std::cout << padRight("", indent + 2) << "Body:\n";
|
|
||||||
if (body) body->log(indent + 4);
|
|
||||||
std::cout << padRight("", indent + 2) << "Condition:\n";
|
|
||||||
if (condition) condition->log(indent + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"DoWhileStatement\"";
|
|
||||||
if (body) {
|
|
||||||
ss << ",\n" << in << " \"body\":\n"
|
|
||||||
<< body->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (condition) {
|
|
||||||
ss << ",\n" << in << " \"condition\":\n"
|
|
||||||
<< condition->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ReturnStatementNode — return [ifade]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ReturnStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* value = nullptr;
|
|
||||||
|
|
||||||
ReturnStatementNode() { kind = ASTKind::ReturnStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "ReturnStatement";
|
|
||||||
if (value) {
|
|
||||||
std::cout << "\n";
|
|
||||||
value->log(indent + 2);
|
|
||||||
} else {
|
|
||||||
std::cout << " (void)\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"ReturnStatement\"";
|
|
||||||
if (value) {
|
|
||||||
ss << ",\n" << in << " \"value\":\n"
|
|
||||||
<< value->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// BreakStatementNode — break
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class BreakStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
BreakStatementNode() { kind = ASTKind::BreakStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "BreakStatement\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
return in + "{\n" + in + " \"kind\": \"BreakStatement\"\n" + in + "}";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ContinueStatementNode — continue
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ContinueStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ContinueStatementNode() { kind = ASTKind::ContinueStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "ContinueStatement\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
return in + "{\n" + in + " \"kind\": \"ContinueStatement\"\n" + in + "}";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ExpressionStatementNode — İfadeyi Statement Olarak Sarma
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ExpressionStatementNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* expression = nullptr;
|
|
||||||
|
|
||||||
ExpressionStatementNode() { kind = ASTKind::ExpressionStatement; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "ExpressionStatement\n";
|
|
||||||
if (expression) expression->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"ExpressionStatement\",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << "";
|
|
||||||
if (expression) {
|
|
||||||
ss << ",\n" << in << " \"expression\":\n"
|
|
||||||
<< expression->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CallExpressionNode — Fonksiyon Çağrısı f(a, b, ...)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class CallExpressionNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* callee = nullptr;
|
|
||||||
std::vector<ASTNode*> arguments;
|
|
||||||
|
|
||||||
CallExpressionNode() { kind = ASTKind::Call; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "Call\n";
|
|
||||||
if (callee) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Callee:\n";
|
|
||||||
callee->log(indent + 4);
|
|
||||||
}
|
|
||||||
std::cout << padRight("", indent + 2) << "Args (" << arguments.size() << "):\n";
|
|
||||||
for (auto* a : arguments) a->log(indent + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"Call\"";
|
|
||||||
if (callee) {
|
|
||||||
ss << ",\n" << in << " \"callee\":\n"
|
|
||||||
<< callee->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << ",\n" << in << " \"arguments\": [\n";
|
|
||||||
for (size_t i = 0; i < arguments.size(); i++) {
|
|
||||||
ss << arguments[i]->toJson(depth + 3);
|
|
||||||
if (i + 1 < arguments.size()) ss << ",";
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
ss << in << " ]\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// MemberAccessNode — Üye Erişimi a.b veya a->b
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class MemberAccessNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* object = nullptr;
|
|
||||||
std::string member;
|
|
||||||
bool arrow = false;
|
|
||||||
|
|
||||||
MemberAccessNode() { kind = ASTKind::MemberAccess; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "MemberAccess "
|
|
||||||
<< (arrow ? "->" : ".") << " " << member << "\n";
|
|
||||||
if (object) object->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"MemberAccess\",\n"
|
|
||||||
<< in << " \"member\": \"" << jsonEscape(member) << "\",\n"
|
|
||||||
<< in << " \"arrow\": " << (arrow ? "true" : "false");
|
|
||||||
if (object) {
|
|
||||||
ss << ",\n" << in << " \"object\":\n"
|
|
||||||
<< object->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// IndexExpressionNode — Dizi Erişimi a[i]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class IndexExpressionNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
ASTNode* object = nullptr;
|
|
||||||
ASTNode* index = nullptr;
|
|
||||||
|
|
||||||
IndexExpressionNode() { kind = ASTKind::IndexExpression; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "IndexExpression\n";
|
|
||||||
if (object) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Object:\n";
|
|
||||||
object->log(indent + 4);
|
|
||||||
}
|
|
||||||
if (index) {
|
|
||||||
std::cout << padRight("", indent + 2) << "Index:\n";
|
|
||||||
index->log(indent + 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"IndexExpression\"";
|
|
||||||
if (object) {
|
|
||||||
ss << ",\n" << in << " \"object\":\n"
|
|
||||||
<< object->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
if (index) {
|
|
||||||
ss << ",\n" << in << " \"index\":\n"
|
|
||||||
<< index->toJson(depth + 2);
|
|
||||||
}
|
|
||||||
ss << "\n" << in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// StructDeclNode — struct Tanımı
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class StructDeclNode : public ASTNode {
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
|
|
||||||
StructDeclNode() { kind = ASTKind::StructDecl; }
|
|
||||||
|
|
||||||
void log(int indent = 0) override {
|
|
||||||
std::cout << padRight("", indent) << "StructDecl " << name << "\n";
|
|
||||||
for (auto* c : getChildren()) c->log(indent + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toJson(int depth = 0) override {
|
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << in << "{\n"
|
|
||||||
<< in << " \"kind\": \"StructDecl\",\n"
|
|
||||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
|
||||||
<< in << " \"children\": [\n"
|
|
||||||
<< childrenToJson(this, depth + 3)
|
|
||||||
<< in << " ]\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif // SAQUT_AST
|
#endif // SAQUT_AST
|
||||||
|
|
|
||||||
|
|
@ -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