Archived
1
0
Fork 0

Added string support to SLOTH (comparisons, string concatenation, etc)

Refactored print_value code
This commit is contained in:
Brandon Rozek 2018-09-26 15:43:08 -04:00
parent 1186419184
commit 28e2352eac
10 changed files with 135 additions and 36 deletions

3
.gitignore vendored
View file

@ -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/*
.vscode/*

View file

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

View file

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

View file

@ -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("<LambdaExpression>\n");
}
print_value(tempVal);
printf("\n");
break;
//------------
case STATEMENT: // Can have a maximum of two children statement nodes

View file

@ -1,11 +1,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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));
}

View file

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

28
src/string.c Normal file
View file

@ -0,0 +1,28 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#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;
}

6
src/string.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef STRING_H
#define STRING_H
char* substring(char* str, int start, int end);
#endif

View file

@ -1,9 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#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("<LambdaExpression>");
}
}

View file

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