cobol-interpreter-lab/lab-5/expr.c

467 lines
10 KiB
C

#include "expr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct SymbolMap *symbol_table = NULL;
/*
Create one node in an expression tree and return the structure.
*/
struct type *type_create(type_t kind, struct type *sub) {
struct type *t = malloc(sizeof(*t));
t->kind = kind;
t->subtype = sub;
return t;
}
struct decl *decl_create(struct expr *name, struct type *type,
struct expr *value, struct stmt *code,
struct decl *next) {
struct decl *d = malloc(sizeof(*d));
d->name = name;
d->type = type;
d->value = value;
d->code = code;
d->next = next;
return d;
}
struct stmt *stmt_create(stmt_t kind, struct decl *decl, struct expr *init_expr,
struct expr *expr, struct expr *next_expr,
struct stmt *body, struct stmt *else_body,
struct stmt *next) {
struct stmt *s = malloc(sizeof(*s));
s->kind = kind;
s->decl = decl;
s->init_expr = init_expr;
s->expr = expr;
s->next_expr = next_expr;
s->body = body;
s->else_body = else_body;
s->next = next;
return s;
}
struct expr *expr_create(expr_t kind, struct expr *left, struct expr *right) {
/* Shortcut: sizeof(*e) means "the size of what e points to" */
struct expr *e = malloc(sizeof(*e));
e->kind = kind;
e->left = left;
e->right = right;
e->name = "";
e->integer_value = 0;
e->float_value = 0.0;
e->string_literal = "";
return e;
}
struct expr *expr_create_name(const char *value) {
struct expr *e = expr_create(EXPR_NAME, 0, 0);
char *dest = malloc(sizeof(*value));
strcpy(dest, value); // copy contents of source to dest
e->name = dest;
return e;
}
struct expr *expr_create_integer_literal(int value) {
struct expr *e = expr_create(EXPR_INTEGER_LITERAL, 0, 0);
e->integer_value = value;
return e;
}
struct expr *expr_create_float_literal(float value) {
struct expr *e = expr_create(EXPR_FLOAT_LITERAL, 0, 0);
e->float_value = value;
return e;
}
struct expr *expr_create_string_literal(const char *value) {
struct expr *e = expr_create(EXPR_STRING_LITERAL, 0, 0);
char *dest = malloc(sizeof(*value));
strcpy(dest, value); // copy contents of source to dest
e->string_literal = dest;
return e;
}
/*
Recursively delete an expression tree.
*/
void expr_delete(struct expr *e) {
/* Careful: Stop on null pointer. */
if (!e)
return;
expr_delete(e->left);
expr_delete(e->right);
free(e);
}
void scope_bind(const char *name, struct expr *value) {
if (symbol_table == NULL) {
symbol_table = createSymbolMap();
}
insertSymbol(symbol_table, name, value);
}
struct expr *scope_lookup(const char *name) {
return getSymbol(symbol_table, name);
}
/*
Recursively print an expression tree by performing an
in-order traversal of the tree, printing the current node
between the left and right nodes.
*/
void stmt_print(struct stmt *s) {
if (!s)
return;
switch (s->kind) {
case STMT_DECL:
decl_print(s->decl);
printf(";\n");
break;
case STMT_EXPR:
expr_print(s->expr);
break;
case STMT_IF:
printf("if ");
expr_print(s->expr);
printf(" then\n");
stmt_print(s->body);
printf("endif\n");
break;
case STMT_PRINT:
printf("print ");
expr_print(s->expr);
printf(";\n");
break;
case STMT_BLOCK:
stmt_print(s->body);
break;
// we haven't implemented sections yet
case STMT_SECTION:
printf("section\n");
break;
}
stmt_print(s->next);
}
void decl_print(struct decl *d) {
expr_print(d->name);
printf(" = ");
expr_print(d->value);
}
void expr_print(struct expr *e) {
/* Careful: Stop on null pointer. */
if (!e)
return;
const char *close = "";
if (e->kind == EXPR_ARRAY) {
printf("[");
close = "]";
} else if (e->kind != EXPR_NAME && e->kind != EXPR_SUBSCRIPT &&
e->kind != EXPR_INTEGER_LITERAL && e->kind != EXPR_FLOAT_LITERAL &&
e->kind != EXPR_STRING_LITERAL) {
printf("(");
close = ")";
}
expr_print(e->left);
switch (e->kind) {
case EXPR_NAME:
printf("%s", e->name);
break;
case EXPR_ARRAY:
if (e->right) {
printf(", ");
}
break;
case EXPR_SUBSCRIPT:
printf("[");
close = "]";
break;
case EXPR_ADD:
printf("+");
break;
case EXPR_SUBTRACT:
printf("-");
break;
case EXPR_MULTIPLY:
printf("*");
break;
case EXPR_DIVIDE:
printf("/");
break;
case EXPR_EQUAL_EQUAL:
printf("==");
break;
case EXPR_NOT_EQUAL:
printf("!=");
break;
case EXPR_GREATER_THAN:
printf(">");
break;
case EXPR_GREATER_THAN_OR_EQUAL:
printf(">=");
break;
case EXPR_LESS_THAN:
printf("<");
break;
case EXPR_LESS_THAN_OR_EQUAL:
printf("<=");
break;
case EXPR_INTEGER_LITERAL:
printf("%d", e->integer_value);
break;
case EXPR_FLOAT_LITERAL:
printf("%f", e->float_value);
break;
case EXPR_STRING_LITERAL:
printf("%s", e->string_literal);
break;
}
expr_print(e->right);
// Options for closing
printf("%s", close);
}
/*
Recursively evaluate an expression by performing
the desired operation and returning it up the tree.
*/
void stmt_evaluate(struct stmt *s) {
if (!s)
return;
switch (s->kind) {
case STMT_DECL:
decl_evaluate(s->decl);
break;
case STMT_EXPR:
expr_evaluate(s->expr);
break;
case STMT_IF:
if (expr_evaluate(s->expr)) {
stmt_evaluate(s->body);
}
break;
case STMT_PRINT:
if (s->expr->kind == EXPR_STRING_LITERAL) {
printf("%s", expr_string_evaluate(s->expr));
} else if (s->expr->kind == EXPR_FLOAT_LITERAL) {
printf("%f", expr_evaluate(s->expr));
} else if (s->expr->kind == EXPR_INTEGER_LITERAL ||
s->expr->kind == EXPR_NAME || s->expr->kind == EXPR_SUBSCRIPT) {
printf("%.0f", expr_evaluate(s->expr));
} else {
printf("runtime error: print expression is not literal\n");
}
break;
case STMT_BLOCK:
stmt_evaluate(s->body);
break;
case STMT_SECTION:
break;
}
stmt_evaluate(s->next);
}
void decl_evaluate(struct decl *d) {
if (!d)
return;
if (d->name->kind == EXPR_NAME && d->value->kind == EXPR_ARRAY) {
struct expr *e = expr_sub_evaluate(d->value);
scope_bind(d->name->name, e);
} else if (d->name->kind == EXPR_NAME) {
float value = expr_evaluate(d->value);
struct expr *e = expr_create_float_literal(value);
scope_bind(d->name->name, e);
} else if (d->name->kind == EXPR_SUBSCRIPT) {
float value = expr_evaluate(d->value);
decl_subscript_evaluate(d->name, value);
} else {
printf("Error: expression type unknown for name");
exit(1);
}
}
void decl_subscript_evaluate(struct expr *e, float value) {
/* Careful: Return zero on null pointer. */
if (!e)
return;
if (e->kind != EXPR_SUBSCRIPT) {
printf("runtime error: not a subscript expression\n");
exit(1);
}
if (e->left->kind != EXPR_NAME) {
printf("runtime error: subscript has no name\n");
exit(1);
}
// Get array expresion
struct expr *a = scope_lookup(e->left->name);
float index = expr_evaluate(e->right);
// Find the right offset
while (index > 0) {
a = a->right;
index--;
}
expr_delete(a->left);
a->left = expr_create_float_literal(value);
}
const char *expr_string_evaluate(struct expr *e) {
/* Careful: Return zero on null pointer. */
if (!e)
return 0;
switch (e->kind) {
case EXPR_NAME:
case EXPR_ARRAY:
case EXPR_SUBSCRIPT:
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
case EXPR_EQUAL_EQUAL:
case EXPR_NOT_EQUAL:
case EXPR_GREATER_THAN:
case EXPR_GREATER_THAN_OR_EQUAL:
case EXPR_LESS_THAN:
case EXPR_LESS_THAN_OR_EQUAL:
case EXPR_INTEGER_LITERAL:
case EXPR_FLOAT_LITERAL:
printf("runtime error: not a string expression\n");
exit(1);
case EXPR_STRING_LITERAL:
return e->string_literal;
}
return "";
}
struct expr *expr_sub_evaluate(struct expr *e) {
/* Careful: Return zero on null pointer. */
if (!e)
return 0;
// TODO evaluate each item in the array and save the result
return e;
}
/*
Recursively evaluate an expression by performing
the desired operation and returning it up the tree.
*/
float expr_subscript_evaluate(struct expr *e) {
/* Careful: Return zero on null pointer. */
if (!e)
return 0;
if (e->kind != EXPR_SUBSCRIPT) {
printf("runtime error: not a subscript expression\n");
exit(1);
}
if (e->left->kind != EXPR_NAME) {
printf("runtime error: subscript has no name\n");
exit(1);
}
// Get array expresion
struct expr *a = scope_lookup(e->left->name);
float index = expr_evaluate(e->right);
// Find the right offset
while (index > 0) {
a = a->right;
index--;
}
return expr_evaluate(a->left);
}
float expr_evaluate(struct expr *e) {
/* Careful: Return zero on null pointer. */
if (!e)
return 0;
if (e->kind == EXPR_SUBSCRIPT)
return expr_subscript_evaluate(e);
float l = expr_evaluate(e->left);
float r = expr_evaluate(e->right);
switch (e->kind) {
case EXPR_NAME:
// Get the variable expression and then evaluate it.
return expr_evaluate(scope_lookup(e->name));
case EXPR_ARRAY:
printf("runtime error: array in expression\n");
exit(1);
case EXPR_SUBSCRIPT:
printf(
"runtime error: subscript should be processed earlier in expression\n");
exit(1);
case EXPR_ADD:
return l + r;
case EXPR_SUBTRACT:
return l - r;
case EXPR_MULTIPLY:
return l * r;
case EXPR_DIVIDE:
if (r == 0) {
printf("runtime error: divide by zero\n");
exit(1);
}
return l / r;
case EXPR_EQUAL_EQUAL:
return l == r;
case EXPR_NOT_EQUAL:
return l != r;
case EXPR_GREATER_THAN:
return l > r;
case EXPR_GREATER_THAN_OR_EQUAL:
return l >= r;
case EXPR_LESS_THAN:
return l < r;
case EXPR_LESS_THAN_OR_EQUAL:
return l <= r;
case EXPR_INTEGER_LITERAL:
return e->integer_value;
case EXPR_FLOAT_LITERAL:
return e->float_value;
case EXPR_STRING_LITERAL:
printf("runtime error: string in expression\n");
exit(1);
}
return 0;
}
void close_parser() { destroySymbolMap(symbol_table); }