diff --git a/source/interpreter.c b/source/interpreter.c index 28caef4..059c581 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -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: diff --git a/source/node.c b/source/node.c index 145a505..58692ed 100644 --- a/source/node.c +++ b/source/node.c @@ -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; } } \ No newline at end of file diff --git a/source/node.h b/source/node.h index c84a894..fd90115 100644 --- a/source/node.h +++ b/source/node.h @@ -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); diff --git a/source/opcodes.h b/source/opcodes.h index 4272183..2542fee 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -12,6 +12,11 @@ typedef enum Opcode { //operators OP_NEGATE, + OP_ADDITION, + OP_SUBTRACTION, + OP_MULTIPLICATION, + OP_DIVISION, + OP_MODULO, //meta OP_SECTION_END, diff --git a/source/parser.c b/source/parser.c index 0e6bbf4..09147bb 100644 --- a/source/parser.c +++ b/source/parser.c @@ -4,6 +4,7 @@ #include "memory.h" #include "literal.h" +#include "opcodes.h" #include @@ -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" diff --git a/source/repl_main.c b/source/repl_main.c index 7fff761..e558281 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -91,7 +91,7 @@ void repl() { Interpreter interpreter; //persist the interpreter for the scopes for(;;) { - printf(">"); + printf("> "); fgets(input, size, stdin); //setup this iteration