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