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) {
|
static void consumeByte(unsigned char byte, unsigned char* tb, int* count) {
|
||||||
if (byte != tb[*count]) {
|
if (byte != tb[*count]) {
|
||||||
printf("Failed to consume the correct byte");
|
printf("Failed to consume the correct byte\n");
|
||||||
}
|
}
|
||||||
*count += 1;
|
*count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
|
static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
|
||||||
if (bytes != *(unsigned short*)(tb + *count)) {
|
if (bytes != *(unsigned short*)(tb + *count)) {
|
||||||
printf("Failed to consume the correct bytes");
|
printf("Failed to consume the correct bytes\n");
|
||||||
}
|
}
|
||||||
*count += 2;
|
*count += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//each available statement
|
//each available statement
|
||||||
static void execPrint(Interpreter* interpreter) {
|
static bool execPrint(Interpreter* interpreter) {
|
||||||
//print what is on top of the stack, then pop it
|
//print what is on top of the stack, then pop it
|
||||||
Literal lit = popLiteralArray(&interpreter->stack);
|
Literal lit = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
@@ -75,9 +75,11 @@ static void execPrint(Interpreter* interpreter) {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
freeLiteral(lit);
|
freeLiteral(lit);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execPushLiteral(Interpreter* interpreter, bool lng) {
|
static bool execPushLiteral(Interpreter* interpreter, bool lng) {
|
||||||
//read the index in the cache
|
//read the index in the cache
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
@@ -90,9 +92,11 @@ static void execPushLiteral(Interpreter* interpreter, bool lng) {
|
|||||||
|
|
||||||
//push from cache to stack
|
//push from cache to stack
|
||||||
pushLiteralArray(&interpreter->stack, interpreter->literalCache.literals[index]);
|
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
|
//negate the top literal on the stack
|
||||||
Literal lit = popLiteralArray(&interpreter->stack);
|
Literal lit = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
@@ -106,9 +110,81 @@ static void execNegate(Interpreter* interpreter) {
|
|||||||
printf("[internal] The interpreter can't negate that literal: ");
|
printf("[internal] The interpreter can't negate that literal: ");
|
||||||
printLiteral(lit);
|
printLiteral(lit);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, lit);
|
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
|
//the heart of toy
|
||||||
@@ -118,16 +194,32 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
|
while(opcode != OP_EOF && opcode != OP_SECTION_END) {
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case OP_PRINT:
|
case OP_PRINT:
|
||||||
execPrint(interpreter);
|
if (!execPrint(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_LITERAL:
|
case OP_LITERAL:
|
||||||
case OP_LITERAL_LONG:
|
case OP_LITERAL_LONG:
|
||||||
execPushLiteral(interpreter, opcode == OP_LITERAL_LONG);
|
if (!execPushLiteral(interpreter, opcode == OP_LITERAL_LONG)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_NEGATE:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -40,6 +40,17 @@ void emitNodeUnary(Node** nodeHandle, Opcode opcode) {
|
|||||||
(*nodeHandle)->unary.child = NULL;
|
(*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) {
|
void printNode(Node* node) {
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
case NODE_LITERAL:
|
case NODE_LITERAL:
|
||||||
@@ -53,10 +64,11 @@ void printNode(Node* node) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_BINARY:
|
case NODE_BINARY:
|
||||||
printf("binary left:");
|
printf("binary-left:");
|
||||||
printNode(node->binary.left);
|
printNode(node->binary.left);
|
||||||
printf("binary right:");
|
printf("binary-right:");
|
||||||
printNode(node->binary.right);
|
printNode(node->binary.right);
|
||||||
|
printf(";");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,7 @@ union _node {
|
|||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
void emitNodeLiteral(Node** nodeHandle, Literal literal);
|
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 printNode(Node* node);
|
void printNode(Node* node);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ typedef enum Opcode {
|
|||||||
|
|
||||||
//operators
|
//operators
|
||||||
OP_NEGATE,
|
OP_NEGATE,
|
||||||
|
OP_ADDITION,
|
||||||
|
OP_SUBTRACTION,
|
||||||
|
OP_MULTIPLICATION,
|
||||||
|
OP_DIVISION,
|
||||||
|
OP_MODULO,
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_SECTION_END,
|
OP_SECTION_END,
|
||||||
|
|||||||
192
source/parser.c
192
source/parser.c
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "literal.h"
|
#include "literal.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -98,7 +99,7 @@ typedef enum {
|
|||||||
PREC_PRIMARY,
|
PREC_PRIMARY,
|
||||||
} PrecedenceRule;
|
} PrecedenceRule;
|
||||||
|
|
||||||
typedef void (*ParseFn)(Parser* parser, Node** nodeHandle, bool canBeAssigned);
|
typedef Opcode (*ParseFn)(Parser* parser, Node** nodeHandle, bool canBeAssigned);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ParseFn prefix;
|
ParseFn prefix;
|
||||||
@@ -112,25 +113,58 @@ ParseRule parseRules[];
|
|||||||
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule);
|
||||||
|
|
||||||
//the expression rules
|
//the expression rules
|
||||||
static void string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
static Opcode string(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||||
//handle strings
|
//handle strings
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOKEN_LITERAL_STRING:
|
case TOKEN_LITERAL_STRING:
|
||||||
emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, parser->previous.length)));
|
emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, parser->previous.length)));
|
||||||
break;
|
return OP_EOF;
|
||||||
|
|
||||||
//TODO: interpolated strings
|
//TODO: interpolated strings
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(parser, parser->previous, "Unexpected token passed to string precedence rule");
|
error(parser, parser->previous, "Unexpected token passed to string precedence rule");
|
||||||
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||||
//TODO
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
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 Opcode unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOKEN_MINUS: {
|
case TOKEN_MINUS: {
|
||||||
//temp handle to potentially negate values
|
//temp handle to potentially negate values
|
||||||
@@ -153,7 +187,7 @@ static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
|||||||
tmpNode->atomic.literal = lit;
|
tmpNode->atomic.literal = lit;
|
||||||
*nodeHandle = tmpNode;
|
*nodeHandle = tmpNode;
|
||||||
|
|
||||||
break;
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
//process the literal without optimizations
|
//process the literal without optimizations
|
||||||
@@ -161,48 +195,50 @@ static void unary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
|
|||||||
emitNodeUnary(nodeHandle, OP_NEGATE);
|
emitNodeUnary(nodeHandle, OP_NEGATE);
|
||||||
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
||||||
(*nodeHandle) = tmpNode; //set negate's child to the literal
|
(*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");
|
error(parser, parser->previous, "Unexpected token passed to unary minus precedence rule");
|
||||||
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(parser, parser->previous, "Unexpected token passed to unary precedence rule");
|
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) {
|
switch(parser->previous.type) {
|
||||||
case TOKEN_NULL:
|
case TOKEN_NULL:
|
||||||
emitNodeLiteral(nodeHandle, TO_NULL_LITERAL);
|
emitNodeLiteral(nodeHandle, TO_NULL_LITERAL);
|
||||||
break;
|
return OP_EOF;
|
||||||
|
|
||||||
case TOKEN_LITERAL_TRUE:
|
case TOKEN_LITERAL_TRUE:
|
||||||
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true));
|
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(true));
|
||||||
break;
|
return OP_EOF;
|
||||||
|
|
||||||
case TOKEN_LITERAL_FALSE:
|
case TOKEN_LITERAL_FALSE:
|
||||||
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(false));
|
emitNodeLiteral(nodeHandle, TO_BOOLEAN_LITERAL(false));
|
||||||
break;
|
return OP_EOF;
|
||||||
|
|
||||||
case TOKEN_LITERAL_INTEGER: {
|
case TOKEN_LITERAL_INTEGER: {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
sscanf(parser->previous.lexeme, "%d", &value);
|
sscanf(parser->previous.lexeme, "%d", &value);
|
||||||
emitNodeLiteral(nodeHandle, TO_INTEGER_LITERAL(value));
|
emitNodeLiteral(nodeHandle, TO_INTEGER_LITERAL(value));
|
||||||
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case TOKEN_LITERAL_FLOAT: {
|
case TOKEN_LITERAL_FLOAT: {
|
||||||
float value = 0;
|
float value = 0;
|
||||||
sscanf(parser->previous.lexeme, "%f", &value);
|
sscanf(parser->previous.lexeme, "%f", &value);
|
||||||
emitNodeLiteral(nodeHandle, TO_FLOAT_LITERAL(value));
|
emitNodeLiteral(nodeHandle, TO_FLOAT_LITERAL(value));
|
||||||
|
return OP_EOF;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(parser, parser->previous, "Unexpected token passed to atomic precedence rule");
|
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,
|
{string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
|
||||||
|
|
||||||
//math operators
|
//math operators
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PLUS,
|
{NULL, binary, PREC_TERM},// TOKEN_PLUS,
|
||||||
{unary, NULL, PREC_UNARY},// TOKEN_MINUS,
|
{unary, binary, PREC_TERM},// TOKEN_MINUS,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY,
|
{NULL, binary, PREC_TERM},// TOKEN_MULTIPLY,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_DIVIDE,
|
{NULL, binary, PREC_TERM},// TOKEN_DIVIDE,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MODULO,
|
{NULL, binary, PREC_TERM},// TOKEN_MODULO,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PLUS_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_PLUS_ASSIGN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_ASSIGN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY_ASSIGN,
|
||||||
@@ -298,6 +334,114 @@ ParseRule* getRule(TokenType type) {
|
|||||||
return &parseRules[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) {
|
static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule) {
|
||||||
//every expression has a prefix rule
|
//every expression has a prefix rule
|
||||||
advance(parser);
|
advance(parser);
|
||||||
@@ -320,7 +464,13 @@ static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule ru
|
|||||||
return;
|
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"
|
//if your precedence is below "assignment"
|
||||||
|
|||||||
Reference in New Issue
Block a user