X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fvars-prs.c;h=9a559d2e0ca016f3bd894a9e4014c808dc986b9e;hb=a7cc8b259f0fe963aa30d4e64f7d39551ded1454;hp=66fec9ae9ea1de88ec920c3c1adc88eb38dcba57;hpb=f2828f801736701c0294803b5dedd4c4ab63b45e;p=pspp-builds.git diff --git a/src/vars-prs.c b/src/vars-prs.c index 66fec9ae..9a559d2e 100644 --- a/src/vars-prs.c +++ b/src/vars-prs.c @@ -19,38 +19,54 @@ #include #include "var.h" -#include #include #include #include "alloc.h" #include "bitvector.h" +#include "dictionary.h" #include "error.h" #include "hash.h" #include "lexer.h" #include "misc.h" #include "str.h" -static struct variable * -parse_vs_variable (struct var_set *vs) +/* Parses a name as a variable within VS and returns the + variable's index if successful. On failure emits an error + message and returns a null pointer. */ +static int +parse_vs_variable_idx (const struct var_set *vs) { - struct variable *vp; + int idx; if (token != T_ID) { - lex_error ("expecting variable name"); - return NULL; + lex_error (_("expecting variable name")); + return -1; } - vp = var_set_lookup_var (vs, tokid); - if (vp == NULL) + idx = var_set_lookup_var_idx (vs, tokid); + if (idx < 0) msg (SE, _("%s is not a variable name."), tokid); lex_get (); - return vp; + return idx; } +/* Parses a name as a variable within VS and returns the variable + if successful. On failure emits an error message and returns + a null pointer. */ +static struct variable * +parse_vs_variable (const struct var_set *vs) +{ + int idx = parse_vs_variable_idx (vs); + return idx >= 0 ? var_set_get_var (vs, idx) : NULL; +} + +/* Parses a variable name in dictionary D and returns the + variable if successful. On failure emits an error message and + returns a null pointer. */ struct variable * -parse_dict_variable (struct dictionary *d) +parse_dict_variable (const struct dictionary *d) { struct var_set *vs = var_set_create_from_dict (d); struct variable *var = parse_vs_variable (vs); @@ -58,13 +74,17 @@ parse_dict_variable (struct dictionary *d) return var; } +/* Parses a variable name in default_dict and returns the + variable if successful. On failure emits an error message and + returns a null pointer. */ struct variable * parse_variable (void) { return parse_dict_variable (default_dict); } - +/* Returns the dictionary class corresponding to a variable named + NAME. */ enum dict_class dict_class_from_id (const char *name) { @@ -81,25 +101,31 @@ dict_class_from_id (const char *name) } } +/* Returns the name of dictionary class DICT_CLASS. */ const char * dict_class_to_name (enum dict_class dict_class) { switch (dict_class) { case DC_ORDINARY: - return "ordinary"; + return _("ordinary"); case DC_SYSTEM: - return "system"; + return _("system"); case DC_SCRATCH: - return "scratch"; + return _("scratch"); default: assert (0); + abort (); } } +/* Parses a set of variables from dictionary D given options + OPTS. Resulting list of variables stored in *VAR and the + number of variables into *CNT. Returns nonzero only if + successful. */ int -parse_variables (struct dictionary *d, struct variable ***var, int *cnt, - int opts) +parse_variables (const struct dictionary *d, struct variable ***var, + int *cnt, int opts) { struct var_set *vs; int success; @@ -110,25 +136,102 @@ parse_variables (struct dictionary *d, struct variable ***var, int *cnt, vs = var_set_create_from_dict (d); success = parse_var_set_vars (vs, var, cnt, opts); + if ( success == 0 ) + free ( *var ) ; var_set_destroy (vs); return success; } +/* Parses a variable name from VS. If successful, sets *IDX to + the variable's index in VS, *CLASS to the variable's + dictionary class, and returns nonzero. Returns zero on + failure. */ +static int +parse_var_idx_class (const struct var_set *vs, int *idx, + enum dict_class *class) +{ + *idx = parse_vs_variable_idx (vs); + if (*idx < 0) + return 0; + + *class = dict_class_from_id (var_set_get_var (vs, *idx)->name); + return 1; +} + +/* Add the variable from VS with index IDX to the list of + variables V that has *NV elements and room for *MV. + Uses and updates INCLUDED to avoid duplicates if indicated by + PV_OPTS, which also affects what variables are allowed in + appropriate ways. */ +static void +add_variable (struct variable ***v, int *nv, int *mv, + char *included, int pv_opts, + const struct var_set *vs, int idx) +{ + struct variable *add = var_set_get_var (vs, idx); + + if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) + msg (SW, _("%s is not a numeric variable. It will not be " + "included in the variable list."), add->name); + else if ((pv_opts & PV_STRING) && add->type != ALPHA) + msg (SE, _("%s is not a string variable. It will not be " + "included in the variable list."), add->name); + else if ((pv_opts & PV_NO_SCRATCH) + && dict_class_from_id (add->name) == DC_SCRATCH) + msg (SE, _("Scratch variables (such as %s) are not allowed " + "here."), add->name); + else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) + msg (SE, _("%s and %s are not the same type. All variables in " + "this variable list must be of the same type. %s " + "will be omitted from list."), + (*v)[0]->name, add->name, add->name); + else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) + msg (SE, _("Variable %s appears twice in variable list."), add->name); + else + { + if (*nv >= *mv) + { + *mv = 2 * (*nv + 1); + *v = xrealloc (*v, *mv * sizeof **v); + } + + if ((pv_opts & PV_DUPLICATE) || !included[idx]) + { + (*v)[(*nv)++] = add; + if (!(pv_opts & PV_DUPLICATE)) + included[idx] = 1; + } + } +} + +/* Adds the variables in VS with indexes FIRST_IDX through + LAST_IDX, inclusive, to the list of variables V that has *NV + elements and room for *MV. Uses and updates INCLUDED to avoid + duplicates if indicated by PV_OPTS, which also affects what + variables are allowed in appropriate ways. */ +static void +add_variables (struct variable ***v, int *nv, int *mv, char *included, + int pv_opts, + const struct var_set *vs, int first_idx, int last_idx, + enum dict_class class) +{ + int i; + + for (i = first_idx; i <= last_idx; i++) + if (dict_class_from_id (var_set_get_var (vs, i)->name) == class) + add_variable (v, nv, mv, included, pv_opts, vs, i); +} + /* Note that if parse_variables() returns 0, *v is free()'d. Conversely, if parse_variables() returns non-zero, then *nv is nonzero and *v is non-NULL. */ int -parse_var_set_vars (struct var_set *vs, +parse_var_set_vars (const struct var_set *vs, struct variable ***v, int *nv, int pv_opts) { - size_t vs_var_cnt; - int i; - char *included = NULL; - - struct variable *v1, *v2; - int count, mv; - enum dict_class dict_class; + int mv; + char *included; assert (vs != NULL); assert (v != NULL); @@ -143,8 +246,6 @@ parse_var_set_vars (struct var_set *vs, /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */ assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE)); - vs_var_cnt = var_set_get_cnt (vs); - if (!(pv_opts & PV_APPEND)) { *v = NULL; @@ -156,147 +257,91 @@ parse_var_set_vars (struct var_set *vs, if (!(pv_opts & PV_DUPLICATE)) { - included = xmalloc (vs_var_cnt); - memset (included, 0, vs_var_cnt); + int i; + + included = xcalloc (var_set_get_cnt (vs)); for (i = 0; i < *nv; i++) included[(*v)[i]->index] = 1; } + else + included = NULL; - do + if (lex_match (T_ALL)) + add_variables (v, nv, &mv, included, pv_opts, + vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY); + else { - if (lex_match (T_ALL)) - { - v1 = var_set_get_var (vs, 0); - v2 = var_set_get_var (vs, vs_var_cnt - 1); - count = vs_var_cnt; - dict_class = DC_ORDINARY; - } - else - { - v1 = parse_vs_variable (vs); - if (!v1) - goto fail; + do + { + enum dict_class class; + int first_idx; + + if (!parse_var_idx_class (vs, &first_idx, &class)) + goto fail; - if (lex_match (T_TO)) - { - enum dict_class dict_class_2; - - v2 = parse_vs_variable (vs); - if (!v2) - { - lex_error ("expecting variable name"); - goto fail; - } - - count = v2->index - v1->index + 1; - if (count < 1) - { - msg (SE, _("%s TO %s is not valid syntax since %s " - "precedes %s in the dictionary."), - v1->name, v2->name, v2->name, v1->name); - goto fail; - } - - dict_class = dict_class_from_id (v1->name); - dict_class_2 = dict_class_from_id (v2->name); - if (dict_class != dict_class_2) - { - msg (SE, _("When using the TO keyword to specify several " + if (!lex_match (T_TO)) + add_variable (v, nv, &mv, included, pv_opts, + vs, first_idx); + else + { + int last_idx; + enum dict_class last_class; + struct variable *first_var, *last_var; + + if (!parse_var_idx_class (vs, &last_idx, &last_class)) + goto fail; + + first_var = var_set_get_var (vs, first_idx); + last_var = var_set_get_var (vs, last_idx); + + if (last_idx < first_idx) + { + msg (SE, _("%s TO %s is not valid syntax since %s " + "precedes %s in the dictionary."), + first_var->name, last_var->name, + first_var->name, last_var->name); + goto fail; + } + + if (class != last_class) + { + msg (SE, _("When using the TO keyword to specify several " "variables, both variables must be from " "the same variable dictionaries, of either " "ordinary, scratch, or system variables. " "%s is a %s variable, whereas %s is %s."), - v1->name, dict_class_to_name (dict_class), - v2->name, dict_class_to_name (dict_class_2)); - goto fail; - } - } - else - { - v2 = v1; - count = 1; - dict_class = dict_class_from_id (v1->name); - } - if (dict_class == DC_SCRATCH && (pv_opts & PV_NO_SCRATCH)) - { - msg (SE, _("Scratch variables (such as %s) are not allowed " - "here."), v1->name); - goto fail; - } - } - - if (*nv + count > mv) - { - mv += ROUND_UP (count, 16); - *v = xrealloc (*v, mv * sizeof **v); - } - - /* Add v1...v2 to the list. */ - for (i = v1->index; i <= v2->index; i++) - { - struct variable *add = var_set_get_var (vs, i); - - /* Skip over other dictionaries. */ - if (dict_class != dict_class_from_id (add->name)) - continue; - - /* Different kinds of errors. */ - if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) - msg (SW, _("%s is not a numeric variable. It will not be " - "included in the variable list."), add->name); - else if ((pv_opts & PV_STRING) && add->type != ALPHA) - msg (SE, _("%s is not a string variable. It will not be " - "included in the variable list."), add->name); - else if ((pv_opts & PV_SAME_TYPE) && *nv - && add->type != (*v)[0]->type) - msg (SE, _("%s and %s are not the same type. All variables in " - "this variable list must be of the same type. %s " - "will be omitted from list."), - (*v)[0]->name, add->name, add->name); - else if ((pv_opts & PV_NO_DUPLICATE) && included[add->index]) - msg (SE, _("Variable %s appears twice in variable list."), - add->name); - else { - /* Success--add the variable to the list. */ - if ((pv_opts & PV_DUPLICATE) || !included[add->index]) - { - (*v)[(*nv)++] = var_set_get_var (vs, i); - if (!(pv_opts & PV_DUPLICATE)) - included[add->index] = 1; - } - - /* Next. */ - continue; - } - - /* Arrive here only on failure. */ + first_var->name, dict_class_to_name (class), + last_var->name, dict_class_to_name (last_class)); + goto fail; + } + + add_variables (v, nv, &mv, included, pv_opts, + vs, first_idx, last_idx, class); + } if (pv_opts & PV_SINGLE) - goto fail; - } - - /* We finished adding v1...v2 to the list. */ - if (pv_opts & PV_SINGLE) - return 1; - lex_match (','); + break; + lex_match (','); + } + while (token == T_ID && var_set_lookup_var (vs, tokid) != NULL); } - while ((token == T_ID && var_set_lookup_var (vs, tokid) != NULL) - || token == T_ALL); - - if (!(pv_opts & PV_DUPLICATE)) - free (included); - if (!*nv) + + if (*nv == 0) goto fail; + + free (included); return 1; fail: + free (included); free (*v); *v = NULL; *nv = 0; - if (!(pv_opts & PV_DUPLICATE)) - free (included); return 0; } +/* Extracts a numeric suffix from variable name S, copying it + into string R. Sets *D to the length of R and *N to its + value. */ static int extract_num (char *s, char *r, int *n, int *d) { @@ -375,7 +420,8 @@ parse_DATA_LIST_vars (char ***names, int *nnames, int pv_opts) lex_error ("expecting variable name"); goto fail; } - if (tokid[0] == '#' && (pv_opts & PV_NO_SCRATCH)) + if (dict_class_from_id (tokid) == DC_SCRATCH + && (pv_opts & PV_NO_SCRATCH)) { msg (SE, _("Scratch variables not allowed here.")); goto fail; @@ -502,25 +548,29 @@ fail: return 0; } +/* A set of variables. */ struct var_set { - size_t (*get_cnt) (struct var_set *); - struct variable *(*get_var) (struct var_set *, size_t idx); - struct variable *(*lookup_var) (struct var_set *, const char *); + size_t (*get_cnt) (const struct var_set *); + struct variable *(*get_var) (const struct var_set *, size_t idx); + int (*lookup_var_idx) (const struct var_set *, const char *); void (*destroy) (struct var_set *); void *aux; }; +/* Returns the number of variables in VS. */ size_t -var_set_get_cnt (struct var_set *vs) +var_set_get_cnt (const struct var_set *vs) { assert (vs != NULL); return vs->get_cnt (vs); } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ struct variable * -var_set_get_var (struct var_set *vs, size_t idx) +var_set_get_var (const struct var_set *vs, size_t idx) { assert (vs != NULL); assert (idx < var_set_get_cnt (vs)); @@ -528,16 +578,28 @@ var_set_get_var (struct var_set *vs, size_t idx) return vs->get_var (vs, idx); } +/* Returns the variable in VS named NAME, or a null pointer if VS + contains no variable with that name. */ struct variable * -var_set_lookup_var (struct var_set *vs, const char *name) +var_set_lookup_var (const struct var_set *vs, const char *name) +{ + int idx = var_set_lookup_var_idx (vs, name); + return idx >= 0 ? var_set_get_var (vs, idx) : NULL; +} + +/* Returns the index in VS of the variable named NAME, or -1 if + VS contains no variable with that name. */ +int +var_set_lookup_var_idx (const struct var_set *vs, const char *name) { assert (vs != NULL); assert (name != NULL); assert (strlen (name) < 9); - return vs->lookup_var (vs, name); + return vs->lookup_var_idx (vs, name); } +/* Destroys VS. */ void var_set_destroy (struct var_set *vs) { @@ -545,82 +607,97 @@ var_set_destroy (struct var_set *vs) vs->destroy (vs); } +/* Returns the number of variables in VS. */ static size_t -dict_var_set_get_cnt (struct var_set *vs) +dict_var_set_get_cnt (const struct var_set *vs) { struct dictionary *d = vs->aux; return dict_get_var_cnt (d); } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ static struct variable * -dict_var_set_get_var (struct var_set *vs, size_t idx) +dict_var_set_get_var (const struct var_set *vs, size_t idx) { struct dictionary *d = vs->aux; return dict_get_var (d, idx); } -static struct variable * -dict_var_set_lookup_var (struct var_set *vs, const char *name) +/* Returns the index of the variable in VS named NAME, or -1 if + VS contains no variable with that name. */ +static int +dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name) { struct dictionary *d = vs->aux; - - return dict_lookup_var (d, name); + struct variable *v = dict_lookup_var (d, name); + return v != NULL ? v->index : -1; } +/* Destroys VS. */ static void dict_var_set_destroy (struct var_set *vs) { free (vs); } +/* Returns a variable set based on D. */ struct var_set * -var_set_create_from_dict (struct dictionary *d) +var_set_create_from_dict (const struct dictionary *d) { struct var_set *vs = xmalloc (sizeof *vs); vs->get_cnt = dict_var_set_get_cnt; vs->get_var = dict_var_set_get_var; - vs->lookup_var = dict_var_set_lookup_var; + vs->lookup_var_idx = dict_var_set_lookup_var_idx; vs->destroy = dict_var_set_destroy; - vs->aux = d; + vs->aux = (void *) d; return vs; } +/* A variable set based on an array. */ struct array_var_set { - struct variable **var; - size_t var_cnt; - struct hsh_table *name_tab; + struct variable *const *var;/* Array of variables. */ + size_t var_cnt; /* Number of elements in var. */ + struct hsh_table *name_tab; /* Hash from variable names to variables. */ }; +/* Returns the number of variables in VS. */ static size_t -array_var_set_get_cnt (struct var_set *vs) +array_var_set_get_cnt (const struct var_set *vs) { struct array_var_set *avs = vs->aux; return avs->var_cnt; } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ static struct variable * -array_var_set_get_var (struct var_set *vs, size_t idx) +array_var_set_get_var (const struct var_set *vs, size_t idx) { struct array_var_set *avs = vs->aux; - return avs->var[idx]; + return (struct variable *) avs->var[idx]; } -static struct variable * -array_var_set_lookup_var (struct var_set *vs, const char *name) +/* Returns the index of the variable in VS named NAME, or -1 if + VS contains no variable with that name. */ +static int +array_var_set_lookup_var_idx (const struct var_set *vs, const char *name) { struct array_var_set *avs = vs->aux; - struct variable v; + struct variable v, *vp, *const *vpp; strcpy (v.name, name); - - return hsh_find (avs->name_tab, &v); + vp = &v; + vpp = hsh_find (avs->name_tab, &vp); + return vpp != NULL ? vpp - avs->var : -1; } +/* Destroys VS. */ static void array_var_set_destroy (struct var_set *vs) { @@ -631,8 +708,10 @@ array_var_set_destroy (struct var_set *vs) free (vs); } +/* Returns a variable set based on the VAR_CNT variables in + VAR. */ struct var_set * -var_set_create_from_array (struct variable **var, size_t var_cnt) +var_set_create_from_array (struct variable *const *var, size_t var_cnt) { struct var_set *vs; struct array_var_set *avs; @@ -641,16 +720,16 @@ var_set_create_from_array (struct variable **var, size_t var_cnt) vs = xmalloc (sizeof *vs); vs->get_cnt = array_var_set_get_cnt; vs->get_var = array_var_set_get_var; - vs->lookup_var = array_var_set_lookup_var; + vs->lookup_var_idx = array_var_set_lookup_var_idx; vs->destroy = array_var_set_destroy; vs->aux = avs = xmalloc (sizeof *avs); avs->var = var; avs->var_cnt = var_cnt; avs->name_tab = hsh_create (2 * var_cnt, - compare_variables, hash_variable, NULL, + compare_var_ptr_names, hash_var_ptr_name, NULL, NULL); for (i = 0; i < var_cnt; i++) - if (hsh_insert (avs->name_tab, var[i]) != NULL) + if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) { var_set_destroy (vs); return NULL;