mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Implemented groupings
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
//single line comment
|
||||||
|
|
||||||
|
/*
|
||||||
|
multi line comment
|
||||||
|
*/
|
||||||
|
|
||||||
print "hello world";
|
print "hello world";
|
||||||
print null;
|
print null;
|
||||||
print true;
|
print true;
|
||||||
@@ -6,3 +12,9 @@ print 42;
|
|||||||
print 3.14;
|
print 3.14;
|
||||||
print -69;
|
print -69;
|
||||||
print -4.20;
|
print -4.20;
|
||||||
|
print 2 + (3 * 3);
|
||||||
|
|
||||||
|
assert true, "This won't be seen";
|
||||||
|
|
||||||
|
assert false, "This is an error";
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ void writeCompiler(Compiler* compiler, Node* node) {
|
|||||||
writeCompiler(compiler, node->binary.right);
|
writeCompiler(compiler, node->binary.right);
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_GROUPING:
|
||||||
|
compiler->bytecode[compiler->count++] = OP_GROUPING_BEGIN; //1 byte
|
||||||
|
writeCompiler(compiler, node->grouping.child);
|
||||||
|
compiler->bytecode[compiler->count++] = OP_GROUPING_END; //1 byte
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
|||||||
|
|
||||||
//catch bad modulo
|
//catch bad modulo
|
||||||
if (opcode == OP_MODULO) {
|
if (opcode == OP_MODULO) {
|
||||||
printf("Bad arithmetic argument (modulo on floats not allowed)");
|
printf("Bad arithmetic argument (modulo on floats not allowed)\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//wrong types
|
//wrong types
|
||||||
printf("Bad arithmetic argument");
|
printf("Bad arithmetic argument\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +269,13 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_GROUPING_BEGIN:
|
||||||
|
execInterpreter(interpreter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GROUPING_END:
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Unknown opcode found %d, terminating\n", opcode);
|
printf("Unknown opcode found %d, terminating\n", opcode);
|
||||||
printLiteralArray(&interpreter->stack, "\n");
|
printLiteralArray(&interpreter->stack, "\n");
|
||||||
|
|||||||
@@ -289,8 +289,11 @@ Token scanLexer(Lexer* lexer) {
|
|||||||
return makeString(lexer, c);
|
return makeString(lexer, c);
|
||||||
//TODO: possibly support interpolated strings
|
//TODO: possibly support interpolated strings
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
return makeErrorToken(lexer, "Unexpected token");
|
char buffer[128];
|
||||||
|
snprintf(buffer, 128, "Unexpected token: %c", c);
|
||||||
|
return makeErrorToken(lexer, buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void freeNode(Node* node) {
|
void freeNode(Node* node) {
|
||||||
|
//don't free a NULL node
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
case NODE_LITERAL:
|
case NODE_LITERAL:
|
||||||
freeLiteral(node->atomic.literal);
|
freeLiteral(node->atomic.literal);
|
||||||
@@ -18,6 +23,10 @@ void freeNode(Node* node) {
|
|||||||
freeNode(node->binary.left);
|
freeNode(node->binary.left);
|
||||||
freeNode(node->binary.right);
|
freeNode(node->binary.right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_GROUPING:
|
||||||
|
freeNode(node->grouping.child);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(Node, node);
|
FREE(Node, node);
|
||||||
@@ -70,5 +79,11 @@ void printNode(Node* node) {
|
|||||||
printNode(node->binary.right);
|
printNode(node->binary.right);
|
||||||
printf(";");
|
printf(";");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_GROUPING:
|
||||||
|
printf("(");
|
||||||
|
printNode(node->grouping.child);
|
||||||
|
printf(")");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ typedef enum NodeType {
|
|||||||
NODE_LITERAL, //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, //one child
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct NodeLiteral {
|
||||||
@@ -32,11 +32,17 @@ typedef struct NodeBinary {
|
|||||||
Node* right;
|
Node* right;
|
||||||
} NodeBinary;
|
} NodeBinary;
|
||||||
|
|
||||||
|
typedef struct NodeGrouping {
|
||||||
|
NodeType type;
|
||||||
|
Node* child;
|
||||||
|
} NodeGrouping;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
NodeUnary unary;
|
NodeUnary unary;
|
||||||
NodeBinary binary;
|
NodeBinary binary;
|
||||||
|
NodeGrouping grouping;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ typedef enum Opcode {
|
|||||||
OP_MULTIPLICATION,
|
OP_MULTIPLICATION,
|
||||||
OP_DIVISION,
|
OP_DIVISION,
|
||||||
OP_MODULO,
|
OP_MODULO,
|
||||||
|
OP_GROUPING_BEGIN,
|
||||||
|
OP_GROUPING_END,
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_SECTION_END,
|
OP_SECTION_END,
|
||||||
|
|||||||
@@ -128,6 +128,33 @@ static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Opcode grouping(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||||
|
//handle three diffent types of groupings: (), {}, []
|
||||||
|
switch(parser->previous.type) {
|
||||||
|
case TOKEN_PAREN_LEFT: {
|
||||||
|
Node* tmpNode = NULL;
|
||||||
|
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
|
||||||
|
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of grouping");
|
||||||
|
|
||||||
|
//if it's just a literal, don't need a grouping
|
||||||
|
if (command.optimize >= 1 && tmpNode->type == NODE_LITERAL) {
|
||||||
|
(*nodeHandle) = tmpNode;
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
//process the result without optimisations
|
||||||
|
emitNodeUnary(nodeHandle, NODE_GROUPING);
|
||||||
|
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
||||||
|
(*nodeHandle) = tmpNode;
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(parser, parser->previous, "Unexpected token passed to grouping precedence rule");
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
@@ -299,7 +326,7 @@ ParseRule parseRules[] = { //must match the token types
|
|||||||
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS,
|
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS,
|
||||||
|
|
||||||
//logical operators
|
//logical operators
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_LEFT,
|
{grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
{NULL, NULL, PREC_NONE},// TOKEN_PAREN_RIGHT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_LEFT,
|
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_LEFT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT,
|
{NULL, NULL, PREC_NONE},// TOKEN_BRACKET_RIGHT,
|
||||||
@@ -447,18 +474,20 @@ static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule ru
|
|||||||
ParseFn prefixRule = getRule(parser->previous.type)->prefix;
|
ParseFn prefixRule = getRule(parser->previous.type)->prefix;
|
||||||
|
|
||||||
if (prefixRule == NULL) {
|
if (prefixRule == NULL) {
|
||||||
|
*nodeHandle = NULL; //the handle's value MUST be set to null for error handling
|
||||||
error(parser, parser->previous, "Expected expression");
|
error(parser, parser->previous, "Expected expression");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canBeAssigned = rule <= PREC_ASSIGNMENT;
|
bool canBeAssigned = rule <= PREC_ASSIGNMENT;
|
||||||
prefixRule(parser, nodeHandle, canBeAssigned);
|
prefixRule(parser, nodeHandle, canBeAssigned); //ignore the returned opcode
|
||||||
|
|
||||||
//infix rules are left-recursive
|
//infix rules are left-recursive
|
||||||
while (rule <= getRule(parser->current.type)->precedence) {
|
while (rule <= getRule(parser->current.type)->precedence) {
|
||||||
ParseFn infixRule = getRule(parser->current.type)->infix;
|
ParseFn infixRule = getRule(parser->current.type)->infix;
|
||||||
|
|
||||||
if (infixRule == NULL) {
|
if (infixRule == NULL) {
|
||||||
|
*nodeHandle = NULL; //the handle's value MUST be set to null for error handling
|
||||||
error(parser, parser->current, "Expected operator");
|
error(parser, parser->current, "Expected operator");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -528,11 +557,14 @@ static void statement(Parser* parser, Node* node) {
|
|||||||
expressionStmt(parser, node);
|
expressionStmt(parser, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void declaration(Parser* parser, Node* node) {
|
static void declaration(Parser* parser, Node** nodeHandle) {
|
||||||
statement(parser, node);
|
statement(parser, *nodeHandle);
|
||||||
|
|
||||||
if (parser->panic) {
|
if (parser->panic) {
|
||||||
synchronize(parser);
|
synchronize(parser);
|
||||||
|
//return an error node for this iteration
|
||||||
|
*nodeHandle = ALLOCATE(Node, 1);
|
||||||
|
(*nodeHandle)->type = NODE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,10 +596,10 @@ Node* scanParser(Parser* parser) {
|
|||||||
|
|
||||||
//returns nodes on the heap
|
//returns nodes on the heap
|
||||||
Node* node = ALLOCATE(Node, 1);
|
Node* node = ALLOCATE(Node, 1);
|
||||||
|
node->type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
|
||||||
|
|
||||||
//process the grammar rule for this line
|
//process the grammar rule for this line
|
||||||
declaration(parser, node);
|
declaration(parser, &node);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,14 @@ void runString(char* source) {
|
|||||||
//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) {
|
||||||
|
//pack up and leave
|
||||||
|
if (node->type == NODE_ERROR) {
|
||||||
|
freeNode(node);
|
||||||
|
freeCompiler(&compiler);
|
||||||
|
freeParser(&parser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
@@ -84,6 +92,8 @@ void runFile(char* fname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void repl() {
|
void repl() {
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
const int size = 2048;
|
const int size = 2048;
|
||||||
char input[size];
|
char input[size];
|
||||||
memset(input, 0, size);
|
memset(input, 0, size);
|
||||||
@@ -106,11 +116,19 @@ void repl() {
|
|||||||
//run this iteration
|
//run this iteration
|
||||||
Node* node = scanParser(&parser);
|
Node* node = scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
|
//pack up and restart
|
||||||
|
if (node->type == NODE_ERROR) {
|
||||||
|
error = true;
|
||||||
|
freeNode(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
writeCompiler(&compiler, node);
|
||||||
freeNode(node);
|
freeNode(node);
|
||||||
node = scanParser(&parser);
|
node = scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
//get the bytecode dump
|
//get the bytecode dump
|
||||||
int size = 0;
|
int size = 0;
|
||||||
char* tb = collateCompiler(&compiler, &size);
|
char* tb = collateCompiler(&compiler, &size);
|
||||||
@@ -119,10 +137,12 @@ void repl() {
|
|||||||
initInterpreter(&interpreter, tb, size);
|
initInterpreter(&interpreter, tb, size);
|
||||||
runInterpreter(&interpreter);
|
runInterpreter(&interpreter);
|
||||||
freeInterpreter(&interpreter); //TODO: option to retain the scopes
|
freeInterpreter(&interpreter); //TODO: option to retain the scopes
|
||||||
|
}
|
||||||
|
|
||||||
//clean up this iteration
|
//clean up this iteration
|
||||||
freeCompiler(&compiler);
|
freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
freeParser(&parser);
|
||||||
|
error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeInterpreter(&interpreter);
|
freeInterpreter(&interpreter);
|
||||||
|
|||||||
Reference in New Issue
Block a user