diff options
Diffstat (limited to 'contrib/snowball/compiler/analyser.c')
-rw-r--r-- | contrib/snowball/compiler/analyser.c | 866 |
1 files changed, 644 insertions, 222 deletions
diff --git a/contrib/snowball/compiler/analyser.c b/contrib/snowball/compiler/analyser.c index ed712f64f..dffa5552d 100644 --- a/contrib/snowball/compiler/analyser.c +++ b/contrib/snowball/compiler/analyser.c @@ -4,31 +4,53 @@ #include <string.h> /* memmove */ #include "header.h" +typedef enum { + e_token_omitted = 0, + e_unexpected_token = 1, + e_string_omitted = 2, + e_unexpected_token_in_among = 3, + /* For codes above here, report "after " t->previous_token after the error. */ + e_unresolved_substring = 14, + e_not_allowed_inside_reverse = 15, + e_empty_grouping = 16, + e_already_backwards = 17, + e_empty_among = 18, + e_adjacent_bracketed_in_among = 19, + e_substring_preceded_by_substring = 20, + /* For codes below here, tokeniser->b is printed before the error. */ + e_redeclared = 30, + e_undeclared = 31, + e_declared_as_different_mode = 32, + e_not_of_type_x = 33, + e_not_of_type_string_or_integer = 34, + e_misplaced = 35, + e_redefined = 36, + e_misused = 37 +} error_code; + /* recursive usage: */ static void read_program_(struct analyser * a, int terminator); static struct node * read_C(struct analyser * a); -static struct node * C_style(struct analyser * a, char * s, int token); - +static struct node * C_style(struct analyser * a, const char * s, int token); -static void fault(int n) { fprintf(stderr, "fault %d\n", n); exit(1); } static void print_node_(struct node * p, int n, const char * s) { int i; for (i = 0; i < n; i++) fputs(i == n - 1 ? s : " ", stdout); printf("%s ", name_of_token(p->type)); - unless (p->name == 0) report_b(stdout, p->name->b); - unless (p->literalstring == 0) { + if (p->name) report_b(stdout, p->name->b); + if (p->literalstring) { printf("'"); report_b(stdout, p->literalstring); printf("'"); } printf("\n"); - unless (p->AE == 0) print_node_(p->AE, n+1, "# "); - unless (p->left == 0) print_node_(p->left, n+1, " "); - unless (p->right == 0) print_node_(p->right, n, " "); - if (p->aux != 0) print_node_(p->aux, n+1, "@ "); + if (p->AE) print_node_(p->AE, n+1, "# "); + if (p->left) print_node_(p->left, n+1, " "); + if (p->aux) print_node_(p->aux, n+1, "@ "); + if (p->right) print_node_(p->right, n, " "); } extern void print_program(struct analyser * a) { @@ -52,22 +74,37 @@ static struct node * new_node(struct analyser * a, int type) { static const char * name_of_mode(int n) { switch (n) { - default: fault(0); - case m_backward: return "string backward"; - case m_forward: return "string forward"; - /* case m_integer: return "integer"; */ + case m_backward: return "string backward"; + case m_forward: return "string forward"; + /* case m_integer: return "integer"; */ } + fprintf(stderr, "Invalid mode %d in name_of_mode()\n", n); + exit(1); } static const char * name_of_type(int n) { switch (n) { - default: fault(1); - case 's': return "string"; - case 'i': return "integer"; - case 'r': return "routine"; - case 'R': return "routine or grouping"; - case 'g': return "grouping"; + case 's': return "string"; + case 'i': return "integer"; + case 'r': return "routine"; + case 'R': return "routine or grouping"; + case 'g': return "grouping"; + } + fprintf(stderr, "Invalid type %d in name_of_type()\n", n); + exit(1); +} + +static const char * name_of_name_type(int code) { + switch (code) { + case t_string: return "string"; + case t_boolean: return "boolean"; + case t_integer: return "integer"; + case t_routine: return "routine"; + case t_external: return "external"; + case t_grouping: return "grouping"; } + fprintf(stderr, "Invalid type code %d in name_of_name_type()\n", code); + exit(1); } static void count_error(struct analyser * a) { @@ -76,86 +113,78 @@ static void count_error(struct analyser * a) { t->error_count++; } -static void error2(struct analyser * a, int n, int x) { +static void error2(struct analyser * a, error_code n, int x) { struct tokeniser * t = a->tokeniser; count_error(a); fprintf(stderr, "%s:%d: ", t->file, t->line_number); - if (n >= 30) report_b(stderr, t->b); + if ((int)n >= (int)e_redeclared) report_b(stderr, t->b); switch (n) { - case 0: + case e_token_omitted: fprintf(stderr, "%s omitted", name_of_token(t->omission)); break; - case 3: + case e_unexpected_token_in_among: fprintf(stderr, "in among(...), "); - case 1: + /* fall through */ + case e_unexpected_token: fprintf(stderr, "unexpected %s", name_of_token(t->token)); if (t->token == c_number) fprintf(stderr, " %d", t->number); if (t->token == c_name) { fprintf(stderr, " "); report_b(stderr, t->b); } break; - case 2: + case e_string_omitted: fprintf(stderr, "string omitted"); break; - case 14: + case e_unresolved_substring: fprintf(stderr, "unresolved substring on line %d", x); break; - case 15: + case e_not_allowed_inside_reverse: fprintf(stderr, "%s not allowed inside reverse(...)", name_of_token(t->token)); break; - case 16: + case e_empty_grouping: fprintf(stderr, "empty grouping"); break; - case 17: + case e_already_backwards: fprintf(stderr, "backwards used when already in this mode"); break; - case 18: + case e_empty_among: fprintf(stderr, "empty among(...)"); break; - case 19: + case e_adjacent_bracketed_in_among: fprintf(stderr, "two adjacent bracketed expressions in among(...)"); break; - case 20: + case e_substring_preceded_by_substring: fprintf(stderr, "substring preceded by another substring on line %d", x); break; - case 30: + case e_redeclared: fprintf(stderr, " re-declared"); break; - case 31: + case e_undeclared: fprintf(stderr, " undeclared"); break; - case 32: + case e_declared_as_different_mode: fprintf(stderr, " declared as %s mode; used as %s mode", name_of_mode(a->mode), name_of_mode(x)); break; - case 33: + case e_not_of_type_x: fprintf(stderr, " not of type %s", name_of_type(x)); break; - case 34: + case e_not_of_type_string_or_integer: fprintf(stderr, " not of type string or integer"); break; - case 35: + case e_misplaced: fprintf(stderr, " misplaced"); break; - case 36: + case e_redefined: fprintf(stderr, " redefined"); break; - case 37: + case e_misused: fprintf(stderr, " mis-used as %s mode", name_of_mode(x)); break; - default: - fprintf(stderr, " error %d", n); break; - } - if (n <= 13 && t->previous_token > 0) + if ((int)n < (int)e_unresolved_substring && t->previous_token > 0) fprintf(stderr, " after %s", name_of_token(t->previous_token)); fprintf(stderr, "\n"); } -static void error(struct analyser * a, int n) { error2(a, n, 0); } - -static void error3(struct analyser * a, struct node * p, symbol * b) { - count_error(a); - fprintf(stderr, "%s:%d: among(...) has repeated string '", a->tokeniser->file, p->line_number); - report_b(stderr, b); - fprintf(stderr, "'\n"); -} +static void error(struct analyser * a, error_code n) { error2(a, n, 0); } static void error4(struct analyser * a, struct name * q) { count_error(a); + fprintf(stderr, "%s:%d: ", a->tokeniser->file, q->used->line_number); report_b(stderr, q->b); fprintf(stderr, " undefined\n"); } static void omission_error(struct analyser * a, int n) { a->tokeniser->omission = n; - error(a, 0); + error(a, e_token_omitted); } static int check_token(struct analyser * a, int code) { @@ -169,71 +198,120 @@ static int get_token(struct analyser * a, int code) { read_token(t); { int x = check_token(a, code); - unless (x) t->token_held = true; + if (!x) t->token_held = true; return x; } } static struct name * look_for_name(struct analyser * a) { - struct name * p = a->names; symbol * q = a->tokeniser->b; - repeat { - if (p == 0) return 0; - { symbol * b = p->b; - int n = SIZE(b); - if (n == SIZE(q) && memcmp(q, b, n * sizeof(symbol)) == 0) { - p->referenced = true; - return p; - } + struct name * p; + for (p = a->names; p; p = p->next) { + symbol * b = p->b; + int n = SIZE(b); + if (n == SIZE(q) && memcmp(q, b, n * sizeof(symbol)) == 0) { + p->referenced = true; + return p; } - p = p->next; } + return 0; } static struct name * find_name(struct analyser * a) { struct name * p = look_for_name(a); - if (p == 0) error(a, 31); + if (p == 0) error(a, e_undeclared); return p; } static void check_routine_mode(struct analyser * a, struct name * p, int mode) { if (p->mode < 0) p->mode = mode; else - unless (p->mode == mode) error2(a, 37, mode); + if (p->mode != mode) error2(a, e_misused, mode); } static void check_name_type(struct analyser * a, struct name * p, int type) { switch (type) { - case 's': if (p->type == t_string) return; break; - case 'i': if (p->type == t_integer) return; break; - case 'b': if (p->type == t_boolean) return; break; - case 'R': if (p->type == t_grouping) return; - case 'r': if (p->type == t_routine || p->type == t_external) return; break; - case 'g': if (p->type == t_grouping) return; break; + case 's': + if (p->type == t_string) return; + break; + case 'i': + if (p->type == t_integer) return; + break; + case 'b': + if (p->type == t_boolean) return; + break; + case 'R': + if (p->type == t_grouping) return; + /* FALLTHRU */ + case 'r': + if (p->type == t_routine || p->type == t_external) return; + break; + case 'g': + if (p->type == t_grouping) return; + break; } - error2(a, 33, type); + error2(a, e_not_of_type_x, type); } static void read_names(struct analyser * a, int type) { struct tokeniser * t = a->tokeniser; - unless (get_token(a, c_bra)) return; - repeat { - if (read_token(t) != c_name) break; - if (look_for_name(a) != 0) error(a, 30); else { - NEW(name, p); - p->b = copy_b(t->b); - p->type = type; - p->mode = -1; /* routines, externals */ - p->count = a->name_count[type]; - p->referenced = false; - p->used = false; - p->grouping = 0; - p->definition = 0; - a->name_count[type] ++; - p->next = a->names; - a->names = p; - } - } - unless (check_token(a, c_ket)) t->token_held = true; + if (!get_token(a, c_bra)) return; + while (true) { + int token = read_token(t); + switch (token) { + case c_len: { + /* Context-sensitive token - once declared as a name, it loses + * its special meaning, for compatibility with older versions + * of snowball. + */ + static const symbol c_len_lit[] = { + 'l', 'e', 'n' + }; + MOVE_TO_B(t->b, c_len_lit); + goto handle_as_name; + } + case c_lenof: { + /* Context-sensitive token - once declared as a name, it loses + * its special meaning, for compatibility with older versions + * of snowball. + */ + static const symbol c_lenof_lit[] = { + 'l', 'e', 'n', 'o', 'f' + }; + MOVE_TO_B(t->b, c_lenof_lit); + goto handle_as_name; + } + case c_name: +handle_as_name: + if (look_for_name(a) != 0) error(a, e_redeclared); else { + NEW(name, p); + p->b = copy_b(t->b); + p->type = type; + p->mode = -1; /* routines, externals */ + /* We defer assigning counts until after we've eliminated + * variables whose values are never used. */ + p->count = -1; + p->referenced = false; + p->used_in_among = false; + p->used = 0; + p->value_used = false; + p->initialised = false; + p->used_in_definition = false; + p->local_to = 0; + p->grouping = 0; + p->definition = 0; + p->declaration_line_number = t->line_number; + p->next = a->names; + a->names = p; + if (token != c_name) { + disable_token(t, token); + } + } + break; + default: + if (!check_token(a, c_ket)) t->token_held = true; + return; + } + } } static symbol * new_literalstring(struct analyser * a) { @@ -259,7 +337,7 @@ static int read_AE_test(struct analyser * a) { case c_ge: case c_ls: case c_le: return t->token; - default: error(a, 1); t->token_held = true; return c_eq; + default: error(a, e_unexpected_token); t->token_held = true; return c_eq; } } @@ -271,11 +349,23 @@ static int binding(int t) { } } +static void mark_used_in(struct analyser * a, struct name * q, struct node * p) { + if (!q->used) { + q->used = p; + q->local_to = a->program_end->name; + } else if (q->local_to) { + if (q->local_to != a->program_end->name) { + /* Used in more than one routine/external. */ + q->local_to = NULL; + } + } +} + static void name_to_node(struct analyser * a, struct node * p, int type) { struct name * q = find_name(a); - unless (q == 0) { + if (q) { check_name_type(a, q, type); - q->used = true; + mark_used_in(a, q, p); } p->name = q; } @@ -286,8 +376,18 @@ static struct node * read_AE(struct analyser * a, int B) { struct node * q; switch (read_token(t)) { case c_minus: /* monadic */ + q = read_AE(a, 100); + if (q->type == c_neg) { + /* Optimise away double negation, which avoids generators + * having to worry about generating "--" (decrement operator + * in many languages). + */ + p = q->right; + /* Don't free q, it's in the linked list a->nodes. */ + break; + } p = new_node(a, c_neg); - p->right = read_AE(a, 100); + p->right = q; break; case c_bra: p = read_AE(a, 0); @@ -296,11 +396,15 @@ static struct node * read_AE(struct analyser * a, int B) { case c_name: p = new_node(a, c_name); name_to_node(a, p, 'i'); + if (p->name) p->name->value_used = true; break; case c_maxint: case c_minint: + a->int_limits_used = true; + /* fall through */ case c_cursor: case c_limit: + case c_len: case c_size: p = new_node(a, t->token); break; @@ -308,18 +412,19 @@ static struct node * read_AE(struct analyser * a, int B) { p = new_node(a, c_number); p->number = t->number; break; + case c_lenof: case c_sizeof: - p = C_style(a, "s", c_sizeof); + p = C_style(a, "s", t->token); break; default: - error(a, 1); + error(a, e_unexpected_token); t->token_held = true; return 0; } - repeat { + while (true) { int token = read_token(t); int b = binding(token); - unless (binding(token) > B) { + if (binding(token) <= B) { t->token_held = true; return p; } @@ -335,14 +440,11 @@ static struct node * read_C_connection(struct analyser * a, struct node * q, int struct node * p = new_node(a, op); struct node * p_end = q; p->left = q; - repeat { + do { q = read_C(a); p_end->right = q; p_end = q; - if (read_token(t) != op) { - t->token_held = true; - break; - } - } + } while (read_token(t) == op); + t->token_held = true; return p; } @@ -350,14 +452,14 @@ static struct node * read_C_list(struct analyser * a) { struct tokeniser * t = a->tokeniser; struct node * p = new_node(a, c_bra); struct node * p_end = 0; - repeat { + while (true) { int token = read_token(t); if (token == c_ket) return p; if (token < 0) { omission_error(a, c_ket); return p; } t->token_held = true; { struct node * q = read_C(a); - repeat { + while (true) { token = read_token(t); if (token != c_and && token != c_or) { t->token_held = true; @@ -371,10 +473,10 @@ static struct node * read_C_list(struct analyser * a) { } } -static struct node * C_style(struct analyser * a, char * s, int token) { +static struct node * C_style(struct analyser * a, const char * s, int token) { int i; struct node * p = new_node(a, token); - for (i = 0; s[i] != 0; i++) switch(s[i]) { + for (i = 0; s[i] != 0; i++) switch (s[i]) { case 'C': p->left = read_C(a); continue; case 'D': @@ -388,7 +490,7 @@ static struct node * C_style(struct analyser * a, char * s, int token) { int str_token = read_token(a->tokeniser); if (str_token == c_name) name_to_node(a, p, 's'); else if (str_token == c_literalstring) p->literalstring = new_literalstring(a); - else error(a, 2); + else error(a, e_string_omitted); } continue; case 'b': @@ -408,7 +510,7 @@ static struct node * read_literalstring(struct analyser * a) { static void reverse_b(symbol * b) { int i = 0; int j = SIZE(b) - 1; - until (i >= j) { + while (i < j) { int ch1 = b[i]; int ch2 = b[j]; b[i++] = ch2; b[j--] = ch1; } @@ -423,7 +525,74 @@ static int compare_amongvec(const void *pv, const void *qv) { int i; for (i = 0; i < smaller_size; i++) if (b_p[i] != b_q[i]) return b_p[i] - b_q[i]; - return p_size - q_size; + if (p_size - q_size) + return p_size - q_size; + return p->line_number - q->line_number; +} + +#define PTR_NULL_CHECK(P, Q) do {\ + if ((Q) == NULL) {\ + if ((P) != NULL) return 1;\ + } else {\ + if ((P) == NULL) return -1;\ + }\ + } while (0) + +static int compare_node(const struct node *p, const struct node *q) { + PTR_NULL_CHECK(p, q); + if (q == NULL) { + /* p must be NULL too. */ + return 0; + } + + if (p->type != q->type) return p->type > q->type ? 1 : -1; + if (p->mode != q->mode) return p->mode > q->mode ? 1 : -1; + if (p->type == c_number) { + if (p->number != q->number) + return p->number > q->number ? 1 : -1; + } + + PTR_NULL_CHECK(p->left, q->left); + if (p->left) { + int r = compare_node(p->left, q->left); + if (r != 0) return r; + } + + PTR_NULL_CHECK(p->AE, q->AE); + if (p->AE) { + int r = compare_node(p->AE, q->AE); + if (r != 0) return r; + } + + PTR_NULL_CHECK(p->aux, q->aux); + if (p->aux) { + int r = compare_node(p->aux, q->aux); + if (r != 0) return r; + } + + PTR_NULL_CHECK(p->name, q->name); + if (p->name) { + int r; + if (SIZE(p->name->b) != SIZE(q->name->b)) { + return SIZE(p->name->b) - SIZE(q->name->b); + } + r = memcmp(p->name->b, q->name->b, + SIZE(p->name->b) * sizeof(symbol)); + if (r != 0) return r; + } + + PTR_NULL_CHECK(p->literalstring, q->literalstring); + if (p->literalstring) { + int r; + if (SIZE(p->literalstring) != SIZE(q->literalstring)) { + return SIZE(p->literalstring) - SIZE(q->literalstring); + } + r = memcmp(p->literalstring, q->literalstring, + SIZE(p->literalstring) * sizeof(symbol)); + if (r != 0) return r; + } + + return compare_node(p->right, q->right); } static void make_among(struct analyser * a, struct node * p, struct node * substring) { @@ -443,38 +612,84 @@ static void make_among(struct analyser * a, struct node * p, struct node * subst x->next = 0; x->b = v; x->number = a->among_count++; + x->function_count = 0; x->starter = 0; + x->nocommand_count = 0; + x->amongvar_needed = false; if (q->type == c_bra) { x->starter = q; q = q->right; } - until (q == 0) { + while (q) { if (q->type == c_literalstring) { symbol * b = q->literalstring; w1->b = b; /* pointer to case string */ - w1->p = 0; /* pointer to corresponding case expression */ + w1->action = NULL; /* action gets filled in below */ + w1->line_number = q->line_number; w1->size = SIZE(b); /* number of characters in string */ w1->i = -1; /* index of longest substring */ w1->result = -1; /* number of corresponding case expression */ - w1->function = q->left == 0 ? 0 : q->left->name; - unless (w1->function == 0) - check_routine_mode(a, w1->function, direction); + if (q->left) { + struct name * function = q->left->name; + w1->function = function; + function->used_in_among = true; + check_routine_mode(a, function, direction); + x->function_count++; + } else { + w1->function = 0; + } w1++; - } - else - if (q->left == 0) /* empty command: () */ + } else if (q->left == 0) { + /* empty command: () */ w0 = w1; - else { - until (w0 == w1) { - w0->p = q; - w0->result = result; + } else { + /* Check for previous action which is the same as this one and use + * the same action code if we find one. + */ + int among_result = -1; + struct amongvec * w; + for (w = v; w < w0; ++w) { + if (w->action && compare_node(w->action->left, q->left) == 0) { + if (w->result <= 0) { + printf("Among code %d isn't positive\n", w->result); + exit(1); + } + among_result = w->result; + break; + } + } + if (among_result < 0) { + among_result = result++; + } + + while (w0 != w1) { + w0->action = q; + w0->result = among_result; w0++; } - result++; } q = q->right; } - unless (w1-v == p->number) { fprintf(stderr, "oh! %d %d\n", (int)(w1-v), p->number); exit(1); } - if (backward) for (w0 = v; w0 < w1; w0++) reverse_b(w0->b); + if (w1-v != p->number) { fprintf(stderr, "oh! %d %d\n", (int)(w1-v), p->number); exit(1); } + x->command_count = result - 1; + { + NEWVEC(node*, commands, x->command_count); + memset(commands, 0, x->command_count * sizeof(struct node*)); + for (w0 = v; w0 < w1; w0++) { + if (w0->result > 0) { + /* result == -1 when there's no command. */ + if (w0->result > x->command_count) { + fprintf(stderr, "More among codes than expected\n"); + exit(1); + } + if (!commands[w0->result - 1]) + commands[w0->result - 1] = w0->action; + } else { + ++x->nocommand_count; + } + if (backward) reverse_b(w0->b); + } + x->commands = commands; + } qsort(v, w1 - v, sizeof(struct amongvec), compare_amongvec); /* the following loop is O(n squared) */ @@ -494,15 +709,30 @@ static void make_among(struct analyser * a, struct node * p, struct node * subst for (w0 = v; w0 < w1 - 1; w0++) if (w0->size == (w0 + 1)->size && - memcmp(w0->b, (w0 + 1)->b, w0->size * sizeof(symbol)) == 0) error3(a, p, w0->b); + memcmp(w0->b, (w0 + 1)->b, w0->size * sizeof(symbol)) == 0) { + count_error(a); + fprintf(stderr, "%s:%d: among(...) has repeated string '", + a->tokeniser->file, (w0 + 1)->line_number); + report_b(stderr, (w0 + 1)->b); + fprintf(stderr, "'\n"); + count_error(a); + fprintf(stderr, "%s:%d: previously seen here\n", + a->tokeniser->file, w0->line_number); + } x->literalstring_count = p->number; - x->command_count = result - 1; p->among = x; x->substring = substring; if (substring != 0) substring->among = x; - unless (x->command_count == 0 && x->starter == 0) a->amongvar_needed = true; + if (x->command_count > 1 || + (x->command_count == 1 && x->nocommand_count > 0) || + x->starter != 0) { + /* We need to set among_var rather than just checking if find_among*() + * returns zero or not. + */ + x->amongvar_needed = a->amongvar_needed = true; + } } static struct node * read_among(struct analyser * a) { @@ -514,8 +744,8 @@ static struct node * read_among(struct analyser * a) { a->substring = 0; p->number = 0; /* counts the number of literals */ - unless (get_token(a, c_bra)) return p; - repeat { + if (!get_token(a, c_bra)) return p; + while (true) { struct node * q; int token = read_token(t); switch (token) { @@ -529,12 +759,14 @@ static struct node * read_among(struct analyser * a) { else t->token_held = true; p->number++; break; case c_bra: - if (previous_token == c_bra) error(a, 19); + if (previous_token == c_bra) error(a, e_adjacent_bracketed_in_among); q = read_C_list(a); break; default: - error(a, 3); + error(a, e_unexpected_token_in_among); + previous_token = token; + continue; case c_ket: - if (p->number == 0) error(a, 18); + if (p->number == 0) error(a, e_empty_among); if (t->error_count == 0) make_among(a, p, substring); return p; } @@ -547,13 +779,13 @@ static struct node * read_among(struct analyser * a) { static struct node * read_substring(struct analyser * a) { struct node * p = new_node(a, c_substring); - if (a->substring != 0) error2(a, 20, a->substring->line_number); + if (a->substring != 0) error2(a, e_substring_preceded_by_substring, a->substring->line_number); a->substring = p; return p; } static void check_modifyable(struct analyser * a) { - unless (a->modifyable) error(a, 15); + if (!a->modifyable) error(a, e_not_allowed_inside_reverse); } static struct node * read_C(struct analyser * a) { @@ -565,7 +797,7 @@ static struct node * read_C(struct analyser * a) { case c_backwards: { int mode = a->mode; - if (a->mode == m_backward) error(a, 17); else a->mode = m_backward; + if (a->mode == m_backward) error(a, e_already_backwards); else a->mode = m_backward; { struct node * p = C_style(a, "C", token); a->mode = mode; return p; @@ -596,14 +828,18 @@ static struct node * read_C(struct analyser * a) { case c_loop: case c_atleast: return C_style(a, "AC", token); - case c_setmark: - return C_style(a, "i", token); + case c_setmark: { + struct node * n = C_style(a, "i", token); + if (n->name) n->name->initialised = true; + return n; + } case c_tomark: case c_atmark: case c_hop: return C_style(a, "A", token); case c_delete: check_modifyable(a); + /* fall through */ case c_next: case c_tolimit: case c_atlimit: @@ -612,60 +848,147 @@ static struct node * read_C(struct analyser * a) { case c_true: case c_false: case c_debug: - return C_style(a, "", token); + return new_node(a, token); case c_assignto: - case c_sliceto: + case c_sliceto: { + struct node *n; check_modifyable(a); - return C_style(a, "s", token); + n = C_style(a, "s", token); + if (n->name) n->name->initialised = true; + return n; + } case c_assign: case c_insert: case c_attach: - case c_slicefrom: + case c_slicefrom: { + struct node *n; check_modifyable(a); - return C_style(a, "S", token); + n = C_style(a, "S", token); + if (n->name) n->name->value_used = true; + return n; + } case c_setlimit: return C_style(a, "CfD", token); case c_set: - case c_unset: - return C_style(a, "b", token); - case c_dollar: - get_token(a, c_name); - { + case c_unset: { + struct node * n = C_style(a, "b", token); + if (n->name) n->name->initialised = true; + return n; + } + case c_dollar: { + struct tokeniser * t = a->tokeniser; + read_token(t); + if (t->token == c_bra) { + /* Handle newer $(AE REL_OP AE) syntax. */ + struct node * n = read_AE(a, 0); + read_token(t); + switch (t->token) { + case c_eq: + case c_ne: + case c_gr: + case c_ge: + case c_ls: + case c_le: { + struct node * lhs = n; + n = new_node(a, t->token); + n->left = lhs; + n->AE = read_AE(a, 0); + get_token(a, c_ket); + break; + } + default: + error(a, e_unexpected_token); + t->token_held = true; + break; + } + return n; + } + + if (t->token == c_name) { struct node * p; struct name * q = find_name(a); int mode = a->mode; int modifyable = a->modifyable; - switch (q ? q->type : t_string) - /* above line was: switch (q->type) - bug #1 fix 7/2/2003 */ - { - default: error(a, 34); - case t_string: - a->mode = m_forward; - a->modifyable = true; - p = new_node(a, c_dollar); - p->left = read_C(a); break; - case t_integer: - /* a->mode = m_integer; */ - p = new_node(a, read_AE_test(a)); - p->AE = read_AE(a, 0); break; + if (q && q->type == t_string) { + /* Assume for now that $ on string both initialises and + * uses the string variable. FIXME: Can we do better? + */ + q->initialised = true; + q->value_used = true; + a->mode = m_forward; + a->modifyable = true; + p = new_node(a, c_dollar); + p->left = read_C(a); + p->name = q; + } else { + if (q && q->type != t_integer) { + /* If $ is used on an unknown name or a name which + * isn't a string or an integer then we assume the + * unknown name is an integer as $ is used more often + * on integers than strings, so hopefully this it less + * likely to cause an error avalanche. + * + * For an unknown name, we'll already have reported an + * error. + */ + error(a, e_not_of_type_string_or_integer); + q = NULL; + } + p = new_node(a, read_AE_test(a)); + p->AE = read_AE(a, 0); + + if (q) { + switch (p->type) { + case c_mathassign: + q->initialised = true; + p->name = q; + break; + default: + /* +=, etc don't "initialise" as they only + * amend an existing value. Similarly, they + * don't count as using the value. + */ + p->name = q; + break; + case c_eq: + case c_ne: + case c_gr: + case c_ge: + case c_ls: + case c_le: + p->left = new_node(a, c_name); + p->left->name = q; + q->value_used = true; + break; + } + } } - p->name = q; + if (q) mark_used_in(a, q, p); a->mode = mode; a->modifyable = modifyable; return p; } + + error(a, e_unexpected_token); + t->token_held = true; + return new_node(a, c_dollar); + } case c_name: { struct name * q = find_name(a); struct node * p = new_node(a, c_name); - unless (q == 0) { - q->used = true; + if (q) { + mark_used_in(a, q, p); switch (q->type) { case t_boolean: - p->type = c_booltest; break; + p->type = c_booltest; + q->value_used = true; + break; case t_integer: - error(a, 35); /* integer name misplaced */ + error(a, e_misplaced); /* integer name misplaced */ + break; case t_string: + q->value_used = true; break; case t_routine: case t_external: @@ -684,7 +1007,7 @@ static struct node * read_C(struct analyser * a) { struct node * p = new_node(a, token); read_token(t); if (t->token == c_minus) read_token(t); - unless (check_token(a, c_name)) { omission_error(a, c_name); return p; } + if (!check_token(a, c_name)) { omission_error(a, c_name); return p; } name_to_node(a, p, 'g'); return p; } @@ -692,7 +1015,7 @@ static struct node * read_C(struct analyser * a) { return read_literalstring(a); case c_among: return read_among(a); case c_substring: return read_substring(a); - default: error(a, 1); return 0; + default: error(a, e_unexpected_token); return 0; } } @@ -739,26 +1062,27 @@ static void read_define_grouping(struct analyser * a, struct name * q) { NEW(grouping, p); if (a->groupings == 0) a->groupings = p; else a->groupings_end->next = p; a->groupings_end = p; - q->grouping = p; + if (q) q->grouping = p; p->next = 0; p->name = q; - p->number = q->count; + p->line_number = a->tokeniser->line_number; p->b = create_b(0); - repeat { + while (true) { switch (read_token(t)) { case c_name: { struct name * r = find_name(a); - unless (r == 0) { + if (r) { check_name_type(a, r, 'g'); p->b = alter_grouping(p->b, r->grouping->b, style, false); + r->used_in_definition = true; } } break; case c_literalstring: - p->b = alter_grouping(p->b, t->b, style, a->utf8); + p->b = alter_grouping(p->b, t->b, style, (a->encoding == ENC_UTF8)); break; - default: error(a, 1); return; + default: error(a, e_unexpected_token); return; } switch (read_token(t)) { case c_plus: @@ -777,7 +1101,7 @@ static void read_define_grouping(struct analyser * a, struct name * q) { } p->largest_ch = max; p->smallest_ch = min; - if (min == 1<<16) error(a, 16); + if (min == 1<<16) error(a, e_empty_grouping); } t->token_held = true; return; } @@ -786,32 +1110,49 @@ static void read_define_grouping(struct analyser * a, struct name * q) { static void read_define_routine(struct analyser * a, struct name * q) { struct node * p = new_node(a, c_define); a->amongvar_needed = false; - unless (q == 0) { + if (q) { check_name_type(a, q, 'R'); - if (q->definition != 0) error(a, 36); + if (q->definition != 0) error(a, e_redefined); if (q->mode < 0) q->mode = a->mode; else - if (q->mode != a->mode) error2(a, 32, q->mode); + if (q->mode != a->mode) error2(a, e_declared_as_different_mode, q->mode); } p->name = q; if (a->program == 0) a->program = p; else a->program_end->right = p; a->program_end = p; get_token(a, c_as); p->left = read_C(a); - unless (q == 0) q->definition = p->left; + if (q) q->definition = p->left; if (a->substring != 0) { - error2(a, 14, a->substring->line_number); - a->substring = 0; + error2(a, e_unresolved_substring, a->substring->line_number); + a->substring = 0; } p->amongvar_needed = a->amongvar_needed; } static void read_define(struct analyser * a) { - unless (get_token(a, c_name)) return; - { + if (get_token(a, c_name)) { struct name * q = find_name(a); - if (q != 0 && q->type == t_grouping) read_define_grouping(a, q); - else read_define_routine(a, q); + int type; + if (q) { + type = q->type; + } else { + /* No declaration, so sniff next token - if it is 'as' then parse + * as a routine, otherwise as a grouping. + */ + if (read_token(a->tokeniser) == c_as) { + type = t_routine; + } else { + type = t_grouping; + } + a->tokeniser->token_held = true; + } + + if (type == t_grouping) { + read_define_grouping(a, q); + } else { + read_define_routine(a, q); + } } } @@ -827,7 +1168,7 @@ static void read_backwardmode(struct analyser * a) { static void read_program_(struct analyser * a, int terminator) { struct tokeniser * t = a->tokeniser; - repeat { + while (true) { switch (read_token(t)) { case c_strings: read_names(a, t_string); break; case c_booleans: read_names(a, t_boolean); break; @@ -839,25 +1180,60 @@ static void read_program_(struct analyser * a, int terminator) { case c_backwardmode:read_backwardmode(a); break; case c_ket: if (terminator == c_ket) return; + /* fall through */ default: - error(a, 1); break; + error(a, e_unexpected_token); break; case -1: - unless (terminator < 0) omission_error(a, c_ket); + if (terminator >= 0) omission_error(a, c_ket); return; } } } +static void remove_dead_assignments(struct node * p, struct name * q) { + if (p->name == q) { + switch (p->type) { + case c_assignto: + case c_sliceto: + case c_mathassign: + case c_plusassign: + case c_minusassign: + case c_multiplyassign: + case c_divideassign: + case c_setmark: + case c_set: + case c_unset: + case c_dollar: + /* c_true is a no-op. */ + p->type = c_true; + break; + default: + /* There are no read accesses to this variable, so any + * references must be assignments. + */ + fprintf(stderr, "Unhandled type of dead assignment via %s\n", + name_of_token(p->type)); + exit(1); + } + } + if (p->AE) remove_dead_assignments(p->AE, q); + if (p->left) remove_dead_assignments(p->left, q); + if (p->aux) remove_dead_assignments(p->aux, q); + if (p->right) remove_dead_assignments(p->right, q); +} + extern void read_program(struct analyser * a) { read_program_(a, -1); { struct name * q = a->names; - until (q == 0) { - switch(q->type) { + while (q) { + switch (q->type) { case t_external: case t_routine: - if (q->used && q->definition == 0) { error4(a, q); } break; + if (q->used && q->definition == 0) error4(a, q); + break; case t_grouping: - if (q->used && q->grouping == 0) { error4(a, q); } break; + if (q->used && q->grouping == 0) error4(a, q); + break; } q = q->next; } @@ -865,33 +1241,77 @@ extern void read_program(struct analyser * a) { if (a->tokeniser->error_count == 0) { struct name * q = a->names; - int warned = false; - until (q == 0) { - unless (q->referenced) { - unless (warned) { - fprintf(stderr, "Declared but not used:"); - warned = true; + struct name ** ptr = &(a->names); + while (q) { + if (!q->referenced) { + fprintf(stderr, "%s:%d: warning: %s '", + a->tokeniser->file, + q->declaration_line_number, + name_of_name_type(q->type)); + report_b(stderr, q->b); + if (q->type == t_routine || + q->type == t_external || + q->type == t_grouping) { + fprintf(stderr, "' declared but not defined\n"); + } else { + fprintf(stderr, "' defined but not used\n"); + q = q->next; + *ptr = q; + continue; } - fprintf(stderr, " "); report_b(stderr, q->b); + } else if (q->type == t_routine || q->type == t_grouping) { + /* It's OK to define a grouping but only use it to define other + * groupings. + */ + if (!q->used && !q->used_in_definition) { + int line_num; + if (q->type == t_routine) { + line_num = q->definition->line_number; + } else { + line_num = q->grouping->line_number; + } + fprintf(stderr, "%s:%d: warning: %s '", + a->tokeniser->file, + line_num, + name_of_name_type(q->type)); + report_b(stderr, q->b); + fprintf(stderr, "' defined but not used\n"); + } + } else if (q->type == t_external) { + /* Unused is OK. */ + } else if (!q->initialised) { + fprintf(stderr, "%s:%d: warning: %s '", + a->tokeniser->file, + q->declaration_line_number, + name_of_name_type(q->type)); + report_b(stderr, q->b); + fprintf(stderr, "' is never initialised\n"); + } else if (!q->value_used) { + fprintf(stderr, "%s:%d: warning: %s '", + a->tokeniser->file, + q->declaration_line_number, + name_of_name_type(q->type)); + report_b(stderr, q->b); + fprintf(stderr, "' is set but never used\n"); + remove_dead_assignments(a->program, q); + q = q->next; + *ptr = q; + continue; } + ptr = &(q->next); q = q->next; } - if (warned) fprintf(stderr, "\n"); - q = a->names; - warned = false; - until (q == 0) { - if (! q->used && (q->type == t_routine || - q->type == t_grouping)) { - unless (warned) { - fprintf(stderr, "Declared and defined but not used:"); - warned = true; - } - fprintf(stderr, " "); report_b(stderr, q->b); + { + /* Now we've eliminated variables whose values are never used we + * can number the variables, which is used by some generators. + */ + int * name_count = a->name_count; + struct name * n; + for (n = a->names; n; n = n->next) { + n->count = name_count[n->type]++; } - q = q->next; } - if (warned) fprintf(stderr, "\n"); } } @@ -909,13 +1329,14 @@ extern struct analyser * create_analyser(struct tokeniser * t) { a->modifyable = true; { int i; for (i = 0; i < t_size; i++) a->name_count[i] = 0; } a->substring = 0; + a->int_limits_used = false; return a; } extern void close_analyser(struct analyser * a) { { struct node * q = a->nodes; - until (q == 0) { + while (q) { struct node * q_next = q->next; FREE(q); q = q_next; @@ -923,7 +1344,7 @@ extern void close_analyser(struct analyser * a) { } { struct name * q = a->names; - until (q == 0) { + while (q) { struct name * q_next = q->next; lose_b(q->b); FREE(q); q = q_next; @@ -931,7 +1352,7 @@ extern void close_analyser(struct analyser * a) { } { struct literalstring * q = a->literalstrings; - until (q == 0) { + while (q) { struct literalstring * q_next = q->next; lose_b(q->b); FREE(q); q = q_next; @@ -939,15 +1360,17 @@ extern void close_analyser(struct analyser * a) { } { struct among * q = a->amongs; - until (q == 0) { + while (q) { struct among * q_next = q->next; - FREE(q->b); FREE(q); + FREE(q->b); + FREE(q->commands); + FREE(q); q = q_next; } } { struct grouping * q = a->groupings; - until (q == 0) { + while (q) { struct grouping * q_next = q->next; lose_b(q->b); FREE(q); q = q_next; @@ -955,4 +1378,3 @@ extern void close_analyser(struct analyser * a) { } FREE(a); } - |