mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-19 07:51:08 +00:00
[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:
parent
9b717c2e1e
commit
dc598c58b5
4 changed files with 80 additions and 16 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue