#define DEFAULT_STORAGE_SIZE 10
int storage_size = -1;
-
double *storage = NULL;
+int argument_size = 0;
+double *argument = NULL;
+
+int stack_size = 0;
+double *stack = NULL;
+
#define DEFAULT_FORMAT "=> %.6g\n"
char *format = NULL;
char *minform = NULL;
/* functions */
+#define MAX_ARGS 100
+
#define NB_OPERATORS 14
keyword_t operators[NB_OPERATORS] = {
{ "+\t", Add, 2, 1, 1},
{ "|", Or, 2, 1, -2}
};
-#define NB_FUNCTIONS 31
+#define NB_FUNCTIONS 50
keyword_t functions[NB_FUNCTIONS] = {
{ "sqrt", Sqr, 1, 4, 5},
{ "pow", Pow, 2, 3, 5},
{ "acos", Acos, 1, 4, 5},
{ "asin", Asin, 1, 4, 5},
{ "atan", Atan, 1, 4, 5},
+ { "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},
{ "inc", Inc, 1, 3, 5},
{ "dec", Dec, 1, 3, 5},
{ "disp", Disp, 0, 4, 9},
- { "mem", Mem, 1, 3, 9},
+ { "mem", Mem, 1, 3, 5},
{ "clr", Clear, 0, 3, 9},
{ "quit", Quit, 0, 4, 9},
{ "help", Help, 0, 4, 9},
{ "cond", Cond, 3, 4, 5},
{ "while", While, 2, 5, 5},
{ "print", Print, 1, 5, 5},
- { "prog", Prog, 3, 4, 9},
- { "call", Call, 10, 4, 5},
+ { "prog", Prog, 2, 4, 9},
+ { "arg", Arg, 1, 3, 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, 5},
+ { "show", Show, 0, 4, 5},
+ { "max", Max, 2, 3, 5},
+ { "mean", Mean, 2, 4, 5},
+ { "med", Median, 0, 3, 5},
+ { "min", Min, 2, 3, 5},
+ { "ord", Order, 0, 3, 5},
+ { "prod", Prod, 0, 4, 5},
+ { "sum", Sum, 0, 3, 5},
+ { "var", Variance, 2, 3, 5},
};
#define NB_CONSTANTS 3
delelement (root);
return ERROR_OP;
}
- element_t *newprog = newelement (Code, root->nbops + 1, 5);
+ element_t *newcode = newelement (Code, root->nbops + 1, 5);
for (i = 0; i < root->nbops; i++) {
- newprog->ops[i] = root->ops[i];
+ newcode->ops[i] = root->ops[i];
root->ops[i] = NULL;
}
- newprog->ops[root->nbops] = new;
+ newcode->ops[root->nbops] = new;
delelement (root);
- root = newprog;
+ root = newcode;
} while (*str == ',');
if (*str != '}') {
keyword_t *operator = operators + i;
if (codecmp (operator->keyword, str) == 0) {
VERBOSE (DEBUG, fprintf (stdout, "start processing operator\n"));
- if (root) {
+ if ((root) && (root->prio == 9)) {
+ VERBOSE (DEBUG, fprintf (stdout, "terminal function (%d)\n", root->func));
+ delelement (root);
+ return ERROR_OP;
+ } else if (root) {
if ((prio) && (prio > operator->prio)) {
VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
*next = str;
return ERROR_OP;
}
} else if (*str == '-') {
- root = newelement (Sig, 1, 9);
+ root = newelement (Sig, 1, 6);
} else {
return ERROR_OP;
}
case Acos: func = "Arc Cosine"; break;
case Asin: func = "Arc Sine"; break;
case Atan: func = "Arc Tangent"; break;
- case Log: func = "Logarithm"; 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;
case Code: func = "Code"; break;
case Print: func = "Print"; break;
case Prog: func = "Program"; break;
+ case Arg: func = "Argument"; break;
case Call: func = "Call"; break;
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;
+ case Max: func = "Maximum"; break;
+ case Mean: func = "Mean"; break;
+ case Median: func = "Median"; break;
+ case Min: func = "Minimum"; break;
+ case Order: func = "Order"; break;
+ case Prod: func = "Product"; break;
+ case Sum: func = "Sum"; break;
+ case Variance: func = "Variance"; break;
}
fprintf (stdout, "Function: %s\n", func);
/* program function */
-void prog (int id, int nbmems, element_t *root)
+void prog (int id, element_t *root)
{
int i, n = -1;
if ((programs + n)->storage) {
free ((programs + n)->storage);
}
+ if ((programs + n)->stack) {
+ free ((programs + n)->stack);
+ }
if ((programs + n)->root) {
delelement ((programs + n)->root);
}
/* set program */
(programs + n)->id = id;
(programs + n)->answer = 0;
- (programs + n)->storage = (double *) callocordie (nbmems, sizeof (double));
- (programs + n)->storage_size = nbmems;
+ (programs + n)->storage = NULL;
+ (programs + n)->storage_size = 0;
+ (programs + n)->stack = NULL;
+ (programs + n)->stack_size = 0;
(programs + n)->root = dupelement (root);
}
-double call (int id, int nbops, element_t **ops)
+double arg (int id)
+{
+ double ret = 0;
+ if ((id <= 0) || (id > argument_size)) {
+ VERBOSE (WARNING, fprintf (stdout, "error out of bound (%d/%d)\n", id, argument_size));
+ } else {
+ ret = argument[id - 1];
+ }
+ return ret;
+}
+
+double call (int id, int nbargs, element_t **args)
{
workspace_t tmp = {0};
- int i, n = -1;
+ int i, l, n = -1;
double ret = 0;
if (programs) {
/* store context */
tmp.answer = answer;
+ tmp.argument = argument;
+ tmp.argument_size = argument_size;
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;
- if (nbops > storage_size) {
- double *tmp = (double *) callocordie (nbops, sizeof (double));
- memcpy (tmp, storage, storage_size * sizeof (double));
- free (storage);
- storage = tmp;
- storage_size = nbops;
- }
- for (i = 0; i < nbops; i++) {
- double val = evaluate_element (ops[i], 0);
- store (i + 1, val);
+ 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++) {
+ if (args[l]) {
+ argument[i++] = evaluate_element (args[l], 0);
+ }
+ }
+ argument_size = nbargs;
}
/* evaluate program */
element_t *elements = dupelement ((programs + n)->root);
ret = evaluate_element (elements, 0);
delelement (elements);
+ (programs + n)->answer = answer;
+ (programs + n)->storage = storage;
+ (programs + n)->storage_size = storage_size;
+ if (argument) {
+ free (argument);
+ }
+ (programs + n)->stack = stack;
+ (programs + n)->stack_size = stack_size;
/* restore context */
answer = tmp.answer;
storage = tmp.storage;
storage_size = tmp.storage_size;
+ argument = tmp.argument;
+ argument_size = tmp.argument_size;
+ stack = tmp.stack;
+ stack_size = tmp.stack_size;
return ret;
}
// free ((programs + n)->string);
//}
- (programs + n)->string = strdup (string);
+ if (string) {
+ (programs + n)->string = strdup (string);
+ }
}
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);
}
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");
+}
+
+/* stack functions */
+
+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));
+ return 0;
+ }
+ ret = stack[0];
+ for (i = 1; i < stack_size; i++) {
+ if (stack[i] > ret) {
+ ret = stack[i];
+ }
+ }
+ return ret;
+}
+
+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));
+ return 0;
+ }
+ for (i = 0; i < stack_size; i++) {
+ ret += stack[i];
+ }
+ return ret / stack_size;
+}
+
+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));
+ return 0;
+ }
+ ret = stack[0];
+ for (i = 1; i < stack_size; i++) {
+ if (stack[i] < ret) {
+ ret = stack[i];
+ }
+ }
+ return ret;
+}
+
+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;
+ }
+ }
+}
+
+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;
+ }
+ 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));
+ return 0;
+ }
+ for (i = 0; i < stack_size; i++) {
+ ret *= stack[i];
+ }
+ return ret;
+}
+
+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));
+ return 0;
+ }
+ for (i = 0; i < stack_size; i++) {
+ ret += stack[i];
+ }
+ return ret;
+}
+
+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));
+ return 0;
+ }
+ m = mean ();
+ for (i = 0; i < stack_size; i++) {
+ ret += (stack[i] - m) * (stack[i] - m);
+ }
+ return ret / stack_size;
+}
+
+
/* 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, " pow sqrt log exp\n");
- fprintf (stdout, "trig. func.:");
- fprintf (stdout, " cos sin tan acos asin atan\n");
- fprintf (stdout, "supported functions:");
+ 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 functions:");
- fprintf (stdout, " mem sto rcl inc dec disp\n");
- fprintf (stdout, "prog. functions:");
- fprintf (stdout, " cond while print {} ;\n");
- fprintf (stdout, "misc. functions:");
- fprintf (stdout, " quit help\n");
- fprintf (stdout, "supported constants:");
- fprintf (stdout, " e pi\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, " help quit\n");
+ fprintf (stdout, "constants:");
+ fprintf (stdout, " ans e pi\n");
}
/* evaluate element tree */
case Lt:
case And:
case Or:
- case Prog:
if (root->ops[1]) {
op1 = evaluate_element (root->ops[1], nextmask);
} else if (root->func != Store) {
case Acos:
case Asin:
case Atan:
+ case Ln:
case Log:
case Exp:
+ case Erfc:
+ case Erf:
case Abs:
case Ceil:
case Floor:
case Not:
case Mem:
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 {
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) {
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;
+ 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;
+ }
}
switch (root->func) {
case Acos: return acos (op0);
case Asin: return asin (op0);
case Atan: return atan (op0);
- case Log: return log (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 Code: return execute_code (root->ops, root->nbops);
case Print: return print (op0);
case Prog:
- prog ((int)op0, (int)op1, root->ops[2]);
+ 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]) {
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 ();
}
return 0;