Basic arithmetic works

This commit is contained in:
2022-08-06 14:50:22 +01:00
parent c178824a0a
commit a05b93975e
6 changed files with 292 additions and 32 deletions

View File

@@ -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:

View File

@@ -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;
} }
} }

View File

@@ -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);

View File

@@ -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,

View File

@@ -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"