forked from ground/ground
Continue work on compiler
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
typedef enum GroundInstType {
|
||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, AND, OR, XOR, NEG, SHIFT, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, LICENSE, ERRORCMD
|
||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, AND, OR, XOR, NEG, SHIFT, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, CALLMETHOD, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, LICENSE, ERRORCMD
|
||||
} GroundInstType;
|
||||
|
||||
typedef enum GroundValueType {
|
||||
|
||||
526
src/compiler.c
526
src/compiler.c
@@ -1,9 +1,386 @@
|
||||
#include "compiler.h"
|
||||
#include "types.h"
|
||||
#include "include/uthash.h"
|
||||
|
||||
#include <tram.h>
|
||||
|
||||
// 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;
|
||||
|
||||
// call &object !methodName [$arg1 $arg2 ...] &returnVal
|
||||
// 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;
|
||||
}
|
||||
|
||||
void compileGroundProgram(GroundProgram* program, char* name) {
|
||||
|
||||
if (!checkForErrors(program)) {
|
||||
printf("Error: Invalid program\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Tram_Program tramProgram = Tram_Program_Create();
|
||||
|
||||
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
|
||||
@@ -27,6 +404,153 @@ void compileGroundProgram(GroundProgram* program, char* name) {
|
||||
|
||||
}
|
||||
|
||||
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ void wasm_print(const char* str);
|
||||
#endif
|
||||
|
||||
typedef enum GroundInstType {
|
||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, AND, OR, XOR, NEG, SHIFT, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, LICENSE, ERRORCMD
|
||||
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, AND, OR, XOR, NEG, SHIFT, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, CALLMETHOD, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, LICENSE, ERRORCMD
|
||||
} GroundInstType;
|
||||
|
||||
typedef enum GroundValueType {
|
||||
|
||||
Reference in New Issue
Block a user