commit fbfaf0ddb87cf53051bf5c42cc226c1b4a05ba7d Author: Brandon Rozek Date: Tue Sep 18 22:50:15 2018 -0400 Added beginning code for SLOTH diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97e2d49 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +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 +clean: + rm src/lex.yy.c src/parser.tab.c src/parser.tab.h sloth diff --git a/examples/acid.sl b/examples/acid.sl new file mode 100644 index 0000000..ec12288 --- /dev/null +++ b/examples/acid.sl @@ -0,0 +1,38 @@ +% a test of most of the features of the langauge the program itself +% is totally meaningless, but should print out "42.000000" at the end. +% if you get 42, there's a good chance you did everything right! + +real_87_varNAME := 2.0 * (12.0 - 6.0) + 4.5; +X2222 := (real_87_varNAME - 1/2) / 4.0; +if 3 < 4 && 5 != 6 then + _a := 5; +else + _a := 17; +if 3 >= 3.01 || 5 == 7 then + X2222 := X2222 + 10; +if _a > X2222 then NUM := X2222 * _a; +i := 70; +while i > 0 do begin + NUM := NUM + 1; + i := i - 7; +end +if !!!(i != 0) then NUM := NUM + 2; +while NUM < 10 do NUM := NUM + 1; +if NUM > 20 then + if NUM > 30 then + if NUM > 40 then + NUM := NUM - 10; + else + NUM := NUM + 5; + else begin + NUM := real_87_varNAME - NUM; + end +NUM := NUM - .5; +begin + a := 0-2; + a := a + 3; +NUM := NUM + a; +end +print NUM + (6 - 1 - 1) + .5; + + diff --git a/examples/area.sl b/examples/area.sl new file mode 100644 index 0000000..7d61095 --- /dev/null +++ b/examples/area.sl @@ -0,0 +1,12 @@ +% program to calculate area of a circle +PI := 3.1416; + +% get input +radius := input; + +% calculate area +area := PI * radius * radius; + +% output +print area; + diff --git a/examples/fact.sl b/examples/fact.sl new file mode 100644 index 0000000..105b61f --- /dev/null +++ b/examples/fact.sl @@ -0,0 +1,15 @@ +% program to calculate factorials + +% get input +x := input; +fact := 1; + +% a loop! +while x > 1.0 do begin + fact := fact * x; + x := x - 1; +end + +% output +print fact; + diff --git a/examples/fibs.sl b/examples/fibs.sl new file mode 100644 index 0000000..c52ee1d --- /dev/null +++ b/examples/fibs.sl @@ -0,0 +1,21 @@ +% program to generate list of the first N fibs + +N := input; +a := 0; +b := 1; +f := 1; + +print f; % print out the first one +while N > 1 do +begin + % update vars + f := a + b; + a := b; + b := f; + N := N - 1; + print f; % print the next fib +end + +% all done! + + diff --git a/examples/minmax.sl b/examples/minmax.sl new file mode 100644 index 0000000..0783727 --- /dev/null +++ b/examples/minmax.sl @@ -0,0 +1,27 @@ +% find the smallest and largest of a set of numbers + +% get the amount of numbers to input +N := input; +min := 99999999; +max := 0 - 99999999; + +while N > 0 do begin + % get the next number + x := input; + + % check if it's the min + if x < min then + min := x; % set it + + % check if it's the max + if x > max then + max := x; % set it + + % keep counting + N := N - 1; +end + +% print the min and max +print min; +print max; + diff --git a/examples/simple.sl b/examples/simple.sl new file mode 100644 index 0000000..6ce3cc3 --- /dev/null +++ b/examples/simple.sl @@ -0,0 +1,3 @@ +% very simple program +print 1 + 1; + diff --git a/extra/token_spitter.l b/extra/token_spitter.l new file mode 100644 index 0000000..76b7a0b --- /dev/null +++ b/extra/token_spitter.l @@ -0,0 +1,93 @@ +%{ +#include +#define IDENTIFIER 100 +#define VALUE 101 +#define PLUS 102 +#define MINUS 103 +#define DIVIDE 104 +#define TIMES 105 +#define LESS 106 +#define GREATER 107 +#define LESSEQ 108 +#define GREATEREQ 109 +#define EQUALS 110 +#define NEQUALS 111 +#define AND 112 +#define OR 113 +#define NOT 114 +#define SEMICOLON 115 +#define ASSIGN 116 +#define OPENPAREM 117 +#define ENDPAREM 118 +#define BEGINTOK 119 +#define END 120 +#define IF 121 +#define THEN 122 +#define ELSE 123 +#define WHILE 124 +#define DO 125 +#define PRINT 126 +#define INPUT 127 +#define COMMENT 128 +#define ERROR 129 +#define WHITESPACE 130 +%} +ALPHA [a-zA-Z] +DIGIT [0-9] +%option noyywrap +%% +"+" {return PLUS; } +"-" {return MINUS;} +"/" {return DIVIDE;} +"*" {return TIMES;} +"!" {return NOT;} +"(" {return OPENPAREM;} +")" {return ENDPAREM;} +";" {return SEMICOLON;} +%.*\n {return COMMENT;} +"<" {return LESS;} +">" {return GREATER;} +"<=" {return LESSEQ;} +">=" {return GREATEREQ;} +"==" {return EQUALS;} +"!=" {return NEQUALS;} +"&&" {return AND;} +"||" {return OR;} +":=" {return ASSIGN;} +"if" {return IF;} +"do" {return DO;} +"end" {return END;} +"then" {return THEN;} +"else" {return ELSE;} +"begin" {return BEGINTOK;} +"while" {return WHILE;} +"print" {return PRINT;} +"input" {return INPUT;} +{DIGIT}*"."?{DIGIT}+ {return VALUE;} +[_a-zA-Z][_a-zA-Z0-9]* {return IDENTIFIER;} +[ \n\t\r]+ {return WHITESPACE;} +. {printf("Syntax Error! Received: %s\n", yytext); return ERROR;} + +%% +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); + } + stdin = fopen(argv[1], "r"); + int token; + + do { + token = yylex(); + if (token == ERROR) { + exit(-1); + } + // Ignore Comments and Whitespace + if (token != COMMENT && token != WHITESPACE) { + printf("%d\n", token); + } + } while(token != 0); + + return 0; +} \ No newline at end of file diff --git a/src/lexer.l b/src/lexer.l new file mode 100644 index 0000000..9c0d989 --- /dev/null +++ b/src/lexer.l @@ -0,0 +1,48 @@ +%{ +#include +#include +#include "node.h" +#include "parser.tab.h" + +/* Keep track of line numbers for error reporting */ +int linenum = 0; +%} + +DIGIT [0-9] +%option noyywrap +%% + +"+" {return PLUS; } +"-" {return MINUS;} +"/" {return DIVIDE;} +"*" {return TIMES;} +"!" {return NOT;} +"(" {return OPENPAREM;} +")" {return ENDPAREM;} +";" {return SEMICOLON;} +%.*\n {} // Comments +"<" {return LESS;} +">" {return GREATER;} +"<=" {return LESSEQ;} +">=" {return GREATEREQ;} +"==" {return EQUALS;} +"!=" {return NEQUALS;} +"&&" {return AND;} +"||" {return OR;} +":=" {return ASSIGN;} +"if" {return IF;} +"do" {return DO;} +"end" {return END;} +"then" {return THEN;} +"else" {return ELSE;} +"begin" {return BEGINTOK;} +"while" {return WHILE;} +"print" {return PRINT;} +"input" {return INPUT;} +{DIGIT}*"."?{DIGIT}+ {yylval.value = make_node(VALUE, atof(yytext), ""); return VALUE;} +[_a-zA-Z][_a-zA-Z0-9]* {yylval.value = make_node(IDENTIFIER, 0, strdup(yytext)); return IDENTIFIER;} +[\n] {linenum++;} +[ \t\r]+ {} +. {printf("Error: invlaid lexeme '%s'.\n", yytext); return 0;} + +%% diff --git a/src/node.h b/src/node.h new file mode 100644 index 0000000..3e6efef --- /dev/null +++ b/src/node.h @@ -0,0 +1,58 @@ +#ifndef NODE_H +#define NODE_H + +#define ID_SIZE 100 +#define MAX_CHILDREN 3 +#define STATEMENT 200 +#define MAX_VARIABLES 200 + +// Share the line number between files +extern int linenum; + +/* a tree node definition */ +struct Node { + int type; + double 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, double 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]; + double value; +}; + +// Variable Functions +struct Variable* make_variable(char* id, double value); +void set_value(struct Variable* var, double value); +double get_value(struct Variable* var); + +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); +double eval_expression(struct Node* node, struct Environment* env); + +#endif diff --git a/src/parser.y b/src/parser.y new file mode 100644 index 0000000..3b63e07 --- /dev/null +++ b/src/parser.y @@ -0,0 +1,506 @@ +%{ +#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 + +/* declare non-terminals */ +%type program statement assignment if-statement if-else-statement while print statements substatements 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 expression SEMICOLON { + $$ = make_node(ASSIGN, 0, ""); + attach_node($$, $1); + attach_node($$, $3); +} + +if-statement: IF expression THEN statement { + $$ = make_node(IF, 0, ""); + attach_node($$, $2); + attach_node($$, $4); +} + +if-else-statement: IF expression THEN statement ELSE statement { + $$ = make_node(IF, 0, ""); + attach_node($$, $2); + attach_node($$, $4); + attach_node($$, $6); +} + +while: WHILE expression DO statement { + $$ = make_node(WHILE, 0, ""); + attach_node($$, $2); + attach_node($$, $4); +} + +print: PRINT expression SEMICOLON { + $$ = make_node(PRINT, 0, ""); + attach_node($$, $2); +} + + +statements: BEGINTOK substatements END { $$ = $2; } + | BEGINTOK END {} + +substatements: statement substatements {$$ = make_node(STATEMENT, 0, ""); attach_node($$, $1); attach_node($$, $2); } + | statement {$$ = make_node(STATEMENT, 0, ""); attach_node($$, $1); } + +expression : expression OR subexpression { $$ = make_node(OR, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | expression AND subexpression { $$ = make_node(AND, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression { $$ = $1; } + +subexpression: subexpression LESS term { $$ = make_node(LESS, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression LESSEQ term { $$ = make_node(LESSEQ, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression GREATER term { $$ = make_node(GREATER, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression GREATEREQ term { $$ = make_node(GREATEREQ, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression EQUALS term { $$ = make_node(EQUALS, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subexpression NEQUALS term { $$ = make_node(NEQUALS, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | term { $$ = $1; } + +term : term PLUS subterm { $$ = make_node(PLUS, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | term MINUS subterm { $$ = make_node(MINUS, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subterm { $$ = $1; } + +subterm: subterm TIMES factor { $$ = make_node(TIMES, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | subterm DIVIDE factor { $$ = make_node(DIVIDE, 0, ""); attach_node($$, $1); attach_node($$, $3);} + | factor { $$ = $1; } + +factor : MINUS factor { $$ = make_node(MINUS, 0, ""); attach_node($$, $2); } + | NOT factor { $$ = make_node(NOT, 0, ""); attach_node($$, $2); } + | atom { $$ = $1; } + +atom: OPENPAREM expression ENDPAREM { $$ = $2; } + | identvalue { $$ = $1; } + +ident: IDENTIFIER { $$ = $1; } + +identvalue: IDENTIFIER { $$ = $1; } + | VALUE { $$ = $1; } + | INPUT { $$ = make_node(INPUT, 0 , ""); } + + + +%% + + +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, double 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 VALUE: printf("VALUE: %lf\n", node->value); 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 STATEMENT: printf("STATEMENT:\n"); 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, double 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, double value) { + if (!var) { fprintf(stderr, "Error: Invalid Variable\n"); return; } + var->value = value; +} +double 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); +} + + +double eval_expression(struct Node* node, struct Environment* env) { + /* base case */ + if(!node) { + fprintf(stderr, "Error: No tree structure to evaluate\n"); + return 0; + } + int nodeNotValid = !( + node->type == IDENTIFIER || + node->type == VALUE || + node->type == INPUT || + node->type == PLUS || + node->type == MINUS || + node->type == DIVIDE || + node->type == TIMES || + node->type == LESS || + node->type == GREATER || + node->type == LESSEQ || + node->type == GREATEREQ || + node->type == EQUALS || + node->type == NEQUALS || + node->type == AND || + node->type == OR || + node->type == NOT + ); + + if (nodeNotValid) { + fprintf(stderr,"Error, %d not a valid expression type.\n", node->type); + return 0; + } + + // Needed if we are going to take input from the user + double temp; + struct Variable* var = NULL; + + switch(node->type) { + case PLUS: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot add more than two expressions.\n"); } + return eval_expression(node->children[0], env) + eval_expression(node->children[1], env); + break; + //---------- + case MINUS: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot subtract more than two expressions.\n"); } + return eval_expression(node->children[0], env) - eval_expression(node->children[1], env); + break; + //---------- + case DIVIDE: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot divide more than two expressions.\n"); } + return eval_expression(node->children[0], env) / eval_expression(node->children[1], env); + break; + //---------- + case TIMES: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot multiply more than two expressions.\n"); } + return eval_expression(node->children[0], env) * eval_expression(node->children[1], env); + break; + //---------- + case LESS: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) < eval_expression(node->children[1], env); + break; + //---------- + case GREATER: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) > eval_expression(node->children[1], env); + break; + //---------- + case LESSEQ: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) <= eval_expression(node->children[1], env); + break; + //---------- + case GREATEREQ: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) >= eval_expression(node->children[1], env); + break; + //---------- + case EQUALS: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) == eval_expression(node->children[1], env); + break; + //---------- + case NEQUALS: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot compare more than two expressions.\n"); } + return eval_expression(node->children[0], env) != eval_expression(node->children[1], env); + break; + //---------- + case AND: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot perform logical operators on more than two expressions.\n"); } + return eval_expression(node->children[0], env) && eval_expression(node->children[1], env); + break; + //---------- + case OR: + if (node->num_children != 2) { fprintf(stderr, "Error, cannot perform logical operators on more than two expressions.\n"); } + return eval_expression(node->children[0], env) || eval_expression(node->children[1], env); + break; + //---------- + case NOT: + if (node->num_children != 1) { fprintf(stderr, "Error, cannot negate more than one expressions.\n"); } + return !eval_expression(node->children[0], env); + break; + //---------- + case INPUT: + scanf("%lf", &temp); + return 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; + } + + switch(node->type) { + case ASSIGN: + if (node->num_children != 2) { fprintf(stderr, "Error: Cannot make an assignment without an identifier and a value.\n"); } + 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"); + } + if (eval_expression(node->children[0], env)) { + eval_statement(node->children[1], env); + } else if (node->num_children == 3) { + eval_statement(node->children[2], env); + } + break; + case WHILE: + if (node->num_children != 2) { fprintf(stderr, "Error: The format of a while statement is while expression statement(s)\n"); } + while (eval_expression(node->children[0], env)) { + eval_statement(node->children[1], env); + } + break; + case PRINT: + if (node->num_children != 1) { fprintf(stderr, "Error: Can only print out one expression at a time.\n"); } + printf("%lf\n", eval_expression(node->children[0], env)); + 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 node type.\n", node->type); + return; + } +}