diff --git a/.gitignore b/.gitignore index bf0b70e..d0908d9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ out/ *.meta *.log out +*.stackdump #Shell files *.bat diff --git a/README.md b/README.md index 0833482..a1e1b35 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that ## Building -TODO +Simply run make in the rood directory. # License diff --git a/scripts/example.toy b/scripts/example.toy index c265ca3..12e97c8 100644 --- a/scripts/example.toy +++ b/scripts/example.toy @@ -2,3 +2,7 @@ print "hello world"; print null; print true; print false; +print 42; +print 3.14; +print -69; +print -4.20; \ No newline at end of file diff --git a/source/common.h b/source/common.h index 4973003..e7dbf3d 100644 --- a/source/common.h +++ b/source/common.h @@ -7,5 +7,5 @@ #define TOY_VERSION_MAJOR 0 #define TOY_VERSION_MINOR 6 #define TOY_VERSION_PATCH 0 -#define TOY_VERSION_BUILD __DATE__ +#define TOY_VERSION_BUILD __DATE__ ";" __TIME__ diff --git a/source/compiler.c b/source/compiler.c new file mode 100644 index 0000000..f163060 --- /dev/null +++ b/source/compiler.c @@ -0,0 +1,208 @@ +#include "compiler.h" + +#include "memory.h" + +void initCompiler(Compiler* compiler) { + initLiteralArray(&compiler->literalCache); + compiler->bytecode = NULL; + compiler->capacity = 0; + compiler->count = 0; + + //default atomic literals + Literal n = TO_NULL_LITERAL; + Literal t = TO_BOOLEAN_LITERAL(true); + Literal f = TO_BOOLEAN_LITERAL(false); + + writeLiteralArray(&compiler->literalCache, n); + writeLiteralArray(&compiler->literalCache, t); + writeLiteralArray(&compiler->literalCache, f); +} + +void writeCompiler(Compiler* compiler, Node* node) { + //grow if the bytecode space is too small + if (compiler->capacity < compiler->count + 8) { //assume 8 is the maximum space needed by each instruction (can change later) + int oldCapacity = compiler->capacity; + + compiler->capacity = GROW_CAPACITY(oldCapacity); + compiler->bytecode = GROW_ARRAY(unsigned char, compiler->bytecode, oldCapacity, compiler->capacity); + } + + //determine node type + switch(node->type) { + case NODE_LITERAL: { + //ensure the literal is in the cache + int index = findLiteralIndex(&compiler->literalCache, node->atomic.literal); + if (index < 0) { + index = writeLiteralArray(&compiler->literalCache, node->atomic.literal); + } + + //push the node opcode to the bytecode + if (index >= 256) { + //push a "long" index + compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes + + compiler->count += sizeof(unsigned short); + } + else { + //push the index + compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte + compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte + } + } + break; + + case NODE_UNARY: + //pass to the child node, then embed the unary command (print, negate, etc.) + writeCompiler(compiler, node->unary.child); + compiler->bytecode[compiler->count++] = (unsigned char)node->unary.opcode; //1 byte + break; + + case NODE_BINARY: + //pass to the child nodes, then embed the binary command (math, etc.) + writeCompiler(compiler, node->binary.left); + writeCompiler(compiler, node->binary.right); + compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte + break; + } +} + +void freeCompiler(Compiler* compiler) { + freeLiteralArray(&compiler->literalCache); + FREE(unsigned char, compiler->bytecode); + compiler->bytecode = NULL; + compiler->capacity = 0; + compiler->count = 0; +} + +static void emitByte(char** collationPtr, int* capacityPtr, int* countPtr, unsigned char byte) { + //grow the array + if (*countPtr + 1 > *capacityPtr) { + int oldCapacity = *capacityPtr; + *capacityPtr = GROW_CAPACITY(*capacityPtr); + *collationPtr = GROW_ARRAY(char, *collationPtr, oldCapacity, *capacityPtr); + } + + //append to the collation + (*collationPtr)[(*countPtr)++] = byte; +} + +static void emitShort(char** collationPtr, int* capacityPtr, int* countPtr, unsigned short bytes) { + char* ptr = (char*)&bytes; + + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); +} + +static void emitInt(char** collationPtr, int* capacityPtr, int* countPtr, int bytes) { + char* ptr = (char*)&bytes; + + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); +} + +static void emitFloat(char** collationPtr, int* capacityPtr, int* countPtr, float bytes) { + char* ptr = (char*)&bytes; + + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); + ptr++; + emitByte(collationPtr, capacityPtr, countPtr, *ptr); +} + +//return the result +char* collateCompiler(Compiler* compiler, int* size) { + int capacity = GROW_CAPACITY(0); + int count = 0; + char* collation = ALLOCATE(char, capacity); + + //embed the header with version information + emitByte(&collation, &capacity, &count, TOY_VERSION_MAJOR); + emitByte(&collation, &capacity, &count, TOY_VERSION_MINOR); + emitByte(&collation, &capacity, &count, TOY_VERSION_PATCH); + + //embed the build info + if (strlen(TOY_VERSION_BUILD) + count + 1 > capacity) { + int oldCapacity = capacity; + capacity = strlen(TOY_VERSION_BUILD) + count + 1; //full header size + collation = GROW_ARRAY(char, collation, oldCapacity, capacity); + } + + memcpy(&collation[count], TOY_VERSION_BUILD, strlen(TOY_VERSION_BUILD)); + count += strlen(TOY_VERSION_BUILD); + collation[count++] = '\0'; //terminate the build string + + emitByte(&collation, &capacity, &count, OP_SECTION_END); //terminate header + + //embed the data section (first short is the number of literals) + emitShort(&collation, &capacity, &count, compiler->literalCache.count); + + //emit each literal by type + for (int i = 0; i < compiler->literalCache.count; i++) { + //literal Opcode + // emitShort(&collation, &capacity, &count, OP_LITERAL); //This isn't needed + + //literal type, followed by literal value + switch(compiler->literalCache.literals[i].type) { + case LITERAL_NULL: + emitByte(&collation, &capacity, &count, LITERAL_NULL); + //null has no following value + break; + + case LITERAL_BOOLEAN: + emitByte(&collation, &capacity, &count, LITERAL_BOOLEAN); + emitByte(&collation, &capacity, &count, AS_BOOLEAN(compiler->literalCache.literals[i])); + break; + + case LITERAL_INTEGER: + emitByte(&collation, &capacity, &count, LITERAL_INTEGER); + emitInt(&collation, &capacity, &count, AS_INTEGER(compiler->literalCache.literals[i])); + break; + + case LITERAL_FLOAT: + emitByte(&collation, &capacity, &count, LITERAL_FLOAT); + emitFloat(&collation, &capacity, &count, AS_FLOAT(compiler->literalCache.literals[i])); + break; + + case LITERAL_STRING: { + emitByte(&collation, &capacity, &count, LITERAL_STRING); + + Literal str = compiler->literalCache.literals[i]; + + for (int c = 0; c < STRLEN(str); c++) { + emitByte(&collation, &capacity, &count, AS_STRING(str)[c]); + } + + emitByte(&collation, &capacity, &count, '\0'); //terminate the string + } + break; + } + } + + emitByte(&collation, &capacity, &count, OP_SECTION_END); //terminate data + + //code section + for (int i = 0; i < compiler->count; i++) { + emitByte(&collation, &capacity, &count, compiler->bytecode[i]); + } + + emitByte(&collation, &capacity, &count, OP_SECTION_END); //terminate code + + emitByte(&collation, &capacity, &count, OP_EOF); //terminate bytecode + + //finalize + SHRINK_ARRAY(char, collation, capacity, count); + + *size = count; + + return collation; +} \ No newline at end of file diff --git a/source/compiler.h b/source/compiler.h new file mode 100644 index 0000000..c186453 --- /dev/null +++ b/source/compiler.h @@ -0,0 +1,21 @@ +#pragma once + +#include "opcodes.h" + +#include "node.h" +#include "literal_array.h" + +//the compiler takes the nodes, and turns them into sequential chunks of bytecode, saving literals to an external array +typedef struct Compiler { + LiteralArray literalCache; + unsigned char* bytecode; + int capacity; + int count; +} Compiler; + +void initCompiler(Compiler* compiler); +void writeCompiler(Compiler* compiler, Node* node); +void freeCompiler(Compiler* compiler); + +//embed the header with version information, data section, code section, etc. +char* collateCompiler(Compiler* compiler, int* size); diff --git a/source/debug.c b/source/debug.c index 7aecd8b..3c2bcea 100644 --- a/source/debug.c +++ b/source/debug.c @@ -1,6 +1,9 @@ #include "debug.h" #include "keyword_types.h" +#include "lexer.h" +#include "parser.h" +#include "compiler.h" #include #include @@ -77,4 +80,151 @@ void copyrightCommand(int argc, const char* argv[]) { printf("1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n\n"); printf("2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n\n"); printf("3. This notice may not be removed or altered from any source distribution.\n\n"); +} + +//utils +static unsigned char printByte(const char* tb, int* count) { + unsigned char ret = *(unsigned char*)(tb + *count); + printf("%u ", ret); + *count += 1; + return ret; +} + +static unsigned short printShort(const char* tb, int* count) { + unsigned short ret = *(unsigned short*)(tb + *count); + printf("%d ", ret); + *count += 2; + return ret; +} + +static int printInt(const char* tb, int* count) { + int ret = *(int*)(tb + *count); + printf("%d ", ret); + *count += 4; + return ret; +} + +static float printFloat(const char* tb, int* count) { + float ret = *(float*)(tb + *count); + printf("%f ", ret); + *count += 4; + return ret; +} + +static const char* printString(const char* tb, int* count) { + const char* ret = tb + *count; + *count += printf("%s ", ret); //return includes the space, but not the null terminator + return ret; +} + +static void consumeByte(unsigned char byte, const char* str, int* count) { + if (byte != str[*count]) { + printf("Failed to consume the correct byte"); + } + *count += 1; +} + +static void consumeShort(unsigned short bytes, const char* str, int* count) { + if (bytes != *(unsigned short*)(str + *count)) { + printf("Failed to consume the correct byte"); + } + *count += 2; +} + +void dissectBytecode(const char* tb, int size) { + int count = 0; + + //header + printf("--header--\n"); + printByte(tb, &count); + printByte(tb, &count); + printByte(tb, &count); + printString(tb, &count); + consumeByte(OP_SECTION_END, tb, &count); + + printf("\n"); + + //data + printf("--data--\n"); + const short literalCount = printShort(tb, &count); + + for (int i = 0; i < literalCount; i++) { + const unsigned char literalType = printByte(tb, &count); + + switch(literalType) { + case LITERAL_NULL: + //NO-OP + printf("(null)"); + break; + + case LITERAL_BOOLEAN: { + const bool b = printByte(tb, &count); + printf("(boolean %s)", b ? "true" : "false"); + } + break; + + case LITERAL_INTEGER: { + const int d = printInt(tb, &count); + printf("(integer %d)", d); + } + break; + + case LITERAL_FLOAT: { + const float f = printFloat(tb, &count); + printf("(float %f)", f); + } + break; + + case LITERAL_STRING: { + const s = printString(tb, &count); + printf("(string)"); + } + break; + } + + printf("\n"); + } + + consumeByte(OP_SECTION_END, tb, &count); + + //code + printf("--bytecode--\n"); + while(tb[count] != OP_EOF) { + const opcode = printByte(tb, &count); + + switch (opcode) { + case OP_PRINT: + printf("print:\n"); + break; + + case OP_LITERAL: { + printf("literal "); + printByte(tb, &count); + printf("\n"); + } + break; + + case OP_LITERAL_LONG: { + printf("long literal "); + printByte(tb, &count); + printf("\n"); + } + break; + + case OP_NEGATE: { + printf("negate\n"); + } + break; + + case OP_SECTION_END: { + printf("--SECTION END--"); + } + break; + + default: + printf("Unknown opcode found\n"); + } + } + + consumeByte(OP_EOF, tb, &count); } \ No newline at end of file diff --git a/source/debug.h b/source/debug.h index 7dc7ad2..08e835e 100644 --- a/source/debug.h +++ b/source/debug.h @@ -19,3 +19,5 @@ void initCommand(int argc, const char* argv[]); void usageCommand(int argc, const char* argv[]); void helpCommand(int argc, const char* argv[]); void copyrightCommand(int argc, const char* argv[]); + +void dissectBytecode(const char* tb, int size); \ No newline at end of file diff --git a/source/literal_array.c b/source/literal_array.c new file mode 100644 index 0000000..890b549 --- /dev/null +++ b/source/literal_array.c @@ -0,0 +1,86 @@ +#include "literal_array.h" + +#include "memory.h" + +#include +#include + +//exposed functions +void initLiteralArray(LiteralArray* array) { + array->capacity = 0; + array->count = 0; + array->literals = NULL; +} + +int writeLiteralArray(LiteralArray* array, Literal literal) { + if (array->capacity < array->count + 1) { + int oldCapacity = array->capacity; + + array->capacity = GROW_CAPACITY(oldCapacity); + array->literals = GROW_ARRAY(Literal, array->literals, oldCapacity, array->capacity); + } + + //if it's a string, make a local copy + if (IS_STRING(literal)) { + literal = TO_STRING_LITERAL(copyString(AS_STRING(literal), STRLEN(literal))); + } + + array->literals[array->count] = literal; + return array->count++; +} + +void freeLiteralArray(LiteralArray* array) { + //clean up memory + for(int i = 0; i < array->count; i++) { + freeLiteral(array->literals[i]); + } + + FREE_ARRAY(Literal, array->literals, array->capacity); + initLiteralArray(array); +} + +//find a literal in the array that matches the "literal" argument +int findLiteralIndex(LiteralArray* array, Literal literal) { + for (int i = 0; i < array->count; i++) { + //not the same type + if (array->literals[i].type != literal.type) { + continue; + } + + //matching type, compare values + switch(array->literals[i].type) { + case LITERAL_NULL: + return i; + + case LITERAL_BOOLEAN: + if (AS_BOOLEAN(array->literals[i]) == AS_BOOLEAN(literal)) { + return i; + } + break; + + case LITERAL_INTEGER: + if (AS_INTEGER(array->literals[i]) == AS_INTEGER(literal)) { + return i; + } + break; + + case LITERAL_FLOAT: + if (AS_FLOAT(array->literals[i]) == AS_FLOAT(literal)) { + return i; + } + break; + + case LITERAL_STRING: + if (strcmp(AS_STRING(array->literals[i]), AS_STRING(literal)) == 0) { + return i; + } + break; + + default: + fprintf(stderr, "[Internal] Unexpected literal type in findLiteralIndex(): %d\n", literal.type); + break; + } + } + + return -1; +} diff --git a/source/literal_array.h b/source/literal_array.h new file mode 100644 index 0000000..9039bf6 --- /dev/null +++ b/source/literal_array.h @@ -0,0 +1,16 @@ +#pragma once + +#include "literal.h" + +typedef struct LiteralArray { + int capacity; + int count; + Literal* literals; +} LiteralArray; + +void initLiteralArray(LiteralArray* array); +int writeLiteralArray(LiteralArray* array, Literal literal); +void freeLiteralArray(LiteralArray* array); + +int findLiteralIndex(LiteralArray* array, Literal literal); + diff --git a/source/memory.h b/source/memory.h index 30e5dcc..05575b3 100644 --- a/source/memory.h +++ b/source/memory.h @@ -5,8 +5,9 @@ #define ALLOCATE(type, count) ((type*)reallocate(NULL, 0, sizeof(type) * (count))) #define FREE(type, pointer) reallocate(pointer, sizeof(type), 0) #define GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2) -#define GROW_ARRAY(type, pointer, oldCount, count) (type*)reallocate(pointer, sizeof(type) * (oldCount), sizeof(type) * (count)) -#define FREE_ARRAY(type, pointer, oldCount) reallocate(pointer, sizeof(type) * (oldCount), 0) +#define GROW_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count)) +#define SHRINK_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count)) +#define FREE_ARRAY(type, pointer, oldCount) reallocate((type*)pointer, sizeof(type) * (oldCount), 0) void* reallocate(void* pointer, size_t oldSize, size_t newSize); diff --git a/source/node.c b/source/node.c index 37b9596..18eef81 100644 --- a/source/node.c +++ b/source/node.c @@ -6,7 +6,7 @@ void freeNode(Node* node) { switch(node->type) { - case NODE_ATOMIC: + case NODE_LITERAL: freeLiteral(node->atomic.literal); break; @@ -23,18 +23,27 @@ void freeNode(Node* node) { FREE(Node, node); } -void emitAtomicLiteral(Node** nodeHandle, Literal literal) { +void emitNodeLiteral(Node** nodeHandle, Literal literal) { //allocate a new node *nodeHandle = ALLOCATE(Node, 1); - (*nodeHandle)->type = NODE_ATOMIC; + (*nodeHandle)->type = NODE_LITERAL; (*nodeHandle)->atomic.literal = literal; } +void emitNodeUnary(Node** nodeHandle, Opcode opcode) { + //allocate a new node + *nodeHandle = ALLOCATE(Node, 1); + + (*nodeHandle)->type = NODE_UNARY; + (*nodeHandle)->unary.opcode = opcode; + (*nodeHandle)->unary.child = NULL; +} + void printNode(Node* node) { switch(node->type) { - case NODE_ATOMIC: - printf("atomic:"); + case NODE_LITERAL: + printf("literal:"); printLiteral(node->atomic.literal); break; diff --git a/source/node.h b/source/node.h index 3b3bc86..058e044 100644 --- a/source/node.h +++ b/source/node.h @@ -1,43 +1,46 @@ #pragma once -#include "opcodes.h" #include "literal.h" +#include "opcodes.h" //nodes are the intermediaries between parsers and compilers typedef union _node Node; typedef enum NodeType { - NODE_ATOMIC, //a simple value + NODE_LITERAL, //a simple value NODE_UNARY, //one child NODE_BINARY, //two children, left and right // NODE_GROUPING, } NodeType; -typedef struct NodeAtomic { +typedef struct NodeLiteral { NodeType type; Literal literal; -} NodeAtomic; +} NodeLiteral; typedef struct NodeUnary { NodeType type; + Opcode opcode; Node* child; } NodeUnary; typedef struct NodeBinary { NodeType type; + Opcode opcode; Node* left; Node* right; } NodeBinary; union _node { NodeType type; - NodeAtomic atomic; + NodeLiteral atomic; NodeUnary unary; NodeBinary binary; }; void freeNode(Node* node); -void emitAtomicLiteral(Node** nodeHandle, Literal literal); +void emitNodeLiteral(Node** nodeHandle, Literal literal); +void emitNodeUnary(Node** nodeHandle, Opcode opcode); void printNode(Node* node); diff --git a/source/opcodes.h b/source/opcodes.h index 4ef776c..4272183 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -8,7 +8,13 @@ typedef enum Opcode { //data OP_LITERAL, + OP_LITERAL_LONG, //for more than 256 literals in a chunk + //operators + OP_NEGATE, + + //meta + OP_SECTION_END, //TODO: add more } Opcode; diff --git a/source/parser.c b/source/parser.c index b26ff3d..7cd1ae0 100644 --- a/source/parser.c +++ b/source/parser.c @@ -110,12 +110,12 @@ ParseRule parseRules[]; //forward declarations static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule); -//the atomic expression rules +//the expression rules static void string(Parser* parser, Node** nodeHandle, bool canBeAssigned) { //handle strings switch(parser->previous.type) { case TOKEN_LITERAL_STRING: - emitAtomicLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, parser->previous.length))); + emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, parser->previous.length))); break; //TODO: interpolated strings @@ -130,21 +130,67 @@ static void binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) { } static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) { - //TODO + switch(parser->previous.type) { + case TOKEN_MINUS: + //temp handle to potentially negate values + Node* tmpNode = NULL; + parsePrecedence(parser, &tmpNode, PREC_TERNARY); + + //check for literals + if (tmpNode->type == NODE_LITERAL) { + //negate directly, if int or float + Literal lit = tmpNode->atomic.literal; + + if (IS_INTEGER(lit)) { + lit = TO_INTEGER_LITERAL( -AS_INTEGER(lit) ); + } + + if (IS_FLOAT(lit)) { + lit = TO_FLOAT_LITERAL( -AS_FLOAT(lit) ); + } + + tmpNode->atomic.literal = lit; + *nodeHandle = tmpNode; + } + else { + //process normally + emitNodeUnary(nodeHandle, OP_NEGATE); + parsePrecedence(parser, nodeHandle, PREC_TERNARY); + } + + break; + + default: + error(parser, parser->previous, "Unexpected token passed to unary precedence rule"); + } } static void atomic(Parser* parser, Node** nodeHandle, bool canBeAssigned) { switch(parser->previous.type) { case TOKEN_NULL: - emitAtomicLiteral(nodeHandle, TO_NULL_LITERAL); + emitNodeLiteral(nodeHandle, TO_NULL_LITERAL); break; case TOKEN_LITERAL_TRUE: - emitAtomicLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true)); + emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true)); break; case TOKEN_LITERAL_FALSE: - emitAtomicLiteral(nodeHandle, TO_BOOLEAN_LITERAL(false)); + emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(false)); + break; + + case TOKEN_LITERAL_INTEGER: { + int value = 0; + sscanf(parser->previous.lexeme, "%d", &value); + emitNodeLiteral(nodeHandle, TO_INTEGER_LITERAL(value)); + } + break; + + case TOKEN_LITERAL_FLOAT: { + float value = 0; + sscanf(parser->previous.lexeme, "%f", &value); + emitNodeLiteral(nodeHandle, TO_FLOAT_LITERAL(value)); + } break; default: @@ -190,13 +236,13 @@ ParseRule parseRules[] = { //must match the token types {NULL, NULL, PREC_NONE},// TOKEN_IDENTIFIER, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_TRUE, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_FALSE, - {NULL, NULL, PREC_NONE},// TOKEN_LITERAL_INTEGER, - {NULL, NULL, PREC_NONE},// TOKEN_LITERAL_FLOAT, + {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_INTEGER, + {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_FLOAT, {string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING, //math operators {NULL, NULL, PREC_NONE},// TOKEN_PLUS, - {NULL, NULL, PREC_NONE},// TOKEN_MINUS, + {unary, NULL, PREC_NONE},// TOKEN_MINUS, {NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY, {NULL, NULL, PREC_NONE},// TOKEN_DIVIDE, {NULL, NULL, PREC_NONE},// TOKEN_MODULO, @@ -287,6 +333,7 @@ static void printStmt(Parser* parser, Node* node) { //set the node info node->type = NODE_UNARY; + node->unary.opcode = OP_PRINT; node->unary.child = ALLOCATE(Node, 1); expression(parser, &(node->unary.child)); @@ -329,7 +376,12 @@ void initParser(Parser* parser, Lexer* lexer) { } void freeParser(Parser* parser) { - initParser(parser, NULL); + parser->lexer = NULL; + parser->error = false; + parser->panic = false; + + parser->previous.type = TOKEN_NULL; + parser->current.type = TOKEN_NULL; } Node* scanParser(Parser* parser) { diff --git a/source/repl_main.c b/source/repl_main.c index d946772..ab5380e 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -2,8 +2,11 @@ #include "lexer.h" #include "parser.h" +#include "compiler.h" //#include "toy.h" +#include "memory.h" + #include #include #include @@ -131,21 +134,34 @@ void repl() { void debug() { Lexer lexer; Parser parser; + Compiler compiler; char* source = readFile(command.filename); initLexer(&lexer, source); initParser(&parser, &lexer); + initCompiler(&compiler); //run the parser until the end of the source Node* node = scanParser(&parser); while(node != NULL) { - printNode(node); + writeCompiler(&compiler, node); freeNode(node); node = scanParser(&parser); } + + //get the data dump + int size = 0; + const char* tb = collateCompiler(&compiler, &size); + + dissectBytecode(tb, size); + + //cleanup + FREE_ARRAY(char, tb, size); + freeCompiler(&compiler); + freeParser(&parser); } //entry point diff --git a/source/token.h b/source/token.h new file mode 100644 index 0000000..e69de29