/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2011 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2012 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
#include "tables.h"
typedef struct SMacro SMacro;
-typedef struct ExpDef ExpDef;
-typedef struct ExpInv ExpInv;
+typedef struct MMacro MMacro;
+typedef struct MMacroInvocation MMacroInvocation;
typedef struct Context Context;
typedef struct Token Token;
typedef struct Blocks Blocks;
typedef struct Line Line;
typedef struct Include Include;
+typedef struct Cond Cond;
typedef struct IncPath IncPath;
/*
* Store the definition of a single-line macro.
*/
struct SMacro {
- SMacro *next;
- char *name;
- Token *expansion;
- unsigned int nparam;
- bool casesense;
- bool in_progress;
+ SMacro *next;
+ char *name;
+ bool casesense;
+ bool in_progress;
+ unsigned int nparam;
+ Token *expansion;
+};
+
+/*
+ * Store the definition of a multi-line macro. This is also used to
+ * store the interiors of `%rep...%endrep' blocks, which are
+ * effectively self-re-invoking multi-line macros which simply
+ * don't have a name or bother to appear in the hash tables. %rep
+ * blocks are signified by having a NULL `name' field.
+ *
+ * In a MMacro describing a `%rep' block, the `in_progress' field
+ * isn't merely boolean, but gives the number of repeats left to
+ * run.
+ *
+ * The `next' field is used for storing MMacros in hash tables; the
+ * `next_active' field is for stacking them on istk entries.
+ *
+ * When a MMacro is being expanded, `params', `iline', `nparam',
+ * `paramlen', `rotate' and `unique' are local to the invocation.
+ */
+struct MMacro {
+ MMacro *next;
+ MMacroInvocation *prev; /* previous invocation */
+ char *name;
+ int nparam_min, nparam_max;
+ bool casesense;
+ bool plus; /* is the last parameter greedy? */
+ bool nolist; /* is this macro listing-inhibited? */
+ int64_t in_progress; /* is this macro currently being expanded? */
+ int32_t max_depth; /* maximum number of recursive expansions allowed */
+ Token *dlist; /* All defaults as one list */
+ Token **defaults; /* Parameter default pointers */
+ int ndefs; /* number of default parameters */
+ Line *expansion;
+
+ MMacro *next_active;
+ MMacro *rep_nest; /* used for nesting %rep */
+ Token **params; /* actual parameters */
+ Token *iline; /* invocation line */
+ unsigned int nparam, rotate;
+ int *paramlen;
+ uint64_t unique;
+ int lineno; /* Current line number on expansion */
+ uint64_t condcnt; /* number of if blocks... */
+};
+
+
+/* Store the definition of a multi-line macro, as defined in a
+ * previous recursive macro expansion.
+ */
+struct MMacroInvocation {
+ MMacroInvocation *prev; /* previous invocation */
+ Token **params; /* actual parameters */
+ Token *iline; /* invocation line */
+ unsigned int nparam, rotate;
+ int *paramlen;
+ uint64_t unique;
+ uint64_t condcnt;
};
+
/*
* The context stack is composed of a linked list of these.
*/
struct Context {
- Context *next;
- char *name;
- struct hash_table localmac;
- uint32_t number;
+ Context *next;
+ char *name;
+ struct hash_table localmac;
+ uint32_t number;
};
/*
* quote to use on the filename we were passed.
*/
enum pp_token_type {
- TOK_NONE = 0,
- TOK_WHITESPACE,
- TOK_COMMENT,
- TOK_ID,
- TOK_PREPROC_ID,
- TOK_STRING,
- TOK_NUMBER,
- TOK_FLOAT,
- TOK_SMAC_END,
- TOK_OTHER,
+ TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT, TOK_ID,
+ TOK_PREPROC_ID, TOK_STRING,
+ TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
TOK_INTERNAL_STRING,
- TOK_PREPROC_Q,
- TOK_PREPROC_QQ,
+ TOK_PREPROC_Q, TOK_PREPROC_QQ,
TOK_PASTE, /* %+ */
TOK_INDIRECT, /* %[...] */
TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */
};
struct Token {
- Token *next;
- char *text;
+ Token *next;
+ char *text;
union {
- SMacro *mac; /* associated macro for TOK_SMAC_END */
- size_t len; /* scratch length field */
- } a; /* Auxiliary data */
- enum pp_token_type type;
+ SMacro *mac; /* associated macro for TOK_SMAC_END */
+ size_t len; /* scratch length field */
+ } a; /* Auxiliary data */
+ enum pp_token_type type;
};
/*
- * Expansion definitions are stored as a linked list of
+ * Multi-line macro definitions are stored as a linked list of
* these, which is essentially a container to allow several linked
* lists of Tokens.
*
* Note that in this module, linked lists are treated as stacks
* wherever possible. For this reason, Lines are _pushed_ on to the
- * `last' field in ExpDef structures, so that the linked list,
- * if walked, would emit the expansion lines in the proper order.
- */
-struct Line {
- Line *next;
- Token *first;
-};
-
-/*
- * Expansion Types
- */
-enum pp_exp_type {
- EXP_NONE = 0,
- EXP_PREDEF,
- EXP_MMACRO,
- EXP_REP,
- EXP_IF,
- EXP_WHILE,
- EXP_COMMENT,
- EXP_FINAL,
- EXP_MAX = INT_MAX /* Keep compiler from reducing the range */
-};
-
-/*
- * Store the definition of an expansion, in which is any
- * preprocessor directive that has an ending pair.
- *
- * This design allows for arbitrary expansion/recursion depth,
- * upto the DEADMAN_LIMIT.
+ * `expansion' field in MMacro structures, so that the linked list,
+ * if walked, would give the macro lines in reverse order; this
+ * means that we can walk the list when expanding a macro, and thus
+ * push the lines on to the `expansion' field in _istk_ in reverse
+ * order (so that when popped back off they are in the right
+ * order). It may seem cockeyed, and it relies on my design having
+ * an even number of steps in, but it works...
*
- * The `next' field is used for storing ExpDef in hash tables; the
- * `prev' field is for the global `expansions` linked-list.
+ * Some of these structures, rather than being actual lines, are
+ * markers delimiting the end of the expansion of a given macro.
+ * This is for use in the cycle-tracking and %rep-handling code.
+ * Such structures have `finishes' non-NULL, and `first' NULL. All
+ * others have `finishes' NULL, but `first' may still be NULL if
+ * the line is blank.
*/
-struct ExpDef {
- ExpDef *prev; /* previous definition */
- ExpDef *next; /* next in hash table */
- enum pp_exp_type type; /* expansion type */
- char *name; /* definition name */
- int nparam_min;
- int nparam_max;
- bool casesense;
- bool plus; /* is the last parameter greedy? */
- bool nolist; /* is this expansion listing-inhibited? */
- Token *dlist; /* all defaults as one list */
- Token **defaults; /* parameter default pointers */
- int ndefs; /* number of default parameters */
-
- int prepend; /* label prepend state */
- Line *label;
- Line *line;
- Line *last;
- int linecount; /* number of lines within expansion */
-
- int64_t def_depth; /* current number of definition pairs deep */
- int64_t cur_depth; /* current number of expansions */
- int64_t max_depth; /* maximum number of expansions allowed */
-
- int state; /* condition state */
- bool ignoring; /* ignoring definition lines */
-};
-
-/*
- * Store the invocation of an expansion.
- *
- * The `prev' field is for the `istk->expansion` linked-list.
- *
- * When an expansion is being expanded, `params', `iline', `nparam',
- * `paramlen', `rotate' and `unique' are local to the invocation.
- */
-struct ExpInv {
- ExpInv *prev; /* previous invocation */
- ExpDef *def; /* pointer to expansion definition */
- char *name; /* invocation name */
- Line *label; /* pointer to label */
- char *label_text; /* pointer to label text */
- Line *current; /* pointer to current line in invocation */
-
- Token **params; /* actual parameters */
- Token *iline; /* invocation line */
- int *paramlen;
- unsigned int nparam;
- unsigned int rotate;
-
- uint64_t unique;
- int lineno; /* current line number in expansion */
- int linnum; /* line number at invocation */
- int relno; /* relative line number at invocation */
- enum pp_exp_type type; /* expansion type */
- bool emitting;
+struct Line {
+ Line *next;
+ MMacro *finishes;
+ Token *first;
};
/*
* stack (ie linked list) of these things.
*/
struct Include {
- Include *next;
- FILE *fp;
- ExpInv *expansion;
- char *fname;
- int lineno;
- int lineinc;
- int mmac_depth;
+ Include *next;
+ FILE *fp;
+ Cond *conds;
+ Line *expansion;
+ char *fname;
+ int lineno, lineinc;
+ MMacro *mstk; /* stack of active macros/reps */
};
/*
* attempt to find the file if it's not in the current directory.
*/
struct IncPath {
- IncPath *next;
- char *path;
+ IncPath *next;
+ char *path;
};
/*
* included from within the true branch of a `%if' won't terminate
* it and cause confusion: instead, rightly, it'll cause an error.)
*/
+struct Cond {
+ Cond *next;
+ int state;
+};
enum {
/*
* These states are for use just after %if or %elif: IF_TRUE
* up. In these states, all directives are admissible: %elif,
* %else and %endif. (And of course %if.)
*/
- COND_IF_TRUE,
- COND_IF_FALSE,
+ COND_IF_TRUE, COND_IF_FALSE,
/*
* These states come up after a %else: ELSE_TRUE means we're
* emitting, and ELSE_FALSE means we're not. In ELSE_* states,
* any %elif or %else will cause an error.
*/
- COND_ELSE_TRUE,
- COND_ELSE_FALSE,
+ COND_ELSE_TRUE, COND_ELSE_FALSE,
/*
* These states mean that we're not emitting now, and also that
* nothing until %endif will be emitted at all. COND_DONE is
* non-emitting branch of a larger condition construct,
* or if there is an error.
*/
- COND_DONE,
- COND_NEVER
+ COND_DONE, COND_NEVER
};
+#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE )
/*
* These defines are used as the possible return values for do_directive
#define DIRECTIVE_FOUND 1
/*
- * This define sets the upper limit for smacro and expansions
+ * This define sets the upper limit for smacro and recursive mmacro
+ * expansions
*/
#define DEADMAN_LIMIT (1 << 20)
c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
};
+/*
+ * Directive names.
+ */
+/* If this is a an IF, ELIF, ELSE or ENDIF keyword */
+static int is_condition(enum preproc_token arg)
+{
+ return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF);
+}
+
/* For TASM compatibility we need to be able to recognise TASM compatible
* conditional compilation directives. Using the NASM pre-processor does
* not work, so we look for them specifically from the following list and
static Context *cstk;
static Include *istk;
-static IncPath *ipath;
+static IncPath *ipath = NULL;
static int pass; /* HACK: pass 0 = generate dependencies only */
static StrList **dephead, **deptail; /* Dependency list */
static uint64_t unique; /* unique identifier numbers */
-static Line *predef;
+static Line *predef = NULL;
static bool do_predef;
static ListGen *list;
/*
- * The current set of expansion definitions we have defined.
+ * The current set of multi-line macros we have defined.
*/
-static struct hash_table expdefs;
+static struct hash_table mmacros;
/*
* The current set of single-line macros we have defined.
static struct hash_table smacros;
/*
- * Linked List of all active expansion definitions
+ * The multi-line macro we are currently defining, or the %rep
+ * block we are currently reading, if any.
*/
-struct ExpDef *expansions;
-
-/*
- * The expansion we are currently defining
- */
-static ExpDef *defining;
+static MMacro *defining;
static uint64_t nested_mac_count;
static uint64_t nested_rep_count;
/*
- * Linked-list of lines to preprocess, prior to cleanup
- */
-static Line *finals;
-static bool in_final = false;
-
-/*
* The number of macro parameters to allocate space for at a time.
*/
#define PARAM_DELTA 16
* The extra standard macros that come from the object format, if
* any.
*/
-static macros_t *extrastdmac;
+static macros_t *extrastdmac = NULL;
static bool any_extrastdmac;
/*
* Tokens are allocated in blocks to improve speed
*/
#define TOKEN_BLOCKSIZE 4096
-static Token *freeTokens;
+static Token *freeTokens = NULL;
struct Blocks {
Blocks *next;
void *chunk;
};
-static Blocks blocks;
+static Blocks blocks = { NULL, NULL };
/*
* Forward declarations.
static Token *expand_mmac_params(Token * tline);
static Token *expand_smacro(Token * tline);
static Token *expand_id(Token * tline);
-static Context *get_ctx(const char *name, const char **namep);
+static Context *get_ctx(const char *name, const char **namep,
+ bool all_contexts);
static void make_tok_num(Token * tok, int64_t val);
static void error(int severity, const char *fmt, ...);
static void error_precond(int severity, const char *fmt, ...);
static void delete_Blocks(void);
static Token *new_Token(Token * next, enum pp_token_type type,
const char *text, int txtlen);
-static Token *copy_Token(Token * tline);
static Token *delete_Token(Token * t);
-static Line *new_Line(void);
-static ExpDef *new_ExpDef(int exp_type);
-static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
/*
* Macros for safe checking of token pointers, avoid *(NULL)
#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
/*
- * A few helpers for single macros
- */
-
-/* We might be not smacro parameter at all */
-static bool is_smacro_param(Token *t)
-{
- return t->type >= TOK_SMAC_PARAM;
-}
-
-/* smacro parameters are counted in a special way */
-static int smacro_get_param_idx(Token *t)
-{
- return t->type - TOK_SMAC_PARAM;
-}
-
-/* encode smacro parameter index */
-static int smacro_set_param_idx(Token *t, unsigned int index)
-{
- return t->type = TOK_SMAC_PARAM + index;
-}
-
-#ifdef NASM_TRACE
-
-#define stringify(x) #x
-
-#define nasm_trace(msg, ...) printf("(%s:%d): " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
-#define nasm_dump_token(t) nasm_raw_dump_token(t, __FILE__, __LINE__, __func__);
-#define nasm_dump_stream(t) nasm_raw_dump_stream(t, __FILE__, __LINE__, __func__);
-
-/* FIXME: we really need some compound type here instead of inplace code */
-static const char *nasm_get_tok_type_str(enum pp_token_type type)
-{
-#define SWITCH_TOK_NAME(type) \
- case (type): \
- return stringify(type)
-
- switch (type) {
- SWITCH_TOK_NAME(TOK_NONE);
- SWITCH_TOK_NAME(TOK_WHITESPACE);
- SWITCH_TOK_NAME(TOK_COMMENT);
- SWITCH_TOK_NAME(TOK_ID);
- SWITCH_TOK_NAME(TOK_PREPROC_ID);
- SWITCH_TOK_NAME(TOK_STRING);
- SWITCH_TOK_NAME(TOK_NUMBER);
- SWITCH_TOK_NAME(TOK_FLOAT);
- SWITCH_TOK_NAME(TOK_SMAC_END);
- SWITCH_TOK_NAME(TOK_OTHER);
- SWITCH_TOK_NAME(TOK_INTERNAL_STRING);
- SWITCH_TOK_NAME(TOK_PREPROC_Q);
- SWITCH_TOK_NAME(TOK_PREPROC_QQ);
- SWITCH_TOK_NAME(TOK_PASTE);
- SWITCH_TOK_NAME(TOK_INDIRECT);
- SWITCH_TOK_NAME(TOK_SMAC_PARAM);
- SWITCH_TOK_NAME(TOK_MAX);
- }
-
- return NULL;
-}
-
-static void nasm_raw_dump_token(Token *token, const char *file, int line, const char *func)
-{
- printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
- if (token) {
- Token *t;
- list_for_each(t, token) {
- if (t->text)
- printf("'%s'(%s) ", t->text,
- nasm_get_tok_type_str(t->type));
- }
- printf("\n\n");
- }
-}
-
-static void nasm_raw_dump_stream(Token *token, const char *file, int line, const char *func)
-{
- printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
- if (token) {
- Token *t;
- list_for_each(t, token)
- printf("%s", t->text ? t->text : " ");
- printf("\n\n");
- }
-}
-
-#else
-#define nasm_trace(msg, ...)
-#define nasm_dump_token(t)
-#define nasm_dump_stream(t)
-#endif
-
-/*
* nasm_unquote with error if the string contains NUL characters.
* If the string contains NUL characters, issue an error and return
* the C len, i.e. truncate at the NUL.
*/
static Token *reverse_tokens(Token *t)
{
- Token *prev, *next;
+ Token *prev = NULL;
+ Token *next;
- list_reverse(t, prev, next);
+ while (t) {
+ next = t->next;
+ t->next = prev;
+ prev = t;
+ t = next;
+ }
- return t;
+ return prev;
}
/*
}
/*
- * Free an ExpDef
+ * Free an MMacro
*/
-static void free_expdef(ExpDef * ed)
+static void free_mmacro(MMacro * m)
{
- nasm_free(ed->name);
- free_tlist(ed->dlist);
- nasm_free(ed->defaults);
- free_llist(ed->line);
- nasm_free(ed);
-}
-
-/*
- * Free an ExpInv
- */
-static void free_expinv(ExpInv * ei)
-{
- nasm_free(ei->name);
- nasm_free(ei->label_text);
- nasm_free(ei);
+ nasm_free(m->name);
+ free_tlist(m->dlist);
+ nasm_free(m->defaults);
+ free_llist(m->expansion);
+ nasm_free(m);
}
/*
hash_free(smt);
}
-static void free_expdef_table(struct hash_table *edt)
+static void free_mmacro_table(struct hash_table *mmt)
{
- ExpDef *ed, *tmp;
+ MMacro *m, *tmp;
const char *key;
struct hash_tbl_node *it = NULL;
it = NULL;
- while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
+ while ((m = hash_iterate(mmt, &it, &key)) != NULL) {
nasm_free((void *)key);
- list_for_each_safe(ed ,tmp, ed)
- free_expdef(ed);
+ list_for_each_safe(m ,tmp, m)
+ free_mmacro(m);
}
- hash_free(edt);
+ hash_free(mmt);
}
static void free_macros(void)
{
free_smacro_table(&smacros);
- free_expdef_table(&expdefs);
+ free_mmacro_table(&mmacros);
}
/*
static void init_macros(void)
{
hash_init(&smacros, HASH_LARGE);
- hash_init(&expdefs, HASH_LARGE);
+ hash_init(&mmacros, HASH_LARGE);
}
/*
}
/*
- * read line from standard macros set,
+ * read line from standart macros set,
* if there no more left -- return NULL
*/
static char *line_from_stdmac(void)
stdmacpos = extrastdmac;
any_extrastdmac = false;
} else if (do_predef) {
- ExpInv *ei;
Line *pd, *l;
Token *head, **tail, *t;
tail = &(*tail)->next;
}
- l = new_Line();
- l->first = head;
- ei = new_ExpInv(EXP_PREDEF, NULL);
- ei->current = l;
- ei->emitting = true;
- ei->prev = istk->expansion;
- istk->expansion = ei;
+ l = nasm_malloc(sizeof(Line));
+ l->next = istk->expansion;
+ l->first = head;
+ l->finishes = NULL;
+
+ istk->expansion = l;
}
do_predef = false;
}
enum pp_token_type type;
Token *list = NULL;
Token *t, **tail = &list;
- bool verbose = true;
-
- nasm_trace("Tokenize for '%s'", line);
-
- if ((defining != NULL) && (defining->ignoring == true)) {
- verbose = false;
- }
while (*line) {
p = line;
type = TOK_PREPROC_ID;
} else if (*p == '{') {
p++;
- while (*p && *p != '}') {
+ while (*p) {
+ if (*p == '}')
+ break;
p[-1] = *p;
p++;
}
+ if (*p != '}')
+ error(ERR_WARNING | ERR_PASS1, "unterminated %{ construct");
p[-1] = '\0';
if (*p)
p++;
p--;
if (*p)
*p++ = '\0';
- if (lvl && verbose)
+ if (lvl)
error(ERR_NONFATAL, "unterminated %[ construct");
type = TOK_INDIRECT;
} else if (*p == '?') {
type = TOK_PREPROC_QQ; /* %?? */
p++;
}
- } else if (*p == '!') {
- type = TOK_PREPROC_ID;
- p++;
- if (isidchar(*p)) {
- do {
- p++;
- } while (isidchar(*p));
- } else if (*p == '\'' || *p == '\"' || *p == '`') {
- p = nasm_skip_string(p);
- if (*p)
- p++;
- else if(verbose)
- error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
- } else {
- /* %! without string or identifier */
- type = TOK_OTHER; /* Legacy behavior... */
- }
+ } else if (*p == '!') {
+ type = TOK_PREPROC_ID;
+ p++;
+ if (isidchar(*p)) {
+ do {
+ p++;
+ }
+ while (isidchar(*p));
+ } else if (*p == '\'' || *p == '\"' || *p == '`') {
+ p = nasm_skip_string(p);
+ if (*p)
+ p++;
+ else
+ error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
+ } else {
+ /* %! without string or identifier */
+ type = TOK_OTHER; /* Legacy behavior... */
+ }
} else if (isidchar(*p) ||
((*p == '!' || *p == '%' || *p == '$') &&
isidchar(p[1]))) {
if (*p) {
p++;
- } else if(verbose) {
+ } else {
error(ERR_WARNING|ERR_PASS1, "unterminated string");
/* Handling unterminated strings by UNV */
/* type = -1; */
}
line = p;
}
-
- nasm_dump_token(list);
-
return list;
}
/* first, get to the end of the linked list */
while (b->next)
b = b->next;
-
/* now allocate the requested chunk */
b->chunk = nasm_malloc(size);
/* now allocate a new block for the next request */
- b->next = nasm_zalloc(sizeof(Blocks));
-
+ b->next = nasm_malloc(sizeof(Blocks));
+ /* and initialize the contents of the new block */
+ b->next->next = NULL;
+ b->next->chunk = NULL;
return b->chunk;
}
* free it.
*/
while (b) {
- nasm_free(b->chunk);
+ if (b->chunk)
+ nasm_free(b->chunk);
a = b;
b = b->next;
if (a != &blocks)
return t;
}
-static Token *copy_Token(Token * tline)
-{
- Token *t, *tt, *first = NULL, *prev = NULL;
- int i;
- for (tt = tline; tt != NULL; tt = tt->next) {
- if (!freeTokens) {
- freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
- for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
- freeTokens[i].next = &freeTokens[i + 1];
- freeTokens[i].next = NULL;
- }
- t = freeTokens;
- freeTokens = t->next;
- t->next = NULL;
- t->text = tt->text ? nasm_strdup(tt->text) : NULL;
- t->a.mac = tt->a.mac;
- t->a.len = tt->a.len;
- t->type = tt->type;
- if (prev != NULL) {
- prev->next = t;
- } else {
- first = t;
- }
- prev = t;
- }
- return first;
-}
-
static Token *delete_Token(Token * t)
{
Token *next = t->next;
list_for_each(t, tlist) {
if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
- char *v;
- char *q = t->text;
-
- v = t->text + 2;
- if (*v == '\'' || *v == '\"' || *v == '`') {
- size_t len = nasm_unquote(v, NULL);
- size_t clen = strlen(v);
-
- if (len != clen) {
- error(ERR_NONFATAL | ERR_PASS1,
- "NUL character in %! string");
- v = NULL;
- }
- }
-
- if (v) {
- char *p = getenv(v);
- if (!p) {
- error(ERR_NONFATAL | ERR_PASS1,
- "nonexistent environment variable `%s'", v);
- p = "";
- }
- t->text = nasm_strdup(p);
- }
- nasm_free(q);
+ char *v;
+ char *q = t->text;
+
+ v = t->text + 2;
+ if (*v == '\'' || *v == '\"' || *v == '`') {
+ size_t len = nasm_unquote(v, NULL);
+ size_t clen = strlen(v);
+
+ if (len != clen) {
+ error(ERR_NONFATAL | ERR_PASS1,
+ "NUL character in %! string");
+ v = NULL;
+ }
+ }
+
+ if (v) {
+ char *p = getenv(v);
+ if (!p) {
+ error(ERR_NONFATAL | ERR_PASS1,
+ "nonexistent environment variable `%s'", v);
+ p = "";
+ }
+ t->text = nasm_strdup(p);
+ }
+ nasm_free(q);
}
/* Expand local macros here and not during preprocessing */
t->text[0] == '%' && t->text[1] == '$') {
const char *q;
char *p;
- Context *ctx = get_ctx(t->text, &q);
+ Context *ctx = get_ctx(t->text, &q, false);
if (ctx) {
char buffer[40];
snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
t->text = p;
}
}
-
- /* Expand %? and %?? directives */
- if ((istk->expansion != NULL) &&
- ((t->type == TOK_PREPROC_Q) ||
- (t->type == TOK_PREPROC_QQ))) {
- ExpInv *ei;
- for (ei = istk->expansion; ei != NULL; ei = ei->prev){
- if (ei->type == EXP_MMACRO) {
- nasm_free(t->text);
- if (t->type == TOK_PREPROC_Q) {
- t->text = nasm_strdup(ei->name);
- } else {
- t->text = nasm_strdup(ei->def->name);
- }
- break;
- }
- }
- }
-
if (t->type == TOK_WHITESPACE)
len++;
else if (t->text)
}
/*
- * Initialize a new Line
- */
-static inline Line *new_Line(void)
-{
- return (Line *)nasm_zalloc(sizeof(Line));
-}
-
-
-/*
- * Initialize a new Expansion Definition
- */
-static ExpDef *new_ExpDef(int exp_type)
-{
- ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
- ed->type = exp_type;
- ed->casesense = true;
- ed->state = COND_NEVER;
-
- return ed;
-}
-
-
-/*
- * Initialize a new Expansion Instance
- */
-static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
-{
- ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
- ei->type = exp_type;
- ei->def = ed;
- ei->unique = ++unique;
-
- if ((istk->mmac_depth < 1) &&
- (istk->expansion == NULL) &&
- (ed != NULL) &&
- (ed->type != EXP_MMACRO) &&
- (ed->type != EXP_REP) &&
- (ed->type != EXP_WHILE)) {
- ei->linnum = src_get_linnum();
- src_set_linnum(ei->linnum - ed->linecount - 1);
- } else {
- ei->linnum = -1;
- }
- if ((istk->expansion == NULL) ||
- (ei->type == EXP_MMACRO)) {
- ei->relno = 0;
- } else {
- ei->relno = istk->expansion->lineno;
- if (ed != NULL) {
- ei->relno -= (ed->linecount + 1);
- }
- }
- return ei;
-}
-
-/*
* A scanner, suitable for use by the expression evaluator, which
* operates on a line of Tokens. Expects a pointer to a pointer to
* the first token in the line to be passed in as its private_data
* NULL, having _already_ reported an error condition, if the
* context stack isn't deep enough for the supplied number of $
* signs.
+ * If all_contexts == true, contexts that enclose current are
+ * also scanned for such smacro, until it is found; if not -
+ * only the context that directly results from the number of $'s
+ * in variable's name.
*
* If "namep" is non-NULL, set it to the pointer to the macro name
* tail, i.e. the part beyond %$...
*/
-static Context *get_ctx(const char *name, const char **namep)
+static Context *get_ctx(const char *name, const char **namep,
+ bool all_contexts)
{
Context *ctx;
+ SMacro *m;
int i;
if (namep)
i++;
ctx = ctx->next;
}
-
if (!ctx) {
error(ERR_NONFATAL, "`%s': context stack is only"
" %d level%s deep", name, i, (i == 1 ? "" : "s"));
if (namep)
*namep = name;
- return ctx;
+ if (!all_contexts)
+ return ctx;
+
+ /*
+ * NOTE: In 2.10 we will not need lookup in extarnal
+ * contexts, so this is a gentle way to inform users
+ * about their source code need to be updated
+ */
+
+ /* first round -- check the current context */
+ m = hash_findix(&ctx->localmac, name);
+ while (m) {
+ if (!mstrcmp(m->name, name, m->casesense))
+ return ctx;
+ m = m->next;
+ }
+
+ /* second round - external contexts */
+ while ((ctx = ctx->next)) {
+ /* Search for this smacro in found context */
+ m = hash_findix(&ctx->localmac, name);
+ while (m) {
+ if (!mstrcmp(m->name, name, m->casesense)) {
+ /* NOTE: deprecated as of 2.10 */
+ static int once = 0;
+ if (!once) {
+ error(ERR_WARNING, "context-local macro expansion"
+ " fall-through (automatic searching of outer"
+ " contexts) will be deprecated starting in"
+ " NASM 2.10, please see the NASM Manual for"
+ " more information");
+ once = 1;
+ }
+ error(ERR_WARNING, "`%s': context-local macro expansion fall-through", name);
+ return ctx;
+ }
+ m = m->next;
+ }
+ }
+
+ return NULL;
}
/*
while (1) {
sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
- sl->next = NULL;
memcpy(sl->str, prefix, prefix_len);
memcpy(sl->str+prefix_len, file, len+1);
fp = fopen(sl->str, "r");
if (fp && dhead && !in_list(*dhead, sl->str)) {
+ sl->next = NULL;
**dtail = sl;
*dtail = &sl->next;
} else {
smtbl = &ctx->localmac;
} else if (name[0] == '%' && name[1] == '$') {
if (cstk)
- ctx = get_ctx(name, &name);
+ ctx = get_ctx(name, &name, false);
if (!ctx)
return false; /* got to return _something_ */
smtbl = &ctx->localmac;
case PPC_IFDEF:
j = false; /* have we matched yet? */
- skip_white_(tline);
- do {
+ while (tline) {
+ skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
if (smacro_defined(NULL, tline->text, 0, NULL, true))
j = true;
tline = tline->next;
- skip_white_(tline);
- } while (tline);
+ }
break;
case PPC_IFENV:
- tline = expand_smacro(tline);
+ tline = expand_smacro(tline);
j = false; /* have we matched yet? */
- skip_white_(tline);
- do {
+ while (tline) {
+ skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
- tline->type != TOK_STRING &&
+ tline->type != TOK_STRING &&
(tline->type != TOK_PREPROC_ID ||
- tline->text[1] != '!'))) {
+ tline->text[1] != '!'))) {
error(ERR_NONFATAL,
"`%s' expects environment variable names",
- pp_directives[ct]);
+ pp_directives[ct]);
goto fail;
}
- p = tline->text;
- if (tline->type == TOK_PREPROC_ID)
- p += 2; /* Skip leading %! */
- if (*p == '\'' || *p == '\"' || *p == '`')
- nasm_unquote_cstr(p, ct);
- if (getenv(p))
- j = true;
+ p = tline->text;
+ if (tline->type == TOK_PREPROC_ID)
+ p += 2; /* Skip leading %! */
+ if (*p == '\'' || *p == '\"' || *p == '`')
+ nasm_unquote_cstr(p, ct);
+ if (getenv(p))
+ j = true;
tline = tline->next;
- skip_white_(tline);
- } while (tline);
+ }
break;
case PPC_IFIDN:
case PPC_IFMACRO:
{
bool found = false;
- ExpDef searching, *ed;
+ MMacro searching, *mmac;
skip_white_(tline);
tline = expand_id(tline);
"`%s' expects a macro name", pp_directives[ct]);
goto fail;
}
- memset(&searching, 0, sizeof(searching));
searching.name = nasm_strdup(tline->text);
searching.casesense = true;
+ searching.plus = false;
+ searching.nolist = false;
+ searching.in_progress = 0;
+ searching.max_depth = 0;
+ searching.rep_nest = NULL;
+ searching.nparam_min = 0;
searching.nparam_max = INT_MAX;
tline = expand_smacro(tline->next);
skip_white_(tline);
tline = tline->next;
searching.plus = true;
}
- ed = (ExpDef *) hash_findix(&expdefs, searching.name);
- while (ed != NULL) {
- if (!strcmp(ed->name, searching.name) &&
- (ed->nparam_min <= searching.nparam_max || searching.plus) &&
- (searching.nparam_min <= ed->nparam_max || ed->plus)) {
+ mmac = (MMacro *) hash_findix(&mmacros, searching.name);
+ while (mmac) {
+ if (!strcmp(mmac->name, searching.name) &&
+ (mmac->nparam_min <= searching.nparam_max
+ || searching.plus)
+ && (searching.nparam_min <= mmac->nparam_max
+ || mmac->plus)) {
found = true;
break;
}
- ed = ed->next;
+ mmac = mmac->next;
}
if (tline && tline->next)
error(ERR_WARNING|ERR_PASS1,
} else {
smtbl = ctx ? &ctx->localmac : &smacros;
smhead = (SMacro **) hash_findi_add(smtbl, mname);
- smac = nasm_zalloc(sizeof(SMacro));
+ smac = nasm_malloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
}
/*
* Parse a mmacro specification.
*/
-static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
+static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
{
bool err;
return false;
}
+ def->prev = NULL;
def->name = nasm_strdup(tline->text);
def->plus = false;
def->nolist = false;
-// def->in_progress = 0;
-// def->rep_nest = NULL;
+ def->in_progress = 0;
+ def->rep_nest = NULL;
def->nparam_min = 0;
def->nparam_max = 0;
def->dlist = NULL;
def->defaults = NULL;
}
- def->line = NULL;
+ def->expansion = NULL;
if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
!def->plus)
const char *mname;
Include *inc;
Context *ctx;
- Line *l;
+ Cond *cond;
+ MMacro *mmac, **mmhead;
Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
+ Line *l;
struct tokenval tokval;
expr *evalresult;
- ExpDef *ed, *eed, **edhead;
- ExpInv *ei, *eei;
+ MMacro *tmp_defining; /* Used when manipulating rep_nest */
int64_t count;
size_t len;
int severity;
i = pp_token_hash(tline->text);
+ /*
+ * FIXME: We zap execution of PP_RMACRO, PP_IRMACRO, PP_EXITMACRO
+ * since they are known to be buggy at moment, we need to fix them
+ * in future release (2.09-2.10)
+ */
+ if (i == PP_RMACRO || i == PP_RMACRO || i == PP_EXITMACRO) {
+ error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
+ tline->text);
+ return NO_DIRECTIVE_FOUND;
+ }
+
+ /*
+ * 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_RMACRO && i != PP_IRMACRO &&
+ 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 ||
+ i == PP_RMACRO || i == PP_IRMACRO) {
+ 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:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
tline->text);
return NO_DIRECTIVE_FOUND; /* didn't get it */
case PP_STACKSIZE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* 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.
return DIRECTIVE_FOUND;
case PP_ARG:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* TASM like ARG directive to define arguments to functions, in
* the following form:
*
return DIRECTIVE_FOUND;
case PP_LOCAL:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* TASM like LOCAL directive to define local variables for a
* function, in the following form:
*
return DIRECTIVE_FOUND;
case PP_CLEAR:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
if (tline->next)
error(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%clear' ignored");
return DIRECTIVE_FOUND;
case PP_DEPEND:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
t = tline->next = expand_smacro(tline->next);
skip_white_(t);
if (!t || (t->type != TOK_STRING &&
return DIRECTIVE_FOUND;
case PP_INCLUDE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
t = tline->next = expand_smacro(tline->next);
skip_white_(t);
p = t->text;
if (t->type != TOK_INTERNAL_STRING)
nasm_unquote_cstr(p, i);
- inc = nasm_zalloc(sizeof(Include));
+ inc = nasm_malloc(sizeof(Include));
inc->next = istk;
+ inc->conds = NULL;
inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
if (!inc->fp) {
/* -MG given but file not found */
inc->lineno = src_set_linnum(0);
inc->lineinc = 1;
inc->expansion = NULL;
+ inc->mstk = NULL;
istk = inc;
list->uplevel(LIST_INCLUDE);
}
return DIRECTIVE_FOUND;
case PP_USE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
static macros_t *use_pkg;
const char *pkg_macro = NULL;
case PP_PUSH:
case PP_REPL:
case PP_POP:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
}
if (i == PP_PUSH) {
- ctx = nasm_zalloc(sizeof(Context));
+ ctx = nasm_malloc(sizeof(Context));
ctx->next = cstk;
hash_init(&ctx->localmac, HASH_SMALL);
ctx->name = p;
goto issue_error;
issue_error:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
/* Only error out if this is the final pass */
if (pass != 2 && i != PP_FATAL)
}
CASE_PP_IF:
- if (defining != NULL) {
- if (defining->type == EXP_IF) {
- defining->def_depth ++;
- }
- return NO_DIRECTIVE_FOUND;
- }
- if ((istk->expansion != NULL) &&
- (istk->expansion->emitting == false)) {
+ if (istk->conds && !emitting(istk->conds->state))
j = COND_NEVER;
- } else {
+ else {
j = if_condition(tline->next, i);
tline->next = NULL; /* it got freed */
- j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
- }
- ed = new_ExpDef(EXP_IF);
- ed->state = j;
- ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
- ed->prev = defining;
- defining = ed;
+ 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;
+ if(istk->mstk)
+ istk->mstk->condcnt ++;
free_tlist(origline);
return DIRECTIVE_FOUND;
CASE_PP_ELIF:
- if (defining != NULL) {
- if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
- return NO_DIRECTIVE_FOUND;
- }
- }
- if ((defining == NULL) || (defining->type != EXP_IF)) {
+ if (!istk->conds)
error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
- }
- switch (defining->state) {
+ switch(istk->conds->state) {
case COND_IF_TRUE:
- defining->state = COND_DONE;
- defining->ignoring = true;
+ istk->conds->state = COND_DONE;
break;
case COND_DONE:
case COND_NEVER:
- defining->ignoring = true;
break;
case COND_ELSE_TRUE:
case COND_ELSE_FALSE:
error_precond(ERR_WARNING|ERR_PASS1,
"`%%elif' after `%%else' ignored");
- defining->state = COND_NEVER;
- defining->ignoring = true;
+ istk->conds->state = COND_NEVER;
break;
case COND_IF_FALSE:
*/
j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */
- defining->state =
+ istk->conds->state =
j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
- defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
break;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ELSE:
- if (defining != NULL) {
- if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
- return NO_DIRECTIVE_FOUND;
- }
- }
if (tline->next)
error_precond(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%else' ignored");
- if ((defining == NULL) || (defining->type != EXP_IF)) {
- error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
- }
- switch (defining->state) {
+ if (!istk->conds)
+ error(ERR_FATAL, "`%%else': no matching `%%if'");
+ switch(istk->conds->state) {
case COND_IF_TRUE:
case COND_DONE:
- defining->state = COND_ELSE_FALSE;
- defining->ignoring = true;
+ istk->conds->state = COND_ELSE_FALSE;
break;
case COND_NEVER:
- defining->ignoring = true;
break;
case COND_IF_FALSE:
- defining->state = COND_ELSE_TRUE;
- defining->ignoring = false;
+ istk->conds->state = COND_ELSE_TRUE;
break;
case COND_ELSE_TRUE:
case COND_ELSE_FALSE:
error_precond(ERR_WARNING|ERR_PASS1,
"`%%else' after `%%else' ignored.");
- defining->state = COND_NEVER;
- defining->ignoring = true;
+ istk->conds->state = COND_NEVER;
break;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ENDIF:
- if (defining != NULL) {
- if (defining->type == EXP_IF) {
- if (defining->def_depth > 0) {
- defining->def_depth --;
- return NO_DIRECTIVE_FOUND;
- }
- } else {
- return NO_DIRECTIVE_FOUND;
- }
- }
if (tline->next)
error_precond(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%endif' ignored");
- if ((defining == NULL) || (defining->type != EXP_IF)) {
- error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
- return DIRECTIVE_FOUND;
- }
- ed = defining;
- defining = ed->prev;
- ed->prev = expansions;
- expansions = ed;
- ei = new_ExpInv(EXP_IF, ed);
- ei->current = ed->line;
- ei->emitting = true;
- ei->prev = istk->expansion;
- istk->expansion = ei;
+ if (!istk->conds)
+ error(ERR_FATAL, "`%%endif': no matching `%%if'");
+ cond = istk->conds;
+ istk->conds = cond->next;
+ nasm_free(cond);
+ if(istk->mstk)
+ istk->mstk->condcnt --;
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_IRMACRO:
case PP_MACRO:
case PP_IMACRO:
- if (defining != NULL) {
- if (defining->type == EXP_MMACRO) {
- defining->def_depth ++;
- }
- return NO_DIRECTIVE_FOUND;
+ if (defining) {
+ error(ERR_FATAL, "`%s': already defining a macro",
+ pp_directives[i]);
+ return DIRECTIVE_FOUND;
}
- ed = new_ExpDef(EXP_MMACRO);
- ed->max_depth =
+ defining = nasm_malloc(sizeof(MMacro));
+ defining->max_depth =
(i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
- ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
- if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
- nasm_free(ed);
- ed = NULL;
+ defining->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
+ if (!parse_mmacro_spec(tline, defining, pp_directives[i])) {
+ nasm_free(defining);
+ defining = NULL;
return DIRECTIVE_FOUND;
}
- ed->def_depth = 0;
- ed->cur_depth = 0;
- ed->max_depth = (ed->max_depth + 1);
- ed->ignoring = false;
- ed->prev = defining;
- defining = ed;
-
- eed = (ExpDef *) hash_findix(&expdefs, ed->name);
- while (eed) {
- if (!strcmp(eed->name, ed->name) &&
- (eed->nparam_min <= ed->nparam_max || ed->plus) &&
- (ed->nparam_min <= eed->nparam_max || eed->plus)) {
- error(ERR_WARNING|ERR_PASS1,
- "redefining multi-line macro `%s'", ed->name);
- return DIRECTIVE_FOUND;
+
+ mmac = (MMacro *) hash_findix(&mmacros, defining->name);
+ while (mmac) {
+ if (!strcmp(mmac->name, defining->name) &&
+ (mmac->nparam_min <= defining->nparam_max
+ || defining->plus)
+ && (defining->nparam_min <= mmac->nparam_max
+ || mmac->plus)) {
+ error(ERR_WARNING|ERR_PASS1,
+ "redefining multi-line macro `%s'", defining->name);
+ return DIRECTIVE_FOUND;
}
- eed = eed->next;
+ mmac = mmac->next;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ENDM:
case PP_ENDMACRO:
- if (defining != NULL) {
- if (defining->type == EXP_MMACRO) {
- if (defining->def_depth > 0) {
- defining->def_depth --;
- return NO_DIRECTIVE_FOUND;
- }
- } else {
- return NO_DIRECTIVE_FOUND;
- }
- }
- if (!(defining) || (defining->type != EXP_MMACRO)) {
+ if (! (defining && defining->name)) {
error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
return DIRECTIVE_FOUND;
}
- edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
- defining->next = *edhead;
- *edhead = defining;
- ed = defining;
- defining = ed->prev;
- ed->prev = expansions;
- expansions = ed;
- ed = NULL;
+ mmhead = (MMacro **) hash_findi_add(&mmacros, defining->name);
+ defining->next = *mmhead;
+ *mmhead = defining;
+ defining = NULL;
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_EXITMACRO:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* We must search along istk->expansion until we hit a
- * macro invocation. Then we disable the emitting state(s)
- * between exitmacro and endmacro.
+ * macro-end marker for a macro with a name. Then we
+ * bypass all lines between exitmacro and endmacro.
*/
- for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
- if(ei->type == EXP_MMACRO) {
+ list_for_each(l, istk->expansion)
+ if (l->finishes && l->finishes->name)
break;
- }
- }
- if (ei != NULL) {
+ if (l) {
/*
- * Set all invocations leading back to the macro
- * invocation to a non-emitting state.
+ * Remove all conditional entries relative to this
+ * macro invocation. (safe to do in this context)
*/
- for (eei = istk->expansion; eei != ei; eei = eei->prev) {
- eei->emitting = false;
+ for ( ; l->finishes->condcnt > 0; l->finishes->condcnt --) {
+ cond = istk->conds;
+ istk->conds = cond->next;
+ nasm_free(cond);
}
- eei->emitting = false;
+ istk->expansion = l;
} else {
error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
}
case PP_UNMACRO:
case PP_UNIMACRO:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
- ExpDef **ed_p;
- ExpDef spec;
+ MMacro **mmac_p;
+ MMacro spec;
spec.casesense = (i == PP_UNMACRO);
if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
return DIRECTIVE_FOUND;
}
- ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
- while (ed_p && *ed_p) {
- ed = *ed_p;
- if (ed->casesense == spec.casesense &&
- !mstrcmp(ed->name, spec.name, spec.casesense) &&
- ed->nparam_min == spec.nparam_min &&
- ed->nparam_max == spec.nparam_max &&
- ed->plus == spec.plus) {
- if (ed->cur_depth > 0) {
- error(ERR_NONFATAL, "`%s' ignored on active macro",
- pp_directives[i]);
- break;
- } else {
- *ed_p = ed->next;
- free_expdef(ed);
- }
+ mmac_p = (MMacro **) hash_findi(&mmacros, spec.name, NULL);
+ while (mmac_p && *mmac_p) {
+ mmac = *mmac_p;
+ if (mmac->casesense == spec.casesense &&
+ !mstrcmp(mmac->name, spec.name, spec.casesense) &&
+ mmac->nparam_min == spec.nparam_min &&
+ mmac->nparam_max == spec.nparam_max &&
+ mmac->plus == spec.plus) {
+ *mmac_p = mmac->next;
+ free_mmacro(mmac);
} else {
- ed_p = &ed->next;
+ mmac_p = &mmac->next;
}
}
free_tlist(origline);
}
case PP_ROTATE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
if (tline->next && tline->next->type == TOK_WHITESPACE)
tline = tline->next;
if (!tline->next) {
error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
return DIRECTIVE_FOUND;
}
- for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
- if (ei->type == EXP_MMACRO) {
- break;
- }
- }
- if (ei == NULL) {
+ mmac = istk->mstk;
+ while (mmac && !mmac->name) /* avoid mistaking %reps for macros */
+ mmac = mmac->next_active;
+ if (!mmac) {
error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
- } else if (ei->nparam == 0) {
+ } else if (mmac->nparam == 0) {
error(ERR_NONFATAL,
"`%%rotate' invoked within macro without parameters");
} else {
- int rotate = ei->rotate + reloc_value(evalresult);
+ int rotate = mmac->rotate + reloc_value(evalresult);
- rotate %= (int)ei->nparam;
+ rotate %= (int)mmac->nparam;
if (rotate < 0)
- rotate += ei->nparam;
- ei->rotate = rotate;
+ rotate += mmac->nparam;
+
+ mmac->rotate = rotate;
}
return DIRECTIVE_FOUND;
case PP_REP:
- if (defining != NULL) {
- if (defining->type == EXP_REP) {
- defining->def_depth ++;
- }
- return NO_DIRECTIVE_FOUND;
- }
nolist = false;
do {
tline = tline->next;
count = 0;
}
free_tlist(origline);
- ed = new_ExpDef(EXP_REP);
- ed->nolist = nolist;
- ed->def_depth = 0;
- ed->cur_depth = 1;
- ed->max_depth = (count - 1);
- ed->ignoring = false;
- ed->prev = defining;
- defining = ed;
+
+ tmp_defining = defining;
+ defining = nasm_malloc(sizeof(MMacro));
+ defining->prev = NULL;
+ defining->name = NULL; /* flags this macro as a %rep block */
+ defining->casesense = false;
+ defining->plus = false;
+ defining->nolist = nolist;
+ defining->in_progress = count;
+ defining->max_depth = 0;
+ defining->nparam_min = defining->nparam_max = 0;
+ defining->defaults = NULL;
+ defining->dlist = NULL;
+ defining->expansion = NULL;
+ defining->next_active = istk->mstk;
+ defining->rep_nest = tmp_defining;
return DIRECTIVE_FOUND;
case PP_ENDREP:
- if (defining != NULL) {
- if (defining->type == EXP_REP) {
- if (defining->def_depth > 0) {
- defining->def_depth --;
- return NO_DIRECTIVE_FOUND;
- }
- } else {
- return NO_DIRECTIVE_FOUND;
- }
- }
- if ((defining == NULL) || (defining->type != EXP_REP)) {
+ if (!defining || defining->name) {
error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
return DIRECTIVE_FOUND;
}
* continues) until the whole expansion is forcibly removed
* from istk->expansion by a %exitrep.
*/
- ed = defining;
- defining = ed->prev;
- ed->prev = expansions;
- expansions = ed;
- ei = new_ExpInv(EXP_REP, ed);
- ei->current = ed->line;
- ei->emitting = ((ed->max_depth > 0) ? true : false);
- list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
- ei->prev = istk->expansion;
- istk->expansion = ei;
+ l = nasm_malloc(sizeof(Line));
+ l->next = istk->expansion;
+ l->finishes = defining;
+ l->first = NULL;
+ istk->expansion = l;
+
+ istk->mstk = defining;
+
+ list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
+ tmp_defining = defining;
+ defining = defining->rep_nest;
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_EXITREP:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* We must search along istk->expansion until we hit a
- * rep invocation. Then we disable the emitting state(s)
- * between exitrep and endrep.
+ * macro-end marker for a macro with no name. Then we set
+ * its `in_progress' flag to 0.
*/
- for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
- if (ei->type == EXP_REP) {
+ list_for_each(l, istk->expansion)
+ if (l->finishes && !l->finishes->name)
break;
- }
- }
- if (ei != NULL) {
- /*
- * Set all invocations leading back to the rep
- * invocation to a non-emitting state.
- */
- for (eei = istk->expansion; eei != ei; eei = eei->prev) {
- eei->emitting = false;
- }
- eei->emitting = false;
- eei->current = NULL;
- eei->def->cur_depth = eei->def->max_depth;
- } else {
+ if (l)
+ l->finishes->in_progress = 1;
+ else
error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
- }
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_IXDEFINE:
case PP_DEFINE:
case PP_IDEFINE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFINE || i == PP_XDEFINE);
tline = tline->next;
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
param_start = tline = tline->next;
nparam = 0;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
-
- smacro_set_param_idx(tline, nparam);
- nparam++;
-
+ tline->type = TOK_SMAC_PARAM + nparam++;
tline = tline->next;
skip_white_(tline);
if (tok_is_(tline, ",")) {
while (t) {
if (t->type == TOK_ID) {
list_for_each(tt, param_start)
- if (is_smacro_param(tt) &&
+ if (tt->type >= TOK_SMAC_PARAM &&
!strcmp(tt->text, t->text))
t->type = tt->type;
}
return DIRECTIVE_FOUND;
case PP_UNDEF:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
}
/* Find the context that symbol belongs to */
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
undef_smacro(ctx, mname);
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_DEFSTR:
case PP_IDEFSTR:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFSTR);
tline = tline->next;
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
tline = delete_Token(tline);
p = detoken(tline, false);
- macro_start = nasm_zalloc(sizeof(*macro_start));
+ macro_start = nasm_malloc(sizeof(*macro_start));
+ macro_start->next = NULL;
macro_start->text = nasm_quote(p, strlen(p));
macro_start->type = TOK_STRING;
+ macro_start->a.mac = NULL;
nasm_free(p);
/*
case PP_DEFTOK:
case PP_IDEFTOK:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFTOK);
tline = tline->next;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
return DIRECTIVE_FOUND;
}
- /*
- * Convert the string to a token stream. Note that smacros
- * are stored with the token stream reversed, so we have to
- * reverse the output of tokenize().
- */
+ /*
+ * Convert the string to a token stream. Note that smacros
+ * are stored with the token stream reversed, so we have to
+ * reverse the output of tokenize().
+ */
nasm_unquote_cstr(t->text, i);
macro_start = reverse_tokens(tokenize(t->text));
return DIRECTIVE_FOUND;
case PP_PATHSEARCH:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
FILE *fp;
StrList *xsl = NULL;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
p = xsl->str;
fclose(fp); /* Don't actually care about the file */
}
- macro_start = nasm_zalloc(sizeof(*macro_start));
+ macro_start = nasm_malloc(sizeof(*macro_start));
+ macro_start->next = NULL;
macro_start->text = nasm_quote(p, strlen(p));
macro_start->type = TOK_STRING;
- nasm_free(xsl);
+ macro_start->a.mac = NULL;
+ if (xsl)
+ nasm_free(xsl);
/*
* We now have a macro name, an implicit parameter count of
}
case PP_STRLEN:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = true;
tline = tline->next;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
return DIRECTIVE_FOUND;
}
- macro_start = nasm_zalloc(sizeof(*macro_start));
+ macro_start = nasm_malloc(sizeof(*macro_start));
+ macro_start->next = NULL;
make_tok_num(macro_start, nasm_unquote(t->text, NULL));
+ macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
return DIRECTIVE_FOUND;
case PP_STRCAT:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = true;
tline = tline->next;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
return DIRECTIVE_FOUND;
case PP_SUBSTR:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
int64_t start, count;
size_t len;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
while (tok_type_(tt, TOK_WHITESPACE))
tt = tt->next;
if (!tt) {
- count = 1; /* Backwards compatibility: one character */
+ count = 1; /* Backwards compatibility: one character */
} else {
tokval.t_type = TOKEN_INVALID;
evalresult = evaluate(ppscan, tptr, &tokval, NULL,
}
len = nasm_unquote(t->text, NULL);
+
/* make start and count being in range */
if (start < 0)
start = 0;
if (!len || count < 0 || start >=(int64_t)len)
start = -1, count = 0; /* empty string */
- macro_start = nasm_zalloc(sizeof(*macro_start));
+ macro_start = nasm_malloc(sizeof(*macro_start));
+ macro_start->next = NULL;
macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
macro_start->type = TOK_STRING;
+ macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
case PP_ASSIGN:
case PP_IASSIGN:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_ASSIGN);
tline = tline->next;
free_tlist(origline);
return DIRECTIVE_FOUND;
}
- ctx = get_ctx(tline->text, &mname);
+ ctx = get_ctx(tline->text, &mname, false);
last = tline;
tline = expand_smacro(tline->next);
last->next = NULL;
return DIRECTIVE_FOUND;
}
- macro_start = nasm_zalloc(sizeof(*macro_start));
+ macro_start = nasm_malloc(sizeof(*macro_start));
+ macro_start->next = NULL;
make_tok_num(macro_start, reloc_value(evalresult));
+ macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
return DIRECTIVE_FOUND;
case PP_LINE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* Syntax is `%line nnn[+mmm] [filename]'
*/
free_tlist(origline);
return DIRECTIVE_FOUND;
- case PP_WHILE:
- if (defining != NULL) {
- if (defining->type == EXP_WHILE) {
- defining->def_depth ++;
- }
- return NO_DIRECTIVE_FOUND;
- }
- l = NULL;
- if ((istk->expansion != NULL) &&
- (istk->expansion->emitting == false)) {
- j = COND_NEVER;
- } else {
- l = new_Line();
- l->first = copy_Token(tline->next);
- j = if_condition(tline->next, i);
- tline->next = NULL; /* it got freed */
- j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
- }
- ed = new_ExpDef(EXP_WHILE);
- ed->state = j;
- ed->cur_depth = 1;
- ed->max_depth = DEADMAN_LIMIT;
- ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
- if (ed->ignoring == false) {
- ed->line = l;
- ed->last = l;
- } else if (l != NULL) {
- delete_Token(l->first);
- nasm_free(l);
- l = NULL;
- }
- ed->prev = defining;
- defining = ed;
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
- case PP_ENDWHILE:
- if (defining != NULL) {
- if (defining->type == EXP_WHILE) {
- if (defining->def_depth > 0) {
- defining->def_depth --;
- return NO_DIRECTIVE_FOUND;
- }
- } else {
- return NO_DIRECTIVE_FOUND;
- }
- }
- if (tline->next != NULL) {
- error_precond(ERR_WARNING|ERR_PASS1,
- "trailing garbage after `%%endwhile' ignored");
- }
- if ((defining == NULL) || (defining->type != EXP_WHILE)) {
- error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
- return DIRECTIVE_FOUND;
- }
- ed = defining;
- defining = ed->prev;
- if (ed->ignoring == false) {
- ed->prev = expansions;
- expansions = ed;
- ei = new_ExpInv(EXP_WHILE, ed);
- ei->current = ed->line->next;
- ei->emitting = true;
- ei->prev = istk->expansion;
- istk->expansion = ei;
- } else {
- nasm_free(ed);
- }
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
- case PP_EXITWHILE:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
- /*
- * We must search along istk->expansion until we hit a
- * while invocation. Then we disable the emitting state(s)
- * between exitwhile and endwhile.
- */
- for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
- if (ei->type == EXP_WHILE) {
- break;
- }
- }
-
- if (ei != NULL) {
- /*
- * Set all invocations leading back to the while
- * invocation to a non-emitting state.
- */
- for (eei = istk->expansion; eei != ei; eei = eei->prev) {
- eei->emitting = false;
- }
- eei->emitting = false;
- eei->current = NULL;
- eei->def->cur_depth = eei->def->max_depth;
- } else {
- error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
- }
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
- case PP_COMMENT:
- if (defining != NULL) {
- if (defining->type == EXP_COMMENT) {
- defining->def_depth ++;
- }
- return NO_DIRECTIVE_FOUND;
- }
- ed = new_ExpDef(EXP_COMMENT);
- ed->ignoring = true;
- ed->prev = defining;
- defining = ed;
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
- case PP_ENDCOMMENT:
- if (defining != NULL) {
- if (defining->type == EXP_COMMENT) {
- if (defining->def_depth > 0) {
- defining->def_depth --;
- return NO_DIRECTIVE_FOUND;
- }
- } else {
- return NO_DIRECTIVE_FOUND;
- }
- }
- if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
- error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
- return DIRECTIVE_FOUND;
- }
- ed = defining;
- defining = ed->prev;
- nasm_free(ed);
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
- case PP_FINAL:
- if (defining != NULL) return NO_DIRECTIVE_FOUND;
- if (in_final != false) {
- error(ERR_FATAL, "`%%final' cannot be used recursively");
- }
- tline = tline->next;
- skip_white_(tline);
- if (tline == NULL) {
- error(ERR_NONFATAL, "`%%final' expects at least one parameter");
- } else {
- l = new_Line();
- l->first = copy_Token(tline);
- l->next = finals;
- finals = l;
- }
- free_tlist(origline);
- return DIRECTIVE_FOUND;
-
default:
error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
char *tmp;
int i;
- nasm_dump_stream(*head);
- nasm_dump_token(*head);
-
/* Now handle token pasting... */
paste_head = NULL;
tail = head;
while (t && (t->type == TOK_WHITESPACE ||
t->type == TOK_PASTE))
t = *tail = delete_Token(t);
- if (!t) { /* Dangling %+ term */
- if (paste_head)
- (*paste_head)->next = NULL;
- else
- *head = NULL;
- return did_paste;
- }
+ if (!paste_head || !t)
+ break; /* Nothing to paste with */
tail = paste_head;
t = *tail;
tt = t->next;
char *tmp, *p;
while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
- len += strlen(tt->text);
- tt = tt->next;
+ len += strlen(tt->text);
+ tt = tt->next;
}
- nasm_dump_token(tt);
-
/*
* Now tt points to the first token after
* the potential paste area...
/*
* expands to a list of tokens from %{x:y}
*/
-static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
+static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last)
{
Token *t = tline, **tt, *tm, *head;
char *pos;
goto err;
/* the values should be sane */
- if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
- (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
+ if ((fst > (int)mac->nparam || fst < (-(int)mac->nparam)) ||
+ (lst > (int)mac->nparam || lst < (-(int)mac->nparam)))
goto err;
- fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
- lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
+ fst = fst < 0 ? fst + (int)mac->nparam + 1: fst;
+ lst = lst < 0 ? lst + (int)mac->nparam + 1: lst;
/* counted from zero */
fst--, lst--;
/*
* it will be at least one token
*/
- tm = ei->params[(fst + ei->rotate) % ei->nparam];
+ tm = mac->params[(fst + mac->rotate) % mac->nparam];
t = new_Token(NULL, tm->type, tm->text, 0);
head = t, tt = &t->next;
if (fst < lst) {
for (i = fst + 1; i <= lst; i++) {
t = new_Token(NULL, TOK_OTHER, ",", 0);
*tt = t, tt = &t->next;
- j = (i + ei->rotate) % ei->nparam;
- tm = ei->params[j];
+ j = (i + mac->rotate) % mac->nparam;
+ tm = mac->params[j];
t = new_Token(NULL, tm->type, tm->text, 0);
*tt = t, tt = &t->next;
}
for (i = fst - 1; i >= lst; i--) {
t = new_Token(NULL, TOK_OTHER, ",", 0);
*tt = t, tt = &t->next;
- j = (i + ei->rotate) % ei->nparam;
- tm = ei->params[j];
+ j = (i + mac->rotate) % mac->nparam;
+ tm = mac->params[j];
t = new_Token(NULL, tm->type, tm->text, 0);
*tt = t, tt = &t->next;
}
tail = &thead;
thead = NULL;
- nasm_dump_stream(tline);
-
while (tline) {
if (tline->type == TOK_PREPROC_ID &&
(((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
char tmpbuf[30];
unsigned int n;
int i;
- ExpInv *ei;
+ MMacro *mac;
t = tline;
tline = tline->next;
- for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
- if (ei->type == EXP_MMACRO) {
- break;
- }
- }
- if (ei == NULL) {
+ mac = istk->mstk;
+ while (mac && !mac->name) /* avoid mistaking %reps for macros */
+ mac = mac->next_active;
+ if (!mac) {
error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
} else {
pos = strchr(t->text, ':');
* forms %1, %-1, %+1, %%foo, %0.
*/
case '0':
- if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
- type = TOK_ID;
- text = nasm_strdup(ei->label_text);
- } else {
- type = TOK_NUMBER;
- snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
- text = nasm_strdup(tmpbuf);
- }
+ type = TOK_NUMBER;
+ snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam);
+ text = nasm_strdup(tmpbuf);
break;
case '%':
type = TOK_ID;
snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
- ei->unique);
+ mac->unique);
text = nasm_strcat(tmpbuf, t->text + 2);
break;
case '-':
n = atoi(t->text + 2) - 1;
- if (n >= ei->nparam)
+ if (n >= mac->nparam)
tt = NULL;
else {
- if (ei->nparam > 1)
- n = (n + ei->rotate) % ei->nparam;
- tt = ei->params[n];
+ if (mac->nparam > 1)
+ n = (n + mac->rotate) % mac->nparam;
+ tt = mac->params[n];
}
cc = find_cc(tt);
if (cc == -1) {
break;
case '+':
n = atoi(t->text + 2) - 1;
- if (n >= ei->nparam)
+ if (n >= mac->nparam)
tt = NULL;
else {
- if (ei->nparam > 1)
- n = (n + ei->rotate) % ei->nparam;
- tt = ei->params[n];
+ if (mac->nparam > 1)
+ n = (n + mac->rotate) % mac->nparam;
+ tt = mac->params[n];
}
cc = find_cc(tt);
if (cc == -1) {
break;
default:
n = atoi(t->text + 1) - 1;
- if (n >= ei->nparam)
+ if (n >= mac->nparam)
tt = NULL;
else {
- if (ei->nparam > 1)
- n = (n + ei->rotate) % ei->nparam;
- tt = ei->params[n];
+ if (mac->nparam > 1)
+ n = (n + mac->rotate) % mac->nparam;
+ tt = mac->params[n];
}
if (tt) {
- for (i = 0; i < ei->paramlen[n]; i++) {
+ for (i = 0; i < mac->paramlen[n]; i++) {
*tail = new_Token(NULL, tt->type, tt->text, 0);
tail = &(*tail)->next;
tt = tt->next;
* seems we have a parameters range here
*/
Token *head, **last;
- head = expand_mmac_params_range(ei, t, &last);
+ head = expand_mmac_params_range(mac, t, &last);
if (head != t) {
*tail = head;
*last = tline;
paste_tokens(&thead, t, ARRAY_SIZE(t), false);
}
- nasm_dump_token(thead);
-
return thead;
}
if (tline->type == TOK_ID) {
head = (SMacro *)hash_findix(&smacros, mname);
} else if (tline->type == TOK_PREPROC_ID) {
- ctx = get_ctx(mname, &mname);
+ ctx = get_ctx(mname, &mname, true);
head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
} else
head = NULL;
* all, then think about checking for parameters if
* necessary.
*/
- list_for_each(m, head) {
+ list_for_each(m, head)
if (!mstrcmp(m->name, mname, m->casesense))
break;
- }
if (m) {
mstart = tline;
params = NULL;
m->in_progress = true;
tline = tt;
list_for_each(t, m->expansion) {
- if (is_smacro_param(t)) {
+ if (t->type >= TOK_SMAC_PARAM) {
Token *pcopy = tline, **ptail = &pcopy;
- Token *ttt;
- int i, idx;
-
- idx = smacro_get_param_idx(t);
- ttt = params[idx];
-
- /*
- * We need smacro paramters appended.
- */
- for (i = paramsize[idx]; i > 0; i--) {
- *ptail = new_Token(tline, ttt->type, ttt->text, 0);
- ptail = &(*ptail)->next;
+ Token *ttt, *pt;
+ int i;
+
+ ttt = params[t->type - TOK_SMAC_PARAM];
+ i = paramsize[t->type - TOK_SMAC_PARAM];
+ while (--i >= 0) {
+ pt = *ptail = new_Token(tline, ttt->type,
+ ttt->text, 0);
+ ptail = &pt->next;
ttt = ttt->next;
}
-
tline = pcopy;
} else if (t->type == TOK_PREPROC_Q) {
tt = new_Token(tline, TOK_ID, mname, 0);
cur = tline;
while (cur->next &&
- (cur->next->type == TOK_ID ||
- cur->next->type == TOK_PREPROC_ID ||
- cur->next->type == TOK_NUMBER))
+ (cur->next->type == TOK_ID ||
+ cur->next->type == TOK_PREPROC_ID
+ || cur->next->type == TOK_NUMBER))
cur = cur->next;
/* If identifier consists of just one token, don't expand */
/*
* Determine whether the given line constitutes a multi-line macro
- * call, and return the ExpDef structure called if so. Doesn't have
+ * call, and return the MMacro structure called if so. Doesn't have
* to check for an initial label - that's taken care of in
* expand_mmacro - but must check numbers of parameters. Guaranteed
* to be called with tline->type == TOK_ID, so the putative macro
* name is easy to find.
*/
-static ExpDef *is_mmacro(Token * tline, Token *** params_array)
+static MMacro *is_mmacro(Token * tline, Token *** params_array)
{
- ExpDef *head, *ed;
+ MMacro *head, *m;
Token **params;
int nparam;
- head = (ExpDef *) hash_findix(&expdefs, tline->text);
+ head = (MMacro *) hash_findix(&mmacros, tline->text);
/*
* Efficiency: first we see if any macro exists with the given
* name. If not, we can return NULL immediately. _Then_ we
* count the parameters, and then we look further along the
- * list if necessary to find the proper ExpDef.
+ * list if necessary to find the proper MMacro.
*/
- list_for_each(ed, head) {
- if (!mstrcmp(ed->name, tline->text, ed->casesense))
+ list_for_each(m, head)
+ if (!mstrcmp(m->name, tline->text, m->casesense))
break;
- }
- if (!ed)
+ if (!m)
return NULL;
/*
count_mmac_params(tline->next, &nparam, ¶ms);
/*
- * So we know how many parameters we've got. Find the ExpDef
+ * So we know how many parameters we've got. Find the MMacro
* structure that handles this number.
*/
- while (ed) {
- if (ed->nparam_min <= nparam
- && (ed->plus || nparam <= ed->nparam_max)) {
+ while (m) {
+ if (m->nparam_min <= nparam
+ && (m->plus || nparam <= m->nparam_max)) {
+ /*
+ * This one is right. Just check if cycle removal
+ * prohibits us using it before we actually celebrate...
+ */
+ if (m->in_progress > m->max_depth) {
+ if (m->max_depth > 0) {
+ error(ERR_WARNING,
+ "reached maximum recursion depth of %i",
+ m->max_depth);
+ }
+ nasm_free(params);
+ return NULL;
+ }
/*
* It's right, and we can use it. Add its default
* parameters to the end of our list if necessary.
*/
- if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
+ if (m->defaults && nparam < m->nparam_min + m->ndefs) {
params =
nasm_realloc(params,
- ((ed->nparam_min + ed->ndefs +
+ ((m->nparam_min + m->ndefs +
1) * sizeof(*params)));
- while (nparam < ed->nparam_min + ed->ndefs) {
- params[nparam] = ed->defaults[nparam - ed->nparam_min];
+ while (nparam < m->nparam_min + m->ndefs) {
+ params[nparam] = m->defaults[nparam - m->nparam_min];
nparam++;
}
}
* we're in Plus mode), ignore parameters beyond
* nparam_max.
*/
- if (ed->plus && nparam > ed->nparam_max)
- nparam = ed->nparam_max;
+ if (m->plus && nparam > m->nparam_max)
+ nparam = m->nparam_max;
/*
* Then terminate the parameter list, and leave.
*/
}
params[nparam] = NULL;
*params_array = params;
- return ed;
+ return m;
}
/*
* This one wasn't right: look for the next one with the
* same name.
*/
- list_for_each(ed, ed->next) {
- if (!mstrcmp(ed->name, tline->text, ed->casesense))
+ list_for_each(m, m->next)
+ if (!mstrcmp(m->name, tline->text, m->casesense))
break;
- }
}
/*
return NULL;
}
+
+/*
+ * Save MMacro invocation specific fields in
+ * preparation for a recursive macro expansion
+ */
+static void push_mmacro(MMacro *m)
+{
+ MMacroInvocation *i;
+
+ i = nasm_malloc(sizeof(MMacroInvocation));
+ i->prev = m->prev;
+ i->params = m->params;
+ i->iline = m->iline;
+ i->nparam = m->nparam;
+ i->rotate = m->rotate;
+ i->paramlen = m->paramlen;
+ i->unique = m->unique;
+ i->condcnt = m->condcnt;
+ m->prev = i;
+}
+
+
+/*
+ * Restore MMacro invocation specific fields that were
+ * saved during a previous recursive macro expansion
+ */
+static void pop_mmacro(MMacro *m)
+{
+ MMacroInvocation *i;
+
+ if (m->prev) {
+ i = m->prev;
+ m->prev = i->prev;
+ m->params = i->params;
+ m->iline = i->iline;
+ m->nparam = i->nparam;
+ m->rotate = i->rotate;
+ m->paramlen = i->paramlen;
+ m->unique = i->unique;
+ m->condcnt = i->condcnt;
+ nasm_free(i);
+ }
+}
+
+
/*
* Expand the multi-line macro call made by the given line, if
* there is one to be expanded. If there is, push the expansion on
- * istk->expansion and return true. Otherwise return false.
+ * istk->expansion and return 1. Otherwise return 0.
*/
-static bool expand_mmacro(Token * tline)
+static int expand_mmacro(Token * tline)
{
+ Token *startline = tline;
Token *label = NULL;
int dont_prepend = 0;
- Token **params, *t;
- Line *l = NULL;
- ExpDef *ed;
- ExpInv *ei;
+ Token **params, *t, *tt;
+ MMacro *m;
+ Line *l, *ll;
int i, nparam, *paramlen;
const char *mname;
skip_white_(t);
/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
- return false;
- ed = is_mmacro(t, ¶ms);
- if (ed != NULL) {
+ return 0;
+ m = is_mmacro(t, ¶ms);
+ if (m) {
mname = t->text;
} else {
Token *last;
if (tok_type_(t, TOK_WHITESPACE))
last = t, t = t->next;
}
- if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, ¶ms)))
- return false;
+ if (!tok_type_(t, TOK_ID) || !(m = is_mmacro(t, ¶ms)))
+ return 0;
last->next = NULL;
mname = t->text;
tline = t;
* trailing whitespace, then stripping braces if they are
* present.
*/
- for (nparam = 0; params[nparam]; nparam++)
- ;
+ for (nparam = 0; params[nparam]; nparam++) ;
paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
for (i = 0; params[i]; i++) {
int brace = false;
- int comma = (!ed->plus || i < nparam - 1);
+ int comma = (!m->plus || i < nparam - 1);
t = params[i];
skip_white_(t);
}
}
- if (ed->cur_depth >= ed->max_depth) {
- if (ed->max_depth > 1) {
- error(ERR_WARNING,
- "reached maximum macro recursion depth of %i for %s",
- ed->max_depth,ed->name);
- }
- return false;
- } else {
- ed->cur_depth ++;
- }
-
/*
- * OK, we have found a ExpDef structure representing a
- * previously defined mmacro. Create an expansion invocation
- * and point it back to the expansion definition. Substitution of
+ * OK, we have a MMacro structure together with a set of
+ * parameters. We must now go through the expansion and push
+ * copies of each Line on to istk->expansion. Substitution of
* parameter tokens and macro-local tokens doesn't get done
* until the single-line macro substitution process; this is
* because delaying them allows us to change the semantics
* later through %rotate.
+ *
+ * First, push an end marker on to istk->expansion, mark this
+ * macro as in progress, and set up its invocation-specific
+ * variables.
*/
- ei = new_ExpInv(EXP_MMACRO, ed);
- ei->name = nasm_strdup(mname);
- //ei->label = label;
- //ei->label_text = detoken(label, false);
- ei->current = ed->line;
- ei->emitting = true;
- //ei->iline = tline;
- ei->params = params;
- ei->nparam = nparam;
- ei->rotate = 0;
- ei->paramlen = paramlen;
- ei->lineno = 0;
-
- ei->prev = istk->expansion;
- istk->expansion = ei;
+ ll = nasm_malloc(sizeof(Line));
+ ll->next = istk->expansion;
+ ll->finishes = m;
+ ll->first = NULL;
+ istk->expansion = ll;
/*
- * Special case: detect %00 on first invocation; if found,
- * avoid emitting any labels that precede the mmacro call.
- * ed->prepend is set to -1 when %00 is detected, else 1.
+ * Save the previous MMacro expansion in the case of
+ * macro recursion
*/
- if (ed->prepend == 0) {
- for (l = ed->line; l != NULL; l = l->next) {
- for (t = l->first; t != NULL; t = t->next) {
- if ((t->type == TOK_PREPROC_ID) &&
- (strlen(t->text) == 3) &&
- (t->text[1] == '0') && (t->text[2] == '0')) {
+ if (m->max_depth && m->in_progress)
+ push_mmacro(m);
+
+ m->in_progress ++;
+ m->params = params;
+ m->iline = tline;
+ m->nparam = nparam;
+ m->rotate = 0;
+ m->paramlen = paramlen;
+ m->unique = unique++;
+ m->lineno = 0;
+ m->condcnt = 0;
+
+ m->next_active = istk->mstk;
+ istk->mstk = m;
+
+ list_for_each(l, m->expansion) {
+ Token **tail;
+
+ ll = nasm_malloc(sizeof(Line));
+ ll->finishes = NULL;
+ ll->next = istk->expansion;
+ istk->expansion = ll;
+ tail = &ll->first;
+
+ list_for_each(t, l->first) {
+ Token *x = t;
+ switch (t->type) {
+ case TOK_PREPROC_Q:
+ tt = *tail = new_Token(NULL, TOK_ID, mname, 0);
+ break;
+ case TOK_PREPROC_QQ:
+ tt = *tail = new_Token(NULL, TOK_ID, m->name, 0);
+ break;
+ case TOK_PREPROC_ID:
+ if (t->text[1] == '0' && t->text[2] == '0') {
dont_prepend = -1;
- break;
+ x = label;
+ if (!x)
+ continue;
}
- }
- if (dont_prepend < 0)
+ /* fall through */
+ default:
+ tt = *tail = new_Token(NULL, x->type, x->text, 0);
break;
+ }
+ tail = &tt->next;
}
- ed->prepend = ((dont_prepend < 0) ? -1 : 1);
+ *tail = NULL;
}
/*
* If we had a label, push it on as the first line of
* the macro expansion.
*/
- if (label != NULL) {
- if (ed->prepend < 0) {
- ei->label_text = detoken(label, false);
- } else {
- if (dont_prepend == 0) {
- t = label;
- while (t->next != NULL) {
- t = t->next;
- }
- t->next = new_Token(NULL, TOK_OTHER, ":", 0);
+ if (label) {
+ if (dont_prepend < 0)
+ free_tlist(startline);
+ else {
+ ll = nasm_malloc(sizeof(Line));
+ ll->finishes = NULL;
+ ll->next = istk->expansion;
+ istk->expansion = ll;
+ ll->first = startline;
+ if (!dont_prepend) {
+ while (label->next)
+ label = label->next;
+ label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0);
}
- l = new_Line();
- l->first = copy_Token(label);
- l->next = ei->current;
- ei->current = l;
}
}
- list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
+ list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
- istk->mmac_depth++;
- return true;
+ return 1;
}
/* The function that actually does the error reporting */
static void verror(int severity, const char *fmt, va_list arg)
{
char buff[1024];
+ MMacro *mmac = NULL;
+ int delta = 0;
vsnprintf(buff, sizeof(buff), fmt, arg);
- if (istk && istk->mmac_depth > 0) {
- ExpInv *ei = istk->expansion;
- int lineno = ei->lineno;
- while (ei) {
- if (ei->type == EXP_MMACRO)
- break;
- lineno += ei->relno;
- ei = ei->prev;
- }
- nasm_error(severity, "(%s:%d) %s", ei->def->name,
- lineno, buff);
- } else {
- nasm_error(severity, "%s", buff);
+ /* get %macro name */
+ if (istk && istk->mstk) {
+ mmac = istk->mstk;
+ /* but %rep blocks should be skipped */
+ while (mmac && !mmac->name)
+ mmac = mmac->next_active, delta++;
}
+
+ if (mmac)
+ nasm_error(severity, "(%s:%d) %s",
+ mmac->name, mmac->lineno - delta, buff);
+ else
+ nasm_error(severity, "%s", buff);
}
/*
static void error(int severity, const char *fmt, ...)
{
va_list arg;
+
+ /* If we're in a dead branch of IF or something like it, ignore the error */
+ if (istk && istk->conds && !emitting(istk->conds->state))
+ return;
+
va_start(arg, fmt);
verror(severity, fmt, arg);
va_end(arg);
va_list arg;
/* Only ignore the error if it's really in a dead branch */
- if ((istk != NULL) &&
- (istk->expansion != NULL) &&
- (istk->expansion->type == EXP_IF) &&
- (istk->expansion->def->state == COND_NEVER))
+ if (istk && istk->conds && istk->conds->state == COND_NEVER)
return;
va_start(arg, fmt);
Token *t;
cstk = NULL;
- istk = nasm_zalloc(sizeof(Include));
+ istk = nasm_malloc(sizeof(Include));
+ istk->next = NULL;
+ istk->conds = NULL;
+ istk->expansion = NULL;
+ istk->mstk = NULL;
istk->fp = fopen(file, "r");
+ istk->fname = NULL;
src_set_fname(nasm_strdup(file));
src_set_linnum(0);
istk->lineinc = 1;
error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
file);
defining = NULL;
- finals = NULL;
- in_final = false;
nested_mac_count = 0;
nested_rep_count = 0;
init_macros();
unique = 0;
- if (tasm_compatible_mode)
+ if (tasm_compatible_mode) {
stdmacpos = nasm_stdmac;
- else
+ } else {
stdmacpos = nasm_stdmac_after_tasm;
+ }
any_extrastdmac = extrastdmac && *extrastdmac;
do_predef = true;
list = listgen;
* all the other builtins, because it is special -- it varies between
* passes.
*/
- t = nasm_zalloc(sizeof(*t));
+ t = nasm_malloc(sizeof(*t));
+ t->next = NULL;
make_tok_num(t, apass);
+ t->a.mac = NULL;
define_smacro(NULL, "__PASS__", true, 0, t);
}
{
char *line;
Token *tline;
- ExpDef *ed;
- ExpInv *ei;
- Line *l;
- int j;
while (1) {
/*
- * Fetch a tokenized line, either from the expansion
+ * Fetch a tokenized line, either from the macro-expansion
* buffer or from the input file.
*/
tline = NULL;
+ while (istk->expansion && istk->expansion->finishes) {
+ Line *l = istk->expansion;
+ if (!l->finishes->name && l->finishes->in_progress > 1) {
+ Line *ll;
- while (1) { /* until we get a line we can use */
- /*
- * Fetch a tokenized line from the expansion buffer
- */
- if (istk->expansion != NULL) {
- ei = istk->expansion;
- if (ei->current != NULL) {
- if (ei->emitting == false) {
- ei->current = NULL;
- continue;
- }
- l = ei->current;
- ei->current = l->next;
- ei->lineno++;
- tline = copy_Token(l->first);
- if (((ei->type == EXP_REP) ||
- (ei->type == EXP_MMACRO) ||
- (ei->type == EXP_WHILE))
- && (ei->def->nolist == false)) {
- char *p = detoken(tline, false);
- list->line(LIST_MACRO, p);
- nasm_free(p);
- }
- if (ei->linnum > -1) {
- src_set_linnum(src_get_linnum() + 1);
- }
- break;
- } else if ((ei->type == EXP_REP) &&
- (ei->def->cur_depth < ei->def->max_depth)) {
- ei->def->cur_depth ++;
- ei->current = ei->def->line;
- ei->lineno = 0;
- continue;
- } else if ((ei->type == EXP_WHILE) &&
- (ei->def->cur_depth < ei->def->max_depth)) {
- ei->current = ei->def->line;
- ei->lineno = 0;
- tline = copy_Token(ei->current->first);
- j = if_condition(tline, PP_WHILE);
- tline = NULL;
- j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
- if (j == COND_IF_TRUE) {
- ei->current = ei->current->next;
- ei->def->cur_depth ++;
- } else {
- ei->emitting = false;
- ei->current = NULL;
- ei->def->cur_depth = ei->def->max_depth;
- }
- continue;
- } else {
- istk->expansion = ei->prev;
- ed = ei->def;
- if (ed != NULL) {
- if ((ei->emitting == true) &&
- (ed->max_depth == DEADMAN_LIMIT) &&
- (ed->cur_depth == DEADMAN_LIMIT)
- ) {
- error(ERR_FATAL, "runaway expansion detected, aborting");
- }
- if (ed->cur_depth > 0) {
- ed->cur_depth --;
- } else if (ed->type != EXP_MMACRO) {
- expansions = ed->prev;
- free_expdef(ed);
- }
- if ((ei->type == EXP_REP) ||
- (ei->type == EXP_MMACRO) ||
- (ei->type == EXP_WHILE)) {
- list->downlevel(LIST_MACRO);
- if (ei->type == EXP_MMACRO) {
- istk->mmac_depth--;
- }
+ /*
+ * This is a macro-end marker for a macro with no
+ * name, which means it's not really a macro at all
+ * but a %rep block, and the `in_progress' field is
+ * more than 1, meaning that we still need to
+ * repeat. (1 means the natural last repetition; 0
+ * means termination by %exitrep.) We have
+ * therefore expanded up to the %endrep, and must
+ * push the whole block on to the expansion buffer
+ * again. We don't bother to remove the macro-end
+ * marker: we'd only have to generate another one
+ * if we did.
+ */
+ l->finishes->in_progress--;
+ list_for_each(l, l->finishes->expansion) {
+ Token *t, *tt, **tail;
+
+ ll = nasm_malloc(sizeof(Line));
+ ll->next = istk->expansion;
+ ll->finishes = NULL;
+ ll->first = NULL;
+ tail = &ll->first;
+
+ list_for_each(t, l->first) {
+ if (t->text || t->type == TOK_WHITESPACE) {
+ tt = *tail = new_Token(NULL, t->type, t->text, 0);
+ tail = &tt->next;
}
}
- if (ei->linnum > -1) {
- src_set_linnum(ei->linnum);
- }
- free_expinv(ei);
- continue;
+
+ istk->expansion = ll;
+ }
+ } else {
+ /*
+ * Check whether a `%rep' was started and not ended
+ * within this macro expansion. This can happen and
+ * should be detected. It's a fatal error because
+ * I'm too confused to work out how to recover
+ * sensibly from it.
+ */
+ if (defining) {
+ if (defining->name)
+ error(ERR_PANIC,
+ "defining with name in expansion");
+ else if (istk->mstk->name)
+ error(ERR_FATAL,
+ "`%%rep' without `%%endrep' within"
+ " expansion of macro `%s'",
+ istk->mstk->name);
}
+
+ /*
+ * FIXME: investigate the relationship at this point between
+ * istk->mstk and l->finishes
+ */
+ {
+ MMacro *m = istk->mstk;
+ istk->mstk = m->next_active;
+ if (m->name) {
+ /*
+ * This was a real macro call, not a %rep, and
+ * therefore the parameter information needs to
+ * be freed.
+ */
+ if (m->prev) {
+ pop_mmacro(m);
+ l->finishes->in_progress --;
+ } else {
+ nasm_free(m->params);
+ free_tlist(m->iline);
+ nasm_free(m->paramlen);
+ l->finishes->in_progress = 0;
+ }
+ } else
+ free_mmacro(m);
+ }
+ istk->expansion = l->next;
+ nasm_free(l);
+ list->downlevel(LIST_MACRO);
}
+ }
+ while (1) { /* until we get a line we can use */
- /*
- * Read in line from input and tokenize
- */
+ if (istk->expansion) { /* from a macro expansion */
+ char *p;
+ Line *l = istk->expansion;
+ if (istk->mstk)
+ istk->mstk->lineno++;
+ tline = l->first;
+ istk->expansion = l->next;
+ nasm_free(l);
+ p = detoken(tline, false);
+ list->line(LIST_MACRO, p);
+ nasm_free(p);
+ break;
+ }
line = read_line();
if (line) { /* from the current input file */
line = prepreproc(line);
nasm_free(line);
break;
}
-
/*
* The current file has ended; work down the istk
*/
{
Include *i = istk;
fclose(i->fp);
- if (i->expansion != NULL) {
- error(ERR_FATAL,
- "end of file while still in an expansion");
+ if (i->conds) {
+ /* nasm_error can't be conditionally suppressed */
+ nasm_error(ERR_FATAL,
+ "expected `%%endif' before end of file");
}
/* only set line and file name if there's a next node */
if (i->next) {
src_set_linnum(i->lineno);
nasm_free(src_set_fname(nasm_strdup(i->fname)));
}
- if ((i->next == NULL) && (finals != NULL)) {
- in_final = true;
- ei = new_ExpInv(EXP_FINAL, NULL);
- ei->emitting = true;
- ei->current = finals;
- istk->expansion = ei;
- finals = NULL;
- continue;
- }
istk = i->next;
list->downlevel(LIST_INCLUDE);
nasm_free(i);
- if (istk == NULL) {
- if (finals != NULL)
- in_final = true;
- else
- return NULL;
- }
- continue;
+ if (!istk)
+ return NULL;
+ if (istk->expansion && istk->expansion->finishes)
+ break;
}
}
- if (defining == NULL)
+ /*
+ * We must expand MMacro parameters and MMacro-local labels
+ * _before_ we plunge into directive processing, to cope
+ * with things like `%define something %1' such as STRUC
+ * uses. Unless we're _defining_ a MMacro, in which case
+ * those tokens should be left alone to go into the
+ * definition; and unless we're in a non-emitting
+ * condition, in which case we don't want to meddle with
+ * anything.
+ */
+ if (!defining && !(istk->conds && !emitting(istk->conds->state))
+ && !(istk->mstk && !istk->mstk->in_progress)) {
tline = expand_mmac_params(tline);
+ }
/*
* Check the line to see if it's a preprocessor directive.
*/
if (do_directive(tline) == DIRECTIVE_FOUND) {
continue;
- } else if (defining != NULL) {
+ } else if (defining) {
/*
- * We're defining an expansion. We emit nothing at all,
- * and just shove the tokenized line on to the definition.
+ * We're defining a multi-line macro. We emit nothing
+ * at all, and just
+ * shove the tokenized line on to the macro definition.
*/
- if (defining->ignoring == false) {
- Line *l = new_Line();
- l->first = tline;
- if (defining->line == NULL) {
- defining->line = l;
- defining->last = l;
- } else {
- defining->last->next = l;
- defining->last = l;
- }
- } else {
- free_tlist(tline);
- }
- defining->linecount++;
+ Line *l = nasm_malloc(sizeof(Line));
+ l->next = defining->expansion;
+ l->first = tline;
+ l->finishes = NULL;
+ defining->expansion = l;
continue;
- } else if ((istk->expansion != NULL) &&
- (istk->expansion->emitting != true)) {
+ } else if (istk->conds && !emitting(istk->conds->state)) {
/*
- * We're in a non-emitting branch of an expansion.
+ * We're in a non-emitting branch of a condition block.
* Emit nothing at all, not even a blank line: when we
- * emerge from the expansion we'll give a line-number
+ * emerge from the condition we'll give a line-number
* directive so we keep our place correctly.
*/
free_tlist(tline);
continue;
+ } else if (istk->mstk && !istk->mstk->in_progress) {
+ /*
+ * We're in a %rep block which has been terminated, so
+ * we're walking through to the %endrep without
+ * emitting anything. Emit nothing at all, not even a
+ * blank line: when we emerge from the %rep block we'll
+ * give a line-number directive so we keep our place
+ * correctly.
+ */
+ free_tlist(tline);
+ continue;
} else {
tline = expand_smacro(tline);
- if (expand_mmacro(tline) != true) {
+ if (!expand_mmacro(tline)) {
/*
* De-tokenize the line again, and emit it.
*/
free_tlist(tline);
break;
} else {
- continue;
+ continue; /* expand_mmacro calls free_tlist */
}
}
}
+
return line;
}
static void pp_cleanup(int pass)
{
- if (defining != NULL) {
- error(ERR_NONFATAL, "end of file while still defining an expansion");
- while (defining != NULL) {
- ExpDef *ed = defining;
- defining = ed->prev;
- free_expdef(ed);
+ if (defining) {
+ if (defining->name) {
+ error(ERR_NONFATAL,
+ "end of file while still defining macro `%s'",
+ defining->name);
+ } else {
+ error(ERR_NONFATAL, "end of file while still in %%rep");
}
+
+ free_mmacro(defining);
defining = NULL;
}
- while (cstk != NULL)
+ while (cstk)
ctx_pop();
free_macros();
- while (istk != NULL) {
+ while (istk) {
Include *i = istk;
istk = istk->next;
fclose(i->fp);
nasm_free(i->fname);
- while (i->expansion != NULL) {
- ExpInv *ei = i->expansion;
- i->expansion = ei->prev;
- free_expinv(ei);
- }
nasm_free(i);
}
while (cstk)
delete_Blocks();
while ((i = ipath)) {
ipath = i->next;
- nasm_free(i->path);
+ if (i->path)
+ nasm_free(i->path);
nasm_free(i);
}
}
void pp_include_path(char *path)
{
- IncPath *i = nasm_zalloc(sizeof(IncPath));
+ IncPath *i;
- if (path)
- i->path = nasm_strdup(path);
+ i = nasm_malloc(sizeof(IncPath));
+ i->path = path ? nasm_strdup(path) : NULL;
+ i->next = NULL;
if (ipath) {
IncPath *j = ipath;
space = new_Token(name, TOK_WHITESPACE, NULL, 0);
inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
- l = new_Line();
+ l = nasm_malloc(sizeof(Line));
l->next = predef;
l->first = inc;
+ l->finishes = NULL;
predef = l;
}
if (equals)
*equals = '=';
- l = new_Line();
+ l = nasm_malloc(sizeof(Line));
l->next = predef;
l->first = def;
+ l->finishes = NULL;
predef = l;
}
def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
space->next = tokenize(definition);
- l = new_Line();
+ l = nasm_malloc(sizeof(Line));
l->next = predef;
l->first = def;
+ l->finishes = NULL;
predef = l;
}
/*
+ * Added by Keith Kanios:
+ *
* This function is used to assist with "runtime" preprocessor
- * directives, e.g. pp_runtime("%define __BITS__ 64");
+ * directives. (e.g. pp_runtime("%define __BITS__ 64");)
*
* ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
* PASS A VALID STRING TO THIS FUNCTION!!!!!