X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcontrol%2Frepeat.c;h=796c6e9354702bd5815cd83093a8793b4cc07ac6;hb=94de2220fa2c449bd99571639b8cabbe28824698;hp=6cfbb6bba5cbc3ff911f81c09b3828488c8bcb52;hpb=b990f5c31bc831e588a86f9f4826387c6843c989;p=pspp diff --git a/src/language/control/repeat.c b/src/language/control/repeat.c index 6cfbb6bba5..796c6e9354 100644 --- a/src/language/control/repeat.c +++ b/src/language/control/repeat.c @@ -18,29 +18,32 @@ 02110-1301, USA. */ #include + #include "repeat.h" -#include + #include #include #include -#include -#include + #include -#include "intprops.h" -#include -#include +#include +#include +#include +#include #include +#include +#include +#include #include #include -#include #include #include +#include "intprops.h" + #include "gettext.h" #define _(msgid) gettext (msgid) -#include - /* Defines a list of lines used by DO REPEAT. */ struct line_list { @@ -69,7 +72,10 @@ struct repeat_entry /* A DO REPEAT...END REPEAT block. */ struct repeat_block { + struct getl_interface parent ; + struct pool *pool; /* Pool used for storage. */ + struct dataset *ds; /* The dataset for this block */ struct line_list *first_line; /* First line in line buffer. */ struct line_list *cur_line; /* Current line in line buffer. */ int loop_cnt; /* Number of loops. */ @@ -78,35 +84,47 @@ struct repeat_block bool print; /* Print lines as executed? */ }; -static bool parse_specification (struct repeat_block *); -static bool parse_lines (struct repeat_block *); +static bool parse_specification (struct lexer *, struct repeat_block *); +static bool parse_lines (struct lexer *, struct repeat_block *); static void create_vars (struct repeat_block *); -static int parse_ids (struct repeat_entry *); -static int parse_numbers (struct repeat_entry *); -static int parse_strings (struct repeat_entry *); +static int parse_ids (struct lexer *, const struct dictionary *dict, + struct repeat_entry *, struct pool *); + +static int parse_numbers (struct lexer *, struct repeat_entry *, + struct pool *); + +static int parse_strings (struct lexer *, struct repeat_entry *, + struct pool *); + +static void do_repeat_filter (struct getl_interface *, struct string *); +static bool do_repeat_read (struct getl_interface *, struct string *); +static void do_repeat_close (struct getl_interface *); +static bool always_false (const struct getl_interface *i UNUSED); -static void do_repeat_filter (struct string *line, void *block); -static bool do_repeat_read (struct string *line, char **file_name, - int *line_number, void *block); -static void do_repeat_close (void *block); int -cmd_do_repeat (void) +cmd_do_repeat (struct lexer *lexer, struct dataset *ds) { struct repeat_block *block; block = pool_create_container (struct repeat_block, pool); + block->ds = ds; - if (!parse_specification (block) || !parse_lines (block)) + if (!parse_specification (lexer, block) || !parse_lines (lexer, block)) goto error; create_vars (block); block->cur_line = NULL; block->loop_idx = -1; - getl_include_filter (do_repeat_filter, do_repeat_close, block); - getl_include_function (do_repeat_read, NULL, block); + + block->parent.read = do_repeat_read; + block->parent.close = do_repeat_close; + block->parent.filter = do_repeat_filter; + block->parent.interactive = always_false; + + getl_include_source ( (struct getl_interface *) block); return CMD_SUCCESS; @@ -118,7 +136,7 @@ cmd_do_repeat (void) /* Parses the whole DO REPEAT command specification. Returns success. */ static bool -parse_specification (struct repeat_block *block) +parse_specification (struct lexer *lexer, struct repeat_block *block) { char first_name[LONG_NAME_LEN + 1]; @@ -128,19 +146,21 @@ parse_specification (struct repeat_block *block) { struct repeat_entry *e; struct repeat_entry *iter; + struct dictionary *dict = dataset_dict (block->ds); int count; /* Get a stand-in variable name and make sure it's unique. */ - if (!lex_force_id ()) + if (!lex_force_id (lexer)) return false; - if (dict_lookup_var (default_dict, tokid)) + if (dict_lookup_var (dict, lex_tokid (lexer))) msg (SW, _("Dummy variable name \"%s\" hides dictionary " "variable \"%s\"."), - tokid, tokid); + lex_tokid (lexer), lex_tokid (lexer)); for (iter = block->macros; iter != NULL; iter = iter->next) - if (!strcasecmp (iter->id, tokid)) + if (!strcasecmp (iter->id, lex_tokid (lexer))) { - msg (SE, _("Dummy variable name \"%s\" is given twice."), tokid); + msg (SE, _("Dummy variable name \"%s\" is given twice."), + lex_tokid (lexer)); return false; } @@ -148,28 +168,33 @@ parse_specification (struct repeat_block *block) list. */ e = pool_alloc (block->pool, sizeof *e); e->next = block->macros; - strcpy (e->id, tokid); + strcpy (e->id, lex_tokid (lexer)); block->macros = e; /* Skip equals sign. */ - lex_get (); - if (!lex_force_match ('=')) + lex_get (lexer); + if (!lex_force_match (lexer, '=')) return false; /* Get the details of the variable's possible values. */ - if (token == T_ID) - count = parse_ids (e); - else if (lex_is_number ()) - count = parse_numbers (e); - else if (token == T_STRING) - count = parse_strings (e); + if (lex_token (lexer) == T_ID) + count = parse_ids (lexer, dict, e, block->pool); + else if (lex_is_number (lexer)) + count = parse_numbers (lexer, e, block->pool); + else if (lex_token (lexer) == T_STRING) + count = parse_strings (lexer, e, block->pool); else { - lex_error (NULL); + lex_error (lexer, NULL); return false; } if (count == 0) return false; + if (lex_token (lexer) != '/' && lex_token (lexer) != '.') + { + lex_error (lexer, NULL); + return false; + } /* If this is the first variable then it defines how many replacements there must be; otherwise enforce this number of @@ -188,9 +213,9 @@ parse_specification (struct repeat_block *block) return false; } - lex_match ('/'); + lex_match (lexer, '/'); } - while (token != '.'); + while (lex_token (lexer) != '.'); return true; } @@ -253,7 +278,7 @@ recognize_end_repeat (const char *line, bool *print) /* Read all the lines we are going to substitute, inside the DO REPEAT...END REPEAT block. */ static bool -parse_lines (struct repeat_block *block) +parse_lines (struct lexer *lexer, struct repeat_block *block) { char *previous_file_name; struct line_list **last_line; @@ -266,44 +291,51 @@ parse_lines (struct repeat_block *block) for (;;) { - const char *cur_file_name; - int cur_line_number; + const char *cur_file_name = getl_source_name (); + int cur_line_number = getl_source_location (); struct line_list *line; + struct string cur_line_copy; bool dot; - if (!getl_read_line (NULL)) + if (! lex_get_line_raw (lexer)) return false; /* If the current file has changed then record the fact. */ - getl_location (&cur_file_name, &cur_line_number); - if (previous_file_name == NULL + if (cur_file_name && + (previous_file_name == NULL || !strcmp (cur_file_name, previous_file_name)) + ) previous_file_name = pool_strdup (block->pool, cur_file_name); - ds_rtrim_spaces (&getl_buf); - dot = ds_chomp (&getl_buf, get_endcmd ()); - if (recognize_do_repeat (ds_c_str (&getl_buf))) + ds_init_string (&cur_line_copy, lex_entire_line_ds (lexer) ); + ds_rtrim (&cur_line_copy, ss_cstr (CC_SPACES)); + dot = ds_chomp (&cur_line_copy, get_endcmd ()); + + if (recognize_do_repeat (ds_cstr (&cur_line_copy))) nesting_level++; - else if (recognize_end_repeat (ds_c_str (&getl_buf), &block->print)) + else if (recognize_end_repeat (ds_cstr (&cur_line_copy), &block->print)) { if (nesting_level-- == 0) { - lex_discard_line (); + lex_discard_line (lexer); + ds_destroy (&cur_line_copy); return true; } } if (dot) - ds_putc (&getl_buf, get_endcmd ()); + ds_put_char (&cur_line_copy, get_endcmd ()); line = *last_line = pool_alloc (block->pool, sizeof *line); line->next = NULL; line->file_name = previous_file_name; line->line_number = cur_line_number; - line->line = pool_strdup (block->pool, ds_c_str (&getl_buf)); + line->line = pool_strdup (block->pool, ds_cstr (&cur_line_copy) ); last_line = &line->next; + + ds_destroy (&cur_line_copy); } - lex_discard_line (); + lex_discard_line (lexer); return true; } @@ -322,160 +354,118 @@ create_vars (struct repeat_block *block) { /* Ignore return value: if the variable already exists there is no harm done. */ - dict_create_var (default_dict, iter->replacement[i], 0); + dict_create_var (dataset_dict (block->ds), iter->replacement[i], 0); } } } /* Parses a set of ids for DO REPEAT. */ static int -parse_ids (struct repeat_entry *e) +parse_ids (struct lexer *lexer, const struct dictionary *dict, + struct repeat_entry *e, struct pool *pool) { - size_t i; size_t n = 0; - e->type = VAR_NAMES; - e->replacement = NULL; - - do - { - char **names; - size_t nnames; - - if (!parse_mixed_vars (&names, &nnames, PV_NONE)) - return 0; - - e->replacement = xnrealloc (e->replacement, - nnames + n, sizeof *e->replacement); - for (i = 0; i < nnames; i++) - { - e->replacement[n + i] = xstrdup (names[i]); - free (names[i]); - } - free (names); - n += nnames; - } - while (token != '/' && token != '.'); - - return n; + return parse_mixed_vars_pool (lexer, dict, pool, + &e->replacement, &n, PV_NONE) ? n : 0; } -/* Stores VALUE into *REPL. */ -static inline void -store_numeric (char **repl, long value) +/* Adds STRING to E's list of replacements, which has *USED + elements and has room for *ALLOCATED. Allocates memory from + POOL. */ +static void +add_replacement (char *string, + struct repeat_entry *e, struct pool *pool, + size_t *used, size_t *allocated) { - *repl = xmalloc (INT_STRLEN_BOUND (value) + 1); - sprintf (*repl, "%ld", value); + if (*used == *allocated) + e->replacement = pool_2nrealloc (pool, e->replacement, allocated, + sizeof *e->replacement); + e->replacement[(*used)++] = string; } /* Parses a list of numbers for DO REPEAT. */ static int -parse_numbers (struct repeat_entry *e) +parse_numbers (struct lexer *lexer, struct repeat_entry *e, struct pool *pool) { - /* First and last numbers for TO, plus the step factor. */ - long a, b; - - /* Alias to e->replacement. */ - char **array; - - /* Number of entries in array; maximum number for this allocation - size. */ - int n, m; - - n = m = 0; + size_t used = 0; + size_t allocated = 0; + e->type = OTHER; - e->replacement = array = NULL; + e->replacement = NULL; do { + long a, b, i; + /* Parse A TO B into a, b. */ - if (!lex_force_int ()) + if (!lex_force_int (lexer)) return 0; - a = lex_integer (); + a = lex_integer (lexer); - lex_get (); - if (token == T_TO) + lex_get (lexer); + if (lex_token (lexer) == T_TO) { - lex_get (); - if (!lex_force_int ()) + lex_get (lexer); + if (!lex_force_int (lexer)) return 0; - b = lex_integer (); - - lex_get (); + b = lex_integer (lexer); + if (b < a) + { + msg (SE, _("%ld TO %ld is an invalid range."), a, b); + return 0; + } + lex_get (lexer); } - else b = a; + else + b = a; - if (n + (abs (b - a) + 1) > m) - { - m = n + (abs (b - a) + 1) + 16; - e->replacement = array = xnrealloc (array, - m, sizeof *e->replacement); - } + for (i = a; i <= b; i++) + add_replacement (pool_asprintf (pool, "%ld", i), + e, pool, &used, &allocated); - if (a == b) - store_numeric (&array[n++], a); - else - { - long iter; - - if (a < b) - for (iter = a; iter <= b; iter++) - store_numeric (&array[n++], iter); - else - for (iter = a; iter >= b; iter--) - store_numeric (&array[n++], iter); - } - lex_match (','); + lex_match (lexer, ','); } - while (token != '/' && token != '.'); - e->replacement = xrealloc (array, n * sizeof *e->replacement); + while (lex_token (lexer) != '/' && lex_token (lexer) != '.'); - return n; + return used; } /* Parses a list of strings for DO REPEAT. */ int -parse_strings (struct repeat_entry *e) +parse_strings (struct lexer *lexer, struct repeat_entry *e, struct pool *pool) { - char **string; - int n, m; - + size_t used = 0; + size_t allocated = 0; + e->type = OTHER; - string = e->replacement = NULL; - n = m = 0; + e->replacement = NULL; do { - if (token != T_STRING) + char *string; + + if (lex_token (lexer) != T_STRING) { - int i; msg (SE, _("String expected.")); - for (i = 0; i < n; i++) - free (string[i]); - free (string); return 0; } - if (n + 1 > m) - { - m += 16; - e->replacement = string = xnrealloc (string, - m, sizeof *e->replacement); - } - string[n++] = lex_token_representation (); - lex_get (); + string = lex_token_representation (lexer); + pool_register (pool, free, string); + add_replacement (string, e, pool, &used, &allocated); - lex_match (','); + lex_get (lexer); + lex_match (lexer, ','); } - while (token != '/' && token != '.'); - e->replacement = xnrealloc (string, n, sizeof *e->replacement); + while (lex_token (lexer) != '/' && lex_token (lexer) != '.'); - return n; + return used; } int -cmd_end_repeat (void) +cmd_end_repeat (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) { msg (SE, _("No matching DO REPEAT.")); return CMD_CASCADING_FAILURE; @@ -495,17 +485,18 @@ find_substitution (struct repeat_block *block, const char *name, size_t length) return NULL; } -/* Makes appropriate DO REPEAT macro substitutions within getl_buf. */ +/* Makes appropriate DO REPEAT macro substitutions within the + repeated lines. */ static void -do_repeat_filter (struct string *line, void *block_) +do_repeat_filter (struct getl_interface *block_, struct string *line) { - struct repeat_block *block = block_; + struct repeat_block *block = (struct repeat_block *) block_; bool in_apos, in_quote; char *cp; struct string output; bool dot; - ds_init (&output, ds_capacity (line)); + ds_init_empty (&output); /* Strip trailing whitespace, check for & remove terminal dot. */ while (isspace (ds_last (line))) @@ -513,7 +504,7 @@ do_repeat_filter (struct string *line, void *block_) dot = ds_chomp (line, get_endcmd ()); in_apos = in_quote = false; - for (cp = ds_c_str (line); cp < ds_end (line); ) + for (cp = ds_cstr (line); cp < ds_end (line); ) { if (*cp == '\'' && !in_quote) in_apos = !in_apos; @@ -521,7 +512,7 @@ do_repeat_filter (struct string *line, void *block_) in_quote = !in_quote; if (in_quote || in_apos || !lex_is_id1 (*cp)) - ds_putc (&output, *cp++); + ds_put_char (&output, *cp++); else { const char *start = cp; @@ -529,14 +520,14 @@ do_repeat_filter (struct string *line, void *block_) const char *substitution = find_substitution (block, start, end - start); if (substitution != NULL) - ds_puts (&output, substitution); + ds_put_cstr (&output, substitution); else - ds_concat (&output, start, end - start); + ds_put_substring (&output, ss_buffer (start, end - start)); cp = end; } } if (dot) - ds_putc (&output, get_endcmd ()); + ds_put_char (&output, get_endcmd ()); ds_swap (line, &output); ds_destroy (&output); @@ -546,11 +537,10 @@ do_repeat_filter (struct string *line, void *block_) Puts the line in OUTPUT, sets the file name in *FILE_NAME and line number in *LINE_NUMBER. Returns true if a line was obtained, false if the source is exhausted. */ -static bool -do_repeat_read (struct string *output, char **file_name, int *line_number, - void *block_) +static bool +do_repeat_read (struct getl_interface *b, struct string *output) { - struct repeat_block *block = block_; + struct repeat_block *block = (struct repeat_block *) b; struct line_list *line; if (block->cur_line == NULL) @@ -562,9 +552,7 @@ do_repeat_read (struct string *output, char **file_name, int *line_number, } line = block->cur_line; - ds_assign_c_str (output, line->line); - *file_name = line->file_name; - *line_number = -line->line_number; + ds_assign_cstr (output, line->line); block->cur_line = line->next; return true; } @@ -572,8 +560,15 @@ do_repeat_read (struct string *output, char **file_name, int *line_number, /* Frees a DO REPEAT block. Called by getl to close out the DO REPEAT block. */ static void -do_repeat_close (void *block_) +do_repeat_close (struct getl_interface *block_) { - struct repeat_block *block = block_; + struct repeat_block *block = (struct repeat_block *) block_; pool_destroy (block->pool); } + + +static bool +always_false (const struct getl_interface *i UNUSED) +{ + return false; +}