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