stack management
[calc.git] / parser.c
index e20427cb0135215912ae9498ee4a5bb8e7f0c18d..4e360ddaf70bec25ea4cb46ad72bd2bb12aa276e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -14,9 +14,11 @@ double answer = 0;
 
 #define DEFAULT_STORAGE_SIZE 10
 int storage_size = -1;
-
 double *storage = NULL;
 
+int stack_size = 0;
+double *stack = NULL;
+
 #define DEFAULT_FORMAT "=> %.6g\n"
 char *format = NULL;
 char *minform = NULL;
@@ -112,6 +114,8 @@ element_t *dupelement (element_t *root)
 
 /* functions */
 
+#define MAX_ARGS 100
+
 #define NB_OPERATORS 14
 keyword_t operators[NB_OPERATORS] = {
     { "+\t", Add, 2, 1, 1},
@@ -130,7 +134,7 @@ keyword_t operators[NB_OPERATORS] = {
     { "|",   Or, 2, 1, -2}
 };
 
-#define NB_FUNCTIONS 32
+#define NB_FUNCTIONS 41
 keyword_t functions[NB_FUNCTIONS] = {
     { "sqrt", Sqr, 1, 4, 5},
     { "pow",  Pow, 2, 3, 5},
@@ -143,6 +147,8 @@ keyword_t functions[NB_FUNCTIONS] = {
     { "ln",   Ln, 1, 2, 5},
     { "log",  Log, 1, 3, 5},
     { "exp",  Exp, 1, 3, 5},
+    { "erfc", Erfc, 1, 4, 5},
+    { "erf",  Erf, 1, 3, 5},
     { "abs",  Abs, 1, 3, 5},
     { "floor", Floor, 1, 5, 5},
     { "ceil", Ceil, 1, 4, 5},
@@ -160,10 +166,17 @@ keyword_t functions[NB_FUNCTIONS] = {
     { "while", While, 2, 5, 5},
     { "print", Print, 1, 5, 5},
     { "prog", Prog, 3, 4, 9},
-    { "call", Call, 10, 4, 5},
+    { "call", Call, MAX_ARGS, 4, 5},
     { "ls",   List, 0, 2, 9},
     { "edit", Edit, 1, 4, 9},
-    { "del",  Del, 1, 3, 9}
+    { "del",  Del, 1, 3, 9},
+    { "get",  Get, 1, 3, 5},
+    { "len",  Length, 0, 3, 5},
+    { "pop",  Pop, 0, 3, 5},
+    { "push", Push, 1, 4, 5},
+    { "put",  Put, 2, 3, 5},
+    { "set",  Set, MAX_ARGS, 3, 9},
+    { "show",  Show, 0, 4, 9},
 };
 
 #define NB_CONSTANTS 3
@@ -514,9 +527,11 @@ void print_element (element_t *root, int level)
     case Acos: func = "Arc Cosine"; break;
     case Asin: func = "Arc Sine"; break;
     case Atan: func = "Arc Tangent"; break;
-    case Ln: func = "Logarithm (e base)"; break;
+    case Ln: func = "Logarithm (natural)"; break;
     case Log: func = "Logarithm (10 base)"; break;
     case Exp: func = "Exponantial"; break;
+    case Erfc: func = "Complementary Error Function"; break;
+    case Erf: func = "Error Function"; break;
     case Abs: func = "Absolute value"; break;
     case Ceil: func = "Ceil value"; break;
     case Floor: func = "Floor value"; break;
@@ -550,6 +565,13 @@ void print_element (element_t *root, int level)
     case List: func = "List"; break;
     case Edit: func = "Edit"; break;
     case Del: func = "Del"; break;
+    case Get: func = "Get"; break;
+    case Length: func = "Length"; break;
+    case Pop: func = "Pop"; break;
+    case Push: func = "Push"; break;
+    case Put: func = "Put"; break;
+    case Set: func = "Set"; break;
+    case Show: func = "Show"; break;
     }
 
     fprintf (stdout, "Function: %s\n", func);
@@ -776,6 +798,9 @@ void prog (int id, int nbmems, element_t *root)
             if ((programs + n)->storage) {
                 free ((programs + n)->storage);
             }
+            if ((programs + n)->stack) {
+                free ((programs + n)->stack);
+            }
             if ((programs + n)->root) {
                 delelement ((programs + n)->root);
             }
@@ -791,6 +816,8 @@ void prog (int id, int nbmems, element_t *root)
     (programs + n)->answer = 0;
     (programs + n)->storage = (double *) callocordie (nbmems, sizeof (double));
     (programs + n)->storage_size = nbmems;
+    (programs + n)->stack = NULL;
+    (programs + n)->stack_size = 0;
     (programs + n)->root = dupelement (root);
 }
 
@@ -819,11 +846,15 @@ double call (int id, int nbops, element_t **ops)
     tmp.answer = answer;
     tmp.storage = storage;
     tmp.storage_size = storage_size;
+    tmp.stack = stack;
+    tmp.stack_size = stack_size;
 
     /* change context */
     answer = 0;
     storage = (programs + n)->storage;
     storage_size = (programs + n)->storage_size;
+    stack = (programs + n)->stack;
+    stack_size = (programs + n)->stack_size;
     if (nbops > storage_size) {
         double *tmp = (double *) callocordie (nbops, sizeof (double));
         memcpy (tmp, storage, storage_size * sizeof (double));
@@ -844,7 +875,9 @@ double call (int id, int nbops, element_t **ops)
     /* restore context */
     answer = tmp.answer;
     storage = tmp.storage;
-    storage_size = tmp.storage_size;
+    storage = tmp.storage;
+    stack_size = tmp.stack_size;
+    stack_size = tmp.stack_size;
 
     return ret;
 }
@@ -932,6 +965,9 @@ void del (int id)
     if ((programs + n)->storage) {
         free ((programs + n)->storage);
     }
+    if ((programs + n)->stack) {
+        free ((programs + n)->stack);
+    }
     if ((programs + n)->root) {
         delelement ((programs + n)->root);
     }
@@ -952,32 +988,127 @@ void del (int id)
     nb_programs--;
 }
 
+/* stack management */
+
+double get (int n)
+{
+    double ret = 0;
+    if ((n <= 0) || (n > stack_size)) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bound (%d/%d)\n", n, stack_size));
+    } else {
+        ret = stack[n - 1];
+    }
+    return ret;
+}
+
+double length ()
+{
+    return stack_size;
+}
+
+double pop ()
+{
+    double ret = 0;
+    if (stack_size > 0) {
+        ret = stack[--stack_size];
+        double *tmp = (double *) callocordie (stack_size, sizeof (double));
+        memcpy (tmp, stack, stack_size * sizeof (double));
+        free (stack);
+        stack = tmp;
+    } else {
+        VERBOSE (WARNING, fprintf (stdout, "error stack empty\n"));
+    }
+    return ret;
+}
+
+double push (double val)
+{
+    double *tmp = (double *) callocordie (stack_size + 1, sizeof (double));
+    memcpy (tmp, stack, stack_size * sizeof (double));
+    if (stack) {
+        free (stack);
+    }
+    stack = tmp;
+    stack[stack_size++] = val;
+    return val;
+}
+
+double put (int n, double val)
+{
+    if (n <= 0) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bound (%d/%d)\n", n, stack_size));
+        return 0;
+    }
+    if (n > stack_size) {
+        double *tmp = (double *) callocordie (n, sizeof (double));
+        memcpy (tmp, stack, stack_size * sizeof (double));
+        free (stack);
+        stack = tmp;
+        stack_size = n;
+    }
+    stack[n - 1] = val;
+    return val;
+}
+
+double set (int nbops, element_t **ops)
+{
+    int i;
+    if (stack) {
+        free (stack);
+    }
+    stack = NULL;
+    stack_size = 0;
+    if (nbops != 0) {
+         stack = (double *) callocordie (nbops, sizeof (double));
+         for (i = 0; i < nbops; i++) {
+             stack[i] = evaluate_element (ops[i], 0);
+         }
+         stack_size = nbops;
+    }
+    return stack_size;
+}
+
+void show (void)
+{
+    int i;
+    fprintf (stdout, "stack:");
+    for (i = 0; i < stack_size; i++) {
+        fprintf (stdout, " ");
+        fprintf (stdout, minform, stack[i]);
+    }
+    fprintf (stdout, "\n");
+}
+
 /* help message */
 
 void help (void)
 {
     fprintf (stdout, "calc is a simple calculator\n\n");
-    fprintf (stdout, "supported operators:");
+    fprintf (stdout, "arithmetic op.:");
     fprintf (stdout, " + - * / %% ^\n");
-    fprintf (stdout, "camparison operators:");
+    fprintf (stdout, "comparison op.:");
     fprintf (stdout, " == != >= <= > <\n");
-    fprintf (stdout, "logical operators:");
+    fprintf (stdout, "logical op.:");
     fprintf (stdout, " & | !\n");
-    fprintf (stdout, "mathematic functions:");
+    fprintf (stdout, "mathematic func.:");
     fprintf (stdout, " exp ln log pow sqrt\n");
-    fprintf (stdout, "trig. func.:");
+    fprintf (stdout, "trigonometric func.:");
     fprintf (stdout, " acos asin atan cos sin tan\n");
-    fprintf (stdout, "supported functions:");
+    fprintf (stdout, "error functions:");
+    fprintf (stdout, " erf erfc\n");
+    fprintf (stdout, "miscellaneous func.:");
     fprintf (stdout, " abs ceil floor\n");
-    fprintf (stdout, "stor. functions:");
+    fprintf (stdout, "storage func.:");
     fprintf (stdout, " clear dec disp inc mem rcl sto\n");
-    fprintf (stdout, "cond. functions:");
+    fprintf (stdout, "control flow prim.:");
     fprintf (stdout, " cond print while {} ;\n");
-    fprintf (stdout, "prog. functions:");
+    fprintf (stdout, "program management:");
     fprintf (stdout, " call del edit ls prog\n");
-    fprintf (stdout, "misc. functions:");
+    fprintf (stdout, "stack management:");
+    fprintf (stdout, " get len pop push put set show\n");
+    fprintf (stdout, "control management:");
     fprintf (stdout, " help quit\n");
-    fprintf (stdout, "supported constants:");
+    fprintf (stdout, "constants:");
     fprintf (stdout, " ans e pi\n");
 }
 
@@ -1055,6 +1186,8 @@ double evaluate_element (element_t *root, char mask)
     case Ln:
     case Log:
     case Exp:
+    case Erfc:
+    case Erf:
     case Abs:
     case Ceil:
     case Floor:
@@ -1067,6 +1200,7 @@ double evaluate_element (element_t *root, char mask)
     case Call:
     case Edit:
     case Del:
+    case Get:
         if (root->ops[0]) {
             op0 = evaluate_element (root->ops[0], 0);
         } else {
@@ -1083,6 +1217,10 @@ double evaluate_element (element_t *root, char mask)
     case E:
     case Code:
     case List:
+    case Length:
+    case Pop:
+    case Set:
+    case Show:
         break;
     case While:
         if (root->ops[0] == NULL) {
@@ -1090,9 +1228,19 @@ double evaluate_element (element_t *root, char mask)
             return 0;
         }
         break;
+    case Push:
     case Print:
         op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : answer;
         break;
+    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;
     }
 
     switch (root->func) {
@@ -1114,6 +1262,8 @@ double evaluate_element (element_t *root, char mask)
     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);
@@ -1163,6 +1313,19 @@ double evaluate_element (element_t *root, char mask)
     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;
     }
 
     return 0;