free (m);
}
\f
+struct macro_set *
+macro_set_create (void)
+{
+ struct macro_set *set = xmalloc (sizeof *set);
+ *set = (struct macro_set) {
+ .macros = HMAP_INITIALIZER (set->macros),
+ };
+ return set;
+}
+
+void
+macro_set_destroy (struct macro_set *set)
+{
+ if (!set)
+ return;
+
+ struct macro *macro, *next;
+ HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
+ {
+ hmap_delete (&set->macros, ¯o->hmap_node);
+ macro_destroy (macro);
+ }
+ hmap_destroy (&set->macros);
+ free (set);
+}
+
+static unsigned int
+hash_macro_name (const char *name)
+{
+ return utf8_hash_case_string (name, 0);
+}
+
+static struct macro *
+macro_set_find__ (struct macro_set *set, const char *name)
+{
+ struct macro *macro;
+ HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
+ hash_macro_name (name), &set->macros)
+ if (!utf8_strcasecmp (macro->name, name))
+ return macro;
+
+ return NULL;
+}
+
const struct macro *
macro_set_find (const struct macro_set *set, const char *name)
{
- struct macro *macro;
+ return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
+}
- HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
- utf8_hash_case_string (name, 0), &set->macros)
+/* Adds M to SET. M replaces any existing macro with the same name. Takes
+ ownership of M. */
+void
+macro_set_add (struct macro_set *set, struct macro *m)
+{
+ struct macro *victim = macro_set_find__ (set, m->name);
+ if (victim)
{
- if (!utf8_strcasecmp (macro->name, name))
- return macro;
+ hmap_delete (&set->macros, &victim->hmap_node);
+ macro_destroy (victim);
}
- return NULL;
+ hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
}
\f
enum me_state
return me_expected (me, token, &equals);
}
+int
+macro_expander_create (const struct macro_set *macros,
+ const struct token *token,
+ struct macro_expander **mep)
+{
+ *mep = NULL;
+ if (macro_set_is_empty (macros))
+ return -1;
+ if (token->type != T_ID && token->type != T_MACRO_ID)
+ return -1;
+
+ const struct macro *macro = macro_set_find (macros, token->string.string);
+ if (!macro)
+ return -1;
+
+ struct macro_expander *me = xmalloc (sizeof *me);
+ *me = (struct macro_expander) {
+ .macros = macros,
+
+ .state = ME_START,
+ .n_tokens = 1,
+
+ .macro = macro,
+ .args = xcalloc (macro->n_params, sizeof *me->args),
+ .arg_index = 0,
+ };
+ *mep = me;
+ return me_next_arg (me);
+}
+
+void
+macro_expander_destroy (struct macro_expander *me)
+{
+ if (!me)
+ return;
+
+ for (size_t i = 0; i < me->macro->n_params; i++)
+ if (me->args[i])
+ {
+ tokens_uninit (me->args[i]);
+ free (me->args[i]);
+ }
+ free (me->args);
+ free (me);
+}
+
/* Adds TOKEN to the collection of tokens in ME that potentially need to be
macro expanded.
- Return values:
-
- * -1: The tokens added do not actually invoke a macro. The caller should
- consume the first token without expanding it.
+ Returns -1 if the tokens added do not actually invoke a macro. The caller
+ should consume the first token without expanding it.
- * 0: The macro expander needs more tokens, for macro arguments or to decide
- whether this is actually a macro invocation. The caller should call
- macro_expander_add() again with the next token.
+ Returns 0 if the macro expander needs more tokens, for macro arguments or to
+ decide whether this is actually a macro invocation. The caller should call
+ macro_expander_add() again with the next token.
- * >0: Expand the given number of tokens. */
+ Returns a positive number to indicate that the returned number of tokens
+ invoke a macro. The number returned might be less than the number of tokens
+ added because it can take a few tokens of lookahead to determine whether the
+ macro invocation is finished. The caller should call
+ macro_expander_get_expansion() to obtain the expansion. */
int
macro_expander_add (struct macro_expander *me, const struct token *token)
{
struct substring segment = ss_head (state.body, seg_len);
ss_advance (&state.body, seg_len);
+ printf ("segment \"%.*s\" %s token.type=%d\n", (int) segment.length, segment.string, segment_type_to_string (type), token.type);
enum scan_result result = scanner_push (&scanner, type, segment, &token);
if (result == SCAN_SAVE)
saved = state;
else if (result == SCAN_BACK)
{
+ printf ("back\n");
state = saved;
break;
}
else if (result == SCAN_DONE)
- break;
+ {
+ printf ("done\n");
+ break;
+ }
}
/* We have a token in 'token'. */
- tokens_add (exp, &token);
+ printf ("add token %d %s\n", token.type, token_type_to_name (token.type));
+ if (is_scan_type (token.type))
+ {
+ /* XXX report error if it's not SCAN_SKIP */
+ }
+ else
+ tokens_add (exp, &token);
token_destroy (&token);
}
}
-