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