Wrote the interpreter

This commit is contained in:
2022-08-06 07:58:32 +01:00
parent 0048c92cf5
commit 7a3986af33
10 changed files with 292 additions and 27 deletions

View File

@@ -13,9 +13,9 @@ void initCompiler(Compiler* compiler) {
Literal t = TO_BOOLEAN_LITERAL(true); Literal t = TO_BOOLEAN_LITERAL(true);
Literal f = TO_BOOLEAN_LITERAL(false); Literal f = TO_BOOLEAN_LITERAL(false);
writeLiteralArray(&compiler->literalCache, n); pushLiteralArray(&compiler->literalCache, n);
writeLiteralArray(&compiler->literalCache, t); pushLiteralArray(&compiler->literalCache, t);
writeLiteralArray(&compiler->literalCache, f); pushLiteralArray(&compiler->literalCache, f);
} }
void writeCompiler(Compiler* compiler, Node* node) { void writeCompiler(Compiler* compiler, Node* node) {
@@ -33,7 +33,7 @@ void writeCompiler(Compiler* compiler, Node* node) {
//ensure the literal is in the cache //ensure the literal is in the cache
int index = findLiteralIndex(&compiler->literalCache, node->atomic.literal); int index = findLiteralIndex(&compiler->literalCache, node->atomic.literal);
if (index < 0) { if (index < 0) {
index = writeLiteralArray(&compiler->literalCache, node->atomic.literal); index = pushLiteralArray(&compiler->literalCache, node->atomic.literal);
} }
//push the node opcode to the bytecode //push the node opcode to the bytecode

View File

@@ -51,7 +51,7 @@ static void consumeByte(unsigned char byte, const char* str, int* count) {
static void consumeShort(unsigned short bytes, const char* str, int* count) { static void consumeShort(unsigned short bytes, const char* str, int* count) {
if (bytes != *(unsigned short*)(str + *count)) { if (bytes != *(unsigned short*)(str + *count)) {
printf("Failed to consume the correct byte"); printf("Failed to consume the correct bytes");
} }
*count += 2; *count += 2;
} }

229
source/interpreter.c Normal file
View File

@@ -0,0 +1,229 @@
#include "interpreter.h"
#include "common.h"
#include "memory.h"
#include <stdio.h>
#include <string.h>
void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
initLiteralArray(&interpreter->literalCache);
interpreter->bytecode = bytecode;
interpreter->length = length;
interpreter->count = 0;
initLiteralArray(&interpreter->stack);
}
void freeInterpreter(Interpreter* interpreter) {
freeLiteralArray(&interpreter->literalCache);
FREE_ARRAY(char, interpreter->bytecode, interpreter->length);
freeLiteralArray(&interpreter->stack);
}
//utils
static unsigned char readByte(unsigned char* tb, int* count) {
unsigned char ret = *(unsigned char*)(tb + *count);
*count += 1;
return ret;
}
static unsigned short readShort(unsigned char* tb, int* count) {
unsigned short ret = *(unsigned short*)(tb + *count);
*count += 2;
return ret;
}
static int readInt(unsigned char* tb, int* count) {
int ret = *(int*)(tb + *count);
*count += 4;
return ret;
}
static float readFloat(unsigned char* tb, int* count) {
float ret = *(float*)(tb + *count);
*count += 4;
return ret;
}
static char* readString(unsigned char* tb, int* count) {
char* ret = tb + *count;
*count += strlen(ret) + 1; //+1 for null character
return ret;
}
static void consumeByte(unsigned char byte, unsigned char* tb, int* count) {
if (byte != tb[*count]) {
printf("Failed to consume the correct byte");
}
*count += 1;
}
static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
if (bytes != *(unsigned short*)(tb + *count)) {
printf("Failed to consume the correct bytes");
}
*count += 2;
}
//each available statement
static void execPrint(Interpreter* interpreter) {
//print what is on top of the stack, then pop it
Literal lit = popLiteralArray(&interpreter->stack);
printLiteral(lit);
printf("\n");
freeLiteral(lit);
}
static void execPushLiteral(Interpreter* interpreter, bool lng) {
//read the index in the cache
int index = 0;
if (lng) {
index = (int)readShort(interpreter->bytecode, &interpreter->count);
}
else {
index = (int)readByte(interpreter->bytecode, &interpreter->count);
}
//push from cache to stack
pushLiteralArray(&interpreter->stack, interpreter->literalCache.literals[index]);
}
static void execNegate(Interpreter* interpreter) {
//negate the top literal on the stack
Literal lit = popLiteralArray(&interpreter->stack);
if (IS_INTEGER(lit)) {
lit = TO_INTEGER_LITERAL(-AS_INTEGER(lit));
}
else if (IS_FLOAT(lit)) {
lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit));
}
else {
printf("[internal] The interpreter can't negate that literal: ");
printLiteral(lit);
printf("\n");
}
pushLiteralArray(&interpreter->stack, lit);
}
//the heart of toy
static void execInterpreter(Interpreter* interpreter) {
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
switch(opcode) {
case OP_PRINT:
execPrint(interpreter);
break;
case OP_LITERAL:
case OP_LITERAL_LONG:
execPushLiteral(interpreter, opcode == OP_LITERAL_LONG);
break;
default:
printf("Unknown opcode found %d, terminating\n", opcode);
printLiteralArray(&interpreter->stack, "\n");
return;
}
opcode = readByte(interpreter->bytecode, &interpreter->count);
}
}
void runInterpreter(Interpreter* interpreter) {
//header section
const unsigned char major = readByte(interpreter->bytecode, &interpreter->count);
const unsigned char minor = readByte(interpreter->bytecode, &interpreter->count);
const unsigned char patch = readByte(interpreter->bytecode, &interpreter->count);
const char* build = readString(interpreter->bytecode, &interpreter->count);
if (command.verbose) {
if (major != TOY_VERSION_MAJOR || minor != TOY_VERSION_MINOR || patch != TOY_VERSION_PATCH) {
printf("Warning: interpreter/bytecode version mismatch\n");
}
if (!strncmp(build, TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD))) {
printf("Warning: interpreter/bytecode build mismatch\n");
}
}
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count);
//data section
const short literalCount = readShort(interpreter->bytecode, &interpreter->count);
if (command.verbose) {
printf("Reading %d literals\n", literalCount);
}
for (int i = 0; i < literalCount; i++) {
const unsigned char literalType = readByte(interpreter->bytecode, &interpreter->count);
switch(literalType) {
case LITERAL_NULL:
//read the null
pushLiteralArray(&interpreter->literalCache, TO_NULL_LITERAL);
if (command.verbose) {
printf("(null)\n");
}
break;
case LITERAL_BOOLEAN: {
//read the booleans
const bool b = readByte(interpreter->bytecode, &interpreter->count);
pushLiteralArray(&interpreter->literalCache, TO_BOOLEAN_LITERAL(b));
if (command.verbose) {
printf("(boolean %s)\n", b ? "true" : "false");
}
}
break;
case LITERAL_INTEGER: {
const int d = readInt(interpreter->bytecode, &interpreter->count);
pushLiteralArray(&interpreter->literalCache, TO_INTEGER_LITERAL(d));
if (command.verbose) {
printf("(integer %d)\n", d);
}
}
break;
case LITERAL_FLOAT: {
const float f = readFloat(interpreter->bytecode, &interpreter->count);
pushLiteralArray(&interpreter->literalCache, TO_FLOAT_LITERAL(f));
if (command.verbose) {
printf("(float %f)\n", f);
}
}
break;
case LITERAL_STRING: {
char* s = readString(interpreter->bytecode, &interpreter->count);
pushLiteralArray(&interpreter->literalCache, TO_STRING_LITERAL(s));
if (command.verbose) {
printf("(string \"%s\")\n", s);
}
}
break;
}
}
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count);
//code section
if (command.verbose) {
printf("executing bytecode\n");
}
execInterpreter(interpreter);
}

20
source/interpreter.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "opcodes.h"
#include "literal_array.h"
//the interpreter acts depending on the bytecode instructions
typedef struct Interpreter {
LiteralArray literalCache; //generally doesn't change after initialization
unsigned char* bytecode;
int length;
int count;
LiteralArray stack;
} Interpreter;
void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length);
void freeInterpreter(Interpreter* interpreter);
void runInterpreter(Interpreter* interpreter);

View File

@@ -7,27 +7,23 @@
void printLiteral(Literal literal) { void printLiteral(Literal literal) {
switch(literal.type) { switch(literal.type) {
case LITERAL_NULL: case LITERAL_NULL:
printf("null\n"); printf("null");
break; break;
case LITERAL_BOOLEAN: case LITERAL_BOOLEAN:
printf(AS_BOOLEAN(literal) ? "true\n" : "false\n"); printf(AS_BOOLEAN(literal) ? "true" : "false");
break; break;
case LITERAL_INTEGER: case LITERAL_INTEGER:
printf("%d\n", AS_INTEGER(literal)); printf("%d", AS_INTEGER(literal));
break; break;
case LITERAL_FLOAT: case LITERAL_FLOAT:
printf("%g\n", AS_FLOAT(literal)); printf("%g", AS_FLOAT(literal));
break; break;
case LITERAL_STRING: case LITERAL_STRING:
printf("%.*s (%d)\n", STRLEN(literal), AS_STRING(literal), STRLEN(literal)); printf("%.*s", STRLEN(literal), AS_STRING(literal));
break;
case LITERAL_FUNCTION:
printf("<toy function>\n");
break; break;
default: default:

View File

@@ -10,9 +10,9 @@ typedef enum {
LITERAL_INTEGER, LITERAL_INTEGER,
LITERAL_FLOAT, LITERAL_FLOAT,
LITERAL_STRING, LITERAL_STRING,
LITERAL_ARRAY, // LITERAL_ARRAY,
LITERAL_DICTIONARY, // LITERAL_DICTIONARY,
LITERAL_FUNCTION, // LITERAL_FUNCTION,
} LiteralType; } LiteralType;
typedef struct { typedef struct {

View File

@@ -12,7 +12,7 @@ void initLiteralArray(LiteralArray* array) {
array->literals = NULL; array->literals = NULL;
} }
int writeLiteralArray(LiteralArray* array, Literal literal) { int pushLiteralArray(LiteralArray* array, Literal literal) {
if (array->capacity < array->count + 1) { if (array->capacity < array->count + 1) {
int oldCapacity = array->capacity; int oldCapacity = array->capacity;
@@ -29,6 +29,17 @@ int writeLiteralArray(LiteralArray* array, Literal literal) {
return array->count++; return array->count++;
} }
Literal popLiteralArray(LiteralArray* array) {
//get the return
Literal ret = array->literals[array->count-1];
//null the existing data
array->literals[array->count-1] = TO_NULL_LITERAL;
array->count--;
return ret;
}
void freeLiteralArray(LiteralArray* array) { void freeLiteralArray(LiteralArray* array) {
//clean up memory //clean up memory
for(int i = 0; i < array->count; i++) { for(int i = 0; i < array->count; i++) {
@@ -84,3 +95,10 @@ int findLiteralIndex(LiteralArray* array, Literal literal) {
return -1; return -1;
} }
void printLiteralArray(LiteralArray* array, const char* delim) {
for (int i = 0; i < array->count; i++) {
printLiteral(array->literals[i]);
printf("%s", delim);
}
}

View File

@@ -9,8 +9,10 @@ typedef struct LiteralArray {
} LiteralArray; } LiteralArray;
void initLiteralArray(LiteralArray* array); void initLiteralArray(LiteralArray* array);
int writeLiteralArray(LiteralArray* array, Literal literal); int pushLiteralArray(LiteralArray* array, Literal literal);
Literal popLiteralArray(LiteralArray* array);
void freeLiteralArray(LiteralArray* array); void freeLiteralArray(LiteralArray* array);
int findLiteralIndex(LiteralArray* array, Literal literal); int findLiteralIndex(LiteralArray* array, Literal literal);
void printLiteralArray(LiteralArray* array, const char* delim);

View File

@@ -1,7 +1,7 @@
CC=gcc CC=gcc
IDIR =. IDIR =.
CFLAGS=$(addprefix -I,$(IDIR)) -g -Wall -W -pedantic CFLAGS=$(addprefix -I,$(IDIR)) -g # -Wall -W -pedantic
LIBS= LIBS=
ODIR=obj ODIR=obj

View File

@@ -3,7 +3,7 @@
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
#include "compiler.h" #include "compiler.h"
//#include "toy.h" #include "interpreter.h"
#include "memory.h" #include "memory.h"
@@ -135,6 +135,7 @@ void debug() {
Lexer lexer; Lexer lexer;
Parser parser; Parser parser;
Compiler compiler; Compiler compiler;
Interpreter interpreter;
char* source = readFile(command.filename); char* source = readFile(command.filename);
@@ -146,22 +147,21 @@ void debug() {
Node* node = scanParser(&parser); Node* node = scanParser(&parser);
while(node != NULL) { while(node != NULL) {
writeCompiler(&compiler, node); writeCompiler(&compiler, node);
freeNode(node); freeNode(node);
node = scanParser(&parser); node = scanParser(&parser);
} }
//get the data dump //get the data dump
int size = 0; int size = 0;
const char* tb = collateCompiler(&compiler, &size); char* tb = collateCompiler(&compiler, &size);
dissectBytecode(tb, size);
//cleanup //cleanup
FREE_ARRAY(char, tb, size);
freeCompiler(&compiler); freeCompiler(&compiler);
freeParser(&parser); freeParser(&parser);
initInterpreter(&interpreter, tb, size);
runInterpreter(&interpreter);
freeInterpreter(&interpreter);
} }
//entry point //entry point