Implemented groupings

This commit is contained in:
2022-08-07 15:04:19 +01:00
parent d7fda480fd
commit 9a415738d9
9 changed files with 124 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,8 @@ typedef enum Opcode {
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
OP_GROUPING_BEGIN,
OP_GROUPING_END,
//meta
OP_SECTION_END,

View File

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

View File

@@ -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,11 +116,19 @@ 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);
}
if (!error) {
//get the bytecode dump
int size = 0;
char* tb = collateCompiler(&compiler, &size);
@@ -119,10 +137,12 @@ void repl() {
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);