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