📄 preproc.c
字号:
* Common code for defining an smacro
*/
static bool define_smacro(Context *ctx, char *mname, bool casesense,
int nparam, Token *expansion)
{
SMacro *smac, **smhead;
struct hash_table *smtbl;
if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
if (!smac) {
error(ERR_WARNING|ERR_PASS1,
"single-line macro `%s' defined both with and"
" without parameters", mname);
/* Some instances of the old code considered this a failure,
some others didn't. What is the right thing to do here? */
free_tlist(expansion);
return false; /* Failure */
} else {
/*
* We're redefining, so we have to take over an
* existing SMacro structure. This means freeing
* what was already in it.
*/
nasm_free(smac->name);
free_tlist(smac->expansion);
}
} else {
smtbl = ctx ? &ctx->localmac : &smacros;
smhead = (SMacro **) hash_findi_add(smtbl, mname);
smac = nasm_malloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
}
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
smac->nparam = nparam;
smac->expansion = expansion;
smac->in_progress = false;
return true; /* Success */
}
/*
* Undefine an smacro
*/
static void undef_smacro(Context *ctx, const char *mname)
{
SMacro **smhead, *s, **sp;
struct hash_table *smtbl;
smtbl = ctx ? &ctx->localmac : &smacros;
smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
if (smhead) {
/*
* We now have a macro name... go hunt for it.
*/
sp = smhead;
while ((s = *sp) != NULL) {
if (!mstrcmp(s->name, mname, s->casesense)) {
*sp = s->next;
nasm_free(s->name);
free_tlist(s->expansion);
nasm_free(s);
} else {
sp = &s->next;
}
}
}
}
/*
* Parse a mmacro specification.
*/
static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
{
bool err;
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL, "`%s' expects a macro name", directive);
return false;
}
def->name = nasm_strdup(tline->text);
def->plus = false;
def->nolist = false;
def->in_progress = 0;
def->rep_nest = NULL;
def->nparam_min = 0;
def->nparam_max = 0;
tline = expand_smacro(tline->next);
skip_white_(tline);
if (!tok_type_(tline, TOK_NUMBER)) {
error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
} else {
def->nparam_min = def->nparam_max =
readnum(tline->text, &err);
if (err)
error(ERR_NONFATAL,
"unable to parse parameter count `%s'", tline->text);
}
if (tline && tok_is_(tline->next, "-")) {
tline = tline->next->next;
if (tok_is_(tline, "*")) {
def->nparam_max = INT_MAX;
} else if (!tok_type_(tline, TOK_NUMBER)) {
error(ERR_NONFATAL,
"`%s' expects a parameter count after `-'", directive);
} else {
def->nparam_max = readnum(tline->text, &err);
if (err) {
error(ERR_NONFATAL, "unable to parse parameter count `%s'",
tline->text);
}
if (def->nparam_min > def->nparam_max) {
error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
}
}
}
if (tline && tok_is_(tline->next, "+")) {
tline = tline->next;
def->plus = true;
}
if (tline && tok_type_(tline->next, TOK_ID) &&
!nasm_stricmp(tline->next->text, ".nolist")) {
tline = tline->next;
def->nolist = true;
}
/*
* Handle default parameters.
*/
if (tline && tline->next) {
def->dlist = tline->next;
tline->next = NULL;
count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
} else {
def->dlist = NULL;
def->defaults = NULL;
}
def->expansion = NULL;
if(def->defaults &&
def->ndefs > def->nparam_max - def->nparam_min &&
!def->plus)
error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
"too many default macro parameters");
return true;
}
/*
* Decode a size directive
*/
static int parse_size(const char *str) {
static const char *size_names[] =
{ "byte", "dword", "oword", "qword", "tword", "word", "yword" };
static const int sizes[] =
{ 0, 1, 4, 16, 8, 10, 2, 32 };
return sizes[bsii(str, size_names, elements(size_names))+1];
}
/**
* find and process preprocessor directive in passed line
* Find out if a line contains a preprocessor directive, and deal
* with it if so.
*
* If a directive _is_ found, it is the responsibility of this routine
* (and not the caller) to free_tlist() the line.
*
* @param tline a pointer to the current tokeninzed line linked list
* @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
*
*/
static int do_directive(Token * tline)
{
enum preproc_token i;
int j;
bool err;
int nparam;
bool nolist;
bool casesense;
int k, m;
int offset;
char *p, *pp, *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;
size_t len;
int severity;
origline = tline;
skip_white_(tline);
if (!tline || !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 nest),
* %endm/%endmacro, and (only if we're in a %rep block) %endrep.
* If we're in a %rep block, another %rep nests, 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;
}
if (defining) {
if (i == PP_MACRO || i == PP_IMACRO) {
nested_mac_count++;
return NO_DIRECTIVE_FOUND;
} else if (nested_mac_count > 0) {
if (i == PP_ENDMACRO) {
nested_mac_count--;
return NO_DIRECTIVE_FOUND;
}
}
if (!defining->name) {
if (i == PP_REP) {
nested_rep_count++;
return NO_DIRECTIVE_FOUND;
} else if (nested_rep_count > 0) {
if (i == PP_ENDREP) {
nested_rep_count--;
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 = 0;
} else if (nasm_stricmp(tline->text, "flat64") == 0) {
/* All subsequent ARG directives are for a 64-bit stack */
StackSize = 8;
StackPointer = "rbp";
ArgOffset = 8;
LocalOffset = 0;
} 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 = 0;
} 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 = 0;
} 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);
size = parse_size(tt->text);
if (!size) {
error(ERR_NONFATAL,
"Invalid size type for `%%arg' missing directive");
free_tlist(tt);
free_tlist(origline);
return DIRECTIVE_FOUND;
}
free_tlist(tt);
/* Round up to even stack slots */
size = (size+StackSize-1) & ~(StackSize-1);
/* 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] == ',');
ArgOffset = offset;
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 = toke
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -