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