+#endif
+
+
+\f
+
+/* Match a variable.
+ If the match succeeds, the variable will be placed in VAR.
+ Returns true if successful */
+static bool
+lex_match_variable (struct lexer *lexer, const struct glm_spec *glm, const struct variable **var)
+{
+ if (lex_token (lexer) != T_ID)
+ return false;
+
+ *var = parse_variable_const (lexer, glm->dict);
+
+ if ( *var == NULL)
+ return false;
+ return true;
+}
+
+/* An interaction is a variable followed by {*, BY} followed by an interaction */
+static bool
+parse_design_interaction (struct lexer *lexer, struct glm_spec *glm)
+{
+ const struct variable *v = NULL;
+ if (! lex_match_variable (lexer, glm, &v))
+ return false;
+
+ if ( lex_match (lexer, T_ASTERISK) || lex_match (lexer, T_BY))
+ {
+ lex_error (lexer, "Interactions are not yet implemented"); return false;
+ return parse_design_interaction (lexer, glm);
+ }
+
+ glm->n_design_vars++;
+ glm->design_vars = xrealloc (glm->design_vars, sizeof (*glm->design_vars) * glm->n_design_vars);
+ glm->design_vars[glm->n_design_vars - 1] = v;
+
+ return true;
+}
+
+/* A design term is a varible OR an interaction */
+static bool
+parse_design_term (struct lexer *lexer, struct glm_spec *glm)
+{
+ const struct variable *v = NULL;
+ if (parse_design_interaction (lexer, glm))
+ return true;
+
+ /* FIXME: This should accept nexted variables */
+ if ( lex_match_variable (lexer, glm, &v))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+/* Parse a complete DESIGN specification.
+ A design spec is a design term, optionally followed by a comma,
+ and another design spec.
+*/
+static bool
+parse_design_spec (struct lexer *lexer, struct glm_spec *glm)
+{
+ /* Kludge: Return success if end of design spec */
+ if (lex_token (lexer) == T_ENDCMD || lex_token (lexer) == T_SLASH)
+ return true;
+
+ if ( ! parse_design_term (lexer, glm))
+ return false;
+
+ lex_match (lexer, T_COMMA);
+
+ return parse_design_spec (lexer, glm);
+}
+