📄 preproc.c
字号:
bool err;
int nparam;
bool nolist;
bool casesense;
int k, m;
int offset;
char *p, *mname;
Include *inc;
Context *ctx;
Cond *cond;
MMacro *mmac, **mmhead;
Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
Line *l;
struct tokenval tokval;
expr *evalresult;
MMacro *tmp_defining; /* Used when manipulating rep_nest */
int64_t count;
origline = tline;
skip_white_(tline);
if (!tok_type_(tline, TOK_PREPROC_ID) ||
(tline->text[1] == '%' || tline->text[1] == '$'
|| tline->text[1] == '!'))
return NO_DIRECTIVE_FOUND;
i = pp_token_hash(tline->text);
/*
* If we're in a non-emitting branch of a condition construct,
* or walking to the end of an already terminated %rep block,
* we should ignore all directives except for condition
* directives.
*/
if (((istk->conds && !emitting(istk->conds->state)) ||
(istk->mstk && !istk->mstk->in_progress)) && !is_condition(i)) {
return NO_DIRECTIVE_FOUND;
}
/*
* If we're defining a macro or reading a %rep block, we should
* ignore all directives except for %macro/%imacro (which
* generate an error), %endm/%endmacro, and (only if we're in a
* %rep block) %endrep. If we're in a %rep block, another %rep
* causes an error, so should be let through.
*/
if (defining && i != PP_MACRO && i != PP_IMACRO &&
i != PP_ENDMACRO && i != PP_ENDM &&
(defining->name || (i != PP_ENDREP && i != PP_REP))) {
return NO_DIRECTIVE_FOUND;
}
switch (i) {
case PP_INVALID:
error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
tline->text);
return NO_DIRECTIVE_FOUND; /* didn't get it */
case PP_STACKSIZE:
/* Directive to tell NASM what the default stack size is. The
* default is for a 16-bit stack, and this can be overriden with
* %stacksize large.
* the following form:
*
* ARG arg1:WORD, arg2:DWORD, arg4:QWORD
*/
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next;
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
if (nasm_stricmp(tline->text, "flat") == 0) {
/* All subsequent ARG directives are for a 32-bit stack */
StackSize = 4;
StackPointer = "ebp";
ArgOffset = 8;
LocalOffset = 4;
} else if (nasm_stricmp(tline->text, "large") == 0) {
/* All subsequent ARG directives are for a 16-bit stack,
* far function call.
*/
StackSize = 2;
StackPointer = "bp";
ArgOffset = 4;
LocalOffset = 2;
} else if (nasm_stricmp(tline->text, "small") == 0) {
/* All subsequent ARG directives are for a 16-bit stack,
* far function call. We don't support near functions.
*/
StackSize = 2;
StackPointer = "bp";
ArgOffset = 6;
LocalOffset = 2;
} else {
error(ERR_NONFATAL, "`%%stacksize' invalid size type");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ARG:
/* TASM like ARG directive to define arguments to functions, in
* the following form:
*
* ARG arg1:WORD, arg2:DWORD, arg4:QWORD
*/
offset = ArgOffset;
do {
char *arg, directive[256];
int size = StackSize;
/* Find the argument name */
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next;
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL, "`%%arg' missing argument parameter");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
arg = tline->text;
/* Find the argument size type */
tline = tline->next;
if (!tline || tline->type != TOK_OTHER
|| tline->text[0] != ':') {
error(ERR_NONFATAL,
"Syntax error processing `%%arg' directive");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
tline = tline->next;
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL, "`%%arg' missing size type parameter");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
/* Allow macro expansion of type parameter */
tt = tokenize(tline->text);
tt = expand_smacro(tt);
if (nasm_stricmp(tt->text, "byte") == 0) {
size = MAX(StackSize, 1);
} else if (nasm_stricmp(tt->text, "word") == 0) {
size = MAX(StackSize, 2);
} else if (nasm_stricmp(tt->text, "dword") == 0) {
size = MAX(StackSize, 4);
} else if (nasm_stricmp(tt->text, "qword") == 0) {
size = MAX(StackSize, 8);
} else if (nasm_stricmp(tt->text, "tword") == 0) {
size = MAX(StackSize, 10);
} else {
error(ERR_NONFATAL,
"Invalid size type for `%%arg' missing directive");
free_tlist(tt);
free_tlist(origline);
return DIRECTIVE_FOUND;
}
free_tlist(tt);
/* Now define the macro for the argument */
snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
arg, StackPointer, offset);
do_directive(tokenize(directive));
offset += size;
/* Move to the next argument in the list */
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next;
}
while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_LOCAL:
/* TASM like LOCAL directive to define local variables for a
* function, in the following form:
*
* LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
*
* The '= LocalSize' at the end is ignored by NASM, but is
* required by TASM to define the local parameter size (and used
* by the TASM macro package).
*/
offset = LocalOffset;
do {
char *local, directive[256];
int size = StackSize;
/* Find the argument name */
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next;
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL,
"`%%local' missing argument parameter");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
local = tline->text;
/* Find the argument size type */
tline = tline->next;
if (!tline || tline->type != TOK_OTHER
|| tline->text[0] != ':') {
error(ERR_NONFATAL,
"Syntax error processing `%%local' directive");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
tline = tline->next;
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL,
"`%%local' missing size type parameter");
free_tlist(origline);
return DIRECTIVE_FOUND;
}
/* Allow macro expansion of type parameter */
tt = tokenize(tline->text);
tt = expand_smacro(tt);
if (nasm_stricmp(tt->text, "byte") == 0) {
size = MAX(StackSize, 1);
} else if (nasm_stricmp(tt->text, "word") == 0) {
size = MAX(StackSize, 2);
} else if (nasm_stricmp(tt->text, "dword") == 0) {
size = MAX(StackSize, 4);
} else if (nasm_stricmp(tt->text, "qword") == 0) {
size = MAX(StackSize, 8);
} else if (nasm_stricmp(tt->text, "tword") == 0) {
size = MAX(StackSize, 10);
} else {
error(ERR_NONFATAL,
"Invalid size type for `%%local' missing directive");
free_tlist(tt);
free_tlist(origline);
return DIRECTIVE_FOUND;
}
free_tlist(tt);
/* Now define the macro for the argument */
snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
local, StackPointer, offset);
do_directive(tokenize(directive));
offset += size;
/* Now define the assign to setup the enter_c macro correctly */
snprintf(directive, sizeof(directive),
"%%assign %%$localsize %%$localsize+%d", size);
do_directive(tokenize(directive));
/* Move to the next argument in the list */
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next;
}
while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_CLEAR:
if (tline->next)
error(ERR_WARNING, "trailing garbage after `%%clear' ignored");
free_macros();
init_macros();
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_INCLUDE:
tline = tline->next;
skip_white_(tline);
if (!tline || (tline->type != TOK_STRING &&
tline->type != TOK_INTERNAL_STRING)) {
error(ERR_NONFATAL, "`%%include' expects a file name");
free_tlist(origline);
return DIRECTIVE_FOUND; /* but we did _something_ */
}
if (tline->next)
error(ERR_WARNING,
"trailing garbage after `%%include' ignored");
if (tline->type != TOK_INTERNAL_STRING) {
p = tline->text + 1; /* point past the quote to the name */
p[strlen(p) - 1] = '\0'; /* remove the trailing quote */
} else
p = tline->text; /* internal_string is easier */
expand_macros_in_string(&p);
inc = nasm_malloc(sizeof(Include));
inc->next = istk;
inc->conds = NULL;
inc->fp = inc_fopen(p);
if (!inc->fp && pass == 0) {
/* -MG given but file not found */
nasm_free(inc);
} else {
inc->fname = src_set_fname(p);
inc->lineno = src_set_linnum(0);
inc->lineinc = 1;
inc->expansion = NULL;
inc->mstk = NULL;
istk = inc;
list->uplevel(LIST_INCLUDE);
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_PUSH:
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL, "`%%push' expects a context identifier");
free_tlist(origline);
return DIRECTIVE_FOUND; /* but we did _something_ */
}
if (tline->next)
error(ERR_WARNING, "trailing garbage after `%%push' ignored");
ctx = nasm_malloc(sizeof(Context));
ctx->next = cstk;
ctx->localmac = NULL;
ctx->name = nasm_strdup(tline->text);
ctx->number = unique++;
cstk = ctx;
free_tlist(origline);
break;
case PP_REPL:
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL, "`%%repl' expects a context identifier");
free_tlist(origline);
return DIRECTIVE_FOUND; /* but we did _something_ */
}
if (tline->next)
error(ERR_WARNING, "trailing garbage after `%%repl' ignored");
if (!cstk)
error(ERR_NONFATAL, "`%%repl': context stack is empty");
else {
nasm_free(cstk->name);
cstk->name = nasm_strdup(tline->text);
}
free_tlist(origline);
break;
case PP_POP:
if (tline->next)
error(ERR_WARNING, "trailing garbage after `%%pop' ignored");
if (!cstk)
error(ERR_NONFATAL, "`%%pop': context stack is already empty");
else
ctx_pop();
free_tlist(origline);
break;
case PP_ERROR:
tline->next = expand_smacro(tline->next);
tline = tline->next;
skip_white_(tline);
if (tok_type_(tline, TOK_STRING)) {
p = tline->text + 1; /* point past the quote to the name */
p[strlen(p) - 1] = '\0'; /* remove the trailing quote */
expand_macros_in_string(&p);
error(ERR_NONFATAL, "%s", p);
nasm_free(p);
} else {
p = detoken(tline, false);
error(ERR_WARNING, "%s", p);
nasm_free(p);
}
free_tlist(origline);
break;
CASE_PP_IF:
if (istk->conds && !emitting(istk->conds->state))
j = COND_NEVER;
else {
j = if_condition(tline->next, i);
tline->next = NULL; /* it got freed */
free_tlist(origline);
j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
}
cond = nasm_malloc(sizeof(Cond));
cond->next = istk->conds;
cond->state = j;
istk->conds = cond;
return DIRECTIVE_FOUND;
CASE_PP_ELIF:
if (!istk->conds)
error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
if (emitting(istk->conds->state)
|| istk->conds->state == COND_NEVER)
istk->conds->state = COND_NEVER;
else {
/*
* IMPORTANT: In the case of %if, we will already have
* called expand_mmac_params(); however, if we're
* processing an %elif we must have been in a
* non-emitting mode, which would have inhibited
* the normal invocation of expand_mmac_params(). Therefore,
* we have to do it explicitly here.
*/
j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */
free_tlist(origline);
istk->conds->state =
j < 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -