[qfcc] Record and expand macro arguments

Stringizing doesn't work correctly (stringizes only the first token, not
the whole argument), but things seems to work otherwise.
This commit is contained in:
Bill Currie 2023-10-24 23:32:13 +09:00
parent 9b717c2e1e
commit dc598c58b5
4 changed files with 80 additions and 16 deletions

View file

@ -53,6 +53,7 @@ typedef struct rua_macro_s {
rua_expr_t *tokens;
rua_expr_t **tail;
int num_tokens;
int num_params;
} rua_macro_t;
typedef struct rua_tok_s {
@ -78,6 +79,7 @@ rua_macro_t *rua_end_params (rua_macro_t *macro, void *scanner);
rua_macro_t *rua_macro_append (rua_macro_t *macro, rua_tok_t *token,
void *scanner);
void rua_macro_finish (rua_macro_t *macro, void *scanner);
rua_macro_t *rua_macro_arg (rua_macro_t *arg, void *scanner);
void rua_start_text (void *scanner);
void rua_start_expr (void *scanner);
void rua_expand_on (void *scanner);

View file

@ -75,7 +75,7 @@ typedef struct symbol_s {
struct param_s *params; ///< the parameters if a function
unsigned no_auto_init; ///< skip for non-designated initializers
union {
int offset; ///< sy_var (in a struct/union)
int offset; ///< sy_var (in a struct/union/macro)
struct def_s *def; ///< sy_var
struct ex_value_s *value; ///< sy_const
const struct expr_s *expr; ///< sy_expr

View file

@ -130,7 +130,7 @@ parse_error (void *scanner)
%token DEFINED EOD
%token CONCAT ARGS
%type <macro> params body
%type <macro> params body arg arg_list
%type <dstr> text text_text
%type <value.expr> unary_expr expr id defined defined_id
@ -143,7 +143,12 @@ parse_error (void *scanner)
start
: directive_list
| ARGS args ')' { YYACCEPT; }
| ARGS
<macro>{
auto arg = rua_start_macro (0, false, scanner);
$$ = rua_macro_arg (arg, scanner);
}
args ')' { YYACCEPT; }
;
directive_list
@ -222,16 +227,23 @@ params
;
args: arg_list
| args ',' arg_list
| args ','
<macro>{
auto arg = rua_start_macro (0, false, scanner);
$$ = rua_macro_arg (arg, scanner);
}
arg_list
;
arg_list
: /* emtpy */
| arg_list arg
: /* emtpy */ { $$ = $<macro>0; }
| arg_list arg { $$ = $2; }
;
arg : '(' args ')'
| TOKEN
arg : '(' <macro> { $$ = rua_macro_append ($<macro>0, yyvsp, scanner); }
args <macro> { $$ = rua_macro_append ($<macro>0, yyvsp, scanner); }
')' { $$ = rua_macro_append ($<macro>0, yyvsp, scanner); }
| TOKEN { $$ = rua_macro_append ($<macro>0, yyvsp, scanner); }
;
id : ID { $$ = 0; }

View file

@ -95,6 +95,7 @@ typedef struct {
typedef struct DARRAY_TYPE (rua_cond_t) rua_cond_stack_t;
typedef struct DARRAY_TYPE (rua_expr_t) rua_expr_stack_t;
typedef struct DARRAY_TYPE (rua_macro_t *) rua_macro_list_t;
typedef struct rua_extra_s {
int start_state;
@ -106,6 +107,7 @@ typedef struct rua_extra_s {
pre_yypstate *pre_state;
rua_cond_stack_t cond_stack;
rua_expr_stack_t expr_stack;
rua_macro_list_t arg_list;
symtab_t *macro_tab;
yyscan_t subscanner;
} rua_extra_t;
@ -1096,16 +1098,35 @@ static void
expand_macro (rua_extra_t *extra, rua_macro_t *macro)
{
int num_tokens = macro->num_tokens;
for (auto t = macro->tokens; t; t = t->next) {
if (t->token == PRE_ID) {
auto sym = symtab_lookup (macro->params, t->text);
if (sym) {
num_tokens += extra->arg_list.a[sym->s.offset]->num_tokens - 1;
}
}
}
int base = extra->expr_stack.size;
DARRAY_OPEN_AT (&extra->expr_stack, base, num_tokens);
int index = num_tokens;
for (auto t = macro->tokens; t; t = t->next) {
extra->expr_stack.a[base + --index] = *t;
auto e = t;
if (t->token == PRE_ID) {
auto sym = symtab_lookup (macro->params, t->text);
int param = sym->s.offset;
for (e = extra->arg_list.a[param]->tokens; e; e = e->next) {
extra->expr_stack.a[base + --index] = *e;
}
}
if (e) {
extra->expr_stack.a[base + --index] = *e;
}
}
if (index) {
internal_error (0, "taniwha can't count: %d", index);
}
for (index = num_tokens; index-- > 0;) {
auto e = &extra->expr_stack.a[base + index];
if (e->token == '#') {
@ -1255,6 +1276,10 @@ parse_args (rua_extra_t *extra, rua_loc_t *location, yyscan_t scanner)
auto state = pre_yypstate_new ();
int token = PRE_ARGS;
rua_tok_t tok = { .location = *location, };
for (auto i = extra->arg_list.size; i-- > 0; ) {
free (extra->arg_list.a[i]);
}
extra->arg_list.size = 0;
do {
if (token != PRE_ARGS) {
token = yylex (&tok, &tok.location, scanner);
@ -1286,7 +1311,8 @@ qc_process (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t scanner)
sym = symtab_lookup (extra->macro_tab, tok->text);
}
if (sym) {
if (sym->s.macro->params) {
auto macro = sym->s.macro;
if (macro->params) {
rua_tok_t ttok = { .location = tok->location, };
int ttoken;
bool saw_space = false;
@ -1311,10 +1337,20 @@ qc_process (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t scanner)
sym = 0;
return -1;
}
int num_args = extra->arg_list.size;
if (num_args == 1 && !extra->arg_list.a[0]->num_tokens) {
num_args = 0;
}
if (num_args != macro->num_params) {
error (0, "macro \"%s\" passed %d arguments,"
" but takes just %d",
macro->name, num_args, macro->num_params);
sym = 0;
}
}
}
if (sym) {
expand_macro (extra, sym->s.macro);
expand_macro (extra, macro);
return YYPUSH_MORE;
}
}
@ -1352,6 +1388,7 @@ qc_yyparse (FILE *in)
.pre_state = pre_yypstate_new (),
.cond_stack = DARRAY_STATIC_INIT (8),
.expr_stack = DARRAY_STATIC_INIT (32),
.arg_list = DARRAY_STATIC_INIT (8),
.macro_tab = new_symtab (0, stab_global),
};
@ -1382,6 +1419,7 @@ qc_yyparse (FILE *in)
pre_yypstate_delete (extra.pre_state);
free (extra.cond_stack.a);
free (extra.expr_stack.a);
free (extra.arg_list.a);
return status;
}
@ -1392,11 +1430,13 @@ rua_start_macro (const char *name, bool params, void *scanner)
extra->params = params;
extra->recording = true;
int len = strlen (name);
if (name[len - 1] == '(') {
name = save_substring (name, len - 1);
} else {
name = save_string (name);
if (name) {
int len = strlen (name);
if (name[len - 1] == '(') {
name = save_substring (name, len - 1);
} else {
name = save_string (name);
}
}
yy_pop_state (scanner);
@ -1462,6 +1502,8 @@ rua_macro_param (rua_macro_t *macro, rua_tok_t *token, void *scanner)
return macro;
}
auto sym = new_symbol (token->text);
sym->sy_type = sy_var;
sym->s.offset = macro->num_params++;
symtab_addsymbol (macro->params, sym);
return macro;
}
@ -1517,6 +1559,14 @@ rua_macro_finish (rua_macro_t *macro, void *scanner)
symtab_addsymbol (macro_tab, sym);
}
rua_macro_t *
rua_macro_arg (rua_macro_t *arg, void *scanner)
{
auto extra = qc_yyget_extra (scanner);
DARRAY_APPEND (&extra->arg_list, arg);
return arg;
}
void
rua_start_text (void *scanner)
{