+/**
+ * When a macro is used we have to handle parameters as well
+ * as special-concatenation via ## or stringification via #
+ *
+ * Note: parenthesis can nest, so FOO((a),b) is valid, but only
+ * this kind of parens. Curly braces or [] don't count towards the
+ * paren-level.
+ */
+typedef struct {
+ pptoken **tokens;
+} macroparam;
+
+static void macroparam_clean(macroparam *self)
+{
+ size_t i;
+ for (i = 0; i < vec_size(self->tokens); ++i)
+ pptoken_delete(self->tokens[i]);
+ vec_free(self->tokens);
+}
+
+static bool ftepp_macro_call_params(ftepp_t *ftepp, macroparam **out_params)
+{
+ macroparam *params = NULL;
+ pptoken *ptok;
+ macroparam mp;
+ size_t parens = 0;
+ size_t i;
+
+ while (true) {
+ mp.tokens = NULL;
+ while (parens || ftepp->token != ',') {
+ if (ftepp->token == '(')
+ ++parens;
+ else if (ftepp->token == ')') {
+ if (!parens)
+ break;
+ --parens;
+ }
+ ptok = pptoken_make(ftepp);
+ vec_push(mp.tokens, ptok);
+ if (ftepp_next(ftepp) >= TOKEN_EOF) {
+ ftepp_error(ftepp, "unexpected EOF in macro call");
+ goto on_error;
+ }
+ }
+ vec_push(params, mp);
+ mp.tokens = NULL;
+ if (ftepp->token == ')')
+ break;
+ if (ftepp->token != ',') {
+ ftepp_error(ftepp, "expected closing paren or comma in macro call");
+ goto on_error;
+ }
+ if (ftepp_next(ftepp) >= TOKEN_EOF) {
+ ftepp_error(ftepp, "unexpected EOF in macro call");
+ goto on_error;
+ }
+ }
+ if (ftepp_next(ftepp) >= TOKEN_EOF) {
+ ftepp_error(ftepp, "unexpected EOF in macro call");
+ goto on_error;
+ }
+ *out_params = params;
+ return true;
+
+on_error:
+ if (mp.tokens)
+ macroparam_clean(&mp);
+ for (i = 0; i < vec_size(params); ++i)
+ macroparam_clean(¶ms[i]);
+ vec_free(params);
+ return false;
+}
+