/* * * Interpreteur de ligne de commande * */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #else #define _(x) x #endif #include "exceptions.h" #include "parser.h" #include "pile.h" typedef unsigned char op_t; typedef struct operator_t { op_t op; int pri, func; } operator_t; static op_t pile_operators[PILEOP_MAX]; static int pile_nestedcall[PILECALL_MAX]; static int pileop_pos = 0, pilecall_pos = 0; /* * La liste des operateurs reconnus par le parser */ static operator_t operators[] = { {',', 0, OP_NEST}, {'+', 2, OP_PLUS}, {'-', 2, OP_MOINS}, {'*', 3, OP_MUL}, {'/', 3, OP_DIV}, {'%', 3, OP_MOD}, {'^', 4, OP_EXP}, {'+' + 128, 5, OP_PLUS_UNARY}, {'-' + 128, 5, OP_MOINS_UNARY}, {'=', 1, OP_ASSIGN}, {'(', 6, OP_FUNC_CALL}, {'(' + 128, 6, OP_LPAREN}, {255, -1, -1} }; /* * Fonction interne: convertit un operateur en sa structure */ static operator_t get_op(op_t op) { int i; for (i = 0; operators[i].op != 255; i++) { if (operators[i].op == op) return operators[i]; } return operators[i]; } /* * Fonctions internes de lectures sur la structure */ static int get_pri(op_t op) { return get_op(op).pri; } static int get_func(op_t op) { return get_op(op).func; } /* * Focntions internes d'empilement / depilement */ static op_t get_last_op(void) { if (pileop_pos) return pile_operators[pileop_pos - 1]; else return -1; } static op_t pop_op(void) { if (pileop_pos) return pile_operators[--pileop_pos]; return -1; } static void push_op(op_t op) { if (pileop_pos != PILEOP_MAX) pile_operators[pileop_pos++] = op; else exception(1, _("Too many nested operators in expression.\n")); } static int pop_call(void) { if (pilecall_pos) return pile_nestedcall[--pilecall_pos]; return -1; } static void increment_call(void) { if (pilecall_pos) { if (pile_nestedcall[pilecall_pos - 1] != -1) pile_nestedcall[pilecall_pos - 1]++; } } static int get_last_call(void) { if (pilecall_pos) return pile_nestedcall[pilecall_pos - 1]; return -1; } static void push_call(int call) { if (pilecall_pos != PILECALL_MAX) pile_nestedcall[pilecall_pos++] = call; else exception(1, _("Too many nested functions calls in expression.\n")); } /* * Cette fonction lit un "mot" sur la chaine line et renvoit le nouveau pointeur */ static char *getword(char *line, char *p) { char o = 0, *d = line, instring = 0, gotbslash = 0; do { if (instring) { o = *(p++) = *line; if (!gotbslash) { switch (instring) { case 1: if (*line == '\'') { instring = 0; } break; case 2: if (*line == '"') { instring = 0; } break; } if (*line == '\\') gotbslash = 1; } else { gotbslash = 0; } } else { if (*(line) == '\'') { o = *(p++) = *line; instring = 1; } else if (*(line) == '"') { o = *(p++) = *line; instring = 2; } else { if (*(line) != ' ' && *(line) != '\t') { o = *(p++) = *line; } else if (d != line) { *p = '\0'; return line; } } } line++; } while (((*line) && (*line != ')') && (*line != ';') && (get_func(*line) == -1) && (get_func(o) == -1)) || (instring)); *p = '\0'; return line; } /* * Cette fonction va parcourir une chaine afin d'appeler les fonction push_pile() et act_pile() */ void parse_line(char *line) { char buffer[BUFSIZ], imm[BUFSIZ], *d = line; op_t op; static int got_unary = 128, nbrargs; sprintf(buffer, "Read line '%s'", line); pushcontext(buffer); while ((*line) && !(global_error)) { line = getword(line, buffer); sprintf(imm, "Analysing word '%s' at position %i", buffer, line - d); pushcontext(imm); if (get_func(buffer[0]) != -1) { /* * Le mot lu est un operateur, on agit sur la pile */ buffer[0] += got_unary; if (got_unary) { } if (get_pri(buffer[0]) == -1) { if (got_unary) { exception(1, _("Invalid unary operator")); } else { exception(1, _("Invalid binary operator")); } } while (((get_pri(get_last_op()) >= get_pri(buffer[0])) && ((get_last_op() & 127) != '(')) && !global_error) { act_pile(get_func(pop_op())); got_unary = 0; } if (buffer[0] == '(') { push_call(0); } if (buffer[0] == ',') { increment_call(); } else push_op(buffer[0]); got_unary = 128; } else if ((buffer[0] == ';') || (buffer[0] == ')')) { /* * Le mot lut est un operateur special, on vide la pile */ switch (buffer[0]) { case ';': /* * Equivalent a fin de ligne */ while ((pileop_pos) && !global_error) { op = pop_op(); if (op == '(') exception(1, _("Parse error: too much left parenthesis")); act_pile(get_func(op)); } got_unary = 128; move_to_resultat_pile(); break; case ')': /* * Fin de parenthese (Appel de fonction ou expression mathematique) */ while (!global_error) { if (!pileop_pos) exception(1, _("Parse error: too much right parenthesis")); op = pop_op(); if (((op & 127) == '(')) break; act_pile(get_func(op)); } if (global_error) break; if (op == '(') { nbrargs = pop_call(); push_pile_int(nbrargs); act_pile(get_func(op)); } got_unary = 0; break; } } else if (((buffer[0] >= 'A') && (buffer[0] <= 'Z')) || ((buffer[0] >= 'a') && (buffer[0] <= 'z')) || ((buffer[0] >= '0') && (buffer[0] <= '9')) || (buffer[0] == '_') || (buffer[0] == '"') || (buffer[0] == '\'') || (buffer[0] == '.') || (buffer[0] == '#') || (buffer[0] == '?')) { /* * Dans tous les autres cas, on a reçu un symbole, on le pose sur la pile */ push_pile(buffer); got_unary = 0; if (!get_last_call()) increment_call(); } else if (buffer[0]) { exception(1, _("Invalid character")); } popcontext(); } popcontext(); if (global_error) { got_unary = 128; while (pileop_pos) { pop_op(); } } }