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