bool
lex_match_variable (struct lexer *lexer, const struct dictionary *dict, const struct variable **var)
{
- if (lex_token (lexer) != T_ID)
+ if (lex_token (lexer) != T_ID)
return false;
- *var = parse_variable_const (lexer, dict);
-
- if (*var == NULL)
- return false;
- return true;
+ *var = parse_variable_const (lexer, dict);
+ return *var != NULL;
}
-
-/* An interaction is a variable followed by {*, BY} followed by an interaction */
-static bool
-parse_internal_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact, struct interaction **it)
-{
- const struct variable *v = NULL;
- assert (iact);
-
- switch (lex_next_token (lexer, 1))
- {
- case T_ENDCMD:
- case T_SLASH:
- case T_COMMA:
- case T_ID:
- case T_BY:
- case T_ASTERISK:
- break;
- default:
- return false;
- break;
- }
-
- if (! lex_match_variable (lexer, dict, &v))
- {
- if (it)
- interaction_destroy (*it);
- *iact = NULL;
- return false;
- }
-
- assert (v);
-
- if (*iact == NULL)
- *iact = interaction_create (v);
- else
- interaction_add_variable (*iact, v);
-
- if (lex_match (lexer, T_ASTERISK) || lex_match (lexer, T_BY))
- {
- return parse_internal_interaction (lexer, dict, iact, iact);
- }
-
- return true;
-}
-
-bool
-parse_design_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact)
-{
- return parse_internal_interaction (lexer, dict, iact, NULL);
-}
-
bool
lex_match_variable (struct lexer *lexer, const struct dictionary *dict, const struct variable **var);
-struct interaction;
-
-/* Parse an interaction.
- If not successful return false.
- Otherwise, a newly created interaction will be placed in IACT.
- It is the caller's responsibility to destroy this interaction.
- */
-bool
-parse_design_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact);
-
-
-
#endif /* variable-parser.h */
return false;
}
+/* An interaction is a variable followed by {*, BY} followed by an interaction */
+static bool
+parse_internal_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact, struct interaction **it)
+{
+ const struct variable *v = NULL;
+ assert (iact);
+
+ switch (lex_next_token (lexer, 1))
+ {
+ case T_ENDCMD:
+ case T_SLASH:
+ case T_COMMA:
+ case T_ID:
+ case T_BY:
+ case T_ASTERISK:
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ if (! lex_match_variable (lexer, dict, &v))
+ {
+ if (it)
+ interaction_destroy (*it);
+ *iact = NULL;
+ return false;
+ }
+
+ assert (v);
+
+ if (*iact == NULL)
+ *iact = interaction_create (v);
+ else
+ interaction_add_variable (*iact, v);
+
+ if (lex_match (lexer, T_ASTERISK) || lex_match (lexer, T_BY))
+ {
+ return parse_internal_interaction (lexer, dict, iact, iact);
+ }
+
+ return true;
+}
+
+/* Parse an interaction.
+ If not successful return false.
+ Otherwise, a newly created interaction will be placed in IACT.
+ It is the caller's responsibility to destroy this interaction.
+ */
+static bool
+parse_design_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact)
+{
+ return parse_internal_interaction (lexer, dict, iact, NULL);
+}
+
/* A design term is an interaction OR a nested variable */
static bool
parse_design_term (struct lexer *lexer, struct glm_spec *glm)
else if (lex_match_id (lexer, "CATEGORICAL"))
{
lex_match (lexer, T_EQUALS);
- do
- {
- lr.cat_predictors = xrealloc (lr.cat_predictors,
- sizeof (*lr.cat_predictors) * ++lr.n_cat_predictors);
- lr.cat_predictors[lr.n_cat_predictors - 1] = 0;
- }
- while (parse_design_interaction (lexer, lr.dict,
- lr.cat_predictors + lr.n_cat_predictors - 1));
- lr.n_cat_predictors--;
+ struct variable **cats;
+ size_t n_cats;
+ if (!parse_variables (lexer, lr.dict, &cats, &n_cats, PV_NO_DUPLICATE))
+ goto error;
+
+ lr.cat_predictors = xrealloc (lr.cat_predictors,
+ sizeof *lr.cat_predictors
+ * (n_cats + lr.n_cat_predictors));
+ for (size_t i = 0; i < n_cats; i++)
+ lr.cat_predictors[lr.n_cat_predictors++] = interaction_create (cats[i]);
+ free (cats);
}
else if (lex_match_id (lexer, "PRINT"))
{