Modularized programming language code. Code is no longer in several large files :)
This commit is contained in:
parent
b0ec7c113c
commit
8c7571bef4
19 changed files with 1093 additions and 986 deletions
30
Makefile
30
Makefile
|
@ -1,8 +1,24 @@
|
||||||
run: src/lex.yy.c src/parser.tab.c
|
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/lex.yy.c src/parser.tab.c -o sloth
|
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.tab.c: src/parser.y
|
src/parser/lex.yy.o: src/parser/lex.yy.c src/parser/parser.tab.h
|
||||||
bison -d -o src/parser.tab.c src/parser.y
|
gcc -c src/parser/lex.yy.c -o src/parser/lex.yy.o
|
||||||
src/lex.yy.c: src/lexer.l
|
src/parser/parser.tab.o: src/parser/parser.tab.c
|
||||||
flex -o src/lex.yy.c src/lexer.l
|
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:
|
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
|
||||||
|
|
11
src/constants.h
Normal file
11
src/constants.h
Normal file
|
@ -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
|
31
src/main.c
Normal file
31
src/main.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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;
|
||||||
|
}
|
93
src/node.h
93
src/node.h
|
@ -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
|
|
342
src/operations/node.c
Normal file
342
src/operations/node.c
Normal file
|
@ -0,0 +1,342 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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("<LambdaExpression>\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;
|
||||||
|
}
|
||||||
|
}
|
33
src/operations/node.h
Normal file
33
src/operations/node.h
Normal file
|
@ -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
|
231
src/operations/operators.c
Normal file
231
src/operations/operators.c
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.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"); }
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
18
src/operations/operators.h
Normal file
18
src/operations/operators.h
Normal file
|
@ -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
|
885
src/parser.y
885
src/parser.y
|
@ -1,885 +0,0 @@
|
||||||
%{
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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 <value> IDENTIFIER
|
|
||||||
%token <value> 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 <value> INPUT
|
|
||||||
%token COMMENT
|
|
||||||
%token WHITESPACE
|
|
||||||
%token DONE
|
|
||||||
%token <value> LAMBDA
|
|
||||||
%token COLON
|
|
||||||
|
|
||||||
/* declare non-terminals */
|
|
||||||
%type <value> 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("<LambdaExpression>\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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,8 @@
|
||||||
%{
|
%{
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "node.h"
|
#include "../operations/node.h"
|
||||||
|
#include "../variables/value.h"
|
||||||
#include "parser.tab.h"
|
#include "parser.tab.h"
|
||||||
|
|
||||||
/* Keep track of line numbers for error reporting */
|
/* Keep track of line numbers for error reporting */
|
8
src/parser/parser.h
Normal file
8
src/parser/parser.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef PARSER_H
|
||||||
|
#define PARSER_H
|
||||||
|
|
||||||
|
int yywrap( );
|
||||||
|
int yylex( );
|
||||||
|
void yyerror(const char* str);
|
||||||
|
|
||||||
|
#endif
|
160
src/parser/parser.y
Normal file
160
src/parser/parser.y
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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 <value> IDENTIFIER
|
||||||
|
%token <value> 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 <value> INPUT
|
||||||
|
%token COMMENT
|
||||||
|
%token WHITESPACE
|
||||||
|
%token DONE
|
||||||
|
%token <value> LAMBDA
|
||||||
|
%token COLON
|
||||||
|
|
||||||
|
/* declare non-terminals */
|
||||||
|
%type <value> 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);
|
||||||
|
}
|
12
src/sloth.h
Normal file
12
src/sloth.h
Normal file
|
@ -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
|
49
src/variables/environment.c
Normal file
49
src/variables/environment.c
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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);
|
||||||
|
}
|
17
src/variables/environment.h
Normal file
17
src/variables/environment.h
Normal file
|
@ -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
|
68
src/variables/value.c
Normal file
68
src/variables/value.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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;
|
||||||
|
}
|
39
src/variables/value.h
Normal file
39
src/variables/value.h
Normal file
|
@ -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
|
27
src/variables/variable.c
Normal file
27
src/variables/variable.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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;
|
||||||
|
}
|
22
src/variables/variable.h
Normal file
22
src/variables/variable.h
Normal file
|
@ -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
|
Reference in a new issue