X-Git-Url: https://secure.softndesign.org/git/?a=blobdiff_plain;f=parser.c;h=9e7e51013e3a050f04a8c48c9e28aa1e971be542;hb=a67f1cfd7bb89dfd00cdc099651b81456ca4c327;hp=b4381ac338dab2381eab0516100b276ad4779939;hpb=b9c1c40d714a293c6cbee5063b5e00de8ccacbe8;p=calc.git diff --git a/parser.c b/parser.c index b4381ac..9e7e510 100644 --- a/parser.c +++ b/parser.c @@ -12,8 +12,17 @@ double answer = 0; -#define STORAGE_SIZE 10 -double storage[STORAGE_SIZE] = {0}; +#define DEFAULT_STORAGE_SIZE 10 +int storage_size = -1; + +double *storage = NULL; + +#define DEFAULT_FORMAT "=> %.6g\n" +char *format = NULL; +char *minform = NULL; + +workspace_t *programs = NULL; +int nb_programs = 0; /* compare codes */ @@ -37,21 +46,28 @@ int codecmp (char *ref, char *str) return 0; } -/* allocate new element */ +/* calloc or die function */ -element_t *newelement (func_t function, int nbops, int prio) +void *callocordie (size_t count, size_t size) { - element_t *new = (element_t *) calloc (1, sizeof (element_t)); + if (count * size == 0) { + return NULL; + } + void *new = calloc (count, size); if (new == NULL) { VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n")); exit (1); } + return new; +} + +/* allocate new element */ + +element_t *newelement (func_t function, int nbops, int prio) +{ + element_t *new = (element_t *) callocordie (1, sizeof (element_t)); if (nbops) { - new->ops = (element_t **) calloc (nbops, sizeof (element_t *)); - if (new->ops == NULL) { - VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n")); - exit (1); - } + new->ops = (element_t **) callocordie (nbops, sizeof (element_t *)); } new->func = function; new->nbops = nbops; @@ -67,9 +83,7 @@ void delelement (element_t *root) if ((root != NULL) && (root != ERROR_OP)) { int i; for (i = 0; i < root->nbops; i++) { - if ((root->ops[i] != NULL) && (root->ops[i] != ERROR_OP)) { - delelement (root->ops[i]); - } + delelement (root->ops[i]); } if (root->nbops) { free (root->ops); @@ -116,7 +130,7 @@ keyword_t operators[NB_OPERATORS] = { { "|", Or, 2, 1, -2} }; -#define NB_FUNCTIONS 23 +#define NB_FUNCTIONS 31 keyword_t functions[NB_FUNCTIONS] = { { "sqrt", Sqr, 1, 4, 5}, { "pow", Pow, 2, 3, 5}, @@ -136,11 +150,19 @@ keyword_t functions[NB_FUNCTIONS] = { { "inc", Inc, 1, 3, 5}, { "dec", Dec, 1, 3, 5}, { "disp", Disp, 0, 4, 9}, + { "mem", Mem, 1, 3, 9}, + { "clr", Clear, 0, 3, 9}, { "quit", Quit, 0, 4, 9}, { "help", Help, 0, 4, 9}, { "!", Not, 1, 1, 6}, { "cond", Cond, 3, 4, 5}, - { "while", While, 2, 5, 5} + { "while", While, 2, 5, 5}, + { "print", Print, 1, 5, 5}, + { "prog", Prog, 3, 4, 9}, + { "call", Call, 10, 4, 5}, + { "ls", List, 0, 2, 9}, + { "edit", Edit, 1, 4, 9}, + { "del", Del, 1, 3, 9} }; #define NB_CONSTANTS 3 @@ -150,6 +172,11 @@ keyword_t constants[NB_CONSTANTS] = { { "pi", Pi, 0, 2, 5} }; +#define NB_SYMBOLS 4 +char *symbols[NB_SYMBOLS] = { + "(", ")", "{", "}" +}; + /* subparser function */ element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, int prio) @@ -177,6 +204,7 @@ element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, in element_t *parser (char *str, char **next, int prio) { element_t *root = NULL; + char *string = str; int i; VERBOSE (DEBUG, fprintf (stdout, "Starting parsing\n")); @@ -187,6 +215,15 @@ element_t *parser (char *str, char **next, int prio) element_t *new = NULL; VERBOSE (INFO, fprintf (stdout, "Processing: %s\n", str)); + /* end without printing */ + + if (*str == ';') { + if (root) { + root->hidden = 1; + } + break; + } + /* skip spaces and tabs */ if ((*str == ' ') || (*str == '\t')) { @@ -202,10 +239,7 @@ element_t *parser (char *str, char **next, int prio) delelement (root); return ERROR_OP; } - element_t **prog = NULL; - new = newelement (Prog, 0, 5); - root = new; - prog = &root; + root = newelement (Code, 0, 5); do { new = parser (str + 1, &str, 0); @@ -217,14 +251,14 @@ element_t *parser (char *str, char **next, int prio) delelement (root); return ERROR_OP; } - element_t *newprog = newelement (Prog, (*prog)->nbops + 1, 5); - for (i = 0; i < (*prog)->nbops; i++) { - newprog->ops[i] = (*prog)->ops[i]; - (*prog)->ops[i] = NULL; + element_t *newprog = newelement (Code, root->nbops + 1, 5); + for (i = 0; i < root->nbops; i++) { + newprog->ops[i] = root->ops[i]; + root->ops[i] = NULL; } - newprog->ops[(*prog)->nbops] = new; - delelement (*prog); - (*prog) = newprog; + newprog->ops[root->nbops] = new; + delelement (root); + root = newprog; } while (*str == ','); if (*str != '}') { @@ -440,6 +474,11 @@ element_t *parser (char *str, char **next, int prio) *next = str; } + /* save string */ + if (root != NULL) { + root->string = string; + } + return root; } @@ -484,6 +523,8 @@ void print_element (element_t *root, int level) case Inc: func = "Increase"; break; case Dec: func = "Decrease"; break; case Disp: func = "Display"; break; + case Mem: func = "Memory"; break; + case Clear: func = "Clear"; break; case Quit: func = "Quit"; break; case Help: func = "Help"; break; case Ans: func = "Ans"; break; @@ -500,7 +541,13 @@ void print_element (element_t *root, int level) case Not: func = "Not"; break; case Cond: func = "Condition"; break; case While: func = "While"; break; + case Code: func = "Code"; break; + case Print: func = "Print"; break; case Prog: func = "Program"; break; + case Call: func = "Call"; break; + case List: func = "List"; break; + case Edit: func = "Edit"; break; + case Del: func = "Del"; break; } fprintf (stdout, "Function: %s\n", func); @@ -519,42 +566,72 @@ void print_element (element_t *root, int level) /* storage functions */ +void memory (int nb) +{ + int i, l; + double *tmp = NULL; + if (nb != storage_size) { + l = (nb < storage_size) ? nb : storage_size; + tmp = (double *) callocordie (nb, sizeof (double)); + for (i = 0; i < l; i++) { + tmp[i] = storage[i]; + } + if (storage != NULL) { + free (storage); + } + storage = tmp; + storage_size = nb; + } +} + double store (int index, double value) { - if ((index > 0) && (index <= STORAGE_SIZE)) { + if (storage_size == -1) { + memory (DEFAULT_STORAGE_SIZE); + } + if ((index > 0) && (index <= storage_size)) { storage[index - 1] = value; } else { - VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE)); + VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [%d, %d]\n", index, (storage_size) ? 1 : 0, storage_size)); } return value; } double recall (int index) { - if ((index > 0) && (index <= STORAGE_SIZE)) { + if (storage_size == -1) { + memory (DEFAULT_STORAGE_SIZE); + } + if ((index > 0) && (index <= storage_size)) { return storage[index - 1]; } else { - VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE)); + VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [%d, %d]\n", index, (storage_size) ? 1 : 0, storage_size)); } return 0; } double increase (int index) { - if ((index > 0) && (index <= STORAGE_SIZE)) { + if (storage_size == -1) { + memory (DEFAULT_STORAGE_SIZE); + } + if ((index > 0) && (index <= storage_size)) { return storage[index - 1]++; } else { - VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE)); + VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [%d, %d]\n", index, (storage_size) ? 1 : 0, storage_size)); } return 0; } double decrease (int index) { - if ((index > 0) && (index <= STORAGE_SIZE)) { + if (storage_size == -1) { + memory (DEFAULT_STORAGE_SIZE); + } + if ((index > 0) && (index <= storage_size)) { return storage[index - 1]--; } else { - VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE)); + VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [%d, %d]\n", index, (storage_size) ? 1 : 0, storage_size)); } return 0; } @@ -562,13 +639,25 @@ double decrease (int index) void display (void) { int i; + if (storage_size == -1) { + memory (DEFAULT_STORAGE_SIZE); + } fprintf (stdout, "storage:"); - for (i = 0; i < STORAGE_SIZE; i++) { - fprintf (stdout, " %g", storage[i]); + for (i = 0; i < storage_size; i++) { + fprintf (stdout, " "); + fprintf (stdout, minform, storage[i]); } fprintf (stdout, "\n"); } +void clear () +{ + int i; + for (i = 0; i < storage_size; i++) { + storage[i] = 0; + } +} + /* While do function */ double while_do (element_t *cond, element_t *action) @@ -581,12 +670,15 @@ double while_do (element_t *cond, element_t *action) VERBOSE (DEBUG, fprintf (stdout, "loop...\n")); temp = dupelement (cond); - if (!evaluate_element (temp, 0)) { + double test = evaluate_element (temp, 0); + delelement (temp); + if (!test) { break; } if (action) { temp = dupelement (action); ret = evaluate_element (temp, 0); + delelement (temp); } } @@ -597,17 +689,47 @@ double while_do (element_t *cond, element_t *action) /* program function */ -double program_do (element_t **prog, int nbcalls) +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); - prog[i] = NULL; } return ret; } +/* print function */ + +void set_format (char *prompt, int precision) +{ + char buffer[128] = {0}; + free_format (); + sprintf (buffer, "%s%%.%dg\n", prompt, precision); + format = strdup (buffer); + sprintf (buffer, "%%.%dg", precision); + minform = strdup (buffer); +} + +void free_format () +{ + if (format) { + free (format); + format = NULL; + } + if (minform) { + free (minform); + minform = NULL; + } +} + +double print (double value) +{ + fprintf (stdout, format ? format : DEFAULT_FORMAT, value); + fflush (stdout); + return value; +} + /* quit function */ void quit (void) @@ -616,6 +738,218 @@ void quit (void) exit (0); } +/* program function */ + +void prog (int id, int nbmems, element_t *root) +{ + int i, n = -1; + + if (programs == NULL) { + + /* initial memory allocation */ + programs = (workspace_t *) callocordie (1, sizeof (workspace_t)); + nb_programs = 1; + n = 0; + + } else { + + /* look for existing program */ + for (i = 0; i < nb_programs; i++) { + if ((programs + i)->id == id) { + n = i; + break; + } + } + if (n == -1) { + + /* new program */ + n = nb_programs++; + workspace_t *tmp = (workspace_t *) callocordie (nb_programs, sizeof (workspace_t)); + memcpy (tmp, programs, (nb_programs - 1) * sizeof (workspace_t)); + free (programs); + programs = tmp; + } else { + + /* clean old program */ + if ((programs + n)->storage) { + free ((programs + n)->storage); + } + if ((programs + n)->root) { + delelement ((programs + n)->root); + } + if ((programs + n)->string) { + free ((programs + n)->string); + (programs + n)->string = NULL; + } + } + } + + /* 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)->root = dupelement (root); +} + +double call (int id, int nbops, element_t **ops) +{ + workspace_t tmp = {0}; + int i, n = -1; + double ret = 0; + + if (programs) { + + /* look for program */ + for (i = 0; i < nb_programs; i++) { + if ((programs + i)->id == id) { + n = i; + break; + } + } + } + if (n == -1) { + VERBOSE (WARNING, fprintf (stdout, "error unknown program (%d)\n", id)); + return 0; + } + + /* store context */ + tmp.answer = answer; + tmp.storage = storage; + tmp.storage_size = storage_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); + (programs + n)->storage = storage = tmp; + (programs + n)->storage_size = storage_size = nbops; + } + for (i = 0; i < nbops; i++) { + double val = evaluate_element (ops[i], 0); + store (i + 1, val); + } + + /* evaluate program */ + element_t *elements = dupelement ((programs + n)->root); + ret = evaluate_element (elements, 0); + delelement (elements); + + /* restore context */ + answer = tmp.answer; + storage = tmp.storage; + storage_size = tmp.storage_size; + + return ret; +} + +void list () +{ + int i; + fprintf (stdout, "programs:"); + for (i = 0; i < nb_programs; i++) { + fprintf (stdout, " %d", (programs + i)->id); + } + fprintf (stdout, "\n"); +} + +void edit (int id) +{ + int i, n = -1; + + if (programs) { + + /* look for program */ + for (i = 0; i < nb_programs; i++) { + if ((programs + i)->id == id) { + n = i; + break; + } + } + } + if (n == -1) { + VERBOSE (WARNING, fprintf (stdout, "error unknown program (%d)\n", id)); + return; + } + + /* set string program */ + fprintf (stdout, "edit: %s\n", (programs + n)->string); +} + +void savestring (int id, char *string) +{ + int i, n = -1; + + if (programs) { + + /* look for program */ + for (i = 0; i < nb_programs; i++) { + if ((programs + i)->id == id) { + n = i; + break; + } + } + } + + /* unnecesary code */ + //if (n == -1) { + // VERBOSE (WARNING, fprintf (stdout, "error unknown program (%d)\n", id)); + // return; + //} + //if ((programs + n)->string) { + // free ((programs + n)->string); + //} + + (programs + n)->string = strdup (string); +} + +void del (int id) +{ + int i, j, n = -1; + + if (programs) { + + /* look for program */ + for (i = 0; i < nb_programs; i++) { + if ((programs + i)->id == id) { + n = i; + break; + } + } + } + if (n == -1) { + VERBOSE (WARNING, fprintf (stdout, "error unknown program (%d)\n", id)); + return; + } + + /* clean program */ + if ((programs + n)->storage) { + free ((programs + n)->storage); + } + if ((programs + n)->root) { + delelement ((programs + n)->root); + } + if ((programs + n)->string) { + free ((programs + n)->string); + } + + /* remove entry */ + workspace_t *tmp = (workspace_t *) callocordie (nb_programs - 1, sizeof (workspace_t)); + for (i = 0, j = 0; i < nb_programs; i++) { + if (i != n) { + memcpy (tmp + j, programs + i, sizeof (workspace_t)); + j++; + } + } + free (programs); + programs = tmp; + nb_programs--; +} + /* help message */ void help (void) @@ -629,15 +963,15 @@ void help (void) fprintf (stdout, " & | !\n"); fprintf (stdout, "mathematic functions:"); fprintf (stdout, " pow sqrt log exp\n"); - fprintf (stdout, "trigonometric functions:"); + fprintf (stdout, "trig. func.:"); fprintf (stdout, " cos sin tan acos asin atan\n"); fprintf (stdout, "supported functions:"); fprintf (stdout, " abs ceil floor\n"); fprintf (stdout, "storage functions:"); - fprintf (stdout, " sto rcl inc dec\n"); - fprintf (stdout, "conditional functions:"); - fprintf (stdout, " cond while\n"); - fprintf (stdout, "miscellaneous 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"); @@ -652,6 +986,7 @@ 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")); @@ -698,6 +1033,7 @@ double evaluate_element (element_t *root, char mask) case Lt: case And: case Or: + case Prog: if (root->ops[1]) { op1 = evaluate_element (root->ops[1], nextmask); } else if (root->func != Store) { @@ -721,7 +1057,11 @@ double evaluate_element (element_t *root, char mask) case Inc: case Dec: case Not: + case Mem: case Cond: + case Call: + case Edit: + case Del: if (root->ops[0]) { op0 = evaluate_element (root->ops[0], 0); } else { @@ -730,12 +1070,14 @@ double evaluate_element (element_t *root, char mask) } break; case Disp: + case Clear: case Quit: case Help: case Ans: case Pi: case E: - case Prog: + case Code: + case List: break; case While: if (root->ops[0] == NULL) { @@ -743,6 +1085,9 @@ double evaluate_element (element_t *root, char mask) return 0; } break; + case Print: + op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : answer; + break; } switch (root->func) { @@ -771,6 +1116,8 @@ double evaluate_element (element_t *root, char mask) case Inc: return increase ((int)op0); case Dec: return decrease ((int)op0); case Disp: display (); break; + case Mem: memory ((int)op0); break; + case Clear: clear (); break; case Quit: quit (); break; case Help: help (); break; case Ans: return answer; @@ -794,7 +1141,22 @@ double evaluate_element (element_t *root, char mask) return 0; } case While: return while_do (root->ops[0], root->ops[1]); - case Prog: return program_do (root->ops, root->nbops); + case Code: return execute_code (root->ops, root->nbops); + case Print: return print (op0); + case Prog: + prog ((int)op0, (int)op1, root->ops[2]); + savestring ((int)op0, root->string); + break; + 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; } return 0; @@ -802,29 +1164,40 @@ double evaluate_element (element_t *root, char mask) char **generate_completion_list () { - int i, l = 0; - char **list = (char **) calloc (NB_FUNCTIONS + NB_CONSTANTS + 1, sizeof (char *)); - if (list == NULL) { - VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n")); - exit (1); + 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) { - VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n")); - exit (1); + if (list[l] != NULL) { + l++; } - l++; } for (i = 0; i < NB_CONSTANTS; i++) { list[l] = strdup ((constants + i)->keyword); - if (list[l] == NULL) { - VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n")); - exit (1); + if (list[l] != NULL) { + l++; + } + } + + for (i = 0; i < NB_SYMBOLS; i++) { + list[l] = strdup (symbols[i]); + if (list[l] != NULL) { + l++; } - l++; } return (list); @@ -835,7 +1208,7 @@ void free_completion_list (char **list) int i; if (list) { - for (i = 0; i < NB_FUNCTIONS + NB_CONSTANTS; i++) { + for (i = 0; i < NB_OPERATORS + NB_FUNCTIONS + NB_CONSTANTS + NB_SYMBOLS + 1; i++) { if (list[i] != NULL) { free (list[i]); }