mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Added scopes using '{}' symbols, read more
I've also added a new literal type called 'identifier'. This will be used for variable names, and has a type mask embedded in it.
This commit is contained in:
@@ -14,7 +14,16 @@ print -69;
|
|||||||
print -4.20;
|
print -4.20;
|
||||||
print 2 + (3 * 3);
|
print 2 + (3 * 3);
|
||||||
|
|
||||||
assert true, "This won't be seen";
|
//test scopes
|
||||||
|
{
|
||||||
|
print "This statement is within a scope.";
|
||||||
|
{
|
||||||
|
print "This is a deeper scope.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "Back to the outer scope.";
|
||||||
|
|
||||||
|
//test asserts
|
||||||
|
assert true, "This won't be seen";
|
||||||
assert false, "This is an error";
|
assert false, "This is an error";
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ void writeCompiler(Compiler* compiler, Node* node) {
|
|||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
//TODO: more types, like variables, etc.
|
//TODO: more types, like variables, etc.
|
||||||
case NODE_ERROR: {
|
case NODE_ERROR: {
|
||||||
printf("[internal] NODE_ERROR encountered in writeCompiler()");
|
fprintf(stderr, "[Internal] NODE_ERROR encountered in writeCompiler()");
|
||||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -80,6 +80,16 @@ void writeCompiler(Compiler* compiler, Node* node) {
|
|||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_END; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_END; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_BLOCK:
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte
|
||||||
|
|
||||||
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
|
writeCompiler(compiler, &(node->block.nodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte
|
||||||
|
break;
|
||||||
|
|
||||||
//TODO: conditional
|
//TODO: conditional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,6 +212,10 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) {
|
|||||||
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
emitByte(&collation, &capacity, &count, '\0'); //terminate the string
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "[Internal] Unknown literal type encountered within literal cache\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ static void stderrWrapper(const char* output) {
|
|||||||
|
|
||||||
void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
|
void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
|
||||||
initLiteralArray(&interpreter->literalCache);
|
initLiteralArray(&interpreter->literalCache);
|
||||||
|
interpreter->scope = pushScope(NULL);
|
||||||
interpreter->bytecode = bytecode;
|
interpreter->bytecode = bytecode;
|
||||||
interpreter->length = length;
|
interpreter->length = length;
|
||||||
interpreter->count = 0;
|
interpreter->count = 0;
|
||||||
@@ -31,6 +32,7 @@ void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int leng
|
|||||||
|
|
||||||
void freeInterpreter(Interpreter* interpreter) {
|
void freeInterpreter(Interpreter* interpreter) {
|
||||||
freeLiteralArray(&interpreter->literalCache);
|
freeLiteralArray(&interpreter->literalCache);
|
||||||
|
interpreter->scope = popScope(interpreter->scope);
|
||||||
FREE_ARRAY(char, interpreter->bytecode, interpreter->length);
|
FREE_ARRAY(char, interpreter->bytecode, interpreter->length);
|
||||||
freeLiteralArray(&interpreter->stack);
|
freeLiteralArray(&interpreter->stack);
|
||||||
}
|
}
|
||||||
@@ -283,6 +285,15 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
case OP_GROUPING_END:
|
case OP_GROUPING_END:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//scope
|
||||||
|
case OP_SCOPE_BEGIN:
|
||||||
|
interpreter->scope = pushScope(interpreter->scope);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SCOPE_END:
|
||||||
|
interpreter->scope = popScope(interpreter->scope);
|
||||||
|
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");
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
#include "literal_array.h"
|
#include "literal_array.h"
|
||||||
#include "literal_dictionary.h"
|
#include "literal_dictionary.h"
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
typedef void (*PrintFn)(const char*);
|
typedef void (*PrintFn)(const char*);
|
||||||
|
|
||||||
//the interpreter acts depending on the bytecode instructions
|
//the interpreter acts depending on the bytecode instructions
|
||||||
typedef struct Interpreter {
|
typedef struct Interpreter {
|
||||||
LiteralArray literalCache; //generally doesn't change after initialization
|
LiteralArray literalCache; //generally doesn't change after initialization
|
||||||
|
Scope* scope;
|
||||||
unsigned char* bytecode;
|
unsigned char* bytecode;
|
||||||
int length;
|
int length;
|
||||||
int count;
|
int count;
|
||||||
|
|||||||
@@ -43,9 +43,16 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LITERAL_IDENTIFIER: {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, 256, "%.*s", STRLEN_I(literal), AS_IDENTIFIER(literal));
|
||||||
|
printFn(buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never bee seen
|
//should never bee seen
|
||||||
fprintf(stderr, "[Internal] Unrecognized literal type: %d", literal.type);
|
fprintf(stderr, "[Internal] Unrecognized literal type in print: %d\n", literal.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +67,12 @@ bool _isTruthy(Literal x) {
|
|||||||
return (IS_NULL(x) || (IS_BOOLEAN(x) && AS_BOOLEAN(x)) || (IS_INTEGER(x) && AS_INTEGER(x) != 0) || (IS_FLOAT(x) && AS_FLOAT(x) != 0));
|
return (IS_NULL(x) || (IS_BOOLEAN(x) && AS_BOOLEAN(x)) || (IS_INTEGER(x) && AS_INTEGER(x) != 0) || (IS_FLOAT(x) && AS_FLOAT(x) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toStringLiteral(char* cstr) {
|
Literal _toStringLiteral(char* str) {
|
||||||
return ((Literal){LITERAL_STRING, { .string.ptr = (char*)cstr, .string.length = strlen((char*)cstr) }});
|
return ((Literal){LITERAL_STRING, {.string.ptr = (char*)str, .string.length = strlen((char*)str)}});
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal _toIdentifierLiteral(char* str, unsigned char types) {
|
||||||
|
return ((Literal){LITERAL_IDENTIFIER,{.identifier.ptr = (char*)str,.identifier.length = strlen((char*)str),.identifier.types = types}});
|
||||||
}
|
}
|
||||||
|
|
||||||
char* copyString(char* original, int length) {
|
char* copyString(char* original, int length) {
|
||||||
@@ -102,9 +113,15 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
|
|||||||
}
|
}
|
||||||
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), STRLEN(lhs));
|
return !strncmp(AS_STRING(lhs), AS_STRING(rhs), STRLEN(lhs));
|
||||||
|
|
||||||
|
case LITERAL_IDENTIFIER:
|
||||||
|
if (STRLEN_I(lhs) != STRLEN_I(rhs)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), STRLEN_I(lhs));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never bee seen
|
//should never bee seen
|
||||||
fprintf(stderr, "[Internal] Unrecognized literal type: %d", lhs.type);
|
fprintf(stderr, "[Internal] Unrecognized literal type: %d\n", lhs.type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,9 +162,12 @@ int hashLiteral(Literal lit) {
|
|||||||
case LITERAL_STRING:
|
case LITERAL_STRING:
|
||||||
return hashString(AS_STRING(lit), STRLEN(lit));
|
return hashString(AS_STRING(lit), STRLEN(lit));
|
||||||
|
|
||||||
|
case LITERAL_IDENTIFIER:
|
||||||
|
return hashString(AS_IDENTIFIER(lit), STRLEN_I(lit));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never bee seen
|
//should never bee seen
|
||||||
fprintf(stderr, "[Internal] Unrecognized literal type in hash: %d", lit.type);
|
fprintf(stderr, "[Internal] Unrecognized literal type in hash: %d\n", lit.type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ typedef enum {
|
|||||||
// LITERAL_ARRAY,
|
// LITERAL_ARRAY,
|
||||||
// LITERAL_DICTIONARY,
|
// LITERAL_DICTIONARY,
|
||||||
// LITERAL_FUNCTION,
|
// LITERAL_FUNCTION,
|
||||||
|
LITERAL_IDENTIFIER,
|
||||||
} LiteralType;
|
} LiteralType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -23,13 +24,19 @@ typedef struct {
|
|||||||
float number;
|
float number;
|
||||||
struct {
|
struct {
|
||||||
char* ptr;
|
char* ptr;
|
||||||
int length; //could possibly cut it down further by removing this
|
int length;
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
// //experimental
|
// //experimental
|
||||||
// void* array;
|
// void* array;
|
||||||
// void* dictionary;
|
// void* dictionary;
|
||||||
// void* function;
|
// void* function;
|
||||||
|
|
||||||
|
struct { //for variable names
|
||||||
|
char* ptr;
|
||||||
|
int length;
|
||||||
|
unsigned char types;
|
||||||
|
} identifier;
|
||||||
} as;
|
} as;
|
||||||
} Literal;
|
} Literal;
|
||||||
|
|
||||||
@@ -41,24 +48,46 @@ typedef struct {
|
|||||||
#define IS_ARRAY(value) ((value).type == LITERAL_ARRAY)
|
#define IS_ARRAY(value) ((value).type == LITERAL_ARRAY)
|
||||||
#define IS_DICTIONARY(value) ((value).type == LITERAL_DICTIONARY)
|
#define IS_DICTIONARY(value) ((value).type == LITERAL_DICTIONARY)
|
||||||
#define IS_FUNCTION(value) ((value).type == LITERAL_FUNCTION)
|
#define IS_FUNCTION(value) ((value).type == LITERAL_FUNCTION)
|
||||||
|
#define IS_IDENTIFIER(value) ((value).type == LITERAL_IDENTIFIER)
|
||||||
|
|
||||||
#define AS_BOOLEAN(value) ((value).as.boolean)
|
#define AS_BOOLEAN(value) ((value).as.boolean)
|
||||||
#define AS_INTEGER(value) ((value).as.integer)
|
#define AS_INTEGER(value) ((value).as.integer)
|
||||||
#define AS_FLOAT(value) ((value).as.number)
|
#define AS_FLOAT(value) ((value).as.number)
|
||||||
#define AS_STRING(value) ((value).as.string.ptr)
|
#define AS_STRING(value) ((value).as.string.ptr)
|
||||||
// #define AS_ARRAY_PTR(value)
|
// #define AS_ARRAY(value)
|
||||||
// #define AS_DICTIONARY_PTR(value)
|
// #define AS_DICTIONARY(value)
|
||||||
// #define AS_FUNCTION_PTR(value) ((Function*)((value).as.function))
|
// #define AS_FUNCTION(value)
|
||||||
|
#define AS_IDENTIFIER(value) ((value).as.identifier.ptr)
|
||||||
|
|
||||||
#define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }})
|
#define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }})
|
||||||
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
|
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
|
||||||
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
||||||
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
||||||
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
||||||
// #define TO_ARRAY_PTR
|
// #define TO_ARRAY_LITERAL
|
||||||
// #define TO_DICTIONARY_PTR
|
// #define TO_DICTIONARY_LITERAL
|
||||||
// #define TO_FUNCTION_PTR(value) ((Literal){LITERAL_FUNCTION, { .function = (Function*)value }})
|
// #define TO_FUNCTION_LITERAL
|
||||||
|
#define TO_IDENTIFIER_LITERAL(value, types) _toIdentifierLiteral(value, types)
|
||||||
|
|
||||||
|
#define MASK(x) (1 >> (x))
|
||||||
|
#define TYPE_CONST 0
|
||||||
|
#define TYPE_BOOLEAN 1
|
||||||
|
#define TYPE_INTEGER 2
|
||||||
|
#define TYPE_FLOAT 3
|
||||||
|
#define TYPE_STRING 4
|
||||||
|
#define TYPE_ARRAY 5
|
||||||
|
#define TYPE_DICTIONARY 6
|
||||||
|
#define TYPE_FUNCTION 7
|
||||||
|
#define MASK_CONST (MASK(TYPE_CONST))
|
||||||
|
#define MASK_BOOLEAN (MASK(TYPE_BOOLEAN))
|
||||||
|
#define MASK_INTEGER (MASK(TYPE_INTEGER))
|
||||||
|
#define MASK_FLOAT (MASK(TYPE_FLOAT))
|
||||||
|
#define MASK_STRING (MASK(TYPE_STRING))
|
||||||
|
#define MASK_ARRAY (MASK(TYPE_ARRAY))
|
||||||
|
#define MASK_DICTIONARY (MASK(TYPE_DICTIONARY))
|
||||||
|
#define MASK_FUNCTION (MASK(TYPE_FUNCTION))
|
||||||
|
|
||||||
|
//utils
|
||||||
void printLiteral(Literal literal);
|
void printLiteral(Literal literal);
|
||||||
void printLiteralCustom(Literal literal, void (printFn)(const char*));
|
void printLiteralCustom(Literal literal, void (printFn)(const char*));
|
||||||
void freeLiteral(Literal literal);
|
void freeLiteral(Literal literal);
|
||||||
@@ -66,10 +95,13 @@ void freeLiteral(Literal literal);
|
|||||||
#define IS_TRUTHY(x) _isTruthy(x)
|
#define IS_TRUTHY(x) _isTruthy(x)
|
||||||
|
|
||||||
#define STRLEN(lit) ((lit).as.string.length)
|
#define STRLEN(lit) ((lit).as.string.length)
|
||||||
|
#define STRLEN_I(lit) ((lit).as.identifier.length)
|
||||||
|
#define TYPES(lit) ((lit).as.identifier.types)
|
||||||
|
|
||||||
//BUGFIX: macros are not functions
|
//BUGFIX: macros are not functions
|
||||||
bool _isTruthy(Literal x);
|
bool _isTruthy(Literal x);
|
||||||
Literal _toStringLiteral(char* cstr);
|
Literal _toStringLiteral(char* str);
|
||||||
|
Literal _toIdentifierLiteral(char* str, unsigned char types);
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
char* copyString(char* original, int length);
|
char* copyString(char* original, int length);
|
||||||
|
|||||||
@@ -199,3 +199,8 @@ void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key) {
|
||||||
|
//null & not tombstoned
|
||||||
|
_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), false);
|
||||||
|
return !(IS_NULL(entry->key) && IS_NULL(entry->value));
|
||||||
|
}
|
||||||
@@ -23,3 +23,5 @@ void freeLiteralDictionary(LiteralDictionary* dictionary);
|
|||||||
void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value);
|
void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value);
|
||||||
Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
||||||
void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
||||||
|
|
||||||
|
bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
void freeNode(Node* node) {
|
void freeNode(Node* node) {
|
||||||
//don't free a NULL node
|
//don't free a NULL node
|
||||||
@@ -31,6 +32,12 @@ void freeNode(Node* node) {
|
|||||||
case NODE_GROUPING:
|
case NODE_GROUPING:
|
||||||
freeNode(node->grouping.child);
|
freeNode(node->grouping.child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_BLOCK:
|
||||||
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
|
freeNode(node->block.nodes + i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(Node, node);
|
FREE(Node, node);
|
||||||
@@ -73,6 +80,17 @@ void emitNodeGrouping(Node** nodeHandle) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitNodeBlock(Node** nodeHandle) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_BLOCK;
|
||||||
|
tmp->block.nodes = NULL;
|
||||||
|
tmp->block.capacity = 0;
|
||||||
|
tmp->block.count = 0;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void printNode(Node* node) {
|
void printNode(Node* node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -106,5 +124,15 @@ void printNode(Node* node) {
|
|||||||
printNode(node->grouping.child);
|
printNode(node->grouping.child);
|
||||||
printf(")");
|
printf(")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_BLOCK:
|
||||||
|
printf("{\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
|
printNode(&(node->block.nodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("}\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@ typedef enum NodeType {
|
|||||||
NODE_UNARY, //one child
|
NODE_UNARY, //one child
|
||||||
NODE_BINARY, //two children, left and right
|
NODE_BINARY, //two children, left and right
|
||||||
NODE_GROUPING, //one child
|
NODE_GROUPING, //one child
|
||||||
|
NODE_BLOCK, //contains bytecode
|
||||||
// NODE_CONDITIONAL, //three children: conditional, then path, else path
|
// NODE_CONDITIONAL, //three children: conditional, then path, else path
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
@@ -38,12 +39,20 @@ typedef struct NodeGrouping {
|
|||||||
Node* child;
|
Node* child;
|
||||||
} NodeGrouping;
|
} NodeGrouping;
|
||||||
|
|
||||||
|
typedef struct NodeBlock {
|
||||||
|
NodeType type;
|
||||||
|
Node* nodes;
|
||||||
|
int capacity;
|
||||||
|
int count;
|
||||||
|
} NodeBlock;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
NodeUnary unary;
|
NodeUnary unary;
|
||||||
NodeBinary binary;
|
NodeBinary binary;
|
||||||
NodeGrouping grouping;
|
NodeGrouping grouping;
|
||||||
|
NodeBlock block;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
@@ -51,6 +60,7 @@ void emitNodeLiteral(Node** nodeHandle, Literal literal);
|
|||||||
void emitNodeUnary(Node** nodeHandle, Opcode opcode);
|
void emitNodeUnary(Node** nodeHandle, Opcode opcode);
|
||||||
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode);
|
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode);
|
||||||
void emitNodeGrouping(Node** nodeHandle);
|
void emitNodeGrouping(Node** nodeHandle);
|
||||||
|
void emitNodeBlock(Node** nodeHandle);
|
||||||
|
|
||||||
void printNode(Node* node);
|
void printNode(Node* node);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ typedef enum Opcode {
|
|||||||
OP_MODULO,
|
OP_MODULO,
|
||||||
OP_GROUPING_BEGIN,
|
OP_GROUPING_BEGIN,
|
||||||
OP_GROUPING_END,
|
OP_GROUPING_END,
|
||||||
|
OP_SCOPE_BEGIN,
|
||||||
|
OP_SCOPE_END,
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_SECTION_END,
|
OP_SECTION_END,
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ typedef struct {
|
|||||||
ParseRule parseRules[];
|
ParseRule parseRules[];
|
||||||
|
|
||||||
//forward declarations
|
//forward declarations
|
||||||
|
static void declaration(Parser* parser, Node** nodeHandle);
|
||||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
||||||
|
|
||||||
//the expression rules
|
//the expression rules
|
||||||
@@ -523,6 +524,37 @@ static void expression(Parser* parser, Node** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//statements
|
//statements
|
||||||
|
static void blockStmt(Parser* parser, Node* node) {
|
||||||
|
//init
|
||||||
|
node->type = NODE_BLOCK;
|
||||||
|
node->block.nodes = NULL;
|
||||||
|
node->block.capacity = 0;
|
||||||
|
node->block.count = 0;
|
||||||
|
|
||||||
|
//sub-scope, compile it and push it up in a node
|
||||||
|
while (!match(parser, TOKEN_BRACE_RIGHT)) {
|
||||||
|
if (node->block.capacity < node->block.count + 1) {
|
||||||
|
int oldCapacity = node->block.capacity;
|
||||||
|
|
||||||
|
node->block.capacity = GROW_CAPACITY(oldCapacity);
|
||||||
|
node->block.nodes = GROW_ARRAY(Node, node->block.nodes, oldCapacity, node->block.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
//use the next node in sequence
|
||||||
|
node->block.nodes[node->block.count].type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
|
||||||
|
|
||||||
|
Node* ptr = &(node->block.nodes[node->block.count++]);
|
||||||
|
|
||||||
|
//process the grammar rule for this line
|
||||||
|
declaration(parser, &ptr);
|
||||||
|
|
||||||
|
// Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up!
|
||||||
|
if (parser->panic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void printStmt(Parser* parser, Node* node) {
|
static void printStmt(Parser* parser, Node* node) {
|
||||||
//set the node info
|
//set the node info
|
||||||
node->type = NODE_UNARY;
|
node->type = NODE_UNARY;
|
||||||
@@ -550,6 +582,12 @@ static void expressionStmt(Parser* parser, Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void statement(Parser* parser, Node* node) {
|
static void statement(Parser* parser, Node* node) {
|
||||||
|
//block
|
||||||
|
if (match(parser, TOKEN_BRACE_LEFT)) {
|
||||||
|
blockStmt(parser, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//print
|
//print
|
||||||
if (match(parser, TOKEN_PRINT)) {
|
if (match(parser, TOKEN_PRINT)) {
|
||||||
printStmt(parser, node);
|
printStmt(parser, node);
|
||||||
@@ -567,14 +605,9 @@ static void statement(Parser* parser, Node* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void declaration(Parser* parser, Node** nodeHandle) {
|
static void declaration(Parser* parser, Node** nodeHandle) {
|
||||||
statement(parser, *nodeHandle);
|
//TODO: variable declarations
|
||||||
|
|
||||||
if (parser->panic) {
|
statement(parser, *nodeHandle);
|
||||||
synchronize(parser);
|
|
||||||
//return an error node for this iteration
|
|
||||||
*nodeHandle = ALLOCATE(Node, 1);
|
|
||||||
(*nodeHandle)->type = NODE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
@@ -610,5 +643,12 @@ Node* scanParser(Parser* parser) {
|
|||||||
//process the grammar rule for this line
|
//process the grammar rule for this line
|
||||||
declaration(parser, &node);
|
declaration(parser, &node);
|
||||||
|
|
||||||
|
if (parser->panic) {
|
||||||
|
synchronize(parser);
|
||||||
|
//return an error node for this iteration
|
||||||
|
node = ALLOCATE(Node, 1);
|
||||||
|
node->type = NODE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,23 +194,8 @@ void debug() {
|
|||||||
|
|
||||||
initLiteralDictionary(&dictionary);
|
initLiteralDictionary(&dictionary);
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++) {
|
setLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER), TO_INTEGER_LITERAL(2));
|
||||||
setLiteralDictionary(&dictionary, TO_INTEGER_LITERAL(i), TO_INTEGER_LITERAL(i * 2));
|
printLiteral( getLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER)) );
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
printf("%d: ", i);
|
|
||||||
printLiteral( getLiteralDictionary(&dictionary, TO_INTEGER_LITERAL(i)) );
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("-------------");
|
|
||||||
|
|
||||||
for (int i = 0; i < dictionary.capacity; i++) {
|
|
||||||
printf("%d: ", i);
|
|
||||||
printLiteral(dictionary.entries[i].key);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
freeLiteralDictionary(&dictionary);
|
freeLiteralDictionary(&dictionary);
|
||||||
}
|
}
|
||||||
|
|||||||
86
source/scope.c
Normal file
86
source/scope.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
//run up the ancestor chain, freeing anything with 0 references left
|
||||||
|
static void freeAncestorChain(Scope* scope) {
|
||||||
|
scope->references--;
|
||||||
|
|
||||||
|
//free scope chain
|
||||||
|
if (scope->ancestor != NULL) {
|
||||||
|
freeAncestorChain(scope->ancestor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope->references > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeLiteralDictionary(&scope->variables);
|
||||||
|
|
||||||
|
FREE(Scope, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed functions
|
||||||
|
Scope* pushScope(Scope* ancestor) {
|
||||||
|
Scope* scope = ALLOCATE(Scope, 1);
|
||||||
|
scope->ancestor = ancestor;
|
||||||
|
initLiteralDictionary(&scope->variables);
|
||||||
|
|
||||||
|
//tick up all scope reference counts
|
||||||
|
scope->references = 0;
|
||||||
|
for (Scope* ptr = scope; ptr; ptr = ptr->ancestor) {
|
||||||
|
ptr->references++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope* popScope(Scope* scope) {
|
||||||
|
Scope* ret = scope->ancestor;
|
||||||
|
|
||||||
|
freeAncestorChain(scope);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns false if error
|
||||||
|
bool declareScopeVariable(Scope* scope, Literal key) {
|
||||||
|
//don't redefine a variable within this scope
|
||||||
|
if (existsLiteralDictionary(&scope->variables, key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLiteralDictionary(&scope->variables, key, TO_NULL_LITERAL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return false if undefined
|
||||||
|
bool setScopeVariable(Scope* scope, Literal key, Literal value) {
|
||||||
|
//dead end
|
||||||
|
if (scope == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if it's not in this scope, keep searching up the chain
|
||||||
|
if (!existsLiteralDictionary(&scope->variables, key)) {
|
||||||
|
return setScopeVariable(scope->ancestor, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLiteralDictionary(&scope->variables, key, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getScopeVariable(Scope* scope, Literal key, Literal* valueHandle) {
|
||||||
|
//dead end
|
||||||
|
if (scope == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if it's not in this scope, keep searching up the chain
|
||||||
|
if (!existsLiteralDictionary(&scope->variables, key)) {
|
||||||
|
return getScopeVariable(scope->ancestor, key, valueHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
*valueHandle = getLiteralDictionary(&scope->variables, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
21
source/scope.h
Normal file
21
source/scope.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "literal_dictionary.h"
|
||||||
|
|
||||||
|
typedef struct Scope {
|
||||||
|
LiteralDictionary variables;
|
||||||
|
struct Scope* ancestor;
|
||||||
|
int references; //how many scopes point here
|
||||||
|
} Scope;
|
||||||
|
|
||||||
|
Scope* pushScope(Scope* scope);
|
||||||
|
Scope* popScope(Scope* scope);
|
||||||
|
|
||||||
|
//returns false if error
|
||||||
|
bool declareScopeVariable(Scope* scope, Literal key);
|
||||||
|
|
||||||
|
//return false if undefined
|
||||||
|
bool setScopeVariable(Scope* scope, Literal key, Literal value);
|
||||||
|
bool getScopeVariable(Scope* scope, Literal key, Literal* value);
|
||||||
|
|
||||||
Reference in New Issue
Block a user