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