0de7a75272675c0dba1ba81fa45130a9b0aaf891
[fw/sdcc] / as / hc08 / asmain.c
1 /* asmain.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * 29-Oct-97 JLH pass ";!" comments to output file
12  */
13
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <setjmp.h>
18 #include <string.h>
19
20 #include "asm.h"
21
22 /*)Module       asmain.c
23  *
24  *      The module asmain.c includes the command argument parser,
25  *      the three pass sequencer, and the machine independent
26  *      assembler parsing code.
27  *
28  *      asmain.c contains the following functions:
29  *              VOID    main(argc, argv)
30  *              VOID    asexit()
31  *              VOID    asmbl()
32  *              FILE *  afile(fn, ft, wf)
33  *              VOID    newdot(nap)
34  *              VOID    phase(ap, a)
35  *              VOID    usage()
36  *
37  *      asmain.c contains the array char *usetxt[] which
38  *      references the usage text strings printed by usage().
39  */
40
41 static const char *search_path[100];
42 static int search_path_length;
43
44 /**
45  * The search_path_append is used to append another directory to the end
46  * of the include file search path.
47  *
48  * @param dir
49  *     The directory to be added to the path.
50  */
51 void
52 search_path_append(const char *dir)
53 {
54         if (search_path_length < sizeof(search_path)/sizeof(char*))
55         {
56                 search_path[search_path_length++] = dir;
57         }
58 }
59
60 /**
61  * The search_path_fopen function is used to open the named file.  If
62  * the file isn't in the current directory, the search path is then used
63  * to build a series of possible file names, and attempts to open them.
64  * The first found is used.
65  *
66  * @param filename
67  *     The name of the file to be opened.
68  * @param mode
69  *     The mode of the file to be opened.
70  * @returns
71  *     what the fopen function would return on success, or NULL if the
72  *     file is not anywhere in the search path.
73  */
74 static FILE *
75 search_path_fopen(const char *filename, const char *mode)
76 {
77         FILE *fp;
78         int j;
79
80         fp = fopen(filename, mode);
81         if (fp != NULL || filename[0] == '/' || filename[0] == '\\')
82                 return fp;
83         for (j = 0; j < search_path_length; ++j)
84         {
85                 char path[2000];
86
87                 strncpy(path, search_path[j], sizeof(path));
88                 if ((path[strlen(path) - 1] != '/') &&
89                     (path[strlen(path) - 1] != DIR_SEPARATOR_CHAR))
90                 {
91                         strncat(path, DIR_SEPARATOR_STRING, sizeof(path));
92                 }
93                 strncat(path, filename, sizeof(path));
94                 fp = fopen(path, mode);
95                 if (fp != NULL)
96                         return fp;
97         }
98         errno = ENOENT;
99         return NULL;
100 }
101
102 /*)Function     VOID    main(argc, argv)
103  *
104  *              int     argc            argument count
105  *              char *  argv            array of pointers to argument strings
106  *
107  *      The function main() is the entry point to the assembler.
108  *      The purpose of main() is to (1) parse the command line
109  *      arguments for options and source file specifications and
110  *      (2) to process the source files through the 3 pass assembler.
111  *      Before each assembler pass various variables are initialized
112  *      and source files are rewound to their beginning.  During each
113  *      assembler pass each assembler-source text line is processed.
114  *      After each assembler pass the assembler information is flushed
115  *      to any opened output files and the if-else-endif processing
116  *      is checked for proper termination.
117  *
118  *      The function main() is also responsible for opening all
119  *      output files (REL, LST, and SYM), sequencing the global (-g)
120  *      and all-global (-a) variable definitions, and dumping the
121  *      REL file header information.
122  *
123  *      local variables:
124  *              char *  p               pointer to argument string
125  *              int     c               character from argument string
126  *              int     i               argument loop counter
127  *              area *  ap              pointer to area structure
128  *
129  *      global variables:
130  *              int     aflag           -a, make all symbols global flag
131  *              char    afn[]           afile() constructed filespec
132  *              area *  areap           pointer to an area structure
133  *              int     cb[]            array of assembler output values
134  *              int     cbt[]           array of assembler relocation types
135  *                                      describing the data in cb[]
136  *              int     cfile           current file handle index
137  *                                      of input assembly files
138  *              int *   cp              pointer to assembler output array cb[]
139  *              int *   cpt             pointer to assembler relocation type
140  *                                      output array cbt[]
141  *              char    eb[]            array of generated error codes
142  *              char *  ep              pointer into error list array eb[]
143  *              int     fflag           -f(f), relocations flagged flag
144  *              int     flevel          IF-ELSE-ENDIF flag will be non
145  *                                      zero for false conditional case
146  *              Addr_T  fuzz            tracks pass to pass changes in the
147  *                                      address of symbols caused by
148  *                                      variable length instruction formats
149  *              int     gflag           -g, make undefined symbols global flag
150  *              char    ib[]            assembler-source text line
151  *              int     inpfil          count of assembler
152  *                                      input files specified
153  *              int     ifcnd[]         array of IF statement condition
154  *                                      values (0 = FALSE) indexed by tlevel
155  *              int     iflvl[]         array of IF-ELSE-ENDIF flevel
156  *                                      values indexed by tlevel
157  *              int     incfil          current file handle index
158  *                                      for include files
159  *              char *  ip              pointer into the assembler-source
160  *                                      text line in ib[]
161  *              jmp_buf jump_env        compiler dependent structure
162  *                                      used by setjmp() and longjmp()
163  *              int     lflag           -l, generate listing flag
164  *              int     line            current assembler source
165  *                                      line number
166  *              int     lop             current line number on page
167  *              int     oflag           -o, generate relocatable output flag
168  *              int     jflag           -j, generate debug info flag
169  *              int     page            current page number
170  *              int     pflag           enable listing pagination
171  *              int     pass            assembler pass number
172  *              int     radix           current number conversion radix:
173  *                                      2 (binary), 8 (octal), 10 (decimal),
174  *                                      16 (hexadecimal)
175  *              int     sflag           -s, generate symbol table flag
176  *              char    srcfn[][]       array of source file names
177  *              int     srcline[]       current source file line
178  *              char    stb[]           Subtitle string buffer
179  *              sym *   symp            pointer to a symbol structure
180  *              int     tlevel          current conditional level
181  *              int     xflag           -x, listing radix flag
182  *              FILE *  lfp             list output file handle
183  *              FILE *  ofp             relocation output file handle
184  *              FILE *  tfp             symbol table output file handle
185  *              FILE *  sfp[]           array of assembler-source file handles
186  *
187  *      called functions:
188  *              FILE *  afile()         asmain.c
189  *              VOID    allglob()       assym.c
190  *              VOID    asexit()        asmain.c
191  *              VOID    diag()          assubr.c
192  *              VOID    err()           assubr.c
193  *              int     fprintf()       c-library
194  *              int     as_getline()    aslex.c
195  *              VOID    list()          aslist.c
196  *              VOID    lstsym()        aslist.c
197  *              VOID    minit()         ___mch.c
198  *              VOID    newdot()        asmain.c
199  *              VOID    outchk()        asout.c
200  *              VOID    outgsd()        asout.c
201  *              int     rewind()        c-library
202  *              int     setjmp()        c-library
203  *              VOID    symglob()       assym.c
204  *              VOID    syminit()       assym.c
205  *              VOID    usage()         asmain.c
206  *
207  *      side effects:
208  *              Completion of main() completes the assembly process.
209  *              REL, LST, and/or SYM files may be generated.
210  */
211
212 int fatalErrors=0;
213 char relFile[128];
214
215 int
216 main(int argc, char *argv[])
217 {
218         register char *p;
219         register int c, i;
220         struct area *ap;
221
222         /*fprintf(stdout, "\n");*/
223         inpfil = -1;
224         pflag = 1;
225         for (i=1; i<argc; ++i) {
226                 p = argv[i];
227                 if (*p == '-') {
228                         if (inpfil >= 0)
229                                 usage();
230                         ++p;
231                         while ((c = *p++) != 0)
232                                 switch(c) {
233
234                                 case 'a':
235                                 case 'A':
236                                         ++aflag;
237                                         break;
238
239                                 case 'c':
240                                 case 'C':
241                                         ++cflag;
242                                         break;
243
244                                 case 'g':
245                                 case 'G':
246                                         ++gflag;
247                                         break;
248
249                                 case 'i':
250                                 case 'I':
251                                         search_path_append(p);
252                                         while (*p)
253                                                 ++p;
254                                         break;
255
256                                 case 'j':               /* JLH: debug info */
257                                 case 'J':
258                                         ++jflag;
259                                         ++oflag;        /* force object */
260                                         break;
261
262                                 case 'l':
263                                 case 'L':
264                                         ++lflag;
265                                         break;
266
267                                 case 'o':
268                                 case 'O':
269                                         ++oflag;
270                                         break;
271
272                                 case 's':
273                                 case 'S':
274                                         ++sflag;
275                                         break;
276
277                                 case 'p':
278                                 case 'P':
279                                         pflag = 0;
280                                         break;
281
282                                 case 'x':
283                                 case 'X':
284                                         xflag = 0;
285                                         break;
286
287                                 case 'q':
288                                 case 'Q':
289                                         xflag = 1;
290                                         break;
291
292                                 case 'd':
293                                 case 'D':
294                                         xflag = 2;
295                                         break;
296
297                                 case 'f':
298                                 case 'F':
299                                         ++fflag;
300                                         break;
301
302                                 default:
303                                         usage();
304                                 }
305                 } else {
306                         if (++inpfil == MAXFIL) {
307                                 fprintf(stderr, "too many input files\n");
308                                 asexit(1);
309                         }
310                         sfp[inpfil] = afile(p, "", 0);
311                         strcpy(srcfn[inpfil],afn);
312                         if (inpfil == 0) {
313                                 if (lflag)
314                                         lfp = afile(p, "lst", 1);
315                                 if (oflag) {
316                                         ofp = afile(p, "rel", 1);
317                                         // save the file name if we have to delete it on error
318                                         strcpy(relFile,afn);
319                                 }
320                                 if (sflag)
321                                         tfp = afile(p, "sym", 1);
322                         }
323                 }
324         }
325         if (inpfil < 0)
326                 usage();
327         syminit();
328         for (pass=0; pass<3; ++pass) {
329                 if (gflag && pass == 1)
330                         symglob();
331                 if (aflag && pass == 1)
332                         allglob();
333                 if (oflag && pass == 2)
334                         outgsd();
335                 flevel = 0;
336                 tlevel = 0;
337                 ifcnd[0] = 0;
338                 iflvl[0] = 0;
339                 radix = 10;
340                 srcline[0] = 0;
341                 page = 0;
342                 org_cnt = 0;
343                 stb[0] = 0;
344                 lop  = NLPP;
345                 cfile = 0;
346                 incfil = -1;
347                 for (i = 0; i <= inpfil; i++)
348                         rewind(sfp[i]);
349                 ap = areap;
350                 while (ap) {
351                         ap->a_fuzz = 0;
352                         ap->a_size = 0;
353                         ap = ap->a_ap;
354                 }
355                 fuzz = 0;
356                 dot.s_addr = 0;
357                 dot.s_area = &dca;
358                 symp = &dot;
359                 minit();
360                 while (as_getline()) {
361                         cp = cb;
362                         cpt = cbt;
363                         ep = eb;
364                         ip = ib;
365
366                         /* JLH: if line begins with ";!", then
367                          * pass this comment on to the output file
368                          */
369                         if (oflag && (pass == 1) &&
370                             (ip[0] == ';') && (ip[1] == '!'))
371                         {
372                                 fprintf(ofp, "%s\n", ip );
373                         }
374
375                         if (setjmp(jump_env) == 0)
376                                 asmbl();
377
378                         if (pass == 2) {
379                                 diag();
380                                 list();
381                         }
382                 }
383                 newdot(dot.s_area); /* Flush area info */
384                 if (flevel || tlevel)
385                         err('i');
386         }
387         if (oflag)
388                 outchk(HUGE, HUGE);  /* Flush */
389         if (sflag) {
390                 lstsym(tfp);
391         } else
392         if (lflag) {
393                 lstsym(lfp);
394         }
395         //printf ("aserr: %d\n", aserr);
396         //printf ("fatalErrors: %d\n", fatalErrors);
397         asexit(fatalErrors);
398         return 0; // hush the compiler
399 }
400
401 /*)Function     VOID    asexit(i)
402  *
403  *                      int     i       exit code
404  *
405  *      The function asexit() explicitly closes all open
406  *      files and then terminates the program.
407  *
408  *      local variables:
409  *              int     j               loop counter
410  *
411  *      global variables:
412  *              FILE *  ifp[]           array of include-file file handles
413  *              FILE *  lfp             list output file handle
414  *              FILE *  ofp             relocation output file handle
415  *              FILE *  tfp             symbol table output file handle
416  *              FILE *  sfp[]           array of assembler-source file handles
417  *
418  *      functions called:
419  *              int     fclose()        c-library
420  *              VOID    exit()          c-library
421  *
422  *      side effects:
423  *              All files closed. Program terminates.
424  */
425
426 VOID
427 asexit(int i)
428 {
429         int j;
430
431         if (lfp != NULL) fclose(lfp);
432         if (ofp != NULL) fclose(ofp);
433         if (tfp != NULL) fclose(tfp);
434
435         for (j=0; j<MAXFIL && sfp[j] != NULL; j++) {
436                 fclose(sfp[j]);
437         }
438
439         /*for (j=0; j<MAXINC && ifp[j] != NULL; j++) {
440                 fclose(ifp[j]);
441                 }*/
442         if (i) {
443           // remove output file
444           printf ("removing %s\n", relFile);
445           remove(relFile);
446         }
447         exit(i);
448 }
449
450 /*)Function     VOID    asmbl()
451  *
452  *      The function asmbl() scans the assembler-source text for
453  *      (1) labels, global labels, equates, global equates, and local
454  *      symbols, (2) .if, .else, .endif, and .page directives,
455  *      (3) machine independent assembler directives, and (4) machine
456  *      dependent mnemonics.
457  *
458  *      local variables:
459  *              mne *   mp              pointer to a mne structure
460  *              sym *   sp              pointer to a sym structure
461  *              tsym *  tp              pointer to a tsym structure
462  *              int     c               character from assembler-source
463  *                                      text line
464  *              area *  ap              pointer to an area structure
465  *              expr    e1              expression structure
466  *              char    id[]            id string
467  *              char    opt[]           options string
468  *              char    fn[]            filename string
469  *              char *  p               pointer into a string
470  *              int     d               temporary value
471  *              int     n               temporary value
472  *              int     uaf             user area options flag
473  *              int     uf              area options
474  *
475  *      global variables:
476  *              area *  areap           pointer to an area structure
477  *              char    ctype[]         array of character types, one per
478  *                                      ASCII character
479  *              int     flevel          IF-ELSE-ENDIF flag will be non
480  *                                      zero for false conditional case
481  *              Addr_T  fuzz            tracks pass to pass changes in the
482  *                                      address of symbols caused by
483  *                                      variable length instruction formats
484  *              int     ifcnd[]         array of IF statement condition
485  *                                      values (0 = FALSE) indexed by tlevel
486  *              int     iflvl[]         array of IF-ELSE-ENDIF flevel
487  *                                      values indexed by tlevel
488  *              FILE *  ifp[]           array of include-file file handles
489  *              char    incfn[][]       array of include file names
490  *              int     incline[]       current include file line
491  *              int     incfil          current file handle index
492  *                                      for include files
493  *              Addr_T  laddr           address of current assembler line
494  *                                      or value of .if argument
495  *              int     lmode           listing mode
496  *              int     lop             current line number on page
497  *              char    module[]        module name string
498  *              int     pass            assembler pass number
499  *              int     radix           current number conversion radix:
500  *                                      2 (binary), 8 (octal), 10 (decimal),
501  *                                      16 (hexadecimal)
502  *              char    stb[]           Subtitle string buffer
503  *              sym *   symp            pointer to a symbol structure
504  *              char    tb[]            Title string buffer
505  *              int     tlevel          current conditional level
506  *
507  *      functions called:
508  *              Addr_T  absexpr()       asexpr.c
509  *              area *  alookup()       assym.c
510  *              VOID    clrexpr()       asexpr.c
511  *              int     digit()         asexpr.c
512  *              char    endline()       aslex.c
513  *              VOID    err()           assubr.c
514  *              VOID    expr()          asexpr.c
515  *              FILE *  fopen()         c-library
516  *              char    get()           aslex.c
517  *              VOID    getid()         aslex.c
518  *              int     getmap()        aslex.c
519  *              char    getnb()         aslex.c
520  *              VOID    getst()         aslex.c
521  *              sym *   lookup()        assym.c
522  *              VOID    machine()       ___mch.c
523  *              mne *   mlookup()       assym.c
524  *              int     more()          aslex.c
525  *              VOID *  new()           assym.c
526  *              VOID    newdot()        asmain.c
527  *              VOID    outall()        asout.c
528  *              VOID    outab()         asout.c
529  *              VOID    outchk()        asout.c
530  *              VOID    outrb()         asout.c
531  *              VOID    outrw()         asout.c
532  *              VOID    phase()         asmain.c
533  *              VOID    qerr()          assubr.c
534  *              char *  strcpy()        c-library
535  *              char *  strncpy()       c-library
536  *              VOID    unget()         aslex.c
537  */
538
539 VOID
540 asmbl(void)
541 {
542         register struct mne *mp;
543         register struct sym *sp;
544         register struct tsym *tp;
545         register int c;
546         struct area  *ap;
547         struct expr e1;
548         char id[NCPS];
549         char opt[NCPS];
550         char fn[PATH_MAX];
551         char *p;
552         int d, n, uaf, uf;
553         static struct area *abs_ap; /* pointer to current absolute area structure */
554
555         laddr = dot.s_addr;
556         lmode = SLIST;
557 loop:
558         if ((c=endline()) == 0) { return; }
559         /*
560          * If the first character is a digit then assume
561          * a local symbol is being specified.  The symbol
562          * must end with $: to be valid.
563          *      pass 0:
564          *              Construct a tsym structure at the first
565          *              occurance of the symbol.  Flag the symbol
566          *              as multiply defined if not the first occurance.
567          *      pass 1:
568          *              Load area, address, and fuzz values
569          *              into structure tsym.
570          *      pass 2:
571          *              Check for assembler phase error and
572          *              multiply defined error.
573          */
574         if (ctype[c] & DIGIT) {
575                 if (flevel)
576                         return;
577                 n = 0;
578                 while ((d = digit(c, 10)) >= 0) {
579                         n = 10*n + d;
580                         c = get();
581                 }
582                 if (c != '$' || get() != ':')
583                         qerr();
584                 tp = symp->s_tsym;
585                 if (pass == 0) {
586                         while (tp) {
587                                 if (n == tp->t_num) {
588                                         tp->t_flg |= S_MDF;
589                                         break;
590                                 }
591                                 tp = tp->t_lnk;
592                         }
593                         if (tp == NULL) {
594                                 tp=(struct tsym *) new (sizeof(struct tsym));
595                                 tp->t_lnk = symp->s_tsym;
596                                 tp->t_num = n;
597                                 tp->t_flg = 0;
598                                 tp->t_area = dot.s_area;
599                                 tp->t_addr = dot.s_addr;
600                                 symp->s_tsym = tp;
601                         }
602                 } else {
603                         while (tp) {
604                                 if (n == tp->t_num) {
605                                         break;
606                                 }
607                                 tp = tp->t_lnk;
608                         }
609                         if (tp) {
610                                 if (pass == 1) {
611                                         fuzz = tp->t_addr - dot.s_addr;
612                                         tp->t_area = dot.s_area;
613                                         tp->t_addr = dot.s_addr;
614                                 } else {
615                                         phase(tp->t_area, tp->t_addr);
616                                         if (tp->t_flg & S_MDF)
617                                                 err('m');
618                                 }
619                         } else {
620                                 err('u');
621                         }
622                 }
623                 lmode = ALIST;
624                 goto loop;
625         }
626         /*
627          * If the first character is a letter then assume a label,
628          * symbol, assembler directive, or assembler mnemonic is
629          * being processed.
630          */
631         if ((ctype[c] & LETTER) == 0) {
632                 if (flevel) {
633                         return;
634                 } else {
635                         qerr();
636                 }
637         }
638         getid(id, c);
639         c = getnb();
640         /*
641          * If the next character is a : then a label is being processed.
642          * A double :: defines a global label.  If this is new label
643          * then create a symbol structure.
644          *      pass 0:
645          *              Flag multiply defined labels.
646          *      pass 1:
647          *              Load area, address, and fuzz values
648          *              into structure symp.
649          *      pass 2:
650          *              Check for assembler phase error and
651          *              multiply defined error.
652          */
653         if (c == ':') {
654                 if (flevel)
655                         return;
656                 if ((c = get()) != ':') {
657                         unget(c);
658                         c = 0;
659                 }
660                 symp = lookup(id);
661                 if (symp == &dot)
662                         err('.');
663                 if (pass == 0)
664                         if ((symp->s_type != S_NEW) &&
665                            ((symp->s_flag & S_ASG) == 0))
666                                 symp->s_flag |= S_MDF;
667                 if (pass != 2) {
668                         fuzz = symp->s_addr - dot.s_addr;
669                         symp->s_type = S_USER;
670                         symp->s_area = dot.s_area;
671                         symp->s_addr = dot.s_addr;
672                 } else {
673                         if (symp->s_flag & S_MDF)
674                                 err('m');
675                         phase(symp->s_area, symp->s_addr);
676                 }
677                 if (c) {
678                         symp->s_flag |= S_GBL;
679                 }
680                 lmode = ALIST;
681                 goto loop;
682         }
683         /*
684          * If the next character is a = then an equate is being processed.
685          * A double == defines a global equate.  If this is new variable
686          * then create a symbol structure.
687          */
688         if (c == '=') {
689                 if (flevel)
690                         return;
691                 if ((c = get()) != '=') {
692                         unget(c);
693                         c = 0;
694                 }
695                 clrexpr(&e1);
696                 expr(&e1, 0);
697                 sp = lookup(id);
698                 if (sp == &dot) {
699                         outall();
700                         if (e1.e_flag || e1.e_base.e_ap != dot.s_area)
701                                 err('.');
702                 } else
703                 if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) {
704                         err('m');
705                 }
706                 sp->s_type = S_USER;
707                 sp->s_area = e1.e_base.e_ap;
708                 sp->s_addr = laddr = e1.e_addr;
709                 sp->s_flag |= S_ASG;
710                 if (c) {
711                         sp->s_flag |= S_GBL;
712                 }
713                 lmode = ELIST;
714                 goto loop;
715         }
716         unget(c);
717         lmode = flevel ? SLIST : CLIST;
718         if ((mp = mlookup(id)) == NULL) {
719                 if (!flevel)
720                         err('o');
721                 return;
722         }
723         /*
724          * If we have gotten this far then we have found an
725          * assembler directive or an assembler mnemonic.
726          *
727          * Check for .if, .else, .endif, and .page directives
728          * which are not controlled by the conditional flags
729          */
730         switch (mp->m_type) {
731
732         case S_IF:
733                 n = absexpr();
734                 if (tlevel < MAXIF) {
735                         ++tlevel;
736                         ifcnd[tlevel] = n;
737                         iflvl[tlevel] = flevel;
738                         if (n == 0) {
739                                 ++flevel;
740                         }
741                 } else {
742                         err('i');
743                 }
744                 lmode = ELIST;
745                 laddr = n;
746                 return;
747
748         case S_ELSE:
749                 if (ifcnd[tlevel]) {
750                         if (++flevel > (iflvl[tlevel]+1)) {
751                                 err('i');
752                         }
753                 } else {
754                         if (--flevel < iflvl[tlevel]) {
755                                 err('i');
756                         }
757                 }
758                 lmode = SLIST;
759                 return;
760
761         case S_ENDIF:
762                 if (tlevel) {
763                         flevel = iflvl[tlevel--];
764                 } else {
765                         err('i');
766                 }
767                 lmode = SLIST;
768                 return;
769
770         case S_PAGE:
771                 lop = NLPP;
772                 lmode = NLIST;
773                 return;
774
775         default:
776                 break;
777         }
778         if (flevel)
779                 return;
780         /*
781          * If we are not in a false state for .if/.else then
782          * process the assembler directives here.
783          */
784         switch (mp->m_type) {
785
786         case S_EVEN:
787                 outall();
788                 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
789                 lmode = ALIST;
790                 break;
791
792         case S_ODD:
793                 outall();
794                 laddr = dot.s_addr |= 1;
795                 lmode = ALIST;
796                 break;
797
798         case S_BYTE:
799         case S_WORD:
800                 do {
801                         clrexpr(&e1);
802                         expr(&e1, 0);
803                         if (mp->m_type == S_BYTE) {
804                                 outrb(&e1, R_NORM);
805                         } else {
806                                 outrw(&e1, R_NORM);
807                         }
808                 } while ((c = getnb()) == ',');
809                 unget(c);
810                 break;
811
812         case S_ULEB128:
813         case S_SLEB128:
814                 do {
815                         Addr_T val = absexpr();
816                         int bit = sizeof(val)*8 - 1;
817                         int impliedBit;
818
819                         if (mp->m_type == S_ULEB128) {
820                                 impliedBit = 0;
821                         } else {
822                                 impliedBit = (val & (1 << bit)) ? 1 : 0;
823                         }
824                         while ((bit>0) && (((val & (1 << bit)) ? 1 : 0) == impliedBit)) {
825                                 bit--;
826                         }
827                         if (mp->m_type == S_SLEB128) {
828                                 bit++;
829                         }
830                         while (bit>=0) {
831                                 if (bit<7) {
832                                         outab(val & 0x7f);
833                                 } else {
834                                         outab(0x80 | (val & 0x7f));
835                                 }
836                                 bit -= 7;
837                                 val >>= 7;
838                         }
839                 } while ((c = getnb()) == ',');
840                 unget(c);
841                 break;
842
843         case S_ASCII:
844         case S_ASCIZ:
845                 if ((d = getnb()) == '\0')
846                         qerr();
847                 while ((c = getmap(d)) >= 0)
848                         outab(c);
849                 if (mp->m_type == S_ASCIZ)
850                         outab(0);
851                 break;
852
853         case S_ASCIS:
854                 if ((d = getnb()) == '\0')
855                         qerr();
856                 c = getmap(d);
857                 while (c >= 0) {
858                         if ((n = getmap(d)) >= 0) {
859                                 outab(c);
860                         } else {
861                                 outab(c | 0x80);
862                         }
863                         c = n;
864                 }
865                 break;
866
867         case S_BLK:
868                 clrexpr(&e1);
869                 expr(&e1, 0);
870                 outchk(HUGE,HUGE);
871                 dot.s_addr += e1.e_addr*mp->m_valu;
872                 lmode = BLIST;
873                 break;
874
875         case S_TITLE:
876                 p = tb;
877                 if ((c = getnb()) != 0) {
878                         do {
879                                 if (p < &tb[NTITL-1])
880                                         *p++ = c;
881                         } while ((c = get()) != 0);
882                 }
883                 *p = 0;
884                 unget(c);
885                 lmode = SLIST;
886                 break;
887
888         case S_SBTL:
889                 p = stb;
890                 if ((c = getnb()) != 0) {
891                         do {
892                                 if (p < &stb[NSBTL-1])
893                                         *p++ = c;
894                         } while ((c = get()) != 0);
895                 }
896                 *p = 0;
897                 unget(c);
898                 lmode = SLIST;
899                 break;
900
901         case S_MODUL:
902                 getst(id, getnb()); // a module can start with a digit
903                 if (pass == 0) {
904                         if (module[0]) {
905                                 err('m');
906                         } else {
907                                 strncpy(module, id, NCPS);
908                         }
909                 }
910                 lmode = SLIST;
911                 break;
912
913         case S_OPTSDCC:
914                 p = optsdcc;
915                 if ((c = getnb()) != 0) {
916                         do {
917                                 if (p < &optsdcc[NINPUT-1])
918                                         *p++ = c;
919                         } while ((c = get()) != 0);
920                 }
921                 *p = 0;
922                 unget(c);
923                 lmode = SLIST;
924                 /*if (pass == 0) printf("optsdcc=%s\n", optsdcc);*/
925                 break;
926
927         case S_GLOBL:
928                 do {
929                         getid(id, -1);
930                         sp = lookup(id);
931                         sp->s_flag |= S_GBL;
932                 } while ((c = getnb()) == ',');
933                 unget(c);
934                 lmode = SLIST;
935                 break;
936
937         case S_DAREA:
938                 getid(id, -1);
939                 uaf = 0;
940                 uf  = A_CON|A_REL;
941                 if ((c = getnb()) == '(') {
942                         do {
943                                 getid(opt, -1);
944                                 mp = mlookup(opt);
945                                 if (mp && mp->m_type == S_ATYP) {
946                                         ++uaf;
947                                         uf |= mp->m_valu;
948                                 } else {
949                                         err('u');
950                                 }
951                         } while ((c = getnb()) == ',');
952                         if (c != ')')
953                                 qerr();
954                 } else {
955                         unget(c);
956                 }
957                 if ((ap = alookup(id)) != NULL) {
958                         if (uaf && uf != ap->a_flag)
959                                 err('m');
960                 } else {
961                         ap = (struct area *) new (sizeof(struct area));
962                         ap->a_ap = areap;
963                         strncpy(ap->a_id, id, NCPS);
964                         ap->a_ref = areap->a_ref + 1;
965                         ap->a_addr = 0;
966                         ap->a_size = 0;
967                         ap->a_fuzz = 0;
968                         ap->a_flag = uaf ? uf : (A_CON|A_REL);
969                         areap = ap;
970                 }
971                 newdot(ap);
972                 lmode = SLIST;
973                 if (dot.s_area->a_flag & A_ABS)
974                         abs_ap = ap;
975                 break;
976
977         case S_ORG:
978                 if (dot.s_area->a_flag & A_ABS) {
979                         char buf[NCPS];
980
981                         laddr = absexpr();
982                         sprintf(buf, "%s%x", abs_ap->a_id, org_cnt++);
983                         if ((ap = alookup(buf)) == NULL) {
984                                 ap = (struct area *) new (sizeof(struct area));
985                                 *ap = *areap;
986                                 ap->a_ap = areap;
987                                 strncpy(ap->a_id, buf, NCPS);
988                                 ap->a_ref = areap->a_ref + 1;
989                                 ap->a_size = 0;
990                                 ap->a_fuzz = 0;
991                                 areap = ap;
992                         }
993                         newdot(ap);
994                         lmode = ALIST;
995                         dot.s_addr = dot.s_org = laddr;
996                 } else {
997                         err('o');
998                 }
999                 break;
1000
1001         case S_RADIX:
1002                 if (more()) {
1003                         switch (getnb()) {
1004                         case 'b':
1005                         case 'B':
1006                                 radix = 2;
1007                                 break;
1008                         case '@':
1009                         case 'o':
1010                         case 'O':
1011                         case 'q':
1012                         case 'Q':
1013                                 radix = 8;
1014                                 break;
1015                         case 'd':
1016                         case 'D':
1017                                 radix = 10;
1018                                 break;
1019                         case 'h':
1020                         case 'H':
1021                         case 'x':
1022                         case 'X':
1023                                 radix = 16;
1024                                 break;
1025                         default:
1026                                 radix = 10;
1027                                 qerr();
1028                                 break;
1029                         }
1030                 } else {
1031                         radix = 10;
1032                 }
1033                 lmode = SLIST;
1034                 break;
1035
1036         case S_INCL:
1037                 d = getnb();
1038                 p = fn;
1039                 while ((c = get()) != d) {
1040                         if (p < &fn[PATH_MAX-1]) {
1041                                 *p++ = c;
1042                         } else {
1043                                 break;
1044                         }
1045                 }
1046                 *p = 0;
1047                 if ((++incfil == MAXINC) ||
1048                     (ifp[incfil] = search_path_fopen(fn, "r")) == NULL) {
1049                         --incfil;
1050                         err('i');
1051                 } else {
1052                         lop = NLPP;
1053                         incline[incfil] = 0;
1054                         strcpy(incfn[incfil],fn);
1055                 }
1056                 lmode = SLIST;
1057                 break;
1058
1059         case S_FLAT24:
1060                 if (more())
1061                 {
1062                     getst(id, -1);
1063
1064                     if (!as_strcmpi(id, "on"))
1065                     {
1066                         /* Quick sanity check: size of
1067                          * Addr_T must be at least 24 bits.
1068                          */
1069                         if (sizeof(Addr_T) < 3)
1070                         {
1071                             warnBanner();
1072                             fprintf(stderr,
1073                                     "Cannot enable Flat24 mode: "
1074                                     "host system must have 24 bit "
1075                                     "or greater integers.\n");
1076                         }
1077                         else
1078                         {
1079                             flat24Mode = 1;
1080                         }
1081                     }
1082                     else if (!as_strcmpi(id, "off"))
1083                     {
1084                         flat24Mode = 0;
1085                     }
1086                     else
1087                     {
1088                         qerr();
1089                     }
1090                 }
1091                 else
1092                 {
1093                     qerr();
1094                 }
1095                 lmode = SLIST;
1096                 #if 0
1097                 printf("as8051: ds390 flat mode %sabled.\n",
1098                         flat24Mode ? "en" : "dis");
1099                 #endif
1100                 break;
1101
1102
1103         /*
1104          * If not an assembler directive then go to
1105          * the machine dependent function which handles
1106          * all the assembler mnemonics.
1107          */
1108         default:
1109                 machine(mp);
1110                 /* if cdb information then generate the line info */
1111                 if (cflag && (pass == 1))
1112                     DefineCDB_Line();
1113
1114                 /* JLH: if -j, generate a line number symbol */
1115                 if (jflag && (pass == 1))
1116                 {
1117                    DefineNoICE_Line();
1118                 }
1119
1120         }
1121         goto loop;
1122 }
1123
1124 /*)Function     FILE *  afile(fn, ft, wf)
1125  *
1126  *              char *  fn              file specification string
1127  *              char *  ft              file type string
1128  *              int     wf              read(0)/write(1) flag
1129  *
1130  *      The function afile() opens a file for reading or writing.
1131  *              (1)     If the file type specification string ft
1132  *                      is not NULL then a file specification is
1133  *                      constructed with the file path\name in fn
1134  *                      and the extension in ft.
1135  *              (2)     If the file type specification string ft
1136  *                      is NULL then the file specification is
1137  *                      constructed from fn.  If fn does not have
1138  *                      a file type then the default source file
1139  *                      type dsft is appended to the file specification.
1140  *
1141  *      afile() returns a file handle for the opened file or aborts
1142  *      the assembler on an open error.
1143  *
1144  *      local variables:
1145  *              int     c               character value
1146  *              FILE *  fp              filehandle for opened file
1147  *              char *  p1              pointer to filespec string fn
1148  *              char *  p2              pointer to filespec string fb
1149  *              char *  p3              pointer to filetype string ft
1150  *
1151  *      global variables:
1152  *              char    afn[]           afile() constructed filespec
1153  *              char    dsft[]          default assembler file type string
1154  *              char    afn[]           constructed file specification string
1155  *
1156  *      functions called:
1157  *              VOID    asexit()        asmain.c
1158  *              FILE *  fopen()         c_library
1159  *              int     fprintf()       c_library
1160  *
1161  *      side effects:
1162  *              File is opened for read or write.
1163  */
1164
1165 FILE *
1166 afile(char *fn, char *ft, int wf)
1167 {
1168         register char *p2, *p3;
1169         register int c;
1170         FILE *fp;
1171
1172         p2 = afn;
1173         p3 = ft;
1174
1175         strcpy (afn, fn);
1176         p2 = strrchr (afn, FSEPX);              // search last '.'
1177         if (!p2)
1178                 p2 = afn + strlen (afn);
1179         if (p2 > &afn[PATH_MAX-4])              // truncate filename, if it's too long
1180                 p2 = &afn[PATH_MAX-4];
1181         *p2++ = FSEPX;
1182
1183         // choose a file-extension
1184         if (*p3 == 0) {                                 // extension supplied?
1185                 p3 = strrchr (fn, FSEPX);       // no: extension in fn?
1186                 if (p3)
1187                         ++p3;
1188                 else
1189                         p3 = dsft;                                      // no: default extension
1190         }
1191
1192         while ((c = *p3++) != 0) {              // strncpy
1193                 if (p2 < &afn[PATH_MAX-1])
1194                         *p2++ = c;
1195         }
1196         *p2++ = 0;
1197
1198         if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1199                 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1200                 asexit(1);
1201         }
1202         return (fp);
1203 }
1204
1205 /*)Function     VOID    newdot(nap)
1206  *
1207  *              area *  nap             pointer to the new area structure
1208  *
1209  *      The function newdot():
1210  *              (1)     copies the current values of fuzz and the last
1211  *                      address into the current area referenced by dot
1212  *              (2)     loads dot with the pointer to the new area and
1213  *                      loads the fuzz and last address parameters
1214  *              (3)     outall() is called to flush any remaining
1215  *                      bufferred code from the old area to the output
1216  *
1217  *      local variables:
1218  *              area *  oap             pointer to old area
1219  *
1220  *      global variables:
1221  *              sym     dot             defined as sym[0]
1222  *              Addr_T  fuzz            tracks pass to pass changes in the
1223  *                                      address of symbols caused by
1224  *                                      variable length instruction formats
1225  *
1226  *      functions called:
1227  *              none
1228  *
1229  *      side effects:
1230  *              Current area saved, new area loaded, buffers flushed.
1231  */
1232
1233 VOID
1234 newdot(register struct area *nap)
1235 {
1236         register struct area *oap;
1237
1238         oap = dot.s_area;
1239         /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n",
1240              oap->a_id, dot.s_area->a_size, dot.s_addr); */
1241         oap->a_fuzz = fuzz;
1242         if (oap->a_flag & A_OVR) {
1243           // the size of an overlay is the biggest size encountered
1244           if (oap->a_size < dot.s_addr) {
1245             oap->a_size = dot.s_addr;
1246           }
1247         } else if (oap->a_flag & A_ABS) {
1248           oap->a_addr = dot.s_org;
1249           oap->a_size += dot.s_addr - dot.s_org;
1250           dot.s_addr = dot.s_org = 0;
1251         } else {
1252           oap->a_addr = 0;
1253           oap->a_size = dot.s_addr;
1254         }
1255         if (nap->a_flag & A_OVR) {
1256           // a new overlay starts at 0, no fuzz
1257           dot.s_addr = 0;
1258           fuzz = 0;
1259         } else if (nap->a_flag & A_ABS) {
1260           // a new absolute starts at org, no fuzz
1261           dot.s_addr = dot.s_org;
1262           fuzz = 0;
1263         } else {
1264           dot.s_addr = nap->a_size;
1265           fuzz = nap->a_fuzz;
1266         }
1267         dot.s_area = nap;
1268         outall();
1269 }
1270
1271 /*)Function     VOID    phase(ap, a)
1272  *
1273  *              area *  ap              pointer to area
1274  *              Addr_T  a               address in area
1275  *
1276  *      Function phase() compares the area ap and address a
1277  *      with the current area dot.s_area and address dot.s_addr
1278  *      to determine if the position of the symbol has changed
1279  *      between assembler passes.
1280  *
1281  *      local variables:
1282  *              none
1283  *
1284  *      global varaibles:
1285  *              sym *   dot             defined as sym[0]
1286  *
1287  *      functions called:
1288  *              none
1289  *
1290  *      side effects:
1291  *              The p error is invoked if the area and/or address
1292  *              has changed.
1293  */
1294
1295 VOID
1296 phase(struct area *ap, Addr_T a)
1297 {
1298         if (ap != dot.s_area || a != dot.s_addr)
1299                 err('p');
1300 }
1301
1302 char *usetxt[] = {
1303         "Usage: [-dqxjgalopsf][ -I<dir> ] file1 [file2 file3 ...]",
1304         "  d    decimal listing",
1305         "  q    octal   listing",
1306         "  x    hex     listing (default)",
1307         "  j    add line number and debug information to file", /* JLH */
1308         "  g    undefined symbols made global",
1309         "  a    all user symbols made global",
1310         "  l    create list   output file1[LST]",
1311         "  o    create object output file1[REL]",
1312         "  s    create symbol output file1[SYM]",
1313         "  c    generate sdcdb debug information",
1314         "  p    disable listing pagination",
1315         "  f    flag relocatable references by `    in listing file",
1316         " ff    flag relocatable references by mode in listing file",
1317         "-I<dir>  Add the named directory to the include file",
1318         "       search path.  This option may be used more than once.",
1319         "       Directories are searched in the order given.",
1320         "",
1321         0
1322 };
1323
1324 /*)Function     VOID    usage()
1325  *
1326  *      The function usage() outputs to the stderr device the
1327  *      assembler name and version and a list of valid assembler options.
1328  *
1329  *      local variables:
1330  *              char ** dp              pointer to an array of
1331  *                                      text string pointers.
1332  *
1333  *      global variables:
1334  *              char    cpu[]           assembler type string
1335  *              char *  usetxt[]        array of string pointers
1336  *
1337  *      functions called:
1338  *              VOID    asexit()        asmain.c
1339  *              int     fprintf()       c_library
1340  *
1341  *      side effects:
1342  *              program is terminated
1343  */
1344
1345 VOID
1346 usage(void)
1347 {
1348         register char   **dp;
1349
1350         fprintf(stderr, "\nASxxxx Assembler %s  (%s)\n\n", VERSION, cpu);
1351         for (dp = usetxt; *dp; dp++)
1352                 fprintf(stderr, "%s\n", *dp);
1353         asexit(1);
1354 }