summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <me@fwei.tk>2018-05-19 22:25:33 -0400
committerFranklin Wei <me@fwei.tk>2018-05-19 22:25:33 -0400
commit91edb3a29c403c689c4fcc3c5d3890ce9e2ee056 (patch)
tree89ac06bb085bea7cd128aab76d1e7f5ff5507f11
parent5abd87353784e6afb5ee232bd9ab1cec6192b19a (diff)
downloadyacas-91edb3a29c403c689c4fcc3c5d3890ce9e2ee056.zip
yacas-91edb3a29c403c689c4fcc3c5d3890ce9e2ee056.tar.gz
yacas-91edb3a29c403c689c4fcc3c5d3890ce9e2ee056.tar.bz2
yacas-91edb3a29c403c689c4fcc3c5d3890ce9e2ee056.tar.xz
make more robust
-rw-r--r--yacas.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/yacas.c b/yacas.c
index ce0539b..4ff9dcb 100644
--- a/yacas.c
+++ b/yacas.c
@@ -1,3 +1,68 @@
+/*
+ * Franklin Wei
+ * 19 May 2018
+ * Northwest Guilford High School
+ * yaCAS - "Yet Another Computer Algebra System"
+ *
+ * This is a program to manipulate algebraic expressions. It features
+ * a way of representing arbitrary expressions in memory, a parser to
+ * convert to and from standard mathematical notation, and functions
+ * to simplify, differentiate, and integrate such
+ * expressions. Additionally, it can function as a simple numerical
+ * calculator.
+ *
+ * Expressions are represented by an abstract syntax tree, a node of
+ * which is represented by a "struct expression" object (see
+ * definition below). Expressions are passed by reference to most
+ * functions, but most functions will allocate an entirely new
+ * expression tree to return their results. This results in a not
+ * insignificant amount of overhead as memory allocations and frees
+ * take place, but also greatly simplifies the memory model.
+ *
+ * Variables are supported through a simple hash map. Strings are
+ * mapped to expression trees through the "struct variable" object,
+ * and the expression trees are then substituted into the computation
+ * as needed. There is a special variable called . that stores the
+ * result of the previous computation.
+ *
+ * Differentiation is performed recursively on the expression
+ * tree. The differentiation of most expressions is performed by
+ * recursing down the tree, applying the basic rules of
+ * differentiation to combine the derivatives of child nodes. See the
+ * "diff" function for implementation.
+ *
+ * The expression parser is rather limited when it comes to
+ * tokenization. In its current form, it relies on tokens in the
+ * expression, say, "x ^ 2", being separated with spaces. That is,
+ * typing an expression like "x^2", without spaces between tokens,
+ * will result in undesired behavior (in this case, the parser wil
+ * view the token "x^2" as a variable name, not an expression). Just
+ * be sure to always separate tokens with a space, and all will be
+ * well.
+ *
+ * Finally, when using the exponential function, the form "exp ( x )"
+ * is preferred over "e ^ x", since the parser will recognize exp() as
+ * a special function and know about its special properties, while e^x
+ * will be treated as some constant raised to a power, without the
+ * special features of the exp() being recognized.
+ *
+ * Please note that this is a work in progress. The simplification,
+ * equality checking, and integration algorithms used are rudimentary
+ * at best, although differentiation should be relatively robust.
+ *
+ * Usage instructions: compile with no optimization, as this may cause
+ * undefined behavior, and link with -lm and -lreadline:
+ *
+ * cc -O0 yacas.c -o yacas -lm -lreadline
+ *
+ * Then run with no arguments and you should be presented with a
+ * "yaCAS> " prompt. From here, you can type "help" at the command
+ * line for an overview of the basic syntax.
+ *
+ * Readline can be disabled by commenting out the #define below (in
+ * which case the getline() function will be used instead):
+ */
+
#define USE_READLINE
#include <assert.h>
@@ -5,8 +70,8 @@
#include <math.h>
#include <setjmp.h>
#include <stdbool.h>
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -18,6 +83,8 @@
#endif
/* tool for manipulating algebraic expressions */
+
+/* packed to save memory with large expressions */
struct expression {
char type; /* T_* */
union {
@@ -747,6 +814,7 @@ struct expression *eval_expr(struct expression *expr)
case T_CONST:
return new_const(expr->constant);
case T_VAR:
+ /* this could fail upon a circular reference */
if(is_var(expr->varname))
return eval_expr(getvar(expr->varname));
@@ -1648,6 +1716,7 @@ int main(int argc, char *argv[])
setvar("pi", new_const(M_PI), true);
setvar("e", new_const(M_E), true);
setvar("memdiag", new_const(0), false);
+ setvar(".", new_const(0), false);
while(1)
{