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