stack management
authorLaurent Mazet <mazet@softndesign.org>
Sat, 4 Feb 2023 21:38:32 +0000 (22:38 +0100)
committerLaurent Mazet <mazet@softndesign.org>
Sat, 4 Feb 2023 21:38:32 +0000 (22:38 +0100)
calc.c
parser.c
parser.h

diff --git a/calc.c b/calc.c
index 87e24e6693fb8a1015b0c8b92027a0260ec2a765..c31743d0193696c94db512c12ddfc04185a5e6ee 100644 (file)
--- a/calc.c
+++ b/calc.c
@@ -384,6 +384,12 @@ int main (int argc, char *argv[])
 // test: echo -e 'prog (2, 2, {rcl (2) - rcl (1)})\nprog (3, 1, cos(rcl (1) * pi / 3))\ncall (1, 2, 3)\nls\nedit (1)\ndel (1)\n\ndel (2)\ncall (2, 1, 4)' | calc.exe | grep -c error | xargs test 4 =
 // test: echo -e 'erf (1)\nerfc (1)\nquit' | calc.exe -v 3 | grep -q bye
 // test: echo -e 'erf ()\nerfc ()' | calc.exe | grep -c error | xargs test 2 =
+// test: echo -e 'set (1, 2, 3, 3.11, pi, 4)\nget (4)' | calc.exe | grep '=> 3.11'
+// test: echo -e 'set (1, 2, 3, 3.11, pi, 4)\npop\npop\n5\npush\nshow' | calc.exe | grep 'stack: 1 2 3 3.11 5'
+// test: echo -e 'set (1, 2, 3, 3.11, pi, 4)\nset\nput (3, 4)\nshow' | calc.exe | grep 'stack: 0 0 4'
+// test: echo -e 'set (1, 2, 3, 3.11, pi, 4)\nlen' | calc.exe | grep '=> 6'
+// test: echo -e 'set (1, 2)\npop\npush (3)\nput (5, -1)\nlen\nshow\nget (3)\nquit' | calc.exe -n -v 3 | grep -q bye
+// test: echo -e 'put\nget\nget (1)\npop\nput (0)' | calc.exe | grep -c 'error' | xargs test 5 =
 
 // Gauss sequence
 // test: echo -e '{sto (1, 0), sto (10, 0), while (inc (10) < 100, {sto (1, rcl (1) + rcl (10)), print (rcl (1))})};' | calc.exe | grep -q '=> 5050'
index b2ef505fc4d5ff77505222ce8524b6f946ea2d3d..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 34
+#define NB_FUNCTIONS 41
 keyword_t functions[NB_FUNCTIONS] = {
     { "sqrt", Sqr, 1, 4, 5},
     { "pow",  Pow, 2, 3, 5},
@@ -162,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
@@ -554,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);
@@ -780,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);
             }
@@ -795,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);
 }
 
@@ -823,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));
@@ -848,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;
 }
@@ -936,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);
     }
@@ -956,6 +988,97 @@ 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)
@@ -981,6 +1104,8 @@ void help (void)
     fprintf (stdout, " cond print while {} ;\n");
     fprintf (stdout, "program management:");
     fprintf (stdout, " call del edit ls prog\n");
+    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, "constants:");
@@ -1075,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 {
@@ -1091,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) {
@@ -1098,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) {
@@ -1173,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;
index 95ee0e594176d6ef31e02e238a2ca00fb6c83ae6..9458aec699e7029931dc29398f7aa490f1a31a20 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -22,7 +22,8 @@ typedef enum {
     Equal, Diff, Ge, Le, Gt, Lt,
     And, Or, Not,
     Cond, While, Code, Print,
-    Prog, Call, List, Edit, Del
+    Prog, Call, List, Edit, Del,
+    Get, Length, Pop, Push, Put, Set, Show
 } func_t;
 
 /* keyword type */
@@ -57,6 +58,8 @@ typedef struct _workspace_t {
     double *storage;
     int storage_size;
     element_t *root;
+    double *stack;
+    int stack_size;
     char *string;
 } workspace_t;