diff --git a/examples/test_bitwise.sqt b/examples/test_bitwise.sqt new file mode 100644 index 0000000..dcba988 --- /dev/null +++ b/examples/test_bitwise.sqt @@ -0,0 +1,25 @@ +int global_x = 10; +int global_y = 3; + +int main() { + // global değişken testi (#38) + print(global_x); + print(global_y); + + // bitsel AND, OR, SHL, SHR (#45) + int a = 12; + int b = 10; + print(a & b); + print(a | b); + print(1 << 3); + print(16 >> 2); + + // unary ~ ve ! + int c = 0; + print(!c); + int d = 5; + print(!d); + print(~0); + + return 0; +} diff --git a/src/ir/instruction.hpp b/src/ir/instruction.hpp index 9ce720f..30110ba 100644 --- a/src/ir/instruction.hpp +++ b/src/ir/instruction.hpp @@ -73,6 +73,14 @@ enum class Opcode { RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet. + // --- Bitsel (tümü: slots[dest] = slots[left] OP slots[right]) --- + BIT_AND, // a & b + BIT_OR, // a | b + BIT_SHL, // a << b + BIT_SHR, // a >> b + BIT_NOT, // ~a (unary: slots[dest] = ~slots[src]) + NOT_UNARY, // !a (unary: slots[dest] = slots[src] == 0 ? 1 : 0) + // --- 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). @@ -99,6 +107,12 @@ inline const char* opcodeName(Opcode op) { case Opcode::JIF_FALSE: return "JIF_FALSE"; case Opcode::CALL: return "CALL"; case Opcode::RETURN: return "RETURN"; + case Opcode::BIT_AND: return "BIT_AND"; + case Opcode::BIT_OR: return "BIT_OR"; + case Opcode::BIT_SHL: return "BIT_SHL"; + case Opcode::BIT_SHR: return "BIT_SHR"; + case Opcode::BIT_NOT: return "BIT_NOT"; + case Opcode::NOT_UNARY: return "NOT_UNARY"; case Opcode::CALLHOST: return "CALLHOST"; } return "UNKNOWN"; diff --git a/src/ir/ir_generator.cpp b/src/ir/ir_generator.cpp index 947355d..a8e9a64 100644 --- a/src/ir/ir_generator.cpp +++ b/src/ir/ir_generator.cpp @@ -17,25 +17,30 @@ IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) { IRProgram program; - // ProgramNode'un her çocuğunu gez. - // Bizi ilgilendiren: FunctionDecl. StructDecl/GlobalVar → TODO. + // Üst düzey global değişken bildirimlerini topla (#38) + std::vector globalVars; + for (ASTNode* child : programNode->getChildren()) { + if (child->kind == ASTKind::VariableDecl) + globalVars.push_back(child); + } + 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); + // Global değişkenleri main'in başına ekle (Seçenek B) + if (fnDecl->name == "main") { + for (ASTNode* gv : globalVars) + generateStatement(gv); + } - // Fonksiyon bitti — toplam slot sayısını kaydet + generateFunction(child); currentFunction_->slotCount = nextSlot_; } } @@ -374,12 +379,18 @@ int IRGenerator::generateExpression(ASTNode* node) { int resultSlot = freshSlot(); if (bin->Operator == TokenType::MINUS) { - // -x → 0 - x int zeroSlot = freshSlot(); emitLoadConst(zeroSlot, 0); emitBinaryOp(Opcode::SUB, resultSlot, zeroSlot, operandSlot); + } else if (bin->Operator == TokenType::BANG) { + Instruction ins(Opcode::NOT_UNARY); + ins.dest = resultSlot; ins.src = operandSlot; + currentFunction_->instructions.push_back(std::move(ins)); + } else if (bin->Operator == TokenType::TILDE) { + Instruction ins(Opcode::BIT_NOT); + ins.dest = resultSlot; ins.src = operandSlot; + currentFunction_->instructions.push_back(std::move(ins)); } else { - // Diğer unary operatörler → TODO emitLoadSlot(resultSlot, operandSlot); } return resultSlot; @@ -399,6 +410,11 @@ int IRGenerator::generateExpression(ASTNode* node) { case TokenType::GREATER_EQUAL: return generateBinaryArithmetic(Opcode::GREATER_EQUAL, bin->Left, bin->Right); 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 + case TokenType::AMPERSAND: return generateBinaryArithmetic(Opcode::BIT_AND, bin->Left, bin->Right); + case TokenType::PIPE: return generateBinaryArithmetic(Opcode::BIT_OR, bin->Left, bin->Right); + case TokenType::LSHIFT: return generateBinaryArithmetic(Opcode::BIT_SHL, bin->Left, bin->Right); + case TokenType::RSHIFT: return generateBinaryArithmetic(Opcode::BIT_SHR, bin->Left, bin->Right); default: { // Bilinmeyen operatör — boş slot döndür int slot = freshSlot(); diff --git a/src/vm/interpreter.cpp b/src/vm/interpreter.cpp index be466c2..1f903ce 100644 --- a/src/vm/interpreter.cpp +++ b/src/vm/interpreter.cpp @@ -148,6 +148,31 @@ int Interpreter::run() { continue; } + // ── Bitsel ──────────────────────────────────────────────────────── + case Opcode::BIT_AND: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue & frame.slots[instr.right].intValue); + break; + case Opcode::BIT_OR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue | frame.slots[instr.right].intValue); + break; + case Opcode::BIT_SHL: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue << frame.slots[instr.right].intValue); + break; + case Opcode::BIT_SHR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue >> frame.slots[instr.right].intValue); + break; + case Opcode::BIT_NOT: + frame.slots[instr.dest] = Value::fromInt(~frame.slots[instr.src].intValue); + break; + case Opcode::NOT_UNARY: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.src].intValue == 0 ? 1 : 0); + break; + // ── FFI ─────────────────────────────────────────────────────────── case Opcode::CALLHOST: executeHostFunction(instr.functionName, frame.slots, instr.argSlots);