new type tab_t and rebuild of stack
authorLaurent Mazet <mazet@softndesign.org>
Sun, 12 Feb 2023 13:42:53 +0000 (14:42 +0100)
committerLaurent Mazet <mazet@softndesign.org>
Sun, 12 Feb 2023 13:42:53 +0000 (14:42 +0100)
calc.c
program.c
program.h
stack.c
stack.h
tabular.c [new file with mode: 0644]
tabular.h [new file with mode: 0644]

diff --git a/calc.c b/calc.c
index 4ef05d76dd50daccd656e41a9b996031a393ce95..7cc1c3f5b3ccc08c79733a6156dea2af2d43c6ae 100644 (file)
--- a/calc.c
+++ b/calc.c
@@ -1,6 +1,6 @@
 /* depend: */
 /* cflags: */
-/* linker: alloc.o debug.o element.o format.o parser.o program.o stack.o storage.o -lm -lreadline */
+/* linker: alloc.o debug.o element.o format.o parser.o program.o stack.o storage.o tabular.o -lm -lreadline */
 
 #include <malloc.h>
 #include <stddef.h>
index 3c94986fbbc7c1f7f2b2a9dac321c3a5db476ec2..97f99293114bd95b76ac4601d62c4b5645fd1a4f 100644 (file)
--- a/program.c
+++ b/program.c
@@ -6,6 +6,7 @@
 #include "parser.h"
 #include "stack.h"
 #include "storage.h"
+#include "tabular.h"
 
 #include "program.h"
 
@@ -54,7 +55,7 @@ void prog (int id, element_t *root)
                 free ((programs + n)->storage);
             }
             if ((programs + n)->stack) {
-                free ((programs + n)->stack);
+                free_tab ((programs + n)->stack);
             }
             if ((programs + n)->root) {
                 delelement ((programs + n)->root);
@@ -72,7 +73,6 @@ void prog (int id, element_t *root)
     (programs + n)->storage = NULL;
     (programs + n)->storage_size = 0;
     (programs + n)->stack = NULL;
-    (programs + n)->stack_size = 0;
     (programs + n)->root = dupelement (root);
 }
 
@@ -115,7 +115,6 @@ double call (int id, int nbargs, element_t **args)
     tmp.storage = storage;
     tmp.storage_size = storage_size;
     tmp.stack = stack;
-    tmp.stack_size = stack_size;
 
     /* change context */
     answer = 0;
@@ -124,7 +123,6 @@ double call (int id, int nbargs, element_t **args)
     argument = NULL;
     argument_size = 0;
     stack = (programs + n)->stack;
-    stack_size = (programs + n)->stack_size;
     if (nbargs > 0) {
         argument = (double *) callocordie (nbargs, sizeof (double));
         for (i = 0, l = 0; i < nbargs; l++) {
@@ -146,7 +144,6 @@ double call (int id, int nbargs, element_t **args)
         free (argument);
     }
     (programs + n)->stack = stack;
-    (programs + n)->stack_size = stack_size;
 
     /* restore context */
     answer = tmp.answer;
@@ -155,7 +152,6 @@ double call (int id, int nbargs, element_t **args)
     argument = tmp.argument;
     argument_size = tmp.argument_size;
     stack = tmp.stack;
-    stack_size = tmp.stack_size;
 
     return ret;
 }
@@ -246,7 +242,7 @@ void del (int id)
         free ((programs + n)->storage);
     }
     if ((programs + n)->stack) {
-        free ((programs + n)->stack);
+        free_tab ((programs + n)->stack);
     }
     if ((programs + n)->root) {
         delelement ((programs + n)->root);
index 8fdca142c58a6085e4ede4503354fa56e7fc05ed..65382d9dca4aaff82f248b52876f31c2272a4aec 100644 (file)
--- a/program.h
+++ b/program.h
@@ -2,6 +2,7 @@
 #define __PROGRAM_H__
 
 #include "element.h"
+#include "tabular.h"
 
 /* global variables */
 
@@ -18,8 +19,7 @@ typedef struct _workspace_t {
     double *argument;
     int argument_size;
     element_t *root;
-    double *stack;
-    int stack_size;
+    tab_t *stack;
     char *string;
 } workspace_t;
 
diff --git a/stack.c b/stack.c
index 5c203edfdd54a0a940be9a0432bf49b14d589d6d..829f8aa6483f9357861680931a49a54d0a045799 100644 (file)
--- a/stack.c
+++ b/stack.c
-#include <malloc.h>
 #include <stdio.h>
-#include <string.h>
 
-#include "alloc.h"
 #include "debug.h"
 #include "format.h"
 #include "parser.h"
+#include "tabular.h"
 
 #include "stack.h"
 
 /* global variables */
 
-int stack_size = 0;
-double *stack = NULL;
+tab_t * stack = NULL;
 
 /* 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;
+    return get_tab (stack, n);
 }
 
 double length ()
 {
-    return stack_size;
+    return size_tab (stack);
 }
 
 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;
+    return pop_tab (stack, -1);
 }
 
 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;
+    return push_tab (stack, -1, 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 > size_tab (stack)) {
+        stack = resize_tab (stack, n);
     }
-    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;
+    return set_tab (stack, n, 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;
+    stack = resize_tab (stack, nbops);
+    for (i = 0; i < nbops; i++) {
+        set_tab (stack, i + 1, evaluate_element (ops[i], 0));
+    }
+    return size_tab (stack);
 }
 
 void show (void)
 {
-    int i;
+    int i, n = size_tab (stack);
     fprintf (stdout, "stack:");
-    for (i = 0; i < stack_size; i++) {
+    for (i = 0; i < n; i++) {
         fprintf (stdout, " ");
-        fprintf (stdout, minform, stack[i]);
+        fprintf (stdout, minform, get_tab (stack, i + 1));
     }
     fprintf (stdout, "\n");
 }
@@ -110,15 +67,16 @@ void show (void)
 double max ()
 {
     double ret = 0;
-    int i;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 1) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    ret = stack[0];
-    for (i = 1; i < stack_size; i++) {
-        if (stack[i] > ret) {
-            ret = stack[i];
+    ret = get_tab (stack, 1);
+    for (i = 1; i < n; i++) {
+        double cur = get_tab (stack, i + 1);
+        if (cur > ret) {
+            ret = cur;
         }
     }
     return ret;
@@ -127,29 +85,30 @@ double max ()
 double mean ()
 {
     double ret = 0;
-    int i;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 1) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    for (i = 0; i < stack_size; i++) {
-        ret += stack[i];
+    for (i = 0; i < n; i++) {
+        ret += get_tab (stack, i + 1);
     }
-    return ret / stack_size;
+    return ret / n;
 }
 
 double min ()
 {
     double ret = 0;
-    int i;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 1) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    ret = stack[0];
-    for (i = 1; i < stack_size; i++) {
-        if (stack[i] < ret) {
-            ret = stack[i];
+    ret = get_tab (stack, 1);
+    for (i = 1; i < n; i++) {
+        double cur = get_tab (stack, i + 1);
+        if (cur < ret) {
+            ret = cur;
         }
     }
     return ret;
@@ -157,53 +116,39 @@ double min ()
 
 void order ()
 {
-    int i, j;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
-        return;
-    }
-    for (i = 0; i < stack_size - 1; i++) {
-        int done = 0;
-        for (j = 0; j < stack_size - 1; j++) {
-            if (stack[j] > stack[j + 1]) {
-                double tmp = stack[j];
-                stack[j] = stack[j + 1];
-                stack[j + 1] = tmp;
-                done = 1;
-            }
-        }
-        if (done == 0) {
-            break;
-        }
+    int n = size_tab (stack);
+    if (n < 3) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
+    } else {
+        order_tab (stack);
     }
 }
 
 double median ()
 {
     double ret = 0;
-    if (stack_size < 3) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
-        return 0;
+    int n = size_tab (stack);
+    if (n < 3) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
+    } else {
+        tab_t *tmp = copy_tab (stack);
+        order_tab (tmp);
+        ret = get_tab (tmp, (n - 1) / 2 + 1);
+        free_tab (tmp);
     }
-    double *tmp = (double *) callocordie (stack_size, sizeof (double));
-    memcpy (tmp, stack, stack_size * sizeof (double));
-    order ();
-    ret = stack[(stack_size - 1)/ 2];
-    memcpy (stack, tmp, stack_size * sizeof (double));
-    free (tmp);
     return ret;
 }
 
 double prod ()
 {
     double ret = 1;
-    int i;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 1) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    for (i = 0; i < stack_size; i++) {
-        ret *= stack[i];
+    for (i = 0; i < n; i++) {
+        ret *= get_tab (stack, i + 1);
     }
     return ret;
 }
@@ -211,13 +156,13 @@ double prod ()
 double sum ()
 {
     double ret = 0;
-    int i;
-    if (stack_size < 1) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 1) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    for (i = 0; i < stack_size; i++) {
-        ret += stack[i];
+    for (i = 0; i < n; i++) {
+        ret += get_tab (stack, i + 1);
     }
     return ret;
 }
@@ -225,17 +170,17 @@ double sum ()
 double variance ()
 {
     double ret = 0;
-    double m = 0;
-    int i;
-    if (stack_size < 2) {
-        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size));
+    int i, n = size_tab (stack);
+    if (n < 2) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", n));
         return 0;
     }
-    m = mean ();
-    for (i = 0; i < stack_size; i++) {
-        ret += (stack[i] - m) * (stack[i] - m);
+    double m = mean ();
+    for (i = 0; i < n; i++) {
+        double x = get_tab (stack, i + 1);
+        ret += (x - m) * (x - m);
     }
-    return ret / stack_size;
+    return ret / n;
 }
 
 /* vim: set ts=4 sw=4 et: */
diff --git a/stack.h b/stack.h
index e3f0c441aba4d8299a346f2821a0394ec408c96a..90460ab7c76cc27242bc7fe26fc6041918cd0484 100644 (file)
--- a/stack.h
+++ b/stack.h
@@ -2,12 +2,11 @@
 #define __STACK_H__
 
 #include "element.h"
+#include "tabular.h"
 
 /* global variables */
 
-extern int stack_size;
-
-extern double *stack;
+extern tab_t *stack;
 
 /* stack management */
 
diff --git a/tabular.c b/tabular.c
new file mode 100644 (file)
index 0000000..0252a8e
--- /dev/null
+++ b/tabular.c
@@ -0,0 +1,180 @@
+#include <malloc.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "debug.h"
+#include "alloc.h"
+
+#include "tabular.h"
+
+/* management function */
+
+/* allocate a tab of N elements */
+
+tab_t *alloc_tab (int nb)
+{
+    tab_t *tab = (tab_t *) callocordie (1, sizeof (tab_t));
+    if (nb > 0) {
+        tab->data = (double *) callocordie (nb, sizeof (double));
+        tab->size = nb;
+    }
+    return (tab);
+}
+
+/* resize a tab to size N */
+
+tab_t *resize_tab (tab_t *tab, int nb)
+{
+    double *tmp = NULL;
+    tab = (tab) ? tab : (tab_t *) callocordie (1, sizeof (tab_t));
+    nb = (nb > 0) ? nb : 0;
+    if (nb > 0) {
+        tmp = (double *) callocordie (nb, sizeof (double));
+        memcpy (tmp, tab->data, ((tab->size < nb) ? tab->size : nb) * sizeof (double));
+    }
+    free (tab->data);
+    tab->data = tmp;
+    tab->size = nb;
+    return tab;
+}
+
+/* copy a tab */
+
+tab_t *copy_tab (tab_t *tab)
+{
+    tab_t *new = alloc_tab (tab->size);
+    memcpy (new->data, tab->data, tab->size * sizeof (double));
+    return new;
+}
+
+/* free a tab */
+
+void free_tab (tab_t *tab)
+{
+    if (tab) {
+        if (tab->data) {
+            free (tab->data);
+        }
+        free (tab);
+    }
+}    
+
+/* get table size */
+
+int size_tab (tab_t *tab)
+{
+    int ret = 0;
+    if (tab) {
+        ret = tab->size;
+    }
+    return ret;
+}
+
+/* set an element into a tab at position id [1..N] */
+
+double set_tab (tab_t *tab, int id, double val)
+{
+    double ret = NAN;
+    if ((!tab) || (id < 1) || (id > tab->size)) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1] = val;
+    }
+    return ret;
+}
+
+/* get an element from a tab at position id [1..N] */
+
+double get_tab (tab_t *tab, int id)
+{
+    double ret = NAN;
+    if ((!tab) || (id < 1) || (id > tab->size)) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1];
+    }
+    return ret;
+}
+
+/* push an element into a tab at position id [1.. N](-1 means end) resulting to a tab of N+1 elements */
+
+double push_tab (tab_t *tab, int id, double val)
+{
+    double ret = NAN;
+    if ((!tab) || (((id < 1) || (id > tab->size + 1)) && (id != -1))) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+
+        /* special case for inserting an element at the end */
+        id = (id == -1) ? tab->size + 1 : id;
+
+        /* create larger tab */
+        double *tmp = (double *) callocordie (tab->size + 1, sizeof (double));
+        memcpy (tmp, tab->data, (id - 1) * sizeof (double));
+        ret = tmp[id - 1] = val;
+        memcpy (tmp + id , tab->data + id - 1, (tab->size - id + 1) * sizeof (double));
+
+        /* update structure */
+        free (tab->data);
+        tab->data = tmp;
+        tab->size++;
+    }
+    return ret;
+}
+
+/* pop an element from a tab at position id [1.. N](-1 means last) resulting to a tab of N-1 elements */
+
+double pop_tab (tab_t *tab, int id)
+{
+    double ret = NAN;
+    if ((!tab) || (((id < 1) || (id > tab->size)) && (id != -1))) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1];
+
+        /* special case for inserting an element at the end */
+        id = (id == -1) ? tab->size : id;
+
+        /* create larger tab */
+        double *tmp = (double *) callocordie (tab->size - 1, sizeof (double));
+        memcpy (tmp, tab->data, (id - 1) * sizeof (double));
+        memcpy (tmp + id - 1, tab->data + id, (tab->size - id) * sizeof (double));
+
+        /* update structure */
+        free (tab->data);
+        tab->data = tmp;
+        tab->size--;
+    }
+    return ret;
+}
+
+/* sort tab */
+
+void order_tab (tab_t *tab)
+{
+    int i, j;
+    if ((!tab) || (tab->size < 3)) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", tab->size));
+        return;
+    }
+
+    /* buble sort */
+    for (i = 0; i < tab->size - 1; i++) {
+        int done = 0;
+        for (j = 0; j < tab->size - 1; j++) {
+            double tab_j = tab->data[j];
+            double tab_jp1 = tab->data[j + 1];
+            if (tab_j > tab_jp1) {
+                tab->data[j] = tab_jp1;
+                tab->data[j + 1] = tab_j;
+                done = 1;
+            }
+        }
+        if (done == 0) {
+            break;
+        }
+    }
+}
+
+/* vim: set ts=4 sw=4 et: */
diff --git a/tabular.h b/tabular.h
new file mode 100644 (file)
index 0000000..d5c03a6
--- /dev/null
+++ b/tabular.h
@@ -0,0 +1,31 @@
+#ifndef __TABULAR_H__
+#define __TABULAR_H__
+
+#include "debug.h"
+#include "alloc.h"
+
+#include "tabular.h"
+
+/* tabular type */
+
+typedef struct {
+    double *data;
+    int size;
+} tab_t;
+
+/* management function */
+
+tab_t *alloc_tab (int nb);
+tab_t *resize_tab (tab_t *tab, int nb);
+tab_t *copy_tab (tab_t *tab);
+void free_tab (tab_t *tab);
+int size_tab (tab_t *tab);
+double set_tab (tab_t *tab, int id, double val);
+double get_tab (tab_t *tab, int id);
+double push_tab (tab_t *tab, int id, double val);
+double pop_tab (tab_t *tab, int id);
+void order_tab (tab_t *tab);
+
+#endif /* __TABULAR_H__ */
+
+/* vim: set ts=4 sw=4 et: */