Compare commits

...

10 Commits

11 changed files with 300 additions and 7 deletions

66
src/compiler.c Normal file
View File

@@ -0,0 +1,66 @@
#include "compiler.h"
#include "interpreter.h"
#include "types.h"
#include "include/estr.h"
#include <stdint.h>
char* compileGroundProgram(GroundProgram* program) {
Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n");
Estr data = CREATE_ESTR("section .rodata\n");
// Create data section
for (size_t i = 0; i < program->size; i++) {
}
// Generate assembly
for (size_t i = 0; i < program->size; i++) {
GroundInstruction gi = program->instructions[i];
switch (gi.type) {
case END: {
if (gi.args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i);
}
if (gi.args.length > 1) {
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i);
}
if (gi.args.args[0].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i);
}
if (gi.args.args[0].value.value.type != INT) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i);
}
int64_t bigretint = gi.args.args[0].value.value.data.intVal;
int retint;
if (bigretint > 255) {
retint = 255;
}
else if (bigretint < 0) {
retint = 0;
}
else {
retint = bigretint;
}
char retstr[8];
snprintf(retstr, sizeof(retstr), "%d", retint);
APPEND_ESTR(start, " mov rax, 60\n");
APPEND_ESTR(start, " mov rdi, ");
APPEND_ESTR(start, retstr);
APPEND_ESTR(start, "\n");
APPEND_ESTR(start, " syscall\n");
break;
}
default: {
printf("no\n");
exit(1);
}
}
}
Estr complete = CREATE_ESTR("");
APPEND_ESTR(complete, start.str);
APPEND_ESTR(complete, data.str)
return complete.str;
}

5
src/compiler.h Normal file
View File

@@ -0,0 +1,5 @@
#include "types.h"
#include "interpreter.h"
char* compileGroundProgram(GroundProgram* program);
[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine);

52
src/include/estr.h Normal file
View File

@@ -0,0 +1,52 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef ESTR_H
#define ESTR_H
/*
estr.h - Easy string manipulation
This library has macros to allow easier manipulation of strings. No longer shall
you have to malloc and realloc away to keep adding to your strings.
Usage:
Estr myString = CREATE_ESTR("my awesome string");
APPEND_ESTR(myString, " is so cool");
printf("%s\n", myString.str);
*/
#define CREATE_ESTR(instr) \
(Estr) { \
.str = instr,\
.size = strlen(instr),\
.shouldBeFreed = 0, \
.destroyed = 0 \
}
#define APPEND_ESTR(estr, instr) { \
estr.size = estr.size + strlen(instr); \
char* tmp_ptr = malloc(estr.size + 1); \
if (tmp_ptr == NULL) printf("WARNING: Could not realloc estr " #estr "\n"); \
else { \
snprintf(tmp_ptr, estr.size + 1, "%s%s", estr.str, instr); \
if (estr.shouldBeFreed > 0) free(estr.str); \
estr.shouldBeFreed = 1; \
estr.str = tmp_ptr; \
} \
}
#define DESTROY_ESTR(estr) if (estr.shouldBeFreed > 0 && estr.destroyed < 1) free(estr.str);
typedef struct Estr {
char* str;
size_t size;
int8_t shouldBeFreed;
int8_t destroyed;
} Estr;
#endif // ESTR_H

View File

@@ -1,4 +1,3 @@
#include "lexer.h"
#include "parser.h"
#include "interpreter.h"
#include "types.h"
@@ -68,11 +67,34 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
return createListGroundValue(va_arg(args, List));
break;
}
default: {
case FUNCTION: {
return createFunctionGroundValue(va_arg(args, GroundFunction*));
break;
}
case STRUCTVAL: {
GroundValue gv;
gv.type = STRUCTVAL;
gv.data.structVal = malloc(sizeof(GroundStruct));
*gv.data.structVal = va_arg(args, GroundStruct);
return gv;
}
case CUSTOM: {
// FIXME do this later lmao
return createNoneGroundValue();
break;
}
case ERROR: {
return createErrorGroundValue(va_arg(args, GroundError));
break;
}
case NONE: {
return createNoneGroundValue();
break;
}
}
return createNoneGroundValue();
va_end(args);
}
@@ -90,3 +112,18 @@ void groundPrintProgram(GroundProgram* program) {
GroundProgram groundParseFile(const char* code) {
return parseFile(code);
}
GroundStruct groundCreateStruct() {
GroundStruct gs;
gs.size = 0;
gs.fields = malloc(sizeof(GroundStructField));
return gs;
}
void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value) {
addVariable(gs->variables, name, value);
}
void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) {
addFieldToStruct(gstruct, name, field);
}

View File

@@ -13,6 +13,23 @@ int currentInstruction = 0;
bool isMainScopeGlobal = true;
[[noreturn]] void customError(GroundArg type, GroundArg what, GroundInstruction* where, int whereLine, int exitCode) {
printf("Ground runtime error:\n ErrorType: ");
printGroundArg(&type);
printf("\n ErrorContext: ");
printGroundArg(&what);
printf("\n");
if (where != NULL) {
printf(" ErrorInstruction: ");
printGroundInstruction(where);
printf("\n");
}
if (whereLine > -1) {
printf(" ErrorLine: %d\n", whereLine + 1);
}
exit(exitCode);
}
[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) {
printf("Ground runtime error:\n ErrorType: ");
switch (error) {
@@ -335,7 +352,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs
GroundValue gv;
switch (stringToValueType(in->instructions[i].args.args[0].value.refName)) {
switch (stringToValueType(in->instructions[i].args.args[1].value.refName)) {
case INT: {
gv = createIntGroundValue(0);
break;
@@ -382,6 +399,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs
gv.type = CUSTOM;
gv.data.customVal = malloc(sizeof(GroundObject));
*gv.data.customVal = createObject(*gstruct);
gv.customType = gstruct;
break;
}
case NONE: {
@@ -813,7 +831,19 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
}
break;
}
case ERRORCMD: {
if (in->args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
} else if (in->args.length > 3) {
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.args[2].value.value.type != INT ) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting an int for arg 2", in, currentInstruction);
}
customError(in->args.args[0], in->args.args[1], in, currentInstruction, in->args.args[2].value.value.data.intVal);
break;
}
/*
* VARIABLES AND LISTS
* These instructions are for initializing variables and lists.
@@ -1753,7 +1783,8 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (in->args.args[i + 1].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
}
if (in->args.args[i + 1].value.value.type != function->args[i].type) {
//if (in->args.args[i + 1].value.value.type != function->args[i].type) {
if (!checkFnTypes(&in->args.args[i + 1].value.value, &function->args[i])) {
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
}
appendToList(&argsList, in->args.args[i + 1].value.value);
@@ -1781,7 +1812,8 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (in->args.args[i + 1].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
}
if (in->args.args[i + 1].value.value.type != function->args[i].type) {
//if (in->args.args[i + 1].value.value.type != function->args[i].type) {
if (!checkFnTypes(&in->args.args[i + 1].value.value, &function->args[i])) {
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
}
addVariable(newScope.variables, function->args[i].name, in->args.args[i + 1].value.value);
@@ -1979,6 +2011,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
gv.type = CUSTOM;
gv.data.customVal = malloc(sizeof(GroundObject));
*gv.data.customVal = createObject(*gstruct);
gv.customType = gstruct;
break;
}
case NONE: {

View File

@@ -42,6 +42,7 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset);
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
void addVariable(GroundVariable **head, const char *id, GroundValue data);

View File

@@ -1,5 +1,6 @@
#include "parser.h"
#include "interpreter.h"
#include "compiler.h"
#include <stdio.h>
char* getFileContents(const char* filename) {
@@ -39,6 +40,7 @@ char* getFileContents(const char* filename) {
}
int main(int argc, char** argv) {
/*
if (argc < 2) {
printf("Usage: ground [file]\n");
exit(1);
@@ -46,5 +48,49 @@ int main(int argc, char** argv) {
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) {
printf("Usage: %s <file> [-c] [--compile] [-h] [--help]\n", argv[0]);
exit(1);
}
bool compile = false;
char* fileName = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp("--compile", argv[i]) == 0 || strcmp("-c", argv[i]) == 0) {
compile = true;
}
else if (strcmp("--help", argv[i]) == 0 || strcmp("-h", argv[i]) == 0) {
printf("GroundVM help\n");
printf("Usage: %s <file> [-c] [--compile] [-h] [--help]\n", argv[0]);
printf("Options:\n");
printf(" -c or --compile: Outputs Linux x86_64 assembly instead of interpreting (WIP)\n");
printf(" -h or --help: Shows this help message\n");
exit(0);
} else {
fileName = argv[i];
}
}
if (fileName == NULL) {
printf("Usage: %s <file> [-c] [--compile] [-h] [--help]\n", argv[0]);
printf("Error: No file name provided\n");
exit(1);
}
char* file = getFileContents(fileName);
GroundProgram program = parseFile(file);
free(file);
if (compile) {
char* compiled = compileGroundProgram(&program);
printf("%s\n", compiled);
} else {
interpretGroundProgram(&program, NULL);
}
}

View File

@@ -137,6 +137,7 @@ static GroundInstType getInstructionType(const char* inst) {
if (strcmp(inst, "input") == 0 || strcmp(inst, "stdin") == 0) return INPUT;
if (strcmp(inst, "print") == 0 || strcmp(inst, "stdout") == 0) return PRINT;
if (strcmp(inst, "println") == 0 || strcmp(inst, "stdlnout") == 0) return PRINTLN;
if (strcmp(inst, "error") == 0) return ERRORCMD;
if (strcmp(inst, "set") == 0) return SET;
if (strcmp(inst, "gettype") == 0) return GETTYPE;
if (strcmp(inst, "exists") == 0) return EXISTS;

View File

@@ -412,6 +412,9 @@ void printGroundInstruction(GroundInstruction* gi) {
break;
case CREATELABEL:
break;
case ERRORCMD:
printf("error");
break;
default:
printf("FIXME");
break;
@@ -582,3 +585,43 @@ GroundError createGroundError(char* what, char* type, GroundInstruction* where,
return ge;
}
bool checkFnTypes(GroundValue* left, GroundFunctionArgs* right) {
if (left->type != right->type) {
return false;
}
if (left->type == CUSTOM) {
if (left->customType->size != right->customType->size) {
return false;
}
for (size_t i = 0; i < left->customType->size; i++) {
if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) {
return false;
}
if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) {
return false;
}
}
}
return true;
}
bool checkTypes(GroundValue* left, GroundValue* right) {
if (left->type != right->type) {
return false;
}
if (left->type == CUSTOM) {
if (left->customType->size != right->customType->size) {
return false;
}
for (size_t i = 0; i < left->customType->size; i++) {
if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) {
return false;
}
if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) {
return false;
}
}
}
return true;
}

View File

@@ -9,7 +9,7 @@
#include "include/uthash.h"
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
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
} GroundInstType;
typedef enum GroundValueType {
@@ -62,6 +62,7 @@ typedef struct GroundError {
*/
typedef struct GroundValue {
GroundValueType type;
struct GroundStruct* customType;
union {
int64_t intVal;
double doubleVal;
@@ -125,6 +126,7 @@ typedef struct GroundProgram {
*/
typedef struct GroundFunctionArgs {
GroundValueType type;
struct GroundStruct* customType;
char* name;
} GroundFunctionArgs;
@@ -276,6 +278,11 @@ void freeGroundObject(GroundObject* object);
// Creates a GroundError.
GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line);
// Compares types of a value and function args.
bool checkFnTypes(GroundValue* left, GroundFunctionArgs* arg);
// Compares types of two values.
bool checkTypes(GroundValue* left, GroundValue* right);
#endif

2
tests/error.grnd Normal file
View File

@@ -0,0 +1,2 @@
setlist &dat 1 2 3 "Hi!"
error "Hello" $dat 1