If-then-else is working with jump statements

This commit is contained in:
2022-08-20 12:38:29 +01:00
parent cbdfcbcc14
commit 975ed41d14
8 changed files with 223 additions and 2 deletions

View File

@@ -288,7 +288,47 @@ void writeCompiler(Compiler* compiler, Node* node) {
} }
break; break;
//TODO: OP_VAR_ASSIGN case NODE_PATH_IF: {
//process the condition
writeCompiler(compiler, node->path.condition);
//cache the point to insert the jump distance at
compiler->bytecode[compiler->count++] = OP_IF_FALSE_JUMP; //1 byte
int jumpToElse = compiler->count;
compiler->count += sizeof(unsigned short); //2 bytes
//write the then path
writeCompiler(compiler, node->path.thenPath);
int jumpToEnd = 0;
if (node->path.elsePath) {
//insert jump to end
compiler->bytecode[compiler->count++] = OP_JUMP; //1 byte
jumpToEnd = compiler->count;
compiler->count += sizeof(unsigned short); //2 bytes
}
//update the jumpToElse to point here
compiler->bytecode[jumpToElse] = compiler->count;
if (node->path.elsePath) {
//if there's an else path, write it and
writeCompiler(compiler, node->path.elsePath);
//update the jumpToEnd to point here
compiler->bytecode[jumpToEnd] = compiler->count;
}
}
break;
// case NODE_PATH_WHILE: {
// //cache the jump point
// int jumpToBeginning = compiler->count;
// compiler->count += sizeof(unsigned short); //2 bytes
// //
// }
} }
} }

View File

@@ -570,6 +570,42 @@ static bool execCompareLessEqual(Interpreter* interpreter, bool invert) {
return true; return true;
} }
static bool execJump(Interpreter* interpreter) {
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
if (target >= interpreter->length) {
printf("Jump out of range\n");
return false;
}
//actually jump
interpreter->count = target + interpreter->codeStart;
return true;
}
static bool execFalseJump(Interpreter* interpreter) {
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
if (target >= interpreter->length) {
printf("Jump out of range\n");
return false;
}
//actually jump
Literal lit = popLiteralArray(&interpreter->stack);
if (!parseIdentifierToValue(interpreter, &lit)) {
return false;
}
if (!IS_TRUTHY(lit)) {
interpreter->count = target + interpreter->codeStart;
}
return true;
}
//the heart of toy //the heart of toy
static void execInterpreter(Interpreter* interpreter) { static void execInterpreter(Interpreter* interpreter) {
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count); unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
@@ -690,6 +726,18 @@ static void execInterpreter(Interpreter* interpreter) {
} }
break; break;
case OP_JUMP:
if (!execJump(interpreter)) {
return;
}
break;
case OP_IF_FALSE_JUMP:
if (!execFalseJump(interpreter)) {
return;
}
break;
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");
@@ -913,6 +961,9 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count); consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count);
//set the starting point for the interpreter
interpreter->codeStart = interpreter->count;
//code section //code section
if (command.verbose) { if (command.verbose) {
printf(NOTICE "executing bytecode\n" RESET); printf(NOTICE "executing bytecode\n" RESET);

View File

@@ -14,6 +14,7 @@ typedef struct Interpreter {
unsigned char* bytecode; unsigned char* bytecode;
int length; int length;
int count; int count;
int codeStart;
LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided
//operation //operation

View File

@@ -61,6 +61,16 @@ void freeNode(Node* node) {
freeLiteral(node->varDecl.typeLiteral); freeLiteral(node->varDecl.typeLiteral);
freeNode(node->varDecl.expression); freeNode(node->varDecl.expression);
break; break;
case NODE_PATH_IF:
case NODE_PATH_WHILE:
case NODE_PATH_FOR:
freeNode(node->path.preClause);
freeNode(node->path.postClause);
freeNode(node->path.condition);
freeNode(node->path.thenPath);
freeNode(node->path.elsePath);
break;
} }
} }
@@ -154,6 +164,19 @@ void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node*
*nodeHandle = tmp; *nodeHandle = tmp;
} }
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath) {
Node* tmp = ALLOCATE(Node, 1);
tmp->type = type;
tmp->path.preClause = preClause;
tmp->path.postClause = postClause;
tmp->path.condition = condition;
tmp->path.thenPath = thenPath;
tmp->path.elsePath = elsePath;
*nodeHandle = tmp;
}
void printNode(Node* node) { void printNode(Node* node) {
if (node == NULL) { if (node == NULL) {
return; return;
@@ -230,6 +253,22 @@ void printNode(Node* node) {
printf(")"); printf(")");
break; break;
case NODE_PATH_IF:
case NODE_PATH_WHILE:
case NODE_PATH_FOR:
printf("path(");
printNode(node->path.preClause);
printf("; ");
printNode(node->path.condition);
printf("; ");
printNode(node->path.postClause);
printf("):(");
printNode(node->path.thenPath);
printf(")else(");
printNode(node->path.elsePath);
printf(")");
break;
default: default:
printf("[internal] unkown node type in printNode: %d\n", node->type); printf("[internal] unkown node type in printNode: %d\n", node->type);
} }

View File

@@ -2,6 +2,7 @@
#include "literal.h" #include "literal.h"
#include "opcodes.h" #include "opcodes.h"
#include "token_types.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;
@@ -17,7 +18,9 @@ typedef enum NodeType {
NODE_PAIR, //contains a left and right NODE_PAIR, //contains a left and right
NODE_VAR_TYPES, //contains a type and a sub-node array for compound types NODE_VAR_TYPES, //contains a type and a sub-node array for compound types
NODE_VAR_DECL, //contains identifier literal, typenode, expression definition NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
// NODE_CONDITIONAL, //three children: conditional, then path, else path NODE_PATH_IF, //for control flow
NODE_PATH_WHILE, //for control flow
NODE_PATH_FOR, //for control flow
} NodeType; } NodeType;
typedef struct NodeLiteral { typedef struct NodeLiteral {
@@ -76,6 +79,15 @@ typedef struct NodeVarDecl {
Node* expression; Node* expression;
} NodeVarDecl; } NodeVarDecl;
typedef struct NodePath {
NodeType type;
Node* preClause;
Node* postClause;
Node* condition;
Node* thenPath;
Node* elsePath;
} NodePath;
union _node { union _node {
NodeType type; NodeType type;
NodeLiteral atomic; NodeLiteral atomic;
@@ -87,6 +99,7 @@ union _node {
NodePair pair; NodePair pair;
NodeVarTypes varTypes; NodeVarTypes varTypes;
NodeVarDecl varDecl; NodeVarDecl varDecl;
NodePath path;
}; };
void freeNode(Node* node); void freeNode(Node* node);
@@ -99,5 +112,6 @@ void emitNodeCompound(Node** nodeHandle, LiteralType literalType);
void emitNodePair(Node** nodeHandle, Node* left, Node* right); void emitNodePair(Node** nodeHandle, Node* left, Node* right);
void emitNodeVarTypes(Node** nodeHandle, Literal literal); void emitNodeVarTypes(Node** nodeHandle, Literal literal);
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression); void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
void printNode(Node* node); void printNode(Node* node);

View File

@@ -44,6 +44,10 @@ typedef enum Opcode {
OP_COMPARE_GREATER_EQUAL, OP_COMPARE_GREATER_EQUAL,
OP_INVERT, //for booleans OP_INVERT, //for booleans
//jumps, and conditional jumps (absolute)
OP_JUMP,
OP_IF_FALSE_JUMP,
//meta //meta
OP_SECTION_END, OP_SECTION_END,
//TODO: add more //TODO: add more

View File

@@ -919,6 +919,38 @@ static void assertStmt(Parser* parser, Node** nodeHandle) {
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of assert statement"); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of assert statement");
} }
static void ifStmt(Parser* parser, Node** nodeHandle) {
Node* condition = NULL;
Node* thenPath = NULL;
Node* elsePath = NULL;
//read the condition
consume(parser, TOKEN_PAREN_LEFT, "Expected '(' at end of if statement");
parsePrecedence(parser, &condition, PREC_TERNARY);
//read the then path
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of if statement");
thenPath = ALLOCATE(Node, 1);
declaration(parser, &thenPath);
//read the optional else path
if (match(parser, TOKEN_ELSE)) {
elsePath = ALLOCATE(Node, 1);
declaration(parser, &elsePath);
}
freeNode(*nodeHandle); //free the initial node
emitNodePath(nodeHandle, NODE_PATH_IF, NULL, NULL, condition, thenPath, elsePath);
}
static void whileStmt(Parser* parser, Node** nodeHandle) {
//
}
static void forStmt(Parser* parser, Node** nodeHandle) {
//
}
//precedence functions //precedence functions
static void expressionStmt(Parser* parser, Node** nodeHandle) { static void expressionStmt(Parser* parser, Node** nodeHandle) {
//BUGFIX: check for empty statements //BUGFIX: check for empty statements
@@ -959,6 +991,24 @@ static void statement(Parser* parser, Node** nodeHandle) {
return; return;
} }
//if-then-else
if (match(parser, TOKEN_IF)) {
ifStmt(parser, nodeHandle);
return;
}
//while-then
if (match(parser, TOKEN_WHILE)) {
whileStmt(parser, nodeHandle);
return;
}
//for-pre-clause-post-then
if (match(parser, TOKEN_FOR)) {
forStmt(parser, nodeHandle);
return;
}
//default //default
expressionStmt(parser, nodeHandle); expressionStmt(parser, nodeHandle);
} }
@@ -1058,6 +1108,7 @@ static void varDecl(Parser* parser, Node** nodeHandle) {
//TODO: static type checking? //TODO: static type checking?
//declare it //declare it
freeNode(*nodeHandle); //free the initial node
emitNodeVarDecl(nodeHandle, identifier, typeLiteral, expressionNode); emitNodeVarDecl(nodeHandle, identifier, typeLiteral, expressionNode);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of var declaration"); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of var declaration");

21
test/jumps.toy Normal file
View File

@@ -0,0 +1,21 @@
//test true jump
if (true) {
assert true, "if-then failed";
}
else {
assert false, "if-then failed";
}
//test false jump
if (false) {
assert false, "if-then failed";
}
else {
assert true, "if-then failed";
}
print "All good";