Merge pull request #52 from abdussamedulutas/fix/38-45-global-ir-bitwise

feat(ir,vm): #38 global değişken IR + #45 bitsel operatörler
This commit is contained in:
Abdussamed 2026-06-19 23:38:41 +03:00 committed by GitHub
commit 4fedcc1bde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 96 additions and 24 deletions

25
examples/test_bitwise.sqt Normal file
View File

@ -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;
}

View File

@ -75,6 +75,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).
@ -102,6 +110,12 @@ inline const char* opcodeName(Opcode op) {
case Opcode::JIF_TRUE: return "JIF_TRUE";
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";

View File

@ -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<ASTNode*> 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_;
}
}
@ -407,17 +412,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) {
// !x → (x == 0): sıfırsa 1, değilse 0 — her zaman 0 ya da 1
int zeroSlot = freshSlot();
emitLoadConst(zeroSlot, 0);
emitBinaryOp(Opcode::EQUAL_EQUAL, resultSlot, operandSlot, zeroSlot);
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 (ör. ~) → TODO
emitLoadSlot(resultSlot, operandSlot);
}
return resultSlot;
@ -437,30 +443,32 @@ 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);
// 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.
// 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);
// Mantıksal: kısa devre dallanmasıyla üretilir (ADR-008)
case TokenType::AMPERSAND_AMPERSAND: {
int slotA = generateExpression(bin->Left);
int result = freshSlot();
emitLoadConst(result, 0); // varsayılan: false
int skipB = emitJumpIfFalse(slotA); // a false → b'yi atla
emitLoadConst(result, 0);
int skipB = emitJumpIfFalse(slotA);
int slotB = generateExpression(bin->Right);
emitLoadSlot(result, slotB); // result = b
emitLoadSlot(result, slotB);
patchJump(skipB);
return result;
}
case TokenType::PIPE_PIPE: {
int slotA = generateExpression(bin->Left);
int result = freshSlot();
emitLoadConst(result, 1); // varsayılan: true
int skipB = emitJumpIfTrue(slotA); // a true → b'yi atla
emitLoadConst(result, 1);
int skipB = emitJumpIfTrue(slotA);
int slotB = generateExpression(bin->Right);
emitLoadSlot(result, slotB); // result = b
emitLoadSlot(result, slotB);
patchJump(skipB);
return result;
}
default: {
// Bilinmeyen operatör — boş slot döndür
int slot = freshSlot();

View File

@ -152,6 +152,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);