preproc: add %(i)defid, fix %(i)deftok code mangling

The previous checkin really got the code for %(i)deftok messed up;
this is fixed.

Add %(i)defid which works like %(i)deftok, except that the string
being input is mangled in such a way that it always results in a valid
NASM identifier.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2018-06-25 22:56:10 -07:00
parent 8884fc60a2
commit 18535fd48c
2 changed files with 78 additions and 7 deletions

View File

@ -51,6 +51,7 @@
%assign
%clear
%define
%defid
%defstr
%deftok
%depend
@ -66,6 +67,7 @@
%fatal
%iassign
%idefine
%idefid
%idefstr
%ideftok
%if*

View File

@ -504,11 +504,11 @@ static void nasm_unquote_pp(char *qstr, enum preproc_token directive)
}
/*
* In-place reverse a list of tokens; optionally link the last
* (formerly first) element to a different token.
* In-place reverse a list of tokens.
*/
static Token *reverse_tokens(Token *t, Token *prev)
static Token *reverse_tokens(Token *t)
{
Token *prev = NULL;
Token *next;
while (t) {
@ -521,6 +521,68 @@ static Token *reverse_tokens(Token *t, Token *prev)
return prev;
}
/*
* Quote an arbitrary string into a valid identifier.
* 1. Prepend a $ to make sure we don't step on any other namespace;
* 2. Any character not valid in a NASM identifier is escaped as @xx;
* 3. A leading $ or . is escaped as @$ and @. respectively;
* 4. @ itself is escaped as @_.
*/
static Token *make_identifier(const char *str)
{
Token *t;
const char *p;
char *q;
size_t n = 2; /* Leading $ + final NUL */
if (!str || !*str) /* Nothing there? */
return NULL;
n += (*str == '@' || *str == '$' || *str == '.') ? 2 :
isidstart(*str) ? 1 : 3;
for (p = str+1; *p; p++)
n += (*p == '@') ? 2 : isidchar(*p) ? 1 : 3;
t = new_Token(NULL, TOK_ID, NULL, 0);
t->text = q = nasm_malloc(n);
*q++ = '$';
switch (*str) {
case '$':
case '.':
*q++ = '@';
*q++ = *str;
break;
case '@':
*q++ = '@';
*q++ = '_';
break;
default:
if (isidstart(*str))
*q++ = *str;
else
q += snprintf(q, 4, "@%02x", (unsigned char)(*str));
}
for (p = str+1; *p; p++) {
if (*str == '@') {
*q++ = '@';
*q++ = '@';
} else if (isidchar(*p)) {
*q++ = *str;
} else {
q += snprintf(q, 4, "@%02x", (unsigned char)(*p));
}
}
*q = '\0';
return t;
}
/*
* Handle TASM specific directives, which do not contain a % in
* front of them. We do it here because I could not find any other
@ -1768,7 +1830,7 @@ static bool if_condition(Token * tline, enum preproc_token ct)
{
enum pp_conditional i = PP_COND(ct);
bool j;
Token *t, *ttwhi, **tptr, *origline;
Token *t, *tt, **tptr, *origline;
struct tokenval tokval;
expr *evalresult;
enum pp_token_type needtype;
@ -3295,10 +3357,12 @@ issue_error:
case PP_DEFTOK:
case PP_IDEFTOK:
case PP_DEFID:
case PP_IDEFID:
{
char *xstr, *ystr;
char *xstr;
casesense = (i == PP_DEFTOK);
casesense = (i == PP_DEFTOK) || (i == PP_DEFID);
tline = tline->next;
skip_white_(tline);
@ -3337,7 +3401,11 @@ issue_error:
* are stored with the token stream reversed, so we have to
* reverse the output of tokenize().
*/
macro_start = reverse_tokens(tokenize(xstr));
if (i == PP_DEFTOK || i == PP_IDEFTOK) {
macro_start = reverse_tokens(tokenize(xstr));
} else {
macro_start = make_identifier(xstr);
}
nasm_free(xstr);
/*
@ -3349,6 +3417,7 @@ issue_error:
free_tlist(tline);
free_tlist(origline);
return DIRECTIVE_FOUND;
}
case PP_PATHSEARCH:
{