1 /* asmain.c */
2 
3 /*
4  *  Copyright (C) 1989-2012  Alan R. Baldwin
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any 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  * Alan R. Baldwin
21  * 721 Berkeley St.
22  * Kent, Ohio  44240
23  *
24  *
25  *   With enhancements from
26  *
27  *      John L. Hartman (JLH)
28  *      jhartman at compuserve dot com
29  *
30  *      Boisy G. Pitre (BGP)
31  *      boisy at boisypitre dot com
32  *
33  *      Mike McCarty
34  *      mike dot mccarty at sbcglobal dot net
35  */
36 
37 #include <errno.h>
38 #include <math.h>
39 #include "sdas.h"
40 #include "dbuf_string.h"
41 #include "asxxxx.h"
42 
43 /*)Module       asmain.c
44  *
45  *      The module asmain.c includes the command argument parser,
46  *      the three pass sequencer, and the machine independent
47  *      assembler parsing code.
48  *
49  *      asmain.c contains the following functions:
50  *              int     main(argc, argv)
51  *              VOID    asexit(n)
52  *              VOID    asmbl()
53  *              VOID    equate()
54  *              FILE *  afile(fn, ft, wf)
55  *              int     fndidx(str)
56  *              int     intsiz()
57  *              VOID    newdot(nap)
58  *              VOID    phase(ap, a)
59  *              VOID    usage()
60  *
61  *      asmain.c contains the array char *usetxt[] which
62  *      references the usage text strings printed by usage().
63  */
64 
65 /* sdas specific */
66 static const char *search_path[100];
67 static int search_path_length;
68 
69 /**
70  * The search_path_append is used to append another directory to the end
71  * of the include file search path.
72  *
73  * @param dir
74  *              The directory to be added to the path.
75  */
76 void
search_path_append(const char * dir)77 search_path_append(const char *dir)
78 {
79         if (search_path_length < sizeof(search_path)/sizeof(char*))
80         {
81                 search_path[search_path_length++] = dir;
82         }
83 }
84 
85 /**
86  * The create_temp_path function is used to build a temporary file path
87  * by concatenating dir and filename. If len >= 0 then only the left
88  * substring of dir with length len is used to build the file path.
89  *
90  * @param dir
91  *              The directory part of the path.
92  * @param len
93  *              < 0:  use the whole dir as the directory part of the path.
94  *              >= 0: the length of dir to use as the directory part of the path.
95  * @param filename
96  *              The filename to be appended to the directory part of the path.
97  * @returns
98  *              The constructed path.
99  */
100 static const char *
create_temp_path(const char * dir,int len,const char * filename)101 create_temp_path(const char * dir, int len, const char * filename)
102 {
103         static struct dbuf_s dbuf;
104         const char * path;
105 
106         if (!dbuf_is_initialized(&dbuf))
107                 dbuf_init (&dbuf, 1024);
108 
109         dbuf_set_length(&dbuf, 0);
110         dbuf_append_str(&dbuf, dir);
111         if (len >= 0)
112                 dbuf_set_length(&dbuf, len);
113         path = dbuf_c_str(&dbuf);
114         if ((path[strlen(path) - 1] != '/') &&
115             (path[strlen(path) - 1] != DIR_SEPARATOR_CHAR)) {
116                 dbuf_append_char(&dbuf, DIR_SEPARATOR_CHAR);
117         }
118         dbuf_append_str(&dbuf, filename);
119         path = dbuf_c_str(&dbuf);
120         return path;
121 }
122 
123 /**
124  * The search_path_fopen function is used to open the named file.  If
125  * the file isn't in the current directory, the search path is then used
126  * to build a series of possible file names, and attempts to open them.
127  * The first found is used.
128  *
129  * @param filename
130  *              The name of the file to be opened.
131  * @param mode
132  *              The mode of the file to be opened.
133  * @returns
134  *              what the fopen function would return on success, or NULL if the
135  *              file is not anywhere in the search path.
136  */
137 static FILE *
search_path_fopen(const char * filename,const char * mode)138 search_path_fopen(const char *filename, const char *mode)
139 {
140         FILE *fp;
141         int j;
142 
143         fp = fopen(filename, mode);
144         if (fp != NULL || filename[0] == '/' || filename[0] == '\\')
145                 return fp;
146 
147         /*
148          * Try the path of the file opening the include file
149          */
150         fp = fopen(create_temp_path(afn, afp, filename), mode);
151         if (fp != NULL)
152                 return fp;
153 
154         for (j = 0; j < search_path_length; ++j) {
155                 fp = fopen(create_temp_path(search_path[j], -1, filename), mode);
156                 if (fp != NULL)
157                         return fp;
158         }
159         errno = ENOENT;
160         return NULL;
161 }
162 /* end sdas specific */
163 
164 /*)Function     int     main(argc, argv)
165  *
166  *              int     argc            argument count
167  *              char *  argv            array of pointers to argument strings
168  *
169  *      The function main() is the entry point to the assembler.
170  *      The purpose of main() is to (1) parse the command line
171  *      arguments for options and source file specifications and
172  *      (2) to process the source files through the 3 pass assembler.
173  *      Before each assembler pass various variables are initialized
174  *      and source files are rewound to their beginning.  During each
175  *      assembler pass each assembler-source text line is processed.
176  *      After each assembler pass the assembler information is flushed
177  *      to any opened output files and the if-else-endif processing
178  *      is checked for proper termination.
179  *
180  *      The function main() is also responsible for opening all
181  *      output files (REL, LST, and SYM), sequencing the global (-g)
182  *      and all-global (-a) variable definitions, and dumping the
183  *      REL file header information.
184  *
185  *      local variables:
186  *              char *  p               pointer to argument string
187  *              int     c               character from argument string
188  *              int     i               argument loop counter
189  *              area *  ap              pointer to area structure
190  *
191  *      global variables:
192  *              int     aflag           -a, make all symbols global flag
193  *              char    afn[]           afile() constructed filespec
194  *              int     afp             afile constructed path length
195  *              area *  areap           pointer to an area structure
196  *              asmf *  asmc            pointer to current assembler file structure
197  *              int     asmline         assembler source file line number
198  *              asmf *  asmp            pointer to first assembler file structure
199  *              int     aserr           assembler error counter
200  *              int     bflag           -b(b), listing mode flag
201  *              int     cb[]            array of assembler output values
202  *              int     cbt[]           array of assembler relocation types
203  *                                      describing the data in cb[]
204  *              int *   cp              pointer to assembler output array cb[]
205  *              int *   cpt             pointer to assembler relocation type
206  *                                      output array cbt[]
207  *              char    eb[]            array of generated error codes
208  *              char *  ep              pointer into error list array eb[]
209  *              int     fflag           -f(f), relocations flagged flag
210  *              int     flevel          IF-ELSE-ENDIF flag will be non
211  *                                      zero for false conditional case
212  *              a_uint  fuzz            tracks pass to pass changes in the
213  *                                      address of symbols caused by
214  *                                      variable length instruction formats
215  *              int     gflag           -g, make undefined symbols global flag
216  *              char  * ib              string buffer containing
217  *                                      assembler-source text line for processing
218  *              char  * ic              string buffer containing
219  *                                      assembler-source text line for listing
220  *              int     ifcnd[]         array of IF statement condition
221  *                                      values (0 = FALSE) indexed by tlevel
222  *              int     iflvl[]         array of IF-ELSE-ENDIF flevel
223  *                                      values indexed by tlevel
224  *              int     incfil          current include file count
225  *              int     incline         include source file line number
226  *              char *  ip              pointer into the assembler-source
227  *                                      text line in ib[]
228  *              jmp_buf jump_env        compiler dependent structure
229  *                                      used by setjmp() and longjmp()
230  *              int     lflag           -l, generate listing flag
231  *              int     line            current assembler source
232  *                                      line number
233  *              int     lnlist          current LIST-NLIST state
234  *              int     lop             current line number on page
235  *              int     maxinc          maximum include file nesting counter
236  *              int     oflag           -o, generate relocatable output flag
237  *              int     jflag           -j, generate debug info flag
238  *              int     page            current page number
239  *              int     pflag           disable listing pagination
240  *              int     pass            assembler pass number
241  *              int     radix           current number conversion radix:
242  *                                      2 (binary), 8 (octal), 10 (decimal),
243  *                                      16 (hexadecimal)
244  *              int     sflag           -s, generate symbol table flag
245  *              int     srcline         current source line number
246  *              char    stb[]           Subtitle string buffer
247  *              sym *   symp            pointer to a symbol structure
248  *              int     tlevel          current conditional level
249  *              int     uflag           -u, disable .list/.nlist processing
250  *              int     wflag           -w, enable wide listing format
251  *              int     xflag           -x, listing radix flag
252  *              int     zflag           -z, disable symbol case sensitivity
253  *              FILE *  lfp             list output file handle
254  *              FILE *  ofp             relocation output file handle
255  *              FILE *  tfp             symbol table output file handle
256  *
257  *      called functions:
258  *              FILE *  afile()         asmain.c
259  *              VOID    allglob()       assym.c
260  *              VOID    asexit()        asmain.c
261  *              VOID    diag()          assubr.c
262  *              VOID    err()           assubr.c
263  *              VOID    exprmasks()     asexpr.c
264  *              int     fprintf()       c_library
265  *              int     int32siz()      asmain.c
266  *              VOID    list()          aslist.c
267  *              VOID    lstsym()        aslist.c
268  *              VOID    mcrinit()       asmcro.c
269  *              VOID    minit()         ___mch.c
270  *              char *  new()           assym.c
271  *              VOID    newdot()        asmain.c
272  *              int     nxtline()       aslex.c
273  *              VOID    outbuf()        asout.c
274  *              VOID    outchk()        asout.c
275  *              VOID    outgsd()        asout.c
276  *              int     rewind()        c_library
277  *              int     setjmp()        c_library
278  *              char *  strcpy()        c_library
279  *              VOID    symglob()       assym.c
280  *              VOID    syminit()       assym.c
281  *              VOID    usage()         asmain.c
282  *
283  *      side effects:
284  *              Completion of main() completes the assembly process.
285  *              REL, LST, and/or SYM files may be generated.
286  */
287 
288 /* sdas specific */
289 char relFile[FILSPC];
290 /* end sdas specific */
291 
292 int
main(int argc,char * argv[])293 main(int argc, char *argv[])
294 {
295         char *p = NULL;
296         char *q;
297         int c, i;
298         struct area *ap;
299 
300         if (intsiz() < 4) {
301                 fprintf(stderr, "?ASxxxx-Error-Size of INT32 is not 32 bits or larger.\n\n");
302                 exit(ER_FATAL);
303         }
304 
305         /* sdas specific */
306         /* sdas initialization */
307         sdas_init(argv[0]);
308         /* end sdas specific */
309 
310         if (!is_sdas())
311                 fprintf(stdout, "\n");
312         q = NULL;
313         asmc = NULL;
314         asmp = NULL;
315         for (i=1; i<argc; ++i) {
316                 p = argv[i];
317                 if (*p == '-') {
318                         if (asmc != NULL)
319                                 usage(ER_FATAL);
320                         ++p;
321                         while ((c = *p++) != 0) {
322                                 switch(c) {
323 
324                                 case 'a':
325                                 case 'A':
326                                         ++aflag;
327                                         break;
328 
329                                 case 'b':
330                                 case 'B':
331                                         ++bflag;
332                                         break;
333 
334                                 case 'c':
335                                 case 'C':
336                                         cflag = 1;      /* Cycle counts in listing */
337                                         break;
338 
339                                 case 'g':
340                                 case 'G':
341                                         ++gflag;
342                                         break;
343 
344                                 case 'i':
345                                 case 'I':
346                                         search_path_append(p);
347                                         while (*p)
348                                                 ++p;
349                                         break;
350 
351 #if NOICE
352                                 case 'j':               /* NoICE Debug  JLH */
353                                 case 'J':
354                                         ++jflag;
355                                         ++oflag;        /* force object */
356                                         break;
357 #endif
358 
359 #if SDCDB
360                                 case 'y':               /* SDCC Debug */
361                                 case 'Y':
362                                         ++yflag;
363                                         break;
364 #endif
365 
366                                 case 'l':
367                                 case 'L':
368                                         ++lflag;
369                                         break;
370 
371                                 case 'o':
372                                 case 'O':
373                                         ++oflag;
374                                         break;
375 
376                                 case 's':
377                                 case 'S':
378                                         ++sflag;
379                                         break;
380 
381                                 case 'p':
382                                 case 'P':
383                                         ++pflag;
384                                         break;
385 
386                                 case 'u':
387                                 case 'U':
388                                         ++uflag;
389                                         break;
390 
391                                 case 'w':
392                                 case 'W':
393                                         ++wflag;
394                                         break;
395 
396                                 case 'z':
397                                 case 'Z':
398                                         ++zflag;
399                                         break;
400 
401                                 case 'x':
402                                 case 'X':
403                                         xflag = 0;
404                                         break;
405 
406                                 case 'q':
407                                 case 'Q':
408                                         xflag = 1;
409                                         break;
410 
411                                 case 'd':
412                                 case 'D':
413                                         xflag = 2;
414                                         break;
415 
416                                 case 'f':
417                                 case 'F':
418                                         ++fflag;
419                                         break;
420 
421                                 default:
422                                         usage(ER_FATAL);
423                                 }
424                         }
425                 } else {
426                         if (asmc == NULL) {
427                                 q = p;
428                                 if (++i < argc) {
429                                         p = argv[i];
430                                         if (*p == '-')
431                                                 usage(ER_FATAL);
432                                 }
433                                 asmp = (struct asmf *)
434                                                 new (sizeof (struct asmf));
435                                 asmc = asmp;
436                         } else {
437                                 asmc->next = (struct asmf *)
438                                                 new (sizeof (struct asmf));
439                                 asmc = asmc->next;
440                         }
441                         asmc->next = NULL;
442                         asmc->objtyp = T_ASM;
443                         asmc->line = 0;
444                         asmc->flevel = 0;
445                         asmc->tlevel = 0;
446                         asmc->lnlist = LIST_NORM;
447                         asmc->fp = afile(p, "", 0);
448                         strcpy(asmc->afn,afn);
449                         asmc->afp = afp;
450                 }
451         }
452         if (asmp == NULL)
453                 usage(ER_WARNING);
454         if (lflag)
455                 lfp = afile(q, "lst", 1);
456         /* sdas specific */
457         if (oflag) {
458                 ofp = afile(q, (is_sdas() && p != q) ? "" : "rel", 1);
459                 // save the file name if we have to delete it on error
460                 strcpy(relFile,afn);
461         }
462         /* end sdas specific */
463         if (sflag)
464                 tfp = afile(q, "sym", 1);
465         exprmasks(2);
466         syminit();
467         for (pass=0; pass<3; ++pass) {
468                 aserr = 0;
469                 if (gflag && pass == 1)
470                         symglob();
471                 if (aflag && pass == 1)
472                         allglob();
473                 if (oflag && pass == 2)
474                         outgsd();
475                 flevel = 0;
476                 tlevel = 0;
477                 lnlist = LIST_NORM;
478                 ifcnd[0] = 0;
479                 iflvl[0] = 0;
480                 radix = 10;
481                 page = 0;
482                 /* sdas specific */
483                 org_cnt = 0;
484                 /* end sdas specific */
485                 stb[0] = 0;
486                 lop  = NLPP;
487                 incfil = 0;
488                 maxinc = 0;
489                 srcline = 0;
490                 asmline = 0;
491                 incline = 0;
492                 asmc = asmp;
493                 while (asmc) {
494                         if (asmc->fp)
495                                 rewind(asmc->fp);
496                         asmc = asmc->next;
497                 }
498                 asmc = asmp;
499                 strcpy(afn, asmc->afn);
500                 afp = asmc->afp;
501                 ap = areap;
502                 while (ap) {
503                         ap->a_fuzz = 0;
504                         ap->a_size = 0;
505                         ap = ap->a_ap;
506                 }
507                 fuzz = 0;
508                 dot.s_addr = 0;
509                 dot.s_area = &dca;
510                 outbuf("I");
511                 outchk(0,0);
512                 symp = &dot;
513                 mcrinit();
514                 minit();
515                 while (nxtline()) {
516                         cp = cb;
517                         cpt = cbt;
518                         ep = eb;
519                         ip = ib;
520 
521                         /* JLH: if line begins with ";!", then
522                          * pass this comment on to the output file
523                          */
524                         if (oflag && (pass == 1) && (ip[0] == ';') && (ip[1] == '!')) {
525                                 fprintf(ofp, "%s\n", ip );
526                         }
527 
528                         opcycles = OPCY_NONE;
529                         if (setjmp(jump_env) == 0)
530                                 asmbl();
531                         if (pass == 2) {
532                                 diag();
533                                 list();
534                         }
535                 }
536                 newdot(dot.s_area);     /* Flush area info */
537         }
538         if (flevel || tlevel) {
539                 err('i');
540                 fprintf(stderr, "?ASxxxx-Error-<i> at end of assembly\n");
541                 fprintf(stderr, "              %s\n", geterr('i'));
542         }
543         if (oflag)
544                 outchk(ASXHUGE, ASXHUGE);       /* Flush */
545         if (sflag) {
546                 lstsym(tfp);
547         } else
548         if (lflag) {
549                 lstsym(lfp);
550         }
551         asexit(aserr ? ER_ERROR : ER_NONE);
552         return(0);
553 }
554 
555 /*)Function     int     intsiz()
556  *
557  *      The function intsiz() returns the size of INT32
558  *
559  *      local variables:
560  *              none
561  *
562  *      global variables:
563  *              none
564  *
565  *      functions called:
566  *              none
567  *
568  *      side effects:
569  *              none
570  */
571 
572 int
intsiz(void)573 intsiz(void)
574 {
575         return(sizeof(INT32));
576 }
577 
578 /*)Function     VOID    asexit(i)
579  *
580  *                      int     i       exit code
581  *
582  *      The function asexit() explicitly closes all open
583  *      files and then terminates the program.
584  *
585  *      local variables:
586  *              int     j               loop counter
587  *
588  *      global variables:
589  *              asmf *  asmc            pointer to current assembler file structure
590  *              asmf *  asmp            pointer to first assembler file structure
591  *              FILE *  lfp             list output file handle
592  *              FILE *  ofp             relocation output file handle
593  *              FILE *  tfp             symbol table output file handle
594  *
595  *      functions called:
596  *              int     fclose()        c_library
597  *              VOID    exit()          c_library
598  *
599  *      side effects:
600  *              All files closed. Program terminates.
601  */
602 
603 VOID
asexit(int i)604 asexit(int i)
605 {
606         if (lfp != NULL) fclose(lfp);
607         if (ofp != NULL) fclose(ofp);
608         if (tfp != NULL) fclose(tfp);
609 
610         while (asmc != NULL) {
611                 if ((asmc->objtyp == T_INCL) && (asmc->fp != NULL)) {
612                         fclose(asmc->fp);
613                 }
614                 asmc = asmc->next;
615         }
616 
617         asmc = asmp;
618         while (asmc != NULL) {
619                 if ((asmc->objtyp == T_ASM) && (asmc->fp != NULL)) {
620                         fclose(asmc->fp);
621                 }
622                 asmc = asmc->next;
623         }
624         /* sdas specific */
625         if (i) {
626                 /* remove output file */
627                 printf ("removing %s\n", relFile);
628                 remove(relFile);
629         }
630         /* end sdas specific */
631         exit(i);
632 }
633 
634 /*)Function     VOID    asmbl()
635  *
636  *      The function asmbl() scans the assembler-source text for
637  *      (1) labels, global labels, equates, global equates, and local
638  *      symbols, (2) .if, .else, .endif, and .page directives,
639  *      (3) machine independent assembler directives, (4) macros and
640  *      macro definitions, and (5) machine dependent mnemonics.
641  *
642  *      local variables:
643  *              mne *   mp              pointer to a mne structure
644  *              mne *   xp              pointer to a mne structure
645  *              mcrdef *np              pointer to a macro definition structure
646  *              sym *   sp              pointer to a sym structure
647  *              tsym *  tp              pointer to a tsym structure
648  *              int     c               character from assembler-source
649  *                                      text line
650  *              area *  ap              pointer to an area structure
651  *              expr    e1              expression structure
652  *              char    id[]            id string
653  *              char    opt[]           options string
654  *              char    fn[]            filename string
655  *              char *  p               pointer into a string
656  *              int     d               temporary value
657  *              int     uaf             user area options flag
658  *              int     uf              area options
659  *              a_uint  n               temporary value
660  *              a_uint  v               temporary value
661  *              int     flags           temporary flag
662  *              FILE *  fp              include file handle
663  *              int     m_type          mnemonic type
664  *
665  *      global variables:
666  *              area *  areap           pointer to an area structure
667  *              char    ctype[]         array of character types, one per
668  *                                      ASCII character
669  *              int     flevel          IF-ELSE-ENDIF flag will be non
670  *                                      zero for false conditional case
671  *              int     ftflevel;       IIFF-IIFT-IIFTF FLAG
672  *              int     lnlist          current LIST-NLIST state
673  *              a_uint  fuzz            tracks pass to pass changes in the
674  *                                      address of symbols caused by
675  *                                      variable length instruction formats
676  *              int     ifcnd[]         array of IF statement condition
677  *                                      values (0 = FALSE) indexed by tlevel
678  *              int     iflvl[]         array of IF-ELSE-ENDIF flevel
679  *                                      values indexed by tlevel
680  *              int     incline         current include file line
681  *              int     incfil          current include file count
682  *              a_uint  laddr           address of current assembler line
683  *                                      or value of .if argument
684  *              int     lmode           listing mode
685  *              int     lop             current line number on page
686  *              char    module[]        module name string
687  *              int     pass            assembler pass number
688  *              int     radix           current number conversion radix:
689  *                                      2 (binary), 8 (octal), 10 (decimal),
690  *                                      16 (hexadecimal)
691  *              char    stb[]           Subtitle string buffer
692  *              sym *   symp            pointer to a symbol structure
693  *              char    tb[]            Title string buffer
694  *              int     tlevel          current conditional level
695  *              int     jflag           -j, generate debug info flag
696  *
697  *      functions called:
698  *              a_uint  absexpr()       asexpr.c
699  *              area *  alookup()       assym.c
700  *              VOID    clrexpr()       asexpr.c
701  *              int     digit()         asexpr.c
702  *              char    endline()       aslex.c
703  *              VOID    equate()        asmain.c
704  *              VOID    err()           assubr.c
705  *              VOID    expr()          asexpr.c
706  *              FILE *  fopen()         c_library
707  *              int     get()           aslex.c
708  *              VOID    getid()         aslex.c
709  *              int     getmap()        aslex.c
710  *              int     getnb()         aslex.c
711  *              VOID    getst()         aslex.c
712  *              VOID    getxstr()       asmcro.c
713  *              sym *   lookup()        assym.c
714  *              VOID    machine()       ___mch.c
715  *              int     macro()         asmcro.c
716  *              int     mcrprc()        asmcro.c
717  *              mne *   mlookup()       assym.c
718  *              int     more()          aslex.c
719  *              mcrdef *nlookup()       asmcro.c
720  *              char *  new()           assym.c
721  *              VOID    newdot()        asmain.c
722  *              VOID    outall()        asout.c
723  *              VOID    outab()         asout.c
724  *              VOID    outchk()        asout.c
725  *              VOID    outrb()         asout.c
726  *              VOID    outrw()         asout.c
727  *              VOID    phase()         asmain.c
728  *              VOID    qerr()          assubr.c
729  *              char *  strcpy()        c_library
730  *              char *  strncpy()       c_library
731  *              char *  strsto()        assym.c
732  *              VOID    unget()         aslex.c
733  */
734 
735 VOID
asmbl(void)736 asmbl(void)
737 {
738         struct mne *mp, *xp;
739         struct mcrdef *np;
740         struct sym *sp;
741         struct tsym *tp;
742         int c;
743         struct area  *ap;
744         struct expr e1;
745         char id[NCPS];
746         char equ[NCPS];
747         char *equ_ip;
748         int  equtype;
749         char opt[NCPS];
750         char fn[FILSPC+FILSPC];
751         char *p;
752         int d, uaf, uf;
753         a_uint n, v;
754         int flags;
755         FILE * fp;
756         int m_type;
757         /* sdas specific */
758         static struct area *abs_ap; /* pointer to current absolute area structure */
759         /* end sdas specific */
760 
761         laddr = dot.s_addr;
762         lmode = SLIST;
763 
764         /*
765          * Check iiff-iift-iiftf processing
766          */
767         if (ftflevel != 0) {
768                 flevel = ftflevel - 1;
769                 ftflevel = 0;
770         }
771 
772         /*
773          * Check if Building a Macro
774          * Check if Exiting  a Macro
775          */
776         if (mcrprc(O_CHECK) != 0) {
777                 return;
778         }
779 
780 loop:
781         if ((c=endline()) == 0) { return; }
782 
783         /*
784          * If the first character is a digit then assume
785          * a reusable symbol is being specified.  The symbol
786          * must end with $: to be valid.
787          *      pass 0:
788          *              Construct a tsym structure at the first
789          *              occurance of the symbol.  Flag the symbol
790          *              as multiply defined if not the first occurance.
791          *      pass 1:
792          *              Load area, address, and fuzz values
793          *              into structure tsym.
794          *      pass 2:
795          *              Check for assembler phase error and
796          *              multiply defined error.
797          */
798         if (ctype[c] & DIGIT) {
799                 if (flevel)
800                         return;
801                 n = 0;
802                 while ((d = digit(c, 10)) >= 0) {
803                         n = 10*n + d;
804                         c = get();
805                 }
806                 if (c != '$' || get() != ':')
807                         qerr();
808 
809                 tp = symp->s_tsym;
810                 if (pass == 0) {
811                         while (tp) {
812                                 if (n == tp->t_num) {
813                                         tp->t_flg |= S_MDF;
814                                         break;
815                                 }
816                                 tp = tp->t_lnk;
817                         }
818                         if (tp == NULL) {
819                                 tp=(struct tsym *) new (sizeof(struct tsym));
820                                 tp->t_lnk = symp->s_tsym;
821                                 tp->t_num = n;
822                                 tp->t_flg = 0;
823                                 tp->t_area = dot.s_area;
824                                 tp->t_addr = dot.s_addr;
825                                 symp->s_tsym = tp;
826                         }
827                 } else {
828                         while (tp) {
829                                 if (n == tp->t_num) {
830                                         break;
831                                 }
832                                 tp = tp->t_lnk;
833                         }
834                         if (tp) {
835                                 if (pass == 1) {
836                                         fuzz = tp->t_addr - dot.s_addr;
837                                         tp->t_area = dot.s_area;
838                                         tp->t_addr = dot.s_addr;
839                                 } else {
840                                         phase(tp->t_area, tp->t_addr);
841                                         if (tp->t_flg & S_MDF)
842                                                 err('m');
843                                 }
844                         } else {
845                                 err('u');
846                         }
847                 }
848                 lmode = ALIST;
849                 goto loop;
850         }
851         /*
852          * If the first character is a letter then assume a label,
853          * symbol, assembler directive, or assembler mnemonic is
854          * being processed.
855          */
856         if ((ctype[c] & LETTER) == 0) {
857                 if (flevel) {
858                         return;
859                 } else {
860                         qerr();
861                 }
862         }
863         getid(id, c);
864         c = getnb();
865         /*
866          * If the next character is a : then a label is being processed.
867          * A double :: defines a global label.  If this is a new label
868          * then create a symbol structure.
869          *      pass 0:
870          *              Flag multiply defined labels.
871          *      pass 1:
872          *              Load area, address, and fuzz values
873          *              into structure symp.
874          *      pass 2:
875          *              Check for assembler phase error and
876          *              multiply defined error.
877          */
878         if (c == ':') {
879                 if (flevel)
880                         return;
881                 if ((c = get()) != ':') {
882                         unget(c);
883                         c = 0;
884                 }
885                 symp = lookup(id);
886                 if (symp == &dot)
887                         qerr();
888                 if (pass == 0) {
889                         if ((symp->s_type != S_NEW) && ((symp->s_flag & S_ASG) == 0))
890                                 symp->s_flag |= S_MDF;
891                 }
892                 if (symp->s_flag & S_MDF)
893                         err('m');
894                 symp->s_type = S_USER;
895                 phase(symp->s_area, symp->s_addr);
896                 fuzz = symp->s_addr - dot.s_addr;
897                 symp->s_area = dot.s_area;
898                 symp->s_addr = dot.s_addr;
899                 if (c) {
900                         symp->s_flag |= S_GBL;
901                 }
902                 lmode = ALIST;
903                 goto loop;
904         }
905         /*
906          * If the next character is a = then an equate is being processed.
907          *
908          * Syntax:
909          *    [labels] sym =  value   defines an equate.
910          *    [labels] sym == value   defines a global equate.
911          *    [labels] sym =: value   defines an internal machine equate.
912          * If this is a new variable then create a symbol structure.
913          */
914         if (c == '=') {
915                 if (flevel)
916                         return;
917                 switch (c = get()) {
918                     case '=':   equtype = O_GBLEQU;                     break;
919                     case ':':   equtype = O_LCLEQU;                     break;
920                     default:    equtype = O_EQU;        unget(c);       break;
921                 }
922                 equate(id, &e1, equtype);
923                 goto loop;
924         }
925         unget(c);
926         /*
927          * Check for Equates if 'id' is not an Assembler Directive
928          *
929          * Syntax:
930          *     [labels] sym .equ    value   defines an equate
931          *     [labels] sym .glbequ value   defines a global equate
932          *     [labels] sym .lclequ value   defines a local equate
933          */
934         if ((mlookup(id) == NULL) && (nlookup(id) == NULL)) {
935                 if (flevel)
936                         return;
937                 /*
938                  * Alternates for =, ==, and =:
939                  */
940                 equ_ip = ip;     /* Save current char pointer for case equate not found. */
941                 getid(equ, -1);
942                 if ((mp = mlookup(equ)) == NULL || mp->m_type != S_EQU) {
943                         ip = equ_ip;
944                 } else {
945                         equate(id, &e1, mp->m_valu);
946                         goto loop;
947                 }
948         }
949         /*
950          * Completed scan for labels , equates, and symbols.
951          */
952         lmode = flevel ? SLIST : CLIST;
953         /*
954          * An assembler directive, mnemonic, or macro is
955          * required to continue processing line.
956          */
957         mp = mlookup(id);
958         np = nlookup(id);
959         if ((mp == NULL) && (np == NULL)) {
960                 if (!flevel) {
961                         err('o');
962                 }
963                 return;
964         }
965         /*
966          * If we have gotten this far then we have found an
967          * assembler directive an assembler mnemonic or
968          * an assembler macro.
969          *
970          * Check for .if[], .iif[], .else, .endif,
971          * .list, .nlist, and .page directives.
972          */
973         m_type = (mp != NULL) ? mp->m_type : ~0;
974 
975         switch (m_type) {
976 
977         case S_CONDITIONAL:
978                 /*
979                  * BGP - .ifeq, .ifne, .ifgt, .iflt, .ifge, .ifle
980                  */
981                 if (mp->m_valu < O_IFEND) {
982                         if (mp->m_valu == O_IF) {
983                                 /*
984                                  * Process conditionals of the form
985                                  *
986                                  *      .if     cnd(,)  arg1 (, arg2)
987                                  *
988                                  * where cnd is one of the following:
989                                  *
990                                  *      eq      ne
991                                  *      gt      lt      ge      le
992                                  *      def     ndef
993                                  *      b       nb      idn     dif
994                                  *      t       f       tf
995                                  */
996                                 p = ip;
997                                 strcpy(id,".if");
998                                 getid(&id[3],getnb());
999                                 xp = mlookup(id);
1000                                 if ((xp != NULL) &&
1001                                     (xp->m_type == S_CONDITIONAL) &&
1002                                     (xp->m_valu != O_IF)) {
1003                                         mp = xp;
1004                                         comma(0);
1005                                 } else {
1006                                         ip = p;
1007                                 }
1008                         }
1009                         if (flevel) {
1010                                 n = 0;
1011                         } else {
1012                                 switch (mp->m_valu) {
1013                                 case O_IF:
1014                                 case O_IFNE:    /* .if ne,.... */
1015                                 case O_IFEQ:    /* .if eq,.... */
1016                                 case O_IFGT:    /* .if gt,.... */
1017                                 case O_IFLT:    /* .if lt,.... */
1018                                 case O_IFGE:    /* .if ge,.... */
1019                                 case O_IFLE:    /* .if le,.... */
1020                                         n = absexpr();
1021                                         switch (mp->m_valu) {
1022                                         default:
1023                                         case O_IF:
1024                                         case O_IFNE:    n = (((v_sint) n) != 0);        break;
1025                                         case O_IFEQ:    n = (((v_sint) n) == 0);        break;
1026                                         case O_IFGT:    n = (((v_sint) n) >  0);        break;
1027                                         case O_IFLT:    n = (((v_sint) n) <  0);        break;
1028                                         case O_IFGE:    n = (((v_sint) n) >= 0);        break;
1029                                         case O_IFLE:    n = (((v_sint) n) <= 0);        break;
1030                                         }
1031                                         break;
1032 
1033                                 case O_IFF:     /* .if f */
1034                                 case O_IFT:     /* .if t */
1035                                 case O_IFTF:    /* .if tf */
1036                                         n = 0;
1037                                         break;
1038 
1039                                 default:
1040                                         n = 0;
1041                                         qerr();
1042                                         break;
1043                                 }
1044                         }
1045                         switch (mp->m_valu) {
1046                         default:
1047                                 if (tlevel < MAXIF) {
1048                                         ++tlevel;
1049                                         ifcnd[tlevel] = (int) n;
1050                                         iflvl[tlevel] = flevel;
1051                                         if (!n) {
1052                                                 ++flevel;
1053                                         }
1054                                 } else {
1055                                         err('i');
1056                                 }
1057                                 if (!iflvl[tlevel]) {
1058                                         lmode = ELIST;
1059                                         laddr = n;
1060                                 } else {
1061                                         lmode = SLIST;
1062                                 }
1063                                 break;
1064 
1065                         case O_IFF:     /* .if f */
1066                         case O_IFT:     /* .if t */
1067                         case O_IFTF:    /* .if tf */
1068                                 if (tlevel == 0) {
1069                                         err('i');
1070                                         lmode = SLIST;
1071                                         break;
1072                                 }
1073                                 if (iflvl[tlevel] == 0) {
1074                                         if (ifcnd[tlevel]) {
1075                                                 switch (mp->m_valu) {
1076                                                 default:
1077                                                 case O_IFF:     flevel = 1;     break;
1078                                                 case O_IFT:     flevel = 0;     break;
1079                                                 case O_IFTF:    flevel = 0;     break;
1080                                                 }
1081                                         } else {
1082                                                 switch (mp->m_valu) {
1083                                                 default:
1084                                                 case O_IFF:     flevel = 0;     break;
1085                                                 case O_IFT:     flevel = 1;     break;
1086                                                 case O_IFTF:    flevel = 0;     break;
1087                                                 }
1088                                         }
1089                                         lmode = ELIST;
1090                                         laddr = flevel ? 0 : 1;
1091                                 } else {
1092                                         lmode = SLIST;
1093                                 }
1094                                 break;
1095                         }
1096                         return;
1097                 } else
1098                 if (mp->m_valu < O_IIFEND) {
1099                         if (mp->m_valu == O_IIF) {
1100                                 /*
1101                                  * Process conditionals of the form
1102                                  *
1103                                  *      .iif    cnd(,)  arg1 (, arg2)
1104                                  *
1105                                  * where cnd is one of the following:
1106                                  *
1107                                  *      eq      ne
1108                                  *      gt      lt      ge      le
1109                                  *      def     ndef
1110                                  *      b       nb      idn     dif
1111                                  *      t       f       tf
1112                                  */
1113                                 p = ip;
1114                                 strcpy(id,".iif");
1115                                 getid(&id[4],getnb());
1116                                 xp = mlookup(id);
1117                                 if ((xp != NULL) &&
1118                                     (xp->m_type == S_CONDITIONAL) &&
1119                                     (xp->m_valu != O_IIF)) {
1120                                         mp = xp;
1121                                         comma(0);
1122                                 } else {
1123                                         ip = p;
1124                                 }
1125                         }
1126                         switch (mp->m_valu) {
1127                         case O_IIFF:    /* .iif f */
1128                         case O_IIFT:    /* .iif t */
1129                         case O_IIFTF:   /* .iif tf */
1130                                 if (tlevel == 0) {
1131                                         err('i');
1132                                         lmode = SLIST;
1133                                         return;
1134                                 }
1135                                 if (iflvl[tlevel] == 0) {
1136                                         ftflevel = flevel + 1;
1137                                         if (ifcnd[tlevel] != 0) {
1138                                                 switch (mp->m_valu) {
1139                                                 default:
1140                                                 case O_IIFF:    flevel = 1;     break;
1141                                                 case O_IIFT:    flevel = 0;     break;
1142                                                 case O_IIFTF:   flevel = 0;     break;
1143                                                 }
1144                                         } else {
1145                                                 switch (mp->m_valu) {
1146                                                 default:
1147                                                 case O_IIFF:    flevel = 0;     break;
1148                                                 case O_IIFT:    flevel = 1;     break;
1149                                                 case O_IIFTF:   flevel = 0;     break;
1150                                                 }
1151                                         }
1152                                 }
1153                                 n = flevel ? 0 : 1;
1154                                 /*
1155                                  * Skip trailing ','
1156                                  */
1157                                 comma(0);
1158                                 lmode = SLIST;
1159                                 if (n) {
1160                                         goto loop;
1161                                 }
1162                                 return;
1163 
1164                         default:
1165                                 if (flevel) {
1166                                         return;
1167                                 }
1168                                 break;
1169                         }
1170                         switch (mp->m_valu) {
1171                         case O_IIF:
1172                         case O_IIFNE:   /* .iif ne,.... */
1173                         case O_IIFEQ:   /* .iif eq,.... */
1174                         case O_IIFGT:   /* .iif gt,.... */
1175                         case O_IIFLT:   /* .iif lt,.... */
1176                         case O_IIFGE:   /* .iif ge,.... */
1177                         case O_IIFLE:   /* .iif le,.... */
1178                                 n = absexpr();
1179                                 switch (mp->m_valu) {
1180                                 default:
1181                                 case O_IIF:
1182                                 case O_IIFNE:   n = (((v_sint) n) != 0);        break;
1183                                 case O_IIFEQ:   n = (((v_sint) n) == 0);        break;
1184                                 case O_IIFGT:   n = (((v_sint) n) >  0);        break;
1185                                 case O_IIFLT:   n = (((v_sint) n) <  0);        break;
1186                                 case O_IIFGE:   n = (((v_sint) n) >= 0);        break;
1187                                 case O_IIFLE:   n = (((v_sint) n) <= 0);        break;
1188                                 }
1189                                 break;
1190 
1191                         default:
1192                                 n = 0;
1193                                 qerr();
1194                                 break;
1195                         }
1196                         /*
1197                          * Skip trailing ','
1198                          */
1199                         comma(0);
1200                         lmode = SLIST;
1201                         if (n) {
1202                                 goto loop;
1203                         }
1204                         return;
1205                 }
1206 
1207                 switch (mp->m_valu) {
1208                 case O_ELSE:
1209                         if (tlevel != 0) {
1210                                 if (ifcnd[tlevel]) {
1211                                         flevel = iflvl[tlevel] + 1;
1212                                         ifcnd[tlevel] = 0;
1213                                 } else {
1214                                         flevel = iflvl[tlevel];
1215                                         ifcnd[tlevel] = 1;
1216                                 }
1217                                 if (!iflvl[tlevel]) {
1218                                         lmode = ELIST;
1219                                         laddr = ifcnd[tlevel];
1220                                         return;
1221                                 }
1222                         } else {
1223                                 err('i');
1224                         }
1225                         lmode = SLIST;
1226                         return;
1227 
1228                 case O_ENDIF:
1229                         if (tlevel) {
1230                                 flevel = iflvl[tlevel--];
1231                         } else {
1232                                 err('i');
1233                         }
1234                         lmode = SLIST;
1235                         return;
1236 
1237                 default:
1238                         break;
1239                 }
1240                 qerr();
1241                 break;
1242 
1243         case S_LISTING:
1244                 flags = 0;
1245                 while ((c=endline()) != 0) {
1246                         if (c == ',') {
1247                                 c = getnb();
1248                         }
1249                         if (c == '(') {
1250                                 do {
1251                                         if ((c = getnb()) == '!') {
1252                                                 flags |= LIST_NOT;
1253                                         } else {
1254                                                 unget(c);
1255                                                 getid(id, -1);
1256                                                 if (symeq(id, "err", 1)) { flags |= LIST_ERR; } else
1257                                                 if (symeq(id, "loc", 1)) { flags |= LIST_LOC; } else
1258                                                 if (symeq(id, "bin", 1)) { flags |= LIST_BIN; } else
1259                                                 if (symeq(id, "eqt", 1)) { flags |= LIST_EQT; } else
1260                                                 if (symeq(id, "cyc", 1)) { flags |= LIST_CYC; } else
1261                                                 if (symeq(id, "lin", 1)) { flags |= LIST_LIN; } else
1262                                                 if (symeq(id, "src", 1)) { flags |= LIST_SRC; } else
1263                                                 if (symeq(id, "pag", 1)) { flags |= LIST_PAG; } else
1264                                                 if (symeq(id, "lst", 1)) { flags |= LIST_LST; } else
1265                                                 if (symeq(id, "md" , 1)) { flags |= LIST_MD;  } else
1266                                                 if (symeq(id, "me" , 1)) { flags |= LIST_ME;  } else
1267                                                 if (symeq(id, "meb", 1)) { flags |= LIST_MEB; } else {
1268                                                         err('u');
1269                                                 }
1270                                         }
1271                                         c = endline();
1272                                 } while (c == ',') ;
1273                                 if (c != ')') {
1274                                         qerr();
1275                                 }
1276                         } else {
1277                                 unget(c);
1278                                 if (absexpr()) {
1279                                         flags |=  LIST_TORF;
1280                                 } else {
1281                                         flags &= ~LIST_TORF;
1282                                 }
1283                         }
1284                 }
1285                 if (!(flags & LIST_TORF) && flevel) {
1286                         return;
1287                 }
1288                 if (flags & ~LIST_TORF) {
1289                         if (flags & LIST_NOT) {
1290                                 switch(mp->m_valu) {
1291                                 case O_LIST:    lnlist = LIST_NONE;     break;
1292                                 case O_NLIST:   lnlist = LIST_NORM;     break;
1293                                 default:                                break;
1294                                 }
1295                         }
1296                         if (flags & LIST_BITS) {
1297                                 switch(mp->m_valu) {
1298                                 case O_LIST:    lnlist |=  (flags & LIST_BITS); break;
1299                                 case O_NLIST:   lnlist &= ~(flags & LIST_BITS); break;
1300                                 default:                                        break;
1301                                 }
1302                         }
1303                 } else {
1304                         switch(mp->m_valu) {
1305                         case O_LIST:    lnlist = LIST_NORM;     break;
1306                         case O_NLIST:   lnlist = LIST_NONE;     break;
1307                         default:                                break;
1308                         }
1309                 }
1310                 lmode = (lnlist & LIST_LST) ? SLIST : NLIST;
1311                 return;
1312 
1313         case S_PAGE:
1314                 lmode = NLIST;
1315                 if (more()) {
1316                         n = absexpr() ? 1 : 0;
1317                 } else {
1318                         n = 0;
1319                 }
1320                 if (!n && flevel)
1321                         return;
1322 
1323                 lop = NLPP;
1324                 return;
1325 
1326         default:
1327                 break;
1328         }
1329         if (flevel)
1330                 return;
1331         /*
1332          * If we are not in a false state for .if/.else then
1333          * process the assembler directives here.
1334          */
1335         switch (m_type) {
1336 
1337         case S_HEADER:
1338                 switch(mp->m_valu) {
1339                 case O_TITLE:
1340                         p = tb;
1341                         if ((c = getnb()) != 0) {
1342                                 do {
1343                                         if (p < &tb[NTITL-1])
1344                                                 *p++ = c;
1345                                 } while ((c = get()) != 0);
1346                         }
1347                         *p = 0;
1348                         unget(c);
1349                         lmode = SLIST;
1350                         break;
1351 
1352                 case O_SBTTL:
1353                         p = stb;
1354                         if ((c = getnb()) != 0) {
1355                                 do {
1356                                         if (p < &stb[NSBTL-1])
1357                                                 *p++ = c;
1358                                 } while ((c = get()) != 0);
1359                         }
1360                         *p = 0;
1361                         unget(c);
1362                         lmode = SLIST;
1363                         break;
1364 
1365                 default:
1366                         break;
1367                 }
1368                 break;
1369 
1370         case S_MODUL:
1371                 getst(id, getnb()); // a module can start with a digit
1372                 if (pass == 0) {
1373                         if (module[0]) {
1374                                 err('m');
1375                         } else {
1376                                 strncpy(module, id, NCPS);
1377                         }
1378                 }
1379                 lmode = SLIST;
1380                 break;
1381 
1382         case S_INCL:
1383                 lmode = SLIST;
1384                 if (incfil > maxinc) {
1385                         maxinc = incfil;
1386                 }
1387                 /*
1388                  * Copy the .include file specification
1389                  */
1390                 getdstr(fn, FILSPC + FILSPC);
1391                 /*
1392                  * Open File
1393                  */
1394                 if ((fp = search_path_fopen(fn, "r")) == NULL) {
1395                         --incfil;
1396                         err('i');
1397                 } else {
1398                         asmi = (struct asmf *) new (sizeof (struct asmf));
1399                         asmi->next = asmc;
1400                         asmi->objtyp = T_INCL;
1401                         asmi->line = srcline;
1402                         asmi->flevel = flevel;
1403                         asmi->tlevel = tlevel;
1404                         asmi->lnlist = lnlist;
1405                         asmi->fp = fp;
1406                         asmi->afp = afptmp;
1407                         strcpy(asmi->afn,afntmp);
1408                         if (lnlist & LIST_PAG) {
1409                                 lop = NLPP;
1410                         }
1411                 }
1412                 break;
1413 
1414         /* sdas specific */
1415         case S_OPTSDCC:
1416                 optsdcc = strsto(ip);
1417                 lmode = SLIST;
1418                 return; /* line consumed */
1419         /* end sdas specific */
1420 
1421         case S_AREA:
1422                 getid(id, -1);
1423                 uaf = 0;
1424                 uf  = A_CON|A_REL;
1425                 if ((c = getnb()) == '(') {
1426                         do {
1427                                 getid(opt, -1);
1428                                 mp = mlookup(opt);
1429                                 if (mp && mp->m_type == S_ATYP) {
1430                                         ++uaf;
1431                                         v = mp->m_valu;
1432                                         uf |= (int) v;
1433                                 } else {
1434                                         err('u');
1435                                 }
1436                         } while ((c = getnb()) == ',');
1437                         if (c != ')')
1438                                 qerr();
1439                 } else {
1440                         unget(c);
1441                 }
1442                 if ((ap = alookup(id)) != NULL) {
1443                         if (uaf && uf != ap->a_flag)
1444                                 err('m');
1445                 } else {
1446                         ap = (struct area *) new (sizeof(struct area));
1447                         ap->a_ap = areap;
1448                         ap->a_id = strsto(id);
1449                         ap->a_ref = areap->a_ref + 1;
1450                         /* sdas specific */
1451                         ap->a_addr = 0;
1452                         /* end sdas specific */
1453                         ap->a_size = 0;
1454                         ap->a_fuzz = 0;
1455                         ap->a_flag = uaf ? uf : (A_CON|A_REL);
1456                         areap = ap;
1457                 }
1458                 newdot(ap);
1459                 lmode = SLIST;
1460                 if (dot.s_area->a_flag & A_ABS)
1461                         abs_ap = ap;
1462                 break;
1463 
1464         case S_ORG:
1465                 if (dot.s_area->a_flag & A_ABS) {
1466                         char buf[NCPS];
1467 
1468                         outall();
1469                         laddr = absexpr();
1470                         sprintf(buf, "%s%x", abs_ap->a_id, org_cnt++);
1471                         if ((ap = alookup(buf)) == NULL) {
1472                                 ap = (struct area *) new (sizeof(struct area));
1473                                 *ap = *areap;
1474                                 ap->a_ap = areap;
1475                                 ap->a_id = strsto(buf);
1476                                 ap->a_ref = areap->a_ref + 1;
1477                                 ap->a_size = 0;
1478                                 ap->a_fuzz = 0;
1479                                 areap = ap;
1480                         }
1481                         newdot(ap);
1482                         dot.s_addr = dot.s_org = laddr;
1483                 } else {
1484                         err('o');
1485                 }
1486                 outall();
1487                 lmode = ALIST;
1488                 break;
1489 
1490         case S_RADIX:
1491                 if (more()) {
1492                         switch (getnb()) {
1493                         case 'b':
1494                         case 'B':
1495                                 radix = 2;
1496                                 break;
1497                         case '@':
1498                         case 'o':
1499                         case 'O':
1500                         case 'q':
1501                         case 'Q':
1502                                 radix = 8;
1503                                 break;
1504                         case 'd':
1505                         case 'D':
1506                                 radix = 10;
1507                                 break;
1508                         case 'h':
1509                         case 'H':
1510                         case 'x':
1511                         case 'X':
1512                                 radix = 16;
1513                                 break;
1514                         default:
1515                                 radix = 10;
1516                                 qerr();
1517                                 break;
1518                         }
1519                 } else {
1520                         radix = 10;
1521                 }
1522                 lmode = SLIST;
1523                 break;
1524 
1525         case S_GLOBL:
1526                 do {
1527                         getid(id, -1);
1528                         sp = lookup(id);
1529                         sp->s_flag &= ~S_LCL;
1530                         sp->s_flag |=  S_GBL;
1531                 } while (comma(0));
1532                 lmode = SLIST;
1533                 break;
1534 
1535         case S_LOCAL:
1536                 do {
1537                         getid(id, -1);
1538                         sp = lookup(id);
1539                         sp->s_flag &= ~S_GBL;
1540                         sp->s_flag |=  S_LCL;
1541                 } while (comma(0));
1542                 lmode = SLIST;
1543                 break;
1544 
1545         case S_EQU:
1546                 /*
1547                  * Syntax:
1548                  *     [labels] .equ    sym, value   defines an equate
1549                  *     [labels] .glbequ sym, value   defines a global equate
1550                  *     [labels] .lclequ sym, value   defines a local equate
1551                  */
1552                 getid(id, -1);
1553                 comma(1);
1554                 equate(id, &e1, mp->m_valu);
1555                 break;
1556 
1557         case S_DATA:
1558                 switch (mp->m_valu) {
1559                 case O_1BYTE:
1560                 case O_2BYTE:
1561                         do {
1562                                 clrexpr(&e1);
1563                                 expr(&e1, 0);
1564                                 if (mp->m_valu == O_1BYTE) {
1565                                         outrb(&e1, R_NORM);
1566                                 } else {
1567                                         outrw(&e1, R_NORM);
1568                                 }
1569                         } while ((c = getnb()) == ',');
1570                         unget(c);
1571                         break;
1572                 default:
1573                         break;
1574                 }
1575                 break;
1576 
1577         /* sdas z80 specific */
1578         case S_FLOAT:
1579                 do {
1580                         double f1, f2;
1581                         unsigned int mantissa, exponent;
1582                         char readbuffer[80];
1583 
1584                         getid(readbuffer, ' '); /* Hack :) */
1585                         if ((c = getnb()) == '.') {
1586                                 getid(&readbuffer[strlen(readbuffer)], '.');
1587                         }
1588                         else
1589                                 unget(c);
1590 
1591                         f1 = strtod(readbuffer, (char **)NULL);
1592                         /* Convert f1 to a gb-lib type fp
1593                          * 24 bit mantissa followed by 7 bit exp and 1 bit sign
1594                          */
1595 
1596                         if (f1 != 0) {
1597                                 f2 = floor(log(fabs(f1)) / log(2)) + 1;
1598                                 mantissa = (unsigned int) ((0x1000000 * fabs(f1)) / exp(f2 * log(2)));
1599                                 mantissa &= 0xffffff;
1600                                 exponent = (unsigned int) (f2 + 0x40) ;
1601                                 if (f1 < 0)
1602                                         exponent |=0x80;
1603                         }
1604                         else {
1605                                 mantissa = 0;
1606                                 exponent = 0;
1607                         }
1608 
1609                         outab(mantissa & 0xff);
1610                         outab((mantissa >> 8) & 0xff);
1611                         outab((mantissa >> 16) & 0xff);
1612                         outab(exponent & 0xff);
1613 
1614                 } while ((c = getnb()) == ',');
1615                 unget(c);
1616                 break;
1617         /* end sdas z80 specific */
1618 
1619         /* sdas hc08 specific */
1620         case S_ULEB128:
1621         case S_SLEB128:
1622                 do {
1623                         a_uint val = absexpr();
1624                         int bit = sizeof(val)*8 - 1;
1625                         int impliedBit;
1626 
1627                         if (mp->m_type == S_ULEB128) {
1628                                 impliedBit = 0;
1629                         } else {
1630                                 impliedBit = (val & (1 << bit)) ? 1 : 0;
1631                         }
1632                         while ((bit>0) && (((val & (1 << bit)) ? 1 : 0) == impliedBit)) {
1633                                 bit--;
1634                         }
1635                         if (mp->m_type == S_SLEB128) {
1636                                 bit++;
1637                         }
1638                         while (bit>=0) {
1639                                 if (bit<7) {
1640                                         outab(val & 0x7f);
1641                                 } else {
1642                                         outab(0x80 | (val & 0x7f));
1643                                 }
1644                                 bit -= 7;
1645                                 val >>= 7;
1646                         }
1647                 } while ((c = getnb()) == ',');
1648                 unget(c);
1649                 break;
1650         /* end sdas hc08 specific */
1651 
1652         case S_BLK:
1653                 clrexpr(&e1);
1654                 expr(&e1, 0);
1655                 outchk(ASXHUGE,ASXHUGE);
1656                 dot.s_addr += e1.e_addr*mp->m_valu;
1657                 lmode = BLIST;
1658                 break;
1659 
1660         case S_ASCIX:
1661                 switch(mp->m_valu) {
1662                 case O_ASCII:
1663                 case O_ASCIZ:
1664                         if ((d = getnb()) == '\0')
1665                                 qerr();
1666                         while ((c = getmap(d)) >= 0)
1667                                 outab(c);
1668                         if (mp->m_valu == O_ASCIZ)
1669                                 outab(0);
1670                         break;
1671 
1672                 case O_ASCIS:
1673                         if ((d = getnb()) == '\0')
1674                                 qerr();
1675                         c = getmap(d);
1676                         while (c >= 0) {
1677                                 int n2;
1678                                 if ((n2 = getmap(d)) >= 0) {
1679                                         outab(c);
1680                                 } else {
1681                                         outab(c | 0x80);
1682                                 }
1683                                 n = n2;
1684                                 c = n2;
1685                         }
1686                         break;
1687                 default:
1688                         break;
1689                 }
1690                 break;
1691 
1692         case S_BOUNDARY:
1693                 switch(mp->m_valu) {
1694                 case O_EVEN:
1695                         outall();
1696                         laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
1697                         lmode = ALIST;
1698                         break;
1699 
1700                 case O_ODD:
1701                         outall();
1702                         laddr = dot.s_addr |= 1;
1703                         lmode = ALIST;
1704                         break;
1705 
1706                 case O_BNDRY:
1707                         v = absexpr();
1708                         n = dot.s_addr % v;
1709                         if (n != 0) {
1710                                 dot.s_addr += (v - n);
1711                         }
1712                         outall();
1713                         laddr = dot.s_addr;
1714                         lmode = ALIST;
1715                         break;
1716 
1717                 default:
1718                         break;
1719                 }
1720                 break;
1721 
1722         case S_MACRO:
1723                 lmode = SLIST;
1724                 mcrprc((int) mp->m_valu);
1725                 return;
1726 
1727         /*
1728          * If not an assembler directive then go to the
1729          * macro function or machine dependent function
1730          * which handles all the assembler mnemonics.
1731          *
1732          * MACRO Definitions take precedence
1733          * over machine specific mnemonics.
1734          */
1735         default:
1736                 if (np != NULL) {
1737                         macro(np);
1738                 } else {
1739                         machine(mp);
1740                 }
1741 
1742                 /*
1743                  * Include Files and Macros are not Debugged
1744                  */
1745                 if (asmc->objtyp == T_ASM) {
1746 
1747 #if NOICE
1748                         /*
1749                          * NoICE        JLH
1750                          * if -j, generate a line number symbol
1751                          */
1752                         if (jflag && (pass == 1)) {
1753                                 DefineNoICE_Line();
1754                         }
1755 #endif
1756 
1757 #if SDCDB
1758                         /*
1759                          * SDCC Debug Information
1760                          * if cdb information then generate the line info
1761                          */
1762                         if (yflag && (pass == 1)) {
1763                                 DefineSDCC_Line();
1764                         }
1765 #endif
1766                 }
1767 
1768                 break;
1769         }
1770 
1771         if (is_sdas()) {
1772                 if ((c = endline()) != 0) {
1773                         err('q');
1774                 }
1775         }
1776         else {
1777                 goto loop;
1778         }
1779 }
1780 
1781 /*)Function     VOID    equate(id,e1,equtype)
1782  *
1783  *              char *          id              ident to equate
1784  *              struct expr *   e1              value of equate
1785  *              a_uint          equtype         equate type (O_EQU,O_LCLEQU,O_GBLEQU)
1786  *
1787  *      The function equate() installs an equate of a
1788  *      given type.
1789  *
1790  *      equate has no return value
1791  *
1792  *      local variables:
1793  *              struct sym *    sp      symbol being equated
1794  *
1795  *      global variables:
1796  *              lmode                   set to ELIST
1797  *
1798  *      functions called:
1799  *              VOID    clrexpr()       asexpr.c
1800  *              VOID    expr()          asexpr.c
1801  *              VOID    err()           assubr.c
1802  *              sym  *  lookup()        assym.c
1803  *              VOID    outall()        asout.c
1804  *              VOID    rerr()          assubr.c
1805  *
1806  *      side effects:
1807  *              A new symbol may be created.
1808  *              Symbol parameters are updated.
1809  */
1810 
1811 VOID
equate(char * id,struct expr * e1,a_uint equtype)1812 equate(char *id, struct expr *e1, a_uint equtype)
1813 {
1814         struct sym *sp;
1815 
1816         clrexpr(e1);
1817         expr(e1, 0);
1818 
1819         sp = lookup(id);
1820 
1821         if (sp == &dot) {
1822                 outall();
1823                 if (e1->e_flag || e1->e_base.e_ap != dot.s_area)
1824                         err('.');
1825         } else {
1826                 switch(equtype) {
1827                 case O_EQU:
1828                 default:
1829                         break;
1830 
1831                 case O_GBLEQU:
1832                         sp->s_flag &= ~S_LCL;
1833                         sp->s_flag |=  S_GBL;
1834                         break;
1835 
1836                 case O_LCLEQU:
1837                         sp->s_flag &= ~S_GBL;
1838                         sp->s_flag |=  S_LCL;
1839                         break;
1840                 }
1841 
1842                 if (e1->e_flag && (e1->e_base.e_sp->s_type == S_NEW)) {
1843                         rerr();
1844                 } else {
1845                         sp->s_area = e1->e_base.e_ap;
1846                 }
1847                 sp->s_flag |= S_ASG;
1848                 sp->s_type = S_USER;
1849         }
1850 
1851         sp->s_addr = laddr = e1->e_addr;
1852         lmode = ELIST;
1853 }
1854 
1855 /*)Function     FILE *  afile(fn, ft, wf)
1856  *
1857  *              char *  fn              file specification string
1858  *              char *  ft              file type string
1859  *              int     wf              read(0)/write(1) flag
1860  *
1861  *      The function afile() opens a file for reading or writing.
1862  *
1863  *      afile() returns a file handle for the opened file or aborts
1864  *      the assembler on an open error.
1865  *
1866  *      local variables:
1867  *              FILE *  fp              file handle for opened file
1868  *
1869  *      global variables:
1870  *              char    afn[]           afile() constructed filespec
1871  *              int     afp             afile() constructed path length
1872  *              char    afntmp[]        afilex() constructed filespec
1873  *              int     afptmp          afilex() constructed path length
1874  *
1875  *      functions called:
1876  *              VOID    asexit()        asmain.c
1877  *              VOID    afilex()        asmain.c
1878  *              FILE *  fopen()         c_library
1879  *              int     fprintf()       c_library
1880  *              char *  strcpy()        c_library
1881  *
1882  *      side effects:
1883  *              File is opened for read or write.
1884  */
1885 
1886 FILE *
afile(char * fn,char * ft,int wf)1887 afile(char *fn, char *ft, int wf)
1888 {
1889         FILE *fp;
1890 
1891         afilex(fn, ft);
1892 
1893         if ((fp = fopen(afntmp, wf?"w":"r")) == NULL) {
1894             fprintf(stderr, "?ASxxxx-Error-<cannot %s> : \"%s\"\n", wf?"create":"open", afntmp);
1895             asexit(ER_FATAL);
1896         }
1897 
1898         strcpy(afn, afntmp);
1899         afp = afptmp;
1900 
1901         return (fp);
1902 }
1903 
1904 /*)Function     VOID    afilex(fn, ft)
1905  *
1906  *              char *  fn              file specification string
1907  *              char *  ft              file type string
1908  *
1909  *      The function afilex() processes the file specification string:
1910  *              (1)     If the file type specification string ft
1911  *                      is not NULL then a file specification is
1912  *                      constructed with the file path\name in fn
1913  *                      and the extension in ft.
1914  *              (2)     If the file type specification string ft
1915  *                      is NULL then the file specification is
1916  *                      constructed from fn.  If fn does not have
1917  *                      a file type then the default source file
1918  *                      type dsft is appended to the file specification.
1919  *
1920  *      afilex() aborts the assembler on a file specification length error.
1921  *
1922  *      local variables:
1923  *              int     c               character value
1924  *              char *  p1              pointer into filespec string afntmp
1925  *              char *  p2              pointer to filetype string ft
1926  *
1927  *      global variables:
1928  *              char    afntmp[]        afilex() constructed filespec
1929  *              int     afptmp          afilex() constructed path length
1930  *              char    dsft[]          default assembler file type string
1931  *
1932  *      functions called:
1933  *              VOID    asexit()        asmain.c
1934  *              int     fndidx()        asmain.c
1935  *              int     fprintf()       c_library
1936  *              char *  strcpy()        c_library
1937  *              int     strlen()        c_library
1938  *
1939  *      side effects:
1940  *              File specification string may be modified.
1941  */
1942 
1943 VOID
afilex(char * fn,char * ft)1944 afilex(char *fn, char *ft)
1945 {
1946         char *p1, *p2;
1947         int c;
1948 
1949         if (strlen(fn) > (FILSPC-7)) {
1950                 fprintf(stderr, "?ASxxxx-Error-<filspc to long> : \"%s\"\n", fn);
1951                 asexit(ER_FATAL);
1952         }
1953 
1954         /*
1955          * Save the File Name Index
1956          */
1957         strcpy(afntmp, fn);
1958         afptmp = fndidx(afntmp);
1959 
1960         /*
1961          * Skip to File Extension separator
1962          */
1963         p1 = strrchr(&afntmp[afptmp], FSEPX);
1964 
1965         /*
1966          * Copy File Extension
1967          */
1968         p2 = ft;
1969 
1970         // choose a file-extension
1971         if (*p2 == 0) {
1972                 // no extension supplied
1973                 if (p1 == NULL) {
1974                         // no extension in fn: use default extension
1975                         p2 = dsft;
1976                 } else {
1977                         p2 = strrchr(&fn[afptmp], FSEPX) + 1;
1978                 }
1979         }
1980         if (p1 == NULL) {
1981                 p1 = &afntmp[strlen(afntmp)];
1982         }
1983         *p1++ = FSEPX;
1984         while ((c = *p2++) != 0) {
1985                 if (p1 < &afntmp[FILSPC-1])
1986                         *p1++ = c;
1987         }
1988         *p1++ = 0;
1989 }
1990 
1991 /*)Function     int     fndidx(str)
1992  *
1993  *              char *  str             file specification string
1994  *
1995  *      The function fndidx() scans the file specification string
1996  *      to find the index to the file name.  If the file
1997  *      specification contains a 'path' then the index will
1998  *      be non zero.
1999  *
2000  *      fndidx() returns the index value.
2001  *
2002  *      local variables:
2003  *              char *  p1              temporary pointer
2004  *              char *  p2              temporary pointer
2005  *
2006  *      global variables:
2007  *              none
2008  *
2009  *      functions called:
2010  *              char *  strrchr()       c_library
2011  *
2012  *      side effects:
2013  *              none
2014  */
2015 
2016 int
fndidx(char * str)2017 fndidx(char *str)
2018 {
2019         char *p1, *p2;
2020 
2021         /*
2022          * Skip Path Delimiters
2023          */
2024         p1 = str;
2025         if ((p2 = strrchr(p1,  ':')) != NULL) { p1 = p2 + 1; }
2026         if ((p2 = strrchr(p1,  '/')) != NULL) { p1 = p2 + 1; }
2027         if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; }
2028 
2029         return((int) (p1 - str));
2030 }
2031 
2032 /*)Function     VOID    newdot(nap)
2033  *
2034  *              area *  nap             pointer to the new area structure
2035  *
2036  *      The function newdot():
2037  *              (1)     copies the current values of fuzz and the last
2038  *                      address into the current area referenced by dot
2039  *              (2)     loads dot with the pointer to the new area and
2040  *                      loads the fuzz and last address parameters
2041  *              (3)     outall() is called to flush any remaining
2042  *                      bufferred code from the old area to the output
2043  *
2044  *      local variables:
2045  *              area *  oap             pointer to old area
2046  *
2047  *      global variables:
2048  *              sym     dot             defined as sym[0]
2049  *              a_uint  fuzz            tracks pass to pass changes in the
2050  *                                      address of symbols caused by
2051  *                                      variable length instruction formats
2052  *
2053  *      functions called:
2054  *              none
2055  *
2056  *      side effects:
2057  *              Current area saved, new area loaded, buffers flushed.
2058  */
2059 
2060 VOID
newdot(struct area * nap)2061 newdot(struct area *nap)
2062 {
2063         struct area *oap;
2064 
2065         oap = dot.s_area;
2066         /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n",
2067                 oap->a_id, dot.s_area->a_size, dot.s_addr); */
2068         oap->a_fuzz = fuzz;
2069         if (oap->a_flag & A_OVR) {
2070                 // the size of an overlay is the biggest size encountered
2071                 if (oap->a_size < dot.s_addr) {
2072                         oap->a_size = dot.s_addr;
2073                 }
2074         }
2075         else if (oap->a_flag & A_ABS) {
2076                 oap->a_addr = dot.s_org;
2077                 oap->a_size += dot.s_addr - dot.s_org;
2078                 dot.s_addr = dot.s_org = 0;
2079         }
2080         else {
2081                 oap->a_addr = 0;
2082                 oap->a_size = dot.s_addr;
2083         }
2084         if (nap->a_flag & A_OVR) {
2085                 // a new overlay starts at 0, no fuzz
2086                 dot.s_addr = 0;
2087                 fuzz = 0;
2088         }
2089         else if (nap->a_flag & A_ABS) {
2090                 // a new absolute starts at org, no fuzz
2091                 dot.s_addr = dot.s_org;
2092                 fuzz = 0;
2093         }
2094         else {
2095                 dot.s_addr = nap->a_size;
2096                 fuzz = nap->a_fuzz;
2097         }
2098         dot.s_area = nap;
2099         outall();
2100 }
2101 
2102 /*)Function     VOID    phase(ap, a)
2103  *
2104  *              area *  ap              pointer to area
2105  *              a_uint  a               address in area
2106  *
2107  *      Function phase() compares the area ap and address a
2108  *      with the current area dot.s_area and address dot.s_addr
2109  *      to determine if the position of the symbol has changed
2110  *      between assembler passes.
2111  *
2112  *      local variables:
2113  *              none
2114  *
2115  *      global varaibles:
2116  *              sym *   dot             defined as sym[0]
2117  *
2118  *      functions called:
2119  *              none
2120  *
2121  *      side effects:
2122  *              The p error is invoked if the area and/or address
2123  *              has changed.
2124  */
2125 
2126 VOID
phase(struct area * ap,a_uint a)2127 phase(struct area *ap, a_uint a)
2128 {
2129         if (ap != dot.s_area || a != dot.s_addr)
2130                 err('p');
2131 }
2132 
2133 char *usetxt[] = {
2134         "Usage: [-Options] file",
2135         "Usage: [-Options] outfile file1 [file2 file3 ...]",
2136         "  -d   Decimal listing",
2137         "  -q   Octal   listing",
2138         "  -x   Hex     listing (default)",
2139         "  -g   Undefined symbols made global",
2140         "  -a   All user symbols made global",
2141         "  -b   Display .define substitutions in listing",
2142         "  -bb  and display without .define substitutions",
2143         "  -c   Disable instruction cycle count in listing",
2144 #if NOICE
2145         "  -j   Enable NoICE Debug Symbols",
2146 #endif
2147 #if SDCDB
2148         "  -y   Enable SDCC  Debug Symbols",
2149 #endif
2150         "  -l   Create list   file/outfile[.lst]",
2151         "  -o   Create object file/outfile[.rel]",
2152         "  -s   Create symbol file/outfile[.sym]",
2153         "  -p   Disable automatic listing pagination",
2154         "  -u   Disable .list/.nlist processing",
2155         "  -w   Wide listing format for symbol table",
2156         "  -z   Disable case sensitivity for symbols",
2157         "  -f   Flag relocatable references by  `   in listing file",
2158         "  -ff  Flag relocatable references by mode in listing file",
2159         "  -I   Add the named directory to the include file",
2160         "       search path.  This option may be used more than once.",
2161         "       Directories are searched in the order given.",
2162         "",
2163         NULL
2164 };
2165 
2166 /*)Function     VOID    usage(n)
2167  *
2168  *              int     n               exit code
2169  *
2170  *      The function usage() outputs to the stderr device the
2171  *      assembler name and version and a list of valid assembler options.
2172  *
2173  *      local variables:
2174  *              char ** dp              pointer to an array of
2175  *                                      text string pointers.
2176  *
2177  *      global variables:
2178  *              char    cpu[]           assembler type string
2179  *              char *  usetxt[]        array of string pointers
2180  *
2181  *      functions called:
2182  *              VOID    asexit()        asmain.c
2183  *              int     fprintf()       c_library
2184  *
2185  *      side effects:
2186  *              program is terminated
2187  */
2188 
2189 VOID
usage(int n)2190 usage(int n)
2191 {
2192         char   **dp;
2193 
2194         fprintf(stderr, "\n%s Assembler %s  (%s)\n\n", is_sdas() ? "sdas" : "ASxxxx", VERSION, cpu);
2195         fprintf(stderr, "\nCopyright (C) %s  Alan R. Baldwin", COPYRIGHT);
2196         fprintf(stderr, "\nThis program comes with ABSOLUTELY NO WARRANTY.\n\n");
2197         for (dp = usetxt; *dp; dp++)
2198                 fprintf(stderr, "%s\n", *dp);
2199         asexit(n);
2200 }
2201