Got the compiler partially working

This commit is contained in:
2022-08-05 16:29:12 +01:00
parent 1ff32fe101
commit cd05d5d84a
17 changed files with 601 additions and 26 deletions

1
.gitignore vendored
View File

@@ -21,6 +21,7 @@ out/
*.meta *.meta
*.log *.log
out out
*.stackdump
#Shell files #Shell files
*.bat *.bat

View File

@@ -10,7 +10,7 @@ Special thanks to http://craftinginterpreters.com/ for their fantastic book that
## Building ## Building
TODO Simply run make in the rood directory.
# License # License

View File

@@ -2,3 +2,7 @@ print "hello world";
print null; print null;
print true; print true;
print false; print false;
print 42;
print 3.14;
print -69;
print -4.20;

View File

@@ -7,5 +7,5 @@
#define TOY_VERSION_MAJOR 0 #define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 6 #define TOY_VERSION_MINOR 6
#define TOY_VERSION_PATCH 0 #define TOY_VERSION_PATCH 0
#define TOY_VERSION_BUILD __DATE__ #define TOY_VERSION_BUILD __DATE__ ";" __TIME__

208
source/compiler.c Normal file
View File

@@ -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;
}

21
source/compiler.h Normal file
View File

@@ -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);

View File

@@ -1,6 +1,9 @@
#include "debug.h" #include "debug.h"
#include "keyword_types.h" #include "keyword_types.h"
#include "lexer.h"
#include "parser.h"
#include "compiler.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -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("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("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"); 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);
} }

View File

@@ -19,3 +19,5 @@ void initCommand(int argc, const char* argv[]);
void usageCommand(int argc, const char* argv[]); void usageCommand(int argc, const char* argv[]);
void helpCommand(int argc, const char* argv[]); void helpCommand(int argc, const char* argv[]);
void copyrightCommand(int argc, const char* argv[]); void copyrightCommand(int argc, const char* argv[]);
void dissectBytecode(const char* tb, int size);

86
source/literal_array.c Normal file
View File

@@ -0,0 +1,86 @@
#include "literal_array.h"
#include "memory.h"
#include <stdio.h>
#include <string.h>
//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;
}

16
source/literal_array.h Normal file
View File

@@ -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);

View File

@@ -5,8 +5,9 @@
#define ALLOCATE(type, count) ((type*)reallocate(NULL, 0, sizeof(type) * (count))) #define ALLOCATE(type, count) ((type*)reallocate(NULL, 0, sizeof(type) * (count)))
#define FREE(type, pointer) reallocate(pointer, sizeof(type), 0) #define FREE(type, pointer) reallocate(pointer, sizeof(type), 0)
#define GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2) #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 GROW_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
#define FREE_ARRAY(type, pointer, oldCount) reallocate(pointer, sizeof(type) * (oldCount), 0) #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); void* reallocate(void* pointer, size_t oldSize, size_t newSize);

View File

@@ -6,7 +6,7 @@
void freeNode(Node* node) { void freeNode(Node* node) {
switch(node->type) { switch(node->type) {
case NODE_ATOMIC: case NODE_LITERAL:
freeLiteral(node->atomic.literal); freeLiteral(node->atomic.literal);
break; break;
@@ -23,18 +23,27 @@ void freeNode(Node* node) {
FREE(Node, node); FREE(Node, node);
} }
void emitAtomicLiteral(Node** nodeHandle, Literal literal) { void emitNodeLiteral(Node** nodeHandle, Literal literal) {
//allocate a new node //allocate a new node
*nodeHandle = ALLOCATE(Node, 1); *nodeHandle = ALLOCATE(Node, 1);
(*nodeHandle)->type = NODE_ATOMIC; (*nodeHandle)->type = NODE_LITERAL;
(*nodeHandle)->atomic.literal = 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) { void printNode(Node* node) {
switch(node->type) { switch(node->type) {
case NODE_ATOMIC: case NODE_LITERAL:
printf("atomic:"); printf("literal:");
printLiteral(node->atomic.literal); printLiteral(node->atomic.literal);
break; break;

View File

@@ -1,43 +1,46 @@
#pragma once #pragma once
#include "opcodes.h"
#include "literal.h" #include "literal.h"
#include "opcodes.h"
//nodes are the intermediaries between parsers and compilers //nodes are the intermediaries between parsers and compilers
typedef union _node Node; typedef union _node Node;
typedef enum NodeType { typedef enum NodeType {
NODE_ATOMIC, //a simple value NODE_LITERAL, //a simple value
NODE_UNARY, //one child NODE_UNARY, //one child
NODE_BINARY, //two children, left and right NODE_BINARY, //two children, left and right
// NODE_GROUPING, // NODE_GROUPING,
} NodeType; } NodeType;
typedef struct NodeAtomic { typedef struct NodeLiteral {
NodeType type; NodeType type;
Literal literal; Literal literal;
} NodeAtomic; } NodeLiteral;
typedef struct NodeUnary { typedef struct NodeUnary {
NodeType type; NodeType type;
Opcode opcode;
Node* child; Node* child;
} NodeUnary; } NodeUnary;
typedef struct NodeBinary { typedef struct NodeBinary {
NodeType type; NodeType type;
Opcode opcode;
Node* left; Node* left;
Node* right; Node* right;
} NodeBinary; } NodeBinary;
union _node { union _node {
NodeType type; NodeType type;
NodeAtomic atomic; NodeLiteral atomic;
NodeUnary unary; NodeUnary unary;
NodeBinary binary; NodeBinary binary;
}; };
void freeNode(Node* node); 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); void printNode(Node* node);

View File

@@ -8,7 +8,13 @@ typedef enum Opcode {
//data //data
OP_LITERAL, OP_LITERAL,
OP_LITERAL_LONG, //for more than 256 literals in a chunk
//operators
OP_NEGATE,
//meta
OP_SECTION_END,
//TODO: add more //TODO: add more
} Opcode; } Opcode;

View File

@@ -110,12 +110,12 @@ ParseRule parseRules[];
//forward declarations //forward declarations
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule); 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) { static void string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
//handle strings //handle strings
switch(parser->previous.type) { switch(parser->previous.type) {
case TOKEN_LITERAL_STRING: 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; break;
//TODO: interpolated strings //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) { 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) { static void atomic(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
switch(parser->previous.type) { switch(parser->previous.type) {
case TOKEN_NULL: case TOKEN_NULL:
emitAtomicLiteral(nodeHandle, TO_NULL_LITERAL); emitNodeLiteral(nodeHandle, TO_NULL_LITERAL);
break; break;
case TOKEN_LITERAL_TRUE: case TOKEN_LITERAL_TRUE:
emitAtomicLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true)); emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true));
break; break;
case TOKEN_LITERAL_FALSE: 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; break;
default: default:
@@ -190,13 +236,13 @@ ParseRule parseRules[] = { //must match the token types
{NULL, NULL, PREC_NONE},// TOKEN_IDENTIFIER, {NULL, NULL, PREC_NONE},// TOKEN_IDENTIFIER,
{atomic, NULL, PREC_NONE},// TOKEN_LITERAL_TRUE, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_TRUE,
{atomic, NULL, PREC_NONE},// TOKEN_LITERAL_FALSE, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_FALSE,
{NULL, NULL, PREC_NONE},// TOKEN_LITERAL_INTEGER, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_INTEGER,
{NULL, NULL, PREC_NONE},// TOKEN_LITERAL_FLOAT, {atomic, NULL, PREC_NONE},// TOKEN_LITERAL_FLOAT,
{string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING, {string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
//math operators //math operators
{NULL, NULL, PREC_NONE},// TOKEN_PLUS, {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_MULTIPLY,
{NULL, NULL, PREC_NONE},// TOKEN_DIVIDE, {NULL, NULL, PREC_NONE},// TOKEN_DIVIDE,
{NULL, NULL, PREC_NONE},// TOKEN_MODULO, {NULL, NULL, PREC_NONE},// TOKEN_MODULO,
@@ -287,6 +333,7 @@ static void printStmt(Parser* parser, Node* node) {
//set the node info //set the node info
node->type = NODE_UNARY; node->type = NODE_UNARY;
node->unary.opcode = OP_PRINT;
node->unary.child = ALLOCATE(Node, 1); node->unary.child = ALLOCATE(Node, 1);
expression(parser, &(node->unary.child)); expression(parser, &(node->unary.child));
@@ -329,7 +376,12 @@ void initParser(Parser* parser, Lexer* lexer) {
} }
void freeParser(Parser* parser) { 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) { Node* scanParser(Parser* parser) {

View File

@@ -2,8 +2,11 @@
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
#include "compiler.h"
//#include "toy.h" //#include "toy.h"
#include "memory.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -131,21 +134,34 @@ void repl() {
void debug() { void debug() {
Lexer lexer; Lexer lexer;
Parser parser; Parser parser;
Compiler compiler;
char* source = readFile(command.filename); char* source = readFile(command.filename);
initLexer(&lexer, source); initLexer(&lexer, source);
initParser(&parser, &lexer); initParser(&parser, &lexer);
initCompiler(&compiler);
//run the parser until the end of the source //run the parser until the end of the source
Node* node = scanParser(&parser); Node* node = scanParser(&parser);
while(node != NULL) { while(node != NULL) {
printNode(node); writeCompiler(&compiler, node);
freeNode(node); freeNode(node);
node = scanParser(&parser); 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 //entry point

0
source/token.h Normal file
View File