diff --git a/.gitignore b/.gitignore index a557fb9..acfc5b3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,8 @@ src/variables/value.o src/operations/node.o src/operations/operators.o src/shell.o +src/string.o sloth vgcore* .vscode -.vscode/* \ No newline at end of file +.vscode/* diff --git a/Makefile b/Makefile index 0b948a7..7c69a73 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -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 src/shell.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 src/shell.o -ledit -o sloth +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 src/string.o src/shell.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 src/string.o src/shell.o -ledit -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 @@ -22,5 +22,7 @@ src/operations/node.o: src/operations/node.h src/operations/node.c gcc -c src/operations/node.c -o src/operations/node.o src/shell.o: src/shell.h src/shell.c gcc -c src/shell.c -o src/shell.o +src/string.o: src/string.h src/string.c + gcc -c src/string.c -o src/string.o clean: 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 src/shell.o sloth diff --git a/src/main.c b/src/main.c index 20eda67..1f7e5f1 100644 --- a/src/main.c +++ b/src/main.c @@ -34,7 +34,7 @@ void interpret_file(char* fileName) { stdin = orig_stdin; // Interpret the AST - // print_tree(result, 0); + // print_tree(result, 0); // For debugging struct Environment* env = create_environment(); eval_statement(result, env); delete_environment(env); diff --git a/src/operations/node.c b/src/operations/node.c index 166f4ab..01c71e9 100644 --- a/src/operations/node.c +++ b/src/operations/node.c @@ -80,17 +80,9 @@ void print_tree(struct Node* node, int tabs) { 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)); - } + printf("VALUE: "); + print_value(node->value); + printf("\n"); break; default: printf("Error, %d not a valid node type.\n", node->type); @@ -311,19 +303,8 @@ void eval_statement(struct Node* node, struct Environment* env) { 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"); - } + print_value(tempVal); + printf("\n"); break; //------------ case STATEMENT: // Can have a maximum of two children statement nodes diff --git a/src/operations/operators.c b/src/operations/operators.c index abe5fac..f07ac7c 100644 --- a/src/operations/operators.c +++ b/src/operations/operators.c @@ -1,11 +1,15 @@ #include #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"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot add a string with another data type.\n"); + } struct Value* ans; @@ -16,6 +20,8 @@ struct Value* add(struct Value* x, struct Value* y) { 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 if (x->type == STRING && y->type == STRING) { + ans = make_string(strcat(get_string(x), get_string(y))); } else { // Both are DOUBLE ans = make_double(get_double(x) + get_double(y)); } @@ -26,6 +32,7 @@ struct Value* add(struct Value* x, struct Value* y) { 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"); } + if (x->type == STRING || y->type == STRING) { fprintf(stderr, "Error, cannot subtract a string.\n"); } struct Value* ans; @@ -46,6 +53,7 @@ struct Value* subtract(struct Value* x, struct Value* y) { 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"); } + if (x->type == STRING || y->type == STRING) { fprintf(stderr, "Error, cannot division a string.\n"); } struct Value* ans; @@ -66,6 +74,7 @@ struct Value* division(struct Value* x, struct Value* y) { 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"); } + if (x->type == STRING || y->type == STRING) { fprintf(stderr, "Error, cannot multiply a string.\n"); } struct Value* ans; @@ -86,6 +95,9 @@ struct Value* multiplication(struct Value* x, struct Value* y) { 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"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -96,6 +108,8 @@ struct Value* less(struct Value* x, struct Value* y) { 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 == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) < 0); } else { // Both are DOUBLE ans = make_boolean(get_double(x) < get_double(y)); } @@ -106,6 +120,9 @@ struct Value* less(struct Value* x, struct Value* y) { 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"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -116,6 +133,8 @@ struct Value* greater(struct Value* x, struct Value* y) { 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 == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) > 0); } else { // Both are DOUBLE ans = make_boolean(get_double(x) > get_double(y)); } @@ -126,6 +145,9 @@ struct Value* greater(struct Value* x, struct Value* y) { 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"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -136,6 +158,8 @@ struct Value* less_equal(struct Value* x, struct Value* y) { 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 == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) <= 0); } else { // Both are DOUBLE ans = make_boolean(get_double(x) <= get_double(y)); } @@ -146,6 +170,9 @@ struct Value* less_equal(struct Value* x, struct Value* y) { 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"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -156,6 +183,8 @@ struct Value* greater_equal(struct Value* x, struct Value* y) { 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 == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) >= 0); } else { // Both are DOUBLE ans = make_boolean(get_double(x) >= get_double(y)); } @@ -165,6 +194,9 @@ struct Value* greater_equal(struct Value* x, struct Value* y) { struct Value* equals(struct Value* x, struct Value* y) { if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in ==.\n"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -179,6 +211,8 @@ struct Value* equals(struct Value* x, struct Value* y) { 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 if (x->type == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) == 0); } else { // Type is a mix between boolean and another type fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); } @@ -188,6 +222,9 @@ struct Value* equals(struct Value* x, struct Value* y) { struct Value* not_equals(struct Value* x, struct Value* y) { if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in !=.\n"); } + if ((x->type == STRING || y->type == STRING) && (x->type != STRING || y->type != STRING)) { + fprintf(stderr, "Error, cannot compare a string with another data type.\n"); + } struct Value* ans; @@ -202,6 +239,8 @@ struct Value* not_equals(struct Value* x, struct Value* y) { 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 if (x->type == STRING && y->type == STRING) { + ans = make_boolean(strcmp(get_string(x), get_string(y)) != 0); } else { // Type is a mix between boolean and another type fprintf(stderr, "Error, cannot compare a boolean with another type.\n"); } @@ -212,6 +251,7 @@ struct Value* not_equals(struct Value* x, struct Value* y) { 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"); } + if (x->type == STRING || y->type == STRING) { fprintf(stderr, "Error, cannot AND a string.\n"); } return make_boolean(get_long(x) && get_long(y)); } @@ -219,6 +259,7 @@ struct Value* and(struct Value* x, struct Value* 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"); } + if (x->type == STRING || y->type == STRING) { fprintf(stderr, "Error, cannot OR a string.\n"); } return make_boolean(get_long(x) || get_long(y)); } @@ -226,6 +267,7 @@ struct Value* or(struct Value* x, struct Value* 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"); } + if (x->type == STRING) { fprintf(stderr, "Error, cannot negate a string.\n"); } return make_boolean(!get_long(x)); } diff --git a/src/parser/lexer.l b/src/parser/lexer.l index d6ba757..b5126b9 100644 --- a/src/parser/lexer.l +++ b/src/parser/lexer.l @@ -4,6 +4,7 @@ #include "../operations/node.h" #include "../variables/value.h" #include "parser.tab.h" +#include "../string.h" /* Keep track of line numbers for error reporting */ int linenum = 0; @@ -44,6 +45,7 @@ DIGIT [0-9] ":" {return COLON;} "true" {yylval.value = make_node(VALUE, make_true(), ""); return VALUE;} "false" {yylval.value = make_node(VALUE, make_false(), ""); return VALUE;} +\".*\" {yylval.value = make_node(VALUE, make_string(substring(yytext, 1, strlen(yytext) - 1)), ""); return VALUE; } {DIGIT} {yylval.value = make_node(VALUE, make_long(atoi(yytext)), ""); return VALUE;} {DIGIT}*"."?{DIGIT}+ {yylval.value = make_node(VALUE, make_double(atof(yytext)), ""); return VALUE;} [_a-zA-Z][_a-zA-Z0-9]* {yylval.value = make_node(IDENTIFIER, NULL, strdup(yytext)); return IDENTIFIER;} diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..5f55218 --- /dev/null +++ b/src/string.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include "string.h" + +char* substring(char* str, int start, int end) { +// Add conditions that substring is valid, probably using strlen + int stringLength = strlen(str); + if (start >= stringLength || end > stringLength) { fprintf(stderr, "Requesting substring outside of valid range.\n"); return NULL; } + + char* substr; + int c; + int length = end - start; + substr = malloc(length + 1); + + if (substr == NULL) { + fprintf(stderr, "Unable to allocate memory for substring.\n"); + exit(1); + } + + for (c = 0; c < length; c++) { + substr[c] = str[start + c]; + } + + substr[c] = '\0'; + + return substr; +} diff --git a/src/string.h b/src/string.h new file mode 100644 index 0000000..a284bfd --- /dev/null +++ b/src/string.h @@ -0,0 +1,6 @@ +#ifndef STRING_H +#define STRING_H + +char* substring(char* str, int start, int end); + +#endif diff --git a/src/variables/value.c b/src/variables/value.c index 78661da..383ff7e 100644 --- a/src/variables/value.c +++ b/src/variables/value.c @@ -1,9 +1,10 @@ +#include #include #include "value.h" #include "../parser/parser.tab.h" -struct Value* make_value(int type, long num, double dec, struct Node* expr) { +struct Value* make_value(int type, long num, double dec, struct Node* expr, char* str) { /* allocate space */ struct Value* val = malloc(sizeof(struct Value)); @@ -13,6 +14,8 @@ struct Value* make_value(int type, long num, double dec, struct Node* expr) { val->value.num = num; } else if (type == DOUBLE){ // Assume DOUBLE val->value.dec = dec; + } else if (type == STRING) { + val->value.str = str; } else { // Assume lambda expression val->value.expr = expr; } @@ -22,22 +25,25 @@ struct Value* make_value(int type, long num, double dec, struct Node* expr) { } struct Value* make_long(long num) { - return make_value(LONG, num, 0, NULL); + return make_value(LONG, num, 0, NULL, NULL); } struct Value* make_double(double dec) { - return make_value(DOUBLE, 0, dec, NULL); + return make_value(DOUBLE, 0, dec, NULL, NULL); } struct Value* make_true() { - return make_value(BOOLEAN, 1, 0, NULL); + return make_value(BOOLEAN, 1, 0, NULL, NULL); } struct Value* make_false() { - return make_value(BOOLEAN, 0, 0, NULL); + return make_value(BOOLEAN, 0, 0, NULL, 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); + return make_value(LAMBDA, 0, 0, expr, NULL); +} +struct Value* make_string(char* str) { + return make_value(STRING, 0, 0, NULL, str); } void delete_value(struct Value* val) { @@ -53,6 +59,9 @@ double get_double(struct Value* val) { struct Node* get_expression(struct Value* val) { return val->value.expr; } +char* get_string(struct Value* val) { + return val->value.str; +} void set_long(struct Value* val, long num) { val->type = LONG; @@ -66,3 +75,25 @@ void set_expression(struct Value* val, struct Node* expr) { val->type = LAMBDA; val->value.expr = expr; } +void set_sring(struct Value* val, char* str) { + val->type = STRING; + val->value.str = str; +} + +void print_value(struct Value* val) { + if (val->type == BOOLEAN) { + if (get_long(val)) { + printf("true"); + } else { + printf("false"); + } + } else if (val->type == LONG) { + printf("%li", get_long(val)); + } else if (val->type == STRING) { + printf("%s", get_string(val)); + } else if (val->type == DOUBLE) { + printf("%lf", get_double(val)); + } else { // Assume lambda expression + printf(""); + } +} diff --git a/src/variables/value.h b/src/variables/value.h index 082b5b7..eb63cbb 100644 --- a/src/variables/value.h +++ b/src/variables/value.h @@ -1,12 +1,13 @@ #ifndef VALUE_H #define VALUE_H -enum TypeTag { DOUBLE, LONG, BOOLEAN }; +enum TypeTag { DOUBLE, LONG, BOOLEAN, STRING }; typedef union typeval { long num; double dec; struct Node* expr; + char* str; } TypeVal; struct Value { @@ -15,13 +16,14 @@ struct Value { }; // Constructors -struct Value* make_value(int type, long num, double dec, struct Node* expr); +struct Value* make_value(int type, long num, double dec, struct Node* expr, char* str); 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 Value* make_string(char* str); // Destructor void delete_value(struct Value* val); @@ -30,10 +32,14 @@ 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); +char* get_string(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); +void set_string(struct Value* val, char* str); + +void print_value(struct Value* val); #endif