#include #include #include #include #include #include #include "expr.h" #include "finalize.h" #include "sym.h" struct Expr { enum ExprKind kind; union { struct { const struct Expr *left, *right; } binary; const struct Expr *unary; struct { struct { uint64_t uint; } literal; const struct UStr *identifier; } primary; }; }; // constructors static struct Expr * newExpr(void) { struct Expr *expr = malloc(sizeof(*expr)); if (!expr) { fprintf(stderr, "newExpr: out of memory\n"); finalizeExit(1); } return expr; } struct Expr * newUnsignedLiteralExpr(uint64_t uint) { struct Expr *expr = newExpr(); expr->kind = EK_UNSIGNED_LITERAL; expr->primary.literal.uint = uint; return expr; } struct Expr * newIdentifierExpr(const struct UStr *identifier) { assert(identifier); struct Expr *expr = newExpr(); expr->kind = EK_IDENTIFIER; expr->primary.identifier = identifier; return expr; } struct Expr * newUnaryExpr(enum ExprKind kind, const struct Expr *unary) { assert(kind >= EK_UNARY && kind < EK_UNARY_END); assert(unary); struct Expr *expr = newExpr(); expr->kind = kind; expr->unary = unary; return expr; } struct Expr * newBinaryExpr(enum ExprKind kind, const struct Expr *left, const struct Expr *right) { assert(kind >= EK_BINARY && kind < EK_BINARY_END); assert(left); assert(right); struct Expr *expr = newExpr(); expr->kind = kind; expr->binary.left = left; expr->binary.right = right; return expr; } // destructor void deleteExpr(const struct Expr *expr) { assert(expr); assert(expr->kind >= EK_BINARY && expr->kind < EK_PRIMARY_END); if (expr->kind >= EK_BINARY && expr->kind < EK_BINARY_END) { deleteExpr(expr->binary.left); deleteExpr(expr->binary.right); } else if (expr->kind >= EK_UNARY && expr->kind < EK_UNARY_END) { deleteExpr(expr->unary); } free((struct Expr *)(uintptr_t)expr); } // methods bool isLValueExpr(const struct Expr *expr) { return expr->kind == EK_IDENTIFIER; } double evalExpr(const struct Expr *expr) { assert(expr); assert(expr->kind >= EK_BINARY && expr->kind < EK_PRIMARY_END); if (expr->kind >= EK_BINARY && expr->kind < EK_UNARY_END) { switch (expr->kind) { case EK_ADD: return evalExpr(expr->binary.left) + evalExpr(expr->binary.right); case EK_ASSIGN: { const struct Expr *left = expr->binary.left; assert(isLValueExpr(left)); struct Sym *lValue = SymFind(left->primary.identifier); return lValue->value = evalExpr(expr->binary.right); } case EK_SUB: return evalExpr(expr->binary.left) - evalExpr(expr->binary.right); case EK_MUL: return evalExpr(expr->binary.left) * evalExpr(expr->binary.right); case EK_DIV: return evalExpr(expr->binary.left) / evalExpr(expr->binary.right); case EK_POW: return pow(evalExpr(expr->binary.left), evalExpr(expr->binary.right)); case EK_UNARY_MINUS: return -evalExpr(expr->unary); case EK_UNARY_PLUS: return evalExpr(expr->unary); default:; } } else if (expr->kind == EK_IDENTIFIER) { struct Sym *sym = SymFind(expr->primary.identifier); assert(sym); return sym->value; } else if (expr->kind == EK_UNSIGNED_LITERAL) { return expr->primary.literal.uint; } fprintf(stderr, "evalExpr: internal error. kind = %d\n", expr->kind); finalizeExit(1); return 0; // never reached; prevent compiler warning } static void printIndent(size_t indent, FILE *out) { for (size_t i = 0; i < indent * 4; ++i) { fprintf(out, " "); } } static void printExprNode(const struct Expr *expr, size_t indent, FILE *out) { assert(expr); printIndent(indent, out); if (expr->kind >= EK_BINARY && expr->kind < EK_UNARY_END) { switch (expr->kind) { case EK_ADD: fprintf(out, "[ +\n"); return; case EK_ASSIGN: fprintf(out, "[ {=}\n"); return; case EK_SUB: fprintf(out, "[ -\n"); return; case EK_MUL: fprintf(out, "[ *\n"); return; case EK_DIV: fprintf(out, "[ /\n"); return; case EK_POW: fprintf(out, "[ $\\hat{}$\n"); return; case EK_UNARY_MINUS: fprintf(out, "[ -\n"); return; case EK_UNARY_PLUS: fprintf(out, "[ +\n"); return; default:; } } else if (expr->kind == EK_UNSIGNED_LITERAL) { fprintf(out, "[ %" PRIu64 "]\n", expr->primary.literal.uint); return; } else if (expr->kind == EK_IDENTIFIER) { fprintf(out, "[ %s ]\n", expr->primary.identifier->cstr); return; } fprintf(stderr, "printExprNode: internal error. kind = %d\n", expr->kind); finalizeExit(1); } static void printExprTree_(const struct Expr *expr, size_t indent, FILE *out) { assert(expr); assert(expr->kind >= EK_BINARY && expr->kind < EK_PRIMARY_END); if (expr->kind >= EK_BINARY && expr->kind < EK_BINARY_END) { printExprNode(expr, indent, out); printExprTree_(expr->binary.left, indent + 1, out); printExprTree_(expr->binary.right, indent + 1, out); printIndent(indent, out); fprintf(out, "]\n"); } else if (expr->kind >= EK_UNARY && expr->kind < EK_UNARY_END) { printExprNode(expr, indent, out); printExprTree_(expr->unary, indent + 1, out); printIndent(indent, out); fprintf(out, "]\n"); } else { printExprNode(expr, indent, out); } } void printExprTree(const struct Expr *expr, FILE *out) { fprintf(out, "\\begin{center}\n"); fprintf(out, "\\begin{forest}\n"); fprintf(out, "for tree={draw,circle,calign=fixed edge angles}\n"); printExprTree_(expr, 0, out); fprintf(out, "\\end{forest}\n"); fprintf(out, "\\end{center}\n"); }