Compare commits

16 Commits

11 changed files with 284 additions and 481 deletions

View File

@@ -75,7 +75,7 @@ build
- [x] String operations - [x] String operations
- [x] Maths - [x] Maths
- [x] Comparisions - [x] Comparisions
- [ ] Type conversions - [x] Type conversions
- [x] Functions - [x] Functions
- [x] Define functions - [x] Define functions
- [x] Call functions - [x] Call functions
@@ -83,7 +83,7 @@ build
- [x] Arguments for functions - [x] Arguments for functions
- [x] Jumping within functions - [x] Jumping within functions
- [x] Custom data structures - [x] Custom data structures
- [ ] Working with external libraries - [x] Working with external libraries
## Debugger ## Debugger
@@ -102,7 +102,7 @@ Commands:
CGround now includes an experimental Ground -> x86_64 Linux ASM compiler. You can try it by adding the `-c` flag when running Ground. This will print the generated ASM to the console. CGround now includes an experimental Ground -> x86_64 Linux ASM compiler. You can try it by adding the `-c` flag when running Ground. This will print the generated ASM to the console.
At present only the `int`, `char`, and `bool` data types are supported. At present only the `int` data type is supported.
Supported instructions so far: Supported instructions so far:

View File

@@ -362,3 +362,23 @@ Looks in the path $GROUND_LIBS/`$libraryName`.grnd for the library. ($GROUND_LIB
Attempts to import a shared library written in a compiled language like C or C++ for usage within the current program. Attempts to import a shared library written in a compiled language like C or C++ for usage within the current program.
Looks in the path $GROUND_LIBS/`$libraryName`.so for the library. ($GROUND_LIBS is a system environment variable.) Looks in the path $GROUND_LIBS/`$libraryName`.so for the library. ($GROUND_LIBS is a system environment variable.)
### Data Structures
#### struct -structName
Creates a new struct which can be initialised. Until the endstruct keyword, the only valid instructions are init, set, fun, endfun, struct, and endstruct.
Any value created inside the struct will be added to the struct.
#### endstruct
Ends the creation of a struct.
#### getfield $object &fieldName &outputVar
Gets a field from an initialised object. fieldName must be a valid name of a field in the object. Errors if the field does not exist.
#### setfield &object &fieldName $value
Sets a field to a new value in the object. The value must be of the same type as the field's old value.

View File

@@ -1,5 +1,6 @@
#ifndef LIBGROUND_H #ifndef LIBGROUND_H
#define LIBGROUND_H #define LIBGROUND_H
#define MAX_ID_LEN 64
/* /*
* groundvm.h * groundvm.h
@@ -13,8 +14,9 @@
#include <stdarg.h> #include <stdarg.h>
#include <uthash.h> #include <uthash.h>
typedef enum GroundInstType { 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, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, 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, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD
} GroundInstType; } GroundInstType;
typedef enum GroundValueType { typedef enum GroundValueType {
@@ -31,6 +33,7 @@ typedef enum ListAccessStatus {
struct GroundValue; struct GroundValue;
struct GroundFunction; struct GroundFunction;
struct GroundStruct;
struct List; struct List;
@@ -59,7 +62,7 @@ typedef struct GroundError {
typedef struct GroundValue { typedef struct GroundValue {
GroundValueType type; GroundValueType type;
struct GroundStruct* customType; struct GroundStruct* customType;
union { struct {
int64_t intVal; int64_t intVal;
double doubleVal; double doubleVal;
char* stringVal; char* stringVal;
@@ -163,6 +166,24 @@ typedef struct GroundObject {
GroundObjectField* fields; GroundObjectField* fields;
} GroundObject; } GroundObject;
typedef struct GroundLabel {
char id[MAX_ID_LEN];
int lineNum;
UT_hash_handle hh;
} GroundLabel;
typedef struct GroundVariable {
char id[MAX_ID_LEN];
GroundValue value;
UT_hash_handle hh;
} GroundVariable;
typedef struct GroundScope {
GroundLabel** labels;
GroundVariable** variables;
bool isMainScope;
} GroundScope;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -178,6 +199,8 @@ void groundAddValueToInstruction(GroundInstruction* inst, GroundValue value);
void groundAddReferenceToInstruction(GroundInstruction* inst, GroundArg value); void groundAddReferenceToInstruction(GroundInstruction* inst, GroundArg value);
GroundArg groundCreateReference(GroundArgType type, char* ref); GroundArg groundCreateReference(GroundArgType type, char* ref);
void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value);
GroundValue groundCreateValue(GroundValueType type, ...); GroundValue groundCreateValue(GroundValueType type, ...);
GroundProgram groundParseFile(const char* code); GroundProgram groundParseFile(const char* code);

View File

@@ -4,7 +4,6 @@
#include "include/estr.h" #include "include/estr.h"
#include <stdint.h> #include <stdint.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
VariableTable createVariableTable() { VariableTable createVariableTable() {
VariableTable vt; VariableTable vt;
@@ -14,7 +13,7 @@ VariableTable createVariableTable() {
return vt; return vt;
} }
void addVtVariable(VariableTable* vt, const char* name, GroundValueType type) { void addVtVariable(VariableTable* vt, const char* name) {
// check if it already exists // check if it already exists
for (size_t i = 0; i < vt->count; i++) { for (size_t i = 0; i < vt->count; i++) {
if (strcmp(vt->vars[i].name, name) == 0) { if (strcmp(vt->vars[i].name, name) == 0) {
@@ -30,20 +29,10 @@ void addVtVariable(VariableTable* vt, const char* name, GroundValueType type) {
// add the variable // add the variable
strcpy(vt->vars[vt->count].name, name); strcpy(vt->vars[vt->count].name, name);
vt->vars[vt->count].type = type;
vt->vars[vt->count].offset = vt->count * 8; vt->vars[vt->count].offset = vt->count * 8;
vt->count++; vt->count++;
} }
VariableInfo* getVariable(VariableTable* vt, const char* name) {
for (size_t i = 0; i < vt->count; i++) {
if (strcmp(vt->vars[i].name, name) == 0) {
return &vt->vars[i];
}
}
return NULL;
}
int getVariablePos(VariableTable* vt, const char* name) { int getVariablePos(VariableTable* vt, const char* name) {
for (size_t i = 0; i < vt->count; i++) { for (size_t i = 0; i < vt->count; i++) {
if (strcmp(vt->vars[i].name, name) == 0) { if (strcmp(vt->vars[i].name, name) == 0) {
@@ -53,318 +42,6 @@ int getVariablePos(VariableTable* vt, const char* name) {
return -1; return -1;
} }
DoubleTable createDoubleTable() {
DoubleTable dt;
dt.count = 0;
dt.capacity = 16;
dt.constants = malloc(sizeof(DoubleConstant) * 16);
return dt;
}
char* addDoubleConstant(DoubleTable* dt, Estr* rodata, double value, int* counter) {
for (size_t i = 0; i < dt->count; i++) {
if (dt->constants[i].value == value) {
return dt->constants[i].label;
}
}
if (dt->count >= dt->capacity) {
dt->capacity = dt->capacity == 0 ? 16 : dt->capacity * 2;
dt->constants = realloc(dt->constants, sizeof(DoubleConstant) * dt->capacity);
}
char label[64];
snprintf(label, sizeof(label), "float_const_%d", (*counter)++);
strcpy(dt->constants[dt->count].label, label);
dt->constants[dt->count].value = value;
dt->count++;
char line[128];
snprintf(line, 128, "%s: dq %.17g ; double constant\n", label, value);
APPEND_ESTR((*rodata), line);
return dt->constants[dt->count - 1].label;
}
GroundValueType getInstructionReturnType(GroundInstruction* gi, VariableTable* table) {
switch (gi->type) {
case JUMP:
case PRINT:
case PRINTLN:
case END:
case IF:
case RETURN:
case ENDFUN:
case PUSHARG:
case CALL: // FIXME do this when functions are added
case USE:
case EXTERN:
case CREATELABEL:
case PAUSE:
case DROP:
case ERRORCMD:
case ENDSTRUCT:
case INIT: // FIXME do this when objects are added
case GETFIELD: // FIXME do this when objects are added
case SETFIELD: // FIXME do this when objects are added
case DIVIDE: // FIXME do this when division is added
case SETLISTAT:
case GETLISTAT: // FIXME do this when lists are getting implemented
case LISTAPPEND: {
return NONE;
}
case TOSTRING:
case GETTYPE:
case INPUT: {
return STRING;
}
case STOI:
case GETLISTSIZE:
case GETSTRSIZE: {
return INT;
}
case STOD: {
return DOUBLE;
}
case EQUAL:
case INEQUAL:
case GREATER:
case LESSER:
case NOT:
case EXISTS: {
return BOOL;
}
case GETSTRCHARAT: {
return CHAR;
}
case SETLIST: {
return LIST;
}
case FUN: {
return FUNCTION;
}
case STRUCT: {
return STRUCTVAL;
}
case SET: {
if (gi->args.length == 2) {
if (gi->args.args[1].type == VALUE) {
return gi->args.args[1].value.value.type;
} else if (gi->args.args[1].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[1].value.refName);
if (var == NULL) {
return NONE;
}
return var->type;
} else {
return NONE;
}
} else {
return NONE;
}
}
case ADD: {
if (gi->args.length == 3) {
GroundValueType leftType;
GroundValueType rightType;
if (gi->args.args[0].type == VALUE) {
leftType = gi->args.args[0].value.value.type;
} else if (gi->args.args[0].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[0].value.refName);
if (var == NULL) {
return NONE;
}
leftType = var->type;
} else {
return NONE;
}
if (gi->args.args[1].type == VALUE) {
rightType = gi->args.args[1].value.value.type;
} else if (gi->args.args[1].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[1].value.refName);
if (var == NULL) {
return NONE;
}
rightType = var->type;
} else {
return NONE;
}
if (leftType == STRING) {
if (rightType == STRING) {
return STRING;
} else {
return NONE;
}
}
if (leftType == DOUBLE) {
if (rightType == DOUBLE || rightType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == DOUBLE) {
if (leftType == DOUBLE || leftType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == INT && leftType == INT) {
return INT;
}
return NONE;
} else {
return NONE;
}
}
case SUBTRACT: {
if (gi->args.length == 3) {
GroundValueType leftType;
GroundValueType rightType;
if (gi->args.args[0].type == VALUE) {
leftType = gi->args.args[0].value.value.type;
} else if (gi->args.args[0].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[0].value.refName);
if (var == NULL) {
return NONE;
}
leftType = var->type;
} else {
return NONE;
}
if (gi->args.args[1].type == VALUE) {
rightType = gi->args.args[1].value.value.type;
} else if (gi->args.args[1].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[1].value.refName);
if (var == NULL) {
return NONE;
}
rightType = var->type;
} else {
return NONE;
}
if (leftType == DOUBLE) {
if (rightType == DOUBLE || rightType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == DOUBLE) {
if (leftType == DOUBLE || leftType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == INT && leftType == INT) {
return INT;
}
return NONE;
} else {
return NONE;
}
}
case MULTIPLY: {
if (gi->args.length == 3) {
GroundValueType leftType;
GroundValueType rightType;
if (gi->args.args[0].type == VALUE) {
leftType = gi->args.args[0].value.value.type;
} else if (gi->args.args[0].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[0].value.refName);
if (var == NULL) {
return NONE;
}
leftType = var->type;
} else {
return NONE;
}
if (gi->args.args[1].type == VALUE) {
rightType = gi->args.args[1].value.value.type;
} else if (gi->args.args[1].type == VALREF) {
VariableInfo* var = getVariable(table, gi->args.args[1].value.refName);
if (var == NULL) {
return NONE;
}
rightType = var->type;
} else {
return NONE;
}
if (leftType == DOUBLE) {
if (rightType == DOUBLE || rightType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == DOUBLE) {
if (leftType == DOUBLE || leftType == INT) {
return DOUBLE;
} else {
return NONE;
}
}
if (rightType == INT && leftType == INT) {
return INT;
}
return NONE;
} else {
return NONE;
}
}
}
return INT;
}
char* processValueString(GroundArg arg, VariableTable* vt, GroundValueType* outType, DoubleTable* dt, Estr* rodata, int* doubleCounter) {
if (arg.type == VALREF) {
VariableInfo* var = getVariable(vt, arg.value.refName);
if (var && outType) *outType = var->type;
char* buf = malloc(260);
snprintf(buf, 260, "[%s]", arg.value.refName);
return buf;
}
if (arg.type == VALUE) {
if (outType) *outType = arg.value.value.type;
switch(arg.value.value.type) {
case INT: {
char* buf = malloc(64);
snprintf(buf, 64, "%" PRId64, arg.value.value.data.intVal);
return buf;
break;
}
case DOUBLE: {
char* label = addDoubleConstant(dt, rodata, arg.value.value.data.doubleVal, doubleCounter);
char* buf = malloc(128);
snprintf(buf, 128, "[rel %s]", label);
return buf;
break;
}
case BOOL:
return arg.value.value.data.boolVal ? "1" : "0";
break;
case CHAR: {
char* buf = malloc(8);
snprintf(buf, 8, "%d", (int)arg.value.value.data.charVal);
return buf;
break;
}
default: {
printf("For now, only int, bool, and char are supported data types in the compiler.");
exit(1);
break;
}
}
}
return NULL;
}
/*
char* processValueString(GroundArg arg) { char* processValueString(GroundArg arg) {
if (arg.type == VALREF) { if (arg.type == VALREF) {
char* buf = malloc(sizeof(char) * 260); char* buf = malloc(sizeof(char) * 260);
@@ -372,43 +49,21 @@ char* processValueString(GroundArg arg) {
return buf; return buf;
} }
if (arg.type == VALUE) { if (arg.type == VALUE) {
switch (arg.value.value.type) { if (arg.value.value.type != INT) {
case INT: { printf("Only int is supported right now\n");
exit(1);
}
char* buf = malloc(sizeof(char) * 64); char* buf = malloc(sizeof(char) * 64);
snprintf(buf, sizeof(char) * 260, "%" PRId64, arg.value.value.data.intVal); snprintf(buf, sizeof(char) * 260, "%" PRId64, arg.value.value.data.intVal);
return buf; return buf;
break;
}
case BOOL: {
return arg.value.value.data.boolVal ? "1" : "0";
break;
}
case CHAR: {
char* buf = malloc(8);
snprintf(buf, 8, "%d", (int) arg.value.value.data.charVal);
return buf;
break;
}
default: {
printf("For now, only int, bool, and char are supported data types in the compiler.");
exit(1);
break;
}
}
} }
return NULL; return NULL;
} }
*/
char* compileGroundProgram(GroundProgram* program) { char* compileGroundProgram(GroundProgram* program) {
Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n");
Estr data = CREATE_ESTR("section .bss\n"); Estr data = CREATE_ESTR("section .bss\n");
Estr helpers = CREATE_ESTR(""); Estr helpers = CREATE_ESTR("");
Estr rodata = CREATE_ESTR("section .rodata\n");
APPEND_ESTR(rodata, " newline_char: db 10\n");
APPEND_ESTR(rodata, " space_char: db 32\n");
DoubleTable doubleTable = createDoubleTable();
int doubleConstCounter = 0;
APPEND_ESTR(helpers, "\n; Helper: Print integer in rax\n"); APPEND_ESTR(helpers, "\n; Helper: Print integer in rax\n");
APPEND_ESTR(helpers, "print_int:\n"); APPEND_ESTR(helpers, "print_int:\n");
@@ -469,7 +124,7 @@ char* compileGroundProgram(GroundProgram* program) {
GroundInstruction gi = program->instructions[i]; GroundInstruction gi = program->instructions[i];
for (size_t j = 0; j < gi.args.length; j++) { for (size_t j = 0; j < gi.args.length; j++) {
if (gi.args.args[j].type == DIRREF) { if (gi.args.args[j].type == DIRREF) {
addVtVariable(&varTable, gi.args.args[j].value.refName, getInstructionReturnType(&gi, &varTable)); addVtVariable(&varTable, gi.args.args[j].value.refName);
} }
} }
} }
@@ -511,7 +166,7 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, " ; set\n") APPEND_ESTR(start, " ; set\n")
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, " mov [");
APPEND_ESTR(start, varName); APPEND_ESTR(start, varName);
@@ -557,7 +212,7 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, " ; if\n"); APPEND_ESTR(start, " ; if\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " test rax, rax\n"); APPEND_ESTR(start, " test rax, rax\n");
APPEND_ESTR(start, " jnz "); APPEND_ESTR(start, " jnz ");
@@ -584,7 +239,7 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, " ; not\n"); APPEND_ESTR(start, " ; not\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " xor rax, 1\n"); APPEND_ESTR(start, " xor rax, 1\n");
APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, " mov [");
@@ -610,55 +265,17 @@ char* compileGroundProgram(GroundProgram* program) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i);
} }
GroundValueType leftType, rightType;
char* left = processValueString(gi.args.args[0], &varTable, &leftType, &doubleTable, &rodata, &doubleConstCounter);
char* right = processValueString(gi.args.args[1], &varTable, &rightType, &doubleTable, &rodata, &doubleConstCounter);
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
bool isDouble = (leftType == DOUBLE || rightType == DOUBLE);
if (isDouble) {
APPEND_ESTR(start, " ; add (double)\n");
if (leftType == INT) {
APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, left);
APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cvtsi2sd xmm0, rax ; Convert int to double\n");
} else {
APPEND_ESTR(start, " movsd xmm0, ");
APPEND_ESTR(start, left);
APPEND_ESTR(start, "\n");
}
if (rightType == INT) {
APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, right);
APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cvtsi2sd xmm1, rax ; Convert int to double\n");
APPEND_ESTR(start, " addsd xmm0, xmm1\n");
} else {
APPEND_ESTR(start, " addsd xmm0, ");
APPEND_ESTR(start, right);
APPEND_ESTR(start, "\n");
}
APPEND_ESTR(start, " movsd [");
APPEND_ESTR(start, varName);
APPEND_ESTR(start, "], xmm0\n");
} else {
APPEND_ESTR(start, " ; add\n"); APPEND_ESTR(start, " ; add\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " add rax, "); APPEND_ESTR(start, " add rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, " mov [");
APPEND_ESTR(start, varName); APPEND_ESTR(start, varName);
APPEND_ESTR(start, "], rax\n"); APPEND_ESTR(start, "], rax\n");
}
break; break;
} }
case SUBTRACT: { case SUBTRACT: {
@@ -681,10 +298,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; subtract\n"); APPEND_ESTR(start, " ; subtract\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " sub rax, "); APPEND_ESTR(start, " sub rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, " mov [");
APPEND_ESTR(start, varName); APPEND_ESTR(start, varName);
@@ -711,10 +328,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; multiply\n"); APPEND_ESTR(start, " ; multiply\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " imul rax, "); APPEND_ESTR(start, " imul rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, " mov [");
APPEND_ESTR(start, varName); APPEND_ESTR(start, varName);
@@ -741,10 +358,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; equal\n"); APPEND_ESTR(start, " ; equal\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, " cmp rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " sete al\n"); APPEND_ESTR(start, " sete al\n");
APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " movzx rax, al\n");
@@ -773,10 +390,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; inequal\n"); APPEND_ESTR(start, " ; inequal\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, " cmp rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " setne al\n"); APPEND_ESTR(start, " setne al\n");
APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " movzx rax, al\n");
@@ -805,10 +422,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; greater\n"); APPEND_ESTR(start, " ; greater\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, " cmp rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " setg al\n"); APPEND_ESTR(start, " setg al\n");
APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " movzx rax, al\n");
@@ -837,10 +454,10 @@ char* compileGroundProgram(GroundProgram* program) {
char* varName= gi.args.args[2].value.refName; char* varName= gi.args.args[2].value.refName;
APPEND_ESTR(start, " ; lesser\n"); APPEND_ESTR(start, " ; lesser\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " cmp rax, "); APPEND_ESTR(start, " cmp rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[1], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[1]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " setl al\n"); APPEND_ESTR(start, " setl al\n");
APPEND_ESTR(start, " movzx rax, al\n"); APPEND_ESTR(start, " movzx rax, al\n");
@@ -870,7 +487,7 @@ char* compileGroundProgram(GroundProgram* program) {
} }
APPEND_ESTR(start, " ; print int\n"); APPEND_ESTR(start, " ; print int\n");
APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[j], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[j]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " call print_int\n"); APPEND_ESTR(start, " call print_int\n");
} }
@@ -895,7 +512,7 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, " ; end\n"); APPEND_ESTR(start, " ; end\n");
APPEND_ESTR(start, " mov rax, 60\n"); APPEND_ESTR(start, " mov rax, 60\n");
APPEND_ESTR(start, " mov rdi, "); APPEND_ESTR(start, " mov rdi, ");
APPEND_ESTR(start, processValueString(gi.args.args[0], &varTable, NULL, &doubleTable, &rodata, &doubleConstCounter)); APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n"); APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " syscall\n"); APPEND_ESTR(start, " syscall\n");
break; break;
@@ -915,8 +532,10 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(complete, start.str); APPEND_ESTR(complete, start.str);
APPEND_ESTR(complete, " ; End of program\n mov rax, 60\n mov rdi, 0\n syscall\n"); APPEND_ESTR(complete, " ; End of program\n mov rax, 60\n mov rdi, 0\n syscall\n");
APPEND_ESTR(complete, helpers.str); APPEND_ESTR(complete, helpers.str);
APPEND_ESTR(complete, data.str); APPEND_ESTR(complete, "\nsection .rodata\n");
APPEND_ESTR(complete, rodata.str); APPEND_ESTR(complete, "newline_char: db 10\n");
APPEND_ESTR(complete, "space_char: db 32\n");
APPEND_ESTR(complete, data.str)
return complete.str; return complete.str;
} }

View File

@@ -7,7 +7,6 @@ char* compileGroundProgram(GroundProgram* program);
typedef struct VariableInfo { typedef struct VariableInfo {
char name[256]; char name[256];
int offset; int offset;
GroundValueType type;
} VariableInfo; } VariableInfo;
typedef struct VariableTable { typedef struct VariableTable {
@@ -16,13 +15,4 @@ typedef struct VariableTable {
size_t capacity; size_t capacity;
} VariableTable; } VariableTable;
typedef struct DoubleConstant {
double value;
char label[64];
} DoubleConstant;
typedef struct DoubleTable {
DoubleConstant* constants;
size_t count;
size_t capacity;
} DoubleTable;

View File

@@ -5,7 +5,9 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _WIN32
#include <dlfcn.h> #include <dlfcn.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h> #include <unistd.h>
@@ -443,6 +445,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs
addInstructionToProgram(&gp, in->instructions[i]); addInstructionToProgram(&gp, in->instructions[i]);
i++; i++;
} }
i--;
GroundFunction* function = parseFunction(&gp, errorOffset); GroundFunction* function = parseFunction(&gp, errorOffset);
function->startLine = i; function->startLine = i;
@@ -509,6 +512,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
addInstructionToProgram(&gp, in->instructions[i]); addInstructionToProgram(&gp, in->instructions[i]);
i++; i++;
} }
i--;
GroundFunction* function = parseFunction(&gp, errorOffset); GroundFunction* function = parseFunction(&gp, errorOffset);
function->startLine = i; function->startLine = i;
@@ -546,6 +550,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
addInstructionToProgram(&gp, in->instructions[i]); addInstructionToProgram(&gp, in->instructions[i]);
i++; i++;
} }
i--;
GroundValue gv = { GroundValue gv = {
.type = STRUCTVAL, .type = STRUCTVAL,
@@ -1104,7 +1109,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (in->args.args[1].type != DIRREF) { if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
} }
addVariable(scope->variables, in->args.args[2].value.refName, createIntGroundValue(atoll(in->args.args[0].value.value.data.stringVal))); addVariable(scope->variables, in->args.args[1].value.refName, createIntGroundValue(atoll(in->args.args[0].value.value.data.stringVal)));
break; break;
} }
case STOD: { case STOD: {
@@ -1120,7 +1125,39 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (in->args.args[1].type != DIRREF) { if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
} }
addVariable(scope->variables, in->args.args[1].value.refName, createIntGroundValue(atof(in->args.args[0].value.value.data.stringVal))); addVariable(scope->variables, in->args.args[1].value.refName, createDoubleGroundValue(atof(in->args.args[0].value.value.data.stringVal)));
break;
}
case ITOC: {
if (in->args.length < 2) {
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
}
if (in->args.length > 2) {
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction);
}
if (in->args.args[0].type != VALUE || in->args.args[0].value.value.type != INT) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", in, currentInstruction);
}
if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
addVariable(scope->variables, in->args.args[1].value.refName, createCharGroundValue((char)in->args.args[0].value.value.data.intVal));
break;
}
case CTOI: {
if (in->args.length < 2) {
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
}
if (in->args.length > 2) {
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction);
}
if (in->args.args[0].type != VALUE || in->args.args[0].value.value.type != CHAR) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Char for arg 1", in, currentInstruction);
}
if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
addVariable(scope->variables, in->args.args[1].value.refName, createIntGroundValue((int)in->args.args[0].value.value.data.charVal));
break; break;
} }
case TOSTRING: { case TOSTRING: {
@@ -1137,57 +1174,53 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
} }
GroundValue* value = &in->args.args[0].value.value; GroundValue* value = &in->args.args[0].value.value;
char buf[256];
switch (value->type) { switch (value->type) {
case INT: { case INT: {
char* buf = malloc(sizeof(char) * 256); snprintf(buf, sizeof(buf) * 256, "%" PRId64, value->data.intVal);
snprintf(buf, sizeof(char) * 256, "%" PRId64, value->data.intVal);
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(buf));
break; break;
} }
case DOUBLE: { case DOUBLE: {
char* buf = malloc(sizeof(char) * 256); snprintf(buf, sizeof(buf) * 256, "%f", value->data.doubleVal);
snprintf(buf, sizeof(char) * 256, "%f", value->data.doubleVal);
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(buf));
break; break;
} }
case STRING: { case STRING: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(value->data.stringVal)); snprintf(buf, sizeof(buf), "%s", value->data.stringVal);
break; break;
} }
case CHAR: { case CHAR: {
char* buf = malloc(sizeof(char) * 2);
buf[0] = value->data.charVal; buf[0] = value->data.charVal;
buf[1] = '\0'; buf[1] = '\0';
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(buf));
break; break;
} }
case BOOL: { case BOOL: {
if (value->data.boolVal) { if (value->data.boolVal) {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("true")); snprintf(buf, sizeof(buf), "true");
} else { } else {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("false")); snprintf(buf, sizeof(buf), "false");
} }
break; break;
} }
case LIST: { case LIST: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("<list>")); snprintf(buf, sizeof(buf), "<list>");
break; break;
} }
case FUNCTION: { case FUNCTION: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("<function>")); snprintf(buf, sizeof(buf), "<function>");
break; break;
} }
case CUSTOM: { case CUSTOM: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("<custom>")); snprintf(buf, sizeof(buf), "<custom>");
break; break;
} }
case NONE: case NONE:
default: { default: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("<default>")); snprintf(buf, sizeof(buf), "<default>");
break; break;
} }
} }
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(buf));
break; break;
} }
@@ -1894,6 +1927,10 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
} }
case EXTERN: { case EXTERN: {
#ifdef _WIN32
runtimeError(FIXME, "No Windows support for extern, sucker", in, currentInstruction);
#endif
#ifndef _WIN32
if (in->args.length < 1) { if (in->args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction); runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction);
} }
@@ -1943,6 +1980,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
} }
initFn(scope); initFn(scope);
#endif
break; break;
} }

View File

@@ -1,6 +1,7 @@
#include "parser.h" #include "parser.h"
#include "interpreter.h" #include "interpreter.h"
#include "compiler.h" #include "compiler.h"
#include "types.h"
#include <stdio.h> #include <stdio.h>
char* getFileContents(const char* filename) { char* getFileContents(const char* filename) {
@@ -40,19 +41,6 @@ char* getFileContents(const char* filename) {
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
/*
if (argc < 2) {
printf("Usage: ground [file]\n");
exit(1);
}
char* file = getFileContents(argv[1]);
GroundProgram program = parseFile(file);
free(file);
char* compiled = compileGroundProgram(&program);
printf("%s\n", compiled);
interpretGroundProgram(&program, NULL);
*/
if (argc < 2) { if (argc < 2) {
printf("Usage: %s <file> [-c] [--compile] [-h] [--help]\n", argv[0]); printf("Usage: %s <file> [-c] [--compile] [-h] [--help]\n", argv[0]);
exit(1); exit(1);
@@ -60,7 +48,7 @@ int main(int argc, char** argv) {
bool compile = false; bool compile = false;
char* fileName = NULL; char* fileName = NULL;
List groundArgs = createList();
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (strcmp("--compile", argv[i]) == 0 || strcmp("-c", argv[i]) == 0) { if (strcmp("--compile", argv[i]) == 0 || strcmp("-c", argv[i]) == 0) {
compile = true; compile = true;
@@ -73,7 +61,11 @@ int main(int argc, char** argv) {
printf(" -h or --help: Shows this help message\n"); printf(" -h or --help: Shows this help message\n");
exit(0); exit(0);
} else { } else {
if (fileName == NULL) {
fileName = argv[i]; fileName = argv[i];
} else {
appendToList(&groundArgs, createStringGroundValue(argv[i]));
}
} }
} }
@@ -91,6 +83,14 @@ int main(int argc, char** argv) {
char* compiled = compileGroundProgram(&program); char* compiled = compileGroundProgram(&program);
printf("%s\n", compiled); printf("%s\n", compiled);
} else { } else {
interpretGroundProgram(&program, NULL); GroundVariable* variables = NULL;
GroundLabel* labels = NULL;
GroundScope scope;
scope.variables = &variables;
scope.labels = &labels;
scope.isMainScope = true;
addVariable(scope.variables, "CMDLINE_ARGS", createListGroundValue(groundArgs));
interpretGroundProgram(&program, &scope);
} }
} }

View File

@@ -5,6 +5,25 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifdef _WIN32
size_t strnlen(const char *src, size_t n) {
size_t len = 0;
while (len < n && src[len])
len++;
return len;
}
char* strndup(const char *s, size_t n) {
size_t len = strnlen(s, n);
char *p = malloc(len + 1);
if (p) {
memcpy(p, s, len);
p[len] = '\0';
}
return p;
}
#endif
GroundProgram createGroundProgram() { GroundProgram createGroundProgram() {
GroundProgram gp; GroundProgram gp;
gp.size = 0; gp.size = 0;
@@ -159,6 +178,8 @@ static GroundInstType getInstructionType(const char* inst) {
if (strcmp(inst, "lesser") == 0) return LESSER; if (strcmp(inst, "lesser") == 0) return LESSER;
if (strcmp(inst, "stoi") == 0) return STOI; if (strcmp(inst, "stoi") == 0) return STOI;
if (strcmp(inst, "stod") == 0) return STOD; if (strcmp(inst, "stod") == 0) return STOD;
if (strcmp(inst, "ctoi") == 0) return CTOI;
if (strcmp(inst, "itoc") == 0) return ITOC;
if (strcmp(inst, "tostring") == 0) return TOSTRING; if (strcmp(inst, "tostring") == 0) return TOSTRING;
if (strcmp(inst, "fun") == 0) return FUN; if (strcmp(inst, "fun") == 0) return FUN;
if (strcmp(inst, "return") == 0) return RETURN; if (strcmp(inst, "return") == 0) return RETURN;

View File

@@ -90,16 +90,55 @@ GroundValue copyGroundValue(const GroundValue* gv) {
} }
case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break; case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break;
case STRUCTVAL: { case STRUCTVAL: {
// do this later lmao newGv.data.structVal = malloc(sizeof(GroundStruct));
// FIXME if (newGv.data.structVal == NULL) {
newGv.data.structVal = gv->data.structVal; printf("Couldn't allocate memory for GroundStruct copy\n");
exit(1);
}
newGv.data.structVal->size = gv->data.structVal->size;
newGv.data.structVal->fields = malloc(gv->data.structVal->size * sizeof(GroundStructField));
if (newGv.data.structVal->fields == NULL && gv->data.structVal->size > 0) {
printf("Couldn't allocate memory for GroundStruct fields copy\n");
exit(1);
}
for (size_t i = 0; i < gv->data.structVal->size; i++) {
strncpy(newGv.data.structVal->fields[i].id,
gv->data.structVal->fields[i].id,
sizeof(newGv.data.structVal->fields[i].id) - 1);
newGv.data.structVal->fields[i].id[sizeof(newGv.data.structVal->fields[i].id) - 1] = '\0';
newGv.data.structVal->fields[i].value = copyGroundValue(&gv->data.structVal->fields[i].value);
}
break; break;
} }
case CUSTOM: case CUSTOM: {
// also do this later newGv.customType = gv->customType;
// FIXME newGv.data.customVal = malloc(sizeof(GroundObject));
newGv.data.customVal = gv->data.customVal; if (newGv.data.customVal == NULL) {
printf("Couldn't allocate memory for GroundObject copy\n");
exit(1);
}
newGv.data.customVal->fields = NULL;
GroundObjectField *field, *tmp;
HASH_ITER(hh, gv->data.customVal->fields, field, tmp) {
GroundObjectField* newField = malloc(sizeof(GroundObjectField));
if (newField == NULL) {
printf("Couldn't allocate memory for GroundObjectField copy\n");
exit(1);
}
strncpy(newField->id, field->id, sizeof(newField->id) - 1);
newField->id[sizeof(newField->id) - 1] = '\0';
newField->value = copyGroundValue(&field->value);
HASH_ADD_STR(newGv.data.customVal->fields, id, newField);
}
break; break;
}
case NONE: case NONE:
default: { default: {
@@ -149,8 +188,47 @@ void printGroundValue(GroundValue* gv) {
printf("<function>"); printf("<function>");
break; break;
} }
default: { case STRUCTVAL: {
printf("FIXME"); printf("<struct fields: { ");
for (size_t i = 0; i < gv->data.structVal->size; i++) {
if (i != 0) {
printf(", ");
}
printf("%s: ", gv->data.structVal->fields[i].id);
if (gv->data.structVal->fields[i].value.type == STRING) {
printf("\"");
printGroundValue(&gv->data.structVal->fields[i].value);
printf("\"");
} else {
printGroundValue(&gv->data.structVal->fields[i].value);
}
}
printf(" }>");
break;
}
case CUSTOM: {
printf("<object fields: { ");
for (size_t i = 0; i < gv->customType->size; i++) {
if (i != 0) {
printf(", ");
}
printf("%s: ", gv->customType->fields[i].id);
GroundObjectField* field = findField(*gv->data.customVal, gv->customType->fields[i].id);
if (field == NULL) {
printf("<missing>");
} else {
printGroundValue(&field->value);
}
}
printf(" }>");
break;
}
case ERROR: {
printf("<error type: %s, what: %s>", gv->data.errorVal.type, gv->data.errorVal.what);
break;
}
case NONE: {
printf("<none>");
break; break;
} }
} }
@@ -374,6 +452,12 @@ void printGroundInstruction(GroundInstruction* gi) {
case STOD: case STOD:
printf("stod"); printf("stod");
break; break;
case CTOI:
printf("ctoi");
break;
case ITOC:
printf("itoc");
break;
case TOSTRING: case TOSTRING:
printf("tostring"); printf("tostring");
break; break;

View File

@@ -9,7 +9,7 @@
#include "include/uthash.h" #include "include/uthash.h"
typedef enum GroundInstType { 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, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, 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, STOI, STOD, ITOC, CTOI, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD
} GroundInstType; } GroundInstType;
typedef enum GroundValueType { typedef enum GroundValueType {
@@ -63,7 +63,7 @@ typedef struct GroundError {
typedef struct GroundValue { typedef struct GroundValue {
GroundValueType type; GroundValueType type;
struct GroundStruct* customType; struct GroundStruct* customType;
union { struct {
int64_t intVal; int64_t intVal;
double doubleVal; double doubleVal;
char* stringVal; char* stringVal;

View File

@@ -1,3 +1,11 @@
tostring 32 &int tostring 32 &str
stoi "12" &int
stod "3.14" &dou
itoc 353 &chr
ctoi 'a' &it2
println $str
println $int println $int
println $dou
println $chr
println $it2