mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Basic arithmetic works
This commit is contained in:
@@ -54,20 +54,20 @@ static char* readString(unsigned char* tb, int* count) {
|
||||
|
||||
static void consumeByte(unsigned char byte, unsigned char* tb, int* count) {
|
||||
if (byte != tb[*count]) {
|
||||
printf("Failed to consume the correct byte");
|
||||
printf("Failed to consume the correct byte\n");
|
||||
}
|
||||
*count += 1;
|
||||
}
|
||||
|
||||
static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
|
||||
if (bytes != *(unsigned short*)(tb + *count)) {
|
||||
printf("Failed to consume the correct bytes");
|
||||
printf("Failed to consume the correct bytes\n");
|
||||
}
|
||||
*count += 2;
|
||||
}
|
||||
|
||||
//each available statement
|
||||
static void execPrint(Interpreter* interpreter) {
|
||||
static bool execPrint(Interpreter* interpreter) {
|
||||
//print what is on top of the stack, then pop it
|
||||
Literal lit = popLiteralArray(&interpreter->stack);
|
||||
|
||||
@@ -75,9 +75,11 @@ static void execPrint(Interpreter* interpreter) {
|
||||
printf("\n");
|
||||
|
||||
freeLiteral(lit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void execPushLiteral(Interpreter* interpreter, bool lng) {
|
||||
static bool execPushLiteral(Interpreter* interpreter, bool lng) {
|
||||
//read the index in the cache
|
||||
int index = 0;
|
||||
|
||||
@@ -90,9 +92,11 @@ static void execPushLiteral(Interpreter* interpreter, bool lng) {
|
||||
|
||||
//push from cache to stack
|
||||
pushLiteralArray(&interpreter->stack, interpreter->literalCache.literals[index]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void execNegate(Interpreter* interpreter) {
|
||||
static bool execNegate(Interpreter* interpreter) {
|
||||
//negate the top literal on the stack
|
||||
Literal lit = popLiteralArray(&interpreter->stack);
|
||||
|
||||
@@ -106,9 +110,81 @@ static void execNegate(Interpreter* interpreter) {
|
||||
printf("[internal] The interpreter can't negate that literal: ");
|
||||
printLiteral(lit);
|
||||
printf("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pushLiteralArray(&interpreter->stack, lit);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
|
||||
Literal rhs = popLiteralArray(&interpreter->stack);
|
||||
Literal lhs = popLiteralArray(&interpreter->stack);
|
||||
|
||||
//type coersion
|
||||
if (IS_FLOAT(lhs) && IS_INTEGER(rhs)) {
|
||||
rhs = TO_FLOAT_LITERAL(AS_INTEGER(rhs));
|
||||
}
|
||||
|
||||
if (IS_INTEGER(lhs) && IS_FLOAT(rhs)) {
|
||||
lhs = TO_FLOAT_LITERAL(AS_INTEGER(lhs));
|
||||
}
|
||||
|
||||
//maths based on types
|
||||
if(IS_INTEGER(lhs) && IS_INTEGER(rhs)) {
|
||||
switch(opcode) {
|
||||
case OP_ADDITION:
|
||||
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) + AS_INTEGER(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_SUBTRACTION:
|
||||
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) - AS_INTEGER(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_MULTIPLICATION:
|
||||
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) * AS_INTEGER(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_DIVISION:
|
||||
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) / AS_INTEGER(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_MODULO:
|
||||
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) % AS_INTEGER(rhs) ));
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//catch bad modulo
|
||||
if (opcode == OP_MODULO) {
|
||||
printf("Bad arithmetic argument (modulo on floats not allowed)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(IS_FLOAT(lhs) && IS_FLOAT(rhs)) {
|
||||
switch(opcode) {
|
||||
case OP_ADDITION:
|
||||
pushLiteralArray(&interpreter->stack, TO_FLOAT_LITERAL( AS_FLOAT(lhs) + AS_FLOAT(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_SUBTRACTION:
|
||||
pushLiteralArray(&interpreter->stack, TO_FLOAT_LITERAL( AS_FLOAT(lhs) - AS_FLOAT(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_MULTIPLICATION:
|
||||
pushLiteralArray(&interpreter->stack, TO_FLOAT_LITERAL( AS_FLOAT(lhs) * AS_FLOAT(rhs) ));
|
||||
return true;
|
||||
|
||||
case OP_DIVISION:
|
||||
pushLiteralArray(&interpreter->stack, TO_FLOAT_LITERAL( AS_FLOAT(lhs) / AS_FLOAT(rhs) ));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//wrong types
|
||||
printf("Bad arithmetic argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
//the heart of toy
|
||||
@@ -118,16 +194,32 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
|
||||
switch(opcode) {
|
||||
case OP_PRINT:
|
||||
execPrint(interpreter);
|
||||
if (!execPrint(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_LITERAL:
|
||||
case OP_LITERAL_LONG:
|
||||
execPushLiteral(interpreter, opcode == OP_LITERAL_LONG);
|
||||
if (!execPushLiteral(interpreter, opcode == OP_LITERAL_LONG)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_NEGATE:
|
||||
execNegate(interpreter);
|
||||
if (!execNegate(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_ADDITION:
|
||||
case OP_SUBTRACTION:
|
||||
case OP_MULTIPLICATION:
|
||||
case OP_DIVISION:
|
||||
case OP_MODULO:
|
||||
if (!execArithmetic(interpreter, opcode)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -40,6 +40,17 @@ void emitNodeUnary(Node** nodeHandle, Opcode opcode) {
|
||||
(*nodeHandle)->unary.child = NULL;
|
||||
}
|
||||
|
||||
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_BINARY;
|
||||
tmp->binary.opcode = opcode;
|
||||
tmp->binary.left = *nodeHandle;
|
||||
tmp->binary.right = rhs;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void printNode(Node* node) {
|
||||
switch(node->type) {
|
||||
case NODE_LITERAL:
|
||||
@@ -53,10 +64,11 @@ void printNode(Node* node) {
|
||||
break;
|
||||
|
||||
case NODE_BINARY:
|
||||
printf("binary left:");
|
||||
printf("binary-left:");
|
||||
printNode(node->binary.left);
|
||||
printf("binary right:");
|
||||
printf("binary-right:");
|
||||
printNode(node->binary.right);
|
||||
printf(";");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ union _node {
|
||||
void freeNode(Node* node);
|
||||
void emitNodeLiteral(Node** nodeHandle, Literal literal);
|
||||
void emitNodeUnary(Node** nodeHandle, Opcode opcode);
|
||||
void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode);
|
||||
|
||||
void printNode(Node* node);
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@ typedef enum Opcode {
|
||||
|
||||
//operators
|
||||
OP_NEGATE,
|
||||
OP_ADDITION,
|
||||
OP_SUBTRACTION,
|
||||
OP_MULTIPLICATION,
|
||||
OP_DIVISION,
|
||||
OP_MODULO,
|
||||
|
||||
//meta
|
||||
OP_SECTION_END,
|
||||
|
||||
192
source/parser.c
192
source/parser.c
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "memory.h"
|
||||
#include "literal.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -98,7 +99,7 @@ typedef enum {
|
||||
PREC_PRIMARY,
|
||||
} PrecedenceRule;
|
||||
|
||||
typedef void (*ParseFn)(Parser* parser, Node** nodeHandle, bool canBeAssigned);
|
||||
typedef Opcode (*ParseFn)(Parser* parser, Node** nodeHandle, bool canBeAssigned);
|
||||
|
||||
typedef struct {
|
||||
ParseFn prefix;
|
||||
@@ -112,25 +113,58 @@ ParseRule parseRules[];
|
||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
||||
|
||||
//the expression rules
|
||||
static void string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
//handle strings
|
||||
switch(parser->previous.type) {
|
||||
case TOKEN_LITERAL_STRING:
|
||||
emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, parser->previous.length)));
|
||||
break;
|
||||
return OP_EOF;
|
||||
|
||||
//TODO: interpolated strings
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to string precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static void binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
//TODO
|
||||
static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
advance(parser);
|
||||
|
||||
//binary() is an infix rule - so only get the RHS of the operator
|
||||
switch(parser->previous.type) {
|
||||
case TOKEN_PLUS: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
||||
return OP_ADDITION;
|
||||
}
|
||||
|
||||
case TOKEN_MINUS: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
||||
return OP_SUBTRACTION;
|
||||
}
|
||||
|
||||
case TOKEN_MULTIPLY: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
return OP_MULTIPLICATION;
|
||||
}
|
||||
|
||||
case TOKEN_DIVIDE: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
return OP_DIVISION;
|
||||
}
|
||||
|
||||
case TOKEN_MODULO: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
||||
return OP_MODULO;
|
||||
}
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
static Opcode unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
switch(parser->previous.type) {
|
||||
case TOKEN_MINUS: {
|
||||
//temp handle to potentially negate values
|
||||
@@ -153,7 +187,7 @@ static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
tmpNode->atomic.literal = lit;
|
||||
*nodeHandle = tmpNode;
|
||||
|
||||
break;
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
//process the literal without optimizations
|
||||
@@ -161,48 +195,50 @@ static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
emitNodeUnary(nodeHandle, OP_NEGATE);
|
||||
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
||||
(*nodeHandle) = tmpNode; //set negate's child to the literal
|
||||
break;
|
||||
return OP_EOF;
|
||||
}
|
||||
|
||||
error(parser, parser->previous, "Unexpected token passed to unary minus precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to unary precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static void atomic(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
static Opcode atomic(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||
switch(parser->previous.type) {
|
||||
case TOKEN_NULL:
|
||||
emitNodeLiteral(nodeHandle, TO_NULL_LITERAL);
|
||||
break;
|
||||
return OP_EOF;
|
||||
|
||||
case TOKEN_LITERAL_TRUE:
|
||||
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true));
|
||||
break;
|
||||
return OP_EOF;
|
||||
|
||||
case TOKEN_LITERAL_FALSE:
|
||||
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(false));
|
||||
break;
|
||||
return OP_EOF;
|
||||
|
||||
case TOKEN_LITERAL_INTEGER: {
|
||||
int value = 0;
|
||||
sscanf(parser->previous.lexeme, "%d", &value);
|
||||
emitNodeLiteral(nodeHandle, TO_INTEGER_LITERAL(value));
|
||||
return OP_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOKEN_LITERAL_FLOAT: {
|
||||
float value = 0;
|
||||
sscanf(parser->previous.lexeme, "%f", &value);
|
||||
emitNodeLiteral(nodeHandle, TO_FLOAT_LITERAL(value));
|
||||
return OP_EOF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to atomic precedence rule");
|
||||
return OP_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,11 +285,11 @@ ParseRule parseRules[] = { //must match the token types
|
||||
{string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
|
||||
|
||||
//math operators
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PLUS,
|
||||
{unary, NULL, PREC_UNARY},// TOKEN_MINUS,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_DIVIDE,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_MODULO,
|
||||
{NULL, binary, PREC_TERM},// TOKEN_PLUS,
|
||||
{unary, binary, PREC_TERM},// TOKEN_MINUS,
|
||||
{NULL, binary, PREC_TERM},// TOKEN_MULTIPLY,
|
||||
{NULL, binary, PREC_TERM},// TOKEN_DIVIDE,
|
||||
{NULL, binary, PREC_TERM},// TOKEN_MODULO,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_PLUS_ASSIGN,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_ASSIGN,
|
||||
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY_ASSIGN,
|
||||
@@ -298,6 +334,114 @@ ParseRule* getRule(TokenType type) {
|
||||
return &parseRules[type];
|
||||
}
|
||||
|
||||
static bool calcStaticBinaryArithmetic(Node** nodeHandle) {
|
||||
switch((*nodeHandle)->binary.opcode) {
|
||||
case OP_ADDITION:
|
||||
case OP_SUBTRACTION:
|
||||
case OP_MULTIPLICATION:
|
||||
case OP_DIVISION:
|
||||
case OP_MODULO:
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
//recurse to the left and right
|
||||
if ((*nodeHandle)->binary.left->type == NODE_BINARY) {
|
||||
calcStaticBinaryArithmetic(&(*nodeHandle)->binary.left);
|
||||
}
|
||||
|
||||
if ((*nodeHandle)->binary.right->type == NODE_BINARY) {
|
||||
calcStaticBinaryArithmetic(&(*nodeHandle)->binary.right);
|
||||
}
|
||||
|
||||
//make sure left and right are both literals
|
||||
if (!((*nodeHandle)->binary.left->type == NODE_LITERAL && (*nodeHandle)->binary.right->type == NODE_LITERAL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//evaluate
|
||||
Literal lhs = (*nodeHandle)->binary.left->atomic.literal;
|
||||
Literal rhs = (*nodeHandle)->binary.right->atomic.literal;
|
||||
Literal result = TO_NULL_LITERAL;
|
||||
|
||||
//type coersion
|
||||
if (IS_FLOAT(lhs) && IS_INTEGER(rhs)) {
|
||||
rhs = TO_FLOAT_LITERAL(AS_INTEGER(rhs));
|
||||
}
|
||||
|
||||
if (IS_INTEGER(lhs) && IS_FLOAT(rhs)) {
|
||||
lhs = TO_FLOAT_LITERAL(AS_INTEGER(lhs));
|
||||
}
|
||||
|
||||
//maths based on types
|
||||
if(IS_INTEGER(lhs) && IS_INTEGER(rhs)) {
|
||||
switch((*nodeHandle)->binary.opcode) {
|
||||
case OP_ADDITION:
|
||||
result = TO_INTEGER_LITERAL( AS_INTEGER(lhs) + AS_INTEGER(rhs) );
|
||||
break;
|
||||
|
||||
case OP_SUBTRACTION:
|
||||
result = TO_INTEGER_LITERAL( AS_INTEGER(lhs) - AS_INTEGER(rhs) );
|
||||
break;
|
||||
|
||||
case OP_MULTIPLICATION:
|
||||
result = TO_INTEGER_LITERAL( AS_INTEGER(lhs) * AS_INTEGER(rhs) );
|
||||
break;
|
||||
|
||||
case OP_DIVISION:
|
||||
result = TO_INTEGER_LITERAL( AS_INTEGER(lhs) / AS_INTEGER(rhs) );
|
||||
break;
|
||||
|
||||
case OP_MODULO:
|
||||
result = TO_INTEGER_LITERAL( AS_INTEGER(lhs) % AS_INTEGER(rhs) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//catch bad modulo
|
||||
if ((IS_FLOAT(lhs) || IS_FLOAT(rhs)) && (*nodeHandle)->binary.opcode == OP_MODULO) {
|
||||
printf("Bad arithmetic argument (modulo on floats not allowed)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(IS_FLOAT(lhs) && IS_FLOAT(rhs)) {
|
||||
switch((*nodeHandle)->binary.opcode) {
|
||||
case OP_ADDITION:
|
||||
printf("binary foobar");
|
||||
result = TO_FLOAT_LITERAL( AS_FLOAT(lhs) + AS_FLOAT(rhs) );
|
||||
break;
|
||||
|
||||
case OP_SUBTRACTION:
|
||||
result = TO_FLOAT_LITERAL( AS_FLOAT(lhs) - AS_FLOAT(rhs) );
|
||||
break;
|
||||
|
||||
case OP_MULTIPLICATION:
|
||||
result = TO_FLOAT_LITERAL( AS_FLOAT(lhs) * AS_FLOAT(rhs) );
|
||||
break;
|
||||
|
||||
case OP_DIVISION:
|
||||
result = TO_FLOAT_LITERAL( AS_FLOAT(lhs) / AS_FLOAT(rhs) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//nothing can be done to optimize
|
||||
if (IS_NULL(result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//optimize by converting this node into a literal
|
||||
freeNode((*nodeHandle)->binary.left);
|
||||
freeNode((*nodeHandle)->binary.right);
|
||||
|
||||
(*nodeHandle)->type = NODE_LITERAL;
|
||||
(*nodeHandle)->atomic.literal = result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule) {
|
||||
//every expression has a prefix rule
|
||||
advance(parser);
|
||||
@@ -320,7 +464,13 @@ static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule ru
|
||||
return;
|
||||
}
|
||||
|
||||
infixRule(parser, nodeHandle, canBeAssigned); //NOTE: infix rule must advance the parser
|
||||
Node* rhsNode = NULL;
|
||||
const Opcode opcode = infixRule(parser, &rhsNode, canBeAssigned); //NOTE: infix rule must advance the parser
|
||||
emitNodeBinary(nodeHandle, rhsNode, opcode);
|
||||
|
||||
if (command.optimize >= 1 && !calcStaticBinaryArithmetic(nodeHandle)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//if your precedence is below "assignment"
|
||||
|
||||
@@ -91,7 +91,7 @@ void repl() {
|
||||
Interpreter interpreter; //persist the interpreter for the scopes
|
||||
|
||||
for(;;) {
|
||||
printf(">");
|
||||
printf("> ");
|
||||
fgets(input, size, stdin);
|
||||
|
||||
//setup this iteration
|
||||
|
||||
Reference in New Issue
Block a user