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:
commit
4fedcc1bde
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue