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