* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / mcs51 / 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_ASCII:
822         case S_ASCIZ:
823                 if ((d = getnb()) == '\0')
824                         qerr();
825                 while ((c = getmap(d)) >= 0)
826                         outab(c);
827                 if (mp->m_type == S_ASCIZ)
828                         outab(0);
829                 break;
830
831         case S_ASCIS:
832                 if ((d = getnb()) == '\0')
833                         qerr();
834                 c = getmap(d);
835                 while (c >= 0) {
836                         if ((n = getmap(d)) >= 0) {
837                                 outab(c);
838                         } else {
839                                 outab(c | 0x80);
840                         }
841                         c = n;
842                 }
843                 break;
844
845         case S_BLK:
846                 clrexpr(&e1);
847                 expr(&e1, 0);
848                 outchk(HUGE,HUGE);
849                 dot.s_addr += e1.e_addr*mp->m_valu;
850                 lmode = BLIST;
851                 break;
852
853         case S_TITLE:
854                 p = tb;
855                 if ((c = getnb()) != 0) {
856                         do {
857                                 if (p < &tb[NTITL-1])
858                                         *p++ = c;
859                         } while ((c = get()) != 0);
860                 }
861                 *p = 0;
862                 unget(c);
863                 lmode = SLIST;
864                 break;
865
866         case S_SBTL:
867                 p = stb;
868                 if ((c = getnb()) != 0) {
869                         do {
870                                 if (p < &stb[NSBTL-1])
871                                         *p++ = c;
872                         } while ((c = get()) != 0);
873                 }
874                 *p = 0;
875                 unget(c);
876                 lmode = SLIST;
877                 break;
878
879         case S_MODUL:
880                 getst(id, getnb()); // a module can start with a digit
881                 if (pass == 0) {
882                         if (module[0]) {
883                                 err('m');
884                         } else {
885                                 strncpy(module, id, NCPS);
886                         }
887                 }
888                 lmode = SLIST;
889                 break;
890
891         case S_OPTSDCC:
892                 p = optsdcc;
893                 if ((c = getnb()) != 0) {
894                         do {
895                                 if (p < &optsdcc[NINPUT-1])
896                                         *p++ = c;
897                         } while ((c = get()) != 0);
898                 }
899                 *p = 0;
900                 unget(c);
901                 lmode = SLIST;
902         /*if (pass == 0) printf("optsdcc=%s\n", optsdcc);*/
903         break;
904
905         case S_GLOBL:
906                 do {
907                         getid(id, -1);
908                         sp = lookup(id);
909                         sp->s_flag |= S_GBL;
910                 } while ((c = getnb()) == ',');
911                 unget(c);
912                 lmode = SLIST;
913                 break;
914
915         case S_DAREA:
916                 getid(id, -1);
917                 uaf = 0;
918                 uf  = A_CON|A_REL;
919                 if ((c = getnb()) == '(') {
920                         do {
921                                 getid(opt, -1);
922                                 mp = mlookup(opt);
923                                 if (mp && mp->m_type == S_ATYP) {
924                                         ++uaf;
925                                         uf |= mp->m_valu;
926                                 } else {
927                                         err('u');
928                                 }
929                         } while ((c = getnb()) == ',');
930                         if (c != ')')
931                                 qerr();
932                 } else {
933                         unget(c);
934                 }
935                 if ((ap = alookup(id)) != NULL) {
936                         if (uaf && uf != ap->a_flag)
937                                 err('m');
938                 } else {
939                         ap = (struct area *) new (sizeof(struct area));
940                         ap->a_ap = areap;
941                         strncpy(ap->a_id, id, NCPS);
942                         ap->a_ref = areap->a_ref + 1;
943                         ap->a_addr = 0;
944                         ap->a_size = 0;
945                         ap->a_fuzz = 0;
946                         ap->a_flag = uaf ? uf : (A_CON|A_REL);
947                         areap = ap;
948                 }
949                 newdot(ap);
950                 lmode = SLIST;
951                 if (dot.s_area->a_flag & A_ABS)
952                         abs_ap = ap;
953                 break;
954
955         case S_ORG:
956                 if (dot.s_area->a_flag & A_ABS) {
957                         char buf[NCPS];
958
959                         laddr = absexpr();
960                         sprintf(buf, "%s%x", abs_ap->a_id, org_cnt++);
961                         if ((ap = alookup(buf)) == NULL) {
962                                 ap = (struct area *) new (sizeof(struct area));
963                                 *ap = *areap;
964                                 ap->a_ap = areap;
965                                 strncpy(ap->a_id, buf, NCPS);
966                                 ap->a_ref = areap->a_ref + 1;
967                                 ap->a_size = 0;
968                                 ap->a_fuzz = 0;
969                                 areap = ap;
970                         }
971                         newdot(ap);
972                         lmode = ALIST;
973                         dot.s_addr = dot.s_org = laddr;
974                 } else {
975                         err('o');
976                 }
977                 break;
978
979         case S_RADIX:
980                 if (more()) {
981                         switch (getnb()) {
982                         case 'b':
983                         case 'B':
984                                 radix = 2;
985                                 break;
986                         case '@':
987                         case 'o':
988                         case 'O':
989                         case 'q':
990                         case 'Q':
991                                 radix = 8;
992                                 break;
993                         case 'd':
994                         case 'D':
995                                 radix = 10;
996                                 break;
997                         case 'h':
998                         case 'H':
999                         case 'x':
1000                         case 'X':
1001                                 radix = 16;
1002                                 break;
1003                         default:
1004                                 radix = 10;
1005                                 qerr();
1006                                 break;
1007                         }
1008                 } else {
1009                         radix = 10;
1010                 }
1011                 lmode = SLIST;
1012                 break;
1013
1014         case S_INCL:
1015                 d = getnb();
1016                 p = fn;
1017                 while ((c = get()) != d) {
1018                         if (p < &fn[PATH_MAX-1]) {
1019                                 *p++ = c;
1020                         } else {
1021                                 break;
1022                         }
1023                 }
1024                 *p = 0;
1025                 if ((++incfil == MAXINC) ||
1026                     (ifp[incfil] = search_path_fopen(fn, "r")) == NULL) {
1027                         --incfil;
1028                         err('i');
1029                 } else {
1030                         lop = NLPP;
1031                         incline[incfil] = 0;
1032                         strcpy(incfn[incfil],fn);
1033                 }
1034                 lmode = SLIST;
1035                 break;
1036
1037         case S_FLAT24:
1038                 if (more())
1039                 {
1040                     getst(id, -1);
1041
1042                     if (!as_strcmpi(id, "on"))
1043                     {
1044                         /* Quick sanity check: size of
1045                          * Addr_T must be at least 24 bits.
1046                          */
1047                         if (sizeof(Addr_T) < 3)
1048                         {
1049                             warnBanner();
1050                             fprintf(stderr,
1051                                     "Cannot enable Flat24 mode: "
1052                                     "host system must have 24 bit "
1053                                     "or greater integers.\n");
1054                         }
1055                         else
1056                         {
1057                             flat24Mode = 1;
1058                         }
1059                     }
1060                     else if (!as_strcmpi(id, "off"))
1061                     {
1062                         flat24Mode = 0;
1063                     }
1064                     else
1065                     {
1066                         qerr();
1067                     }
1068                 }
1069                 else
1070                 {
1071                     qerr();
1072                 }
1073                 lmode = SLIST;
1074                 #if 0
1075                 printf("as8051: ds390 flat mode %sabled.\n",
1076                         flat24Mode ? "en" : "dis");
1077                 #endif
1078                 break;
1079
1080
1081         /*
1082          * If not an assembler directive then go to
1083          * the machine dependent function which handles
1084          * all the assembler mnemonics.
1085          */
1086         default:
1087                 machine(mp);
1088                 /* if cdb information then generate the line info */
1089                 if (cflag && (pass == 1))
1090                     DefineCDB_Line();
1091
1092                 /* JLH: if -j, generate a line number symbol */
1093                 if (jflag && (pass == 1))
1094                 {
1095                    DefineNoICE_Line();
1096                 }
1097
1098         }
1099         goto loop;
1100 }
1101
1102 /*)Function     FILE *  afile(fn, ft, wf)
1103  *
1104  *              char *  fn              file specification string
1105  *              char *  ft              file type string
1106  *              int     wf              read(0)/write(1) flag
1107  *
1108  *      The function afile() opens a file for reading or writing.
1109  *              (1)     If the file type specification string ft
1110  *                      is not NULL then a file specification is
1111  *                      constructed with the file path\name in fn
1112  *                      and the extension in ft.
1113  *              (2)     If the file type specification string ft
1114  *                      is NULL then the file specification is
1115  *                      constructed from fn.  If fn does not have
1116  *                      a file type then the default source file
1117  *                      type dsft is appended to the file specification.
1118  *
1119  *      afile() returns a file handle for the opened file or aborts
1120  *      the assembler on an open error.
1121  *
1122  *      local variables:
1123  *              int     c               character value
1124  *              FILE *  fp              filehandle for opened file
1125  *              char *  p1              pointer to filespec string fn
1126  *              char *  p2              pointer to filespec string fb
1127  *              char *  p3              pointer to filetype string ft
1128  *
1129  *      global variables:
1130  *              char    afn[]           afile() constructed filespec
1131  *              char    dsft[]          default assembler file type string
1132  *              char    afn[]           constructed file specification string
1133  *
1134  *      functions called:
1135  *              VOID    asexit()        asmain.c
1136  *              FILE *  fopen()         c_library
1137  *              int     fprintf()       c_library
1138  *
1139  *      side effects:
1140  *              File is opened for read or write.
1141  */
1142
1143 FILE *
1144 afile(char *fn, char *ft, int wf)
1145 {
1146         register char *p2, *p3;
1147         register int c;
1148         FILE *fp;
1149
1150         p2 = afn;
1151         p3 = ft;
1152
1153         strcpy (afn, fn);
1154         p2 = strrchr (afn, FSEPX);              // search last '.'
1155         if (!p2)
1156                 p2 = afn + strlen (afn);
1157         if (p2 > &afn[PATH_MAX-4])              // truncate filename, if it's too long
1158                 p2 = &afn[PATH_MAX-4];
1159         *p2++ = FSEPX;
1160
1161         // choose a file-extension
1162         if (*p3 == 0) {                                 // extension supplied?
1163                 p3 = strrchr (fn, FSEPX);       // no: extension in fn?
1164                 if (p3)
1165                         ++p3;
1166                 else
1167                         p3 = dsft;                                      // no: default extension
1168         }
1169
1170         while ((c = *p3++) != 0) {              // strncpy
1171                 if (p2 < &afn[PATH_MAX-1])
1172                         *p2++ = c;
1173         }
1174         *p2++ = 0;
1175
1176         if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1177                 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1178                 asexit(1);
1179         }
1180         return (fp);
1181 }
1182
1183 /*)Function     VOID    newdot(nap)
1184  *
1185  *              area *  nap             pointer to the new area structure
1186  *
1187  *      The function newdot():
1188  *              (1)     copies the current values of fuzz and the last
1189  *                      address into the current area referenced by dot
1190  *              (2)     loads dot with the pointer to the new area and
1191  *                      loads the fuzz and last address parameters
1192  *              (3)     outall() is called to flush any remaining
1193  *                      bufferred code from the old area to the output
1194  *
1195  *      local variables:
1196  *              area *  oap             pointer to old area
1197  *
1198  *      global variables:
1199  *              sym     dot             defined as sym[0]
1200  *              Addr_T  fuzz            tracks pass to pass changes in the
1201  *                                      address of symbols caused by
1202  *                                      variable length instruction formats
1203  *
1204  *      functions called:
1205  *              none
1206  *
1207  *      side effects:
1208  *              Current area saved, new area loaded, buffers flushed.
1209  */
1210
1211 VOID
1212 newdot(register struct area *nap)
1213 {
1214         register struct area *oap;
1215
1216         oap = dot.s_area;
1217         /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n",
1218              oap->a_id, dot.s_area->a_size, dot.s_addr); */
1219         oap->a_fuzz = fuzz;
1220         if (oap->a_flag & A_OVR) {
1221           // the size of an overlay is the biggest size encountered
1222           if (oap->a_size < dot.s_addr) {
1223             oap->a_size = dot.s_addr;
1224           }
1225         } else if (oap->a_flag & A_ABS) {
1226           oap->a_addr = dot.s_org;
1227           oap->a_size += dot.s_addr - dot.s_org;
1228           dot.s_addr = dot.s_org = 0;
1229         } else {
1230           oap->a_addr = 0;
1231           oap->a_size = dot.s_addr;
1232         }
1233         if (nap->a_flag & A_OVR) {
1234           // a new overlay starts at 0, no fuzz
1235           dot.s_addr = 0;
1236           fuzz = 0;
1237         } else if (nap->a_flag & A_ABS) {
1238           // a new absolute starts at org, no fuzz
1239           dot.s_addr = dot.s_org;
1240           fuzz = 0;
1241         } else {
1242           dot.s_addr = nap->a_size;
1243           fuzz = nap->a_fuzz;
1244         }
1245         dot.s_area = nap;
1246         outall();
1247 }
1248
1249 /*)Function     VOID    phase(ap, a)
1250  *
1251  *              area *  ap              pointer to area
1252  *              Addr_T  a               address in area
1253  *
1254  *      Function phase() compares the area ap and address a
1255  *      with the current area dot.s_area and address dot.s_addr
1256  *      to determine if the position of the symbol has changed
1257  *      between assembler passes.
1258  *
1259  *      local variables:
1260  *              none
1261  *
1262  *      global varaibles:
1263  *              sym *   dot             defined as sym[0]
1264  *
1265  *      functions called:
1266  *              none
1267  *
1268  *      side effects:
1269  *              The p error is invoked if the area and/or address
1270  *              has changed.
1271  */
1272
1273 VOID
1274 phase(struct area *ap, Addr_T a)
1275 {
1276         if (ap != dot.s_area || a != dot.s_addr)
1277                 err('p');
1278 }
1279
1280 char *usetxt[] = {
1281         "Usage: [-dqxjgalopsf][ -I<dir> ] file1 [file2 file3 ...]",
1282         "  d    decimal listing",
1283         "  q    octal   listing",
1284         "  x    hex     listing (default)",
1285         "  j    add line number and debug information to file", /* JLH */
1286         "  g    undefined symbols made global",
1287         "  a    all user symbols made global",
1288         "  l    create list   output file1[LST]",
1289         "  o    create object output file1[REL]",
1290         "  s    create symbol output file1[SYM]",
1291         "  c    generate sdcdb debug information",
1292         "  p    disable listing pagination",
1293         "  f    flag relocatable references by `    in listing file",
1294         " ff    flag relocatable references by mode in listing file",
1295         "-I<dir>  Add the named directory to the include file",
1296         "       search path.  This option may be used more than once.",
1297         "       Directories are searched in the order given.",
1298         "",
1299         0
1300 };
1301
1302 /*)Function     VOID    usage()
1303  *
1304  *      The function usage() outputs to the stderr device the
1305  *      assembler name and version and a list of valid assembler options.
1306  *
1307  *      local variables:
1308  *              char ** dp              pointer to an array of
1309  *                                      text string pointers.
1310  *
1311  *      global variables:
1312  *              char    cpu[]           assembler type string
1313  *              char *  usetxt[]        array of string pointers
1314  *
1315  *      functions called:
1316  *              VOID    asexit()        asmain.c
1317  *              int     fprintf()       c_library
1318  *
1319  *      side effects:
1320  *              program is terminated
1321  */
1322
1323 VOID
1324 usage(void)
1325 {
1326         register char   **dp;
1327
1328         fprintf(stderr, "\nASxxxx Assembler %s  (%s)\n\n", VERSION, cpu);
1329         for (dp = usetxt; *dp; dp++)
1330                 fprintf(stderr, "%s\n", *dp);
1331         asexit(1);
1332 }