[qfcc] Implement object-type macro expansion

Really, function-type macros expand too, but incorrectly as the
parameters are not parsed and thus not expanded, but this gets the basic
handling implemented, including # and ## processing.
This commit is contained in:
Bill Currie 2023-10-24 15:58:37 +09:00
parent 45e61544bb
commit 3307ef77ec
3 changed files with 118 additions and 2 deletions

View file

@ -43,6 +43,7 @@ typedef struct rua_expr_s {
rua_loc_t location; rua_loc_t location;
int textlen; int textlen;
int token; int token;
int param; // 1-based param index (0 if not a param)
const char *text; const char *text;
} rua_expr_t; } rua_expr_t;
@ -51,6 +52,7 @@ typedef struct rua_macro_s {
symtab_t *params; symtab_t *params;
rua_expr_t *tokens; rua_expr_t *tokens;
rua_expr_t **tail; rua_expr_t **tail;
int num_tokens;
} rua_macro_t; } rua_macro_t;
typedef struct rua_tok_s { typedef struct rua_tok_s {
@ -78,6 +80,8 @@ rua_macro_t *rua_macro_append (rua_macro_t *macro, rua_tok_t *token,
void rua_macro_finish (rua_macro_t *macro, void *scanner); void rua_macro_finish (rua_macro_t *macro, void *scanner);
void rua_start_text (void *scanner); void rua_start_text (void *scanner);
void rua_start_expr (void *scanner); void rua_start_expr (void *scanner);
void rua_expand_on (void *scanner);
void rua_expand_off (void *scanner);
void rua_end_directive (void *scanner); void rua_end_directive (void *scanner);
void rua_if (bool pass, void *scanner); void rua_if (bool pass, void *scanner);
void rua_else (bool pass, const char *tok, void *scanner); void rua_else (bool pass, const char *tok, void *scanner);

View file

@ -264,7 +264,8 @@ unary_expr
$$ = new_long_expr (1, false); $$ = new_long_expr (1, false);
} }
| '(' expr ')' { $$ = $2; } | '(' expr ')' { $$ = $2; }
| DEFINED defined { $$ = $2; } | DEFINED { rua_expand_off (scanner); }
defined { rua_expand_on (scanner); $$ = $3; }
| '+' unary_expr { $$ = $2; } | '+' unary_expr { $$ = $2; }
| '-' unary_expr { $$ = UEXPR (-, $2); } | '-' unary_expr { $$ = UEXPR (-, $2); }
| '~' unary_expr { $$ = UEXPR (~, $2); } | '~' unary_expr { $$ = UEXPR (~, $2); }

View file

@ -52,6 +52,7 @@
#include <QF/dstring.h> #include <QF/dstring.h>
#include <QF/hash.h> #include <QF/hash.h>
#include <QF/sys.h> #include <QF/sys.h>
#include <QF/va.h>
#include "tools/qfcc/include/class.h" #include "tools/qfcc/include/class.h"
#include "tools/qfcc/include/debug.h" #include "tools/qfcc/include/debug.h"
@ -93,16 +94,20 @@ typedef struct {
} rua_cond_t; } rua_cond_t;
typedef struct DARRAY_TYPE (rua_cond_t) rua_cond_stack_t; typedef struct DARRAY_TYPE (rua_cond_t) rua_cond_stack_t;
typedef struct DARRAY_TYPE (rua_expr_t) rua_expr_stack_t;
typedef struct rua_extra_s { typedef struct rua_extra_s {
int start_state; int start_state;
bool preprocessor; bool preprocessor;
bool recording; bool recording;
bool params; bool params;
bool expand;
qc_yypstate *qc_state; qc_yypstate *qc_state;
pre_yypstate *pre_state; pre_yypstate *pre_state;
rua_cond_stack_t cond_stack; rua_cond_stack_t cond_stack;
rua_expr_stack_t expr_stack;
symtab_t *macro_tab; symtab_t *macro_tab;
yyscan_t subscanner;
} rua_extra_t; } rua_extra_t;
#define YY_EXTRA_TYPE rua_extra_t * #define YY_EXTRA_TYPE rua_extra_t *
@ -1064,6 +1069,61 @@ user_action (rua_tok_t *tok, rua_loc_t *loc, const char *text, size_t textlen,
#endif #endif
} }
static void
expand_macro (rua_extra_t *extra, rua_macro_t *macro)
{
int num_tokens = macro->num_tokens;
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;
}
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 == '#') {
e->token = -rua_string;
auto p = e - 1;
auto str = quote_string (p->text);
e->text = save_string (va (0, "\"%s\"", str));
extra->expr_stack.a[base + --index] = (rua_expr_t) {
.token = -rua_ignore,
};
} else if (e->token == PRE_CONCAT) {
auto p1 = e + 1;
auto p2 = e - 1;
auto str = va (0, "%s%s", p1->text, p2->text);
yy_scan_string (str, extra->subscanner);
rua_tok_t tok = { .location = e->location, };
int token = yylex (&tok, &tok.location, extra->subscanner);
if (token && yylex (&tok, &tok.location, extra->subscanner)) {
error (0, "pasting \"%s\" and \"%s\" does not give a valid"
" preprocessing token", p1->text, p2->text);
*e = (rua_expr_t) {
.token = -rua_space,
.text = " ",
};
} else {
*e = (rua_expr_t) {
.location = tok.location,
.textlen = tok.textlen,
.token = token,
.text = save_string (tok.text),
};
*p2 = *p1 = (rua_expr_t) {
.token = -rua_ignore,
};
index--;
}
}
}
}
static int static int
preproc_token (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t *scanner) preproc_token (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t *scanner)
{ {
@ -1153,6 +1213,20 @@ qc_process (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t scanner)
{ {
auto loc = &tok->location; auto loc = &tok->location;
if (-token == rua_ignore) {
return YYPUSH_MORE;
}
if (extra->expand || !extra->preprocessor) {
symbol_t *sym = 0;
if (token == PRE_ID || token == -rua_id) {
sym = symtab_lookup (extra->macro_tab, tok->text);
}
if (sym) {
expand_macro (extra, sym->s.macro);
return YYPUSH_MORE;
}
}
if (extra->preprocessor) { if (extra->preprocessor) {
auto state = extra->pre_state; auto state = extra->pre_state;
token = preproc_token (extra, token, tok, scanner); token = preproc_token (extra, token, tok, scanner);
@ -1185,20 +1259,37 @@ qc_yyparse (FILE *in)
.qc_state = qc_yypstate_new (), .qc_state = qc_yypstate_new (),
.pre_state = pre_yypstate_new (), .pre_state = pre_yypstate_new (),
.cond_stack = DARRAY_STATIC_INIT (8), .cond_stack = DARRAY_STATIC_INIT (8),
.expr_stack = DARRAY_STATIC_INIT (32),
.macro_tab = new_symtab (0, stab_global), .macro_tab = new_symtab (0, stab_global),
}; };
yylex_init_extra (&extra, &scanner); yylex_init_extra (&extra, &scanner);
yylex_init (&extra.subscanner);
yyset_in (in, scanner); yyset_in (in, scanner);
do { do {
int token = yylex (&tok, &tok.location, scanner); int token = yylex (&tok, &tok.location, scanner);
status = qc_process (&extra, token, &tok, scanner); while (true) {
status = qc_process (&extra, token, &tok, scanner);
if (status != YYPUSH_MORE || !extra.expr_stack.size) {
break;
}
auto expr = DARRAY_REMOVE (&extra.expr_stack);
token = expr.token;
tok = (rua_tok_t) {
.location = expr.location,
.textlen = expr.textlen,
.text = expr.text, // macro token strings use save_string
.token = token,
};
}
} while (status == YYPUSH_MORE); } while (status == YYPUSH_MORE);
yylex_destroy (extra.subscanner);
yylex_destroy (scanner); yylex_destroy (scanner);
qc_yypstate_delete (extra.qc_state); qc_yypstate_delete (extra.qc_state);
pre_yypstate_delete (extra.pre_state); pre_yypstate_delete (extra.pre_state);
free (extra.cond_stack.a); free (extra.cond_stack.a);
free (extra.expr_stack.a);
return status; return status;
} }
@ -1255,6 +1346,7 @@ rua_macro_append (rua_macro_t *macro, rua_tok_t *token, void *scanner)
|| !macro->tokens || !macro->tokens
|| expr->token != -rua_space) { || expr->token != -rua_space) {
expr = malloc (sizeof (*expr)); expr = malloc (sizeof (*expr));
macro->num_tokens++;
} }
*expr = (rua_expr_t) { *expr = (rua_expr_t) {
.location = token->location, .location = token->location,
@ -1299,6 +1391,7 @@ rua_macro_finish (rua_macro_t *macro, void *scanner)
free (t->next); free (t->next);
t->next = 0; t->next = 0;
macro->tail = &t->next; macro->tail = &t->next;
macro->num_tokens--;
} }
if (macro->tokens->token == PRE_CONCAT if (macro->tokens->token == PRE_CONCAT
|| ((rua_expr_t *) macro->tail)->token == PRE_CONCAT) { || ((rua_expr_t *) macro->tail)->token == PRE_CONCAT) {
@ -1347,16 +1440,34 @@ rua_start_text (void *scanner)
void void
rua_start_expr (void *scanner) rua_start_expr (void *scanner)
{ {
auto extra = qc_yyget_extra (scanner);
extra->expand = true;
yy_pop_state (scanner); yy_pop_state (scanner);
yy_push_state (PREEXPR, scanner); yy_push_state (PREEXPR, scanner);
} }
void
rua_expand_on (void *scanner)
{
auto extra = qc_yyget_extra (scanner);
extra->expand = true;
}
void
rua_expand_off (void *scanner)
{
auto extra = qc_yyget_extra (scanner);
extra->expand = false;
}
void void
rua_end_directive (void *scanner) rua_end_directive (void *scanner)
{ {
auto extra = qc_yyget_extra (scanner); auto extra = qc_yyget_extra (scanner);
extra->preprocessor = false; extra->preprocessor = false;
extra->recording = false; extra->recording = false;
extra->expand = false;
yy_pop_state (scanner); yy_pop_state (scanner);
} }