Compare commits

23 Commits

Author SHA1 Message Date
d011d2beb4 Expose GroundScope struct 2026-02-02 13:07:02 +11:00
e3702f46f3 Command line arguments via CMDLINE_ARGS list var 2026-01-31 09:08:38 +11:00
ca861f7e4b Copy custom values and structs properly 2026-01-27 14:10:12 +11:00
9796e309cf Fix the header file 2026-01-25 20:53:24 +11:00
a18479b21c It compiles on windows now I guess 2026-01-25 14:38:37 +11:00
b502184478 Merge pull request 'More type conversions' (#19) from DiamondNether90/cground:master into master
Reviewed-on: #19
2026-01-25 13:12:42 +11:00
b348ca7626 More type conversions 2026-01-24 18:18:52 +11:00
1570177de1 Fix type conversions 2026-01-24 16:36:37 +11:00
2da11f854d Struct and object printing 2026-01-24 16:23:01 +11:00
337c6ada24 Actually fix the bug 2026-01-24 15:46:09 +11:00
bb0baba167 Fix bug when defining functions and structs 2026-01-24 15:05:05 +11:00
ca0b87aacd Update docs 2026-01-23 15:30:12 +11:00
e8c49508a0 Band-aid fix for structs, use more memory :\ 2026-01-23 13:48:18 +11:00
68182d916e Satisfy Leo's thirst for structs and extlibs 2026-01-22 20:58:49 +11:00
3f684dad3f I'm tired of ragebaiting Leo 2026-01-22 20:40:27 +11:00
03aab86413 Fix the fix? 2026-01-22 20:36:19 +11:00
c382ecd867 Fix the header again 2026-01-22 10:50:48 +11:00
228d2ac762 I forgot the header again lmao 2026-01-21 18:59:24 +11:00
b289448f56 Add struct field access 2026-01-21 18:41:24 +11:00
a3ca979133 Add not to compiler 2026-01-21 16:02:13 +11:00
3e9ce0dfc0 Expose compiler in groundvm.h 2026-01-21 15:54:18 +11:00
063e85d24a Merge pull request 'Add compiler' (#14) from unstable into master
Reviewed-on: #14
2026-01-21 15:53:20 +11:00
07474d4317 Add print and println to compiler 2026-01-21 15:20:00 +11:00
12 changed files with 470 additions and 52 deletions

View File

@@ -75,15 +75,15 @@ 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
- [x] Return values (type checked) - [x] Return values (type checked)
- [x] Arguments for functions - [x] Arguments for functions
- [x] Jumping within functions - [x] Jumping within functions
- [ ] Custom data structures - [x] Custom data structures
- [ ] Working with external libraries - [x] Working with external libraries
## Debugger ## Debugger
@@ -114,7 +114,10 @@ Supported instructions so far:
* inequal * inequal
* greater * greater
* lesser * lesser
* not
* jump * jump
* if * if
* @ (label creation) * @ (label creation)
* print
* println
* end * end

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, 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;
@@ -58,7 +61,8 @@ typedef struct GroundError {
*/ */
typedef struct GroundValue { typedef struct GroundValue {
GroundValueType type; GroundValueType type;
union { struct GroundStruct* customType;
struct {
int64_t intVal; int64_t intVal;
double doubleVal; double doubleVal;
char* stringVal; char* stringVal;
@@ -162,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
@@ -170,12 +192,15 @@ GroundProgram groundCreateProgram();
void groundAddInstructionToProgram(GroundProgram* program, GroundInstruction instruction); void groundAddInstructionToProgram(GroundProgram* program, GroundInstruction instruction);
GroundValue groundRunProgram(GroundProgram* program); GroundValue groundRunProgram(GroundProgram* program);
void groundPrintProgram(GroundProgram* program); void groundPrintProgram(GroundProgram* program);
char* groundCompileProgram(GroundProgram* program);
GroundInstruction groundCreateInstruction(GroundInstType type); GroundInstruction groundCreateInstruction(GroundInstType type);
void groundAddValueToInstruction(GroundInstruction* inst, GroundValue value); 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

@@ -50,7 +50,7 @@ char* processValueString(GroundArg arg) {
} }
if (arg.type == VALUE) { if (arg.type == VALUE) {
if (arg.value.value.type != INT) { if (arg.value.value.type != INT) {
printf("Only int is supported right now"); printf("Only int is supported right now\n");
exit(1); exit(1);
} }
char* buf = malloc(sizeof(char) * 64); char* buf = malloc(sizeof(char) * 64);
@@ -63,6 +63,59 @@ char* processValueString(GroundArg arg) {
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("");
APPEND_ESTR(helpers, "\n; Helper: Print integer in rax\n");
APPEND_ESTR(helpers, "print_int:\n");
APPEND_ESTR(helpers, " push rbp\n");
APPEND_ESTR(helpers, " mov rbp, rsp\n");
APPEND_ESTR(helpers, " sub rsp, 32 ; Allocate buffer on stack\n");
APPEND_ESTR(helpers, " mov rdi, rsp ; RDI = buffer pointer\n");
APPEND_ESTR(helpers, " add rdi, 31 ; Point to end of buffer\n");
APPEND_ESTR(helpers, " mov byte [rdi], 0 ; Null terminator\n");
APPEND_ESTR(helpers, " dec rdi\n");
APPEND_ESTR(helpers, " mov rbx, 10 ; Divisor\n");
APPEND_ESTR(helpers, " test rax, rax\n");
APPEND_ESTR(helpers, " jns .positive\n");
APPEND_ESTR(helpers, " neg rax ; Make positive\n");
APPEND_ESTR(helpers, " push rax\n");
APPEND_ESTR(helpers, " mov byte [rdi], '-'\n");
APPEND_ESTR(helpers, " dec rdi\n");
APPEND_ESTR(helpers, " pop rax\n");
APPEND_ESTR(helpers, ".positive:\n");
APPEND_ESTR(helpers, " xor rcx, rcx ; Digit counter\n");
APPEND_ESTR(helpers, ".convert_loop:\n");
APPEND_ESTR(helpers, " xor rdx, rdx\n");
APPEND_ESTR(helpers, " div rbx ; rax = rax/10, rdx = remainder\n");
APPEND_ESTR(helpers, " add dl, '0' ; Convert to ASCII\n");
APPEND_ESTR(helpers, " mov [rdi], dl\n");
APPEND_ESTR(helpers, " dec rdi\n");
APPEND_ESTR(helpers, " inc rcx\n");
APPEND_ESTR(helpers, " test rax, rax\n");
APPEND_ESTR(helpers, " jnz .convert_loop\n");
APPEND_ESTR(helpers, " inc rdi ; Point back to first digit\n");
APPEND_ESTR(helpers, " ; Now print the string\n");
APPEND_ESTR(helpers, " mov rax, 1 ; sys_write\n");
APPEND_ESTR(helpers, " mov rsi, rdi ; Buffer\n");
APPEND_ESTR(helpers, " mov rdx, rcx ; Length\n");
APPEND_ESTR(helpers, " mov rdi, 1 ; stdout\n");
APPEND_ESTR(helpers, " syscall\n");
APPEND_ESTR(helpers, " mov rsp, rbp\n");
APPEND_ESTR(helpers, " pop rbp\n");
APPEND_ESTR(helpers, " ret\n");
APPEND_ESTR(helpers, "\n; Helper: Print string at address in rax, length in rbx\n");
APPEND_ESTR(helpers, "print_string:\n");
APPEND_ESTR(helpers, " push rax\n");
APPEND_ESTR(helpers, " push rbx\n");
APPEND_ESTR(helpers, " mov rdi, 1 ; stdout\n");
APPEND_ESTR(helpers, " mov rsi, rax ; String address\n");
APPEND_ESTR(helpers, " mov rdx, rbx ; Length\n");
APPEND_ESTR(helpers, " mov rax, 1 ; sys_write\n");
APPEND_ESTR(helpers, " syscall\n");
APPEND_ESTR(helpers, " pop rbx\n");
APPEND_ESTR(helpers, " pop rax\n");
APPEND_ESTR(helpers, " ret\n");
VariableTable varTable = createVariableTable(); VariableTable varTable = createVariableTable();
@@ -77,7 +130,7 @@ char* compileGroundProgram(GroundProgram* program) {
} }
// Create data section // Create data section
for (size_t i = 0; i < program->size; i++) { for (size_t i = 0; i < varTable.count; i++) {
if (strcmp(varTable.vars[i].name, "") == 0) { if (strcmp(varTable.vars[i].name, "") == 0) {
continue; continue;
} }
@@ -168,6 +221,33 @@ char* compileGroundProgram(GroundProgram* program) {
break; break;
} }
case NOT: {
if (gi.args.length < 2) {
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i);
}
if (gi.args.length > 2) {
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &gi, i);
}
if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int (for now) for arg 1", &gi, i);
}
if (gi.args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef", &gi, i);
}
char* varName = gi.args.args[1].value.refName;
APPEND_ESTR(start, " ; not\n");
APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[0]));
APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " xor rax, 1\n");
APPEND_ESTR(start, " mov [");
APPEND_ESTR(start, varName);
APPEND_ESTR(start, "], rax\n");
break;
}
case ADD: { case ADD: {
if (gi.args.length < 3) { if (gi.args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i); runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i);
@@ -386,6 +466,42 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, "], rax\n"); APPEND_ESTR(start, "], rax\n");
break; break;
} }
case PRINT:
case PRINTLN: {
if (gi.args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &gi, i);
}
for (size_t j = 0; j < gi.args.length; j++) {
if (gi.args.args[j].type != VALUE && gi.args.args[j].type != VALREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", &gi, i);
}
if (j > 0) {
// Print space between arguments
APPEND_ESTR(start, " ; print space\n");
APPEND_ESTR(start, " mov rax, 1\n");
APPEND_ESTR(start, " mov rdi, 1\n");
APPEND_ESTR(start, " lea rsi, [rel space_char]\n");
APPEND_ESTR(start, " mov rdx, 1\n");
APPEND_ESTR(start, " syscall\n");
}
APPEND_ESTR(start, " ; print int\n");
APPEND_ESTR(start, " mov rax, ");
APPEND_ESTR(start, processValueString(gi.args.args[j]));
APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " call print_int\n");
}
if (gi.type == PRINTLN) {
APPEND_ESTR(start, " ; print newline\n");
APPEND_ESTR(start, " mov rax, 1\n");
APPEND_ESTR(start, " mov rdi, 1\n");
APPEND_ESTR(start, " lea rsi, [rel newline_char]\n");
APPEND_ESTR(start, " mov rdx, 1\n");
APPEND_ESTR(start, " syscall\n");
}
break;
}
case END: { case END: {
if (gi.args.length < 1) { if (gi.args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i);
@@ -401,6 +517,10 @@ char* compileGroundProgram(GroundProgram* program) {
APPEND_ESTR(start, " syscall\n"); APPEND_ESTR(start, " syscall\n");
break; break;
} }
case DROP: {
// Drop does nothing in ground->asm as we use the stack
break;
}
default: { default: {
printf("no\n"); printf("no\n");
exit(1); exit(1);
@@ -411,6 +531,10 @@ char* compileGroundProgram(GroundProgram* program) {
Estr complete = CREATE_ESTR(""); Estr complete = CREATE_ESTR("");
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, "\nsection .rodata\n");
APPEND_ESTR(complete, "newline_char: db 10\n");
APPEND_ESTR(complete, "space_char: db 32\n");
APPEND_ESTR(complete, data.str) APPEND_ESTR(complete, data.str)
return complete.str; return complete.str;

View File

@@ -1,5 +1,6 @@
#include "parser.h" #include "parser.h"
#include "interpreter.h" #include "interpreter.h"
#include "compiler.h"
#include "types.h" #include "types.h"
#include <stdlib.h> #include <stdlib.h>
@@ -123,3 +124,7 @@ void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value)
void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) { void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) {
addFieldToStruct(gstruct, name, field); addFieldToStruct(gstruct, name, field);
} }
char* groundCompileProgram(GroundProgram* program) {
return compileGroundProgram(program);
}

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;
} }
@@ -2028,6 +2066,77 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
break; break;
} }
/*
* OBJECTS
* Allows manipulation of Ground objects.
*/
// getfield $obj &field &result
case GETFIELD: {
if (in->args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.length > 3) {
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.args[0].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Object for arg 1", in, currentInstruction);
}
if (in->args.args[0].value.value.type != CUSTOM) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Object for arg 1", in, currentInstruction);
}
if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
if (in->args.args[2].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction);
}
GroundObjectField* field = findField(*in->args.args[0].value.value.data.customVal, in->args.args[1].value.refName);
if (field == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
}
addVariable(scope->variables, in->args.args[2].value.refName, field->value);
break;
}
// setfield &obj &field $value
case SETFIELD: {
if (in->args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.length > 3) {
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.args[0].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction);
}
if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
if (in->args.args[2].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 3", in, currentInstruction);
}
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
if (var == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Could not find that object", in, currentInstruction);
}
if (var->value.type != CUSTOM) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction);
}
GroundObjectField* field = findField(*var->value.data.customVal, in->args.args[1].value.refName);
if (field == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
}
if (field->value.type != in->args.args[2].value.value.type) {
runtimeError(ARG_TYPE_MISMATCH, "Field type and provided type do not match", in, currentInstruction);
}
field->value = copyGroundValue(&in->args.args[2].value.value);
break;
}
case DROP: { case DROP: {
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);

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;
@@ -168,6 +189,8 @@ static GroundInstType getInstructionType(const char* inst) {
if (strcmp(inst, "struct") == 0) return STRUCT; if (strcmp(inst, "struct") == 0) return STRUCT;
if (strcmp(inst, "endstruct") == 0) return ENDSTRUCT; if (strcmp(inst, "endstruct") == 0) return ENDSTRUCT;
if (strcmp(inst, "init") == 0) return INIT; if (strcmp(inst, "init") == 0) return INIT;
if (strcmp(inst, "getfield") == 0) return GETFIELD;
if (strcmp(inst, "setfield") == 0) return SETFIELD;
if (strcmp(inst, "use") == 0) return USE; if (strcmp(inst, "use") == 0) return USE;
if (strcmp(inst, "extern") == 0) return EXTERN; if (strcmp(inst, "extern") == 0) return EXTERN;
if (strcmp(inst, "drop") == 0) return DROP; if (strcmp(inst, "drop") == 0) return DROP;

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, 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

17
tests/struct.grnd Normal file
View File

@@ -0,0 +1,17 @@
struct -point
init &x -int
init &y -int
endstruct
init &mypoint -point
setfield &mypoint &x 53
setfield &mypoint &y 32
getfield $mypoint &x &value
println $value
getfield $mypoint &y &value
println $value