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