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