diff --git a/src/ir/instruction.hpp b/src/ir/instruction.hpp index b626984..3d11db4 100644 --- a/src/ir/instruction.hpp +++ b/src/ir/instruction.hpp @@ -55,6 +55,13 @@ enum class Opcode { DIV, // UYARI: sıfıra bölme → runtime_error fırlatılır MOD, + // --- Bitsel (tümü: slots[dest] = slots[left] OP slots[right]) --- + BAND, // slots[left] & slots[right] + BOR, // slots[left] | slots[right] + SHL, // slots[left] << slots[right] + SHR, // slots[left] >> slots[right] + BNOT, // ~slots[src] → slots[dest] (tekli operatör; src kullanır, left/right değil) + // --- Karşılaştırma (sonuç: 1 = doğru, 0 = yanlış) --- LESS, // slots[left] < slots[right] LESS_EQUAL, // slots[left] <= slots[right] @@ -75,6 +82,10 @@ enum class Opcode { RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet. + // --- Global değişken erişimi --- + LOAD_GLOBAL, // slots[dest] = globalSlots[intValue] + STORE_GLOBAL, // globalSlots[intValue] = slots[src] + // --- Dış dünya (FFI — Foreign Function Interface) --- CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli. // Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi). @@ -91,6 +102,13 @@ inline const char* opcodeName(Opcode op) { case Opcode::MUL: return "MUL"; case Opcode::DIV: return "DIV"; case Opcode::MOD: return "MOD"; + case Opcode::BAND: return "BAND"; + case Opcode::BOR: return "BOR"; + case Opcode::SHL: return "SHL"; + case Opcode::SHR: return "SHR"; + case Opcode::BNOT: return "BNOT"; + case Opcode::LOAD_GLOBAL: return "LOAD_GLOBAL"; + case Opcode::STORE_GLOBAL: return "STORE_GLOBAL"; case Opcode::LESS: return "LESS"; case Opcode::LESS_EQUAL: return "LESS_EQUAL"; case Opcode::GREATER: return "GREATER"; diff --git a/src/ir/ir_function.cpp b/src/ir/ir_function.cpp index 690b566..481f5e2 100644 --- a/src/ir/ir_function.cpp +++ b/src/ir/ir_function.cpp @@ -21,6 +21,10 @@ static const char* opSymbol(Opcode op) { case Opcode::MUL: return "*"; case Opcode::DIV: return "/"; case Opcode::MOD: return "%"; + case Opcode::BAND: return "&"; + case Opcode::BOR: return "|"; + case Opcode::SHL: return "<<"; + case Opcode::SHR: return ">>"; case Opcode::LESS: return "<"; case Opcode::LESS_EQUAL: return "<="; case Opcode::GREATER: return ">"; @@ -35,6 +39,7 @@ static bool isBinaryOp(Opcode op) { switch (op) { case Opcode::ADD: case Opcode::SUB: case Opcode::MUL: case Opcode::DIV: case Opcode::MOD: + case Opcode::BAND: case Opcode::BOR: case Opcode::SHL: case Opcode::SHR: case Opcode::LESS: case Opcode::LESS_EQUAL: case Opcode::GREATER: case Opcode::GREATER_EQUAL: case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL: @@ -113,6 +118,15 @@ void IRFunction::dump() const { } std::cout << ")"; + } else if (ins.opcode == Opcode::BNOT) { + std::cout << slot(ins.dest) << " = ~" << slot(ins.src); + + } else if (ins.opcode == Opcode::LOAD_GLOBAL) { + std::cout << slot(ins.dest) << " = global[" << ins.intValue << "]"; + + } else if (ins.opcode == Opcode::STORE_GLOBAL) { + std::cout << "global[" << ins.intValue << "] = " << slot(ins.src); + } else if (ins.opcode == Opcode::RETURN) { std::cout << slot(ins.src); } diff --git a/src/ir/ir_generator.cpp b/src/ir/ir_generator.cpp index ba7ef7d..b67d3d2 100644 --- a/src/ir/ir_generator.cpp +++ b/src/ir/ir_generator.cpp @@ -17,25 +17,40 @@ IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) { IRProgram program; - // ProgramNode'un her çocuğunu gez. - // Bizi ilgilendiren: FunctionDecl. StructDecl/GlobalVar → TODO. + // 1. Geçiş: global VariableDecl'leri topla ve kayıt et + std::vector globalVars; + for (ASTNode* child : programNode->getChildren()) { + if (child->kind == ASTKind::VariableDecl) { + auto* vd = (VariableDeclNode*)child; + nameToGlobal_[vd->name] = globalCount_++; + program.globalCount++; + program.globalNames.push_back(vd->name); + globalVars.push_back(vd); + } + } + + // 2. Geçiş: fonksiyonları üret for (ASTNode* child : programNode->getChildren()) { if (child->kind == ASTKind::FunctionDecl) { - // Her fonksiyon üretimi için sıfırla nameToSlot_.clear(); nextSlot_ = 0; - // IRFunction oluştur, currentFunction_ olarak işaretle auto* fnDecl = (FunctionDeclNode*)child; IRFunction irFn(fnDecl->name, (int)fnDecl->params.size()); program.addFunction(std::move(irFn)); - - // addFunction std::move yaptığı için pointer'ı haritadan alalım currentFunction_ = program.findFunction(fnDecl->name); - generateFunction(child); + // main'in başında global değişkenlerin init ifadelerini üret + if (fnDecl->name == "main") { + for (VariableDeclNode* gv : globalVars) { + if (gv->initExpr) { + int initSlot = generateExpression(gv->initExpr); + emitStoreGlobal(initSlot, nameToGlobal_[gv->name]); + } + } + } - // Fonksiyon bitti — toplam slot sayısını kaydet + generateFunction(child); currentFunction_->slotCount = nextSlot_; } } @@ -344,13 +359,15 @@ int IRGenerator::generateExpression(ASTNode* node) { } // ── Değişken ismi: n, first, second ... ────────────────────────────── - // Bu değişkenin değeri zaten bir slotta. O slotu döndür. case ASTKind::Identifier: { auto* id = (IdentifierNode*)node; std::string name = id->parserToken.token ? id->parserToken.token->token : ""; - // Önce builtin mi? (print gibi) — identifier olarak gelen builtin fonksiyon - // çağrıları CallExpression içinde yakalanıyor, burada sadece değişken kalır + if (isGlobal(name)) { + int tempSlot = freshSlot(); + emitLoadGlobal(tempSlot, getGlobalIndex(name)); + return tempSlot; + } return lookupVariable(name); } @@ -358,44 +375,59 @@ int IRGenerator::generateExpression(ASTNode* node) { case ASTKind::BinaryExpression: { auto* bin = (BinaryExpressionNode*)node; - // Atama operatörleri: x = expr, x += expr ... - // Sol taraf bir değişken, sağ taraf hesaplanır ve o değişkene yazılır. + // Atama operatörleri: x = expr if (bin->Operator == TokenType::EQUAL) { - // Sağ tarafı hesapla int rhsSlot = generateExpression(bin->Right); - - // Sol taraf değişkenin slotunu bul auto* lhsId = (IdentifierNode*)bin->Left; std::string varName = lhsId->parserToken.token->token; - int varSlot = lookupVariable(varName); - // Sonucu değişkenin slotuna kopyala - if (rhsSlot != varSlot) { - emitLoadSlot(varSlot, rhsSlot); + if (isGlobal(varName)) { + emitStoreGlobal(rhsSlot, getGlobalIndex(varName)); + return rhsSlot; } + + int varSlot = lookupVariable(varName); + if (rhsSlot != varSlot) emitLoadSlot(varSlot, rhsSlot); return varSlot; } - // Birleşik atama: += -= *= /= %= + // Birleşik atama: += -= *= /= %= &= |= <<= >>= // x OP= y ≡ x = x OP y if (bin->Operator == TokenType::PLUS_EQUAL || bin->Operator == TokenType::MINUS_EQUAL || bin->Operator == TokenType::STAR_EQUAL || bin->Operator == TokenType::SLASH_EQUAL || - bin->Operator == TokenType::PERCENT_EQUAL) { + bin->Operator == TokenType::PERCENT_EQUAL || + bin->Operator == TokenType::AMPERSAND_EQUAL || + bin->Operator == TokenType::PIPE_EQUAL || + bin->Operator == TokenType::LSHIFT_EQUAL || + bin->Operator == TokenType::RSHIFT_EQUAL) { auto* lhsId = (IdentifierNode*)bin->Left; std::string varName = lhsId->parserToken.token->token; - int varSlot = lookupVariable(varName); int rhsSlot = generateExpression(bin->Right); Opcode arithOp = Opcode::ADD; - if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB; - else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL; - else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV; - else if (bin->Operator == TokenType::PERCENT_EQUAL) arithOp = Opcode::MOD; + if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB; + else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL; + else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV; + else if (bin->Operator == TokenType::PERCENT_EQUAL) arithOp = Opcode::MOD; + else if (bin->Operator == TokenType::AMPERSAND_EQUAL) arithOp = Opcode::BAND; + else if (bin->Operator == TokenType::PIPE_EQUAL) arithOp = Opcode::BOR; + else if (bin->Operator == TokenType::LSHIFT_EQUAL) arithOp = Opcode::SHL; + else if (bin->Operator == TokenType::RSHIFT_EQUAL) arithOp = Opcode::SHR; int resultSlot = freshSlot(); + + if (isGlobal(varName)) { + int currentSlot = freshSlot(); + emitLoadGlobal(currentSlot, getGlobalIndex(varName)); + emitBinaryOp(arithOp, resultSlot, currentSlot, rhsSlot); + emitStoreGlobal(resultSlot, getGlobalIndex(varName)); + return resultSlot; + } + + int varSlot = lookupVariable(varName); emitBinaryOp(arithOp, resultSlot, varSlot, rhsSlot); emitLoadSlot(varSlot, resultSlot); return varSlot; @@ -412,12 +444,17 @@ int IRGenerator::generateExpression(ASTNode* node) { emitLoadConst(zeroSlot, 0); emitBinaryOp(Opcode::SUB, resultSlot, zeroSlot, operandSlot); } else if (bin->Operator == TokenType::BANG) { - // !x → (x == 0): sıfırsa 1, değilse 0 — her zaman 0 ya da 1 + // !x → (x == 0): sıfırsa 1, değilse 0 int zeroSlot = freshSlot(); emitLoadConst(zeroSlot, 0); emitBinaryOp(Opcode::EQUAL_EQUAL, resultSlot, operandSlot, zeroSlot); + } else if (bin->Operator == TokenType::TILDE) { + // ~x — bitsel değil + Instruction ins(Opcode::BNOT); + ins.dest = resultSlot; + ins.src = operandSlot; + currentFunction_->instructions.push_back(std::move(ins)); } else { - // Diğer unary operatörler (ör. ~) → TODO emitLoadSlot(resultSlot, operandSlot); } return resultSlot; @@ -438,6 +475,12 @@ int IRGenerator::generateExpression(ASTNode* node) { case TokenType::EQUAL_EQUAL: return generateBinaryArithmetic(Opcode::EQUAL_EQUAL, bin->Left, bin->Right); case TokenType::BANG_EQUAL: return generateBinaryArithmetic(Opcode::NOT_EQUAL, bin->Left, bin->Right); + // Bitsel operatörler + case TokenType::AMPERSAND: return generateBinaryArithmetic(Opcode::BAND, bin->Left, bin->Right); + case TokenType::PIPE: return generateBinaryArithmetic(Opcode::BOR, bin->Left, bin->Right); + case TokenType::LSHIFT: return generateBinaryArithmetic(Opcode::SHL, bin->Left, bin->Right); + case TokenType::RSHIFT: return generateBinaryArithmetic(Opcode::SHR, bin->Left, bin->Right); + // Mantıksal operatörler: kısa devre dallanmasıyla üretilir (ADR-008). // NOT: sıradan ikili işlem değil — b, a'nın değerine göre atlanabilir. case TokenType::AMPERSAND_AMPERSAND: { @@ -593,6 +636,29 @@ void IRGenerator::emitLoadSlot(int destSlot, int srcSlot) { currentFunction_->instructions.push_back(std::move(ins)); } +void IRGenerator::emitLoadGlobal(int destSlot, int globalIndex) { + Instruction ins(Opcode::LOAD_GLOBAL); + ins.dest = destSlot; + ins.intValue = globalIndex; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitStoreGlobal(int srcSlot, int globalIndex) { + Instruction ins(Opcode::STORE_GLOBAL); + ins.src = srcSlot; + ins.intValue = globalIndex; + currentFunction_->instructions.push_back(std::move(ins)); +} + +bool IRGenerator::isGlobal(const std::string& name) const { + return nameToGlobal_.count(name) > 0; +} + +int IRGenerator::getGlobalIndex(const std::string& name) const { + auto it = nameToGlobal_.find(name); + return (it != nameToGlobal_.end()) ? it->second : -1; +} + void IRGenerator::emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot) { Instruction ins(op); ins.dest = destSlot; diff --git a/src/ir/ir_generator.hpp b/src/ir/ir_generator.hpp index 62ef77f..4f24ce1 100644 --- a/src/ir/ir_generator.hpp +++ b/src/ir/ir_generator.hpp @@ -56,6 +56,8 @@ private: void emitLoadConst(int destSlot, int value); void emitLoadSlot(int destSlot, int srcSlot); + void emitLoadGlobal(int destSlot, int globalIndex); + void emitStoreGlobal(int srcSlot, int globalIndex); void emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot); void emitReturn(int srcSlot); // Koşulsuz atlama yazar; instruction indeksini döndürür (backpatch için). @@ -88,9 +90,15 @@ private: IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon int nextSlot_ = 0; // sıradaki boş slot numarası - // Değişken ismi → slot numarası. - // Sınırlama: aynı isimdeki farklı scope değişkenleri çakışır (TODO). + // Değişken ismi → slot numarası (lokal). std::unordered_map nameToSlot_; + + // Global değişken ismi → global index + std::unordered_map nameToGlobal_; + int globalCount_ = 0; + + bool isGlobal(const std::string& name) const; + int getGlobalIndex(const std::string& name) const; }; #endif // SAQUT_IR_GENERATOR diff --git a/src/ir/ir_program.cpp b/src/ir/ir_program.cpp index 38014b6..43d1af7 100644 --- a/src/ir/ir_program.cpp +++ b/src/ir/ir_program.cpp @@ -3,6 +3,14 @@ void IRProgram::dump() const { std::cout << "IR DUMP\n\n"; + + if (globalCount > 0) { + std::cout << "GLOBALS (" << globalCount << ")\n"; + for (int i = 0; i < (int)globalNames.size(); i++) + std::cout << " global[" << i << "] = " << globalNames[i] << "\n"; + std::cout << "\n"; + } + for (const auto& name : functionOrder) { auto it = functions.find(name); if (it != functions.end()) it->second.dump(); diff --git a/src/ir/ir_program.hpp b/src/ir/ir_program.hpp index a60e1a4..59caf89 100644 --- a/src/ir/ir_program.hpp +++ b/src/ir/ir_program.hpp @@ -29,6 +29,10 @@ struct IRProgram { // Ekleme sırası (dump'ta orijinal sırayla göstermek için) std::vector functionOrder; + // Global değişkenler (LOAD_GLOBAL / STORE_GLOBAL için) + int globalCount = 0; + std::vector globalNames; // index → isim (dump için) + // Yeni fonksiyon ekle void addFunction(IRFunction fn) { functionOrder.push_back(fn.name); diff --git a/src/opt/constant_folding.hpp b/src/opt/constant_folding.hpp index f09426a..9e413c4 100644 --- a/src/opt/constant_folding.hpp +++ b/src/opt/constant_folding.hpp @@ -104,6 +104,10 @@ private: case TokenType::GREATER: case TokenType::LESS_EQUAL: case TokenType::GREATER_EQUAL: + case TokenType::AMPERSAND: + case TokenType::PIPE: + case TokenType::LSHIFT: + case TokenType::RSHIFT: case TokenType::AMPERSAND_AMPERSAND: case TokenType::PIPE_PIPE: return true; @@ -125,6 +129,10 @@ private: case TokenType::GREATER: return l > r ? 1 : 0; case TokenType::LESS_EQUAL: return l <= r ? 1 : 0; case TokenType::GREATER_EQUAL: return l >= r ? 1 : 0; + case TokenType::AMPERSAND: return l & r; + case TokenType::PIPE: return l | r; + case TokenType::LSHIFT: return l << r; + case TokenType::RSHIFT: return l >> r; case TokenType::AMPERSAND_AMPERSAND: return (l && r) ? 1 : 0; case TokenType::PIPE_PIPE: return (l || r) ? 1 : 0; default: return 0; diff --git a/src/vm/interpreter.cpp b/src/vm/interpreter.cpp index 0ff74ea..a55bf00 100644 --- a/src/vm/interpreter.cpp +++ b/src/vm/interpreter.cpp @@ -3,6 +3,9 @@ #include int Interpreter::run() { + // Global slot'ları sıfırla + globalSlots_.assign(program_.globalCount, Value::fromInt(0)); + IRFunction* mainFunction = program_.findFunction("main"); if (!mainFunction) throw std::runtime_error("Çalışma hatası: 'main' fonksiyonu bulunamadı"); @@ -70,6 +73,35 @@ int Interpreter::run() { break; } + // ── Bitsel ──────────────────────────────────────────────────────── + case Opcode::BAND: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue & frame.slots[instr.right].intValue); + break; + case Opcode::BOR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue | frame.slots[instr.right].intValue); + break; + case Opcode::SHL: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue << frame.slots[instr.right].intValue); + break; + case Opcode::SHR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue >> frame.slots[instr.right].intValue); + break; + case Opcode::BNOT: + frame.slots[instr.dest] = Value::fromInt(~frame.slots[instr.src].intValue); + break; + + // ── Global değişken erişimi ──────────────────────────────────────── + case Opcode::LOAD_GLOBAL: + frame.slots[instr.dest] = globalSlots_[instr.intValue]; + break; + case Opcode::STORE_GLOBAL: + globalSlots_[instr.intValue] = frame.slots[instr.src]; + break; + // ── Karşılaştırma ───────────────────────────────────────────────── case Opcode::LESS: frame.slots[instr.dest] = Value::fromInt( diff --git a/src/vm/interpreter.hpp b/src/vm/interpreter.hpp index d7fb687..d0748d3 100644 --- a/src/vm/interpreter.hpp +++ b/src/vm/interpreter.hpp @@ -28,6 +28,7 @@ public: private: IRProgram& program_; std::vector callStack_; + std::vector globalSlots_; // Host (C++) fonksiyon çağrısı — şu an sadece "print" destekli void executeHostFunction(const std::string& name,