mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Bytecode and Routine working, Routine tests incomplete
There may be a build issue on windows
This commit is contained in:
@@ -28,24 +28,17 @@ Things to consider later:
|
|||||||
|
|
||||||
===
|
===
|
||||||
|
|
||||||
//general instructions
|
//variable instructions
|
||||||
READ
|
READ
|
||||||
read one value from C onto S
|
read one value from C onto S
|
||||||
LOAD
|
LOAD
|
||||||
read one value from .data onto S
|
read one value from .data onto S
|
||||||
ASSERT
|
|
||||||
if S(-1) is falsy, print S(0) and exit
|
|
||||||
PRINT
|
|
||||||
pop S(0), and print the output
|
|
||||||
SET
|
|
||||||
read one word from C, saves the key E[SYMBOL(word)] to the value S(0), popping S(0)
|
|
||||||
GET
|
|
||||||
read one word from C, finds the value of E[SYMBOL(word)], leaves the value on S
|
|
||||||
DECLARE
|
DECLARE
|
||||||
read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value 'null'
|
read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value 'null'
|
||||||
DEFINE
|
DEFINE
|
||||||
read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value popped from S(0)
|
read one word from C, saves the pre-existing key E[SYMBOL(word)] to the value S(0), popping S(0)
|
||||||
|
ACCESS
|
||||||
|
read one word from C, finds the pre-existing value of E[SYMBOL(word)], leaves the value on S
|
||||||
|
|
||||||
//arithmetic instructions
|
//arithmetic instructions
|
||||||
ADD
|
ADD
|
||||||
@@ -80,7 +73,7 @@ OR
|
|||||||
pops S(-1) and S(0), replacing it with TRUE or FALSE, depending on truthiness
|
pops S(-1) and S(0), replacing it with TRUE or FALSE, depending on truthiness
|
||||||
TRUTHY
|
TRUTHY
|
||||||
pops S(0), replacing it with TRUE or FALSE, depending on truthiness
|
pops S(0), replacing it with TRUE or FALSE, depending on truthiness
|
||||||
INVERT
|
NEGATE
|
||||||
pops S(0), replacing it with TRUE or FALSE, depending on truthiness
|
pops S(0), replacing it with TRUE or FALSE, depending on truthiness
|
||||||
|
|
||||||
|
|
||||||
@@ -92,10 +85,13 @@ JUMP_IF_FALSE
|
|||||||
FN_CALL
|
FN_CALL
|
||||||
*read a list of arguments specified in C into 'A', store (S, E, C, D) as D, push S, move the stack pointer to the specified routine, push a new E based on the contents of 'A'
|
*read a list of arguments specified in C into 'A', store (S, E, C, D) as D, push S, move the stack pointer to the specified routine, push a new E based on the contents of 'A'
|
||||||
FN_RETURN
|
FN_RETURN
|
||||||
This
|
|
||||||
*read a list of return values specified in C into 'R', pop S, restore (S, E, C, D) from D(0) popping it, store the contents of 'R' in E or S based on the next few parts of C
|
*read a list of return values specified in C into 'R', pop S, restore (S, E, C, D) from D(0) popping it, store the contents of 'R' in E or S based on the next few parts of C
|
||||||
|
|
||||||
//bespoke utility instructions
|
//bespoke utility instructions
|
||||||
|
ASSERT
|
||||||
|
if S(-1) is falsy, print S(0) and exit
|
||||||
|
PRINT
|
||||||
|
pop S(0), and print the output
|
||||||
IMPORT
|
IMPORT
|
||||||
//invoke an external library into the current scope
|
//invoke an external library into the current scope
|
||||||
CONCAT
|
CONCAT
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Additional information may be added later, or multiple 'modules' listed sequenti
|
|||||||
# where 'module' can be omitted if it's local to this module ('identifier' within the symbols is calculated at the module level, it's always unique)
|
# where 'module' can be omitted if it's local to this module ('identifier' within the symbols is calculated at the module level, it's always unique)
|
||||||
|
|
||||||
.header:
|
.header:
|
||||||
total size # size of this routine, including all data and subroutines
|
N total size # size of this routine, including all data and subroutines
|
||||||
N .param count # the number of parameter fields expected
|
N .param count # the number of parameter fields expected
|
||||||
N .data count # the number of data fields expected
|
N .data count # the number of data fields expected
|
||||||
N .routine count # the number of routines present
|
N .routine count # the number of routines present
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ typedef enum Toy_AstFlag {
|
|||||||
TOY_AST_FLAG_MULTIPLY,
|
TOY_AST_FLAG_MULTIPLY,
|
||||||
TOY_AST_FLAG_DIVIDE,
|
TOY_AST_FLAG_DIVIDE,
|
||||||
TOY_AST_FLAG_MODULO,
|
TOY_AST_FLAG_MODULO,
|
||||||
|
TOY_AST_FLAG_ASSIGN, //TODO: implement the declare statement
|
||||||
TOY_AST_FLAG_ADD_ASSIGN,
|
TOY_AST_FLAG_ADD_ASSIGN,
|
||||||
TOY_AST_FLAG_SUBTRACT_ASSIGN,
|
TOY_AST_FLAG_SUBTRACT_ASSIGN,
|
||||||
TOY_AST_FLAG_MULTIPLY_ASSIGN,
|
TOY_AST_FLAG_MULTIPLY_ASSIGN,
|
||||||
TOY_AST_FLAG_DIVIDE_ASSIGN,
|
TOY_AST_FLAG_DIVIDE_ASSIGN,
|
||||||
TOY_AST_FLAG_MODULO_ASSIGN,
|
TOY_AST_FLAG_MODULO_ASSIGN,
|
||||||
TOY_AST_FLAG_ASSIGN,
|
|
||||||
TOY_AST_FLAG_COMPARE_EQUAL,
|
TOY_AST_FLAG_COMPARE_EQUAL,
|
||||||
TOY_AST_FLAG_COMPARE_NOT,
|
TOY_AST_FLAG_COMPARE_NOT,
|
||||||
TOY_AST_FLAG_COMPARE_LESS,
|
TOY_AST_FLAG_COMPARE_LESS,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "toy_bytecode.h"
|
#include "toy_bytecode.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "toy_memory.h"
|
#include "toy_memory.h"
|
||||||
#include "toy_routine.h"
|
#include "toy_routine.h"
|
||||||
@@ -21,10 +22,6 @@ static void emitByte(Toy_Bytecode* bc, unsigned char byte) {
|
|||||||
bc->ptr[bc->count++] = byte;
|
bc->ptr[bc->count++] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeModule(Toy_Bytecode* bc, Toy_Ast* ast) {
|
|
||||||
//TODO: routines
|
|
||||||
}
|
|
||||||
|
|
||||||
//bytecode
|
//bytecode
|
||||||
static void writeBytecodeHeader(Toy_Bytecode* bc) {
|
static void writeBytecodeHeader(Toy_Bytecode* bc) {
|
||||||
emitByte(bc, TOY_VERSION_MAJOR);
|
emitByte(bc, TOY_VERSION_MAJOR);
|
||||||
@@ -36,7 +33,7 @@ static void writeBytecodeHeader(Toy_Bytecode* bc) {
|
|||||||
int len = (int)strlen(build) + 1;
|
int len = (int)strlen(build) + 1;
|
||||||
|
|
||||||
expand(bc, len);
|
expand(bc, len);
|
||||||
sprintf((char*)(bc->ptr + bc->count), "%.*s", len, build);
|
memcpy(bc->ptr + bc->count, build, len);
|
||||||
bc->count += len;
|
bc->count += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +41,13 @@ static void writeBytecodeBody(Toy_Bytecode* bc, Toy_Ast* ast) {
|
|||||||
//a 'module' is a routine that runs at the root-level of a file
|
//a 'module' is a routine that runs at the root-level of a file
|
||||||
//since routines can be recursive, this distinction is important
|
//since routines can be recursive, this distinction is important
|
||||||
//eventually, the bytecode may support multiple modules packed into one file
|
//eventually, the bytecode may support multiple modules packed into one file
|
||||||
writeModule(bc, ast);
|
void* module = Toy_compileRoutine(ast);
|
||||||
|
|
||||||
|
int len = ((int*)module)[0];
|
||||||
|
|
||||||
|
expand(bc, len);
|
||||||
|
memcpy(bc->ptr + bc->count, module, len);
|
||||||
|
bc->count += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
|
|||||||
@@ -1,10 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
typedef enum Toy_OpcodeType {
|
typedef enum Toy_OpcodeType {
|
||||||
//
|
//variable instructions
|
||||||
|
TOY_OPCODE_READ,
|
||||||
|
TOY_OPCODE_LOAD,
|
||||||
|
TOY_OPCODE_LOAD_LONG, //corner case
|
||||||
|
TOY_OPCODE_DECLARE,
|
||||||
|
TOY_OPCODE_ASSIGN,
|
||||||
|
TOY_OPCODE_ACCESS,
|
||||||
|
|
||||||
|
//arithmetic instructions
|
||||||
|
TOY_OPCODE_ADD,
|
||||||
|
TOY_OPCODE_SUBTRACT,
|
||||||
|
TOY_OPCODE_MULTIPLY,
|
||||||
|
TOY_OPCODE_DIVIDE,
|
||||||
|
TOY_OPCODE_MODULO,
|
||||||
|
|
||||||
|
//comparison instructions
|
||||||
|
TOY_OPCODE_COMPARE_EQUAL,
|
||||||
|
// TOY_OPCODE_COMPARE_NOT,
|
||||||
|
TOY_OPCODE_COMPARE_LESS,
|
||||||
|
TOY_OPCODE_COMPARE_LESS_EQUAL,
|
||||||
|
TOY_OPCODE_COMPARE_GREATER,
|
||||||
|
TOY_OPCODE_COMPARE_GREATER_EQUAL,
|
||||||
|
|
||||||
|
//logical instructions
|
||||||
|
TOY_OPCODE_AND,
|
||||||
|
TOY_OPCODE_OR,
|
||||||
|
TOY_OPCODE_TRUTHY,
|
||||||
|
TOY_OPCODE_NEGATE,
|
||||||
|
|
||||||
|
//control instructions
|
||||||
|
TOY_OPCODE_RETURN,
|
||||||
|
|
||||||
|
//meta instructions
|
||||||
TOY_OPCODE_PASS,
|
TOY_OPCODE_PASS,
|
||||||
TOY_OPCODE_ERROR,
|
TOY_OPCODE_ERROR,
|
||||||
TOY_OPCODE_EOF,
|
TOY_OPCODE_EOF,
|
||||||
} Toy_OpcodeType;
|
} Toy_OpcodeType;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
#include "toy_routine.h"
|
#include "toy_routine.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "toy_memory.h"
|
#include "toy_memory.h"
|
||||||
|
#include "toy_opcodes.h"
|
||||||
|
#include "toy_value.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
@@ -10,7 +14,7 @@ static void expand(void** handle, int* capacity, int* count, int amount) {
|
|||||||
while ((*count) + amount > (*capacity)) {
|
while ((*count) + amount > (*capacity)) {
|
||||||
int oldCapacity = (*capacity);
|
int oldCapacity = (*capacity);
|
||||||
|
|
||||||
(*capacity) = TOY_GROW_CAPACITY(oldCapacity);
|
(*capacity) = TOY_GROW_CAPACITY(oldCapacity); //TODO: don't need GROW
|
||||||
(*handle) = TOY_GROW_ARRAY(unsigned char, (*handle), oldCapacity, (*capacity));
|
(*handle) = TOY_GROW_ARRAY(unsigned char, (*handle), oldCapacity, (*capacity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,11 +24,273 @@ static void emitByte(void** handle, int* capacity, int* count, unsigned char byt
|
|||||||
((unsigned char*)(*handle))[(*count)++] = byte;
|
((unsigned char*)(*handle))[(*count)++] = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
//routine
|
static void emitInt(void** handle, int* capacity, int* count, int bytes) {
|
||||||
//TODO
|
char* ptr = (char*)&bytes;
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitFloat(void** handle, int* capacity, int* count, float bytes) {
|
||||||
|
char* ptr = (char*)&bytes;
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
emitByte(handle, capacity, count, *(ptr++));
|
||||||
|
}
|
||||||
|
|
||||||
|
//write instructions based on the AST types
|
||||||
|
#define EMIT_BYTE(rt, byte) \
|
||||||
|
emitByte((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
||||||
|
#define EMIT_INT(rt, code, byte) \
|
||||||
|
emitInt((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
||||||
|
#define EMIT_FLOAT(rt, code, byte) \
|
||||||
|
emitFloat((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
||||||
|
|
||||||
|
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion
|
||||||
|
|
||||||
|
static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
|
||||||
|
//TODO: store more complex values in the data code
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_READ);
|
||||||
|
EMIT_BYTE(rt, ast.value.type);
|
||||||
|
|
||||||
|
//emit the raw value based on the type
|
||||||
|
if (TOY_VALUE_IS_NULL(ast.value)) {
|
||||||
|
//NOTHING - null's type data is enough
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_BOOLEAN(ast.value)) {
|
||||||
|
EMIT_BYTE(rt, TOY_VALUE_AS_BOOLEAN(ast.value));
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_INTEGER(ast.value)) {
|
||||||
|
EMIT_INT(rt, code, TOY_VALUE_AS_INTEGER(ast.value));
|
||||||
|
}
|
||||||
|
else if (TOY_VALUE_IS_FLOAT(ast.value)) {
|
||||||
|
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
|
||||||
|
//working with a stack means the child gets placed first
|
||||||
|
writeRoutineCode(rt, ast.child);
|
||||||
|
|
||||||
|
if (ast.flag == TOY_AST_FLAG_NEGATE) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST unary flag found\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
||||||
|
//left, then right, then the binary's operation
|
||||||
|
writeRoutineCode(rt, ast.left);
|
||||||
|
writeRoutineCode(rt, ast.right);
|
||||||
|
|
||||||
|
if (ast.flag == TOY_AST_FLAG_ADD) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_ADD);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_SUBTRACT) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_MULTIPLY) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_DIVIDE) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_MODULO) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_MODULO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ADD);
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
// if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_MODULO);
|
||||||
|
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
||||||
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_LESS) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_LESS_EQUAL) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS_EQUAL);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER_EQUAL) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER_EQUAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast.flag == TOY_AST_FLAG_AND) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_AND);
|
||||||
|
}
|
||||||
|
if (ast.flag == TOY_AST_FLAG_OR) {
|
||||||
|
EMIT_BYTE(rt, TOY_OPCODE_OR);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST binary flag found\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//routine structure
|
||||||
|
// static void writeRoutineParam(Toy_Routine* rt) {
|
||||||
|
// //
|
||||||
|
// }
|
||||||
|
|
||||||
|
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
||||||
|
if (ast == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//determine how to write each instruction based on the Ast
|
||||||
|
switch(ast->type) {
|
||||||
|
case TOY_AST_BLOCK:
|
||||||
|
writeRoutineCode(rt, ast->block.child);
|
||||||
|
writeRoutineCode(rt, ast->block.next);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_VALUE:
|
||||||
|
writeInstructionValue(rt, ast->value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_UNARY:
|
||||||
|
writeInstructionUnary(rt, ast->unary);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_BINARY:
|
||||||
|
writeInstructionBinary(rt, ast->binary);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//other disallowed instructions
|
||||||
|
case TOY_AST_GROUP:
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Group shouldn't be used\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_PASS:
|
||||||
|
//NOTE: this should be disallowed, but for now it's required for testing
|
||||||
|
// fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown pass\n" TOY_CC_RESET);
|
||||||
|
// exit(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//meta instructions are disallowed
|
||||||
|
case TOY_AST_ERROR:
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown error\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_END:
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown end\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void writeRoutineJumps(Toy_Routine* rt) {
|
||||||
|
// //
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static void writeRoutineData(Toy_Routine* rt) {
|
||||||
|
// //
|
||||||
|
// }
|
||||||
|
|
||||||
|
static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
|
||||||
|
//build the routine's parts
|
||||||
|
//param
|
||||||
|
//code
|
||||||
|
writeRoutineCode(&rt, ast);
|
||||||
|
EMIT_BYTE(&rt, TOY_OPCODE_RETURN); //temp terminator
|
||||||
|
//jumps
|
||||||
|
//data
|
||||||
|
|
||||||
|
//write the header and combine the parts
|
||||||
|
void* buffer = TOY_ALLOCATE(unsigned char, 16);
|
||||||
|
int capacity = 0, count = 0;
|
||||||
|
// int paramAddr = 0, codeAddr = 0, jumpsAddr = 0, dataAddr = 0, subsAddr = 0;
|
||||||
|
int codeAddr = 0;
|
||||||
|
|
||||||
|
emitInt(&buffer, &capacity, &count, 0); //total size (overwritten later)
|
||||||
|
emitInt(&buffer, &capacity, &count, rt->paramCount); //param count
|
||||||
|
emitInt(&buffer, &capacity, &count, rt->dataCount); //data count
|
||||||
|
emitInt(&buffer, &capacity, &count, rt->subsCount); //routine count
|
||||||
|
|
||||||
|
//generate blank spaces, cache their positions in the []Addr variables
|
||||||
|
if (rt->paramCount > 0) {
|
||||||
|
// paramAddr = count;
|
||||||
|
emitInt((void**)&buffer, &capacity, &count, 0); //params
|
||||||
|
}
|
||||||
|
if (rt->codeCount > 0) {
|
||||||
|
codeAddr = count;
|
||||||
|
emitInt((void**)&buffer, &capacity, &count, 0); //code
|
||||||
|
}
|
||||||
|
if (rt->jumpsCount > 0) {
|
||||||
|
// jumpsAddr = count;
|
||||||
|
emitInt((void**)&buffer, &capacity, &count, 0); //jumps
|
||||||
|
}
|
||||||
|
if (rt->dataCount > 0) {
|
||||||
|
// dataAddr = count;
|
||||||
|
emitInt((void**)&buffer, &capacity, &count, 0); //data
|
||||||
|
}
|
||||||
|
if (rt->subsCount > 0) {
|
||||||
|
// subsAddr = count;
|
||||||
|
emitInt((void**)&buffer, &capacity, &count, 0); //subs
|
||||||
|
}
|
||||||
|
|
||||||
|
//append various parts to the buffer TODO: add the rest
|
||||||
|
if (rt->codeCount > 0) {
|
||||||
|
expand(&buffer, &capacity, &count, rt->codeCount);
|
||||||
|
memcpy((buffer + count), rt->code, rt->codeCount);
|
||||||
|
|
||||||
|
((int*)buffer)[codeAddr] = count;
|
||||||
|
count += rt->codeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally, record the total size, and return the result
|
||||||
|
((int*)buffer)[0] = count;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
Toy_Routine Toy_compileRoutine(Toy_Ast* ast) {
|
void* Toy_compileRoutine(Toy_Ast* ast) {
|
||||||
//setup
|
//setup
|
||||||
Toy_Routine rt;
|
Toy_Routine rt;
|
||||||
|
|
||||||
@@ -36,23 +302,27 @@ Toy_Routine Toy_compileRoutine(Toy_Ast* ast) {
|
|||||||
rt.codeCapacity = 0;
|
rt.codeCapacity = 0;
|
||||||
rt.codeCount = 0;
|
rt.codeCount = 0;
|
||||||
|
|
||||||
|
rt.jumps = NULL;
|
||||||
|
rt.jumpsCapacity = 0;
|
||||||
|
rt.jumpsCount = 0;
|
||||||
|
|
||||||
rt.data = NULL;
|
rt.data = NULL;
|
||||||
rt.dataCapacity = 0;
|
rt.dataCapacity = 0;
|
||||||
rt.dataCount = 0;
|
rt.dataCount = 0;
|
||||||
|
|
||||||
rt.jump = NULL;
|
rt.subs = NULL;
|
||||||
rt.jumpCapacity = 0;
|
rt.subsCapacity = 0;
|
||||||
rt.jumpCount = 0;
|
rt.subsCount = 0;
|
||||||
|
|
||||||
//build
|
//build
|
||||||
//TODO
|
void * buffer = writeRoutine(&rt, ast);
|
||||||
|
|
||||||
return rt;
|
//cleanup the temp object
|
||||||
}
|
|
||||||
|
|
||||||
void freeRoutine(Toy_Routine rt) {
|
|
||||||
TOY_FREE_ARRAY(unsigned char, rt.param, rt.paramCapacity);
|
TOY_FREE_ARRAY(unsigned char, rt.param, rt.paramCapacity);
|
||||||
TOY_FREE_ARRAY(unsigned char, rt.code, rt.codeCapacity);
|
TOY_FREE_ARRAY(unsigned char, rt.code, rt.codeCapacity);
|
||||||
|
TOY_FREE_ARRAY(int, rt.jumps, rt.jumpsCapacity);
|
||||||
TOY_FREE_ARRAY(unsigned char, rt.data, rt.dataCapacity);
|
TOY_FREE_ARRAY(unsigned char, rt.data, rt.dataCapacity);
|
||||||
TOY_FREE_ARRAY(int, rt.jump, rt.jumpCapacity);
|
TOY_FREE_ARRAY(unsigned char, rt.subs, rt.subsCapacity);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "toy_ast.h"
|
#include "toy_ast.h"
|
||||||
|
|
||||||
//routine - holds the individual parts of a compiled routine
|
//routine - internal structure that holds the individual parts of a compiled routine
|
||||||
typedef struct Toy_Routine {
|
typedef struct Toy_Routine {
|
||||||
unsigned char* param; //c-string params in sequence
|
unsigned char* param; //c-string params in sequence
|
||||||
int paramCapacity;
|
int paramCapacity;
|
||||||
@@ -13,16 +13,17 @@ typedef struct Toy_Routine {
|
|||||||
int codeCapacity;
|
int codeCapacity;
|
||||||
int codeCount;
|
int codeCount;
|
||||||
|
|
||||||
|
int* jumps; //each 'jump' is the starting address of an element within 'data'
|
||||||
|
int jumpsCapacity;
|
||||||
|
int jumpsCount;
|
||||||
|
|
||||||
unsigned char* data; //{type,val} tuples of data
|
unsigned char* data; //{type,val} tuples of data
|
||||||
int dataCapacity;
|
int dataCapacity;
|
||||||
int dataCount;
|
int dataCount;
|
||||||
|
|
||||||
int* jump; //each 'jump' is the starting address of an element within 'data'
|
unsigned char* subs; //subroutines, recursively
|
||||||
int jumpCapacity;
|
int subsCapacity;
|
||||||
int jumpCount;
|
int subsCount;
|
||||||
|
|
||||||
//TODO: duplicate the data and jumps for subroutines
|
|
||||||
} Toy_Routine;
|
} Toy_Routine;
|
||||||
|
|
||||||
TOY_API Toy_Routine Toy_compileRoutine(Toy_Ast* ast);
|
TOY_API void* Toy_compileRoutine(Toy_Ast* ast);
|
||||||
TOY_API void Toy_freeRoutine(Toy_Routine routine);
|
|
||||||
@@ -38,8 +38,6 @@ int test_bytecode_header(Toy_Bucket* bucket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
fprintf(stderr, TOY_CC_WARN "WARNING: Bytecode implementation incomplete\n" TOY_CC_RESET);
|
|
||||||
|
|
||||||
//run each test set, returning the total errors given
|
//run each test set, returning the total errors given
|
||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
|
|||||||
47
tests/cases/test_routine.c
Normal file
47
tests/cases/test_routine.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "toy_routine.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//tests
|
||||||
|
int test_routine_header(Toy_Bucket* bucket) {
|
||||||
|
//simple test to ensure the header looks right
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Ast* ast = NULL;
|
||||||
|
Toy_private_emitAstPass(&bucket, &ast);
|
||||||
|
|
||||||
|
//run
|
||||||
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
|
int len = ((int*)buffer)[0];
|
||||||
|
|
||||||
|
//check
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
TOY_FREE_ARRAY(unsigned char, buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fprintf(stderr, TOY_CC_WARN "WARNING: Routine tests incomplete\n" TOY_CC_RESET);
|
||||||
|
|
||||||
|
//run each test set, returning the total errors given
|
||||||
|
int total = 0, res = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
|
res = test_routine_header(bucket);
|
||||||
|
TOY_BUCKET_FREE(bucket);
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user