From 8c7571bef40edfe9c92b07ee956c5e74cf0f13fe Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Tue, 25 Sep 2018 22:37:05 -0400 Subject: [PATCH] Modularized programming language code. Code is no longer in several large files :) --- Makefile | 30 +- src/constants.h | 11 + src/main.c | 31 ++ src/node.h | 93 ---- src/operations/node.c | 342 ++++++++++++++ src/operations/node.h | 33 ++ src/operations/operators.c | 231 ++++++++++ src/operations/operators.h | 18 + src/parser.y | 885 ------------------------------------ src/{ => parser}/lexer.l | 3 +- src/parser/parser.h | 8 + src/parser/parser.y | 160 +++++++ src/sloth.h | 12 + src/variables/environment.c | 49 ++ src/variables/environment.h | 17 + src/variables/value.c | 68 +++ src/variables/value.h | 39 ++ src/variables/variable.c | 27 ++ src/variables/variable.h | 22 + 19 files changed, 1093 insertions(+), 986 deletions(-) create mode 100644 src/constants.h create mode 100644 src/main.c delete mode 100644 src/node.h create mode 100644 src/operations/node.c create mode 100644 src/operations/node.h create mode 100644 src/operations/operators.c create mode 100644 src/operations/operators.h delete mode 100644 src/parser.y rename src/{ => parser}/lexer.l (96%) create mode 100644 src/parser/parser.h create mode 100644 src/parser/parser.y create mode 100644 src/sloth.h create mode 100644 src/variables/environment.c create mode 100644 src/variables/environment.h create mode 100644 src/variables/value.c create mode 100644 src/variables/value.h create mode 100644 src/variables/variable.c create mode 100644 src/variables/variable.h diff --git a/Makefile b/Makefile index 97e2d49..dc5ea91 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,24 @@ -run: src/lex.yy.c src/parser.tab.c - gcc src/lex.yy.c src/parser.tab.c -o sloth -src/parser.tab.c: src/parser.y - bison -d -o src/parser.tab.c src/parser.y -src/lex.yy.c: src/lexer.l - flex -o src/lex.yy.c src/lexer.l +sloth: src/main.c src/parser/lex.yy.o src/parser/parser.tab.o src/variables/environment.o src/variables/variable.o src/variables/value.o src/operations/node.o src/operations/operators.o + gcc src/main.c src/parser/lex.yy.o src/parser/parser.tab.o src/variables/environment.o src/variables/variable.o src/variables/value.o src/operations/node.o src/operations/operators.o -o sloth +src/parser/lex.yy.o: src/parser/lex.yy.c src/parser/parser.tab.h + gcc -c src/parser/lex.yy.c -o src/parser/lex.yy.o +src/parser/parser.tab.o: src/parser/parser.tab.c + gcc -c src/parser/parser.tab.c -o src/parser/parser.tab.o +src/parser/parser.tab.h: src/parser/parser.y + bison -d -o src/parser/parser.tab.c src/parser/parser.y +src/parser/parser.tab.c: src/parser/parser.y + bison -d -o src/parser/parser.tab.c src/parser/parser.y +src/parser/lex.yy.c: src/parser/lexer.l + flex -o src/parser/lex.yy.c src/parser/lexer.l +src/variables/environment.o: src/variables/environment.h src/variables/environment.c + gcc -c src/variables/environment.c -o src/variables/environment.o +src/variables/variable.o: src/variables/variable.h src/variables/variable.c + gcc -c src/variables/variable.c -o src/variables/variable.o +src/variables/value.o: src/variables/value.h src/variables/value.h + gcc -c src/variables/value.c -o src/variables/value.o +src/operations/operators.o: src/operations/operators.h src/operations/operators.c + gcc -c src/operations/operators.c -o src/operations/operators.o +src/operations/node.o: src/operations/node.h src/operations/node.c + gcc -c src/operations/node.c -o src/operations/node.o clean: - rm src/lex.yy.c src/parser.tab.c src/parser.tab.h sloth + rm src/parser/lex.yy.c src/parser/parser.tab.c src/parser/parser.tab.h src/parser/lex.yy.o src/parser/parser.tab.o src/variables/environment.o src/variables/variable.o src/variables/value.o src/operations/node.o src/operations/operators.o sloth diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000..06c47ac --- /dev/null +++ b/src/constants.h @@ -0,0 +1,11 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#define STATEMENT 200 +#define CALLFUNC 201 + +// Share the line number between files +extern int linenum; +extern struct Node* result; + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..50b8f5d --- /dev/null +++ b/src/main.c @@ -0,0 +1,31 @@ +#include +#include +#include "sloth.h" + +/* the result variable */ +struct Node* result; + +int main(int argc, char* argv[]) { + if (argc != 2) { + printf("Incorrect number of arguments passed. Expected %d, got %d.\n", 1, argc - 1); + printf("Usage: lexer [program_name].sl\n"); + exit(-1); + } + /* save stdin */ + FILE* orig_stdin = stdin; + stdin = fopen(argv[1], "r"); + + yyparse( ); + + /* restore stdin */ + fclose(stdin); + stdin = orig_stdin; + + // Interpret the AST + // print_tree(result, 0); + struct Environment* env = create_environment(); + eval_statement(result, env); + delete_environment(env); + delete_tree(result); + return 0; +} diff --git a/src/node.h b/src/node.h deleted file mode 100644 index 8c4838b..0000000 --- a/src/node.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef NODE_H -#define NODE_H - -#define ID_SIZE 100 -#define MAX_CHILDREN 3 -#define STATEMENT 200 -#define CALLFUNC 201 -#define MAX_VARIABLES 200 - -enum TypeTag { DOUBLE, LONG, BOOLEAN }; - -// Share the line number between files -extern int linenum; - -/* a tree node definition */ -struct Node { - int type; - struct Value* value; - - /* the id of the node (used for identifiers only) */ - char id[ID_SIZE]; - - /* at most three children nodes */ - int num_children; - struct Node* children[MAX_CHILDREN]; -}; - -// Abstract Syntax Tree Functions -struct Node* make_node(int type, struct Value* value, char* id); -void attach_node(struct Node* parent, struct Node* child); -void print_tree(struct Node* node, int tabs); -void delete_tree(struct Node* node); - - -struct Variable { - char id[ID_SIZE]; - struct Value* value; -}; - -typedef union typeval { - long num; - double dec; - struct Node* expr; -} TypeVal; - -struct Value { - enum TypeTag type; - TypeVal value; -}; - -// Value functions -struct Value* make_value(int type, long num, double dec, struct Node* expr); -struct Value* make_long(long num); -struct Value* make_double(double dec); -struct Value* make_true(); -struct Value* make_false(); - -void delete_value(struct Value* val); -long get_long(struct Value* val); -double get_double(struct Value* val); -struct Node* get_expression(struct Value* val); -void set_long(struct Value* val, long num); -void set_double(struct Value* val, double dec); -void set_expression(struct Value* val, struct Node* node); - -// Variable Functions -struct Variable* make_variable(char* id, struct Value* value); -void set_value(struct Variable* var, struct Value* value); -struct Value* get_value(struct Variable* var); -struct Value* make_long(long num); -struct Value* make_double(double dec); -struct Value* make_true(); -struct Value* make_false(); -struct Value* make_boolean(int x); -struct Value* make_expression(struct Node* expr); - -struct Environment { - int num_vars; - struct Variable* vars[MAX_VARIABLES]; -}; - -// Variable Lookup Functions -struct Environment* create_environment(void); -void delete_environment(struct Environment* env); -struct Variable* find_variable(struct Environment* env, char* id); -void add_variable(struct Environment* env, struct Variable* var); - - -// Interpreting AST -void eval_statement(struct Node* node, struct Environment* env); -struct Value* eval_expression(struct Node* node, struct Environment* env); - -#endif diff --git a/src/operations/node.c b/src/operations/node.c new file mode 100644 index 0000000..166f4ab --- /dev/null +++ b/src/operations/node.c @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include "node.h" +#include "operators.h" +#include "../constants.h" +#include "../parser/parser.tab.h" +#include "../variables/value.h" +#include "../variables/variable.h" + +/* creates a new node and returns it */ +struct Node* make_node(int type, struct Value* value, char* id) { + int i; + + /* allocate space */ + struct Node* node = malloc(sizeof(struct Node)); + + /* set properties */ + node->type = type; + node->value = value; + strcpy(node->id, id); + node->num_children = 0; + for(i = 0; i < MAX_CHILDREN; i++) { + node->children[i] = NULL; + } + + /* return new node */ + return node; +} + +/* attach an existing node onto a parent */ +void attach_node(struct Node* parent, struct Node* child) { + /* connect it */ + parent->children[parent->num_children] = child; + parent->num_children++; + assert(parent->num_children <= MAX_CHILDREN); +} + +void check_num_nodes(struct Node* node, int num_children, char* error) { + if (node && node->num_children != num_children) { + fprintf(stderr, "%s%s%s", "Error, ", error, "\n"); + } +} + +void print_tree(struct Node* node, int tabs) { + int i; + /* base case */ + if(!node) { + fprintf(stderr, "NO TREE STRUCTURE\n"); + return; + } + + /* print leading tabs */ + for(i = 0; i < tabs; i++) { + printf(" "); + } + + switch(node->type) { + case IDENTIFIER: printf("IDENTIFIER: %s\n", node->id); break; + case PLUS: printf("PLUS:\n"); break; + case MINUS: printf("MINUS:\n"); break; + case DIVIDE: printf("DIVIDE:\n"); break; + case TIMES: printf("TIMES:\n"); break; + case LESS: printf("LESS THAN:\n"); break; + case GREATER: printf("GREATER:\n"); break; + case LESSEQ: printf("LESS EQUAL:\n"); break; + case GREATEREQ: printf("GREATER EQUAL:\n"); break; + case EQUALS: printf("EQUALS:\n"); break; + case NEQUALS: printf("NOT EQUALS:\n"); break; + case AND: printf("AND:\n"); break; + case OR: printf("OR:\n"); break; + case NOT: printf("NOT:\n"); break; + case ASSIGN: printf("ASSIGN:\n"); break; + case IF: printf("IF:\n"); break; + case WHILE: printf("WHILE:\n"); break; + case PRINT: printf("PRINT:\n"); break; + case INPUT: printf("INPUT:\n"); break; + case LAMBDA: printf("LAMBDA:\n"); break; + case CALLFUNC: printf("FUNCTIONCALL:\n"); break; + case STATEMENT: printf("STATEMENT:\n"); break; + case VALUE: + if (node->value->type == BOOLEAN) { + if (get_long(node->value)) { + printf("VALUE: true\n"); + } else { + printf("VALUE: false\n"); + } + } else if (node->value->type == LONG) { + printf("VALUE: %li\n", get_long(node->value)); + } else { // Assume double + printf("VALUE: %lf\n", get_double(node->value)); + } + break; + default: + printf("Error, %d not a valid node type.\n", node->type); + exit(1); + } + + /* print all children nodes underneath */ + for(i = 0; i < node->num_children; i++) { + print_tree(node->children[i], tabs + 1); + } +} + +void delete_tree(struct Node* node) { + if (!node) { return; } + for(int i = 0; i < node->num_children; i++) { + delete_tree(node->children[i]); + } + free(node); +} + + + +struct Value* eval_expression(struct Node* node, struct Environment* env) { + /* base case */ + if(!node) { + fprintf(stderr, "Error: No tree structure to evaluate\n"); + return 0; + } + + // Needed if we are going to take input from the user + double temp; + struct Variable* var = NULL; + struct Environment* local_env = NULL; + struct Node* tempNode = NULL; + struct Value* tempVal = NULL; + + // Evaluate subexpressions if existent and node is not a lambda expression + struct Value* val1 = NULL; + struct Value* val2 = NULL; + struct Value* val3 = NULL; + if (node->num_children > 0 && node->type != LAMBDA) { + val1 = eval_expression(node->children[0], env); + if (node->num_children > 1) { + val2 = eval_expression(node->children[1], env); + if (node->num_children > 2) { + val3 = eval_expression(node->children[2], env); + // delete_value(val3); // No code below uses val3 for now... + } + } + } + + switch(node->type) { + case LAMBDA: return make_expression(node); break; + case CALLFUNC: + check_num_nodes(node, 2, "cannot have more than two nodes for a function call."); + tempNode = get_expression(get_value(find_variable(env, node->children[0]->id))); + local_env = create_environment(); + add_variable(local_env, + make_variable(tempNode->children[0]->id, // Get the name of the variable needed for the lambda expression + eval_expression(node->children[1], env))); + tempVal = eval_expression(tempNode->children[1], local_env); + delete_environment(local_env); + return tempVal; + break; + case PLUS: + check_num_nodes(node, 2, "cannot add more than two expressions."); + return add(val1, val2); + // return val1 + val2; + break; + //---------- + case MINUS: + check_num_nodes(node, 2, "cannot subtract more than two expressions."); + return subtract(val1, val2); + // return val1 - val2; + break; + //---------- + case DIVIDE: + check_num_nodes(node, 2, "cannot divide more than two expressions."); + return division(val1, val2); + // return val1 / val2; + break; + //---------- + case TIMES: + check_num_nodes(node, 2, "cannot multiply more than two expressions."); + return multiplication(val1, val2); + // return val1 * val2; + break; + //---------- + case LESS: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return less(val1, val2); + // return val1 < val2; + break; + //---------- + case GREATER: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + return greater(val1, val2); + // return val1 > val2; + break; + //---------- + case LESSEQ: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + return less_equal(val1, val2); + // return val1 <= val2; + break; + //---------- + case GREATEREQ: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + return greater_equal(val1, val2); + // return val1 >= val2; + break; + //---------- + case EQUALS: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + return equals(val1, val2); + // return val1 == val2; + break; + //---------- + case NEQUALS: + check_num_nodes(node, 2, "cannot compare more than two expressions."); + return not_equals(val1, val2); + // return val1 != val2; + break; + //---------- + case AND: + check_num_nodes(node, 2, "cannot perform logical operators on more than two expressions."); + return and(val1, val2); + // return val1 && val2; + break; + //---------- + case OR: + check_num_nodes(node, 2, "cannot perform logical operators on more than two expressions."); + return or(val1, val2); + // return val1 || val2; + break; + //---------- + case NOT: + check_num_nodes(node, 1, "cannot negate more than one expressions."); + return not(val1); + // return !val1; + break; + //---------- + case INPUT: // We're only going to support reading in doubles + // Look into deleting possible values...? + scanf("%lf", &temp); + return make_double(temp); + break; + //---------- + case IDENTIFIER: + var = find_variable(env, node->id); + if (var == NULL) { + fprintf(stderr, "Error: Symbol %s not found.\n", node->id); + return 0; + } + return get_value(var); + break; + //---------- + case VALUE: + return node->value; + break; + //---------- + default: + fprintf(stderr,"Error, %d not a valid expression type.\n", node->type); + return 0; + } + +} + + +void eval_statement(struct Node* node, struct Environment* env) { + /* base case */ + if(!node) { + fprintf(stderr, "Error: No tree structure to evaluate\n"); + return; + } + + struct Value* tempVal; + + switch(node->type) { + case ASSIGN: + check_num_nodes(node, 2, "cannot make an assignment without an identifier and a value."); + add_variable(env, + make_variable(node->children[0]->id, + eval_expression(node->children[1], env))); + break; + //------------ + case IF: + if (node->num_children != 2 && node->num_children != 3) { + fprintf(stderr, "Error: The format of an if-statement is if expression statement with an optional else.\n"); + } + tempVal = eval_expression(node->children[0], env); + if (tempVal->type == BOOLEAN) { + if (get_long(tempVal)) { + eval_statement(node->children[1], env); + } else if (node->num_children == 3) { + eval_statement(node->children[2], env); + } + } else { + fprintf(stderr, "Error, a non-boolean was in the condition of an if statement.\n"); + } + break; + //------------ + case WHILE: + check_num_nodes(node, 2, "the format of a while statement is: while expression statement(s)"); + tempVal = eval_expression(node->children[0], env); + if (tempVal->type == BOOLEAN) { + while (get_long(tempVal)) { + eval_statement(node->children[1], env); + tempVal = eval_expression(node->children[0], env); + } + } else { + fprintf(stderr, "Error, a non-boolean was in the condition of the while loop.\n"); + } + + break; + //------------ + case PRINT: + check_num_nodes(node, 1, "can only print out one expression at a time."); + tempVal = eval_expression(node->children[0], env); + if (tempVal->type == BOOLEAN) { + if (get_long(tempVal)) { + printf("true\n"); + } else { + printf("false\n"); + } + } else if (tempVal->type == LONG) { + printf("%li\n", get_long(tempVal)); + } else if (tempVal ->type == DOUBLE) { + printf("%lf\n", get_double(tempVal)); + } else { // Assume lambda expression + printf("\n"); + } + break; + //------------ + case STATEMENT: // Can have a maximum of two children statement nodes + if (node->num_children > 0) { + eval_statement(node->children[0], env); + } + if (node->num_children > 1) { + eval_statement(node->children[1], env); + } + break; + //------------ + default: + printf("Error, %d not a valid statement type.\n", node->type); + return; + } +} diff --git a/src/operations/node.h b/src/operations/node.h new file mode 100644 index 0000000..d1db734 --- /dev/null +++ b/src/operations/node.h @@ -0,0 +1,33 @@ +#ifndef NODE_H +#define NODE_H + +#include "../variables/value.h" +#include "../variables/environment.h" + +#define ID_SIZE 100 +#define MAX_CHILDREN 3 + +/* a tree node definition */ +struct Node { + int type; + struct Value* value; + + /* the id of the node (used for identifiers only) */ + char id[ID_SIZE]; + + /* at most three children nodes */ + int num_children; + struct Node* children[MAX_CHILDREN]; +}; + +// Abstract Syntax Tree Functions +struct Node* make_node(int type, struct Value* value, char* id); +void attach_node(struct Node* parent, struct Node* child); +void print_tree(struct Node* node, int tabs); +void delete_tree(struct Node* node); + +// Interpreting AST +void eval_statement(struct Node* node, struct Environment* env); +struct Value* eval_expression(struct Node* node, struct Environment* env); + +#endif diff --git a/src/operations/operators.c b/src/operations/operators.c new file mode 100644 index 0000000..abe5fac --- /dev/null +++ b/src/operations/operators.c @@ -0,0 +1,231 @@ +#include +#include +#include "operators.h" +#include "../variables/value.h" + +struct Value* add(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in add.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot add a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_long(get_long(x) + get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_double(get_long(x) + get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_double(get_double(x) + get_long(y)); + } else { // Both are DOUBLE + ans = make_double(get_double(x) + get_double(y)); + } + + return ans; +} + +struct Value* subtract(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in subtract.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot subtract a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_long(get_long(x) - get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_double(get_long(x) - get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_double(get_double(x) - get_long(y)); + } else { // Both are DOUBLE + ans = make_double(get_double(x) - get_double(y)); + } + + return ans; +} + +struct Value* division(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in divide.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot divide a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_long(get_long(x) / get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_double(get_long(x) / get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_double(get_double(x) / get_long(y)); + } else { // Both are DOUBLE + ans = make_double(get_double(x) / get_double(y)); + } + + return ans; +} + +struct Value* multiplication(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in multiply.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot multiply a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_long(get_long(x) * get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_double(get_long(x) * get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_double(get_double(x) * get_long(y)); + } else { // Both are DOUBLE + ans = make_double(get_double(x) * get_double(y)); + } + + return ans; +} + +struct Value* less(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in <.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) < get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) < get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) < get_long(y)); + } else { // Both are DOUBLE + ans = make_boolean(get_double(x) < get_double(y)); + } + + return ans; +} + +struct Value* greater(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in greater.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) > get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) > get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) > get_long(y)); + } else { // Both are DOUBLE + ans = make_boolean(get_double(x) > get_double(y)); + } + + return ans; +} + +struct Value* less_equal(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in <=.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) <= get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) <= get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) <= get_long(y)); + } else { // Both are DOUBLE + ans = make_boolean(get_double(x) <= get_double(y)); + } + + return ans; +} + +struct Value* greater_equal(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in >=.\n"); } + if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) >= get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) >= get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) >= get_long(y)); + } else { // Both are DOUBLE + ans = make_boolean(get_double(x) >= get_double(y)); + } + + return ans; +} + +struct Value* equals(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in ==.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) == get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) == get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) == get_long(y)); + } else if (x->type == DOUBLE && y->type == DOUBLE) { + ans = make_boolean(get_double(x) == get_double(y)); + } else if (x->type == BOOLEAN && y->type == BOOLEAN) { + ans = make_boolean(get_long(x) == get_long(y)); + } else { // Type is a mix between boolean and another type + fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); + } + + return ans; +} + +struct Value* not_equals(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in !=.\n"); } + + struct Value* ans; + + // Destruct all four cases + if (x->type == LONG && y->type == LONG) { + ans = make_boolean(get_long(x) != get_long(y)); + } else if (x->type == LONG && y->type == DOUBLE) { + ans = make_boolean(get_long(x) != get_double(y)); + } else if (x->type == DOUBLE && y->type == LONG) { + ans = make_boolean(get_double(x) != get_long(y)); + } else if (x->type == DOUBLE && y->type == DOUBLE) { + ans = make_boolean(get_double(x) != get_double(y)); + } else if (x->type == BOOLEAN && y->type == BOOLEAN) { + ans = make_boolean(get_long(x) != get_long(y)); + } else { // Type is a mix between boolean and another type + fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); + } + + return ans; +} + +struct Value* and(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in &&.\n"); } + if (x->type != BOOLEAN || y->type != BOOLEAN) { fprintf(stderr, "Error, cannot use and AND operation with a non-boolean.\n"); } + + return make_boolean(get_long(x) && get_long(y)); +} + +struct Value* or(struct Value* x, struct Value* y) { + if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in ||.\n"); } + if (x->type != BOOLEAN || y->type != BOOLEAN) { fprintf(stderr, "Error, cannot use and OR operation with a non-boolean.\n"); } + + return make_boolean(get_long(x) || get_long(y)); +} + +struct Value* not(struct Value* x) { + if (!x) { fprintf(stderr, "Error, uninitialized values being used in !.\n"); } + if (x->type != BOOLEAN) { fprintf(stderr, "Error, cannot NOT a non-boolean.\n"); } + + return make_boolean(!get_long(x)); +} diff --git a/src/operations/operators.h b/src/operations/operators.h new file mode 100644 index 0000000..174cea0 --- /dev/null +++ b/src/operations/operators.h @@ -0,0 +1,18 @@ +#ifndef OPERATORS_H +#define OPERATORS_H + +struct Value* add(struct Value* x, struct Value* y); +struct Value* subtract(struct Value* x, struct Value* y); +struct Value* division(struct Value* x, struct Value* y); +struct Value* multiplication(struct Value* x, struct Value* y); +struct Value* less(struct Value* x, struct Value* y); +struct Value* greater(struct Value* x, struct Value* y); +struct Value* less_equal(struct Value* x, struct Value* y); +struct Value* greater_equal(struct Value* x, struct Value* y); +struct Value* equals(struct Value* x, struct Value* y); +struct Value* not_equals(struct Value* x, struct Value* y); +struct Value* and(struct Value* x, struct Value* y); +struct Value* or(struct Value* x, struct Value* y); +struct Value* not(struct Value* x); + +#endif diff --git a/src/parser.y b/src/parser.y deleted file mode 100644 index 6b805d7..0000000 --- a/src/parser.y +++ /dev/null @@ -1,885 +0,0 @@ -%{ -#include -#include -#include -#include -#include "node.h" - -int yywrap( ); -int yylex( ); -void yyerror(const char* str); - -/* the result variable */ -struct Node* result; - -%} - -/* declare type possibilities of symbols */ -%union { - struct Node* value; -} - -/* declare tokens (default is typeless) */ -%token IDENTIFIER -%token VALUE -%token PLUS -%token MINUS -%token DIVIDE -%token TIMES -%token LESS -%token GREATER -%token LESSEQ -%token GREATEREQ -%token EQUALS -%token NEQUALS -%token AND -%token OR -%token NOT -%token SEMICOLON -%token ASSIGN -%token OPENPAREM -%token ENDPAREM -%token BEGINTOK -%token END -%token IF -%token THEN -%token ELSE -%token WHILE -%token DO -%token PRINT -%token INPUT -%token COMMENT -%token WHITESPACE -%token DONE -%token LAMBDA -%token COLON - -/* declare non-terminals */ -%type program statement assignment if-statement if-else-statement while print statements substatements callfunc exprlambda expression subexpression term subterm factor atom identvalue ident - -/* give us more detailed errors */ -%error-verbose - -%% -program: substatements {result = $1; return 0;} - | "" {return 0;} - -statement: assignment { $$ = $1; } - | if-statement { $$ = $1; } - | if-else-statement { $$ = $1; } - | while { $$ = $1; } - | print { $$ = $1; } - | statements { $$ = $1; } - -assignment: ident ASSIGN exprlambda SEMICOLON { - $$ = make_node(ASSIGN, NULL, ""); - attach_node($$, $1); - attach_node($$, $3); -} - -if-statement: IF expression THEN statement { - $$ = make_node(IF, NULL, ""); - attach_node($$, $2); - attach_node($$, $4); -} - -if-else-statement: IF expression THEN statement ELSE statement { - $$ = make_node(IF, NULL, ""); - attach_node($$, $2); - attach_node($$, $4); - attach_node($$, $6); -} - -while: WHILE expression DO statement { - $$ = make_node(WHILE, NULL, ""); - attach_node($$, $2); - attach_node($$, $4); -} - -print: PRINT exprlambda SEMICOLON { - $$ = make_node(PRINT, NULL, ""); - attach_node($$, $2); -} - - -statements: BEGINTOK substatements END { $$ = $2; } - | BEGINTOK END {} - -substatements: statement substatements {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); attach_node($$, $2); } - | statement {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); } - -exprlambda: LAMBDA ident COLON expression { - // Only supports one argument functions for now - $$ = make_node(LAMBDA, NULL, ""); - attach_node($$, $2); - attach_node($$, $4); } - | expression { $$ = $1; } - -expression: expression OR subexpression { $$ = make_node(OR, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | expression AND subexpression { $$ = make_node(AND, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression { $$ = $1; } - -subexpression: subexpression LESS term { $$ = make_node(LESS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression LESSEQ term { $$ = make_node(LESSEQ, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression GREATER term { $$ = make_node(GREATER, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression GREATEREQ term { $$ = make_node(GREATEREQ, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression EQUALS term { $$ = make_node(EQUALS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subexpression NEQUALS term { $$ = make_node(NEQUALS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | term { $$ = $1; } - -term : term PLUS subterm { $$ = make_node(PLUS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | term MINUS subterm { $$ = make_node(MINUS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subterm { $$ = $1; } - -subterm: subterm TIMES factor { $$ = make_node(TIMES, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | subterm DIVIDE factor { $$ = make_node(DIVIDE, NULL, ""); attach_node($$, $1); attach_node($$, $3);} - | factor { $$ = $1; } - -factor : MINUS factor { $$ = make_node(MINUS, NULL, ""); attach_node($$, $2); } - | NOT factor { $$ = make_node(NOT, NULL, ""); attach_node($$, $2); } - | atom { $$ = $1; } - -callfunc: ident OPENPAREM expression ENDPAREM { $$ = make_node(CALLFUNC, NULL, ""); attach_node($$, $1); attach_node($$, $3); } - -atom: OPENPAREM expression ENDPAREM { $$ = $2; } - | callfunc { $$ = $1; } - | identvalue { $$ = $1; } - -ident: IDENTIFIER { $$ = $1; } - -identvalue: ident { $$ = $1; } - | VALUE { $$ = $1; } - | INPUT { $$ = make_node(INPUT, NULL , ""); } - - - - -%% - - -int yywrap( ) { - return 1; -} - -void yyerror(const char* str) { - fprintf(stderr, "Compiler error on line %d: '%s'.\n", linenum, str); - exit(1); -} - -int main(int argc, char* argv[]) { - if (argc != 2) { - printf("Incorrect number of arguments passed. Expected %d, got %d.\n", 1, argc - 1); - printf("Usage: lexer [program_name].sl\n"); - exit(-1); - } - /* save stdin */ - FILE* orig_stdin = stdin; - stdin = fopen(argv[1], "r"); - - yyparse( ); - - /* restore stdin */ - fclose(stdin); - stdin = orig_stdin; - - // Interpret the AST - // print_tree(result, 0); - struct Environment* env = create_environment(); - eval_statement(result, env); - delete_environment(env); - delete_tree(result); - return 0; -} - - - - - - -/* creates a new node and returns it */ -struct Node* make_node(int type, struct Value* value, char* id) { - int i; - - /* allocate space */ - struct Node* node = malloc(sizeof(struct Node)); - - /* set properties */ - node->type = type; - node->value = value; - strcpy(node->id, id); - node->num_children = 0; - for(i = 0; i < MAX_CHILDREN; i++) { - node->children[i] = NULL; - } - - /* return new node */ - return node; -} - -/* attach an existing node onto a parent */ -void attach_node(struct Node* parent, struct Node* child) { - /* connect it */ - parent->children[parent->num_children] = child; - parent->num_children++; - assert(parent->num_children <= MAX_CHILDREN); -} - -void print_tree(struct Node* node, int tabs) { - int i; - /* base case */ - if(!node) { - fprintf(stderr, "NO TREE STRUCTURE\n"); - return; - } - - /* print leading tabs */ - for(i = 0; i < tabs; i++) { - printf(" "); - } - - switch(node->type) { - case IDENTIFIER: printf("IDENTIFIER: %s\n", node->id); break; - case PLUS: printf("PLUS:\n"); break; - case MINUS: printf("MINUS:\n"); break; - case DIVIDE: printf("DIVIDE:\n"); break; - case TIMES: printf("TIMES:\n"); break; - case LESS: printf("LESS THAN:\n"); break; - case GREATER: printf("GREATER:\n"); break; - case LESSEQ: printf("LESS EQUAL:\n"); break; - case GREATEREQ: printf("GREATER EQUAL:\n"); break; - case EQUALS: printf("EQUALS:\n"); break; - case NEQUALS: printf("NOT EQUALS:\n"); break; - case AND: printf("AND:\n"); break; - case OR: printf("OR:\n"); break; - case NOT: printf("NOT:\n"); break; - case ASSIGN: printf("ASSIGN:\n"); break; - case IF: printf("IF:\n"); break; - case WHILE: printf("WHILE:\n"); break; - case PRINT: printf("PRINT:\n"); break; - case INPUT: printf("INPUT:\n"); break; - case LAMBDA: printf("LAMBDA:\n"); break; - case CALLFUNC: printf("FUNCTIONCALL:\n"); break; - case STATEMENT: printf("STATEMENT:\n"); break; - case VALUE: - if (node->value->type == BOOLEAN) { - if (get_long(node->value)) { - printf("VALUE: true\n"); - } else { - printf("VALUE: false\n"); - } - } else if (node->value->type == LONG) { - printf("VALUE: %li\n", get_long(node->value)); - } else { // Assume double - printf("VALUE: %lf\n", get_double(node->value)); - } - break; - default: - printf("Error, %d not a valid node type.\n", node->type); - exit(1); - } - - /* print all children nodes underneath */ - for(i = 0; i < node->num_children; i++) { - print_tree(node->children[i], tabs + 1); - } -} - -void delete_tree(struct Node* node) { - if (!node) { return; } - for(int i = 0; i < node->num_children; i++) { - delete_tree(node->children[i]); - } - free(node); -} - -/* creates a new variable and returns it */ -struct Variable* make_variable(char* id, struct Value* value) { - /* allocate space */ - struct Variable* var = malloc(sizeof(struct Variable)); - - /* set properties */ - strcpy(var->id, id); - var->value = value; - - /* return new variable */ - return var; -} - -void set_value(struct Variable* var, struct Value* value) { - if (!var) { fprintf(stderr, "Error: Invalid Variable\n"); return; } - var->value = value; -} - -struct Value* get_value(struct Variable* var) { - if (!var) { fprintf(stderr, "Error: Invalid Variable\n"); return 0; } - return var->value; -} - -struct Environment* create_environment(void) { - struct Environment* env = malloc(sizeof(struct Environment)); - env->num_vars = 0; - for(int i = 0; i < MAX_VARIABLES; i++) { - env->vars[i] = NULL; - } - return env; -} - -struct Variable* find_variable(struct Environment* env, char* id) { - for (int i = 0; i < env->num_vars; i++) { - if (strcmp(env->vars[i]->id, id) == 0) { - return env->vars[i]; - } - } - return NULL; -} - -void add_variable(struct Environment* env, struct Variable* var) { - if (env->num_vars >= MAX_VARIABLES) { - fprintf(stderr, "Error: Maximum number of variables reached.\n"); - return; - } - - // If variable exists, replace it - struct Variable* temp_var = find_variable(env, var->id); - if (temp_var != NULL) { - temp_var->value = var->value; - free(var); - return; - } - - // If not, add variable to environment - env->vars[env->num_vars] = var; - env->num_vars += 1; -} - -void delete_environment(struct Environment* env) { - for (int i = 0; i < env->num_vars; i++) { - free(env->vars[i]); - } - free(env); -} - -void check_num_nodes(struct Node* node, int num_children, char* error) { - if (node && node->num_children != num_children) { - fprintf(stderr, "%s%s%s", "Error, ", error, "\n"); - } -} - -struct Value* make_value(int type, long num, double dec, struct Node* expr) { - /* allocate space */ - struct Value* val = malloc(sizeof(struct Value)); - - /* set properties */ - val->type = type; - if (type == LONG || type == BOOLEAN) { - val->value.num = num; - } else if (type == DOUBLE){ // Assume DOUBLE - val->value.dec = dec; - } else { // Assume lambda expression - val->value.expr = expr; - } - - /* return new variable */ - return val; -} - -struct Value* make_long(long num) { - return make_value(LONG, num, 0, NULL); -} -struct Value* make_double(double dec) { - return make_value(DOUBLE, 0, dec, NULL); -} -struct Value* make_true() { - return make_value(BOOLEAN, 1, 0, NULL); -} -struct Value* make_false() { - return make_value(BOOLEAN, 0, 0, NULL); -} -struct Value* make_boolean(int x) { - return (x)? make_true() : make_false(); -} -struct Value* make_expression(struct Node* expr) { - return make_value(LAMBDA, 0, 0, expr); -} - -void delete_value(struct Value* val) { - free(val); -} - -long get_long(struct Value* val) { - return val->value.num; -} -double get_double(struct Value* val) { - return val->value.dec; -} -struct Node* get_expression(struct Value* val) { - return val->value.expr; -} - -void set_long(struct Value* val, long num) { - val->type = LONG; - val->value.num = num; -} -void set_double(struct Value* val, double dec) { - val->type = DOUBLE; - val->value.dec = dec; -} -void set_expression(struct Value* val, struct Node* expr) { - val->type = LAMBDA; - val->value.expr = expr; -} - -struct Value* add(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in add.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot add a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_long(get_long(x) + get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_double(get_long(x) + get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_double(get_double(x) + get_long(y)); - } else { // Both are DOUBLE - ans = make_double(get_double(x) + get_double(y)); - } - - return ans; -} - -struct Value* subtract(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in subtract.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot subtract a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_long(get_long(x) - get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_double(get_long(x) - get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_double(get_double(x) - get_long(y)); - } else { // Both are DOUBLE - ans = make_double(get_double(x) - get_double(y)); - } - - return ans; -} - -struct Value* division(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in divide.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot divide a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_long(get_long(x) / get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_double(get_long(x) / get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_double(get_double(x) / get_long(y)); - } else { // Both are DOUBLE - ans = make_double(get_double(x) / get_double(y)); - } - - return ans; -} - -struct Value* multiplication(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in multiply.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot multiply a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_long(get_long(x) * get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_double(get_long(x) * get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_double(get_double(x) * get_long(y)); - } else { // Both are DOUBLE - ans = make_double(get_double(x) * get_double(y)); - } - - return ans; -} - -struct Value* less(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in <.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) < get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) < get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) < get_long(y)); - } else { // Both are DOUBLE - ans = make_boolean(get_double(x) < get_double(y)); - } - - return ans; -} - -struct Value* greater(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in greater.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) > get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) > get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) > get_long(y)); - } else { // Both are DOUBLE - ans = make_boolean(get_double(x) > get_double(y)); - } - - return ans; -} - -struct Value* less_equal(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in <=.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) <= get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) <= get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) <= get_long(y)); - } else { // Both are DOUBLE - ans = make_boolean(get_double(x) <= get_double(y)); - } - - return ans; -} - -struct Value* greater_equal(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in >=.\n"); } - if (x->type == BOOLEAN || y->type == BOOLEAN) { fprintf(stderr, "Error, cannot numerically compare a boolean.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) >= get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) >= get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) >= get_long(y)); - } else { // Both are DOUBLE - ans = make_boolean(get_double(x) >= get_double(y)); - } - - return ans; -} - -struct Value* equals(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in ==.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) == get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) == get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) == get_long(y)); - } else if (x->type == DOUBLE && y->type == DOUBLE) { - ans = make_boolean(get_double(x) == get_double(y)); - } else if (x->type == BOOLEAN && y->type == BOOLEAN) { - ans = make_boolean(get_long(x) == get_long(y)); - } else { // Type is a mix between boolean and another type - fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); - } - - return ans; -} - -struct Value* not_equals(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in !=.\n"); } - - struct Value* ans; - - // Destruct all four cases - if (x->type == LONG && y->type == LONG) { - ans = make_boolean(get_long(x) != get_long(y)); - } else if (x->type == LONG && y->type == DOUBLE) { - ans = make_boolean(get_long(x) != get_double(y)); - } else if (x->type == DOUBLE && y->type == LONG) { - ans = make_boolean(get_double(x) != get_long(y)); - } else if (x->type == DOUBLE && y->type == DOUBLE) { - ans = make_boolean(get_double(x) != get_double(y)); - } else if (x->type == BOOLEAN && y->type == BOOLEAN) { - ans = make_boolean(get_long(x) != get_long(y)); - } else { // Type is a mix between boolean and another type - fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); - } - - return ans; -} - -struct Value* and(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in &&.\n"); } - if (x->type != BOOLEAN || y->type != BOOLEAN) { fprintf(stderr, "Error, cannot use and AND operation with a non-boolean.\n"); } - - return make_boolean(get_long(x) && get_long(y)); -} - -struct Value* or(struct Value* x, struct Value* y) { - if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in ||.\n"); } - if (x->type != BOOLEAN || y->type != BOOLEAN) { fprintf(stderr, "Error, cannot use and OR operation with a non-boolean.\n"); } - - return make_boolean(get_long(x) || get_long(y)); -} - -struct Value* not(struct Value* x) { - if (!x) { fprintf(stderr, "Error, uninitialized values being used in !.\n"); } - if (x->type != BOOLEAN) { fprintf(stderr, "Error, cannot NOT a non-boolean.\n"); } - - return make_boolean(!get_long(x)); -} - -struct Value* eval_expression(struct Node* node, struct Environment* env) { - /* base case */ - if(!node) { - fprintf(stderr, "Error: No tree structure to evaluate\n"); - return 0; - } - - // Needed if we are going to take input from the user - double temp; - struct Variable* var = NULL; - struct Environment* local_env = NULL; - struct Node* tempNode = NULL; - struct Value* tempVal = NULL; - - // Evaluate subexpressions if existent and node is not a lambda expression - struct Value* val1 = NULL; - struct Value* val2 = NULL; - struct Value* val3 = NULL; - if (node->num_children > 0 && node->type != LAMBDA) { - val1 = eval_expression(node->children[0], env); - if (node->num_children > 1) { - val2 = eval_expression(node->children[1], env); - if (node->num_children > 2) { - val3 = eval_expression(node->children[2], env); - // delete_value(val3); // No code below uses val3 for now... - } - } - } - - switch(node->type) { - case LAMBDA: return make_expression(node); break; - case CALLFUNC: - check_num_nodes(node, 2, "cannot have more than two nodes for a function call."); - tempNode = get_expression(get_value(find_variable(env, node->children[0]->id))); - local_env = create_environment(); - add_variable(local_env, - make_variable(tempNode->children[0]->id, // Get the name of the variable needed for the lambda expression - eval_expression(node->children[1], env))); - tempVal = eval_expression(tempNode->children[1], local_env); - delete_environment(local_env); - return tempVal; - break; - case PLUS: - check_num_nodes(node, 2, "cannot add more than two expressions."); - return add(val1, val2); - // return val1 + val2; - break; - //---------- - case MINUS: - check_num_nodes(node, 2, "cannot subtract more than two expressions."); - return subtract(val1, val2); - // return val1 - val2; - break; - //---------- - case DIVIDE: - check_num_nodes(node, 2, "cannot divide more than two expressions."); - return division(val1, val2); - // return val1 / val2; - break; - //---------- - case TIMES: - check_num_nodes(node, 2, "cannot multiply more than two expressions."); - return multiplication(val1, val2); - // return val1 * val2; - break; - //---------- - case LESS: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } - return less(val1, val2); - // return val1 < val2; - break; - //---------- - case GREATER: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - return greater(val1, val2); - // return val1 > val2; - break; - //---------- - case LESSEQ: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - return less_equal(val1, val2); - // return val1 <= val2; - break; - //---------- - case GREATEREQ: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - return greater_equal(val1, val2); - // return val1 >= val2; - break; - //---------- - case EQUALS: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - return equals(val1, val2); - // return val1 == val2; - break; - //---------- - case NEQUALS: - check_num_nodes(node, 2, "cannot compare more than two expressions."); - return not_equals(val1, val2); - // return val1 != val2; - break; - //---------- - case AND: - check_num_nodes(node, 2, "cannot perform logical operators on more than two expressions."); - return and(val1, val2); - // return val1 && val2; - break; - //---------- - case OR: - check_num_nodes(node, 2, "cannot perform logical operators on more than two expressions."); - return or(val1, val2); - // return val1 || val2; - break; - //---------- - case NOT: - check_num_nodes(node, 1, "cannot negate more than one expressions."); - return not(val1); - // return !val1; - break; - //---------- - case INPUT: // We're only going to support reading in doubles - // Look into deleting possible values...? - scanf("%lf", &temp); - return make_double(temp); - break; - //---------- - case IDENTIFIER: - var = find_variable(env, node->id); - if (var == NULL) { - fprintf(stderr, "Error: Symbol %s not found.\n", node->id); - return 0; - } - return get_value(var); - break; - //---------- - case VALUE: - return node->value; - break; - //---------- - default: - fprintf(stderr,"Error, %d not a valid expression type.\n", node->type); - return 0; - } - -} - - -void eval_statement(struct Node* node, struct Environment* env) { - /* base case */ - if(!node) { - fprintf(stderr, "Error: No tree structure to evaluate\n"); - return; - } - - struct Value* tempVal; - - switch(node->type) { - case ASSIGN: - check_num_nodes(node, 2, "cannot make an assignment without an identifier and a value."); - add_variable(env, - make_variable(node->children[0]->id, - eval_expression(node->children[1], env))); - break; - //------------ - case IF: - if (node->num_children != 2 && node->num_children != 3) { - fprintf(stderr, "Error: The format of an if-statement is if expression statement with an optional else.\n"); - } - tempVal = eval_expression(node->children[0], env); - if (tempVal->type == BOOLEAN) { - if (get_long(tempVal)) { - eval_statement(node->children[1], env); - } else if (node->num_children == 3) { - eval_statement(node->children[2], env); - } - } else { - fprintf(stderr, "Error, a non-boolean was in the condition of an if statement.\n"); - } - break; - //------------ - case WHILE: - check_num_nodes(node, 2, "the format of a while statement is: while expression statement(s)"); - tempVal = eval_expression(node->children[0], env); - if (tempVal->type == BOOLEAN) { - while (get_long(tempVal)) { - eval_statement(node->children[1], env); - tempVal = eval_expression(node->children[0], env); - } - } else { - fprintf(stderr, "Error, a non-boolean was in the condition of the while loop.\n"); - } - - break; - //------------ - case PRINT: - check_num_nodes(node, 1, "can only print out one expression at a time."); - tempVal = eval_expression(node->children[0], env); - if (tempVal->type == BOOLEAN) { - if (get_long(tempVal)) { - printf("true\n"); - } else { - printf("false\n"); - } - } else if (tempVal->type == LONG) { - printf("%li\n", get_long(tempVal)); - } else if (tempVal ->type == DOUBLE) { - printf("%lf\n", get_double(tempVal)); - } else { // Assume lambda expression - printf("\n"); - } - break; - //------------ - case STATEMENT: // Can have a maximum of two children statement nodes - if (node->num_children > 0) { - eval_statement(node->children[0], env); - } - if (node->num_children > 1) { - eval_statement(node->children[1], env); - } - break; - //------------ - default: - printf("Error, %d not a valid statement type.\n", node->type); - return; - } -} diff --git a/src/lexer.l b/src/parser/lexer.l similarity index 96% rename from src/lexer.l rename to src/parser/lexer.l index 33026f8..d6ba757 100644 --- a/src/lexer.l +++ b/src/parser/lexer.l @@ -1,7 +1,8 @@ %{ #include #include -#include "node.h" +#include "../operations/node.h" +#include "../variables/value.h" #include "parser.tab.h" /* Keep track of line numbers for error reporting */ diff --git a/src/parser/parser.h b/src/parser/parser.h new file mode 100644 index 0000000..aaa1b53 --- /dev/null +++ b/src/parser/parser.h @@ -0,0 +1,8 @@ +#ifndef PARSER_H +#define PARSER_H + +int yywrap( ); +int yylex( ); +void yyerror(const char* str); + +#endif diff --git a/src/parser/parser.y b/src/parser/parser.y new file mode 100644 index 0000000..e6fcbff --- /dev/null +++ b/src/parser/parser.y @@ -0,0 +1,160 @@ +%{ +#include +#include +#include "parser.h" +#include "../operations/node.h" +#include "../constants.h" + +%} + +/* declare type possibilities of symbols */ +%union { + struct Node* value; +} + +/* declare tokens (default is typeless) */ +%token IDENTIFIER +%token VALUE +%token PLUS +%token MINUS +%token DIVIDE +%token TIMES +%token LESS +%token GREATER +%token LESSEQ +%token GREATEREQ +%token EQUALS +%token NEQUALS +%token AND +%token OR +%token NOT +%token SEMICOLON +%token ASSIGN +%token OPENPAREM +%token ENDPAREM +%token BEGINTOK +%token END +%token IF +%token THEN +%token ELSE +%token WHILE +%token DO +%token PRINT +%token INPUT +%token COMMENT +%token WHITESPACE +%token DONE +%token LAMBDA +%token COLON + +/* declare non-terminals */ +%type program statement assignment if-statement if-else-statement while print statements substatements callfunc exprlambda expression subexpression term subterm factor atom identvalue ident + +/* give us more detailed errors */ +%error-verbose + +%% +program: substatements {result = $1; return 0;} + | "" {return 0;} + +statement: assignment { $$ = $1; } + | if-statement { $$ = $1; } + | if-else-statement { $$ = $1; } + | while { $$ = $1; } + | print { $$ = $1; } + | statements { $$ = $1; } + +assignment: ident ASSIGN exprlambda SEMICOLON { + $$ = make_node(ASSIGN, NULL, ""); + attach_node($$, $1); + attach_node($$, $3); +} + +if-statement: IF expression THEN statement { + $$ = make_node(IF, NULL, ""); + attach_node($$, $2); + attach_node($$, $4); +} + +if-else-statement: IF expression THEN statement ELSE statement { + $$ = make_node(IF, NULL, ""); + attach_node($$, $2); + attach_node($$, $4); + attach_node($$, $6); +} + +while: WHILE expression DO statement { + $$ = make_node(WHILE, NULL, ""); + attach_node($$, $2); + attach_node($$, $4); +} + +print: PRINT exprlambda SEMICOLON { + $$ = make_node(PRINT, NULL, ""); + attach_node($$, $2); +} + + +statements: BEGINTOK substatements END { $$ = $2; } + | BEGINTOK END {} + +substatements: statement substatements {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); attach_node($$, $2); } + | statement {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); } + +exprlambda: LAMBDA ident COLON expression { + // Only supports one argument functions for now + $$ = make_node(LAMBDA, NULL, ""); + attach_node($$, $2); + attach_node($$, $4); } + | expression { $$ = $1; } + +expression: expression OR subexpression { $$ = make_node(OR, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | expression AND subexpression { $$ = make_node(AND, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression { $$ = $1; } + +subexpression: subexpression LESS term { $$ = make_node(LESS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression LESSEQ term { $$ = make_node(LESSEQ, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression GREATER term { $$ = make_node(GREATER, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression GREATEREQ term { $$ = make_node(GREATEREQ, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression EQUALS term { $$ = make_node(EQUALS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression NEQUALS term { $$ = make_node(NEQUALS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | term { $$ = $1; } + +term : term PLUS subterm { $$ = make_node(PLUS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | term MINUS subterm { $$ = make_node(MINUS, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subterm { $$ = $1; } + +subterm: subterm TIMES factor { $$ = make_node(TIMES, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | subterm DIVIDE factor { $$ = make_node(DIVIDE, NULL, ""); attach_node($$, $1); attach_node($$, $3);} + | factor { $$ = $1; } + +factor : MINUS factor { $$ = make_node(MINUS, NULL, ""); attach_node($$, $2); } + | NOT factor { $$ = make_node(NOT, NULL, ""); attach_node($$, $2); } + | atom { $$ = $1; } + +callfunc: ident OPENPAREM expression ENDPAREM { $$ = make_node(CALLFUNC, NULL, ""); attach_node($$, $1); attach_node($$, $3); } + +atom: OPENPAREM expression ENDPAREM { $$ = $2; } + | callfunc { $$ = $1; } + | identvalue { $$ = $1; } + +ident: IDENTIFIER { $$ = $1; } + +identvalue: ident { $$ = $1; } + | VALUE { $$ = $1; } + | INPUT { $$ = make_node(INPUT, NULL , ""); } + + + + +%% + + +int yywrap( ) { + return 1; +} + +void yyerror(const char* str) { + fprintf(stderr, "Compiler error on line %d: '%s'.\n", linenum, str); + exit(1); +} diff --git a/src/sloth.h b/src/sloth.h new file mode 100644 index 0000000..f083197 --- /dev/null +++ b/src/sloth.h @@ -0,0 +1,12 @@ +#ifndef SLOTH_H +#define SLOTH_H + +#include "constants.h" +#include "operations/node.h" +#include "variables/value.h" +#include "variables/variable.h" +#include "variables/environment.h" +#include "parser/parser.h" +#include "parser/parser.tab.h" + +#endif diff --git a/src/variables/environment.c b/src/variables/environment.c new file mode 100644 index 0000000..db0411e --- /dev/null +++ b/src/variables/environment.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include "environment.h" +#include "variable.h" + +struct Environment* create_environment(void) { + struct Environment* env = malloc(sizeof(struct Environment)); + env->num_vars = 0; + for(int i = 0; i < MAX_VARIABLES; i++) { + env->vars[i] = NULL; + } + return env; +} + +struct Variable* find_variable(struct Environment* env, char* id) { + for (int i = 0; i < env->num_vars; i++) { + if (strcmp(env->vars[i]->id, id) == 0) { + return env->vars[i]; + } + } + return NULL; +} + +void add_variable(struct Environment* env, struct Variable* var) { + if (env->num_vars >= MAX_VARIABLES) { + fprintf(stderr, "Error: Maximum number of variables reached.\n"); + return; + } + + // If variable exists, replace it + struct Variable* temp_var = find_variable(env, var->id); + if (temp_var != NULL) { + temp_var->value = var->value; + free(var); + return; + } + + // If not, add variable to environment + env->vars[env->num_vars] = var; + env->num_vars += 1; +} + +void delete_environment(struct Environment* env) { + for (int i = 0; i < env->num_vars; i++) { + free(env->vars[i]); + } + free(env); +} diff --git a/src/variables/environment.h b/src/variables/environment.h new file mode 100644 index 0000000..2408410 --- /dev/null +++ b/src/variables/environment.h @@ -0,0 +1,17 @@ +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +#define MAX_VARIABLES 200 + +struct Environment { + int num_vars; + struct Variable* vars[MAX_VARIABLES]; +}; + +// Variable Lookup Functions +struct Environment* create_environment(void); +void delete_environment(struct Environment* env); +struct Variable* find_variable(struct Environment* env, char* id); +void add_variable(struct Environment* env, struct Variable* var); + +#endif diff --git a/src/variables/value.c b/src/variables/value.c new file mode 100644 index 0000000..78661da --- /dev/null +++ b/src/variables/value.c @@ -0,0 +1,68 @@ +#include +#include "value.h" +#include "../parser/parser.tab.h" + + +struct Value* make_value(int type, long num, double dec, struct Node* expr) { + /* allocate space */ + struct Value* val = malloc(sizeof(struct Value)); + + /* set properties */ + val->type = type; + if (type == LONG || type == BOOLEAN) { + val->value.num = num; + } else if (type == DOUBLE){ // Assume DOUBLE + val->value.dec = dec; + } else { // Assume lambda expression + val->value.expr = expr; + } + + /* return new variable */ + return val; +} + +struct Value* make_long(long num) { + return make_value(LONG, num, 0, NULL); +} +struct Value* make_double(double dec) { + return make_value(DOUBLE, 0, dec, NULL); +} +struct Value* make_true() { + return make_value(BOOLEAN, 1, 0, NULL); +} +struct Value* make_false() { + return make_value(BOOLEAN, 0, 0, NULL); +} +struct Value* make_boolean(int x) { + return (x)? make_true() : make_false(); +} +struct Value* make_expression(struct Node* expr) { + return make_value(LAMBDA, 0, 0, expr); +} + +void delete_value(struct Value* val) { + free(val); +} + +long get_long(struct Value* val) { + return val->value.num; +} +double get_double(struct Value* val) { + return val->value.dec; +} +struct Node* get_expression(struct Value* val) { + return val->value.expr; +} + +void set_long(struct Value* val, long num) { + val->type = LONG; + val->value.num = num; +} +void set_double(struct Value* val, double dec) { + val->type = DOUBLE; + val->value.dec = dec; +} +void set_expression(struct Value* val, struct Node* expr) { + val->type = LAMBDA; + val->value.expr = expr; +} diff --git a/src/variables/value.h b/src/variables/value.h new file mode 100644 index 0000000..082b5b7 --- /dev/null +++ b/src/variables/value.h @@ -0,0 +1,39 @@ +#ifndef VALUE_H +#define VALUE_H + +enum TypeTag { DOUBLE, LONG, BOOLEAN }; + +typedef union typeval { + long num; + double dec; + struct Node* expr; +} TypeVal; + +struct Value { + enum TypeTag type; + TypeVal value; +}; + +// Constructors +struct Value* make_value(int type, long num, double dec, struct Node* expr); +struct Value* make_long(long num); +struct Value* make_double(double dec); +struct Value* make_true(); +struct Value* make_false(); +struct Value* make_boolean(int x); +struct Value* make_expression(struct Node* expr); + +// Destructor +void delete_value(struct Value* val); + +// Getters +long get_long(struct Value* val); +double get_double(struct Value* val); +struct Node* get_expression(struct Value* val); + +// Setters +void set_long(struct Value* val, long num); +void set_double(struct Value* val, double dec); +void set_expression(struct Value* val, struct Node* node); + +#endif diff --git a/src/variables/variable.c b/src/variables/variable.c new file mode 100644 index 0000000..2ab5275 --- /dev/null +++ b/src/variables/variable.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include "variable.h" + +/* creates a new variable and returns it */ +struct Variable* make_variable(char* id, struct Value* value) { + /* allocate space */ + struct Variable* var = malloc(sizeof(struct Variable)); + + /* set properties */ + strcpy(var->id, id); + var->value = value; + + /* return new variable */ + return var; +} + +void set_value(struct Variable* var, struct Value* value) { + if (!var) { fprintf(stderr, "Error: Invalid Variable\n"); return; } + var->value = value; +} + +struct Value* get_value(struct Variable* var) { + if (!var) { fprintf(stderr, "Error: Invalid Variable\n"); return 0; } + return var->value; +} \ No newline at end of file diff --git a/src/variables/variable.h b/src/variables/variable.h new file mode 100644 index 0000000..766d571 --- /dev/null +++ b/src/variables/variable.h @@ -0,0 +1,22 @@ +#ifndef VARIABLE_H +#define VARIABLE_H + +#include "../operations/node.h" + +struct Variable { + char id[ID_SIZE]; + struct Value* value; +}; + +// Variable Functions +struct Variable* make_variable(char* id, struct Value* value); +void set_value(struct Variable* var, struct Value* value); +struct Value* get_value(struct Variable* var); +struct Value* make_long(long num); +struct Value* make_double(double dec); +struct Value* make_true(); +struct Value* make_false(); +struct Value* make_boolean(int x); +struct Value* make_expression(struct Node* expr); + +#endif