15 throw mx::Exception(
"Argument must be a variable, got: " + varName);
25 throw mx::Exception(
"Argument '" + varName +
"' must be a string or pointer variable.");
47 if (operand.size() != 1) {
48 throw mx::Exception(
"strlen requires exactly 1 argument (string | pointer).");
50 std::string &name = operand[0].op;
52 throw mx::Exception(
"strlen argument must be a declared variable (string | pointer): " + name);
56 const char *src =
nullptr;
67 throw mx::Exception(
"strlen argument '" + v.
var_name +
"' must be string or pointer variable (got different type).");
70 int64_t length =
static_cast<int64_t
>(std::strlen(src));
73 program->
vars[
"%rax"].var_value.int_value = length;
77 if (operand.size() != 2) {
78 throw mx::Exception(
"strcmp requires two pointer/string arguments.");
80 std::string &var1 = operand[0].op;
81 std::string &var2 = operand[1].op;
84 throw mx::Exception(
"strcmp arguments must be variables (pointer or string).");
90 const char *s1 =
nullptr;
91 const char *s2 =
nullptr;
99 throw mx::Exception(
"strcmp first argument must be a pointer or string variable.");
108 throw mx::Exception(
"strcmp second argument must be a pointer or string variable.");
111 int64_t cmp_result = strcmp(s1, s2);
114 program->
vars[
"%rax"].var_value.int_value = cmp_result;
118 if (operand.size() != 3)
125 int64_t n = operand[2].op_value;
132 throw mx::Exception(
"strncpy dest must be pointer or string");
134 throw mx::Exception(
"strncpy src must be pointer or string");
141 std::strncpy(dptr, sptr, n);
148 program->
vars[
"%rax"].var_value.int_value = n;
152 if (operand.size() != 3)
159 int64_t n = operand[2].op_value;
166 throw mx::Exception(
"strncat dest must be pointer or string");
168 throw mx::Exception(
"strncat src must be pointer or string");
183 program->
vars[
"%rax"].var_value.int_value = n;
187 if (operand.size() < 4) {
188 throw mx::Exception(
"snprintf requires at least destination, size, format, and one argument.");
190 std::string &dest_var = operand[0].op;
191 int64_t n = operand[1].op_value;
192 std::string &fmt_var = operand[2].op;
195 throw mx::Exception(
"snprintf destination: " + dest_var +
" and format: " + fmt_var +
" must be variables.");
208 throw mx::Exception(
"snprintf format must be a string variable.");
211 std::ostringstream oss;
221 (format[j] ==
'-' || format[j] ==
'+' || format[j] ==
' ' || format[j] ==
'#' || format[j] ==
'0' ||
222 (format[j] >=
'0' && format[j] <=
'9') || format[j] ==
'.' ||
223 format[j] ==
'l' || format[j] ==
'h' || format[j] ==
'z' || format[j] ==
'j' || format[j] ==
't')) {
233 if (!std::isalpha(format[j])) {
237 std::string spec(format + start, format + j + 1);
238 if (argIndex < operand.size()) {
239 std::string &arg_var = operand[argIndex++].op;
241 throw mx::Exception(
"snprintf argument must be a variable.");
255 std::snprintf(buffer,
sizeof(buffer),
"%s",
"(unsupported)");
269 std::strncpy(
reinterpret_cast<char *
>(dest.
var_value.
ptr_value), oss.str().c_str(), n);
276 throw mx::Exception(
"snprintf destination must be a pointer or string variable.");
281 program->
vars[
"%rax"].var_value.int_value = oss.str().length();
285 if (operand.size() != 3)
286 throw mx::Exception(
"strfind requires (haystack, needle, start)");
292 int64_t start = operand[2].op_value;
299 throw mx::Exception(
"strfind args must be pointer or string");
304 size_t pos = H.find(N, (
size_t)start);
305 int64_t result = (
pos == std::string::npos) ? -1 : (int64_t)
pos;
307 program->
vars[
"%rax"].var_value.int_value = result;
311 if (operand.size() != 5)
319 throw mx::Exception(
"substr dest/src must be pointer or string");
321 int64_t size = operand[1].op_value;
322 int64_t
pos = operand[3].op_value;
323 int64_t len = operand[4].op_value;
334 std::string out = (
pos > (int64_t)S.size()) ?
"" : S.substr((
size_t)
pos, (
size_t)len);
340 std::strncpy(
reinterpret_cast<char *
>(dest.
var_value.
ptr_value), out.c_str(), (
size_t)size);
348 program->
vars[
"%rax"].var_value.int_value = (int64_t)out.size();
352 if (operand.size() == 2 && program->
isVariable(operand[0].op)) {
356 pos = operand[1].op_value;
372 if (operand.size() != 2)
373 throw mx::Exception(
"pos requires 2 arguments: (substr, s)");
378 size_t position = s.find(sub);
379 int64_t result = (position == std::string::npos) ? 0 :
static_cast<int64_t
>(position + 1);
381 program->
vars[
"%rax"].var_value.int_value = result;
386 if (operand.size() != 3)
387 throw mx::Exception(
"copy requires 3 arguments: (s, index, count)");
393 if (index < 1 ||
static_cast<size_t>(index - 1) > s.size()) {
394 throw mx::Exception(
"copy: index " + std::to_string(index) +
" out of bounds for string of length " + std::to_string(s.size()));
399 std::string result_str = s.substr(
static_cast<size_t>(index - 1),
static_cast<size_t>(count));
401 char *new_buf =
static_cast<char *
>(malloc(result_str.length() + 1));
404 strcpy(new_buf, result_str.c_str());
406 program->
vars[
"%rax"].var_value.ptr_value = new_buf;
407 program->
vars[
"%rax"].var_value.ptr_size = 1;
408 program->
vars[
"%rax"].var_value.ptr_count =
static_cast<int64_t
>(result_str.length() + 1);
409 program->
vars[
"%rax"].var_value.owns =
true;
414 if (operand.size() != 3)
415 throw mx::Exception(
"insert requires 3 arguments: (source, dest, index)");
421 if (index < 1 ||
static_cast<size_t>(index - 1) > dest.size()) {
422 throw mx::Exception(
"insert: index " + std::to_string(index) +
" out of bounds for string of length " + std::to_string(dest.size()));
424 dest.insert(
static_cast<size_t>(index - 1), source);
426 char *new_buf =
static_cast<char *
>(malloc(dest.length() + 1));
429 strcpy(new_buf, dest.c_str());
431 program->
vars[
"%rax"].var_value.ptr_value = new_buf;
432 program->
vars[
"%rax"].var_value.ptr_size = 1;
433 program->
vars[
"%rax"].var_value.ptr_count =
static_cast<int64_t
>(dest.length() + 1);
434 program->
vars[
"%rax"].var_value.owns =
true;
439 if (operand.size() != 3)
440 throw mx::Exception(
"delete requires 3 arguments: (s, index, count)");
446 if (index < 1 ||
static_cast<size_t>(index - 1) > s.size()) {
447 throw mx::Exception(
"delete: index " + std::to_string(index) +
" out of bounds for string of length " + std::to_string(s.size()));
452 s.erase(
static_cast<size_t>(index - 1),
static_cast<size_t>(count));
454 char *new_buf =
static_cast<char *
>(malloc(s.length() + 1));
457 strcpy(new_buf, s.c_str());
459 program->
vars[
"%rax"].var_value.ptr_value = new_buf;
460 program->
vars[
"%rax"].var_value.ptr_size = 1;
461 program->
vars[
"%rax"].var_value.ptr_count =
static_cast<int64_t
>(s.length() + 1);
462 program->
vars[
"%rax"].var_value.owns =
true;
478 if (operand.size() != 1)
479 throw mx::Exception(
"inttostr requires 1 argument: (integer)");
482 std::string result_str = std::to_string(val);
484 char *new_buf =
static_cast<char *
>(malloc(result_str.length() + 1));
487 strcpy(new_buf, result_str.c_str());
490 auto &rax = program->
vars[
"%rax"];
492 std::free(rax.var_value.ptr_value);
495 rax.var_value.ptr_value = new_buf;
496 rax.var_value.ptr_size = 1;
497 rax.var_value.ptr_count =
static_cast<int64_t
>(result_str.length() + 1);
498 rax.var_value.owns =
true;
503 if (operand.size() != 1)
504 throw mx::Exception(
"strtoint requires 1 argument: (string)");
509 result = std::stoll(s);
510 }
catch (
const std::exception &e) {
514 program->
vars[
"%rax"].var_value.int_value = result;
General-purpose exception with errno-aware factory method.
std::unordered_map< std::string, Variable > vars
variable symbol table
Complete MXVM program: instruction interpreter and native x64 code generator.
Variable & getVariable(const std::string &name)
Look up a variable by name, searching local scope then global.
bool isVariable(const std::string &name)
Check whether a variable exists in local or global scope.
int64_t pos(const char *substr, const char *s)
Intermediate code representation, execution engine, and native x64 code generation (SysV + Win64).
Instruction set enum, operand/instruction structs, variable types, and Variable/Variable_Value defini...
void except_assert(std::string reason, bool value)
Assert a condition, throwing an Exception with the given reason on failure.
static std::string getStringFromVar(mxvm::Program *program, const std::string &varName)
void mxvm_string_strat(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
static bool isStringLike(mxvm::Variable &v)
void mxvm_string_strfind(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_snprintf(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_strncpy(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_copy(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_strcmp(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_substr(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_insert(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_pos(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_delete(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_strlen(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
void mxvm_string_inttostr(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
Convert an integer to its decimal string representation.
void mxvm_string_strncat(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
static char * asWritePtr(mxvm::Variable &v)
void mxvm_string_strtoint(mxvm::Program *program, std::vector< mxvm::Operand > &operand)
static const char * asReadPtr(mxvm::Variable &v)
uint64_t buffer_size
declared buffer size
A named variable with type, value, and optional object association.