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