Added beginning code for SLOTH
This commit is contained in:
commit
fbfaf0ddb8
11 changed files with 829 additions and 0 deletions
8
Makefile
Normal file
8
Makefile
Normal file
|
@ -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
|
38
examples/acid.sl
Normal file
38
examples/acid.sl
Normal file
|
@ -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;
|
||||||
|
|
||||||
|
|
12
examples/area.sl
Normal file
12
examples/area.sl
Normal file
|
@ -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;
|
||||||
|
|
15
examples/fact.sl
Normal file
15
examples/fact.sl
Normal file
|
@ -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;
|
||||||
|
|
21
examples/fibs.sl
Normal file
21
examples/fibs.sl
Normal file
|
@ -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!
|
||||||
|
|
||||||
|
|
27
examples/minmax.sl
Normal file
27
examples/minmax.sl
Normal file
|
@ -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;
|
||||||
|
|
3
examples/simple.sl
Normal file
3
examples/simple.sl
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
% very simple program
|
||||||
|
print 1 + 1;
|
||||||
|
|
93
extra/token_spitter.l
Normal file
93
extra/token_spitter.l
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
48
src/lexer.l
Normal file
48
src/lexer.l
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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;}
|
||||||
|
|
||||||
|
%%
|
58
src/node.h
Normal file
58
src/node.h
Normal file
|
@ -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
|
506
src/parser.y
Normal file
506
src/parser.y
Normal file
|
@ -0,0 +1,506 @@
|
||||||
|
%{
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* declare non-terminals */
|
||||||
|
%type <value> 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;
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue