mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Parser is reading variable declarations, read more
This is an incomplete process. It's supposed to be robust enough to support the types of arrays and dictionaries, but arrays and dictionaries aren't implemented in the literals yet, so that's my next task. I'll come back to variable declarations later.
This commit is contained in:
@@ -90,7 +90,15 @@ void writeCompiler(Compiler* compiler, Node* node) {
|
|||||||
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TODO: conditional
|
case NODE_VAR_TYPES:
|
||||||
|
//TODO: OP_TYPE_DECL
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_DECL:
|
||||||
|
//TODO: OP_VAR_DECL + OP_VAR_ASSIGN
|
||||||
|
break;
|
||||||
|
|
||||||
|
//TODO: more
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,6 @@ Token scanLexer(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void trim(char** s, int* l) { //all this to remove a newline?
|
static void trim(char** s, int* l) { //all this to remove a newline?
|
||||||
*l = strlen(*s);
|
|
||||||
while( isspace(( (*((unsigned char**)(s)))[(*l) - 1] )) ) (*l)--;
|
while( isspace(( (*((unsigned char**)(s)))[(*l) - 1] )) ) (*l)--;
|
||||||
while(**s && isspace( **(unsigned char**)(s)) ) { (*s)++; (*l)--; }
|
while(**s && isspace( **(unsigned char**)(s)) ) { (*s)++; (*l)--; }
|
||||||
}
|
}
|
||||||
@@ -323,9 +322,9 @@ void printToken(Token* token) {
|
|||||||
printf("%s", keyword);
|
printf("%s", keyword);
|
||||||
} else {
|
} else {
|
||||||
char* str = token->lexeme;
|
char* str = token->lexeme;
|
||||||
int length = 0;
|
int length = token->length;
|
||||||
trim(&str, &length);
|
trim(&str, &length);
|
||||||
printf("%.*s", length, token->lexeme);
|
printf("%.*s", length, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ Literal _toStringLiteral(char* str) {
|
|||||||
return ((Literal){LITERAL_STRING, {.string.ptr = (char*)str, .string.length = strlen((char*)str)}});
|
return ((Literal){LITERAL_STRING, {.string.ptr = (char*)str, .string.length = strlen((char*)str)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toIdentifierLiteral(char* str, unsigned char types) {
|
Literal _toIdentifierLiteral(char* str) {
|
||||||
return ((Literal){LITERAL_IDENTIFIER,{.identifier.ptr = (char*)str,.identifier.length = strlen((char*)str),.identifier.types = types}});
|
return ((Literal){LITERAL_IDENTIFIER,{.identifier.ptr = (char*)str,.identifier.length = strlen((char*)str)}});
|
||||||
}
|
}
|
||||||
|
|
||||||
char* copyString(char* original, int length) {
|
char* copyString(char* original, int length) {
|
||||||
@@ -121,7 +121,7 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
//should never bee seen
|
//should never bee seen
|
||||||
fprintf(stderr, "[Internal] Unrecognized literal type: %d\n", lhs.type);
|
fprintf(stderr, "[internal] Unrecognized literal type: %d\n", lhs.type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ typedef struct {
|
|||||||
struct { //for variable names
|
struct { //for variable names
|
||||||
char* ptr;
|
char* ptr;
|
||||||
int length;
|
int length;
|
||||||
unsigned char types;
|
|
||||||
} identifier;
|
} identifier;
|
||||||
} as;
|
} as;
|
||||||
} Literal;
|
} Literal;
|
||||||
@@ -67,7 +66,7 @@ typedef struct {
|
|||||||
// #define TO_ARRAY_LITERAL
|
// #define TO_ARRAY_LITERAL
|
||||||
// #define TO_DICTIONARY_LITERAL
|
// #define TO_DICTIONARY_LITERAL
|
||||||
// #define TO_FUNCTION_LITERAL
|
// #define TO_FUNCTION_LITERAL
|
||||||
#define TO_IDENTIFIER_LITERAL(value, types) _toIdentifierLiteral(value, types)
|
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value)
|
||||||
|
|
||||||
#define MASK(x) (1 >> (x))
|
#define MASK(x) (1 >> (x))
|
||||||
#define TYPE_CONST 0
|
#define TYPE_CONST 0
|
||||||
@@ -86,6 +85,7 @@ typedef struct {
|
|||||||
#define MASK_ARRAY (MASK(TYPE_ARRAY))
|
#define MASK_ARRAY (MASK(TYPE_ARRAY))
|
||||||
#define MASK_DICTIONARY (MASK(TYPE_DICTIONARY))
|
#define MASK_DICTIONARY (MASK(TYPE_DICTIONARY))
|
||||||
#define MASK_FUNCTION (MASK(TYPE_FUNCTION))
|
#define MASK_FUNCTION (MASK(TYPE_FUNCTION))
|
||||||
|
#define MASK_ANY (MASK_BOOLEAN|MASK_INTEGER|MASK_FLOAT|MASK_STRING|MASK_ARRAY|MASK_DICTIONARY|MASK_FUNCTION)
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
void printLiteral(Literal literal);
|
void printLiteral(Literal literal);
|
||||||
@@ -101,7 +101,7 @@ void freeLiteral(Literal literal);
|
|||||||
//BUGFIX: macros are not functions
|
//BUGFIX: macros are not functions
|
||||||
bool _isTruthy(Literal x);
|
bool _isTruthy(Literal x);
|
||||||
Literal _toStringLiteral(char* str);
|
Literal _toStringLiteral(char* str);
|
||||||
Literal _toIdentifierLiteral(char* str, unsigned char types);
|
Literal _toIdentifierLiteral(char* str);
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
char* copyString(char* original, int length);
|
char* copyString(char* original, int length);
|
||||||
|
|||||||
@@ -37,6 +37,20 @@ void freeNode(Node* node) {
|
|||||||
for (int i = 0; i < node->block.count; i++) {
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
freeNode(node->block.nodes + i);
|
freeNode(node->block.nodes + i);
|
||||||
}
|
}
|
||||||
|
//each sub-node gets freed individually
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_TYPES:
|
||||||
|
for (int i = 0; i < node->varTypes.count; i++) {
|
||||||
|
freeNode(node->varTypes.nodes + 1);
|
||||||
|
}
|
||||||
|
//each sub-node gets freed individually
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_DECL:
|
||||||
|
freeLiteral(node->varDecl.identifier);
|
||||||
|
freeNode(node->varDecl.varType);
|
||||||
|
freeNode(node->varDecl.expression);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +105,29 @@ void emitNodeBlock(Node** nodeHandle) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitNodeVarTypes(Node** nodeHandle, unsigned char mask) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_VAR_TYPES;
|
||||||
|
tmp->varTypes.mask = mask;
|
||||||
|
tmp->varTypes.nodes = NULL;
|
||||||
|
tmp->varTypes.capacity = 0;
|
||||||
|
tmp->varTypes.count = 0;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Node* varType, Node* expression) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_VAR_DECL;
|
||||||
|
tmp->varDecl.identifier = identifier;
|
||||||
|
tmp->varDecl.varType = varType;
|
||||||
|
tmp->varDecl.expression = expression;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void printNode(Node* node) {
|
void printNode(Node* node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -134,5 +171,25 @@ void printNode(Node* node) {
|
|||||||
|
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_TYPES:
|
||||||
|
printf("[\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < node->varTypes.count; i++) {
|
||||||
|
printNode(&(node->varTypes.nodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("]\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_VAR_DECL:
|
||||||
|
printf("vardecl(");
|
||||||
|
printLiteral(node->varDecl.identifier);
|
||||||
|
printf("; ");
|
||||||
|
printNode(node->varDecl.varType);
|
||||||
|
printf("; ");
|
||||||
|
printNode(node->varDecl.expression);
|
||||||
|
printf(")");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,9 @@ 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_BLOCK, //contains sub-node array
|
||||||
|
NODE_VAR_TYPES, //contains a type mask and a sub-node array for compound types
|
||||||
|
NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
||||||
// NODE_CONDITIONAL, //three children: conditional, then path, else path
|
// NODE_CONDITIONAL, //three children: conditional, then path, else path
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
@@ -46,6 +48,21 @@ typedef struct NodeBlock {
|
|||||||
int count;
|
int count;
|
||||||
} NodeBlock;
|
} NodeBlock;
|
||||||
|
|
||||||
|
typedef struct NodeVarTypes {
|
||||||
|
NodeType type;
|
||||||
|
unsigned char mask;
|
||||||
|
Node* nodes;
|
||||||
|
int capacity;
|
||||||
|
int count;
|
||||||
|
} NodeVarTypes;
|
||||||
|
|
||||||
|
typedef struct NodeVarDecl {
|
||||||
|
NodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
Node* varType;
|
||||||
|
Node* expression;
|
||||||
|
} NodeVarDecl;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
@@ -53,6 +70,8 @@ union _node {
|
|||||||
NodeBinary binary;
|
NodeBinary binary;
|
||||||
NodeGrouping grouping;
|
NodeGrouping grouping;
|
||||||
NodeBlock block;
|
NodeBlock block;
|
||||||
|
NodeVarTypes varTypes;
|
||||||
|
NodeVarDecl varDecl;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
@@ -61,6 +80,8 @@ 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 emitNodeBlock(Node** nodeHandle);
|
||||||
|
void emitNodeVarTypes(Node** nodeHandle, unsigned char mask);
|
||||||
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Node* varType, Node* expression);
|
||||||
|
|
||||||
void printNode(Node* node);
|
void printNode(Node* node);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ typedef enum Opcode {
|
|||||||
OP_LITERAL,
|
OP_LITERAL,
|
||||||
OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
||||||
|
|
||||||
//operators
|
//arithmetic operators
|
||||||
OP_NEGATE,
|
OP_NEGATE,
|
||||||
OP_ADDITION,
|
OP_ADDITION,
|
||||||
OP_SUBTRACTION,
|
OP_SUBTRACTION,
|
||||||
@@ -20,9 +20,15 @@ typedef enum Opcode {
|
|||||||
OP_MODULO,
|
OP_MODULO,
|
||||||
OP_GROUPING_BEGIN,
|
OP_GROUPING_BEGIN,
|
||||||
OP_GROUPING_END,
|
OP_GROUPING_END,
|
||||||
|
|
||||||
|
//variable stuff
|
||||||
OP_SCOPE_BEGIN,
|
OP_SCOPE_BEGIN,
|
||||||
OP_SCOPE_END,
|
OP_SCOPE_END,
|
||||||
|
|
||||||
|
OP_TYPE_DECL, //declare a compound type to be used
|
||||||
|
OP_VAR_DECL, //stack: literal name, literal type (referenced by array index)
|
||||||
|
OP_VAR_ASSIGN, //stack: literal name, literal value
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_SECTION_END,
|
OP_SECTION_END,
|
||||||
//TODO: add more
|
//TODO: add more
|
||||||
|
|||||||
116
source/parser.c
116
source/parser.c
@@ -363,6 +363,7 @@ ParseRule* getRule(TokenType type) {
|
|||||||
return &parseRules[type];
|
return &parseRules[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static analasys
|
||||||
static bool calcStaticBinaryArithmetic(Node** nodeHandle) {
|
static bool calcStaticBinaryArithmetic(Node** nodeHandle) {
|
||||||
switch((*nodeHandle)->binary.opcode) {
|
switch((*nodeHandle)->binary.opcode) {
|
||||||
case OP_ADDITION:
|
case OP_ADDITION:
|
||||||
@@ -479,7 +480,7 @@ static bool calcStaticBinaryArithmetic(Node** nodeHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule) {
|
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule) {
|
||||||
//every expression has a prefix rule
|
//every valid expression has a prefix rule
|
||||||
advance(parser);
|
advance(parser);
|
||||||
ParseFn prefixRule = getRule(parser->previous.type)->prefix;
|
ParseFn prefixRule = getRule(parser->previous.type)->prefix;
|
||||||
|
|
||||||
@@ -604,11 +605,120 @@ static void statement(Parser* parser, Node* node) {
|
|||||||
expressionStmt(parser, node);
|
expressionStmt(parser, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void declaration(Parser* parser, Node** nodeHandle) {
|
//declarations and definitions
|
||||||
//TODO: variable declarations
|
static void readVarType(Parser* parser, Node** nodeHandle) {
|
||||||
|
//TODO: compound types with the "type" keyword
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
unsigned char typeMask = 0;
|
||||||
|
|
||||||
|
Node* left = NULL;
|
||||||
|
Node* right = NULL;
|
||||||
|
|
||||||
|
switch(parser->previous.type) {
|
||||||
|
case TOKEN_BOOLEAN:
|
||||||
|
typeMask |= MASK_BOOLEAN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOKEN_INTEGER:
|
||||||
|
typeMask |= MASK_INTEGER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOKEN_FLOAT:
|
||||||
|
typeMask |= MASK_FLOAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOKEN_STRING:
|
||||||
|
typeMask |= MASK_STRING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//array, dictionary - read the sub-types
|
||||||
|
case TOKEN_BRACKET_LEFT:
|
||||||
|
//at least 1 type required
|
||||||
|
readVarType(parser, &left);
|
||||||
|
|
||||||
|
if (match(parser, TOKEN_COMMA)) {
|
||||||
|
//if there's 2 types, it's a dictionary
|
||||||
|
readVarType(parser, &right);
|
||||||
|
typeMask |= MASK_DICTIONARY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//else it's just an array
|
||||||
|
typeMask |= MASK_ARRAY;
|
||||||
|
}
|
||||||
|
consume(parser, TOKEN_BRACKET_RIGHT, "Expected ']' at end of type definition");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOKEN_ANY:
|
||||||
|
typeMask |= MASK_ANY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//TODO: function
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(parser, parser->previous, "Bad type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const follows the type
|
||||||
|
if (match(parser, TOKEN_CONST)) {
|
||||||
|
typeMask |= MASK_CONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate the node
|
||||||
|
emitNodeVarTypes(nodeHandle, typeMask);
|
||||||
|
|
||||||
|
//check for sub-nodes
|
||||||
|
if (left) {
|
||||||
|
int oldCapacity = (*nodeHandle)->varTypes.capacity;
|
||||||
|
|
||||||
|
(*nodeHandle)->varTypes.capacity = GROW_CAPACITY(oldCapacity);
|
||||||
|
(*nodeHandle)->varTypes.nodes = GROW_ARRAY(Node, (*nodeHandle)->varTypes.nodes, oldCapacity, (*nodeHandle)->varTypes.capacity);
|
||||||
|
|
||||||
|
//push left to the array
|
||||||
|
*((*nodeHandle)->varTypes.nodes) = *left;
|
||||||
|
|
||||||
|
//append the other one too
|
||||||
|
if (right) {
|
||||||
|
*((*nodeHandle)->varTypes.nodes + 1) = *right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void varDecl(Parser* parser, Node** nodeHandle) {
|
||||||
|
//read the identifier
|
||||||
|
consume(parser, TOKEN_IDENTIFIER, "Expected identifier after var keyword");
|
||||||
|
Token identifierToken = parser->previous;
|
||||||
|
|
||||||
|
//read the type, if present
|
||||||
|
Node* typeNode = NULL;
|
||||||
|
if (match(parser, TOKEN_COLON)) {
|
||||||
|
readVarType(parser, &typeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//variable definition is an expression
|
||||||
|
Node* expressionNode = NULL;
|
||||||
|
if (match(parser, TOKEN_ASSIGN)) {
|
||||||
|
expression(parser, &expressionNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: compile-time static type check
|
||||||
|
|
||||||
|
//finally
|
||||||
|
emitNodeVarDecl(nodeHandle, TO_IDENTIFIER_LITERAL(identifierToken.lexeme), typeNode, expressionNode);
|
||||||
|
|
||||||
|
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of var declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void declaration(Parser* parser, Node** nodeHandle) { //assume nodeHandle holds a blank node
|
||||||
|
//variable declarations
|
||||||
|
if (match(parser, TOKEN_VAR)) {
|
||||||
|
varDecl(parser, nodeHandle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
statement(parser, *nodeHandle);
|
statement(parser, *nodeHandle);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void initParser(Parser* parser, Lexer* lexer) {
|
void initParser(Parser* parser, Lexer* lexer) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "literal_dictionary.h"
|
#include "literal_dictionary.h"
|
||||||
|
|
||||||
typedef struct Scope {
|
typedef struct Scope {
|
||||||
LiteralDictionary variables;
|
LiteralDictionary variables; //only allow identifiers as the keys
|
||||||
struct Scope* ancestor;
|
struct Scope* ancestor;
|
||||||
int references; //how many scopes point here
|
int references; //how many scopes point here
|
||||||
} Scope;
|
} Scope;
|
||||||
|
|||||||
Reference in New Issue
Block a user