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