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