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