mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Implemented groupings
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
//single line comment
|
||||
|
||||
/*
|
||||
multi line comment
|
||||
*/
|
||||
|
||||
print "hello world";
|
||||
print null;
|
||||
print true;
|
||||
@@ -6,3 +12,9 @@ print 42;
|
||||
print 3.14;
|
||||
print -69;
|
||||
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);
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
||||
}
|
||||
|
||||
//wrong types
|
||||
printf("Bad arithmetic argument");
|
||||
printf("Bad arithmetic argument\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -269,6 +269,13 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_GROUPING_BEGIN:
|
||||
execInterpreter(interpreter);
|
||||
break;
|
||||
|
||||
case OP_GROUPING_END:
|
||||
return;
|
||||
|
||||
default:
|
||||
printf("Unknown opcode found %d, terminating\n", opcode);
|
||||
printLiteralArray(&interpreter->stack, "\n");
|
||||
|
||||
@@ -289,8 +289,11 @@ Token scanLexer(Lexer* lexer) {
|
||||
return makeString(lexer, c);
|
||||
//TODO: possibly support interpolated strings
|
||||
|
||||
default:
|
||||
return makeErrorToken(lexer, "Unexpected token");
|
||||
default: {
|
||||
char buffer[128];
|
||||
snprintf(buffer, 128, "Unexpected token: %c", c);
|
||||
return makeErrorToken(lexer, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void freeNode(Node* node) {
|
||||
//don't free a NULL node
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(node->type) {
|
||||
case NODE_LITERAL:
|
||||
freeLiteral(node->atomic.literal);
|
||||
@@ -18,6 +23,10 @@ void freeNode(Node* node) {
|
||||
freeNode(node->binary.left);
|
||||
freeNode(node->binary.right);
|
||||
break;
|
||||
|
||||
case NODE_GROUPING:
|
||||
freeNode(node->grouping.child);
|
||||
break;
|
||||
}
|
||||
|
||||
FREE(Node, node);
|
||||
@@ -70,5 +79,11 @@ void printNode(Node* node) {
|
||||
printNode(node->binary.right);
|
||||
printf(";");
|
||||
break;
|
||||
|
||||
case NODE_GROUPING:
|
||||
printf("(");
|
||||
printNode(node->grouping.child);
|
||||
printf(")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ typedef enum NodeType {
|
||||
NODE_LITERAL, //a simple value
|
||||
NODE_UNARY, //one child
|
||||
NODE_BINARY, //two children, left and right
|
||||
// NODE_GROUPING,
|
||||
NODE_GROUPING, //one child
|
||||
} NodeType;
|
||||
|
||||
typedef struct NodeLiteral {
|
||||
@@ -32,11 +32,17 @@ typedef struct NodeBinary {
|
||||
Node* right;
|
||||
} NodeBinary;
|
||||
|
||||
typedef struct NodeGrouping {
|
||||
NodeType type;
|
||||
Node* child;
|
||||
} NodeGrouping;
|
||||
|
||||
union _node {
|
||||
NodeType type;
|
||||
NodeLiteral atomic;
|
||||
NodeUnary unary;
|
||||
NodeBinary binary;
|
||||
NodeGrouping grouping;
|
||||
};
|
||||
|
||||
void freeNode(Node* node);
|
||||
|
||||
@@ -18,6 +18,8 @@ typedef enum Opcode {
|
||||
OP_MULTIPLICATION,
|
||||
OP_DIVISION,
|
||||
OP_MODULO,
|
||||
OP_GROUPING_BEGIN,
|
||||
OP_GROUPING_END,
|
||||
|
||||
//meta
|
||||
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) {
|
||||
advance(parser);
|
||||
|
||||
@@ -158,9 +185,9 @@ static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
return OP_MODULO;
|
||||
}
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||
return OP_EOF;
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +326,7 @@ ParseRule parseRules[] = { //must match the token types
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS,
|
||||
|
||||
//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_BRACKET_LEFT,
|
||||
{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;
|
||||
|
||||
if (prefixRule == NULL) {
|
||||
*nodeHandle = NULL; //the handle's value MUST be set to null for error handling
|
||||
error(parser, parser->previous, "Expected expression");
|
||||
return;
|
||||
}
|
||||
|
||||
bool canBeAssigned = rule <= PREC_ASSIGNMENT;
|
||||
prefixRule(parser, nodeHandle, canBeAssigned);
|
||||
prefixRule(parser, nodeHandle, canBeAssigned); //ignore the returned opcode
|
||||
|
||||
//infix rules are left-recursive
|
||||
while (rule <= getRule(parser->current.type)->precedence) {
|
||||
ParseFn infixRule = getRule(parser->current.type)->infix;
|
||||
|
||||
if (infixRule == NULL) {
|
||||
*nodeHandle = NULL; //the handle's value MUST be set to null for error handling
|
||||
error(parser, parser->current, "Expected operator");
|
||||
return;
|
||||
}
|
||||
@@ -528,11 +557,14 @@ static void statement(Parser* parser, Node* node) {
|
||||
expressionStmt(parser, node);
|
||||
}
|
||||
|
||||
static void declaration(Parser* parser, Node* node) {
|
||||
statement(parser, node);
|
||||
static void declaration(Parser* parser, Node** nodeHandle) {
|
||||
statement(parser, *nodeHandle);
|
||||
|
||||
if (parser->panic) {
|
||||
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
|
||||
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
|
||||
declaration(parser, node);
|
||||
declaration(parser, &node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,14 @@ void runString(char* source) {
|
||||
//run the parser until the end of the source
|
||||
Node* node = scanParser(&parser);
|
||||
while(node != NULL) {
|
||||
//pack up and leave
|
||||
if (node->type == NODE_ERROR) {
|
||||
freeNode(node);
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
return;
|
||||
}
|
||||
|
||||
writeCompiler(&compiler, node);
|
||||
freeNode(node);
|
||||
node = scanParser(&parser);
|
||||
@@ -84,6 +92,8 @@ void runFile(char* fname) {
|
||||
}
|
||||
|
||||
void repl() {
|
||||
bool error = false;
|
||||
|
||||
const int size = 2048;
|
||||
char input[size];
|
||||
memset(input, 0, size);
|
||||
@@ -106,23 +116,33 @@ void repl() {
|
||||
//run this iteration
|
||||
Node* node = scanParser(&parser);
|
||||
while(node != NULL) {
|
||||
//pack up and restart
|
||||
if (node->type == NODE_ERROR) {
|
||||
error = true;
|
||||
freeNode(node);
|
||||
break;
|
||||
}
|
||||
|
||||
writeCompiler(&compiler, node);
|
||||
freeNode(node);
|
||||
node = scanParser(&parser);
|
||||
}
|
||||
|
||||
//get the bytecode dump
|
||||
int size = 0;
|
||||
char* tb = collateCompiler(&compiler, &size);
|
||||
if (!error) {
|
||||
//get the bytecode dump
|
||||
int size = 0;
|
||||
char* tb = collateCompiler(&compiler, &size);
|
||||
|
||||
//run the bytecode
|
||||
initInterpreter(&interpreter, tb, size);
|
||||
runInterpreter(&interpreter);
|
||||
freeInterpreter(&interpreter); //TODO: option to retain the scopes
|
||||
//run the bytecode
|
||||
initInterpreter(&interpreter, tb, size);
|
||||
runInterpreter(&interpreter);
|
||||
freeInterpreter(&interpreter); //TODO: option to retain the scopes
|
||||
}
|
||||
|
||||
//clean up this iteration
|
||||
freeCompiler(&compiler);
|
||||
freeParser(&parser);
|
||||
error = false;
|
||||
}
|
||||
|
||||
freeInterpreter(&interpreter);
|
||||
|
||||
Reference in New Issue
Block a user