feat(cli): saqut ir komutu — IR talimat dump'u

- IRFunction::dump() yenilendi: ASCII kutu, sn slot notasyonu,
  ikili op'larda sembol (+/-/*/<= vb.), hizalı sütunlar
- src/cli/commands/ir.hpp: tokenize→parse→collect→ir→dump pipeline
- main.cpp + args.hpp: "ir" komutu kayıtlı
This commit is contained in:
saqut 2026-06-18 19:21:12 +03:00
parent 3c76eab932
commit 4c67f29362
6 changed files with 168 additions and 54 deletions

Binary file not shown.

View File

@ -10,14 +10,16 @@
21 7502 1781796718449424977 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o 3c8869307381c930
14 6864 1781796718442362341 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o 5cc8b697133bcf64
15 6733 1781796718442847556 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o c3d262615ede4c95
2 4655 1781799345769869911 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
4655 4925 1781799350422111935 saqut f2e198803c4dbffb
0 22 1781799395548855747 build.ninja 1876a59d627a585
0 22 1781799395548855747 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
2 4490 1781799598563879630 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
4490 4758 1781799603051859470 saqut f2e198803c4dbffb
0 22 1781799611852960564 build.ninja 1876a59d627a585
0 22 1781799611852960564 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
6733 11112 1781796725160284765 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o ec4e483b8ddb4007
4805 9685 1781796723232278341 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 248faa3675024351
6700 10405 1781796725127284655 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o b29c133293d988b0
2 795 1781799345769990010 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d
1 958 1781799106946635459 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
1 668 1781799598562879634 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
1 1001 1781799106947865509 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
2 3078 1781799345769137653 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530
1 636 1781799663202595202 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
636 892 1781799663837592468 saqut f2e198803c4dbffb

View File

@ -88,8 +88,9 @@ inline CliArgs parseArgs(int argc, char* argv[]) {
// İlk argüman komut mu?
if (args.command.empty() && i == 1) {
if (arg == "run" || arg == "tokens" || arg == "ast" ||
arg == "symbols" || arg == "check" || arg == "compile" ||
arg == "parse" || arg == "transpile" || arg == "interpret") {
arg == "symbols" || arg == "check" || arg == "ir" ||
arg == "compile" || arg == "parse" || arg == "transpile" ||
arg == "interpret") {
args.command = arg;
continue;
}

50
src/cli/commands/ir.hpp Normal file
View File

@ -0,0 +1,50 @@
#ifndef SAQUT_CLI_IR
#define SAQUT_CLI_IR
#include <iostream>
#include "cli/args.hpp"
#include "tokenizer/tokenizer.hpp"
#include "parser/parser.hpp"
#include "symbol/symbol_table.hpp"
#include "symbol/symbol_collector.hpp"
#include "diagnostic/diagnostic_engine.hpp"
#include "ir/ir_generator.hpp"
inline int cmdIr(const CliArgs& args) {
std::string filePath = inputFilePath(args);
std::string source = readSource(args);
if (source.empty()) return 1;
Tokenizer tokenizer;
auto tokens = tokenizer.scan(source, filePath);
Parser parser;
ASTNode* ast = parser.parse(tokens);
if (!ast) {
std::cerr << "Hata: AST üretilemedi\n";
for (auto* t : tokens) delete t;
return 1;
}
SymbolTable symbolTable;
DiagnosticEngine diag;
SymbolCollector(symbolTable, diag).collect(ast);
if (diag.hasErrors()) {
diag.printAll(std::cerr);
delete ast;
for (auto* t : tokens) delete t;
return 1;
}
IRGenerator irGenerator;
IRProgram program = irGenerator.generate(ast, symbolTable);
program.dump();
delete ast;
for (auto* t : tokens) delete t;
return 0;
}
#endif // SAQUT_CLI_IR

View File

@ -1,62 +1,118 @@
#include "ir/ir_function.hpp"
#include <iomanip>
#include <iostream>
#include <string>
// Her instruction'ı "indeks: OPCODE operandlar" formatında yazdır.
// Bu çıktı hem insanın okuduğu hem de birim testlerin karşılaştırdığı formattır.
void IRFunction::dump() const {
std::cout << "=== " << name
<< " (paramCount=" << paramCount
<< ", slotCount=" << slotCount << ") ===\n";
// ─────────────────────────────────────────────────────────────────────────────
// Yardımcılar
// ─────────────────────────────────────────────────────────────────────────────
for (int i = 0; i < (int)instructions.size(); i++) {
const Instruction& ins = instructions[i];
std::cout << " " << std::setw(3) << i << ": "
<< std::left << std::setw(14) << opcodeName(ins.opcode);
// Slot adını kısa göster: s0, s1, ...
static std::string slot(int s) {
if (s == -1) return "?";
return "s" + std::to_string(s);
}
switch (ins.opcode) {
case Opcode::LOAD_CONST:
std::cout << "slot[" << ins.dest << "] = " << ins.intValue;
break;
case Opcode::LOAD_SLOT:
std::cout << "slot[" << ins.dest << "] = slot[" << ins.src << "]";
break;
// İkili op sembolü: ADD → "+"
static const char* opSymbol(Opcode op) {
switch (op) {
case Opcode::ADD: return "+";
case Opcode::SUB: return "-";
case Opcode::MUL: return "*";
case Opcode::DIV: return "/";
case Opcode::MOD: return "%";
case Opcode::LESS: return "<";
case Opcode::LESS_EQUAL: return "<=";
case Opcode::GREATER: return ">";
case Opcode::GREATER_EQUAL: return ">=";
case Opcode::EQUAL_EQUAL: return "==";
case Opcode::NOT_EQUAL: return "!=";
default: return "?";
}
}
static bool isBinaryOp(Opcode op) {
switch (op) {
case Opcode::ADD: case Opcode::SUB: case Opcode::MUL:
case Opcode::DIV: case Opcode::MOD:
case Opcode::LESS: case Opcode::LESS_EQUAL:
case Opcode::GREATER: case Opcode::GREATER_EQUAL:
case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL:
std::cout << "slot[" << ins.dest << "] = "
<< "slot[" << ins.left << "] op slot[" << ins.right << "]";
break;
case Opcode::JMP:
return true;
default: return false;
}
}
// ─────────────────────────────────────────────────────────────────────────────
// IRFunction::dump
// ─────────────────────────────────────────────────────────────────────────────
void IRFunction::dump() const {
// Başlık: fonksiyon adı + slot bilgisi
std::string header = " " + name + "()";
if (paramCount > 0) {
header = " " + name + "(";
for (int i = 0; i < paramCount; i++) {
if (i) header += ", ";
header += "s" + std::to_string(i);
}
header += ")";
}
header += " [" + std::to_string(slotCount) + " slot]";
// Üst çizgi
std::cout << "+-" << std::string(header.size(), '-') << "-+\n";
std::cout << "|" << header << " |\n";
std::cout << "+-" << std::string(header.size(), '-') << "-+\n";
// Talimatlar
for (int i = 0; i < (int)instructions.size(); i++) {
const Instruction& ins = instructions[i];
// Satır numarası
std::cout << " " << std::setw(3) << std::right << i << "";
// Opcode sütunu (12 karakter genişlik)
std::cout << std::left << std::setw(12) << opcodeName(ins.opcode);
// Operandlar — opcode'a göre farklı format
if (ins.opcode == Opcode::LOAD_CONST) {
std::cout << slot(ins.dest) << " = " << ins.intValue;
} else if (ins.opcode == Opcode::LOAD_SLOT) {
std::cout << slot(ins.dest) << " = " << slot(ins.src);
} else if (isBinaryOp(ins.opcode)) {
std::cout << slot(ins.dest) << " = "
<< slot(ins.left) << " " << opSymbol(ins.opcode)
<< " " << slot(ins.right);
} else if (ins.opcode == Opcode::JMP) {
std::cout << "" << ins.jumpTarget;
break;
case Opcode::JIF_FALSE:
std::cout << "if !slot[" << ins.cond << "] → " << ins.jumpTarget;
break;
case Opcode::CALL: {
std::cout << "slot[" << ins.dest << "] = " << ins.functionName << "(";
} else if (ins.opcode == Opcode::JIF_FALSE) {
std::cout << "!" << slot(ins.cond) << "" << ins.jumpTarget;
} else if (ins.opcode == Opcode::CALL) {
std::cout << slot(ins.dest) << " = " << ins.functionName << "(";
for (int j = 0; j < (int)ins.argSlots.size(); j++) {
if (j) std::cout << ", ";
std::cout << "slot[" << ins.argSlots[j] << "]";
std::cout << slot(ins.argSlots[j]);
}
std::cout << ")";
break;
}
case Opcode::RETURN:
std::cout << "slot[" << ins.src << "]";
break;
case Opcode::CALLHOST: {
} else if (ins.opcode == Opcode::CALLHOST) {
std::cout << ins.functionName << "(";
for (int j = 0; j < (int)ins.argSlots.size(); j++) {
if (j) std::cout << ", ";
std::cout << "slot[" << ins.argSlots[j] << "]";
std::cout << slot(ins.argSlots[j]);
}
std::cout << ")";
break;
}
} else if (ins.opcode == Opcode::RETURN) {
std::cout << slot(ins.src);
}
std::cout << "\n";
}
std::cout << "\n";

View File

@ -28,6 +28,7 @@
#include "cli/commands/ast.hpp"
#include "cli/commands/symbols.hpp"
#include "cli/commands/check.hpp"
#include "cli/commands/ir.hpp"
int main(int argc, char* argv[]) {
// Komutları kaydet
@ -53,6 +54,10 @@ int main(int argc, char* argv[]) {
"Semantik analiz — tip denetimi + yapısal doğrulama",
false, cmdCheck});
cli.registerCommand({"ir",
"IR talimat listesini göster (ara temsil — bytecode öncesi)",
false, cmdIr});
// --- Gelecek komutlar (TODO) ---
cli.registerCommand({"compile",
"TODO: Kaynak kodu derle",