Archived
1
0
Fork 0

Now you can define a single argument lambda expression and call it using the standard parenthesis notation

This commit is contained in:
Brandon Rozek 2018-09-24 16:43:53 -04:00
parent 82f7e21d3a
commit b0ec7c113c
3 changed files with 70 additions and 30 deletions

View file

@ -41,10 +41,10 @@ DIGIT [0-9]
"input" {return INPUT;} "input" {return INPUT;}
"lambda" {return LAMBDA;} "lambda" {return LAMBDA;}
":" {return COLON;} ":" {return COLON;}
"true" {yylval.value = make_node(VALUE, make_value(BOOLEAN, 1, 0), ""); return VALUE;} "true" {yylval.value = make_node(VALUE, make_true(), ""); return VALUE;}
"false" {yylval.value = make_node(VALUE, make_value(BOOLEAN, 0, 0), ""); return VALUE;} "false" {yylval.value = make_node(VALUE, make_false(), ""); return VALUE;}
{DIGIT} {yylval.value = make_node(VALUE, make_value(LONG, atoi(yytext), 0), ""); return VALUE;} {DIGIT} {yylval.value = make_node(VALUE, make_long(atoi(yytext)), ""); return VALUE;}
{DIGIT}*"."?{DIGIT}+ {yylval.value = make_node(VALUE, make_value(DOUBLE, 0, atof(yytext)), ""); return VALUE;} {DIGIT}*"."?{DIGIT}+ {yylval.value = make_node(VALUE, make_double(atof(yytext)), ""); return VALUE;}
[_a-zA-Z][_a-zA-Z0-9]* {yylval.value = make_node(IDENTIFIER, NULL, strdup(yytext)); return IDENTIFIER;} [_a-zA-Z][_a-zA-Z0-9]* {yylval.value = make_node(IDENTIFIER, NULL, strdup(yytext)); return IDENTIFIER;}
[\n] {linenum++;} [\n] {linenum++;}
[ \t\r]+ {} [ \t\r]+ {}

View file

@ -40,6 +40,7 @@ struct Variable {
typedef union typeval { typedef union typeval {
long num; long num;
double dec; double dec;
struct Node* expr;
} TypeVal; } TypeVal;
struct Value { struct Value {
@ -48,7 +49,7 @@ struct Value {
}; };
// Value functions // Value functions
struct Value* make_value(int type, long num, double dec); struct Value* make_value(int type, long num, double dec, struct Node* expr);
struct Value* make_long(long num); struct Value* make_long(long num);
struct Value* make_double(double dec); struct Value* make_double(double dec);
struct Value* make_true(); struct Value* make_true();
@ -57,13 +58,21 @@ struct Value* make_false();
void delete_value(struct Value* val); void delete_value(struct Value* val);
long get_long(struct Value* val); long get_long(struct Value* val);
double get_double(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_long(struct Value* val, long num);
void set_double(struct Value* val, double dec); void set_double(struct Value* val, double dec);
void set_expression(struct Value* val, struct Node* node);
// Variable Functions // Variable Functions
struct Variable* make_variable(char* id, struct Value* value); struct Variable* make_variable(char* id, struct Value* value);
void set_value(struct Variable* var, struct Value* value); void set_value(struct Variable* var, struct Value* value);
struct Value* get_value(struct Variable* var); 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 { struct Environment {
int num_vars; int num_vars;

View file

@ -55,7 +55,7 @@ struct Node* result;
%token COLON %token COLON
/* declare non-terminals */ /* declare non-terminals */
%type <value> program statement assignment if-statement if-else-statement while print statements substatements callfunc expression subexpression term subterm factor atom identvalue ident %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 */ /* give us more detailed errors */
%error-verbose %error-verbose
@ -71,7 +71,7 @@ statement: assignment { $$ = $1; }
| print { $$ = $1; } | print { $$ = $1; }
| statements { $$ = $1; } | statements { $$ = $1; }
assignment: ident ASSIGN expression SEMICOLON { assignment: ident ASSIGN exprlambda SEMICOLON {
$$ = make_node(ASSIGN, NULL, ""); $$ = make_node(ASSIGN, NULL, "");
attach_node($$, $1); attach_node($$, $1);
attach_node($$, $3); attach_node($$, $3);
@ -96,7 +96,7 @@ while: WHILE expression DO statement {
attach_node($$, $4); attach_node($$, $4);
} }
print: PRINT expression SEMICOLON { print: PRINT exprlambda SEMICOLON {
$$ = make_node(PRINT, NULL, ""); $$ = make_node(PRINT, NULL, "");
attach_node($$, $2); attach_node($$, $2);
} }
@ -108,6 +108,13 @@ statements: BEGINTOK substatements END { $$ = $2; }
substatements: statement substatements {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); attach_node($$, $2); } substatements: statement substatements {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); attach_node($$, $2); }
| statement {$$ = make_node(STATEMENT, NULL, ""); attach_node($$, $1); } | 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: 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);} | expression AND subexpression { $$ = make_node(AND, NULL, ""); attach_node($$, $1); attach_node($$, $3);}
| subexpression { $$ = $1; } | subexpression { $$ = $1; }
@ -132,22 +139,18 @@ factor : MINUS factor { $$ = make_node(MINUS, NULL, ""); attach_node($$, $2); }
| NOT factor { $$ = make_node(NOT, NULL, ""); attach_node($$, $2); } | NOT factor { $$ = make_node(NOT, NULL, ""); attach_node($$, $2); }
| atom { $$ = $1; } | atom { $$ = $1; }
callfunc: ident OPENPAREM expression ENDPAREM { $$ = make_node(CALLFUNC, NULL, ""); attach_node($$, $1); attach_node($$, $3); }
atom: OPENPAREM expression ENDPAREM { $$ = $2; } atom: OPENPAREM expression ENDPAREM { $$ = $2; }
| callfunc { $$ = $1; }
| identvalue { $$ = $1; } | identvalue { $$ = $1; }
ident: IDENTIFIER { $$ = $1; } ident: IDENTIFIER { $$ = $1; }
callfunc: ident OPENPAREM ident ENDPAREM { $$ = make_node(CALLFUNC, NULL, 0); attach_node($$, $1); attach_node($$, $3); } identvalue: ident { $$ = $1; }
identvalue: callfunc { $$ = $1; }
| ident { $$ = $1; }
| VALUE { $$ = $1; } | VALUE { $$ = $1; }
| INPUT { $$ = make_node(INPUT, NULL , ""); } | INPUT { $$ = make_node(INPUT, NULL , ""); }
| LAMBDA ident COLON expression {
// Only supports one argument functions for now
$$ = make_node(LAMBDA, NULL, "");
attach_node($$, $2);
attach_node($$, $4); }
@ -255,6 +258,7 @@ void print_tree(struct Node* node, int tabs) {
case PRINT: printf("PRINT:\n"); break; case PRINT: printf("PRINT:\n"); break;
case INPUT: printf("INPUT:\n"); break; case INPUT: printf("INPUT:\n"); break;
case LAMBDA: printf("LAMBDA:\n"); break; case LAMBDA: printf("LAMBDA:\n"); break;
case CALLFUNC: printf("FUNCTIONCALL:\n"); break;
case STATEMENT: printf("STATEMENT:\n"); break; case STATEMENT: printf("STATEMENT:\n"); break;
case VALUE: case VALUE:
if (node->value->type == BOOLEAN) { if (node->value->type == BOOLEAN) {
@ -361,7 +365,7 @@ void check_num_nodes(struct Node* node, int num_children, char* error) {
} }
} }
struct Value* make_value(int type, long num, double dec) { struct Value* make_value(int type, long num, double dec, struct Node* expr) {
/* allocate space */ /* allocate space */
struct Value* val = malloc(sizeof(struct Value)); struct Value* val = malloc(sizeof(struct Value));
@ -369,8 +373,10 @@ struct Value* make_value(int type, long num, double dec) {
val->type = type; val->type = type;
if (type == LONG || type == BOOLEAN) { if (type == LONG || type == BOOLEAN) {
val->value.num = num; val->value.num = num;
} else { // Assume DOUBLE } else if (type == DOUBLE){ // Assume DOUBLE
val->value.dec = dec; val->value.dec = dec;
} else { // Assume lambda expression
val->value.expr = expr;
} }
/* return new variable */ /* return new variable */
@ -378,34 +384,38 @@ struct Value* make_value(int type, long num, double dec) {
} }
struct Value* make_long(long num) { struct Value* make_long(long num) {
return make_value(LONG, num, 0); return make_value(LONG, num, 0, NULL);
} }
struct Value* make_double(double dec) { struct Value* make_double(double dec) {
return make_value(DOUBLE, 0, dec); return make_value(DOUBLE, 0, dec, NULL);
} }
struct Value* make_true() { struct Value* make_true() {
return make_value(BOOLEAN, 1, 0); return make_value(BOOLEAN, 1, 0, NULL);
} }
struct Value* make_false() { struct Value* make_false() {
return make_value(BOOLEAN, 0, 0); return make_value(BOOLEAN, 0, 0, NULL);
} }
struct Value* make_boolean(int x) { struct Value* make_boolean(int x) {
return (x)? make_true() : make_false(); 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) { void delete_value(struct Value* val) {
free(val); free(val);
} }
long get_long(struct Value* val) { long get_long(struct Value* val) {
return val->value.num; return val->value.num;
} }
double get_double(struct Value* val) { double get_double(struct Value* val) {
return val->value.dec; return val->value.dec;
} }
struct Node* get_expression(struct Value* val) {
return val->value.expr;
}
void set_long(struct Value* val, long num) { void set_long(struct Value* val, long num) {
val->type = LONG; val->type = LONG;
val->value.num = num; val->value.num = num;
@ -414,6 +424,10 @@ void set_double(struct Value* val, double dec) {
val->type = DOUBLE; val->type = DOUBLE;
val->value.dec = dec; 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) { struct Value* add(struct Value* x, struct Value* y) {
if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in add.\n"); } if (!x || !y) { fprintf(stderr, "Error, uninitialized values being used in add.\n"); }
@ -652,6 +666,9 @@ struct Value* eval_expression(struct Node* node, struct Environment* env) {
// Needed if we are going to take input from the user // Needed if we are going to take input from the user
double temp; double temp;
struct Variable* var = NULL; 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 // Evaluate subexpressions if existent and node is not a lambda expression
struct Value* val1 = NULL; struct Value* val1 = NULL;
@ -669,7 +686,18 @@ struct Value* eval_expression(struct Node* node, struct Environment* env) {
} }
switch(node->type) { switch(node->type) {
case LAMBDA: printf("<LambdaExpression>\n"); return make_long(0); break; 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: case PLUS:
check_num_nodes(node, 2, "cannot add more than two expressions."); check_num_nodes(node, 2, "cannot add more than two expressions.");
return add(val1, val2); return add(val1, val2);
@ -782,6 +810,7 @@ void eval_statement(struct Node* node, struct Environment* env) {
fprintf(stderr, "Error: No tree structure to evaluate\n"); fprintf(stderr, "Error: No tree structure to evaluate\n");
return; return;
} }
struct Value* tempVal; struct Value* tempVal;
switch(node->type) { switch(node->type) {
@ -833,8 +862,10 @@ void eval_statement(struct Node* node, struct Environment* env) {
} }
} else if (tempVal->type == LONG) { } else if (tempVal->type == LONG) {
printf("%li\n", get_long(tempVal)); printf("%li\n", get_long(tempVal));
} else { } else if (tempVal ->type == DOUBLE) {
printf("%lf\n", get_double(tempVal)); printf("%lf\n", get_double(tempVal));
} else { // Assume lambda expression
printf("<LambdaExpression>\n");
} }
break; break;
//------------ //------------