+/* While do function */
+
+double while_do (element_t *cond, element_t *action)
+{
+ double ret = 0;
+ element_t *temp = NULL;
+
+ VERBOSE (DEBUG, fprintf (stdout, "starting while loop\n"));
+ while (1) {
+ VERBOSE (DEBUG, fprintf (stdout, "loop...\n"));
+
+ temp = dupelement (cond);
+ double test = evaluate_element (temp, 0);
+ delelement (temp);
+ if (!test) {
+ break;
+ }
+ if (action) {
+ temp = dupelement (action);
+ ret = evaluate_element (temp, 0);
+ delelement (temp);
+ }
+ }
+
+ VERBOSE (DEBUG, fprintf (stdout, "ending while loop\n"));
+
+ return ret;
+}
+
+/* program function */
+
+double execute_code (element_t **prog, int nbcalls)
+{
+ double ret = 0;
+ int i;
+ for (i = 0; i < nbcalls; i++) {
+ ret = evaluate_element (prog[i], 0);
+ }
+ return ret;
+}
+
+/* quit function */
+
+void quit (void)
+{
+ fprintf (stdout, "bye\n");
+ exit (0);
+}
+
+/* help message */
+
+void help (void)
+{
+ fprintf (stdout, "calc is a simple calculator\n\n");
+ fprintf (stdout, "arithmetic op.:");
+ fprintf (stdout, " + - * / %% ^\n");
+ fprintf (stdout, "comparison op.:");
+ fprintf (stdout, " == != >= <= > <\n");
+ fprintf (stdout, "logical op.:");
+ fprintf (stdout, " & | !\n");
+ fprintf (stdout, "mathematic func.:");
+ fprintf (stdout, " exp ln log pow sqrt\n");
+ fprintf (stdout, "trigonometric func.:");
+ fprintf (stdout, " acos asin atan cos sin tan\n");
+ fprintf (stdout, "error functions:");
+ fprintf (stdout, " erf erfc\n");
+ fprintf (stdout, "miscellaneous func.:");
+ fprintf (stdout, " abs ceil floor\n");
+ fprintf (stdout, "storage func.:");
+ fprintf (stdout, " clear dec disp inc mem rcl sto\n");
+ fprintf (stdout, "control flow prim.:");
+ fprintf (stdout, " cond print while {} ;\n");
+ fprintf (stdout, "program management:");
+ fprintf (stdout, " arg call del edit ls prog\n");
+ fprintf (stdout, "stack management:");
+ fprintf (stdout, " get len pop push put set show\n");
+ fprintf (stdout, "stack func.:");
+ fprintf (stdout, " max mean med min ord prod sum var\n");
+ fprintf (stdout, "control management:");
+ fprintf (stdout, " base format help quit\n");
+ fprintf (stdout, "constants:");
+ fprintf (stdout, " ans e pi\n");
+}
+
+/* format function */
+
+int format (int precision)
+{
+ if (precision > 0) {
+ set_precision (precision);
+ set_format ();
+ } else if (precision != -1) {
+ VERBOSE (WARNING, fprintf (stdout, "error incorrect precision (%d)\n", precision));
+ return 0;
+ }
+ return get_precision ();
+}
+
+/* base function */
+
+void base (int in, int out)
+{
+ if ((in > 0) && (in < 37)) {
+ set_base (in, in);
+ if ((out > 0) && (out < 37)) {
+ set_base (in, out);
+ } else if (out != - 1) {
+ VERBOSE (WARNING, fprintf (stdout, "error incorrect output base (%d)\n", out));
+ }
+ } else if (in != -1 ) {
+ VERBOSE (WARNING, fprintf (stdout, "error incorrect input base (%d)\n", in));
+ } else {
+ printf ("base (I/O): %s\n", show_base ());
+ }
+}
+
+/* evaluate element tree */
+
+#define MASK_SUB 0x1
+#define MASK_DIV 0x2
+
+double evaluate_element (element_t *root, char mask)
+{
+ double op0 = 0, op1 = 0;
+ char nextmask = mask;
+ int i, nb;
+
+ if ((root == NULL) || (root == ERROR_OP)) {
+ VERBOSE (WARNING, fprintf (stdout, "error while evaluating\n"));
+ return 0;
+ }
+
+ /* mask to manage sub operator sub and div */
+ switch (root->func) {
+ case Add:
+ nextmask &= ~MASK_SUB;
+ nextmask &= ~MASK_DIV;
+ break;
+ case Sub:
+ nextmask |= MASK_SUB;
+ nextmask &= ~MASK_DIV;
+ break;
+ case Mul:
+ nextmask &= ~MASK_DIV;
+ break;
+ case Div:
+ nextmask |= MASK_DIV;
+ break;
+ default:
+ nextmask = mask;
+ }
+
+ switch (root->func) {
+ case Val:
+ case Sig:
+ op0 = (root->ops[0]) ? evaluate_element (root->ops[0], nextmask) : root->value;
+ break;
+ case Add:
+ case Sub:
+ case Mul:
+ case Div:
+ case Mod:
+ case Pow:
+ case Equal:
+ case Diff:
+ case Ge:
+ case Le:
+ case Gt:
+ case Lt:
+ case And:
+ case Or:
+ if (root->ops[1]) {
+ op1 = evaluate_element (root->ops[1], nextmask);
+ } else {
+ VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[1])\n"));
+ return 0;
+ }
+ /* fallthrough */
+ case Sqr:
+ case Cos:
+ case Sin:
+ case Tan:
+ case Acos:
+ case Asin:
+ case Atan:
+ case Ln:
+ case Log:
+ case Exp:
+ case Erfc:
+ case Erf:
+ case Abs:
+ case Ceil:
+ case Floor:
+ case Recall:
+ case Inc:
+ case Dec:
+ case Not:
+ case Cond:
+ case Prog:
+ case Arg:
+ case Call:
+ case Edit:
+ case Del:
+ case Get:
+ if (root->ops[0]) {
+ op0 = evaluate_element (root->ops[0], 0);
+ } else {
+ VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
+ return 0;
+ }
+ break;
+ case Disp:
+ case Clear:
+ case Quit:
+ case Help:
+ case Ans:
+ case Pi:
+ case E:
+ case Code:
+ case List:
+ case Length:
+ case Pop:
+ case Set:
+ case Show:
+ case Median:
+ case Order:
+ case Prod:
+ case Sum:
+ break;
+ case While:
+ if (root->ops[0] == NULL) {
+ VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
+ return 0;
+ }
+ break;
+ case Memory:
+ if (root->ops[0] == NULL) {
+ op0 = -1;
+ } else {
+ op0 = (int)evaluate_element (root->ops[0], 0);
+ if (op0 < 0) {
+ VERBOSE (WARNING, fprintf (stdout, "error incorrect memory size (%d)\n", (int)op0));
+ return 0;
+ }
+ }
+ break;
+ case Push:
+ case Print:
+ op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : answer;
+ break;
+ case Store:
+ case Put:
+ if (root->ops[0]) {
+ op0 = evaluate_element (root->ops[0], 0);
+ } else {
+ VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
+ return 0;
+ }
+ op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : answer;
+ break;
+ case Max:
+ case Mean:
+ case Min:
+ case Variance:
+ if (root->ops[0]) {
+ op0 = evaluate_element (root->ops[0], 0);
+ op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : answer;
+ }
+ break;
+ case Precision:
+ op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : -1;
+ break;
+ case Base:
+ op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : -1;
+ op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : -1;
+ break;
+ }
+
+ switch (root->func) {
+ case Val: return op0;
+ case Sig: return -op0;
+ case Add: return ((mask & MASK_SUB) == 0) ? op0 + op1 : op0 - op1;
+ case Sub: return ((mask & MASK_SUB) == 0) ? op0 - op1 : op0 + op1;
+ case Mul: return ((mask & MASK_DIV) == 0) ? op0 * op1 : op0 / op1;
+ case Div: return ((mask & MASK_DIV) == 0) ? op0 / op1 : op0 * op1;
+ case Mod: return fmod (op0, op1);
+ case Pow: return pow (op0, op1);
+ case Sqr: return sqrt (op0);
+ case Cos: return cos (op0);
+ case Sin: return sin (op0);
+ case Tan: return tan (op0);
+ case Acos: return acos (op0);
+ case Asin: return asin (op0);
+ case Atan: return atan (op0);
+ case Ln: return log (op0);
+ case Log: return log10 (op0);
+ case Exp: return exp (op0);
+ case Erfc: return erfc (op0);
+ case Erf: return erf (op0);
+ case Abs: return fabs (op0);
+ case Ceil: return ceil (op0);
+ case Floor: return floor (op0);
+ case Store: return store ((int)op0, op1);
+ case Recall: return recall ((int)op0);
+ case Inc: return increase ((int)op0);
+ case Dec: return decrease ((int)op0);
+ case Disp: display (); break;
+ case Memory: return memory ((root->ops[0]) ? (int)op0 : -1);
+ case Clear: clear (); break;
+ case Quit: quit (); break;
+ case Help: help (); break;
+ case Ans: return answer;
+ case Pi: return M_PI;
+ case E: return M_E;
+ case Equal: return op0 == op1;
+ case Diff: return op0 != op1;
+ case Ge: return op0 >= op1;
+ case Le: return op0 <= op1;
+ case Gt: return op0 > op1;
+ case Lt: return op0 < op1;
+ case And: return (op0 != 0) && (op1 != 0);
+ case Or: return (op0 != 0) || (op1 != 0);
+ case Not: return (op0 == 0);
+ case Cond:
+ if ((op0) && (root->ops[1])) {
+ return evaluate_element (root->ops[1], 0);
+ } else if ((!op0) && (root->ops[2])) {
+ return evaluate_element (root->ops[2], 0);
+ } else {
+ return 0;
+ }
+ case While: return while_do (root->ops[0], root->ops[1]);
+ case Code: return execute_code (root->ops, root->nbops);
+ case Print: return print (op0);
+ case Prog:
+ prog ((int)op0, root->ops[1]);
+ savestring ((int)op0, root->string);
+ break;
+ case Arg: return arg ((int)op0);
+ case Call:
+ for (i = 1, nb = 0; i < root->nbops; i++) {
+ if (root->ops[i]) {
+ nb++;
+ }
+ }
+ return call ((int)op0, nb, root->ops + 1);
+ case List: list (); break;
+ case Edit: edit ((int)op0); break;
+ case Del: del ((int)op0); break;
+ case Get: return get ((int)op0);
+ case Length: return length ();
+ case Pop: return pop ();
+ case Push: return push (op0);
+ case Put: return put ((int)op0, op1);
+ case Set:
+ for (i = 0, nb =0; i < root->nbops; i++) {
+ if (root->ops[i]) {
+ nb++;
+ }
+ }
+ return set (nb, root->ops);
+ case Show: show (); break;
+ case Max:
+ if (root->ops[0]) {
+ return op0 > op1 ? op0 : op1;
+ }
+ return max ();
+ case Mean:
+ if (root->ops[0]) {
+ return (op0 + op1) / 2;
+ }
+ return mean ();
+ case Median: return median ();
+ case Min:
+ if (root->ops[0]) {
+ return op0 < op1 ? op0 : op1;
+ }
+ return min ();
+ case Order: order (); break;
+ case Prod: return prod ();
+ case Sum: return sum ();
+ case Variance:
+ if (root->ops[0]) {
+ double m = (op0 + op1) / 2;
+ op0 -= m;
+ op1 -= m;
+ return op0 * op0 + op1 * op1;
+ }
+ return variance ();
+ case Precision:
+ return format ((int)op0);
+ case Base:
+ base ((int)op0, (int)op1);
+ break;
+ }
+
+ return 0;
+}
+
+char **generate_completion_list ()
+{
+ int i, j, l = 0;
+ char **list = (char **) callocordie (NB_OPERATORS + NB_FUNCTIONS + NB_CONSTANTS + NB_SYMBOLS + 1, sizeof (char *));
+
+ for (i = 0; i < NB_OPERATORS; i++) {
+ list[l] = strdup ((operators + i)->keyword);
+ for (j = 0; j < (int)strlen (list[l]); j++) {
+ if (list[i][j] == '\t') {
+ list[i][j] = '\0';
+ }
+ }
+ if (list[l] != NULL) {
+ l++;
+ }
+ }
+
+ for (i = 0; i < NB_FUNCTIONS; i++) {
+ list[l] = strdup ((functions + i)->keyword);
+ if (list[l] != NULL) {
+ l++;
+ }
+ }
+
+ for (i = 0; i < NB_CONSTANTS; i++) {
+ list[l] = strdup ((constants + i)->keyword);
+ if (list[l] != NULL) {
+ l++;
+ }
+ }
+
+ for (i = 0; i < NB_SYMBOLS; i++) {
+ list[l] = strdup (symbols[i]);
+ if (list[l] != NULL) {
+ l++;
+ }
+ }
+
+ return (list);
+}
+
+void free_completion_list (char **list)
+{
+ int i;
+
+ if (list) {
+ for (i = 0; i < NB_OPERATORS + NB_FUNCTIONS + NB_CONSTANTS + NB_SYMBOLS + 1; i++) {
+ if (list[i] != NULL) {
+ free (list[i]);
+ }
+ }
+ free (list);
+ }
+}
+