insns: Add VPERMD instruction
[nasm/nasm.git] / preproc.c
blob0614400eb8a9c7378c6c706d1e407aaac90348b3
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2011 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * preproc.c macro preprocessor for the Netwide Assembler
38 /* Typical flow of text through preproc
40 * pp_getline gets tokenized lines, either
42 * from a macro expansion
44 * or
45 * {
46 * read_line gets raw text from stdmacpos, or predef, or current input file
47 * tokenize converts to tokens
48 * }
50 * expand_mmac_params is used to expand %1 etc., unless a macro is being
51 * defined or a false conditional is being processed
52 * (%0, %1, %+1, %-1, %%foo
54 * do_directive checks for directives
56 * expand_smacro is used to expand single line macros
58 * expand_mmacro is used to expand multi-line macros
60 * detoken is used to convert the line back to text
63 #include "compiler.h"
65 #include <stdio.h>
66 #include <stdarg.h>
67 #include <stdlib.h>
68 #include <stddef.h>
69 #include <string.h>
70 #include <ctype.h>
71 #include <limits.h>
72 #include <inttypes.h>
74 #include "nasm.h"
75 #include "nasmlib.h"
76 #include "preproc.h"
77 #include "hashtbl.h"
78 #include "quote.h"
79 #include "stdscan.h"
80 #include "eval.h"
81 #include "tokens.h"
82 #include "tables.h"
84 typedef struct SMacro SMacro;
85 typedef struct ExpDef ExpDef;
86 typedef struct ExpInv ExpInv;
87 typedef struct Context Context;
88 typedef struct Token Token;
89 typedef struct Blocks Blocks;
90 typedef struct Line Line;
91 typedef struct Include Include;
92 typedef struct Cond Cond;
93 typedef struct IncPath IncPath;
96 * Note on the storage of both SMacro and MMacros: the hash table
97 * indexes them case-insensitively, and we then have to go through a
98 * linked list of potential case aliases (and, for MMacros, parameter
99 * ranges); this is to preserve the matching semantics of the earlier
100 * code. If the number of case aliases for a specific macro is a
101 * performance issue, you may want to reconsider your coding style.
105 * Store the definition of a single-line macro.
107 struct SMacro {
108 SMacro *next;
109 char *name;
110 bool casesense;
111 bool in_progress;
112 unsigned int nparam;
113 Token *expansion;
117 * The context stack is composed of a linked list of these.
119 struct Context {
120 Context *next;
121 char *name;
122 struct hash_table localmac;
123 uint32_t number;
127 * This is the internal form which we break input lines up into.
128 * Typically stored in linked lists.
130 * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not
131 * necessarily used as-is, but is intended to denote the number of
132 * the substituted parameter. So in the definition
134 * %define a(x,y) ( (x) & ~(y) )
136 * the token representing `x' will have its type changed to
137 * TOK_SMAC_PARAM, but the one representing `y' will be
138 * TOK_SMAC_PARAM+1.
140 * TOK_INTERNAL_STRING is a dirty hack: it's a single string token
141 * which doesn't need quotes around it. Used in the pre-include
142 * mechanism as an alternative to trying to find a sensible type of
143 * quote to use on the filename we were passed.
145 enum pp_token_type {
146 TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT, TOK_ID,
147 TOK_PREPROC_ID, TOK_STRING,
148 TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
149 TOK_INTERNAL_STRING,
150 TOK_PREPROC_Q, TOK_PREPROC_QQ,
151 TOK_PASTE, /* %+ */
152 TOK_INDIRECT, /* %[...] */
153 TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */
154 TOK_MAX = INT_MAX /* Keep compiler from reducing the range */
157 #define PP_CONCAT_MASK(x) (1 << (x))
159 struct tokseq_match {
160 int mask_head;
161 int mask_tail;
164 struct Token {
165 Token *next;
166 char *text;
167 union {
168 SMacro *mac; /* associated macro for TOK_SMAC_END */
169 size_t len; /* scratch length field */
170 } a; /* Auxiliary data */
171 enum pp_token_type type;
175 * Expansion definitions are stored as a linked list of
176 * these, which is essentially a container to allow several linked
177 * lists of Tokens.
179 * Note that in this module, linked lists are treated as stacks
180 * wherever possible. For this reason, Lines are _pushed_ on to the
181 * `last' field in ExpDef structures, so that the linked list,
182 * if walked, would emit the expansion lines in the proper order.
184 struct Line {
185 Line *next;
186 Token *first;
190 * Expansion Types
192 enum pp_exp_type {
193 EXP_NONE = 0, EXP_PREDEF,
194 EXP_MMACRO, EXP_REP,
195 EXP_IF, EXP_WHILE,
196 EXP_COMMENT, EXP_FINAL,
197 EXP_MAX = INT_MAX /* Keep compiler from reducing the range */
201 * Store the definition of an expansion, in which is any
202 * preprocessor directive that has an ending pair.
204 * This design allows for arbitrary expansion/recursion depth,
205 * upto the DEADMAN_LIMIT.
207 * The `next' field is used for storing ExpDef in hash tables; the
208 * `prev' field is for the global `expansions` linked-list.
210 struct ExpDef {
211 ExpDef *prev; /* previous definition */
212 ExpDef *next; /* next in hash table */
213 enum pp_exp_type type; /* expansion type */
214 char *name; /* definition name */
215 int nparam_min, nparam_max;
216 bool casesense;
217 bool plus; /* is the last parameter greedy? */
218 bool nolist; /* is this expansion listing-inhibited? */
219 Token *dlist; /* all defaults as one list */
220 Token **defaults; /* parameter default pointers */
221 int ndefs; /* number of default parameters */
223 int prepend; /* label prepend state */
224 Line *label;
225 Line *line;
226 Line *last;
227 int linecount; /* number of lines within expansion */
229 int64_t def_depth; /* current number of definition pairs deep */
230 int64_t cur_depth; /* current number of expansions */
231 int64_t max_depth; /* maximum number of expansions allowed */
233 int state; /* condition state */
234 bool ignoring; /* ignoring definition lines */
238 * Store the invocation of an expansion.
240 * The `prev' field is for the `istk->expansion` linked-list.
242 * When an expansion is being expanded, `params', `iline', `nparam',
243 * `paramlen', `rotate' and `unique' are local to the invocation.
245 struct ExpInv {
246 ExpInv *prev; /* previous invocation */
247 enum pp_exp_type type; /* expansion type */
248 ExpDef *def; /* pointer to expansion definition */
249 char *name; /* invocation name */
250 Line *label; /* pointer to label */
251 char *label_text; /* pointer to label text */
252 Line *current; /* pointer to current line in invocation */
254 Token **params; /* actual parameters */
255 Token *iline; /* invocation line */
256 unsigned int nparam, rotate;
257 int *paramlen;
259 uint64_t unique;
260 bool emitting;
261 int lineno; /* current line number in expansion */
262 int linnum; /* line number at invocation */
263 int relno; /* relative line number at invocation */
267 * To handle an arbitrary level of file inclusion, we maintain a
268 * stack (ie linked list) of these things.
270 struct Include {
271 Include *next;
272 FILE *fp;
273 Cond *conds;
274 ExpInv *expansion;
275 char *fname;
276 int lineno, lineinc;
277 int mmac_depth;
281 * Include search path. This is simply a list of strings which get
282 * prepended, in turn, to the name of an include file, in an
283 * attempt to find the file if it's not in the current directory.
285 struct IncPath {
286 IncPath *next;
287 char *path;
291 * Conditional assembly: we maintain a separate stack of these for
292 * each level of file inclusion. (The only reason we keep the
293 * stacks separate is to ensure that a stray `%endif' in a file
294 * included from within the true branch of a `%if' won't terminate
295 * it and cause confusion: instead, rightly, it'll cause an error.)
297 enum {
299 * These states are for use just after %if or %elif: IF_TRUE
300 * means the condition has evaluated to truth so we are
301 * currently emitting, whereas IF_FALSE means we are not
302 * currently emitting but will start doing so if a %else comes
303 * up. In these states, all directives are admissible: %elif,
304 * %else and %endif. (And of course %if.)
306 COND_IF_TRUE, COND_IF_FALSE,
308 * These states come up after a %else: ELSE_TRUE means we're
309 * emitting, and ELSE_FALSE means we're not. In ELSE_* states,
310 * any %elif or %else will cause an error.
312 COND_ELSE_TRUE, COND_ELSE_FALSE,
314 * These states mean that we're not emitting now, and also that
315 * nothing until %endif will be emitted at all. COND_DONE is
316 * used when we've had our moment of emission
317 * and have now started seeing %elifs. COND_NEVER is used when
318 * the condition construct in question is contained within a
319 * non-emitting branch of a larger condition construct,
320 * or if there is an error.
322 COND_DONE, COND_NEVER
324 #define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE )
327 * These defines are used as the possible return values for do_directive
329 #define NO_DIRECTIVE_FOUND 0
330 #define DIRECTIVE_FOUND 1
333 * This define sets the upper limit for smacro and expansions
335 #define DEADMAN_LIMIT (1 << 20)
337 /* max reps */
338 #define REP_LIMIT ((INT64_C(1) << 62))
340 const struct tokseq_match pp_concat_match[] = {
342 PP_CONCAT_MASK(TOK_ID) |
343 PP_CONCAT_MASK(TOK_PREPROC_ID) |
344 PP_CONCAT_MASK(TOK_NUMBER) |
345 PP_CONCAT_MASK(TOK_FLOAT) |
346 PP_CONCAT_MASK(TOK_OTHER),
348 PP_CONCAT_MASK(TOK_ID) |
349 PP_CONCAT_MASK(TOK_PREPROC_ID) |
350 PP_CONCAT_MASK(TOK_NUMBER) |
351 PP_CONCAT_MASK(TOK_FLOAT) |
352 PP_CONCAT_MASK(TOK_OTHER)
357 * Condition codes. Note that we use c_ prefix not C_ because C_ is
358 * used in nasm.h for the "real" condition codes. At _this_ level,
359 * we treat CXZ and ECXZ as condition codes, albeit non-invertible
360 * ones, so we need a different enum...
362 static const char * const conditions[] = {
363 "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le",
364 "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no",
365 "np", "ns", "nz", "o", "p", "pe", "po", "rcxz", "s", "z"
367 enum pp_conds {
368 c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE,
369 c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO,
370 c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_RCXZ, c_S, c_Z,
371 c_none = -1
373 static const enum pp_conds inverse_ccs[] = {
374 c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE,
375 c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S,
376 c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
379 /* For TASM compatibility we need to be able to recognise TASM compatible
380 * conditional compilation directives. Using the NASM pre-processor does
381 * not work, so we look for them specifically from the following list and
382 * then jam in the equivalent NASM directive into the input stream.
385 enum {
386 TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
387 TM_IFNDEF, TM_INCLUDE, TM_LOCAL
390 static const char * const tasm_directives[] = {
391 "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi",
392 "ifndef", "include", "local"
395 static int StackSize = 4;
396 static char *StackPointer = "ebp";
397 static int ArgOffset = 8;
398 static int LocalOffset = 0;
400 static Context *cstk;
401 static Include *istk;
402 static IncPath *ipath = NULL;
404 static int pass; /* HACK: pass 0 = generate dependencies only */
405 static StrList **dephead, **deptail; /* Dependency list */
407 static uint64_t unique; /* unique identifier numbers */
409 static Line *predef = NULL;
410 static bool do_predef;
412 static ListGen *list;
415 * The current set of expansion definitions we have defined.
417 static struct hash_table expdefs;
420 * The current set of single-line macros we have defined.
422 static struct hash_table smacros;
425 * Linked List of all active expansion definitions
427 struct ExpDef *expansions = NULL;
430 * The expansion we are currently defining
432 static ExpDef *defining = NULL;
434 static uint64_t nested_mac_count;
435 static uint64_t nested_rep_count;
438 * Linked-list of lines to preprocess, prior to cleanup
440 static Line *finals = NULL;
441 static bool in_final = false;
444 * The number of macro parameters to allocate space for at a time.
446 #define PARAM_DELTA 16
449 * The standard macro set: defined in macros.c in the array nasm_stdmac.
450 * This gives our position in the macro set, when we're processing it.
452 static macros_t *stdmacpos;
455 * The extra standard macros that come from the object format, if
456 * any.
458 static macros_t *extrastdmac = NULL;
459 static bool any_extrastdmac;
462 * Tokens are allocated in blocks to improve speed
464 #define TOKEN_BLOCKSIZE 4096
465 static Token *freeTokens = NULL;
466 struct Blocks {
467 Blocks *next;
468 void *chunk;
471 static Blocks blocks = { NULL, NULL };
474 * Forward declarations.
476 static Token *expand_mmac_params(Token * tline);
477 static Token *expand_smacro(Token * tline);
478 static Token *expand_id(Token * tline);
479 static Context *get_ctx(const char *name, const char **namep,
480 bool all_contexts);
481 static void make_tok_num(Token * tok, int64_t val);
482 static void error(int severity, const char *fmt, ...);
483 static void error_precond(int severity, const char *fmt, ...);
484 static void *new_Block(size_t size);
485 static void delete_Blocks(void);
486 static Token *new_Token(Token * next, enum pp_token_type type,
487 const char *text, int txtlen);
488 static Token *copy_Token(Token * tline);
489 static Token *delete_Token(Token * t);
490 static Line *new_Line(void);
491 static ExpDef *new_ExpDef(int exp_type);
492 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
495 * Macros for safe checking of token pointers, avoid *(NULL)
497 #define tok_type_(x,t) ((x) && (x)->type == (t))
498 #define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
499 #define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
500 #define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
502 #ifdef NASM_TRACE
504 #define stringify(x) #x
506 #define nasm_trace(msg, ...) printf("(%s:%d): " msg "\n", __func__, __LINE__, __VA_ARGS__)
507 #define nasm_dump_token(t) nasm_raw_dump_token(t, __FILE__, __LINE__, __func__);
509 /* FIXME: we really need some compound type here instead of inplace code */
510 static const char *nasm_get_tok_type_str(enum pp_token_type type)
512 #define SWITCH_TOK_NAME(type) \
513 case (type): \
514 return stringify(type)
516 switch (type) {
517 SWITCH_TOK_NAME(TOK_NONE);
518 SWITCH_TOK_NAME(TOK_WHITESPACE);
519 SWITCH_TOK_NAME(TOK_COMMENT);
520 SWITCH_TOK_NAME(TOK_ID);
521 SWITCH_TOK_NAME(TOK_PREPROC_ID);
522 SWITCH_TOK_NAME(TOK_STRING);
523 SWITCH_TOK_NAME(TOK_NUMBER);
524 SWITCH_TOK_NAME(TOK_FLOAT);
525 SWITCH_TOK_NAME(TOK_SMAC_END);
526 SWITCH_TOK_NAME(TOK_OTHER);
527 SWITCH_TOK_NAME(TOK_INTERNAL_STRING);
528 SWITCH_TOK_NAME(TOK_PREPROC_Q);
529 SWITCH_TOK_NAME(TOK_PREPROC_QQ);
530 SWITCH_TOK_NAME(TOK_PASTE);
531 SWITCH_TOK_NAME(TOK_INDIRECT);
532 SWITCH_TOK_NAME(TOK_SMAC_PARAM);
533 SWITCH_TOK_NAME(TOK_MAX);
536 return NULL;
539 static void nasm_raw_dump_token(Token *token, const char *file, int line, const char *func)
541 printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
542 if (token) {
543 Token *t;
544 list_for_each(t, token) {
545 if (t->text)
546 printf("'%s'(%s) ", t->text,
547 nasm_get_tok_type_str(t->type));
549 printf("\n\n");
553 #else
554 #define nasm_trace(msg, ...)
555 #define nasm_dump_token(t)
556 #endif
559 * nasm_unquote with error if the string contains NUL characters.
560 * If the string contains NUL characters, issue an error and return
561 * the C len, i.e. truncate at the NUL.
563 static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
565 size_t len = nasm_unquote(qstr, NULL);
566 size_t clen = strlen(qstr);
568 if (len != clen)
569 error(ERR_NONFATAL, "NUL character in `%s' directive",
570 pp_directives[directive]);
572 return clen;
576 * In-place reverse a list of tokens.
578 static Token *reverse_tokens(Token *t)
580 Token *prev, *next;
582 list_reverse(t, prev, next);
584 return t;
588 * Handle TASM specific directives, which do not contain a % in
589 * front of them. We do it here because I could not find any other
590 * place to do it for the moment, and it is a hack (ideally it would
591 * be nice to be able to use the NASM pre-processor to do it).
593 static char *check_tasm_directive(char *line)
595 int32_t i, j, k, m, len;
596 char *p, *q, *oldline, oldchar;
598 p = nasm_skip_spaces(line);
600 /* Binary search for the directive name */
601 i = -1;
602 j = ARRAY_SIZE(tasm_directives);
603 q = nasm_skip_word(p);
604 len = q - p;
605 if (len) {
606 oldchar = p[len];
607 p[len] = 0;
608 while (j - i > 1) {
609 k = (j + i) / 2;
610 m = nasm_stricmp(p, tasm_directives[k]);
611 if (m == 0) {
612 /* We have found a directive, so jam a % in front of it
613 * so that NASM will then recognise it as one if it's own.
615 p[len] = oldchar;
616 len = strlen(p);
617 oldline = line;
618 line = nasm_malloc(len + 2);
619 line[0] = '%';
620 if (k == TM_IFDIFI) {
622 * NASM does not recognise IFDIFI, so we convert
623 * it to %if 0. This is not used in NASM
624 * compatible code, but does need to parse for the
625 * TASM macro package.
627 strcpy(line + 1, "if 0");
628 } else {
629 memcpy(line + 1, p, len + 1);
631 nasm_free(oldline);
632 return line;
633 } else if (m < 0) {
634 j = k;
635 } else
636 i = k;
638 p[len] = oldchar;
640 return line;
644 * The pre-preprocessing stage... This function translates line
645 * number indications as they emerge from GNU cpp (`# lineno "file"
646 * flags') into NASM preprocessor line number indications (`%line
647 * lineno file').
649 static char *prepreproc(char *line)
651 int lineno, fnlen;
652 char *fname, *oldline;
654 if (line[0] == '#' && line[1] == ' ') {
655 oldline = line;
656 fname = oldline + 2;
657 lineno = atoi(fname);
658 fname += strspn(fname, "0123456789 ");
659 if (*fname == '"')
660 fname++;
661 fnlen = strcspn(fname, "\"");
662 line = nasm_malloc(20 + fnlen);
663 snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
664 nasm_free(oldline);
666 if (tasm_compatible_mode)
667 return check_tasm_directive(line);
668 return line;
672 * Free a linked list of tokens.
674 static void free_tlist(Token * list)
676 while (list)
677 list = delete_Token(list);
681 * Free a linked list of lines.
683 static void free_llist(Line * list)
685 Line *l, *tmp;
686 list_for_each_safe(l, tmp, list) {
687 free_tlist(l->first);
688 nasm_free(l);
693 * Free an ExpDef
695 static void free_expdef(ExpDef * ed)
697 nasm_free(ed->name);
698 free_tlist(ed->dlist);
699 nasm_free(ed->defaults);
700 free_llist(ed->line);
701 nasm_free(ed);
705 * Free an ExpInv
707 static void free_expinv(ExpInv * ei)
709 if (ei->name != NULL)
710 nasm_free(ei->name);
711 if (ei->label_text != NULL)
712 nasm_free(ei->label_text);
713 nasm_free(ei);
717 * Free all currently defined macros, and free the hash tables
719 static void free_smacro_table(struct hash_table *smt)
721 SMacro *s, *tmp;
722 const char *key;
723 struct hash_tbl_node *it = NULL;
725 while ((s = hash_iterate(smt, &it, &key)) != NULL) {
726 nasm_free((void *)key);
727 list_for_each_safe(s, tmp, s) {
728 nasm_free(s->name);
729 free_tlist(s->expansion);
730 nasm_free(s);
733 hash_free(smt);
736 static void free_expdef_table(struct hash_table *edt)
738 ExpDef *ed, *tmp;
739 const char *key;
740 struct hash_tbl_node *it = NULL;
742 it = NULL;
743 while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
744 nasm_free((void *)key);
745 list_for_each_safe(ed ,tmp, ed)
746 free_expdef(ed);
748 hash_free(edt);
751 static void free_macros(void)
753 free_smacro_table(&smacros);
754 free_expdef_table(&expdefs);
758 * Initialize the hash tables
760 static void init_macros(void)
762 hash_init(&smacros, HASH_LARGE);
763 hash_init(&expdefs, HASH_LARGE);
767 * Pop the context stack.
769 static void ctx_pop(void)
771 Context *c = cstk;
773 cstk = cstk->next;
774 free_smacro_table(&c->localmac);
775 nasm_free(c->name);
776 nasm_free(c);
780 * Search for a key in the hash index; adding it if necessary
781 * (in which case we initialize the data pointer to NULL.)
783 static void **
784 hash_findi_add(struct hash_table *hash, const char *str)
786 struct hash_insert hi;
787 void **r;
788 char *strx;
790 r = hash_findi(hash, str, &hi);
791 if (r)
792 return r;
794 strx = nasm_strdup(str); /* Use a more efficient allocator here? */
795 return hash_add(&hi, strx, NULL);
799 * Like hash_findi, but returns the data element rather than a pointer
800 * to it. Used only when not adding a new element, hence no third
801 * argument.
803 static void *
804 hash_findix(struct hash_table *hash, const char *str)
806 void **p;
808 p = hash_findi(hash, str, NULL);
809 return p ? *p : NULL;
813 * read line from standard macros set,
814 * if there no more left -- return NULL
816 static char *line_from_stdmac(void)
818 unsigned char c;
819 const unsigned char *p = stdmacpos;
820 char *line, *q;
821 size_t len = 0;
823 if (!stdmacpos)
824 return NULL;
826 while ((c = *p++)) {
827 if (c >= 0x80)
828 len += pp_directives_len[c - 0x80] + 1;
829 else
830 len++;
833 line = nasm_malloc(len + 1);
834 q = line;
835 while ((c = *stdmacpos++)) {
836 if (c >= 0x80) {
837 memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]);
838 q += pp_directives_len[c - 0x80];
839 *q++ = ' ';
840 } else {
841 *q++ = c;
844 stdmacpos = p;
845 *q = '\0';
847 if (!*stdmacpos) {
848 /* This was the last of the standard macro chain... */
849 stdmacpos = NULL;
850 if (any_extrastdmac) {
851 stdmacpos = extrastdmac;
852 any_extrastdmac = false;
853 } else if (do_predef) {
854 ExpInv *ei;
855 Line *pd, *l;
856 Token *head, **tail, *t;
859 * Nasty hack: here we push the contents of
860 * `predef' on to the top-level expansion stack,
861 * since this is the most convenient way to
862 * implement the pre-include and pre-define
863 * features.
865 list_for_each(pd, predef) {
866 head = NULL;
867 tail = &head;
868 list_for_each(t, pd->first) {
869 *tail = new_Token(NULL, t->type, t->text, 0);
870 tail = &(*tail)->next;
873 l = new_Line();
874 l->first = head;
875 ei = new_ExpInv(EXP_PREDEF, NULL);
876 ei->current = l;
877 ei->emitting = true;
878 ei->prev = istk->expansion;
879 istk->expansion = ei;
881 do_predef = false;
885 return line;
888 #define BUF_DELTA 512
890 * Read a line from the top file in istk, handling multiple CR/LFs
891 * at the end of the line read, and handling spurious ^Zs. Will
892 * return lines from the standard macro set if this has not already
893 * been done.
895 static char *read_line(void)
897 char *buffer, *p, *q;
898 int bufsize, continued_count;
901 * standart macros set (predefined) goes first
903 p = line_from_stdmac();
904 if (p)
905 return p;
908 * regular read from a file
910 bufsize = BUF_DELTA;
911 buffer = nasm_malloc(BUF_DELTA);
912 p = buffer;
913 continued_count = 0;
914 while (1) {
915 q = fgets(p, bufsize - (p - buffer), istk->fp);
916 if (!q)
917 break;
918 p += strlen(p);
919 if (p > buffer && p[-1] == '\n') {
921 * Convert backslash-CRLF line continuation sequences into
922 * nothing at all (for DOS and Windows)
924 if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) {
925 p -= 3;
926 *p = 0;
927 continued_count++;
930 * Also convert backslash-LF line continuation sequences into
931 * nothing at all (for Unix)
933 else if (((p - 1) > buffer) && (p[-2] == '\\')) {
934 p -= 2;
935 *p = 0;
936 continued_count++;
937 } else {
938 break;
941 if (p - buffer > bufsize - 10) {
942 int32_t offset = p - buffer;
943 bufsize += BUF_DELTA;
944 buffer = nasm_realloc(buffer, bufsize);
945 p = buffer + offset; /* prevent stale-pointer problems */
949 if (!q && p == buffer) {
950 nasm_free(buffer);
951 return NULL;
954 src_set_linnum(src_get_linnum() + istk->lineinc +
955 (continued_count * istk->lineinc));
958 * Play safe: remove CRs as well as LFs, if any of either are
959 * present at the end of the line.
961 while (--p >= buffer && (*p == '\n' || *p == '\r'))
962 *p = '\0';
965 * Handle spurious ^Z, which may be inserted into source files
966 * by some file transfer utilities.
968 buffer[strcspn(buffer, "\032")] = '\0';
970 list->line(LIST_READ, buffer);
972 return buffer;
976 * Tokenize a line of text. This is a very simple process since we
977 * don't need to parse the value out of e.g. numeric tokens: we
978 * simply split one string into many.
980 static Token *tokenize(char *line)
982 char c, *p = line;
983 enum pp_token_type type;
984 Token *list = NULL;
985 Token *t, **tail = &list;
986 bool verbose = true;
988 nasm_trace("Tokenize for '%s'", line);
990 if ((defining != NULL) && (defining->ignoring == true)) {
991 verbose = false;
994 while (*line) {
995 p = line;
996 if (*p == '%') {
997 p++;
998 if (*p == '+' && !nasm_isdigit(p[1])) {
999 p++;
1000 type = TOK_PASTE;
1001 } else if (nasm_isdigit(*p) ||
1002 ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) {
1003 do {
1004 p++;
1006 while (nasm_isdigit(*p));
1007 type = TOK_PREPROC_ID;
1008 } else if (*p == '{') {
1009 p++;
1010 while (*p && *p != '}') {
1011 p[-1] = *p;
1012 p++;
1014 p[-1] = '\0';
1015 if (*p)
1016 p++;
1017 type = TOK_PREPROC_ID;
1018 } else if (*p == '[') {
1019 int lvl = 1;
1020 line += 2; /* Skip the leading %[ */
1021 p++;
1022 while (lvl && (c = *p++)) {
1023 switch (c) {
1024 case ']':
1025 lvl--;
1026 break;
1027 case '%':
1028 if (*p == '[')
1029 lvl++;
1030 break;
1031 case '\'':
1032 case '\"':
1033 case '`':
1034 p = nasm_skip_string(p - 1) + 1;
1035 break;
1036 default:
1037 break;
1040 p--;
1041 if (*p)
1042 *p++ = '\0';
1043 if (lvl && verbose)
1044 error(ERR_NONFATAL, "unterminated %[ construct");
1045 type = TOK_INDIRECT;
1046 } else if (*p == '?') {
1047 type = TOK_PREPROC_Q; /* %? */
1048 p++;
1049 if (*p == '?') {
1050 type = TOK_PREPROC_QQ; /* %?? */
1051 p++;
1053 } else if (*p == '!') {
1054 type = TOK_PREPROC_ID;
1055 p++;
1056 if (isidchar(*p)) {
1057 do {
1058 p++;
1059 } while (isidchar(*p));
1060 } else if (*p == '\'' || *p == '\"' || *p == '`') {
1061 p = nasm_skip_string(p);
1062 if (*p)
1063 p++;
1064 else if(verbose)
1065 error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
1066 } else {
1067 /* %! without string or identifier */
1068 type = TOK_OTHER; /* Legacy behavior... */
1070 } else if (isidchar(*p) ||
1071 ((*p == '!' || *p == '%' || *p == '$') &&
1072 isidchar(p[1]))) {
1073 do {
1074 p++;
1076 while (isidchar(*p));
1077 type = TOK_PREPROC_ID;
1078 } else {
1079 type = TOK_OTHER;
1080 if (*p == '%')
1081 p++;
1083 } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
1084 type = TOK_ID;
1085 p++;
1086 while (*p && isidchar(*p))
1087 p++;
1088 } else if (*p == '\'' || *p == '"' || *p == '`') {
1090 * A string token.
1092 type = TOK_STRING;
1093 p = nasm_skip_string(p);
1095 if (*p) {
1096 p++;
1097 } else if(verbose) {
1098 error(ERR_WARNING|ERR_PASS1, "unterminated string");
1099 /* Handling unterminated strings by UNV */
1100 /* type = -1; */
1102 } else if (p[0] == '$' && p[1] == '$') {
1103 type = TOK_OTHER; /* TOKEN_BASE */
1104 p += 2;
1105 } else if (isnumstart(*p)) {
1106 bool is_hex = false;
1107 bool is_float = false;
1108 bool has_e = false;
1109 char c, *r;
1112 * A numeric token.
1115 if (*p == '$') {
1116 p++;
1117 is_hex = true;
1120 for (;;) {
1121 c = *p++;
1123 if (!is_hex && (c == 'e' || c == 'E')) {
1124 has_e = true;
1125 if (*p == '+' || *p == '-') {
1127 * e can only be followed by +/- if it is either a
1128 * prefixed hex number or a floating-point number
1130 p++;
1131 is_float = true;
1133 } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
1134 is_hex = true;
1135 } else if (c == 'P' || c == 'p') {
1136 is_float = true;
1137 if (*p == '+' || *p == '-')
1138 p++;
1139 } else if (isnumchar(c) || c == '_')
1140 ; /* just advance */
1141 else if (c == '.') {
1143 * we need to deal with consequences of the legacy
1144 * parser, like "1.nolist" being two tokens
1145 * (TOK_NUMBER, TOK_ID) here; at least give it
1146 * a shot for now. In the future, we probably need
1147 * a flex-based scanner with proper pattern matching
1148 * to do it as well as it can be done. Nothing in
1149 * the world is going to help the person who wants
1150 * 0x123.p16 interpreted as two tokens, though.
1152 r = p;
1153 while (*r == '_')
1154 r++;
1156 if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
1157 (!is_hex && (*r == 'e' || *r == 'E')) ||
1158 (*r == 'p' || *r == 'P')) {
1159 p = r;
1160 is_float = true;
1161 } else
1162 break; /* Terminate the token */
1163 } else
1164 break;
1166 p--; /* Point to first character beyond number */
1168 if (p == line+1 && *line == '$') {
1169 type = TOK_OTHER; /* TOKEN_HERE */
1170 } else {
1171 if (has_e && !is_hex) {
1172 /* 1e13 is floating-point, but 1e13h is not */
1173 is_float = true;
1176 type = is_float ? TOK_FLOAT : TOK_NUMBER;
1178 } else if (nasm_isspace(*p)) {
1179 type = TOK_WHITESPACE;
1180 p = nasm_skip_spaces(p);
1182 * Whitespace just before end-of-line is discarded by
1183 * pretending it's a comment; whitespace just before a
1184 * comment gets lumped into the comment.
1186 if (!*p || *p == ';') {
1187 type = TOK_COMMENT;
1188 while (*p)
1189 p++;
1191 } else if (*p == ';') {
1192 type = TOK_COMMENT;
1193 while (*p)
1194 p++;
1195 } else {
1197 * Anything else is an operator of some kind. We check
1198 * for all the double-character operators (>>, <<, //,
1199 * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything
1200 * else is a single-character operator.
1202 type = TOK_OTHER;
1203 if ((p[0] == '>' && p[1] == '>') ||
1204 (p[0] == '<' && p[1] == '<') ||
1205 (p[0] == '/' && p[1] == '/') ||
1206 (p[0] == '<' && p[1] == '=') ||
1207 (p[0] == '>' && p[1] == '=') ||
1208 (p[0] == '=' && p[1] == '=') ||
1209 (p[0] == '!' && p[1] == '=') ||
1210 (p[0] == '<' && p[1] == '>') ||
1211 (p[0] == '&' && p[1] == '&') ||
1212 (p[0] == '|' && p[1] == '|') ||
1213 (p[0] == '^' && p[1] == '^')) {
1214 p++;
1216 p++;
1219 /* Handling unterminated string by UNV */
1220 /*if (type == -1)
1222 *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1);
1223 t->text[p-line] = *line;
1224 tail = &t->next;
1226 else */
1227 if (type != TOK_COMMENT) {
1228 *tail = t = new_Token(NULL, type, line, p - line);
1229 tail = &t->next;
1231 line = p;
1234 nasm_dump_token(list);
1236 return list;
1240 * this function allocates a new managed block of memory and
1241 * returns a pointer to the block. The managed blocks are
1242 * deleted only all at once by the delete_Blocks function.
1244 static void *new_Block(size_t size)
1246 Blocks *b = &blocks;
1248 /* first, get to the end of the linked list */
1249 while (b->next)
1250 b = b->next;
1252 /* now allocate the requested chunk */
1253 b->chunk = nasm_malloc(size);
1255 /* now allocate a new block for the next request */
1256 b->next = nasm_zalloc(sizeof(Blocks));
1258 return b->chunk;
1262 * this function deletes all managed blocks of memory
1264 static void delete_Blocks(void)
1266 Blocks *a, *b = &blocks;
1269 * keep in mind that the first block, pointed to by blocks
1270 * is a static and not dynamically allocated, so we don't
1271 * free it.
1273 while (b) {
1274 if (b->chunk)
1275 nasm_free(b->chunk);
1276 a = b;
1277 b = b->next;
1278 if (a != &blocks)
1279 nasm_free(a);
1284 * this function creates a new Token and passes a pointer to it
1285 * back to the caller. It sets the type and text elements, and
1286 * also the a.mac and next elements to NULL.
1288 static Token *new_Token(Token * next, enum pp_token_type type,
1289 const char *text, int txtlen)
1291 Token *t;
1292 int i;
1294 if (!freeTokens) {
1295 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1296 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1297 freeTokens[i].next = &freeTokens[i + 1];
1298 freeTokens[i].next = NULL;
1300 t = freeTokens;
1301 freeTokens = t->next;
1302 t->next = next;
1303 t->a.mac = NULL;
1304 t->type = type;
1305 if (type == TOK_WHITESPACE || !text) {
1306 t->text = NULL;
1307 } else {
1308 if (txtlen == 0)
1309 txtlen = strlen(text);
1310 t->text = nasm_malloc(txtlen+1);
1311 memcpy(t->text, text, txtlen);
1312 t->text[txtlen] = '\0';
1314 return t;
1317 static Token *copy_Token(Token * tline)
1319 Token *t, *tt, *first = NULL, *prev = NULL;
1320 int i;
1321 for (tt = tline; tt != NULL; tt = tt->next) {
1322 if (!freeTokens) {
1323 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1324 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1325 freeTokens[i].next = &freeTokens[i + 1];
1326 freeTokens[i].next = NULL;
1328 t = freeTokens;
1329 freeTokens = t->next;
1330 t->next = NULL;
1331 t->text = tt->text ? nasm_strdup(tt->text) : NULL;
1332 t->a.mac = tt->a.mac;
1333 t->a.len = tt->a.len;
1334 t->type = tt->type;
1335 if (prev != NULL) {
1336 prev->next = t;
1337 } else {
1338 first = t;
1340 prev = t;
1342 return first;
1345 static Token *delete_Token(Token * t)
1347 Token *next = t->next;
1348 nasm_free(t->text);
1349 t->next = freeTokens;
1350 freeTokens = t;
1351 return next;
1355 * Convert a line of tokens back into text.
1356 * If expand_locals is not zero, identifiers of the form "%$*xxx"
1357 * will be transformed into ..@ctxnum.xxx
1359 static char *detoken(Token * tlist, bool expand_locals)
1361 Token *t;
1362 char *line, *p;
1363 const char *q;
1364 int len = 0;
1366 list_for_each(t, tlist) {
1367 if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
1368 char *v;
1369 char *q = t->text;
1371 v = t->text + 2;
1372 if (*v == '\'' || *v == '\"' || *v == '`') {
1373 size_t len = nasm_unquote(v, NULL);
1374 size_t clen = strlen(v);
1376 if (len != clen) {
1377 error(ERR_NONFATAL | ERR_PASS1,
1378 "NUL character in %! string");
1379 v = NULL;
1383 if (v) {
1384 char *p = getenv(v);
1385 if (!p) {
1386 error(ERR_NONFATAL | ERR_PASS1,
1387 "nonexistent environment variable `%s'", v);
1388 p = "";
1390 t->text = nasm_strdup(p);
1392 nasm_free(q);
1395 /* Expand local macros here and not during preprocessing */
1396 if (expand_locals &&
1397 t->type == TOK_PREPROC_ID && t->text &&
1398 t->text[0] == '%' && t->text[1] == '$') {
1399 const char *q;
1400 char *p;
1401 Context *ctx = get_ctx(t->text, &q, false);
1402 if (ctx) {
1403 char buffer[40];
1404 snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
1405 p = nasm_strcat(buffer, q);
1406 nasm_free(t->text);
1407 t->text = p;
1411 /* Expand %? and %?? directives */
1412 if ((istk->expansion != NULL) &&
1413 ((t->type == TOK_PREPROC_Q) ||
1414 (t->type == TOK_PREPROC_QQ))) {
1415 ExpInv *ei;
1416 for (ei = istk->expansion; ei != NULL; ei = ei->prev){
1417 if (ei->type == EXP_MMACRO) {
1418 nasm_free(t->text);
1419 if (t->type == TOK_PREPROC_Q) {
1420 t->text = nasm_strdup(ei->name);
1421 } else {
1422 t->text = nasm_strdup(ei->def->name);
1424 break;
1429 if (t->type == TOK_WHITESPACE)
1430 len++;
1431 else if (t->text)
1432 len += strlen(t->text);
1435 p = line = nasm_malloc(len + 1);
1437 list_for_each(t, tlist) {
1438 if (t->type == TOK_WHITESPACE) {
1439 *p++ = ' ';
1440 } else if (t->text) {
1441 q = t->text;
1442 while (*q)
1443 *p++ = *q++;
1446 *p = '\0';
1448 return line;
1452 * Initialize a new Line
1454 static inline Line *new_Line(void)
1456 return (Line *)nasm_zalloc(sizeof(Line));
1461 * Initialize a new Expansion Definition
1463 static ExpDef *new_ExpDef(int exp_type)
1465 ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
1466 ed->type = exp_type;
1467 ed->casesense = true;
1468 ed->state = COND_NEVER;
1470 return ed;
1475 * Initialize a new Expansion Instance
1477 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
1479 ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
1480 ei->type = exp_type;
1481 ei->def = ed;
1482 ei->unique = ++unique;
1484 if ((istk->mmac_depth < 1) &&
1485 (istk->expansion == NULL) &&
1486 (ed != NULL) &&
1487 (ed->type != EXP_MMACRO) &&
1488 (ed->type != EXP_REP) &&
1489 (ed->type != EXP_WHILE)) {
1490 ei->linnum = src_get_linnum();
1491 src_set_linnum(ei->linnum - ed->linecount - 1);
1492 } else {
1493 ei->linnum = -1;
1495 if ((istk->expansion == NULL) ||
1496 (ei->type == EXP_MMACRO)) {
1497 ei->relno = 0;
1498 } else {
1499 ei->relno = istk->expansion->lineno;
1500 if (ed != NULL) {
1501 ei->relno -= (ed->linecount + 1);
1504 return ei;
1508 * A scanner, suitable for use by the expression evaluator, which
1509 * operates on a line of Tokens. Expects a pointer to a pointer to
1510 * the first token in the line to be passed in as its private_data
1511 * field.
1513 * FIX: This really needs to be unified with stdscan.
1515 static int ppscan(void *private_data, struct tokenval *tokval)
1517 Token **tlineptr = private_data;
1518 Token *tline;
1519 char ourcopy[MAX_KEYWORD+1], *p, *r, *s;
1521 do {
1522 tline = *tlineptr;
1523 *tlineptr = tline ? tline->next : NULL;
1524 } while (tline && (tline->type == TOK_WHITESPACE ||
1525 tline->type == TOK_COMMENT));
1527 if (!tline)
1528 return tokval->t_type = TOKEN_EOS;
1530 tokval->t_charptr = tline->text;
1532 if (tline->text[0] == '$' && !tline->text[1])
1533 return tokval->t_type = TOKEN_HERE;
1534 if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
1535 return tokval->t_type = TOKEN_BASE;
1537 if (tline->type == TOK_ID) {
1538 p = tokval->t_charptr = tline->text;
1539 if (p[0] == '$') {
1540 tokval->t_charptr++;
1541 return tokval->t_type = TOKEN_ID;
1544 for (r = p, s = ourcopy; *r; r++) {
1545 if (r >= p+MAX_KEYWORD)
1546 return tokval->t_type = TOKEN_ID; /* Not a keyword */
1547 *s++ = nasm_tolower(*r);
1549 *s = '\0';
1550 /* right, so we have an identifier sitting in temp storage. now,
1551 * is it actually a register or instruction name, or what? */
1552 return nasm_token_hash(ourcopy, tokval);
1555 if (tline->type == TOK_NUMBER) {
1556 bool rn_error;
1557 tokval->t_integer = readnum(tline->text, &rn_error);
1558 tokval->t_charptr = tline->text;
1559 if (rn_error)
1560 return tokval->t_type = TOKEN_ERRNUM;
1561 else
1562 return tokval->t_type = TOKEN_NUM;
1565 if (tline->type == TOK_FLOAT) {
1566 return tokval->t_type = TOKEN_FLOAT;
1569 if (tline->type == TOK_STRING) {
1570 char bq, *ep;
1572 bq = tline->text[0];
1573 tokval->t_charptr = tline->text;
1574 tokval->t_inttwo = nasm_unquote(tline->text, &ep);
1576 if (ep[0] != bq || ep[1] != '\0')
1577 return tokval->t_type = TOKEN_ERRSTR;
1578 else
1579 return tokval->t_type = TOKEN_STR;
1582 if (tline->type == TOK_OTHER) {
1583 if (!strcmp(tline->text, "<<"))
1584 return tokval->t_type = TOKEN_SHL;
1585 if (!strcmp(tline->text, ">>"))
1586 return tokval->t_type = TOKEN_SHR;
1587 if (!strcmp(tline->text, "//"))
1588 return tokval->t_type = TOKEN_SDIV;
1589 if (!strcmp(tline->text, "%%"))
1590 return tokval->t_type = TOKEN_SMOD;
1591 if (!strcmp(tline->text, "=="))
1592 return tokval->t_type = TOKEN_EQ;
1593 if (!strcmp(tline->text, "<>"))
1594 return tokval->t_type = TOKEN_NE;
1595 if (!strcmp(tline->text, "!="))
1596 return tokval->t_type = TOKEN_NE;
1597 if (!strcmp(tline->text, "<="))
1598 return tokval->t_type = TOKEN_LE;
1599 if (!strcmp(tline->text, ">="))
1600 return tokval->t_type = TOKEN_GE;
1601 if (!strcmp(tline->text, "&&"))
1602 return tokval->t_type = TOKEN_DBL_AND;
1603 if (!strcmp(tline->text, "^^"))
1604 return tokval->t_type = TOKEN_DBL_XOR;
1605 if (!strcmp(tline->text, "||"))
1606 return tokval->t_type = TOKEN_DBL_OR;
1610 * We have no other options: just return the first character of
1611 * the token text.
1613 return tokval->t_type = tline->text[0];
1617 * Compare a string to the name of an existing macro; this is a
1618 * simple wrapper which calls either strcmp or nasm_stricmp
1619 * depending on the value of the `casesense' parameter.
1621 static int mstrcmp(const char *p, const char *q, bool casesense)
1623 return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
1627 * Compare a string to the name of an existing macro; this is a
1628 * simple wrapper which calls either strcmp or nasm_stricmp
1629 * depending on the value of the `casesense' parameter.
1631 static int mmemcmp(const char *p, const char *q, size_t l, bool casesense)
1633 return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l);
1637 * Return the Context structure associated with a %$ token. Return
1638 * NULL, having _already_ reported an error condition, if the
1639 * context stack isn't deep enough for the supplied number of $
1640 * signs.
1641 * If all_contexts == true, contexts that enclose current are
1642 * also scanned for such smacro, until it is found; if not -
1643 * only the context that directly results from the number of $'s
1644 * in variable's name.
1646 * If "namep" is non-NULL, set it to the pointer to the macro name
1647 * tail, i.e. the part beyond %$...
1649 static Context *get_ctx(const char *name, const char **namep,
1650 bool all_contexts)
1652 Context *ctx;
1653 SMacro *m;
1654 int i;
1656 if (namep)
1657 *namep = name;
1659 if (!name || name[0] != '%' || name[1] != '$')
1660 return NULL;
1662 if (!cstk) {
1663 error(ERR_NONFATAL, "`%s': context stack is empty", name);
1664 return NULL;
1667 name += 2;
1668 ctx = cstk;
1669 i = 0;
1670 while (ctx && *name == '$') {
1671 name++;
1672 i++;
1673 ctx = ctx->next;
1675 if (!ctx) {
1676 error(ERR_NONFATAL, "`%s': context stack is only"
1677 " %d level%s deep", name, i, (i == 1 ? "" : "s"));
1678 return NULL;
1681 if (namep)
1682 *namep = name;
1684 if (!all_contexts)
1685 return ctx;
1687 do {
1688 /* Search for this smacro in found context */
1689 m = hash_findix(&ctx->localmac, name);
1690 while (m) {
1691 if (!mstrcmp(m->name, name, m->casesense))
1692 return ctx;
1693 m = m->next;
1695 ctx = ctx->next;
1697 while (ctx);
1698 return NULL;
1702 * Check to see if a file is already in a string list
1704 static bool in_list(const StrList *list, const char *str)
1706 while (list) {
1707 if (!strcmp(list->str, str))
1708 return true;
1709 list = list->next;
1711 return false;
1715 * Open an include file. This routine must always return a valid
1716 * file pointer if it returns - it's responsible for throwing an
1717 * ERR_FATAL and bombing out completely if not. It should also try
1718 * the include path one by one until it finds the file or reaches
1719 * the end of the path.
1721 static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
1722 bool missing_ok)
1724 FILE *fp;
1725 char *prefix = "";
1726 IncPath *ip = ipath;
1727 int len = strlen(file);
1728 size_t prefix_len = 0;
1729 StrList *sl;
1731 while (1) {
1732 sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
1733 sl->next = NULL;
1734 memcpy(sl->str, prefix, prefix_len);
1735 memcpy(sl->str+prefix_len, file, len+1);
1736 fp = fopen(sl->str, "r");
1737 if (fp && dhead && !in_list(*dhead, sl->str)) {
1738 **dtail = sl;
1739 *dtail = &sl->next;
1740 } else {
1741 nasm_free(sl);
1743 if (fp)
1744 return fp;
1745 if (!ip) {
1746 if (!missing_ok)
1747 break;
1748 prefix = NULL;
1749 } else {
1750 prefix = ip->path;
1751 ip = ip->next;
1753 if (prefix) {
1754 prefix_len = strlen(prefix);
1755 } else {
1756 /* -MG given and file not found */
1757 if (dhead && !in_list(*dhead, file)) {
1758 sl = nasm_malloc(len+1+sizeof sl->next);
1759 sl->next = NULL;
1760 strcpy(sl->str, file);
1761 **dtail = sl;
1762 *dtail = &sl->next;
1764 return NULL;
1768 error(ERR_FATAL, "unable to open include file `%s'", file);
1769 return NULL;
1773 * Determine if we should warn on defining a single-line macro of
1774 * name `name', with `nparam' parameters. If nparam is 0 or -1, will
1775 * return true if _any_ single-line macro of that name is defined.
1776 * Otherwise, will return true if a single-line macro with either
1777 * `nparam' or no parameters is defined.
1779 * If a macro with precisely the right number of parameters is
1780 * defined, or nparam is -1, the address of the definition structure
1781 * will be returned in `defn'; otherwise NULL will be returned. If `defn'
1782 * is NULL, no action will be taken regarding its contents, and no
1783 * error will occur.
1785 * Note that this is also called with nparam zero to resolve
1786 * `ifdef'.
1788 * If you already know which context macro belongs to, you can pass
1789 * the context pointer as first parameter; if you won't but name begins
1790 * with %$ the context will be automatically computed. If all_contexts
1791 * is true, macro will be searched in outer contexts as well.
1793 static bool
1794 smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
1795 bool nocase)
1797 struct hash_table *smtbl;
1798 SMacro *m;
1800 if (ctx) {
1801 smtbl = &ctx->localmac;
1802 } else if (name[0] == '%' && name[1] == '$') {
1803 if (cstk)
1804 ctx = get_ctx(name, &name, false);
1805 if (!ctx)
1806 return false; /* got to return _something_ */
1807 smtbl = &ctx->localmac;
1808 } else {
1809 smtbl = &smacros;
1811 m = (SMacro *) hash_findix(smtbl, name);
1813 while (m) {
1814 if (!mstrcmp(m->name, name, m->casesense && nocase) &&
1815 (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
1816 if (defn) {
1817 if (nparam == (int) m->nparam || nparam == -1)
1818 *defn = m;
1819 else
1820 *defn = NULL;
1822 return true;
1824 m = m->next;
1827 return false;
1831 * Count and mark off the parameters in a multi-line macro call.
1832 * This is called both from within the multi-line macro expansion
1833 * code, and also to mark off the default parameters when provided
1834 * in a %macro definition line.
1836 static void count_mmac_params(Token * t, int *nparam, Token *** params)
1838 int paramsize, brace;
1840 *nparam = paramsize = 0;
1841 *params = NULL;
1842 while (t) {
1843 /* +1: we need space for the final NULL */
1844 if (*nparam+1 >= paramsize) {
1845 paramsize += PARAM_DELTA;
1846 *params = nasm_realloc(*params, sizeof(**params) * paramsize);
1848 skip_white_(t);
1849 brace = false;
1850 if (tok_is_(t, "{"))
1851 brace = true;
1852 (*params)[(*nparam)++] = t;
1853 while (tok_isnt_(t, brace ? "}" : ","))
1854 t = t->next;
1855 if (t) { /* got a comma/brace */
1856 t = t->next;
1857 if (brace) {
1859 * Now we've found the closing brace, look further
1860 * for the comma.
1862 skip_white_(t);
1863 if (tok_isnt_(t, ",")) {
1864 error(ERR_NONFATAL,
1865 "braces do not enclose all of macro parameter");
1866 while (tok_isnt_(t, ","))
1867 t = t->next;
1869 if (t)
1870 t = t->next; /* eat the comma */
1877 * Determine whether one of the various `if' conditions is true or
1878 * not.
1880 * We must free the tline we get passed.
1882 static bool if_condition(Token * tline, enum preproc_token ct)
1884 enum pp_conditional i = PP_COND(ct);
1885 bool j;
1886 Token *t, *tt, **tptr, *origline;
1887 struct tokenval tokval;
1888 expr *evalresult;
1889 enum pp_token_type needtype;
1890 char *p;
1892 origline = tline;
1894 switch (i) {
1895 case PPC_IFCTX:
1896 j = false; /* have we matched yet? */
1897 while (true) {
1898 skip_white_(tline);
1899 if (!tline)
1900 break;
1901 if (tline->type != TOK_ID) {
1902 error(ERR_NONFATAL,
1903 "`%s' expects context identifiers", pp_directives[ct]);
1904 free_tlist(origline);
1905 return -1;
1907 if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
1908 j = true;
1909 tline = tline->next;
1911 break;
1913 case PPC_IFDEF:
1914 j = false; /* have we matched yet? */
1915 while (tline) {
1916 skip_white_(tline);
1917 if (!tline || (tline->type != TOK_ID &&
1918 (tline->type != TOK_PREPROC_ID ||
1919 tline->text[1] != '$'))) {
1920 error(ERR_NONFATAL,
1921 "`%s' expects macro identifiers", pp_directives[ct]);
1922 goto fail;
1924 if (smacro_defined(NULL, tline->text, 0, NULL, true))
1925 j = true;
1926 tline = tline->next;
1928 break;
1930 case PPC_IFENV:
1931 tline = expand_smacro(tline);
1932 j = false; /* have we matched yet? */
1933 while (tline) {
1934 skip_white_(tline);
1935 if (!tline || (tline->type != TOK_ID &&
1936 tline->type != TOK_STRING &&
1937 (tline->type != TOK_PREPROC_ID ||
1938 tline->text[1] != '!'))) {
1939 error(ERR_NONFATAL,
1940 "`%s' expects environment variable names",
1941 pp_directives[ct]);
1942 goto fail;
1944 p = tline->text;
1945 if (tline->type == TOK_PREPROC_ID)
1946 p += 2; /* Skip leading %! */
1947 if (*p == '\'' || *p == '\"' || *p == '`')
1948 nasm_unquote_cstr(p, ct);
1949 if (getenv(p))
1950 j = true;
1951 tline = tline->next;
1953 break;
1955 case PPC_IFIDN:
1956 case PPC_IFIDNI:
1957 tline = expand_smacro(tline);
1958 t = tt = tline;
1959 while (tok_isnt_(tt, ","))
1960 tt = tt->next;
1961 if (!tt) {
1962 error(ERR_NONFATAL,
1963 "`%s' expects two comma-separated arguments",
1964 pp_directives[ct]);
1965 goto fail;
1967 tt = tt->next;
1968 j = true; /* assume equality unless proved not */
1969 while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
1970 if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
1971 error(ERR_NONFATAL, "`%s': more than one comma on line",
1972 pp_directives[ct]);
1973 goto fail;
1975 if (t->type == TOK_WHITESPACE) {
1976 t = t->next;
1977 continue;
1979 if (tt->type == TOK_WHITESPACE) {
1980 tt = tt->next;
1981 continue;
1983 if (tt->type != t->type) {
1984 j = false; /* found mismatching tokens */
1985 break;
1987 /* When comparing strings, need to unquote them first */
1988 if (t->type == TOK_STRING) {
1989 size_t l1 = nasm_unquote(t->text, NULL);
1990 size_t l2 = nasm_unquote(tt->text, NULL);
1992 if (l1 != l2) {
1993 j = false;
1994 break;
1996 if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
1997 j = false;
1998 break;
2000 } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
2001 j = false; /* found mismatching tokens */
2002 break;
2005 t = t->next;
2006 tt = tt->next;
2008 if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
2009 j = false; /* trailing gunk on one end or other */
2010 break;
2012 case PPC_IFMACRO:
2014 bool found = false;
2015 ExpDef searching, *ed;
2017 skip_white_(tline);
2018 tline = expand_id(tline);
2019 if (!tok_type_(tline, TOK_ID)) {
2020 error(ERR_NONFATAL,
2021 "`%s' expects a macro name", pp_directives[ct]);
2022 goto fail;
2024 memset(&searching, 0, sizeof(searching));
2025 searching.name = nasm_strdup(tline->text);
2026 searching.casesense = true;
2027 searching.nparam_max = INT_MAX;
2028 tline = expand_smacro(tline->next);
2029 skip_white_(tline);
2030 if (!tline) {
2031 } else if (!tok_type_(tline, TOK_NUMBER)) {
2032 error(ERR_NONFATAL,
2033 "`%s' expects a parameter count or nothing",
2034 pp_directives[ct]);
2035 } else {
2036 searching.nparam_min = searching.nparam_max =
2037 readnum(tline->text, &j);
2038 if (j)
2039 error(ERR_NONFATAL,
2040 "unable to parse parameter count `%s'",
2041 tline->text);
2043 if (tline && tok_is_(tline->next, "-")) {
2044 tline = tline->next->next;
2045 if (tok_is_(tline, "*"))
2046 searching.nparam_max = INT_MAX;
2047 else if (!tok_type_(tline, TOK_NUMBER))
2048 error(ERR_NONFATAL,
2049 "`%s' expects a parameter count after `-'",
2050 pp_directives[ct]);
2051 else {
2052 searching.nparam_max = readnum(tline->text, &j);
2053 if (j)
2054 error(ERR_NONFATAL,
2055 "unable to parse parameter count `%s'",
2056 tline->text);
2057 if (searching.nparam_min > searching.nparam_max)
2058 error(ERR_NONFATAL,
2059 "minimum parameter count exceeds maximum");
2062 if (tline && tok_is_(tline->next, "+")) {
2063 tline = tline->next;
2064 searching.plus = true;
2066 ed = (ExpDef *) hash_findix(&expdefs, searching.name);
2067 while (ed != NULL) {
2068 if (!strcmp(ed->name, searching.name) &&
2069 (ed->nparam_min <= searching.nparam_max || searching.plus) &&
2070 (searching.nparam_min <= ed->nparam_max || ed->plus)) {
2071 found = true;
2072 break;
2074 ed = ed->next;
2076 if (tline && tline->next)
2077 error(ERR_WARNING|ERR_PASS1,
2078 "trailing garbage after %%ifmacro ignored");
2079 nasm_free(searching.name);
2080 j = found;
2081 break;
2084 case PPC_IFID:
2085 needtype = TOK_ID;
2086 goto iftype;
2087 case PPC_IFNUM:
2088 needtype = TOK_NUMBER;
2089 goto iftype;
2090 case PPC_IFSTR:
2091 needtype = TOK_STRING;
2092 goto iftype;
2094 iftype:
2095 t = tline = expand_smacro(tline);
2097 while (tok_type_(t, TOK_WHITESPACE) ||
2098 (needtype == TOK_NUMBER &&
2099 tok_type_(t, TOK_OTHER) &&
2100 (t->text[0] == '-' || t->text[0] == '+') &&
2101 !t->text[1]))
2102 t = t->next;
2104 j = tok_type_(t, needtype);
2105 break;
2107 case PPC_IFTOKEN:
2108 t = tline = expand_smacro(tline);
2109 while (tok_type_(t, TOK_WHITESPACE))
2110 t = t->next;
2112 j = false;
2113 if (t) {
2114 t = t->next; /* Skip the actual token */
2115 while (tok_type_(t, TOK_WHITESPACE))
2116 t = t->next;
2117 j = !t; /* Should be nothing left */
2119 break;
2121 case PPC_IFEMPTY:
2122 t = tline = expand_smacro(tline);
2123 while (tok_type_(t, TOK_WHITESPACE))
2124 t = t->next;
2126 j = !t; /* Should be empty */
2127 break;
2129 case PPC_IF:
2130 t = tline = expand_smacro(tline);
2131 tptr = &t;
2132 tokval.t_type = TOKEN_INVALID;
2133 evalresult = evaluate(ppscan, tptr, &tokval,
2134 NULL, pass | CRITICAL, error, NULL);
2135 if (!evalresult)
2136 return -1;
2137 if (tokval.t_type)
2138 error(ERR_WARNING|ERR_PASS1,
2139 "trailing garbage after expression ignored");
2140 if (!is_simple(evalresult)) {
2141 error(ERR_NONFATAL,
2142 "non-constant value given to `%s'", pp_directives[ct]);
2143 goto fail;
2145 j = reloc_value(evalresult) != 0;
2146 break;
2148 default:
2149 error(ERR_FATAL,
2150 "preprocessor directive `%s' not yet implemented",
2151 pp_directives[ct]);
2152 goto fail;
2155 free_tlist(origline);
2156 return j ^ PP_NEGATIVE(ct);
2158 fail:
2159 free_tlist(origline);
2160 return -1;
2164 * Common code for defining an smacro
2166 static bool define_smacro(Context *ctx, const char *mname, bool casesense,
2167 int nparam, Token *expansion)
2169 SMacro *smac, **smhead;
2170 struct hash_table *smtbl;
2172 if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
2173 if (!smac) {
2174 error(ERR_WARNING|ERR_PASS1,
2175 "single-line macro `%s' defined both with and"
2176 " without parameters", mname);
2178 * Some instances of the old code considered this a failure,
2179 * some others didn't. What is the right thing to do here?
2181 free_tlist(expansion);
2182 return false; /* Failure */
2183 } else {
2185 * We're redefining, so we have to take over an
2186 * existing SMacro structure. This means freeing
2187 * what was already in it.
2189 nasm_free(smac->name);
2190 free_tlist(smac->expansion);
2192 } else {
2193 smtbl = ctx ? &ctx->localmac : &smacros;
2194 smhead = (SMacro **) hash_findi_add(smtbl, mname);
2195 smac = nasm_zalloc(sizeof(SMacro));
2196 smac->next = *smhead;
2197 *smhead = smac;
2199 smac->name = nasm_strdup(mname);
2200 smac->casesense = casesense;
2201 smac->nparam = nparam;
2202 smac->expansion = expansion;
2203 smac->in_progress = false;
2204 return true; /* Success */
2208 * Undefine an smacro
2210 static void undef_smacro(Context *ctx, const char *mname)
2212 SMacro **smhead, *s, **sp;
2213 struct hash_table *smtbl;
2215 smtbl = ctx ? &ctx->localmac : &smacros;
2216 smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
2218 if (smhead) {
2220 * We now have a macro name... go hunt for it.
2222 sp = smhead;
2223 while ((s = *sp) != NULL) {
2224 if (!mstrcmp(s->name, mname, s->casesense)) {
2225 *sp = s->next;
2226 nasm_free(s->name);
2227 free_tlist(s->expansion);
2228 nasm_free(s);
2229 } else {
2230 sp = &s->next;
2237 * Parse a mmacro specification.
2239 static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
2241 bool err;
2243 tline = tline->next;
2244 skip_white_(tline);
2245 tline = expand_id(tline);
2246 if (!tok_type_(tline, TOK_ID)) {
2247 error(ERR_NONFATAL, "`%s' expects a macro name", directive);
2248 return false;
2251 def->name = nasm_strdup(tline->text);
2252 def->plus = false;
2253 def->nolist = false;
2254 // def->in_progress = 0;
2255 // def->rep_nest = NULL;
2256 def->nparam_min = 0;
2257 def->nparam_max = 0;
2259 tline = expand_smacro(tline->next);
2260 skip_white_(tline);
2261 if (!tok_type_(tline, TOK_NUMBER)) {
2262 error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
2263 } else {
2264 def->nparam_min = def->nparam_max =
2265 readnum(tline->text, &err);
2266 if (err)
2267 error(ERR_NONFATAL,
2268 "unable to parse parameter count `%s'", tline->text);
2270 if (tline && tok_is_(tline->next, "-")) {
2271 tline = tline->next->next;
2272 if (tok_is_(tline, "*")) {
2273 def->nparam_max = INT_MAX;
2274 } else if (!tok_type_(tline, TOK_NUMBER)) {
2275 error(ERR_NONFATAL,
2276 "`%s' expects a parameter count after `-'", directive);
2277 } else {
2278 def->nparam_max = readnum(tline->text, &err);
2279 if (err) {
2280 error(ERR_NONFATAL, "unable to parse parameter count `%s'",
2281 tline->text);
2283 if (def->nparam_min > def->nparam_max) {
2284 error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
2288 if (tline && tok_is_(tline->next, "+")) {
2289 tline = tline->next;
2290 def->plus = true;
2292 if (tline && tok_type_(tline->next, TOK_ID) &&
2293 !nasm_stricmp(tline->next->text, ".nolist")) {
2294 tline = tline->next;
2295 def->nolist = true;
2299 * Handle default parameters.
2301 if (tline && tline->next) {
2302 def->dlist = tline->next;
2303 tline->next = NULL;
2304 count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
2305 } else {
2306 def->dlist = NULL;
2307 def->defaults = NULL;
2309 def->line = NULL;
2311 if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
2312 !def->plus)
2313 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
2314 "too many default macro parameters");
2316 return true;
2321 * Decode a size directive
2323 static int parse_size(const char *str) {
2324 static const char *size_names[] =
2325 { "byte", "dword", "oword", "qword", "tword", "word", "yword" };
2326 static const int sizes[] =
2327 { 0, 1, 4, 16, 8, 10, 2, 32 };
2329 return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
2333 * find and process preprocessor directive in passed line
2334 * Find out if a line contains a preprocessor directive, and deal
2335 * with it if so.
2337 * If a directive _is_ found, it is the responsibility of this routine
2338 * (and not the caller) to free_tlist() the line.
2340 * @param tline a pointer to the current tokeninzed line linked list
2341 * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
2344 static int do_directive(Token * tline)
2346 enum preproc_token i;
2347 int j;
2348 bool err;
2349 int nparam;
2350 bool nolist;
2351 bool casesense;
2352 int k, m;
2353 int offset;
2354 char *p, *pp;
2355 const char *mname;
2356 Include *inc;
2357 Context *ctx;
2358 Line *l;
2359 Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
2360 struct tokenval tokval;
2361 expr *evalresult;
2362 ExpDef *ed, *eed, **edhead;
2363 ExpInv *ei, *eei;
2364 int64_t count;
2365 size_t len;
2366 int severity;
2368 origline = tline;
2370 skip_white_(tline);
2371 if (!tline || !tok_type_(tline, TOK_PREPROC_ID) ||
2372 (tline->text[1] == '%' || tline->text[1] == '$'
2373 || tline->text[1] == '!'))
2374 return NO_DIRECTIVE_FOUND;
2376 i = pp_token_hash(tline->text);
2378 switch (i) {
2379 case PP_INVALID:
2380 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2381 error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
2382 tline->text);
2383 return NO_DIRECTIVE_FOUND; /* didn't get it */
2385 case PP_STACKSIZE:
2386 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2387 /* Directive to tell NASM what the default stack size is. The
2388 * default is for a 16-bit stack, and this can be overriden with
2389 * %stacksize large.
2391 tline = tline->next;
2392 if (tline && tline->type == TOK_WHITESPACE)
2393 tline = tline->next;
2394 if (!tline || tline->type != TOK_ID) {
2395 error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
2396 free_tlist(origline);
2397 return DIRECTIVE_FOUND;
2399 if (nasm_stricmp(tline->text, "flat") == 0) {
2400 /* All subsequent ARG directives are for a 32-bit stack */
2401 StackSize = 4;
2402 StackPointer = "ebp";
2403 ArgOffset = 8;
2404 LocalOffset = 0;
2405 } else if (nasm_stricmp(tline->text, "flat64") == 0) {
2406 /* All subsequent ARG directives are for a 64-bit stack */
2407 StackSize = 8;
2408 StackPointer = "rbp";
2409 ArgOffset = 16;
2410 LocalOffset = 0;
2411 } else if (nasm_stricmp(tline->text, "large") == 0) {
2412 /* All subsequent ARG directives are for a 16-bit stack,
2413 * far function call.
2415 StackSize = 2;
2416 StackPointer = "bp";
2417 ArgOffset = 4;
2418 LocalOffset = 0;
2419 } else if (nasm_stricmp(tline->text, "small") == 0) {
2420 /* All subsequent ARG directives are for a 16-bit stack,
2421 * far function call. We don't support near functions.
2423 StackSize = 2;
2424 StackPointer = "bp";
2425 ArgOffset = 6;
2426 LocalOffset = 0;
2427 } else {
2428 error(ERR_NONFATAL, "`%%stacksize' invalid size type");
2429 free_tlist(origline);
2430 return DIRECTIVE_FOUND;
2432 free_tlist(origline);
2433 return DIRECTIVE_FOUND;
2435 case PP_ARG:
2436 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2437 /* TASM like ARG directive to define arguments to functions, in
2438 * the following form:
2440 * ARG arg1:WORD, arg2:DWORD, arg4:QWORD
2442 offset = ArgOffset;
2443 do {
2444 char *arg, directive[256];
2445 int size = StackSize;
2447 /* Find the argument name */
2448 tline = tline->next;
2449 if (tline && tline->type == TOK_WHITESPACE)
2450 tline = tline->next;
2451 if (!tline || tline->type != TOK_ID) {
2452 error(ERR_NONFATAL, "`%%arg' missing argument parameter");
2453 free_tlist(origline);
2454 return DIRECTIVE_FOUND;
2456 arg = tline->text;
2458 /* Find the argument size type */
2459 tline = tline->next;
2460 if (!tline || tline->type != TOK_OTHER
2461 || tline->text[0] != ':') {
2462 error(ERR_NONFATAL,
2463 "Syntax error processing `%%arg' directive");
2464 free_tlist(origline);
2465 return DIRECTIVE_FOUND;
2467 tline = tline->next;
2468 if (!tline || tline->type != TOK_ID) {
2469 error(ERR_NONFATAL, "`%%arg' missing size type parameter");
2470 free_tlist(origline);
2471 return DIRECTIVE_FOUND;
2474 /* Allow macro expansion of type parameter */
2475 tt = tokenize(tline->text);
2476 tt = expand_smacro(tt);
2477 size = parse_size(tt->text);
2478 if (!size) {
2479 error(ERR_NONFATAL,
2480 "Invalid size type for `%%arg' missing directive");
2481 free_tlist(tt);
2482 free_tlist(origline);
2483 return DIRECTIVE_FOUND;
2485 free_tlist(tt);
2487 /* Round up to even stack slots */
2488 size = ALIGN(size, StackSize);
2490 /* Now define the macro for the argument */
2491 snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
2492 arg, StackPointer, offset);
2493 do_directive(tokenize(directive));
2494 offset += size;
2496 /* Move to the next argument in the list */
2497 tline = tline->next;
2498 if (tline && tline->type == TOK_WHITESPACE)
2499 tline = tline->next;
2500 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2501 ArgOffset = offset;
2502 free_tlist(origline);
2503 return DIRECTIVE_FOUND;
2505 case PP_LOCAL:
2506 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2507 /* TASM like LOCAL directive to define local variables for a
2508 * function, in the following form:
2510 * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
2512 * The '= LocalSize' at the end is ignored by NASM, but is
2513 * required by TASM to define the local parameter size (and used
2514 * by the TASM macro package).
2516 offset = LocalOffset;
2517 do {
2518 char *local, directive[256];
2519 int size = StackSize;
2521 /* Find the argument name */
2522 tline = tline->next;
2523 if (tline && tline->type == TOK_WHITESPACE)
2524 tline = tline->next;
2525 if (!tline || tline->type != TOK_ID) {
2526 error(ERR_NONFATAL,
2527 "`%%local' missing argument parameter");
2528 free_tlist(origline);
2529 return DIRECTIVE_FOUND;
2531 local = tline->text;
2533 /* Find the argument size type */
2534 tline = tline->next;
2535 if (!tline || tline->type != TOK_OTHER
2536 || tline->text[0] != ':') {
2537 error(ERR_NONFATAL,
2538 "Syntax error processing `%%local' directive");
2539 free_tlist(origline);
2540 return DIRECTIVE_FOUND;
2542 tline = tline->next;
2543 if (!tline || tline->type != TOK_ID) {
2544 error(ERR_NONFATAL,
2545 "`%%local' missing size type parameter");
2546 free_tlist(origline);
2547 return DIRECTIVE_FOUND;
2550 /* Allow macro expansion of type parameter */
2551 tt = tokenize(tline->text);
2552 tt = expand_smacro(tt);
2553 size = parse_size(tt->text);
2554 if (!size) {
2555 error(ERR_NONFATAL,
2556 "Invalid size type for `%%local' missing directive");
2557 free_tlist(tt);
2558 free_tlist(origline);
2559 return DIRECTIVE_FOUND;
2561 free_tlist(tt);
2563 /* Round up to even stack slots */
2564 size = ALIGN(size, StackSize);
2566 offset += size; /* Negative offset, increment before */
2568 /* Now define the macro for the argument */
2569 snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
2570 local, StackPointer, offset);
2571 do_directive(tokenize(directive));
2573 /* Now define the assign to setup the enter_c macro correctly */
2574 snprintf(directive, sizeof(directive),
2575 "%%assign %%$localsize %%$localsize+%d", size);
2576 do_directive(tokenize(directive));
2578 /* Move to the next argument in the list */
2579 tline = tline->next;
2580 if (tline && tline->type == TOK_WHITESPACE)
2581 tline = tline->next;
2582 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2583 LocalOffset = offset;
2584 free_tlist(origline);
2585 return DIRECTIVE_FOUND;
2587 case PP_CLEAR:
2588 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2589 if (tline->next)
2590 error(ERR_WARNING|ERR_PASS1,
2591 "trailing garbage after `%%clear' ignored");
2592 free_macros();
2593 init_macros();
2594 free_tlist(origline);
2595 return DIRECTIVE_FOUND;
2597 case PP_DEPEND:
2598 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2599 t = tline->next = expand_smacro(tline->next);
2600 skip_white_(t);
2601 if (!t || (t->type != TOK_STRING &&
2602 t->type != TOK_INTERNAL_STRING)) {
2603 error(ERR_NONFATAL, "`%%depend' expects a file name");
2604 free_tlist(origline);
2605 return DIRECTIVE_FOUND; /* but we did _something_ */
2607 if (t->next)
2608 error(ERR_WARNING|ERR_PASS1,
2609 "trailing garbage after `%%depend' ignored");
2610 p = t->text;
2611 if (t->type != TOK_INTERNAL_STRING)
2612 nasm_unquote_cstr(p, i);
2613 if (dephead && !in_list(*dephead, p)) {
2614 StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next);
2615 sl->next = NULL;
2616 strcpy(sl->str, p);
2617 *deptail = sl;
2618 deptail = &sl->next;
2620 free_tlist(origline);
2621 return DIRECTIVE_FOUND;
2623 case PP_INCLUDE:
2624 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2625 t = tline->next = expand_smacro(tline->next);
2626 skip_white_(t);
2628 if (!t || (t->type != TOK_STRING &&
2629 t->type != TOK_INTERNAL_STRING)) {
2630 error(ERR_NONFATAL, "`%%include' expects a file name");
2631 free_tlist(origline);
2632 return DIRECTIVE_FOUND; /* but we did _something_ */
2634 if (t->next)
2635 error(ERR_WARNING|ERR_PASS1,
2636 "trailing garbage after `%%include' ignored");
2637 p = t->text;
2638 if (t->type != TOK_INTERNAL_STRING)
2639 nasm_unquote_cstr(p, i);
2640 inc = nasm_zalloc(sizeof(Include));
2641 inc->next = istk;
2642 inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
2643 if (!inc->fp) {
2644 /* -MG given but file not found */
2645 nasm_free(inc);
2646 } else {
2647 inc->fname = src_set_fname(nasm_strdup(p));
2648 inc->lineno = src_set_linnum(0);
2649 inc->lineinc = 1;
2650 inc->expansion = NULL;
2651 istk = inc;
2652 list->uplevel(LIST_INCLUDE);
2654 free_tlist(origline);
2655 return DIRECTIVE_FOUND;
2657 case PP_USE:
2658 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2660 static macros_t *use_pkg;
2661 const char *pkg_macro = NULL;
2663 tline = tline->next;
2664 skip_white_(tline);
2665 tline = expand_id(tline);
2667 if (!tline || (tline->type != TOK_STRING &&
2668 tline->type != TOK_INTERNAL_STRING &&
2669 tline->type != TOK_ID)) {
2670 error(ERR_NONFATAL, "`%%use' expects a package name");
2671 free_tlist(origline);
2672 return DIRECTIVE_FOUND; /* but we did _something_ */
2674 if (tline->next)
2675 error(ERR_WARNING|ERR_PASS1,
2676 "trailing garbage after `%%use' ignored");
2677 if (tline->type == TOK_STRING)
2678 nasm_unquote_cstr(tline->text, i);
2679 use_pkg = nasm_stdmac_find_package(tline->text);
2680 if (!use_pkg)
2681 error(ERR_NONFATAL, "unknown `%%use' package: %s", tline->text);
2682 else
2683 pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */
2684 if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) {
2685 /* Not already included, go ahead and include it */
2686 stdmacpos = use_pkg;
2688 free_tlist(origline);
2689 return DIRECTIVE_FOUND;
2691 case PP_PUSH:
2692 case PP_REPL:
2693 case PP_POP:
2694 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2695 tline = tline->next;
2696 skip_white_(tline);
2697 tline = expand_id(tline);
2698 if (tline) {
2699 if (!tok_type_(tline, TOK_ID)) {
2700 error(ERR_NONFATAL, "`%s' expects a context identifier",
2701 pp_directives[i]);
2702 free_tlist(origline);
2703 return DIRECTIVE_FOUND; /* but we did _something_ */
2705 if (tline->next)
2706 error(ERR_WARNING|ERR_PASS1,
2707 "trailing garbage after `%s' ignored",
2708 pp_directives[i]);
2709 p = nasm_strdup(tline->text);
2710 } else {
2711 p = NULL; /* Anonymous */
2714 if (i == PP_PUSH) {
2715 ctx = nasm_zalloc(sizeof(Context));
2716 ctx->next = cstk;
2717 hash_init(&ctx->localmac, HASH_SMALL);
2718 ctx->name = p;
2719 ctx->number = unique++;
2720 cstk = ctx;
2721 } else {
2722 /* %pop or %repl */
2723 if (!cstk) {
2724 error(ERR_NONFATAL, "`%s': context stack is empty",
2725 pp_directives[i]);
2726 } else if (i == PP_POP) {
2727 if (p && (!cstk->name || nasm_stricmp(p, cstk->name)))
2728 error(ERR_NONFATAL, "`%%pop' in wrong context: %s, "
2729 "expected %s",
2730 cstk->name ? cstk->name : "anonymous", p);
2731 else
2732 ctx_pop();
2733 } else {
2734 /* i == PP_REPL */
2735 nasm_free(cstk->name);
2736 cstk->name = p;
2737 p = NULL;
2739 nasm_free(p);
2741 free_tlist(origline);
2742 return DIRECTIVE_FOUND;
2743 case PP_FATAL:
2744 severity = ERR_FATAL;
2745 goto issue_error;
2746 case PP_ERROR:
2747 severity = ERR_NONFATAL;
2748 goto issue_error;
2749 case PP_WARNING:
2750 severity = ERR_WARNING|ERR_WARN_USER;
2751 goto issue_error;
2753 issue_error:
2754 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2756 /* Only error out if this is the final pass */
2757 if (pass != 2 && i != PP_FATAL)
2758 return DIRECTIVE_FOUND;
2760 tline->next = expand_smacro(tline->next);
2761 tline = tline->next;
2762 skip_white_(tline);
2763 t = tline ? tline->next : NULL;
2764 skip_white_(t);
2765 if (tok_type_(tline, TOK_STRING) && !t) {
2766 /* The line contains only a quoted string */
2767 p = tline->text;
2768 nasm_unquote(p, NULL); /* Ignore NUL character truncation */
2769 error(severity, "%s", p);
2770 } else {
2771 /* Not a quoted string, or more than a quoted string */
2772 p = detoken(tline, false);
2773 error(severity, "%s", p);
2774 nasm_free(p);
2776 free_tlist(origline);
2777 return DIRECTIVE_FOUND;
2780 CASE_PP_IF:
2781 if (defining != NULL) {
2782 if (defining->type == EXP_IF) {
2783 defining->def_depth ++;
2785 return NO_DIRECTIVE_FOUND;
2787 if ((istk->expansion != NULL) &&
2788 (istk->expansion->emitting == false)) {
2789 j = COND_NEVER;
2790 } else {
2791 j = if_condition(tline->next, i);
2792 tline->next = NULL; /* it got freed */
2793 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
2795 ed = new_ExpDef(EXP_IF);
2796 ed->state = j;
2797 ed->nolist = NULL;
2798 ed->def_depth = 0;
2799 ed->cur_depth = 0;
2800 ed->max_depth = 0;
2801 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
2802 ed->prev = defining;
2803 defining = ed;
2804 free_tlist(origline);
2805 return DIRECTIVE_FOUND;
2807 CASE_PP_ELIF:
2808 if (defining != NULL) {
2809 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2810 return NO_DIRECTIVE_FOUND;
2813 if ((defining == NULL) || (defining->type != EXP_IF)) {
2814 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2816 switch (defining->state) {
2817 case COND_IF_TRUE:
2818 defining->state = COND_DONE;
2819 defining->ignoring = true;
2820 break;
2822 case COND_DONE:
2823 case COND_NEVER:
2824 defining->ignoring = true;
2825 break;
2827 case COND_ELSE_TRUE:
2828 case COND_ELSE_FALSE:
2829 error_precond(ERR_WARNING|ERR_PASS1,
2830 "`%%elif' after `%%else' ignored");
2831 defining->state = COND_NEVER;
2832 defining->ignoring = true;
2833 break;
2835 case COND_IF_FALSE:
2837 * IMPORTANT: In the case of %if, we will already have
2838 * called expand_mmac_params(); however, if we're
2839 * processing an %elif we must have been in a
2840 * non-emitting mode, which would have inhibited
2841 * the normal invocation of expand_mmac_params().
2842 * Therefore, we have to do it explicitly here.
2844 j = if_condition(expand_mmac_params(tline->next), i);
2845 tline->next = NULL; /* it got freed */
2846 defining->state =
2847 j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
2848 defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
2849 break;
2851 free_tlist(origline);
2852 return DIRECTIVE_FOUND;
2854 case PP_ELSE:
2855 if (defining != NULL) {
2856 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2857 return NO_DIRECTIVE_FOUND;
2860 if (tline->next)
2861 error_precond(ERR_WARNING|ERR_PASS1,
2862 "trailing garbage after `%%else' ignored");
2863 if ((defining == NULL) || (defining->type != EXP_IF)) {
2864 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2866 switch (defining->state) {
2867 case COND_IF_TRUE:
2868 case COND_DONE:
2869 defining->state = COND_ELSE_FALSE;
2870 defining->ignoring = true;
2871 break;
2873 case COND_NEVER:
2874 defining->ignoring = true;
2875 break;
2877 case COND_IF_FALSE:
2878 defining->state = COND_ELSE_TRUE;
2879 defining->ignoring = false;
2880 break;
2882 case COND_ELSE_TRUE:
2883 case COND_ELSE_FALSE:
2884 error_precond(ERR_WARNING|ERR_PASS1,
2885 "`%%else' after `%%else' ignored.");
2886 defining->state = COND_NEVER;
2887 defining->ignoring = true;
2888 break;
2890 free_tlist(origline);
2891 return DIRECTIVE_FOUND;
2893 case PP_ENDIF:
2894 if (defining != NULL) {
2895 if (defining->type == EXP_IF) {
2896 if (defining->def_depth > 0) {
2897 defining->def_depth --;
2898 return NO_DIRECTIVE_FOUND;
2900 } else {
2901 return NO_DIRECTIVE_FOUND;
2904 if (tline->next)
2905 error_precond(ERR_WARNING|ERR_PASS1,
2906 "trailing garbage after `%%endif' ignored");
2907 if ((defining == NULL) || (defining->type != EXP_IF)) {
2908 error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
2909 return DIRECTIVE_FOUND;
2911 ed = defining;
2912 defining = ed->prev;
2913 ed->prev = expansions;
2914 expansions = ed;
2915 ei = new_ExpInv(EXP_IF, ed);
2916 ei->current = ed->line;
2917 ei->emitting = true;
2918 ei->prev = istk->expansion;
2919 istk->expansion = ei;
2920 free_tlist(origline);
2921 return DIRECTIVE_FOUND;
2923 case PP_RMACRO:
2924 case PP_IRMACRO:
2925 case PP_MACRO:
2926 case PP_IMACRO:
2927 if (defining != NULL) {
2928 if (defining->type == EXP_MMACRO) {
2929 defining->def_depth ++;
2931 return NO_DIRECTIVE_FOUND;
2933 ed = new_ExpDef(EXP_MMACRO);
2934 ed->max_depth =
2935 (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
2936 ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
2937 if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
2938 nasm_free(ed);
2939 ed = NULL;
2940 return DIRECTIVE_FOUND;
2942 ed->def_depth = 0;
2943 ed->cur_depth = 0;
2944 ed->max_depth = (ed->max_depth + 1);
2945 ed->ignoring = false;
2946 ed->prev = defining;
2947 defining = ed;
2949 eed = (ExpDef *) hash_findix(&expdefs, ed->name);
2950 while (eed) {
2951 if (!strcmp(eed->name, ed->name) &&
2952 (eed->nparam_min <= ed->nparam_max || ed->plus) &&
2953 (ed->nparam_min <= eed->nparam_max || eed->plus)) {
2954 error(ERR_WARNING|ERR_PASS1,
2955 "redefining multi-line macro `%s'", ed->name);
2956 return DIRECTIVE_FOUND;
2958 eed = eed->next;
2960 free_tlist(origline);
2961 return DIRECTIVE_FOUND;
2963 case PP_ENDM:
2964 case PP_ENDMACRO:
2965 if (defining != NULL) {
2966 if (defining->type == EXP_MMACRO) {
2967 if (defining->def_depth > 0) {
2968 defining->def_depth --;
2969 return NO_DIRECTIVE_FOUND;
2971 } else {
2972 return NO_DIRECTIVE_FOUND;
2975 if (!(defining) || (defining->type != EXP_MMACRO)) {
2976 error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
2977 return DIRECTIVE_FOUND;
2979 edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
2980 defining->next = *edhead;
2981 *edhead = defining;
2982 ed = defining;
2983 defining = ed->prev;
2984 ed->prev = expansions;
2985 expansions = ed;
2986 ed = NULL;
2987 free_tlist(origline);
2988 return DIRECTIVE_FOUND;
2990 case PP_EXITMACRO:
2991 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2993 * We must search along istk->expansion until we hit a
2994 * macro invocation. Then we disable the emitting state(s)
2995 * between exitmacro and endmacro.
2997 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
2998 if(ei->type == EXP_MMACRO) {
2999 break;
3003 if (ei != NULL) {
3005 * Set all invocations leading back to the macro
3006 * invocation to a non-emitting state.
3008 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3009 eei->emitting = false;
3011 eei->emitting = false;
3012 } else {
3013 error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
3015 free_tlist(origline);
3016 return DIRECTIVE_FOUND;
3018 case PP_UNMACRO:
3019 case PP_UNIMACRO:
3020 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3022 ExpDef **ed_p;
3023 ExpDef spec;
3025 spec.casesense = (i == PP_UNMACRO);
3026 if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
3027 return DIRECTIVE_FOUND;
3029 ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
3030 while (ed_p && *ed_p) {
3031 ed = *ed_p;
3032 if (ed->casesense == spec.casesense &&
3033 !mstrcmp(ed->name, spec.name, spec.casesense) &&
3034 ed->nparam_min == spec.nparam_min &&
3035 ed->nparam_max == spec.nparam_max &&
3036 ed->plus == spec.plus) {
3037 if (ed->cur_depth > 0) {
3038 error(ERR_NONFATAL, "`%s' ignored on active macro",
3039 pp_directives[i]);
3040 break;
3041 } else {
3042 *ed_p = ed->next;
3043 free_expdef(ed);
3045 } else {
3046 ed_p = &ed->next;
3049 free_tlist(origline);
3050 free_tlist(spec.dlist);
3051 return DIRECTIVE_FOUND;
3054 case PP_ROTATE:
3055 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3056 if (tline->next && tline->next->type == TOK_WHITESPACE)
3057 tline = tline->next;
3058 if (!tline->next) {
3059 free_tlist(origline);
3060 error(ERR_NONFATAL, "`%%rotate' missing rotate count");
3061 return DIRECTIVE_FOUND;
3063 t = expand_smacro(tline->next);
3064 tline->next = NULL;
3065 free_tlist(origline);
3066 tline = t;
3067 tptr = &t;
3068 tokval.t_type = TOKEN_INVALID;
3069 evalresult =
3070 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3071 free_tlist(tline);
3072 if (!evalresult)
3073 return DIRECTIVE_FOUND;
3074 if (tokval.t_type)
3075 error(ERR_WARNING|ERR_PASS1,
3076 "trailing garbage after expression ignored");
3077 if (!is_simple(evalresult)) {
3078 error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
3079 return DIRECTIVE_FOUND;
3081 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3082 if (ei->type == EXP_MMACRO) {
3083 break;
3086 if (ei == NULL) {
3087 error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
3088 } else if (ei->nparam == 0) {
3089 error(ERR_NONFATAL,
3090 "`%%rotate' invoked within macro without parameters");
3091 } else {
3092 int rotate = ei->rotate + reloc_value(evalresult);
3094 rotate %= (int)ei->nparam;
3095 if (rotate < 0)
3096 rotate += ei->nparam;
3097 ei->rotate = rotate;
3099 return DIRECTIVE_FOUND;
3101 case PP_REP:
3102 if (defining != NULL) {
3103 if (defining->type == EXP_REP) {
3104 defining->def_depth ++;
3106 return NO_DIRECTIVE_FOUND;
3108 nolist = false;
3109 do {
3110 tline = tline->next;
3111 } while (tok_type_(tline, TOK_WHITESPACE));
3113 if (tok_type_(tline, TOK_ID) &&
3114 nasm_stricmp(tline->text, ".nolist") == 0) {
3115 nolist = true;
3116 do {
3117 tline = tline->next;
3118 } while (tok_type_(tline, TOK_WHITESPACE));
3121 if (tline) {
3122 t = expand_smacro(tline);
3123 tptr = &t;
3124 tokval.t_type = TOKEN_INVALID;
3125 evalresult =
3126 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3127 if (!evalresult) {
3128 free_tlist(origline);
3129 return DIRECTIVE_FOUND;
3131 if (tokval.t_type)
3132 error(ERR_WARNING|ERR_PASS1,
3133 "trailing garbage after expression ignored");
3134 if (!is_simple(evalresult)) {
3135 error(ERR_NONFATAL, "non-constant value given to `%%rep'");
3136 return DIRECTIVE_FOUND;
3138 count = reloc_value(evalresult);
3139 if (count >= REP_LIMIT) {
3140 error(ERR_NONFATAL, "`%%rep' value exceeds limit");
3141 count = 0;
3142 } else
3143 count++;
3144 } else {
3145 error(ERR_NONFATAL, "`%%rep' expects a repeat count");
3146 count = 0;
3148 free_tlist(origline);
3149 ed = new_ExpDef(EXP_REP);
3150 ed->nolist = nolist;
3151 ed->def_depth = 0;
3152 ed->cur_depth = 1;
3153 ed->max_depth = (count - 1);
3154 ed->ignoring = false;
3155 ed->prev = defining;
3156 defining = ed;
3157 return DIRECTIVE_FOUND;
3159 case PP_ENDREP:
3160 if (defining != NULL) {
3161 if (defining->type == EXP_REP) {
3162 if (defining->def_depth > 0) {
3163 defining->def_depth --;
3164 return NO_DIRECTIVE_FOUND;
3166 } else {
3167 return NO_DIRECTIVE_FOUND;
3170 if ((defining == NULL) || (defining->type != EXP_REP)) {
3171 error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
3172 return DIRECTIVE_FOUND;
3176 * Now we have a "macro" defined - although it has no name
3177 * and we won't be entering it in the hash tables - we must
3178 * push a macro-end marker for it on to istk->expansion.
3179 * After that, it will take care of propagating itself (a
3180 * macro-end marker line for a macro which is really a %rep
3181 * block will cause the macro to be re-expanded, complete
3182 * with another macro-end marker to ensure the process
3183 * continues) until the whole expansion is forcibly removed
3184 * from istk->expansion by a %exitrep.
3186 ed = defining;
3187 defining = ed->prev;
3188 ed->prev = expansions;
3189 expansions = ed;
3190 ei = new_ExpInv(EXP_REP, ed);
3191 ei->current = ed->line;
3192 ei->emitting = ((ed->max_depth > 0) ? true : false);
3193 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
3194 ei->prev = istk->expansion;
3195 istk->expansion = ei;
3196 free_tlist(origline);
3197 return DIRECTIVE_FOUND;
3199 case PP_EXITREP:
3200 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3202 * We must search along istk->expansion until we hit a
3203 * rep invocation. Then we disable the emitting state(s)
3204 * between exitrep and endrep.
3206 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3207 if (ei->type == EXP_REP) {
3208 break;
3212 if (ei != NULL) {
3214 * Set all invocations leading back to the rep
3215 * invocation to a non-emitting state.
3217 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3218 eei->emitting = false;
3220 eei->emitting = false;
3221 eei->current = NULL;
3222 eei->def->cur_depth = eei->def->max_depth;
3223 } else {
3224 error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
3226 free_tlist(origline);
3227 return DIRECTIVE_FOUND;
3229 case PP_XDEFINE:
3230 case PP_IXDEFINE:
3231 case PP_DEFINE:
3232 case PP_IDEFINE:
3233 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3234 casesense = (i == PP_DEFINE || i == PP_XDEFINE);
3236 tline = tline->next;
3237 skip_white_(tline);
3238 tline = expand_id(tline);
3239 if (!tline || (tline->type != TOK_ID &&
3240 (tline->type != TOK_PREPROC_ID ||
3241 tline->text[1] != '$'))) {
3242 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3243 pp_directives[i]);
3244 free_tlist(origline);
3245 return DIRECTIVE_FOUND;
3248 ctx = get_ctx(tline->text, &mname, false);
3249 last = tline;
3250 param_start = tline = tline->next;
3251 nparam = 0;
3253 /* Expand the macro definition now for %xdefine and %ixdefine */
3254 if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
3255 tline = expand_smacro(tline);
3257 if (tok_is_(tline, "(")) {
3259 * This macro has parameters.
3262 tline = tline->next;
3263 while (1) {
3264 skip_white_(tline);
3265 if (!tline) {
3266 error(ERR_NONFATAL, "parameter identifier expected");
3267 free_tlist(origline);
3268 return DIRECTIVE_FOUND;
3270 if (tline->type != TOK_ID) {
3271 error(ERR_NONFATAL,
3272 "`%s': parameter identifier expected",
3273 tline->text);
3274 free_tlist(origline);
3275 return DIRECTIVE_FOUND;
3277 tline->type = TOK_SMAC_PARAM + nparam++;
3278 tline = tline->next;
3279 skip_white_(tline);
3280 if (tok_is_(tline, ",")) {
3281 tline = tline->next;
3282 } else {
3283 if (!tok_is_(tline, ")")) {
3284 error(ERR_NONFATAL,
3285 "`)' expected to terminate macro template");
3286 free_tlist(origline);
3287 return DIRECTIVE_FOUND;
3289 break;
3292 last = tline;
3293 tline = tline->next;
3295 if (tok_type_(tline, TOK_WHITESPACE))
3296 last = tline, tline = tline->next;
3297 macro_start = NULL;
3298 last->next = NULL;
3299 t = tline;
3300 while (t) {
3301 if (t->type == TOK_ID) {
3302 list_for_each(tt, param_start)
3303 if (tt->type >= TOK_SMAC_PARAM &&
3304 !strcmp(tt->text, t->text))
3305 t->type = tt->type;
3307 tt = t->next;
3308 t->next = macro_start;
3309 macro_start = t;
3310 t = tt;
3313 * Good. We now have a macro name, a parameter count, and a
3314 * token list (in reverse order) for an expansion. We ought
3315 * to be OK just to create an SMacro, store it, and let
3316 * free_tlist have the rest of the line (which we have
3317 * carefully re-terminated after chopping off the expansion
3318 * from the end).
3320 define_smacro(ctx, mname, casesense, nparam, macro_start);
3321 free_tlist(origline);
3322 return DIRECTIVE_FOUND;
3324 case PP_UNDEF:
3325 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3326 tline = tline->next;
3327 skip_white_(tline);
3328 tline = expand_id(tline);
3329 if (!tline || (tline->type != TOK_ID &&
3330 (tline->type != TOK_PREPROC_ID ||
3331 tline->text[1] != '$'))) {
3332 error(ERR_NONFATAL, "`%%undef' expects a macro identifier");
3333 free_tlist(origline);
3334 return DIRECTIVE_FOUND;
3336 if (tline->next) {
3337 error(ERR_WARNING|ERR_PASS1,
3338 "trailing garbage after macro name ignored");
3341 /* Find the context that symbol belongs to */
3342 ctx = get_ctx(tline->text, &mname, false);
3343 undef_smacro(ctx, mname);
3344 free_tlist(origline);
3345 return DIRECTIVE_FOUND;
3347 case PP_DEFSTR:
3348 case PP_IDEFSTR:
3349 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3350 casesense = (i == PP_DEFSTR);
3352 tline = tline->next;
3353 skip_white_(tline);
3354 tline = expand_id(tline);
3355 if (!tline || (tline->type != TOK_ID &&
3356 (tline->type != TOK_PREPROC_ID ||
3357 tline->text[1] != '$'))) {
3358 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3359 pp_directives[i]);
3360 free_tlist(origline);
3361 return DIRECTIVE_FOUND;
3364 ctx = get_ctx(tline->text, &mname, false);
3365 last = tline;
3366 tline = expand_smacro(tline->next);
3367 last->next = NULL;
3369 while (tok_type_(tline, TOK_WHITESPACE))
3370 tline = delete_Token(tline);
3372 p = detoken(tline, false);
3373 macro_start = nasm_zalloc(sizeof(*macro_start));
3374 macro_start->text = nasm_quote(p, strlen(p));
3375 macro_start->type = TOK_STRING;
3376 nasm_free(p);
3379 * We now have a macro name, an implicit parameter count of
3380 * zero, and a string token to use as an expansion. Create
3381 * and store an SMacro.
3383 define_smacro(ctx, mname, casesense, 0, macro_start);
3384 free_tlist(origline);
3385 return DIRECTIVE_FOUND;
3387 case PP_DEFTOK:
3388 case PP_IDEFTOK:
3389 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3390 casesense = (i == PP_DEFTOK);
3392 tline = tline->next;
3393 skip_white_(tline);
3394 tline = expand_id(tline);
3395 if (!tline || (tline->type != TOK_ID &&
3396 (tline->type != TOK_PREPROC_ID ||
3397 tline->text[1] != '$'))) {
3398 error(ERR_NONFATAL,
3399 "`%s' expects a macro identifier as first parameter",
3400 pp_directives[i]);
3401 free_tlist(origline);
3402 return DIRECTIVE_FOUND;
3404 ctx = get_ctx(tline->text, &mname, false);
3405 last = tline;
3406 tline = expand_smacro(tline->next);
3407 last->next = NULL;
3409 t = tline;
3410 while (tok_type_(t, TOK_WHITESPACE))
3411 t = t->next;
3412 /* t should now point to the string */
3413 if (!tok_type_(t, TOK_STRING)) {
3414 error(ERR_NONFATAL,
3415 "`%s` requires string as second parameter",
3416 pp_directives[i]);
3417 free_tlist(tline);
3418 free_tlist(origline);
3419 return DIRECTIVE_FOUND;
3423 * Convert the string to a token stream. Note that smacros
3424 * are stored with the token stream reversed, so we have to
3425 * reverse the output of tokenize().
3427 nasm_unquote_cstr(t->text, i);
3428 macro_start = reverse_tokens(tokenize(t->text));
3431 * We now have a macro name, an implicit parameter count of
3432 * zero, and a numeric token to use as an expansion. Create
3433 * and store an SMacro.
3435 define_smacro(ctx, mname, casesense, 0, macro_start);
3436 free_tlist(tline);
3437 free_tlist(origline);
3438 return DIRECTIVE_FOUND;
3440 case PP_PATHSEARCH:
3441 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3443 FILE *fp;
3444 StrList *xsl = NULL;
3445 StrList **xst = &xsl;
3447 casesense = true;
3449 tline = tline->next;
3450 skip_white_(tline);
3451 tline = expand_id(tline);
3452 if (!tline || (tline->type != TOK_ID &&
3453 (tline->type != TOK_PREPROC_ID ||
3454 tline->text[1] != '$'))) {
3455 error(ERR_NONFATAL,
3456 "`%%pathsearch' expects a macro identifier as first parameter");
3457 free_tlist(origline);
3458 return DIRECTIVE_FOUND;
3460 ctx = get_ctx(tline->text, &mname, false);
3461 last = tline;
3462 tline = expand_smacro(tline->next);
3463 last->next = NULL;
3465 t = tline;
3466 while (tok_type_(t, TOK_WHITESPACE))
3467 t = t->next;
3469 if (!t || (t->type != TOK_STRING &&
3470 t->type != TOK_INTERNAL_STRING)) {
3471 error(ERR_NONFATAL, "`%%pathsearch' expects a file name");
3472 free_tlist(tline);
3473 free_tlist(origline);
3474 return DIRECTIVE_FOUND; /* but we did _something_ */
3476 if (t->next)
3477 error(ERR_WARNING|ERR_PASS1,
3478 "trailing garbage after `%%pathsearch' ignored");
3479 p = t->text;
3480 if (t->type != TOK_INTERNAL_STRING)
3481 nasm_unquote(p, NULL);
3483 fp = inc_fopen(p, &xsl, &xst, true);
3484 if (fp) {
3485 p = xsl->str;
3486 fclose(fp); /* Don't actually care about the file */
3488 macro_start = nasm_zalloc(sizeof(*macro_start));
3489 macro_start->text = nasm_quote(p, strlen(p));
3490 macro_start->type = TOK_STRING;
3491 if (xsl)
3492 nasm_free(xsl);
3495 * We now have a macro name, an implicit parameter count of
3496 * zero, and a string token to use as an expansion. Create
3497 * and store an SMacro.
3499 define_smacro(ctx, mname, casesense, 0, macro_start);
3500 free_tlist(tline);
3501 free_tlist(origline);
3502 return DIRECTIVE_FOUND;
3505 case PP_STRLEN:
3506 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3507 casesense = true;
3509 tline = tline->next;
3510 skip_white_(tline);
3511 tline = expand_id(tline);
3512 if (!tline || (tline->type != TOK_ID &&
3513 (tline->type != TOK_PREPROC_ID ||
3514 tline->text[1] != '$'))) {
3515 error(ERR_NONFATAL,
3516 "`%%strlen' expects a macro identifier as first parameter");
3517 free_tlist(origline);
3518 return DIRECTIVE_FOUND;
3520 ctx = get_ctx(tline->text, &mname, false);
3521 last = tline;
3522 tline = expand_smacro(tline->next);
3523 last->next = NULL;
3525 t = tline;
3526 while (tok_type_(t, TOK_WHITESPACE))
3527 t = t->next;
3528 /* t should now point to the string */
3529 if (!tok_type_(t, TOK_STRING)) {
3530 error(ERR_NONFATAL,
3531 "`%%strlen` requires string as second parameter");
3532 free_tlist(tline);
3533 free_tlist(origline);
3534 return DIRECTIVE_FOUND;
3537 macro_start = nasm_zalloc(sizeof(*macro_start));
3538 make_tok_num(macro_start, nasm_unquote(t->text, NULL));
3541 * We now have a macro name, an implicit parameter count of
3542 * zero, and a numeric token to use as an expansion. Create
3543 * and store an SMacro.
3545 define_smacro(ctx, mname, casesense, 0, macro_start);
3546 free_tlist(tline);
3547 free_tlist(origline);
3548 return DIRECTIVE_FOUND;
3550 case PP_STRCAT:
3551 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3552 casesense = true;
3554 tline = tline->next;
3555 skip_white_(tline);
3556 tline = expand_id(tline);
3557 if (!tline || (tline->type != TOK_ID &&
3558 (tline->type != TOK_PREPROC_ID ||
3559 tline->text[1] != '$'))) {
3560 error(ERR_NONFATAL,
3561 "`%%strcat' expects a macro identifier as first parameter");
3562 free_tlist(origline);
3563 return DIRECTIVE_FOUND;
3565 ctx = get_ctx(tline->text, &mname, false);
3566 last = tline;
3567 tline = expand_smacro(tline->next);
3568 last->next = NULL;
3570 len = 0;
3571 list_for_each(t, tline) {
3572 switch (t->type) {
3573 case TOK_WHITESPACE:
3574 break;
3575 case TOK_STRING:
3576 len += t->a.len = nasm_unquote(t->text, NULL);
3577 break;
3578 case TOK_OTHER:
3579 if (!strcmp(t->text, ",")) /* permit comma separators */
3580 break;
3581 /* else fall through */
3582 default:
3583 error(ERR_NONFATAL,
3584 "non-string passed to `%%strcat' (%d)", t->type);
3585 free_tlist(tline);
3586 free_tlist(origline);
3587 return DIRECTIVE_FOUND;
3591 p = pp = nasm_malloc(len);
3592 list_for_each(t, tline) {
3593 if (t->type == TOK_STRING) {
3594 memcpy(p, t->text, t->a.len);
3595 p += t->a.len;
3600 * We now have a macro name, an implicit parameter count of
3601 * zero, and a numeric token to use as an expansion. Create
3602 * and store an SMacro.
3604 macro_start = new_Token(NULL, TOK_STRING, NULL, 0);
3605 macro_start->text = nasm_quote(pp, len);
3606 nasm_free(pp);
3607 define_smacro(ctx, mname, casesense, 0, macro_start);
3608 free_tlist(tline);
3609 free_tlist(origline);
3610 return DIRECTIVE_FOUND;
3612 case PP_SUBSTR:
3613 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3615 int64_t start, count;
3616 size_t len;
3618 casesense = true;
3620 tline = tline->next;
3621 skip_white_(tline);
3622 tline = expand_id(tline);
3623 if (!tline || (tline->type != TOK_ID &&
3624 (tline->type != TOK_PREPROC_ID ||
3625 tline->text[1] != '$'))) {
3626 error(ERR_NONFATAL,
3627 "`%%substr' expects a macro identifier as first parameter");
3628 free_tlist(origline);
3629 return DIRECTIVE_FOUND;
3631 ctx = get_ctx(tline->text, &mname, false);
3632 last = tline;
3633 tline = expand_smacro(tline->next);
3634 last->next = NULL;
3636 if (tline) /* skip expanded id */
3637 t = tline->next;
3638 while (tok_type_(t, TOK_WHITESPACE))
3639 t = t->next;
3641 /* t should now point to the string */
3642 if (!tok_type_(t, TOK_STRING)) {
3643 error(ERR_NONFATAL,
3644 "`%%substr` requires string as second parameter");
3645 free_tlist(tline);
3646 free_tlist(origline);
3647 return DIRECTIVE_FOUND;
3650 tt = t->next;
3651 tptr = &tt;
3652 tokval.t_type = TOKEN_INVALID;
3653 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3654 pass, error, NULL);
3655 if (!evalresult) {
3656 free_tlist(tline);
3657 free_tlist(origline);
3658 return DIRECTIVE_FOUND;
3659 } else if (!is_simple(evalresult)) {
3660 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3661 free_tlist(tline);
3662 free_tlist(origline);
3663 return DIRECTIVE_FOUND;
3665 start = evalresult->value - 1;
3667 while (tok_type_(tt, TOK_WHITESPACE))
3668 tt = tt->next;
3669 if (!tt) {
3670 count = 1; /* Backwards compatibility: one character */
3671 } else {
3672 tokval.t_type = TOKEN_INVALID;
3673 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3674 pass, error, NULL);
3675 if (!evalresult) {
3676 free_tlist(tline);
3677 free_tlist(origline);
3678 return DIRECTIVE_FOUND;
3679 } else if (!is_simple(evalresult)) {
3680 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3681 free_tlist(tline);
3682 free_tlist(origline);
3683 return DIRECTIVE_FOUND;
3685 count = evalresult->value;
3688 len = nasm_unquote(t->text, NULL);
3689 /* make start and count being in range */
3690 if (start < 0)
3691 start = 0;
3692 if (count < 0)
3693 count = len + count + 1 - start;
3694 if (start + count > (int64_t)len)
3695 count = len - start;
3696 if (!len || count < 0 || start >=(int64_t)len)
3697 start = -1, count = 0; /* empty string */
3699 macro_start = nasm_zalloc(sizeof(*macro_start));
3700 macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
3701 macro_start->type = TOK_STRING;
3704 * We now have a macro name, an implicit parameter count of
3705 * zero, and a numeric token to use as an expansion. Create
3706 * and store an SMacro.
3708 define_smacro(ctx, mname, casesense, 0, macro_start);
3709 free_tlist(tline);
3710 free_tlist(origline);
3711 return DIRECTIVE_FOUND;
3714 case PP_ASSIGN:
3715 case PP_IASSIGN:
3716 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3717 casesense = (i == PP_ASSIGN);
3719 tline = tline->next;
3720 skip_white_(tline);
3721 tline = expand_id(tline);
3722 if (!tline || (tline->type != TOK_ID &&
3723 (tline->type != TOK_PREPROC_ID ||
3724 tline->text[1] != '$'))) {
3725 error(ERR_NONFATAL,
3726 "`%%%sassign' expects a macro identifier",
3727 (i == PP_IASSIGN ? "i" : ""));
3728 free_tlist(origline);
3729 return DIRECTIVE_FOUND;
3731 ctx = get_ctx(tline->text, &mname, false);
3732 last = tline;
3733 tline = expand_smacro(tline->next);
3734 last->next = NULL;
3736 t = tline;
3737 tptr = &t;
3738 tokval.t_type = TOKEN_INVALID;
3739 evalresult =
3740 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3741 free_tlist(tline);
3742 if (!evalresult) {
3743 free_tlist(origline);
3744 return DIRECTIVE_FOUND;
3747 if (tokval.t_type)
3748 error(ERR_WARNING|ERR_PASS1,
3749 "trailing garbage after expression ignored");
3751 if (!is_simple(evalresult)) {
3752 error(ERR_NONFATAL,
3753 "non-constant value given to `%%%sassign'",
3754 (i == PP_IASSIGN ? "i" : ""));
3755 free_tlist(origline);
3756 return DIRECTIVE_FOUND;
3759 macro_start = nasm_zalloc(sizeof(*macro_start));
3760 make_tok_num(macro_start, reloc_value(evalresult));
3763 * We now have a macro name, an implicit parameter count of
3764 * zero, and a numeric token to use as an expansion. Create
3765 * and store an SMacro.
3767 define_smacro(ctx, mname, casesense, 0, macro_start);
3768 free_tlist(origline);
3769 return DIRECTIVE_FOUND;
3771 case PP_LINE:
3772 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3774 * Syntax is `%line nnn[+mmm] [filename]'
3776 tline = tline->next;
3777 skip_white_(tline);
3778 if (!tok_type_(tline, TOK_NUMBER)) {
3779 error(ERR_NONFATAL, "`%%line' expects line number");
3780 free_tlist(origline);
3781 return DIRECTIVE_FOUND;
3783 k = readnum(tline->text, &err);
3784 m = 1;
3785 tline = tline->next;
3786 if (tok_is_(tline, "+")) {
3787 tline = tline->next;
3788 if (!tok_type_(tline, TOK_NUMBER)) {
3789 error(ERR_NONFATAL, "`%%line' expects line increment");
3790 free_tlist(origline);
3791 return DIRECTIVE_FOUND;
3793 m = readnum(tline->text, &err);
3794 tline = tline->next;
3796 skip_white_(tline);
3797 src_set_linnum(k);
3798 istk->lineinc = m;
3799 if (tline) {
3800 nasm_free(src_set_fname(detoken(tline, false)));
3802 free_tlist(origline);
3803 return DIRECTIVE_FOUND;
3805 case PP_WHILE:
3806 if (defining != NULL) {
3807 if (defining->type == EXP_WHILE) {
3808 defining->def_depth ++;
3810 return NO_DIRECTIVE_FOUND;
3812 l = NULL;
3813 if ((istk->expansion != NULL) &&
3814 (istk->expansion->emitting == false)) {
3815 j = COND_NEVER;
3816 } else {
3817 l = new_Line();
3818 l->first = copy_Token(tline->next);
3819 j = if_condition(tline->next, i);
3820 tline->next = NULL; /* it got freed */
3821 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
3823 ed = new_ExpDef(EXP_WHILE);
3824 ed->state = j;
3825 ed->cur_depth = 1;
3826 ed->max_depth = DEADMAN_LIMIT;
3827 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
3828 if (ed->ignoring == false) {
3829 ed->line = l;
3830 ed->last = l;
3831 } else if (l != NULL) {
3832 delete_Token(l->first);
3833 nasm_free(l);
3834 l = NULL;
3836 ed->prev = defining;
3837 defining = ed;
3838 free_tlist(origline);
3839 return DIRECTIVE_FOUND;
3841 case PP_ENDWHILE:
3842 if (defining != NULL) {
3843 if (defining->type == EXP_WHILE) {
3844 if (defining->def_depth > 0) {
3845 defining->def_depth --;
3846 return NO_DIRECTIVE_FOUND;
3848 } else {
3849 return NO_DIRECTIVE_FOUND;
3852 if (tline->next != NULL) {
3853 error_precond(ERR_WARNING|ERR_PASS1,
3854 "trailing garbage after `%%endwhile' ignored");
3856 if ((defining == NULL) || (defining->type != EXP_WHILE)) {
3857 error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
3858 return DIRECTIVE_FOUND;
3860 ed = defining;
3861 defining = ed->prev;
3862 if (ed->ignoring == false) {
3863 ed->prev = expansions;
3864 expansions = ed;
3865 ei = new_ExpInv(EXP_WHILE, ed);
3866 ei->current = ed->line->next;
3867 ei->emitting = true;
3868 ei->prev = istk->expansion;
3869 istk->expansion = ei;
3870 } else {
3871 nasm_free(ed);
3873 free_tlist(origline);
3874 return DIRECTIVE_FOUND;
3876 case PP_EXITWHILE:
3877 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3879 * We must search along istk->expansion until we hit a
3880 * while invocation. Then we disable the emitting state(s)
3881 * between exitwhile and endwhile.
3883 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3884 if (ei->type == EXP_WHILE) {
3885 break;
3889 if (ei != NULL) {
3891 * Set all invocations leading back to the while
3892 * invocation to a non-emitting state.
3894 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3895 eei->emitting = false;
3897 eei->emitting = false;
3898 eei->current = NULL;
3899 eei->def->cur_depth = eei->def->max_depth;
3900 } else {
3901 error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
3903 free_tlist(origline);
3904 return DIRECTIVE_FOUND;
3906 case PP_COMMENT:
3907 if (defining != NULL) {
3908 if (defining->type == EXP_COMMENT) {
3909 defining->def_depth ++;
3911 return NO_DIRECTIVE_FOUND;
3913 ed = new_ExpDef(EXP_COMMENT);
3914 ed->ignoring = true;
3915 ed->prev = defining;
3916 defining = ed;
3917 free_tlist(origline);
3918 return DIRECTIVE_FOUND;
3920 case PP_ENDCOMMENT:
3921 if (defining != NULL) {
3922 if (defining->type == EXP_COMMENT) {
3923 if (defining->def_depth > 0) {
3924 defining->def_depth --;
3925 return NO_DIRECTIVE_FOUND;
3927 } else {
3928 return NO_DIRECTIVE_FOUND;
3931 if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
3932 error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
3933 return DIRECTIVE_FOUND;
3935 ed = defining;
3936 defining = ed->prev;
3937 nasm_free(ed);
3938 free_tlist(origline);
3939 return DIRECTIVE_FOUND;
3941 case PP_FINAL:
3942 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3943 if (in_final != false) {
3944 error(ERR_FATAL, "`%%final' cannot be used recursively");
3946 tline = tline->next;
3947 skip_white_(tline);
3948 if (tline == NULL) {
3949 error(ERR_NONFATAL, "`%%final' expects at least one parameter");
3950 } else {
3951 l = new_Line();
3952 l->first = copy_Token(tline);
3953 l->next = finals;
3954 finals = l;
3956 free_tlist(origline);
3957 return DIRECTIVE_FOUND;
3959 default:
3960 error(ERR_FATAL,
3961 "preprocessor directive `%s' not yet implemented",
3962 pp_directives[i]);
3963 return DIRECTIVE_FOUND;
3968 * Ensure that a macro parameter contains a condition code and
3969 * nothing else. Return the condition code index if so, or -1
3970 * otherwise.
3972 static int find_cc(Token * t)
3974 Token *tt;
3975 int i, j, k, m;
3977 if (!t)
3978 return -1; /* Probably a %+ without a space */
3980 skip_white_(t);
3981 if (t->type != TOK_ID)
3982 return -1;
3983 tt = t->next;
3984 skip_white_(tt);
3985 if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
3986 return -1;
3988 i = -1;
3989 j = ARRAY_SIZE(conditions);
3990 while (j - i > 1) {
3991 k = (j + i) / 2;
3992 m = nasm_stricmp(t->text, conditions[k]);
3993 if (m == 0) {
3994 i = k;
3995 j = -2;
3996 break;
3997 } else if (m < 0) {
3998 j = k;
3999 } else
4000 i = k;
4002 if (j != -2)
4003 return -1;
4004 return i;
4007 static bool paste_tokens(Token **head, const struct tokseq_match *m,
4008 int mnum, bool handle_paste_tokens)
4010 Token **tail, *t, *tt;
4011 Token **paste_head;
4012 bool did_paste = false;
4013 char *tmp;
4014 int i;
4016 /* Now handle token pasting... */
4017 paste_head = NULL;
4018 tail = head;
4019 while ((t = *tail) && (tt = t->next)) {
4020 switch (t->type) {
4021 case TOK_WHITESPACE:
4022 if (tt->type == TOK_WHITESPACE) {
4023 /* Zap adjacent whitespace tokens */
4024 t->next = delete_Token(tt);
4025 } else {
4026 /* Do not advance paste_head here */
4027 tail = &t->next;
4029 break;
4030 case TOK_PASTE: /* %+ */
4031 if (handle_paste_tokens) {
4032 /* Zap %+ and whitespace tokens to the right */
4033 while (t && (t->type == TOK_WHITESPACE ||
4034 t->type == TOK_PASTE))
4035 t = *tail = delete_Token(t);
4036 if (!paste_head || !t)
4037 break; /* Nothing to paste with */
4038 tail = paste_head;
4039 t = *tail;
4040 tt = t->next;
4041 while (tok_type_(tt, TOK_WHITESPACE))
4042 tt = t->next = delete_Token(tt);
4043 if (tt) {
4044 tmp = nasm_strcat(t->text, tt->text);
4045 delete_Token(t);
4046 tt = delete_Token(tt);
4047 t = *tail = tokenize(tmp);
4048 nasm_free(tmp);
4049 while (t->next) {
4050 tail = &t->next;
4051 t = t->next;
4053 t->next = tt; /* Attach the remaining token chain */
4054 did_paste = true;
4056 paste_head = tail;
4057 tail = &t->next;
4058 break;
4060 /* else fall through */
4061 default:
4063 * Concatenation of tokens might look nontrivial
4064 * but in real it's pretty simple -- the caller
4065 * prepares the masks of token types to be concatenated
4066 * and we simply find matched sequences and slip
4067 * them together
4069 for (i = 0; i < mnum; i++) {
4070 if (PP_CONCAT_MASK(t->type) & m[i].mask_head) {
4071 size_t len = 0;
4072 char *tmp, *p;
4074 while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
4075 len += strlen(tt->text);
4076 tt = tt->next;
4080 * Now tt points to the first token after
4081 * the potential paste area...
4083 if (tt != t->next) {
4084 /* We have at least two tokens... */
4085 len += strlen(t->text);
4086 p = tmp = nasm_malloc(len+1);
4087 while (t != tt) {
4088 strcpy(p, t->text);
4089 p = strchr(p, '\0');
4090 t = delete_Token(t);
4092 t = *tail = tokenize(tmp);
4093 nasm_free(tmp);
4094 while (t->next) {
4095 tail = &t->next;
4096 t = t->next;
4098 t->next = tt; /* Attach the remaining token chain */
4099 did_paste = true;
4101 paste_head = tail;
4102 tail = &t->next;
4103 break;
4106 if (i >= mnum) { /* no match */
4107 tail = &t->next;
4108 if (!tok_type_(t->next, TOK_WHITESPACE))
4109 paste_head = tail;
4111 break;
4114 return did_paste;
4118 * expands to a list of tokens from %{x:y}
4120 static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
4122 Token *t = tline, **tt, *tm, *head;
4123 char *pos;
4124 int fst, lst, j, i;
4126 pos = strchr(tline->text, ':');
4127 nasm_assert(pos);
4129 lst = atoi(pos + 1);
4130 fst = atoi(tline->text + 1);
4133 * only macros params are accounted so
4134 * if someone passes %0 -- we reject such
4135 * value(s)
4137 if (lst == 0 || fst == 0)
4138 goto err;
4140 /* the values should be sane */
4141 if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
4142 (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
4143 goto err;
4145 fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
4146 lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
4148 /* counted from zero */
4149 fst--, lst--;
4152 * it will be at least one token
4154 tm = ei->params[(fst + ei->rotate) % ei->nparam];
4155 t = new_Token(NULL, tm->type, tm->text, 0);
4156 head = t, tt = &t->next;
4157 if (fst < lst) {
4158 for (i = fst + 1; i <= lst; i++) {
4159 t = new_Token(NULL, TOK_OTHER, ",", 0);
4160 *tt = t, tt = &t->next;
4161 j = (i + ei->rotate) % ei->nparam;
4162 tm = ei->params[j];
4163 t = new_Token(NULL, tm->type, tm->text, 0);
4164 *tt = t, tt = &t->next;
4166 } else {
4167 for (i = fst - 1; i >= lst; i--) {
4168 t = new_Token(NULL, TOK_OTHER, ",", 0);
4169 *tt = t, tt = &t->next;
4170 j = (i + ei->rotate) % ei->nparam;
4171 tm = ei->params[j];
4172 t = new_Token(NULL, tm->type, tm->text, 0);
4173 *tt = t, tt = &t->next;
4177 *last = tt;
4178 return head;
4180 err:
4181 error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range",
4182 &tline->text[1]);
4183 return tline;
4187 * Expand MMacro-local things: parameter references (%0, %n, %+n,
4188 * %-n) and MMacro-local identifiers (%%foo) as well as
4189 * macro indirection (%[...]) and range (%{..:..}).
4191 static Token *expand_mmac_params(Token * tline)
4193 Token *t, *tt, **tail, *thead;
4194 bool changed = false;
4195 char *pos;
4197 tail = &thead;
4198 thead = NULL;
4200 while (tline) {
4201 if (tline->type == TOK_PREPROC_ID &&
4202 (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
4203 (tline->text[1] >= '0' && tline->text[1] <= '9') ||
4204 tline->text[1] == '%')) {
4205 char *text = NULL;
4206 int type = 0, cc; /* type = 0 to placate optimisers */
4207 char tmpbuf[30];
4208 unsigned int n;
4209 int i;
4210 ExpInv *ei;
4212 t = tline;
4213 tline = tline->next;
4215 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
4216 if (ei->type == EXP_MMACRO) {
4217 break;
4220 if (ei == NULL) {
4221 error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
4222 } else {
4223 pos = strchr(t->text, ':');
4224 if (!pos) {
4225 switch (t->text[1]) {
4227 * We have to make a substitution of one of the
4228 * forms %1, %-1, %+1, %%foo, %0.
4230 case '0':
4231 if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
4232 type = TOK_ID;
4233 text = nasm_strdup(ei->label_text);
4234 } else {
4235 type = TOK_NUMBER;
4236 snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
4237 text = nasm_strdup(tmpbuf);
4239 break;
4240 case '%':
4241 type = TOK_ID;
4242 snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
4243 ei->unique);
4244 text = nasm_strcat(tmpbuf, t->text + 2);
4245 break;
4246 case '-':
4247 n = atoi(t->text + 2) - 1;
4248 if (n >= ei->nparam)
4249 tt = NULL;
4250 else {
4251 if (ei->nparam > 1)
4252 n = (n + ei->rotate) % ei->nparam;
4253 tt = ei->params[n];
4255 cc = find_cc(tt);
4256 if (cc == -1) {
4257 error(ERR_NONFATAL,
4258 "macro parameter %d is not a condition code",
4259 n + 1);
4260 text = NULL;
4261 } else {
4262 type = TOK_ID;
4263 if (inverse_ccs[cc] == -1) {
4264 error(ERR_NONFATAL,
4265 "condition code `%s' is not invertible",
4266 conditions[cc]);
4267 text = NULL;
4268 } else
4269 text = nasm_strdup(conditions[inverse_ccs[cc]]);
4271 break;
4272 case '+':
4273 n = atoi(t->text + 2) - 1;
4274 if (n >= ei->nparam)
4275 tt = NULL;
4276 else {
4277 if (ei->nparam > 1)
4278 n = (n + ei->rotate) % ei->nparam;
4279 tt = ei->params[n];
4281 cc = find_cc(tt);
4282 if (cc == -1) {
4283 error(ERR_NONFATAL,
4284 "macro parameter %d is not a condition code",
4285 n + 1);
4286 text = NULL;
4287 } else {
4288 type = TOK_ID;
4289 text = nasm_strdup(conditions[cc]);
4291 break;
4292 default:
4293 n = atoi(t->text + 1) - 1;
4294 if (n >= ei->nparam)
4295 tt = NULL;
4296 else {
4297 if (ei->nparam > 1)
4298 n = (n + ei->rotate) % ei->nparam;
4299 tt = ei->params[n];
4301 if (tt) {
4302 for (i = 0; i < ei->paramlen[n]; i++) {
4303 *tail = new_Token(NULL, tt->type, tt->text, 0);
4304 tail = &(*tail)->next;
4305 tt = tt->next;
4308 text = NULL; /* we've done it here */
4309 break;
4311 } else {
4313 * seems we have a parameters range here
4315 Token *head, **last;
4316 head = expand_mmac_params_range(ei, t, &last);
4317 if (head != t) {
4318 *tail = head;
4319 *last = tline;
4320 tline = head;
4321 text = NULL;
4325 if (!text) {
4326 delete_Token(t);
4327 } else {
4328 *tail = t;
4329 tail = &t->next;
4330 t->type = type;
4331 nasm_free(t->text);
4332 t->text = text;
4333 t->a.mac = NULL;
4335 changed = true;
4336 continue;
4337 } else if (tline->type == TOK_INDIRECT) {
4338 t = tline;
4339 tline = tline->next;
4340 tt = tokenize(t->text);
4341 tt = expand_mmac_params(tt);
4342 tt = expand_smacro(tt);
4343 *tail = tt;
4344 while (tt) {
4345 tt->a.mac = NULL; /* Necessary? */
4346 tail = &tt->next;
4347 tt = tt->next;
4349 delete_Token(t);
4350 changed = true;
4351 } else {
4352 t = *tail = tline;
4353 tline = tline->next;
4354 t->a.mac = NULL;
4355 tail = &t->next;
4358 *tail = NULL;
4360 if (changed)
4361 paste_tokens(&thead, pp_concat_match,
4362 ARRAY_SIZE(pp_concat_match),
4363 false);
4365 return thead;
4369 * Expand all single-line macro calls made in the given line.
4370 * Return the expanded version of the line. The original is deemed
4371 * to be destroyed in the process. (In reality we'll just move
4372 * Tokens from input to output a lot of the time, rather than
4373 * actually bothering to destroy and replicate.)
4376 static Token *expand_smacro(Token * tline)
4378 Token *t, *tt, *mstart, **tail, *thead;
4379 SMacro *head = NULL, *m;
4380 Token **params;
4381 int *paramsize;
4382 unsigned int nparam, sparam;
4383 int brackets;
4384 Token *org_tline = tline;
4385 Context *ctx;
4386 const char *mname;
4387 int deadman = DEADMAN_LIMIT;
4388 bool expanded;
4391 * Trick: we should avoid changing the start token pointer since it can
4392 * be contained in "next" field of other token. Because of this
4393 * we allocate a copy of first token and work with it; at the end of
4394 * routine we copy it back
4396 if (org_tline) {
4397 tline = new_Token(org_tline->next, org_tline->type,
4398 org_tline->text, 0);
4399 tline->a.mac = org_tline->a.mac;
4400 nasm_free(org_tline->text);
4401 org_tline->text = NULL;
4404 expanded = true; /* Always expand %+ at least once */
4406 again:
4407 thead = NULL;
4408 tail = &thead;
4410 while (tline) { /* main token loop */
4411 if (!--deadman) {
4412 error(ERR_NONFATAL, "interminable macro recursion");
4413 goto err;
4416 if ((mname = tline->text)) {
4417 /* if this token is a local macro, look in local context */
4418 if (tline->type == TOK_ID) {
4419 head = (SMacro *)hash_findix(&smacros, mname);
4420 } else if (tline->type == TOK_PREPROC_ID) {
4421 ctx = get_ctx(mname, &mname, false);
4422 head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
4423 } else
4424 head = NULL;
4427 * We've hit an identifier. As in is_mmacro below, we first
4428 * check whether the identifier is a single-line macro at
4429 * all, then think about checking for parameters if
4430 * necessary.
4432 list_for_each(m, head)
4433 if (!mstrcmp(m->name, mname, m->casesense))
4434 break;
4435 if (m) {
4436 mstart = tline;
4437 params = NULL;
4438 paramsize = NULL;
4439 if (m->nparam == 0) {
4441 * Simple case: the macro is parameterless. Discard the
4442 * one token that the macro call took, and push the
4443 * expansion back on the to-do stack.
4445 if (!m->expansion) {
4446 if (!strcmp("__FILE__", m->name)) {
4447 int32_t num = 0;
4448 char *file = NULL;
4449 src_get(&num, &file);
4450 tline->text = nasm_quote(file, strlen(file));
4451 tline->type = TOK_STRING;
4452 nasm_free(file);
4453 continue;
4455 if (!strcmp("__LINE__", m->name)) {
4456 nasm_free(tline->text);
4457 make_tok_num(tline, src_get_linnum());
4458 continue;
4460 if (!strcmp("__BITS__", m->name)) {
4461 nasm_free(tline->text);
4462 make_tok_num(tline, globalbits);
4463 continue;
4465 tline = delete_Token(tline);
4466 continue;
4468 } else {
4470 * Complicated case: at least one macro with this name
4471 * exists and takes parameters. We must find the
4472 * parameters in the call, count them, find the SMacro
4473 * that corresponds to that form of the macro call, and
4474 * substitute for the parameters when we expand. What a
4475 * pain.
4477 /*tline = tline->next;
4478 skip_white_(tline); */
4479 do {
4480 t = tline->next;
4481 while (tok_type_(t, TOK_SMAC_END)) {
4482 t->a.mac->in_progress = false;
4483 t->text = NULL;
4484 t = tline->next = delete_Token(t);
4486 tline = t;
4487 } while (tok_type_(tline, TOK_WHITESPACE));
4488 if (!tok_is_(tline, "(")) {
4490 * This macro wasn't called with parameters: ignore
4491 * the call. (Behaviour borrowed from gnu cpp.)
4493 tline = mstart;
4494 m = NULL;
4495 } else {
4496 int paren = 0;
4497 int white = 0;
4498 brackets = 0;
4499 nparam = 0;
4500 sparam = PARAM_DELTA;
4501 params = nasm_malloc(sparam * sizeof(Token *));
4502 params[0] = tline->next;
4503 paramsize = nasm_malloc(sparam * sizeof(int));
4504 paramsize[0] = 0;
4505 while (true) { /* parameter loop */
4507 * For some unusual expansions
4508 * which concatenates function call
4510 t = tline->next;
4511 while (tok_type_(t, TOK_SMAC_END)) {
4512 t->a.mac->in_progress = false;
4513 t->text = NULL;
4514 t = tline->next = delete_Token(t);
4516 tline = t;
4518 if (!tline) {
4519 error(ERR_NONFATAL,
4520 "macro call expects terminating `)'");
4521 break;
4523 if (tline->type == TOK_WHITESPACE
4524 && brackets <= 0) {
4525 if (paramsize[nparam])
4526 white++;
4527 else
4528 params[nparam] = tline->next;
4529 continue; /* parameter loop */
4531 if (tline->type == TOK_OTHER
4532 && tline->text[1] == 0) {
4533 char ch = tline->text[0];
4534 if (ch == ',' && !paren && brackets <= 0) {
4535 if (++nparam >= sparam) {
4536 sparam += PARAM_DELTA;
4537 params = nasm_realloc(params,
4538 sparam * sizeof(Token *));
4539 paramsize = nasm_realloc(paramsize,
4540 sparam * sizeof(int));
4542 params[nparam] = tline->next;
4543 paramsize[nparam] = 0;
4544 white = 0;
4545 continue; /* parameter loop */
4547 if (ch == '{' &&
4548 (brackets > 0 || (brackets == 0 &&
4549 !paramsize[nparam])))
4551 if (!(brackets++)) {
4552 params[nparam] = tline->next;
4553 continue; /* parameter loop */
4556 if (ch == '}' && brackets > 0)
4557 if (--brackets == 0) {
4558 brackets = -1;
4559 continue; /* parameter loop */
4561 if (ch == '(' && !brackets)
4562 paren++;
4563 if (ch == ')' && brackets <= 0)
4564 if (--paren < 0)
4565 break;
4567 if (brackets < 0) {
4568 brackets = 0;
4569 error(ERR_NONFATAL, "braces do not "
4570 "enclose all of macro parameter");
4572 paramsize[nparam] += white + 1;
4573 white = 0;
4574 } /* parameter loop */
4575 nparam++;
4576 while (m && (m->nparam != nparam ||
4577 mstrcmp(m->name, mname,
4578 m->casesense)))
4579 m = m->next;
4580 if (!m)
4581 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4582 "macro `%s' exists, "
4583 "but not taking %d parameters",
4584 mstart->text, nparam);
4587 if (m && m->in_progress)
4588 m = NULL;
4589 if (!m) { /* in progess or didn't find '(' or wrong nparam */
4591 * Design question: should we handle !tline, which
4592 * indicates missing ')' here, or expand those
4593 * macros anyway, which requires the (t) test a few
4594 * lines down?
4596 nasm_free(params);
4597 nasm_free(paramsize);
4598 tline = mstart;
4599 } else {
4601 * Expand the macro: we are placed on the last token of the
4602 * call, so that we can easily split the call from the
4603 * following tokens. We also start by pushing an SMAC_END
4604 * token for the cycle removal.
4606 t = tline;
4607 if (t) {
4608 tline = t->next;
4609 t->next = NULL;
4611 tt = new_Token(tline, TOK_SMAC_END, NULL, 0);
4612 tt->a.mac = m;
4613 m->in_progress = true;
4614 tline = tt;
4615 list_for_each(t, m->expansion) {
4616 if (t->type >= TOK_SMAC_PARAM) {
4617 Token *pcopy = tline, **ptail = &pcopy;
4618 Token *ttt, *pt;
4619 int i;
4621 ttt = params[t->type - TOK_SMAC_PARAM];
4622 i = paramsize[t->type - TOK_SMAC_PARAM];
4623 while (--i >= 0) {
4624 pt = *ptail = new_Token(tline, ttt->type,
4625 ttt->text, 0);
4626 ptail = &pt->next;
4627 ttt = ttt->next;
4629 tline = pcopy;
4630 } else if (t->type == TOK_PREPROC_Q) {
4631 tt = new_Token(tline, TOK_ID, mname, 0);
4632 tline = tt;
4633 } else if (t->type == TOK_PREPROC_QQ) {
4634 tt = new_Token(tline, TOK_ID, m->name, 0);
4635 tline = tt;
4636 } else {
4637 tt = new_Token(tline, t->type, t->text, 0);
4638 tline = tt;
4643 * Having done that, get rid of the macro call, and clean
4644 * up the parameters.
4646 nasm_free(params);
4647 nasm_free(paramsize);
4648 free_tlist(mstart);
4649 expanded = true;
4650 continue; /* main token loop */
4655 if (tline->type == TOK_SMAC_END) {
4656 tline->a.mac->in_progress = false;
4657 tline = delete_Token(tline);
4658 } else {
4659 t = *tail = tline;
4660 tline = tline->next;
4661 t->a.mac = NULL;
4662 t->next = NULL;
4663 tail = &t->next;
4668 * Now scan the entire line and look for successive TOK_IDs that resulted
4669 * after expansion (they can't be produced by tokenize()). The successive
4670 * TOK_IDs should be concatenated.
4671 * Also we look for %+ tokens and concatenate the tokens before and after
4672 * them (without white spaces in between).
4674 if (expanded) {
4675 if (paste_tokens(&thead, pp_concat_match,
4676 ARRAY_SIZE(pp_concat_match),
4677 true)) {
4679 * If we concatenated something, *and* we had previously expanded
4680 * an actual macro, scan the lines again for macros...
4682 tline = thead;
4683 expanded = false;
4684 goto again;
4688 err:
4689 if (org_tline) {
4690 if (thead) {
4691 *org_tline = *thead;
4692 /* since we just gave text to org_line, don't free it */
4693 thead->text = NULL;
4694 delete_Token(thead);
4695 } else {
4696 /* the expression expanded to empty line;
4697 we can't return NULL for some reasons
4698 we just set the line to a single WHITESPACE token. */
4699 memset(org_tline, 0, sizeof(*org_tline));
4700 org_tline->text = NULL;
4701 org_tline->type = TOK_WHITESPACE;
4703 thead = org_tline;
4706 return thead;
4710 * Similar to expand_smacro but used exclusively with macro identifiers
4711 * right before they are fetched in. The reason is that there can be
4712 * identifiers consisting of several subparts. We consider that if there
4713 * are more than one element forming the name, user wants a expansion,
4714 * otherwise it will be left as-is. Example:
4716 * %define %$abc cde
4718 * the identifier %$abc will be left as-is so that the handler for %define
4719 * will suck it and define the corresponding value. Other case:
4721 * %define _%$abc cde
4723 * In this case user wants name to be expanded *before* %define starts
4724 * working, so we'll expand %$abc into something (if it has a value;
4725 * otherwise it will be left as-is) then concatenate all successive
4726 * PP_IDs into one.
4728 static Token *expand_id(Token * tline)
4730 Token *cur, *oldnext = NULL;
4732 if (!tline || !tline->next)
4733 return tline;
4735 cur = tline;
4736 while (cur->next &&
4737 (cur->next->type == TOK_ID ||
4738 cur->next->type == TOK_PREPROC_ID
4739 || cur->next->type == TOK_NUMBER))
4740 cur = cur->next;
4742 /* If identifier consists of just one token, don't expand */
4743 if (cur == tline)
4744 return tline;
4746 if (cur) {
4747 oldnext = cur->next; /* Detach the tail past identifier */
4748 cur->next = NULL; /* so that expand_smacro stops here */
4751 tline = expand_smacro(tline);
4753 if (cur) {
4754 /* expand_smacro possibly changhed tline; re-scan for EOL */
4755 cur = tline;
4756 while (cur && cur->next)
4757 cur = cur->next;
4758 if (cur)
4759 cur->next = oldnext;
4762 return tline;
4766 * Determine whether the given line constitutes a multi-line macro
4767 * call, and return the ExpDef structure called if so. Doesn't have
4768 * to check for an initial label - that's taken care of in
4769 * expand_mmacro - but must check numbers of parameters. Guaranteed
4770 * to be called with tline->type == TOK_ID, so the putative macro
4771 * name is easy to find.
4773 static ExpDef *is_mmacro(Token * tline, Token *** params_array)
4775 ExpDef *head, *ed;
4776 Token **params;
4777 int nparam;
4779 head = (ExpDef *) hash_findix(&expdefs, tline->text);
4782 * Efficiency: first we see if any macro exists with the given
4783 * name. If not, we can return NULL immediately. _Then_ we
4784 * count the parameters, and then we look further along the
4785 * list if necessary to find the proper ExpDef.
4787 list_for_each(ed, head)
4788 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4789 break;
4790 if (!ed)
4791 return NULL;
4794 * OK, we have a potential macro. Count and demarcate the
4795 * parameters.
4797 count_mmac_params(tline->next, &nparam, &params);
4800 * So we know how many parameters we've got. Find the ExpDef
4801 * structure that handles this number.
4803 while (ed) {
4804 if (ed->nparam_min <= nparam
4805 && (ed->plus || nparam <= ed->nparam_max)) {
4807 * It's right, and we can use it. Add its default
4808 * parameters to the end of our list if necessary.
4810 if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
4811 params =
4812 nasm_realloc(params,
4813 ((ed->nparam_min + ed->ndefs +
4814 1) * sizeof(*params)));
4815 while (nparam < ed->nparam_min + ed->ndefs) {
4816 params[nparam] = ed->defaults[nparam - ed->nparam_min];
4817 nparam++;
4821 * If we've gone over the maximum parameter count (and
4822 * we're in Plus mode), ignore parameters beyond
4823 * nparam_max.
4825 if (ed->plus && nparam > ed->nparam_max)
4826 nparam = ed->nparam_max;
4828 * Then terminate the parameter list, and leave.
4830 if (!params) { /* need this special case */
4831 params = nasm_malloc(sizeof(*params));
4832 nparam = 0;
4834 params[nparam] = NULL;
4835 *params_array = params;
4836 return ed;
4839 * This one wasn't right: look for the next one with the
4840 * same name.
4842 list_for_each(ed, ed->next)
4843 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4844 break;
4848 * After all that, we didn't find one with the right number of
4849 * parameters. Issue a warning, and fail to expand the macro.
4851 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4852 "macro `%s' exists, but not taking %d parameters",
4853 tline->text, nparam);
4854 nasm_free(params);
4855 return NULL;
4859 * Expand the multi-line macro call made by the given line, if
4860 * there is one to be expanded. If there is, push the expansion on
4861 * istk->expansion and return true. Otherwise return false.
4863 static bool expand_mmacro(Token * tline)
4865 Token *label = NULL;
4866 int dont_prepend = 0;
4867 Token **params, *t;
4868 Line *l = NULL;
4869 ExpDef *ed;
4870 ExpInv *ei;
4871 int i, nparam, *paramlen;
4872 const char *mname;
4874 t = tline;
4875 skip_white_(t);
4876 /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
4877 if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
4878 return false;
4879 ed = is_mmacro(t, &params);
4880 if (ed != NULL) {
4881 mname = t->text;
4882 } else {
4883 Token *last;
4885 * We have an id which isn't a macro call. We'll assume
4886 * it might be a label; we'll also check to see if a
4887 * colon follows it. Then, if there's another id after
4888 * that lot, we'll check it again for macro-hood.
4890 label = last = t;
4891 t = t->next;
4892 if (tok_type_(t, TOK_WHITESPACE))
4893 last = t, t = t->next;
4894 if (tok_is_(t, ":")) {
4895 dont_prepend = 1;
4896 last = t, t = t->next;
4897 if (tok_type_(t, TOK_WHITESPACE))
4898 last = t, t = t->next;
4900 if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
4901 return false;
4902 last->next = NULL;
4903 mname = t->text;
4904 tline = t;
4908 * Fix up the parameters: this involves stripping leading and
4909 * trailing whitespace, then stripping braces if they are
4910 * present.
4912 for (nparam = 0; params[nparam]; nparam++) ;
4913 paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
4915 for (i = 0; params[i]; i++) {
4916 int brace = false;
4917 int comma = (!ed->plus || i < nparam - 1);
4919 t = params[i];
4920 skip_white_(t);
4921 if (tok_is_(t, "{"))
4922 t = t->next, brace = true, comma = false;
4923 params[i] = t;
4924 paramlen[i] = 0;
4925 while (t) {
4926 if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
4927 break; /* ... because we have hit a comma */
4928 if (comma && t->type == TOK_WHITESPACE
4929 && tok_is_(t->next, ","))
4930 break; /* ... or a space then a comma */
4931 if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
4932 break; /* ... or a brace */
4933 t = t->next;
4934 paramlen[i]++;
4938 if (ed->cur_depth >= ed->max_depth) {
4939 if (ed->max_depth > 1) {
4940 error(ERR_WARNING,
4941 "reached maximum macro recursion depth of %i for %s",
4942 ed->max_depth,ed->name);
4944 return false;
4945 } else {
4946 ed->cur_depth ++;
4950 * OK, we have found a ExpDef structure representing a
4951 * previously defined mmacro. Create an expansion invocation
4952 * and point it back to the expansion definition. Substitution of
4953 * parameter tokens and macro-local tokens doesn't get done
4954 * until the single-line macro substitution process; this is
4955 * because delaying them allows us to change the semantics
4956 * later through %rotate.
4958 ei = new_ExpInv(EXP_MMACRO, ed);
4959 ei->name = nasm_strdup(mname);
4960 //ei->label = label;
4961 //ei->label_text = detoken(label, false);
4962 ei->current = ed->line;
4963 ei->emitting = true;
4964 //ei->iline = tline;
4965 ei->params = params;
4966 ei->nparam = nparam;
4967 ei->rotate = 0;
4968 ei->paramlen = paramlen;
4969 ei->lineno = 0;
4971 ei->prev = istk->expansion;
4972 istk->expansion = ei;
4975 * Special case: detect %00 on first invocation; if found,
4976 * avoid emitting any labels that precede the mmacro call.
4977 * ed->prepend is set to -1 when %00 is detected, else 1.
4979 if (ed->prepend == 0) {
4980 for (l = ed->line; l != NULL; l = l->next) {
4981 for (t = l->first; t != NULL; t = t->next) {
4982 if ((t->type == TOK_PREPROC_ID) &&
4983 (strlen(t->text) == 3) &&
4984 (t->text[1] == '0') && (t->text[2] == '0')) {
4985 dont_prepend = -1;
4986 break;
4989 if (dont_prepend < 0) {
4990 break;
4993 ed->prepend = ((dont_prepend < 0) ? -1 : 1);
4997 * If we had a label, push it on as the first line of
4998 * the macro expansion.
5000 if (label != NULL) {
5001 if (ed->prepend < 0) {
5002 ei->label_text = detoken(label, false);
5003 } else {
5004 if (dont_prepend == 0) {
5005 t = label;
5006 while (t->next != NULL) {
5007 t = t->next;
5009 t->next = new_Token(NULL, TOK_OTHER, ":", 0);
5011 l = new_Line();
5012 l->first = copy_Token(label);
5013 l->next = ei->current;
5014 ei->current = l;
5018 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
5020 istk->mmac_depth++;
5021 return true;
5024 /* The function that actually does the error reporting */
5025 static void verror(int severity, const char *fmt, va_list arg)
5027 char buff[1024];
5029 vsnprintf(buff, sizeof(buff), fmt, arg);
5031 if (istk && istk->mmac_depth > 0) {
5032 ExpInv *ei = istk->expansion;
5033 int lineno = ei->lineno;
5034 while (ei) {
5035 if (ei->type == EXP_MMACRO)
5036 break;
5037 lineno += ei->relno;
5038 ei = ei->prev;
5040 nasm_error(severity, "(%s:%d) %s", ei->def->name,
5041 lineno, buff);
5042 } else
5043 nasm_error(severity, "%s", buff);
5047 * Since preprocessor always operate only on the line that didn't
5048 * arrived yet, we should always use ERR_OFFBY1.
5050 static void error(int severity, const char *fmt, ...)
5052 va_list arg;
5053 va_start(arg, fmt);
5054 verror(severity, fmt, arg);
5055 va_end(arg);
5059 * Because %else etc are evaluated in the state context
5060 * of the previous branch, errors might get lost with error():
5061 * %if 0 ... %else trailing garbage ... %endif
5062 * So %else etc should report errors with this function.
5064 static void error_precond(int severity, const char *fmt, ...)
5066 va_list arg;
5068 /* Only ignore the error if it's really in a dead branch */
5069 if ((istk != NULL) &&
5070 (istk->expansion != NULL) &&
5071 (istk->expansion->type == EXP_IF) &&
5072 (istk->expansion->def->state == COND_NEVER))
5073 return;
5075 va_start(arg, fmt);
5076 verror(severity, fmt, arg);
5077 va_end(arg);
5080 static void
5081 pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
5083 Token *t;
5085 cstk = NULL;
5086 istk = nasm_zalloc(sizeof(Include));
5087 istk->fp = fopen(file, "r");
5088 src_set_fname(nasm_strdup(file));
5089 src_set_linnum(0);
5090 istk->lineinc = 1;
5091 if (!istk->fp)
5092 error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
5093 file);
5094 defining = NULL;
5095 finals = NULL;
5096 in_final = false;
5097 nested_mac_count = 0;
5098 nested_rep_count = 0;
5099 init_macros();
5100 unique = 0;
5101 if (tasm_compatible_mode) {
5102 stdmacpos = nasm_stdmac;
5103 } else {
5104 stdmacpos = nasm_stdmac_after_tasm;
5106 any_extrastdmac = extrastdmac && *extrastdmac;
5107 do_predef = true;
5108 list = listgen;
5111 * 0 for dependencies, 1 for preparatory passes, 2 for final pass.
5112 * The caller, however, will also pass in 3 for preprocess-only so
5113 * we can set __PASS__ accordingly.
5115 pass = apass > 2 ? 2 : apass;
5117 dephead = deptail = deplist;
5118 if (deplist) {
5119 StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
5120 sl->next = NULL;
5121 strcpy(sl->str, file);
5122 *deptail = sl;
5123 deptail = &sl->next;
5127 * Define the __PASS__ macro. This is defined here unlike
5128 * all the other builtins, because it is special -- it varies between
5129 * passes.
5131 t = nasm_zalloc(sizeof(*t));
5132 make_tok_num(t, apass);
5133 define_smacro(NULL, "__PASS__", true, 0, t);
5136 static char *pp_getline(void)
5138 char *line;
5139 Token *tline;
5140 ExpDef *ed;
5141 ExpInv *ei;
5142 Line *l;
5143 int j;
5145 while (1) {
5147 * Fetch a tokenized line, either from the expansion
5148 * buffer or from the input file.
5150 tline = NULL;
5152 while (1) { /* until we get a line we can use */
5154 * Fetch a tokenized line from the expansion buffer
5156 if (istk->expansion != NULL) {
5157 ei = istk->expansion;
5158 if (ei->current != NULL) {
5159 if (ei->emitting == false) {
5160 ei->current = NULL;
5161 continue;
5163 l = ei->current;
5164 ei->current = l->next;
5165 ei->lineno++;
5166 tline = copy_Token(l->first);
5167 if (((ei->type == EXP_REP) ||
5168 (ei->type == EXP_MMACRO) ||
5169 (ei->type == EXP_WHILE))
5170 && (ei->def->nolist == false)) {
5171 char *p = detoken(tline, false);
5172 list->line(LIST_MACRO, p);
5173 nasm_free(p);
5175 if (ei->linnum > -1) {
5176 src_set_linnum(src_get_linnum() + 1);
5178 break;
5179 } else if ((ei->type == EXP_REP) &&
5180 (ei->def->cur_depth < ei->def->max_depth)) {
5181 ei->def->cur_depth ++;
5182 ei->current = ei->def->line;
5183 ei->lineno = 0;
5184 continue;
5185 } else if ((ei->type == EXP_WHILE) &&
5186 (ei->def->cur_depth < ei->def->max_depth)) {
5187 ei->current = ei->def->line;
5188 ei->lineno = 0;
5189 tline = copy_Token(ei->current->first);
5190 j = if_condition(tline, PP_WHILE);
5191 tline = NULL;
5192 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
5193 if (j == COND_IF_TRUE) {
5194 ei->current = ei->current->next;
5195 ei->def->cur_depth ++;
5196 } else {
5197 ei->emitting = false;
5198 ei->current = NULL;
5199 ei->def->cur_depth = ei->def->max_depth;
5201 continue;
5202 } else {
5203 istk->expansion = ei->prev;
5204 ed = ei->def;
5205 if (ed != NULL) {
5206 if ((ei->emitting == true) &&
5207 (ed->max_depth == DEADMAN_LIMIT) &&
5208 (ed->cur_depth == DEADMAN_LIMIT)
5210 error(ERR_FATAL, "runaway expansion detected, aborting");
5212 if (ed->cur_depth > 0) {
5213 ed->cur_depth --;
5214 } else if (ed->type != EXP_MMACRO) {
5215 expansions = ed->prev;
5216 free_expdef(ed);
5218 if ((ei->type == EXP_REP) ||
5219 (ei->type == EXP_MMACRO) ||
5220 (ei->type == EXP_WHILE)) {
5221 list->downlevel(LIST_MACRO);
5222 if (ei->type == EXP_MMACRO) {
5223 istk->mmac_depth--;
5227 if (ei->linnum > -1) {
5228 src_set_linnum(ei->linnum);
5230 free_expinv(ei);
5231 continue;
5236 * Read in line from input and tokenize
5238 line = read_line();
5239 if (line) { /* from the current input file */
5240 line = prepreproc(line);
5241 tline = tokenize(line);
5242 nasm_free(line);
5243 break;
5247 * The current file has ended; work down the istk
5250 Include *i = istk;
5251 fclose(i->fp);
5252 if (i->expansion != NULL) {
5253 error(ERR_FATAL,
5254 "end of file while still in an expansion");
5256 /* only set line and file name if there's a next node */
5257 if (i->next) {
5258 src_set_linnum(i->lineno);
5259 nasm_free(src_set_fname(nasm_strdup(i->fname)));
5261 if ((i->next == NULL) && (finals != NULL)) {
5262 in_final = true;
5263 ei = new_ExpInv(EXP_FINAL, NULL);
5264 ei->emitting = true;
5265 ei->current = finals;
5266 istk->expansion = ei;
5267 finals = NULL;
5268 continue;
5270 istk = i->next;
5271 list->downlevel(LIST_INCLUDE);
5272 nasm_free(i);
5273 if (istk == NULL) {
5274 if (finals != NULL) {
5275 in_final = true;
5276 } else {
5277 return NULL;
5280 continue;
5284 if (defining == NULL) {
5285 tline = expand_mmac_params(tline);
5289 * Check the line to see if it's a preprocessor directive.
5291 if (do_directive(tline) == DIRECTIVE_FOUND) {
5292 continue;
5293 } else if (defining != NULL) {
5295 * We're defining an expansion. We emit nothing at all,
5296 * and just shove the tokenized line on to the definition.
5298 if (defining->ignoring == false) {
5299 Line *l = new_Line();
5300 l->first = tline;
5301 if (defining->line == NULL) {
5302 defining->line = l;
5303 defining->last = l;
5304 } else {
5305 defining->last->next = l;
5306 defining->last = l;
5308 } else {
5309 free_tlist(tline);
5311 defining->linecount++;
5312 continue;
5313 } else if ((istk->expansion != NULL) &&
5314 (istk->expansion->emitting != true)) {
5316 * We're in a non-emitting branch of an expansion.
5317 * Emit nothing at all, not even a blank line: when we
5318 * emerge from the expansion we'll give a line-number
5319 * directive so we keep our place correctly.
5321 free_tlist(tline);
5322 continue;
5323 } else {
5324 tline = expand_smacro(tline);
5325 if (expand_mmacro(tline) != true) {
5327 * De-tokenize the line again, and emit it.
5329 line = detoken(tline, true);
5330 free_tlist(tline);
5331 break;
5332 } else {
5333 continue;
5337 return line;
5340 static void pp_cleanup(int pass)
5342 if (defining != NULL) {
5343 error(ERR_NONFATAL, "end of file while still defining an expansion");
5344 while (defining != NULL) {
5345 ExpDef *ed = defining;
5346 defining = ed->prev;
5347 free_expdef(ed);
5349 defining = NULL;
5351 while (cstk != NULL)
5352 ctx_pop();
5353 free_macros();
5354 while (istk != NULL) {
5355 Include *i = istk;
5356 istk = istk->next;
5357 fclose(i->fp);
5358 nasm_free(i->fname);
5359 while (i->expansion != NULL) {
5360 ExpInv *ei = i->expansion;
5361 i->expansion = ei->prev;
5362 free_expinv(ei);
5364 nasm_free(i);
5366 while (cstk)
5367 ctx_pop();
5368 nasm_free(src_set_fname(NULL));
5369 if (pass == 0) {
5370 IncPath *i;
5371 free_llist(predef);
5372 delete_Blocks();
5373 while ((i = ipath)) {
5374 ipath = i->next;
5375 if (i->path)
5376 nasm_free(i->path);
5377 nasm_free(i);
5382 void pp_include_path(char *path)
5384 IncPath *i = nasm_zalloc(sizeof(IncPath));
5386 if (path)
5387 i->path = nasm_strdup(path);
5389 if (ipath) {
5390 IncPath *j = ipath;
5391 while (j->next)
5392 j = j->next;
5393 j->next = i;
5394 } else {
5395 ipath = i;
5399 void pp_pre_include(char *fname)
5401 Token *inc, *space, *name;
5402 Line *l;
5404 name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
5405 space = new_Token(name, TOK_WHITESPACE, NULL, 0);
5406 inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
5408 l = new_Line();
5409 l->next = predef;
5410 l->first = inc;
5411 predef = l;
5414 void pp_pre_define(char *definition)
5416 Token *def, *space;
5417 Line *l;
5418 char *equals;
5420 equals = strchr(definition, '=');
5421 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5422 def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
5423 if (equals)
5424 *equals = ' ';
5425 space->next = tokenize(definition);
5426 if (equals)
5427 *equals = '=';
5429 l = new_Line();
5430 l->next = predef;
5431 l->first = def;
5432 predef = l;
5435 void pp_pre_undefine(char *definition)
5437 Token *def, *space;
5438 Line *l;
5440 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5441 def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
5442 space->next = tokenize(definition);
5444 l = new_Line();
5445 l->next = predef;
5446 l->first = def;
5447 predef = l;
5451 * This function is used to assist with "runtime" preprocessor
5452 * directives, e.g. pp_runtime("%define __BITS__ 64");
5454 * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
5455 * PASS A VALID STRING TO THIS FUNCTION!!!!!
5458 void pp_runtime(char *definition)
5460 Token *def;
5462 def = tokenize(definition);
5463 if (do_directive(def) == NO_DIRECTIVE_FOUND)
5464 free_tlist(def);
5468 void pp_extra_stdmac(macros_t *macros)
5470 extrastdmac = macros;
5473 static void make_tok_num(Token * tok, int64_t val)
5475 char numbuf[20];
5476 snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
5477 tok->text = nasm_strdup(numbuf);
5478 tok->type = TOK_NUMBER;
5481 Preproc nasmpp = {
5482 pp_reset,
5483 pp_getline,
5484 pp_cleanup