2026-01-21 11:17:19 +11:00
|
|
|
#include "compiler.h"
|
|
|
|
|
#include "types.h"
|
2026-04-11 09:49:14 +10:00
|
|
|
#include "include/uthash.h"
|
2026-01-21 13:25:13 +11:00
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
#include <tram.h>
|
2026-01-21 13:25:13 +11:00
|
|
|
|
2026-04-11 09:49:14 +10:00
|
|
|
// Helper macros to reduce repetition
|
|
|
|
|
#define CHECK_ARGC(expected) \
|
|
|
|
|
if (instruction->args.length != (expected)) { \
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu (%s): expected %d argument(s), got %zu\n", \
|
|
|
|
|
i, #expected, (expected), instruction->args.length); \
|
|
|
|
|
return false; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define CHECK_ARGC_MIN(min) \
|
|
|
|
|
if (instruction->args.length < (min)) { \
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu: expected at least %d argument(s), got %zu\n", \
|
|
|
|
|
i, (min), instruction->args.length); \
|
|
|
|
|
return false; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define CHECK_ARG_TYPE(idx, expected_type) \
|
|
|
|
|
if (instruction->args.args[(idx)].type != (expected_type)) { \
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu: argument %d should be " #expected_type ", got %d\n", \
|
|
|
|
|
i, (idx), instruction->args.args[(idx)].type); \
|
|
|
|
|
return false; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool checkForErrors(GroundProgram* program) {
|
|
|
|
|
for (size_t i = 0; i < program->size; i++) {
|
|
|
|
|
GroundInstruction* instruction = &program->instructions[i];
|
|
|
|
|
switch (instruction->type) {
|
|
|
|
|
|
|
|
|
|
// if $condition %label
|
|
|
|
|
case IF:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, LINEREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// jump %label
|
|
|
|
|
case JUMP:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, LINEREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// end $status
|
|
|
|
|
case END:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// input &variable
|
|
|
|
|
case INPUT:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// print $value
|
|
|
|
|
case PRINT:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// println $value
|
|
|
|
|
case PRINTLN:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// set &variable $value
|
|
|
|
|
case SET:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// gettype $value &variable
|
|
|
|
|
case GETTYPE:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// exists &variable &output
|
|
|
|
|
case EXISTS:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// setlist &varname $val1 $val2 ... (at least 1 arg, rest are valrefs)
|
|
|
|
|
case SETLIST:
|
|
|
|
|
CHECK_ARGC_MIN(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
for (size_t j = 1; j < instruction->args.length; j++) {
|
|
|
|
|
if (instruction->args.args[j].type != VALREF) {
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu (SETLIST): argument %zu should be VALREF, got %d\n",
|
|
|
|
|
i, j, instruction->args.args[j].type);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// setlistat &listname $index $value
|
|
|
|
|
case SETLISTAT:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// getlistat &list $index &variable
|
|
|
|
|
case GETLISTAT:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// getlistsize &list &variable
|
|
|
|
|
case GETLISTSIZE:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// listappend $value &list
|
|
|
|
|
case LISTAPPEND:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// getstrsize $string &variable
|
|
|
|
|
case GETSTRSIZE:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// getstrcharat $string $index &variable
|
|
|
|
|
case GETSTRCHARAT:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// add $value $value &variable
|
|
|
|
|
case ADD:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// subtract $value $value &variable
|
|
|
|
|
case SUBTRACT:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// multiply $value $value &variable
|
|
|
|
|
case MULTIPLY:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// divide $value $value &variable
|
|
|
|
|
case DIVIDE:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// equal $value $value &variable
|
|
|
|
|
case EQUAL:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// inequal $value $value &variable
|
|
|
|
|
case INEQUAL:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// not $value &variable
|
|
|
|
|
case NOT:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// greater $value $value &variable
|
|
|
|
|
case GREATER:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// lesser $value $value &variable
|
|
|
|
|
case LESSER:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// stoi $value &variable
|
|
|
|
|
case STOI:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// stod $value &variable
|
|
|
|
|
case STOD:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// itoc, ctoi $value &variable
|
|
|
|
|
case ITOC:
|
|
|
|
|
case CTOI:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// tostring $value &variable
|
|
|
|
|
case TOSTRING:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// fun !functionName -returnType [-argType &arg ...]
|
|
|
|
|
// Minimum 2 args: the function ref and return type
|
|
|
|
|
case FUN:
|
|
|
|
|
CHECK_ARGC_MIN(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, FNREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, TYPEREF);
|
|
|
|
|
// Remaining args must be alternating TYPEREF, DIRREF pairs
|
|
|
|
|
if ((instruction->args.length - 2) % 2 != 0) {
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu (FUN): argument pairs after return type must be -type &name pairs\n", i);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (size_t j = 2; j < instruction->args.length; j += 2) {
|
|
|
|
|
CHECK_ARG_TYPE(j, TYPEREF);
|
|
|
|
|
CHECK_ARG_TYPE(j + 1, DIRREF);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// return $value
|
|
|
|
|
case RETURN:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// endfun - no args
|
|
|
|
|
case ENDFUN:
|
|
|
|
|
CHECK_ARGC(0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// call !function [$arg1 $arg2 ...] &returnVal
|
|
|
|
|
// Minimum 2 args: function ref and return variable
|
|
|
|
|
case CALL:
|
|
|
|
|
CHECK_ARGC_MIN(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, FNREF);
|
|
|
|
|
// Middle args are valrefs, last arg is dirref
|
|
|
|
|
for (size_t j = 1; j < instruction->args.length - 1; j++) {
|
|
|
|
|
if (instruction->args.args[j].type != VALREF) {
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu (CALL): argument %zu should be VALREF, got %d\n",
|
|
|
|
|
i, j, instruction->args.args[j].type);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CHECK_ARG_TYPE(instruction->args.length - 1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
2026-04-11 10:42:53 +10:00
|
|
|
// callmethod &object !methodName [$arg1 $arg2 ...] &returnVal
|
2026-04-11 09:49:14 +10:00
|
|
|
// Minimum 3 args: object ref, method name, return variable
|
|
|
|
|
case CALLMETHOD:
|
|
|
|
|
CHECK_ARGC_MIN(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, FNREF);
|
|
|
|
|
// Middle args are valrefs, last arg is dirref
|
|
|
|
|
for (size_t j = 2; j < instruction->args.length - 1; j++) {
|
|
|
|
|
if (instruction->args.args[j].type != VALREF) {
|
|
|
|
|
fprintf(stderr, "Error at instruction %zu (CALL): argument %zu should be VALREF, got %d\n",
|
|
|
|
|
i, j, instruction->args.args[j].type);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CHECK_ARG_TYPE(instruction->args.length - 1, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// struct -structName
|
|
|
|
|
case STRUCT:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, TYPEREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// endstruct - no args
|
|
|
|
|
case ENDSTRUCT:
|
|
|
|
|
CHECK_ARGC(0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// init &var -type
|
|
|
|
|
case INIT:
|
|
|
|
|
CHECK_ARGC(2);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, TYPEREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// getfield $object &fieldName &outputVar
|
|
|
|
|
case GETFIELD:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// setfield &object &fieldName $value
|
|
|
|
|
case SETFIELD:
|
|
|
|
|
CHECK_ARGC(3);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(1, DIRREF);
|
|
|
|
|
CHECK_ARG_TYPE(2, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// use $libraryName
|
|
|
|
|
case USE:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// extern $libraryName
|
|
|
|
|
case EXTERN:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, VALREF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// createlabel @label
|
|
|
|
|
case CREATELABEL:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, LABEL);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// pause, licence - no args
|
|
|
|
|
case PAUSE:
|
|
|
|
|
case LICENSE:
|
|
|
|
|
break;
|
|
|
|
|
// drop &variable
|
|
|
|
|
case DROP:
|
|
|
|
|
CHECK_ARGC(1);
|
|
|
|
|
CHECK_ARG_TYPE(0, DIRREF);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
void compileGroundProgram(GroundProgram* program, char* name) {
|
2026-04-11 09:49:14 +10:00
|
|
|
|
|
|
|
|
if (!checkForErrors(program)) {
|
|
|
|
|
printf("Error: Invalid program\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
Tram_Program tramProgram = Tram_Program_Create();
|
2026-01-21 13:25:13 +11:00
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
|
|
|
|
|
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
|
2026-01-21 13:25:13 +11:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < program->size; i++) {
|
2026-04-10 17:43:51 +10:00
|
|
|
compileGroundInstruction(&program->instructions[i], &tramProgram);
|
2026-01-21 13:25:13 +11:00
|
|
|
}
|
2026-01-21 11:17:19 +11:00
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
Tram_Compiler* compiler = Tram_Compiler_Create(tramProgram);
|
|
|
|
|
Tram_Compiler_SetLogLevel(compiler, Tram_LogLevel_Debug);
|
|
|
|
|
Tram_Compiler_SetTarget(compiler, Tram_Target_x86_64_Linux_libc);
|
|
|
|
|
Tram_Compiler_Compile(compiler);
|
2026-01-21 13:25:13 +11:00
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
if (Tram_Compiler_HasCompiled(compiler)) {
|
|
|
|
|
Tram_Compiler_AssembleAndLink(compiler, name, (Tram_LinkerArgs){.size = 0, .data = NULL});
|
|
|
|
|
} else {
|
|
|
|
|
printf("Compilation failed\n");
|
|
|
|
|
exit(EXIT_FAILURE);
|
2026-01-21 11:17:19 +11:00
|
|
|
}
|
|
|
|
|
|
2026-04-10 17:43:51 +10:00
|
|
|
}
|
|
|
|
|
|
2026-04-11 09:49:14 +10:00
|
|
|
typedef struct GroundCompilerVariable {
|
|
|
|
|
GroundValueType type;
|
|
|
|
|
char id[MAX_ID_LEN];
|
|
|
|
|
UT_hash_handle hh;
|
|
|
|
|
} GroundCompilerVariable;
|
|
|
|
|
|
|
|
|
|
typedef struct GroundState {
|
|
|
|
|
GroundCompilerVariable* variables;
|
|
|
|
|
GroundLabel* labels;
|
|
|
|
|
} GroundState;
|
|
|
|
|
|
|
|
|
|
GroundState createGroundState() {
|
|
|
|
|
GroundState state = {
|
|
|
|
|
.variables = NULL,
|
|
|
|
|
.labels = NULL
|
|
|
|
|
};
|
|
|
|
|
return state;
|
|
|
|
|
}
|
2026-01-21 11:17:19 +11:00
|
|
|
|
2026-04-11 09:49:14 +10:00
|
|
|
GroundCompilerVariable* cFindVariable(GroundState* state, const char* id) {
|
|
|
|
|
GroundCompilerVariable* var;
|
|
|
|
|
HASH_FIND_STR(state->variables, id, var);
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GroundCompilerVariable* cDeleteVariable(GroundState* state, const char* id) {
|
|
|
|
|
GroundCompilerVariable* var;
|
|
|
|
|
HASH_FIND_STR(state->variables, id, var);
|
|
|
|
|
HASH_DEL(state->variables, var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GroundCompilerVariable* cAddVariable(GroundState* state, const char* id, GroundValueType type) {
|
|
|
|
|
GroundCompilerVariable* var = malloc(sizeof(GroundCompilerVariable));
|
|
|
|
|
snprintf(var->id, MAX_ID_LEN, "%s", id);
|
|
|
|
|
var->type = type;
|
|
|
|
|
HASH_ADD_STR(state->variables, id, var);
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program) {
|
|
|
|
|
switch (instruction->type) {
|
|
|
|
|
case IF:
|
|
|
|
|
break;
|
|
|
|
|
case JUMP:
|
|
|
|
|
break;
|
|
|
|
|
case END:
|
|
|
|
|
break;
|
|
|
|
|
case INPUT:
|
|
|
|
|
break;
|
|
|
|
|
case PRINT:
|
|
|
|
|
break;
|
|
|
|
|
case PRINTLN:
|
|
|
|
|
break;
|
|
|
|
|
case SET:
|
|
|
|
|
break;
|
|
|
|
|
case GETTYPE:
|
|
|
|
|
break;
|
|
|
|
|
case EXISTS:
|
|
|
|
|
break;
|
|
|
|
|
case SETLIST:
|
|
|
|
|
break;
|
|
|
|
|
case SETLISTAT:
|
|
|
|
|
break;
|
|
|
|
|
case GETLISTAT:
|
|
|
|
|
break;
|
|
|
|
|
case GETLISTSIZE:
|
|
|
|
|
break;
|
|
|
|
|
case LISTAPPEND:
|
|
|
|
|
break;
|
|
|
|
|
case GETSTRSIZE:
|
|
|
|
|
break;
|
|
|
|
|
case GETSTRCHARAT:
|
|
|
|
|
break;
|
|
|
|
|
case ADD:
|
|
|
|
|
break;
|
|
|
|
|
case SUBTRACT:
|
|
|
|
|
break;
|
|
|
|
|
case MULTIPLY:
|
|
|
|
|
break;
|
|
|
|
|
case DIVIDE:
|
|
|
|
|
break;
|
|
|
|
|
case EQUAL:
|
|
|
|
|
break;
|
|
|
|
|
case INEQUAL:
|
|
|
|
|
break;
|
|
|
|
|
case NOT:
|
|
|
|
|
break;
|
|
|
|
|
case GREATER:
|
|
|
|
|
break;
|
|
|
|
|
case LESSER:
|
|
|
|
|
break;
|
|
|
|
|
case AND:
|
|
|
|
|
break;
|
|
|
|
|
case OR:
|
|
|
|
|
break;
|
|
|
|
|
case XOR:
|
|
|
|
|
break;
|
|
|
|
|
case NEG:
|
|
|
|
|
break;
|
|
|
|
|
case SHIFT:
|
|
|
|
|
break;
|
|
|
|
|
case STOI:
|
|
|
|
|
break;
|
|
|
|
|
case STOD:
|
|
|
|
|
break;
|
|
|
|
|
case ITOC:
|
|
|
|
|
break;
|
|
|
|
|
case CTOI:
|
|
|
|
|
break;
|
|
|
|
|
case TOSTRING:
|
|
|
|
|
break;
|
|
|
|
|
case FUN:
|
|
|
|
|
break;
|
|
|
|
|
case RETURN:
|
|
|
|
|
break;
|
|
|
|
|
case ENDFUN:
|
|
|
|
|
break;
|
|
|
|
|
case PUSHARG:
|
|
|
|
|
break;
|
|
|
|
|
case CALL:
|
|
|
|
|
break;
|
|
|
|
|
case STRUCT:
|
|
|
|
|
break;
|
|
|
|
|
case ENDSTRUCT:
|
|
|
|
|
break;
|
|
|
|
|
case INIT:
|
|
|
|
|
break;
|
|
|
|
|
case GETFIELD:
|
|
|
|
|
break;
|
|
|
|
|
case SETFIELD:
|
|
|
|
|
break;
|
|
|
|
|
case USE:
|
|
|
|
|
break;
|
|
|
|
|
case EXTERN:
|
|
|
|
|
break;
|
|
|
|
|
case CREATELABEL: {
|
|
|
|
|
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
|
|
|
|
|
Tram_Program_AddInstruction(program, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case PAUSE:
|
|
|
|
|
break;
|
|
|
|
|
case DROP:
|
|
|
|
|
break;
|
|
|
|
|
case LICENSE:
|
|
|
|
|
break;
|
|
|
|
|
case ERRORCMD:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-01-21 11:17:19 +11:00
|
|
|
}
|