home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / NASM.C < prev    next >
C/C++ Source or Header  |  1997-11-02  |  29KB  |  1,108 lines

  1. /* The Netwide Assembler main program module
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. #include "nasm.h"
  16. #include "nasmlib.h"
  17. #include "preproc.h"
  18. #include "parser.h"
  19. #include "eval.h"
  20. #include "assemble.h"
  21. #include "labels.h"
  22. #include "outform.h"
  23. #include "listing.h"
  24.  
  25. static void report_error (int, char *, ...);
  26. static void parse_cmdline (int, char **);
  27. static void assemble_file (char *);
  28. static int getkw (char *buf, char **value);
  29. static void register_output_formats(void);
  30. static void usage(void);
  31.  
  32. static char *obuf;
  33. static char inname[FILENAME_MAX];
  34. static char outname[FILENAME_MAX];
  35. static char listname[FILENAME_MAX];
  36. static int lineno;               /* for error reporting */
  37. static int lineinc;               /* set by [LINE] or [ONELINE] */
  38. static int globallineno;           /* for forward-reference tracking */
  39. static int pass;
  40. static struct ofmt *ofmt = NULL;
  41.  
  42. static FILE *ofile = NULL;
  43. static int sb = 16;               /* by default */
  44.  
  45. static int use_stdout = FALSE;           /* by default, errors to stderr */
  46.  
  47. static long current_seg, abs_seg;
  48. static struct RAA *offsets;
  49. static long abs_offset;
  50.  
  51. static struct SAA *forwrefs;           /* keep track of forward references */
  52. static int forwline;
  53.  
  54. static Preproc *preproc;
  55. static int preprocess_only;
  56.  
  57. /* used by error function to report location */
  58. static char currentfile[FILENAME_MAX];
  59.  
  60. /*
  61.  * Which of the suppressible warnings are suppressed. Entry zero
  62.  * doesn't do anything. Initial defaults are given here.
  63.  */
  64. static char suppressed[1+ERR_WARN_MAX] = {
  65.     0, FALSE, TRUE, FALSE
  66. };
  67.  
  68. /*
  69.  * The option names for the suppressible warnings. As before, entry
  70.  * zero does nothing.
  71.  */
  72. static char *suppressed_names[1+ERR_WARN_MAX] = {
  73.     NULL, "macro-params", "orphan-labels", "number-overflow"
  74. };
  75.  
  76. /*
  77.  * The explanations for the suppressible warnings. As before, entry
  78.  * zero does nothing.
  79.  */
  80. static char *suppressed_what[1+ERR_WARN_MAX] = {
  81.     NULL, "macro calls with wrong no. of params",
  82.     "labels alone on lines without trailing `:'",
  83.     "numeric constants greater than 0xFFFFFFFF"
  84. };
  85.  
  86. /*
  87.  * This is a null preprocessor which just copies lines from input
  88.  * to output. It's used when someone explicitly requests that NASM
  89.  * not preprocess their source file.
  90.  */
  91.  
  92. static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
  93. static char *no_pp_getline (void);
  94. static void no_pp_cleanup (void);
  95. static Preproc no_pp = {
  96.     no_pp_reset,
  97.     no_pp_getline,
  98.     no_pp_cleanup
  99. };
  100.  
  101. /*
  102.  * get/set current offset...
  103.  */
  104. #define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
  105.               raa_read(offsets,current_seg))
  106. #define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
  107.              (void)(offsets=raa_write(offsets,current_seg,(x))))
  108.  
  109. static int want_usage;
  110. static int terminate_after_phase;
  111.  
  112. int main(int argc, char **argv) {
  113.     want_usage = terminate_after_phase = FALSE;
  114.  
  115.     nasm_set_malloc_error (report_error);
  116.     offsets = raa_init();
  117.     forwrefs = saa_init ((long)sizeof(int));
  118.  
  119.     preproc = &nasmpp;
  120.     preprocess_only = FALSE;
  121.  
  122.     seg_init();
  123.  
  124.     register_output_formats();
  125.  
  126.     parse_cmdline(argc, argv);
  127.  
  128.     if (terminate_after_phase) {
  129.     if (want_usage)
  130.         usage();
  131.     return 1;
  132.     }
  133.  
  134.     if (ofmt->stdmac)
  135.     pp_extra_stdmac (ofmt->stdmac);
  136.     eval_global_info (ofmt, lookup_label);
  137.  
  138.     if (preprocess_only) {
  139.     char *line;
  140.  
  141.     if (*outname) {
  142.         ofile = fopen(outname, "w");
  143.         if (!ofile)
  144.         report_error (ERR_FATAL | ERR_NOFILE,
  145.                   "unable to open output file `%s'", outname);
  146.     } else
  147.         ofile = NULL;
  148.  
  149.     eval_info ("%", 0L, 0L);       /* disallow labels, $ or $$ in exprs */
  150.  
  151.     preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
  152.     strcpy(currentfile,inname);
  153.     lineno = 0;
  154.     lineinc = 1;
  155.     while ( (line = preproc->getline()) ) {
  156.         int ln, li;
  157.         char buf[FILENAME_MAX];
  158.  
  159.         lineno += lineinc;
  160.         /*
  161.          * We must still check for %line directives, so that we
  162.          * can report errors accurately.
  163.          */
  164.         if (!strncmp(line, "%line", 5) &&
  165.         sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
  166.         lineno = ln - li;
  167.         lineinc = li;
  168.         strncpy (currentfile, buf, FILENAME_MAX-1);
  169.         currentfile[FILENAME_MAX-1] = '\0';
  170.         }
  171.         if (ofile) {
  172.         fputs(line, ofile);
  173.         fputc('\n', ofile);
  174.         } else
  175.         puts(line);
  176.         nasm_free (line);
  177.     }
  178.     preproc->cleanup();
  179.     if (ofile)
  180.         fclose(ofile);
  181.     if (ofile && terminate_after_phase)
  182.         remove(outname);
  183.     } else {
  184.     /*
  185.      * We must call ofmt->filename _anyway_, even if the user
  186.      * has specified their own output file, because some
  187.      * formats (eg OBJ and COFF) use ofmt->filename to find out
  188.      * the name of the input file and then put that inside the
  189.      * file.
  190.      */
  191.     ofmt->filename (inname, outname, report_error);
  192.  
  193.     ofile = fopen(outname, "wb");
  194.     if (!ofile) {
  195.         report_error (ERR_FATAL | ERR_NOFILE,
  196.               "unable to open output file `%s'", outname);
  197.     }
  198.     /*
  199.      * We must call init_labels() before ofmt->init() since
  200.      * some object formats will want to define labels in their
  201.      * init routines. (eg OS/2 defines the FLAT group)
  202.      */
  203.     init_labels ();
  204.     ofmt->init (ofile, report_error, define_label, evaluate);
  205.     assemble_file (inname);
  206.     if (!terminate_after_phase) {
  207.         ofmt->cleanup ();
  208.         cleanup_labels ();
  209.     }
  210.     /*
  211.      * We had an fclose on the output file here, but we
  212.      * actually do that in all the object file drivers as well,
  213.      * so we're leaving out the one here.
  214.      *     fclose (ofile);
  215.      */
  216.     if (terminate_after_phase) {
  217.         remove(outname);
  218.         if (listname[0])
  219.         remove(listname);
  220.     }
  221.     }
  222.  
  223.     if (want_usage)
  224.     usage();
  225.     raa_free (offsets);
  226.     saa_free (forwrefs);
  227.  
  228.     if (terminate_after_phase)
  229.     return 1;
  230.     else
  231.     return 0;
  232. }
  233.  
  234. static int process_arg (char *p, char *q) {
  235.     char *param;
  236.     int i;
  237.     int advance = 0;
  238.  
  239.     if (!p || !p[0])
  240.     return 0;
  241.  
  242.     if (p[0]=='-') {
  243.     switch (p[1]) {
  244.       case 's':
  245.         use_stdout = TRUE;
  246.         break;
  247.       case 'o':               /* these parameters take values */
  248.       case 'f':
  249.       case 'p':
  250.       case 'd':
  251.       case 'i':
  252.       case 'l':
  253.         if (p[2])               /* the parameter's in the option */
  254.         param = p+2;
  255.         else if (!q) {
  256.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  257.                   "option `-%c' requires an argument",
  258.                   p[1]);
  259.         break;
  260.         } else
  261.         advance = 1, param = q;
  262.         if (p[1]=='o') {           /* output file */
  263.         strcpy (outname, param);
  264.         } else if (p[1]=='f') {    /* output format */
  265.         ofmt = ofmt_find(param);
  266.         if (!ofmt) {
  267.             report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
  268.                   "unrecognised output format `%s'",
  269.                   param);
  270.         }
  271.         } else if (p[1]=='p') {    /* pre-include */
  272.         pp_pre_include (param);
  273.         } else if (p[1]=='d') {    /* pre-define */
  274.         pp_pre_define (param);
  275.         } else if (p[1]=='i') {    /* include search path */
  276.         pp_include_path (param);
  277.         } else if (p[1]=='l') {    /* listing file */
  278.         strcpy (listname, param);
  279.         }
  280.         break;
  281.       case 'h':
  282.         fprintf(use_stdout ? stdout : stderr,
  283.             "usage: nasm [-o outfile] [-f format] [-l listfile]"
  284.             " [options...] filename\n");
  285.         fprintf(use_stdout ? stdout : stderr,
  286.             "    or nasm -r   for version info\n\n");
  287.         fprintf(use_stdout ? stdout : stderr,
  288.             "    -e means preprocess only; "
  289.             "-a means don't preprocess\n");
  290.         fprintf(use_stdout ? stdout : stderr,
  291.             "    -s means send errors to stdout not stderr\n");
  292.         fprintf(use_stdout ? stdout : stderr,
  293.             "    -i<path> adds a pathname to the include file"
  294.             " path\n    -p<file> pre-includes a file;"
  295.             " -d<macro>[=<value] pre-defines a macro\n");
  296.         fprintf(use_stdout ? stdout : stderr,
  297.             "    -w+foo enables warnings about foo; "
  298.             "-w-foo disables them\n  where foo can be:\n");
  299.         for (i=1; i<=ERR_WARN_MAX; i++)
  300.         fprintf(use_stdout ? stdout : stderr,
  301.             "    %-16s%s (default %s)\n",
  302.             suppressed_names[i], suppressed_what[i],
  303.             suppressed[i] ? "off" : "on");
  304.         fprintf(use_stdout ? stdout : stderr,
  305.             "\nvalid output formats for -f are"
  306.             " (`*' denotes default):\n");
  307.         ofmt_list(ofmt, use_stdout ? stdout : stderr);
  308.         exit (0);               /* never need usage message here */
  309.         break;
  310.       case 'r':
  311.         fprintf(use_stdout ? stdout : stderr,
  312.             "NASM version %s\n", NASM_VER);
  313.         exit (0);               /* never need usage message here */
  314.         break;
  315.       case 'e':               /* preprocess only */
  316.         preprocess_only = TRUE;
  317.         break;
  318.       case 'a':               /* assemble only - don't preprocess */
  319.         preproc = &no_pp;
  320.         break;
  321.       case 'w':
  322.         if (p[2] != '+' && p[2] != '-') {
  323.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  324.                   "invalid option to `-w'");
  325.         } else {
  326.         for (i=1; i<=ERR_WARN_MAX; i++)
  327.             if (!nasm_stricmp(p+3, suppressed_names[i]))
  328.             break;
  329.         if (i <= ERR_WARN_MAX)
  330.             suppressed[i] = (p[2] == '-');
  331.         else
  332.             report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  333.                   "invalid option to `-w'");
  334.         }
  335.         break;
  336.       default:
  337.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  338.               "unrecognised option `-%c'",
  339.               p[1]);
  340.         break;
  341.     }
  342.     } else {
  343.     if (*inname) {
  344.         report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  345.               "more than one input file specified");
  346.     } else
  347.         strcpy(inname, p);
  348.     }
  349.  
  350.     return advance;
  351. }
  352.  
  353. static void parse_cmdline(int argc, char **argv) {
  354.     char *envreal, *envcopy, *p, *q, *arg, *prevarg;
  355.     char separator = ' ';
  356.  
  357.     *inname = *outname = *listname = '\0';
  358.  
  359.     /*
  360.      * First, process the NASM environment variable.
  361.      */
  362.     envreal = getenv("NASM");
  363.     arg = NULL;
  364.     if (envreal) {
  365.     envcopy = nasm_strdup(envreal);
  366.     p = envcopy;
  367.     if (*p && *p != '-')
  368.         separator = *p++;
  369.     while (*p) {
  370.         q = p;
  371.         while (*p && *p != separator) p++;
  372.         while (*p == separator) *p++ = '\0';
  373.         prevarg = arg;
  374.         arg = q;
  375.         if (process_arg (prevarg, arg))
  376.         arg = NULL;
  377.     }
  378.     nasm_free (envcopy);
  379.     }
  380.     if (arg)
  381.     process_arg (arg, NULL);
  382.  
  383.     /*
  384.      * Now process the actual command line.
  385.      */
  386.     while (--argc) {
  387.     int i;
  388.     argv++;
  389.     i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
  390.     argv += i, argc -= i;
  391.     }
  392.  
  393.     if (!*inname)
  394.     report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
  395.               "no input file specified");
  396. }
  397.  
  398. static void assemble_file (char *fname) {
  399.     char *value, *p, *q, *special, *line;
  400.     insn output_ins;
  401.     int i, rn_error, validid;
  402.     long seg, offs;
  403.     struct tokenval tokval;
  404.     expr *e;
  405.  
  406.     /* pass one */
  407.     pass = 1;
  408.     current_seg = ofmt->section(NULL, pass, &sb);
  409.     preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
  410.     strcpy(currentfile,fname);
  411.     lineno = 0;
  412.     lineinc = 1;
  413.     globallineno = 0;
  414.     offs = get_curr_ofs;
  415.     eval_info (NULL, current_seg, offs);   /* set $ */
  416.     while ( (line = preproc->getline()) ) {
  417.     lineno += lineinc;
  418.     globallineno++;
  419.  
  420.     if (line[0] == '%') {
  421.         int ln, li;
  422.         char buf[FILENAME_MAX];
  423.  
  424.         /*
  425.          * This will be a line number directive. They come
  426.          * straight from the preprocessor, so we'll subject
  427.          * them to only minimal error checking.
  428.          */
  429.         if (strncmp(line, "%line", 5)) {
  430.         if (preproc == &no_pp)
  431.             report_error (ERR_WARNING, "unknown `%%' directive in "
  432.                   " preprocessed source");
  433.         } else if (sscanf(line, "%%line %d+%d %s", &ln, &li, buf) != 3) {
  434.         report_error (ERR_WARNING, "bogus line number directive in"
  435.                   " preprocessed source");
  436.         } else {
  437.         lineno = ln - li;
  438.         lineinc = li;
  439.         strncpy (currentfile, buf, FILENAME_MAX-1);
  440.         currentfile[FILENAME_MAX-1] = '\0';
  441.         }
  442.         continue;
  443.     }
  444.  
  445.     /* here we parse our directives; this is not handled by the 'real'
  446.      * parser. */
  447.     if ( (i = getkw (line, &value)) ) {
  448.         switch (i) {
  449.           case 1:           /* [SEGMENT n] */
  450.         seg = ofmt->section (value, pass, &sb);
  451.         if (seg == NO_SEG) {
  452.             report_error (ERR_NONFATAL,
  453.                   "segment name `%s' not recognised",
  454.                   value);
  455.         } else {
  456.             current_seg = seg;
  457.         }
  458.         break;
  459.           case 2:           /* [EXTERN label:special] */
  460.         if (*value == '$')
  461.             value++;           /* skip initial $ if present */
  462.         q = value;
  463.         validid = TRUE;
  464.         if (!isidstart(*q))
  465.             validid = FALSE;
  466.         while (*q && *q != ':') {
  467.             if (!isidchar(*q))
  468.             validid = FALSE;
  469.             q++;
  470.         }
  471.         if (!validid) {
  472.             report_error (ERR_NONFATAL,
  473.                   "identifier expected after EXTERN");
  474.             break;
  475.         }
  476.         if (*q == ':') {
  477.             *q++ = '\0';
  478.             special = q;
  479.         } else
  480.             special = NULL;
  481.         if (!is_extern(value)) {   /* allow re-EXTERN to be ignored */
  482.             declare_as_global (value, special, report_error);
  483.             define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
  484.                   ofmt, report_error);
  485.         }
  486.         break;
  487.           case 3:           /* [BITS bits] */
  488.         switch (atoi(value)) {
  489.           case 16:
  490.           case 32:
  491.             sb = atoi(value);
  492.             break;
  493.           default:
  494.             report_error(ERR_NONFATAL,
  495.                  "`%s' is not a valid argument to [BITS]",
  496.                  value);
  497.             break;
  498.         }
  499.         break;
  500.           case 4:           /* [GLOBAL symbol:special] */
  501.         if (*value == '$')
  502.             value++;           /* skip initial $ if present */
  503.         q = value;
  504.         validid = TRUE;
  505.         if (!isidstart(*q))
  506.             validid = FALSE;
  507.         while (*q && *q != ':') {
  508.             if (!isidchar(*q))
  509.             validid = FALSE;
  510.             q++;
  511.         }
  512.         if (!validid) {
  513.             report_error (ERR_NONFATAL,
  514.                   "identifier expected after GLOBAL");
  515.             break;
  516.         }
  517.         if (*q == ':') {
  518.             *q++ = '\0';
  519.             special = q;
  520.         } else
  521.             special = NULL;
  522.         declare_as_global (value, special, report_error);
  523.         break;
  524.           case 5:           /* [COMMON symbol size:special] */
  525.         p = value;
  526.         validid = TRUE;
  527.         if (!isidstart(*p))
  528.             validid = FALSE;
  529.         while (*p && !isspace(*p)) {
  530.             if (!isidchar(*p))
  531.             validid = FALSE;
  532.             p++;
  533.         }
  534.         if (!validid) {
  535.             report_error (ERR_NONFATAL,
  536.                   "identifier expected after COMMON");
  537.             break;
  538.         }
  539.         if (*p) {
  540.             long size;
  541.  
  542.             while (*p && isspace(*p))
  543.             *p++ = '\0';
  544.             q = p;
  545.             while (*q && *q != ':')
  546.             q++;
  547.             if (*q == ':') {
  548.             *q++ = '\0';
  549.             special = q;
  550.             } else
  551.             special = NULL;
  552.             size = readnum (p, &rn_error);
  553.             if (rn_error)
  554.             report_error (ERR_NONFATAL, "invalid size specified"
  555.                       " in COMMON declaration");
  556.             else
  557.             define_common (value, seg_alloc(), size,
  558.                        special, ofmt, report_error);
  559.         } else
  560.             report_error (ERR_NONFATAL, "no size specified in"
  561.                   " COMMON declaration");
  562.         break;
  563.           case 6:               /* [ABSOLUTE address] */
  564.         current_seg = NO_SEG;
  565.         stdscan_reset();
  566.         stdscan_bufptr = value;
  567.         tokval.t_type = TOKEN_INVALID;
  568.         e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
  569.                  NULL);
  570.         if (e) {
  571.             if (!is_reloc(e))
  572.             report_error (ERR_NONFATAL, "cannot use non-"
  573.                       "relocatable expression as ABSOLUTE"
  574.                       " address");
  575.             else {
  576.             abs_seg = reloc_seg(e);
  577.             abs_offset = reloc_value(e);
  578.             }
  579.         } else
  580.             abs_offset = 0x100;/* don't go near zero in case of / */
  581.         break;
  582.           default:
  583.         if (!ofmt->directive (line+1, value, 1))
  584.             report_error (ERR_NONFATAL, "unrecognised directive [%s]",
  585.                   line+1);
  586.         break;
  587.         }
  588.     } else {
  589.         parse_line (1, line, &output_ins,
  590.             report_error, evaluate, eval_info);
  591.         if (output_ins.forw_ref)
  592.         *(int *)saa_wstruct(forwrefs) = globallineno;
  593.  
  594.         /*
  595.          * Hack to prevent phase error in the code
  596.          *   rol ax,x
  597.          *   x equ 1
  598.          *
  599.          * We rule that the presence of a forward reference
  600.          * cancels out the UNITY property of the number 1. This
  601.          * isn't _strictly_ necessary in pass one, since the
  602.          * problem occurs in pass two, but for the sake of
  603.          * having the passes as near to identical as we can
  604.          * manage, we do it like this.
  605.          */
  606.         if (output_ins.forw_ref) {
  607.         int i;
  608.         for (i=0; i<output_ins.operands; i++)
  609.             output_ins.oprs[i].type &= ~ONENESS;
  610.         }
  611.  
  612.         if (output_ins.opcode == I_EQU) {
  613.         /*
  614.          * Special `..' EQUs get processed in pass two,
  615.          * except `..@' macro-processor EQUs which are done
  616.          * in the normal place.
  617.          */
  618.         if (!output_ins.label)
  619.             report_error (ERR_NONFATAL,
  620.                   "EQU not preceded by label");
  621.         else if (output_ins.label[0] != '.' ||
  622.              output_ins.label[1] != '.' ||
  623.              output_ins.label[2] == '@') {
  624.             if (output_ins.operands == 1 &&
  625.             (output_ins.oprs[0].type & IMMEDIATE) &&
  626.             output_ins.oprs[0].wrt == NO_SEG) {
  627.             define_label (output_ins.label,
  628.                       output_ins.oprs[0].segment,
  629.                       output_ins.oprs[0].offset,
  630.                       NULL, FALSE, FALSE, ofmt, report_error);
  631.             } else if (output_ins.operands == 2 &&
  632.                    (output_ins.oprs[0].type & IMMEDIATE) &&
  633.                    (output_ins.oprs[0].type & COLON) &&
  634.                    output_ins.oprs[0].segment == NO_SEG &&
  635.                    output_ins.oprs[0].wrt == NO_SEG &&
  636.                    (output_ins.oprs[1].type & IMMEDIATE) &&
  637.                    output_ins.oprs[1].segment == NO_SEG &&
  638.                    output_ins.oprs[1].wrt == NO_SEG) {
  639.             define_label (output_ins.label,
  640.                       output_ins.oprs[0].offset | SEG_ABS,
  641.                       output_ins.oprs[1].offset,
  642.                       NULL, FALSE, FALSE, ofmt, report_error);
  643.             } else
  644.             report_error(ERR_NONFATAL, "bad syntax for EQU");
  645.         }
  646.         } else {
  647.         if (output_ins.label)
  648.             define_label (output_ins.label,
  649.                   current_seg==NO_SEG ? abs_seg : current_seg,
  650.                   offs, NULL, TRUE, FALSE, ofmt, report_error);
  651.         offs += insn_size (current_seg, offs, sb,
  652.                    &output_ins, report_error);
  653.         set_curr_ofs (offs);
  654.         }
  655.         cleanup_insn (&output_ins);
  656.     }
  657.     nasm_free (line);
  658.     offs = get_curr_ofs;
  659.     eval_info (NULL, current_seg, offs);   /* set $ */
  660.     }
  661.     preproc->cleanup();
  662.  
  663.     if (terminate_after_phase) {
  664.     fclose(ofile);
  665.     remove(outname);
  666.     if (want_usage)
  667.         usage();
  668.     exit (1);
  669.     }
  670.  
  671.     /* pass two */
  672.     pass = 2;
  673.     saa_rewind (forwrefs);
  674.     if (*listname)
  675.     nasmlist.init(listname, report_error);
  676.     {
  677.     int *p = saa_rstruct (forwrefs);
  678.     if (p)
  679.         forwline = *p;
  680.     else
  681.         forwline = -1;
  682.     }
  683.     current_seg = ofmt->section(NULL, pass, &sb);
  684.     raa_free (offsets);
  685.     offsets = raa_init();
  686.     preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
  687.     strcpy(currentfile,fname);
  688.     lineno = 0;
  689.     lineinc = 1;
  690.     globallineno = 0;
  691.     offs = get_curr_ofs;
  692.     eval_info (NULL, current_seg, offs);   /* set $ */
  693.     while ( (line = preproc->getline()) ) {
  694.     lineno += lineinc;
  695.     globallineno++;
  696.  
  697.     if (line[0] == '%') {
  698.         int ln, li;
  699.         char buf[FILENAME_MAX];
  700.  
  701.         /*
  702.          * This will be a line number directive. They come
  703.          * straight from the preprocessor, so we'll subject
  704.          * them to only minimal error checking.
  705.          */
  706.         if (!strncmp(line, "%line", 5) &&
  707.         sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
  708.         lineno = ln - li;
  709.         lineinc = li;
  710.         strncpy (currentfile, buf, FILENAME_MAX-1);
  711.         currentfile[FILENAME_MAX-1] = '\0';
  712.         }
  713.         continue;
  714.     }
  715.  
  716.     /* here we parse our directives; this is not handled by
  717.      * the 'real' parser. */
  718.     if ( (i = getkw (line, &value)) ) {
  719.         switch (i) {
  720.           case 1:           /* [SEGMENT n] */
  721.         seg = ofmt->section (value, pass, &sb);
  722.         if (seg == NO_SEG) {
  723.             report_error (ERR_PANIC,
  724.                   "invalid segment name on pass two");
  725.         } else
  726.             current_seg = seg;
  727.         break;
  728.           case 2:           /* [EXTERN label] */
  729.         q = value;
  730.         while (*q && *q != ':')
  731.             q++;
  732.         if (*q == ':') {
  733.             *q++ = '\0';
  734.             ofmt->symdef(value, 0L, 0L, 3, q);
  735.         }
  736.         break;
  737.           case 3:           /* [BITS bits] */
  738.         switch (atoi(value)) {
  739.           case 16:
  740.           case 32:
  741.             sb = atoi(value);
  742.             break;
  743.           default:
  744.             report_error(ERR_PANIC,
  745.                  "invalid [BITS] value on pass two",
  746.                  value);
  747.             break;
  748.         }
  749.         break;
  750.           case 4:               /* [GLOBAL symbol] */
  751.         q = value;
  752.         while (*q && *q != ':')
  753.             q++;
  754.         if (*q == ':') {
  755.             *q++ = '\0';
  756.             ofmt->symdef(value, 0L, 0L, 3, q);
  757.         }
  758.         break;
  759.           case 5:               /* [COMMON symbol size] */
  760.         q = value;
  761.         while (*q && *q != ':') {
  762.             if (isspace(*q))
  763.             *q = '\0';
  764.             q++;
  765.         }
  766.         if (*q == ':') {
  767.             *q++ = '\0';
  768.             ofmt->symdef(value, 0L, 0L, 3, q);
  769.         }
  770.         break;
  771.           case 6:               /* [ABSOLUTE addr] */
  772.         current_seg = NO_SEG;
  773.         stdscan_reset();
  774.         stdscan_bufptr = value;
  775.         tokval.t_type = TOKEN_INVALID;
  776.         e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
  777.                  NULL);
  778.         if (e) {
  779.             if (!is_reloc(e))
  780.             report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
  781.                       " in pass two");
  782.             else {
  783.             abs_seg = reloc_seg(e);
  784.             abs_offset = reloc_value(e);
  785.             }
  786.         } else
  787.             report_error (ERR_PANIC, "invalid ABSOLUTE address "
  788.                   "in pass two");
  789.         break;
  790.           default:
  791.         if (!ofmt->directive (line+1, value, 2))
  792.             report_error (ERR_PANIC, "invalid directive on pass two");
  793.         break;
  794.         }
  795.     } else {
  796.         parse_line (2, line, &output_ins,
  797.             report_error, evaluate, eval_info);
  798.         if (globallineno == forwline) {
  799.         int *p = saa_rstruct (forwrefs);
  800.         if (p)
  801.             forwline = *p;
  802.         else
  803.             forwline = -1;
  804.         output_ins.forw_ref = TRUE;
  805.         } else
  806.         output_ins.forw_ref = FALSE;
  807.  
  808.         /*
  809.          * Hack to prevent phase error in the code
  810.          *   rol ax,x
  811.          *   x equ 1
  812.          */
  813.         if (output_ins.forw_ref) {
  814.         int i;
  815.         for (i=0; i<output_ins.operands; i++)
  816.             output_ins.oprs[i].type &= ~ONENESS;
  817.         }
  818.  
  819.         obuf = line;
  820.         if (output_ins.label)
  821.         define_label_stub (output_ins.label, report_error);
  822.         if (output_ins.opcode == I_EQU) {
  823.         /*
  824.          * Special `..' EQUs get processed here, except
  825.          * `..@' macro processor EQUs which are done above.
  826.          */
  827.         if (output_ins.label[0] == '.' &&
  828.             output_ins.label[1] == '.' &&
  829.             output_ins.label[2] != '@') {
  830.             if (output_ins.operands == 1 &&
  831.             (output_ins.oprs[0].type & IMMEDIATE)) {
  832.             define_label (output_ins.label,
  833.                       output_ins.oprs[0].segment,
  834.                       output_ins.oprs[0].offset,
  835.                       NULL, FALSE, FALSE, ofmt, report_error);
  836.             } else if (output_ins.operands == 2 &&
  837.                    (output_ins.oprs[0].type & IMMEDIATE) &&
  838.                    (output_ins.oprs[0].type & COLON) &&
  839.                    output_ins.oprs[0].segment == NO_SEG &&
  840.                    (output_ins.oprs[1].type & IMMEDIATE) &&
  841.                    output_ins.oprs[1].segment == NO_SEG) {
  842.             define_label (output_ins.label,
  843.                       output_ins.oprs[0].offset | SEG_ABS,
  844.                       output_ins.oprs[1].offset,
  845.                       NULL, FALSE, FALSE, ofmt, report_error);
  846.             } else
  847.             report_error(ERR_NONFATAL, "bad syntax for EQU");
  848.         }
  849.         }
  850.         offs += assemble (current_seg, offs, sb,
  851.                   &output_ins, ofmt, report_error, &nasmlist);
  852.         cleanup_insn (&output_ins);
  853.         set_curr_ofs (offs);
  854.     }
  855.     nasm_free (line);
  856.  
  857.     offs = get_curr_ofs;
  858.     eval_info (NULL, current_seg, offs);   /* set $ */
  859.     }
  860.     preproc->cleanup();
  861.     nasmlist.cleanup();
  862. }
  863.  
  864. static int getkw (char *buf, char **value) {
  865.     char *p, *q;
  866.  
  867.     if (*buf!='[')
  868.         return 0;
  869.     p = buf;
  870.     while (*p && *p != ']') p++;
  871.     if (!*p)
  872.     return 0;
  873.     q = p++;
  874.     while (*p && *p != ';') {
  875.     if (!isspace(*p))
  876.         return 0;
  877.     p++;
  878.     }
  879.     q[1] = '\0';
  880.  
  881.     p = buf+1;
  882.     while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t')
  883.         buf++;
  884.     if (*buf==']') {
  885.     *buf = '\0';
  886.     *value = buf;
  887.     } else {
  888.     *buf++ = '\0';
  889.         while (isspace(*buf)) buf++;   /* beppu - skip leading whitespace */
  890.     *value = buf;
  891.     while (*buf!=']') buf++;
  892.     *buf++ = '\0';
  893.     }
  894.     for (q=p; *q; q++)
  895.     *q = tolower(*q);
  896.     if (!strcmp(p, "segment") || !strcmp(p, "section"))
  897.         return 1;
  898.     if (!strcmp(p, "extern"))
  899.         return 2;
  900.     if (!strcmp(p, "bits"))
  901.         return 3;
  902.     if (!strcmp(p, "global"))
  903.         return 4;
  904.     if (!strcmp(p, "common"))
  905.         return 5;
  906.     if (!strcmp(p, "absolute"))
  907.         return 6;
  908.     return -1;
  909. }
  910.  
  911. static void report_error (int severity, char *fmt, ...) {
  912.     va_list ap;
  913.  
  914.     /*
  915.      * See if it's a suppressed warning.
  916.      */
  917.     if ((severity & ERR_MASK) == ERR_WARNING &&
  918.     (severity & ERR_WARN_MASK) != 0 &&
  919.     suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
  920.     return;                   /* and bail out if so */
  921.  
  922.     /*
  923.      * See if it's a pass-one only warning and we're not in pass one.
  924.      */
  925.     if ((severity & ERR_PASS1) && pass != 1)
  926.     return;
  927.  
  928.     if (severity & ERR_NOFILE)
  929.     fputs ("nasm: ", use_stdout ? stdout : stderr);
  930.     else
  931.     fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
  932.          lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
  933.  
  934.     if ( (severity & ERR_MASK) == ERR_WARNING)
  935.     fputs ("warning: ", use_stdout ? stdout : stderr);
  936.     else if ( (severity & ERR_MASK) == ERR_PANIC)
  937.     fputs ("panic: ", use_stdout ? stdout : stderr);
  938.  
  939.     va_start (ap, fmt);
  940.     vfprintf (use_stdout ? stdout : stderr, fmt, ap);
  941.     fputc ('\n', use_stdout ? stdout : stderr);
  942.  
  943.     if (severity & ERR_USAGE)
  944.     want_usage = TRUE;
  945.  
  946.     switch (severity & ERR_MASK) {
  947.       case ERR_WARNING:
  948.     /* no further action, by definition */
  949.     break;
  950.       case ERR_NONFATAL:
  951.     terminate_after_phase = TRUE;
  952.     break;
  953.       case ERR_FATAL:
  954.     if (ofile) {
  955.         fclose(ofile);
  956.         remove(outname);
  957.     }
  958.     if (want_usage)
  959.         usage();
  960.     exit(1);               /* instantly die */
  961.     break;                   /* placate silly compilers */
  962.       case ERR_PANIC:
  963.     abort();               /* halt, catch fire, and dump core */
  964.     break;
  965.     }
  966. }
  967.  
  968. static void usage(void) {
  969.     fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr);
  970. }
  971.  
  972. static void register_output_formats(void) {
  973.     /* Flat-form binary format */
  974. #ifdef OF_BIN
  975.     extern struct ofmt of_bin;
  976. #endif
  977.     /* Unix formats: a.out, COFF, ELF */
  978. #ifdef OF_AOUT
  979.     extern struct ofmt of_aout;
  980. #endif
  981. #ifdef OF_AOUTB
  982.     extern struct ofmt of_aoutb;
  983. #endif
  984. #ifdef OF_COFF
  985.     extern struct ofmt of_coff;
  986. #endif
  987. #ifdef OF_ELF
  988.     extern struct ofmt of_elf;
  989. #endif
  990.     /* Linux strange format: as86 */
  991. #ifdef OF_AS86
  992.     extern struct ofmt of_as86;
  993. #endif
  994.     /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
  995. #ifdef OF_OBJ
  996.     extern struct ofmt of_obj;
  997. #endif
  998. #ifdef OF_WIN32
  999.     extern struct ofmt of_win32;
  1000. #endif
  1001. #ifdef OF_RDF
  1002.     extern struct ofmt of_rdf;
  1003. #endif
  1004. #ifdef OF_DBG     /* debug format must be included specifically */
  1005.     extern struct ofmt of_dbg;
  1006. #endif
  1007.  
  1008. #ifdef OF_BIN
  1009.     ofmt_register (&of_bin);
  1010. #endif
  1011. #ifdef OF_AOUT
  1012.     ofmt_register (&of_aout);
  1013. #endif
  1014. #ifdef OF_AOUTB
  1015.     ofmt_register (&of_aoutb);
  1016. #endif
  1017. #ifdef OF_COFF
  1018.     ofmt_register (&of_coff);
  1019. #endif
  1020. #ifdef OF_ELF
  1021.     ofmt_register (&of_elf);
  1022. #endif
  1023. #ifdef OF_AS86
  1024.     ofmt_register (&of_as86);
  1025. #endif
  1026. #ifdef OF_OBJ
  1027.     ofmt_register (&of_obj);
  1028. #endif
  1029. #ifdef OF_WIN32
  1030.     ofmt_register (&of_win32);
  1031. #endif
  1032. #ifdef OF_RDF
  1033.     ofmt_register (&of_rdf);
  1034. #endif
  1035. #ifdef OF_DBG
  1036.     ofmt_register (&of_dbg);
  1037. #endif
  1038.     /*
  1039.      * set the default format
  1040.      */
  1041.     ofmt = &OF_DEFAULT;
  1042. }
  1043.  
  1044. #define BUF_DELTA 512
  1045.  
  1046. static FILE *no_pp_fp;
  1047. static efunc no_pp_err;
  1048. static ListGen *no_pp_list;
  1049.  
  1050. static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
  1051.              ListGen *listgen) {
  1052.     no_pp_err = error;
  1053.     no_pp_fp = fopen(file, "r");
  1054.     if (!no_pp_fp)
  1055.     no_pp_err (ERR_FATAL | ERR_NOFILE,
  1056.            "unable to open input file `%s'", file);
  1057.     no_pp_list = listgen;
  1058.     (void) pass;               /* placate compilers */
  1059.     (void) eval;               /* placate compilers */
  1060. }
  1061.  
  1062. static char *no_pp_getline (void) {
  1063.     char *buffer, *p, *q;
  1064.     int bufsize;
  1065.  
  1066.     bufsize = BUF_DELTA;
  1067.     buffer = nasm_malloc(BUF_DELTA);
  1068.     p = buffer;
  1069.     while (1) {
  1070.     q = fgets(p, bufsize-(p-buffer), no_pp_fp);
  1071.     if (!q)
  1072.         break;
  1073.     p += strlen(p);
  1074.     if (p > buffer && p[-1] == '\n')
  1075.         break;
  1076.     if (p-buffer > bufsize-10) {
  1077.         bufsize += BUF_DELTA;
  1078.         buffer = nasm_realloc(buffer, bufsize);
  1079.     }
  1080.     }
  1081.  
  1082.     if (!q && p == buffer) {
  1083.     nasm_free (buffer);
  1084.     return NULL;
  1085.     }
  1086.  
  1087.     /*
  1088.      * Play safe: remove CRs as well as LFs, if any of either are
  1089.      * present at the end of the line.
  1090.      */
  1091.     while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
  1092.     *--p = '\0';
  1093.  
  1094.     /*
  1095.      * Handle spurious ^Z, which may be inserted into source files
  1096.      * by some file transfer utilities.
  1097.      */
  1098.     buffer[strcspn(buffer, "\032")] = '\0';
  1099.  
  1100.     no_pp_list->line (LIST_READ, buffer);
  1101.  
  1102.     return buffer;
  1103. }
  1104.  
  1105. static void no_pp_cleanup (void) {
  1106.     fclose(no_pp_fp);
  1107. }
  1108.