struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / sdas / asxxsrc / asmain.c
blobf4e8669c118406f4444982133d4c62b629f599d7
1 /* asmain.c */
3 /*
4 * Copyright (C) 1989-2021 Alan R. Baldwin
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.
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.
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/>.
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
25 * With enhancements from
27 * John L. Hartman (JLH)
28 * jhartman at compuserve dot com
30 * Boisy G. Pitre (BGP)
31 * boisy at boisypitre dot com
33 * Mike McCarty
34 * mike dot mccarty at sbcglobal dot net
37 #include <errno.h>
38 #include <math.h>
39 #include "sdas.h"
40 #include "dbuf_string.h"
41 #include "asxxxx.h"
43 /*)Module asmain.c
45 * The module asmain.c includes the command argument parser,
46 * the three pass sequencer, and the machine independent
47 * assembler parsing code.
49 * asmain.c contains the following functions:
50 * int main(argc, argv)
51 * VOID asexit(n)
52 * VOID asmbl()
53 * VOID equate(id, e1, equtype)
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()
61 * asmain.c contains the array char *usetxt[] which
62 * references the usage text strings printed by usage().
65 /* sdas specific */
66 static const char *search_path[100];
67 static int search_path_length;
69 /**
70 * The search_path_append is used to append another directory to the end
71 * of the include file search path.
73 * @param dir
74 * The directory to be added to the path.
76 void
77 search_path_append(const char *dir)
79 if (search_path_length < sizeof(search_path)/sizeof(char*))
81 search_path[search_path_length++] = dir;
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.
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.
100 static const char *
101 create_temp_path(const char * dir, int len, const char * filename)
103 static struct dbuf_s dbuf;
104 const char * path;
106 if (!dbuf_is_initialized(&dbuf))
107 dbuf_init (&dbuf, 1024);
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);
118 dbuf_append_str(&dbuf, filename);
119 path = dbuf_c_str(&dbuf);
120 return path;
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.
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.
137 static FILE *
138 search_path_fopen(const char *filename, const char *mode)
140 FILE *fp;
141 int j;
143 fp = fopen(filename, mode);
144 if (fp != NULL || filename[0] == '/' || filename[0] == '\\')
145 return fp;
148 * Try the path of the file opening the include file
150 fp = fopen(create_temp_path(afn, afp, filename), mode);
151 if (fp != NULL)
152 return fp;
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;
159 errno = ENOENT;
160 return NULL;
162 /* end sdas specific */
164 /*)Function int main(argc, argv)
166 * int argc argument count
167 * char * argv array of pointers to argument strings
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.
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.
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 * def * dp pointer to def structure
192 * global variables:
193 * int aflag -a, make all symbols global flag
194 * char afn[] afile() constructed filespec
195 * int afp afile constructed path length
196 * area * areap pointer to an area structure
197 * asmf * asmc pointer to current assembler file structure
198 * int asmline assembler source file line number
199 * asmf * asmp pointer to first assembler file structure
200 * int aserr assembler error counter
201 * int bflag -b(b), listing mode flag
202 * int cb[] array of assembler output values
203 * int cbt[] array of assembler relocation types
204 * describing the data in cb[]
205 * int * cp pointer to assembler output array cb[]
206 * int * cpt pointer to assembler relocation type
207 * output array cbt[]
208 * time_t curtim current time string pointer
209 * def * defp pointer to a def structure
210 * char eb[] array of generated error codes
211 * char * ep pointer into error list array eb[]
212 * int fflag -f(f), relocations flagged flag
213 * int flevel IF-ELSE-ENDIF flag will be non
214 * zero for false conditional case
215 * a_uint fuzz tracks pass to pass changes in the
216 * address of symbols caused by
217 * variable length instruction formats
218 * int gflag -g, make undefined symbols global flag
219 * char * ib string buffer containing
220 * assembler-source text line for processing
221 * char * ic string buffer containing
222 * assembler-source text line for listing
223 * int ifcnd[] array of IF statement condition
224 * values (0 = FALSE) indexed by tlevel
225 * int iflvl[] array of IF-ELSE-ENDIF flevel
226 * values indexed by tlevel
227 * int incfil current include file count
228 * int incline include source file line number
229 * char * ip pointer into the assembler-source
230 * text line in ib[]
231 * jmp_buf jump_env compiler dependent structure
232 * used by setjmp() and longjmp()
233 * int lflag -l, generate listing flag
234 * int line current assembler source
235 * line number
236 * int lnlist current LIST-NLIST state
237 * int lop current line number on page
238 * int maxinc maximum include file nesting counter
239 * int nflag -n, don't resolve global assigned value symbols flag
240 * int oflag -o, generate relocatable output flag
241 * int jflag -j, generate debug info flag
242 * int page current page number
243 * int pflag disable listing pagination
244 * int pass assembler pass number
245 * int radix current number conversion radix:
246 * 2 (binary), 8 (octal), 10 (decimal),
247 * 16 (hexadecimal)
248 * int sflag -s, generate symbol table flag
249 * int srcline current source line number
250 * char stb[] Subtitle string buffer
251 * sym * symp pointer to a symbol structure
252 * int tlevel current conditional level
253 * int uflag -u, disable .list/.nlist processing
254 * int wflag -w, enable wide listing format
255 * int xflag -x, listing radix flag
256 * int zflag -z, disable symbol case sensitivity
257 * FILE * lfp list output file handle
258 * FILE * ofp relocation output file handle
259 * FILE * tfp symbol table output file handle
261 * called functions:
262 * FILE * afile() asmain.c
263 * VOID allglob() assym.c
264 * VOID asexit() asmain.c
265 * VOID diag() assubr.c
266 * VOID err() assubr.c
267 * VOID exprmasks() asexpr.c
268 * int fprintf() c_library
269 * int int32siz() asmain.c
270 * VOID list() aslist.c
271 * VOID lstsym() aslist.c
272 * VOID mcrinit() asmcro.c
273 * VOID minit() ___mch.c
274 * char * new() assym.c
275 * VOID newdot() asmain.c
276 * int nxtline() aslex.c
277 * VOID outbuf() asout.c
278 * VOID outchk() asout.c
279 * VOID outgsd() asout.c
280 * int rewind() c_library
281 * int setjmp() c_library
282 * char * strcpy() c_library
283 * VOID symglob() assym.c
284 * VOID syminit() assym.c
285 * time_t time() c_library
286 * VOID usage() asmain.c
288 * side effects:
289 * Completion of main() completes the assembly process.
290 * REL, LST, and/or SYM files may be generated.
293 /* sdas specific */
294 char relFile[FILSPC];
295 /* end sdas specific */
298 main(int argc, char *argv[])
300 char *p = NULL;
301 char *q;
302 int c, i;
303 struct area *ap;
304 struct def *dp;
306 /* sdas specific */
307 /* sdas initialization */
308 sdas_init(argv[0]);
309 /* end sdas specific */
311 if (argc == 1) {
312 usage();
313 exit(ER_NONE);
316 if (intsiz() < 4) {
317 fprintf(stderr, "?ASxxxx-Error-Size of INT32 is not 32 bits or larger.\n\n");
318 exit(ER_FATAL);
321 if (!is_sdas())
322 fprintf(stdout, "\n");
323 q = NULL;
324 asmc = NULL;
325 asmp = NULL;
326 for (i=1; i<argc; ++i) {
327 p = argv[i];
328 if (*p == '-') {
329 if (asmc != NULL) {
330 usage();
331 fprintf(stderr, "?ASxxxx-Error-Options come first.\n");
332 asexit(ER_FATAL);
334 ++p;
335 while ((c = *p++) != 0) {
336 switch(c) {
338 * -h Show the help list
340 case 'h':
341 case 'H':
342 usage();
343 exit(ER_NONE);
344 break;
346 // case 'i':
347 /* TODO: collides with new Insert assembler line */
348 case 'I':
349 search_path_append(p);
350 while (*p)
351 ++p;
352 break;
355 * Output:
356 * -o Create object file/outfile[.rel]
358 case 'o':
359 case 'O':
360 ++oflag;
361 break;
364 * Create Listing Output
366 case 'l':
367 case 'L':
368 ++lflag;
369 break;
372 * Create Symbol Output
374 case 's':
375 case 'S':
376 ++sflag;
377 break;
380 * Listing:
381 * -d Decimal listing
382 * -q Octal listing
383 * -x Hex listing (default)
384 * -b Display .define substitutions in listing
385 * -bb and display without .define substitutions
386 * -c Disable instruction cycle count in listing
387 * -f Flag relocatable references by ` in listing file
388 * -ff Flag relocatable references by mode in listing file
389 * -k Disable error output to listing file
390 * -p Disable automatic listing pagination
391 * -u Disable .list/.nlist processing
392 * -w Wide listing format for symbol table
394 case 'd':
395 case 'D':
396 xflag = 2;
397 break;
399 case 'q':
400 case 'Q':
401 xflag = 1;
402 break;
404 case 'x':
405 case 'X':
406 xflag = 0;
407 break;
409 case 'b':
410 case 'B':
411 ++bflag;
412 break;
414 case 'c':
415 case 'C':
416 ++cflag; /* Cycle counts in listing */
417 break;
419 case 'f':
420 case 'F':
421 ++fflag;
422 break;
424 case 'k':
425 case 'K':
426 // ++kflag; /* not yet implemented */
427 break;
429 case 'p':
430 case 'P':
431 ++pflag;
432 break;
434 case 'u':
435 case 'U':
436 ++uflag;
437 break;
439 case 'w':
440 case 'W':
441 ++wflag;
442 break;
445 * Assembly Processing Options:",
446 * -v Enable out of range signed / unsigned errors
448 case 'v':
449 case 'V':
450 ++vflag;
451 break;
454 * Symbol Options:
455 * -a All user symbols made global
456 * -g Undefined symbols made global
457 * -z Disable case sensitivity for symbols
459 case 'a':
460 case 'A':
461 ++aflag;
462 break;
464 case 'g':
465 case 'G':
466 ++gflag;
467 break;
469 // case 'n':
470 /* TODO: collides with new Specify number of assembler scanning passes */
471 case 'N':
472 nflag = 1;
473 break;
475 case 'z':
476 case 'Z':
477 ++zflag;
478 break;
481 * Debug Options:
482 * -j Enable NoICE Debug Symbols
483 * -y Enable SDCC Debug Symbols
485 #if NOICE
486 case 'j': /* NoICE Debug JLH */
487 case 'J':
488 ++jflag;
489 ++oflag; /* force object */
490 break;
491 #endif
493 #if SDCDB
494 case 'y': /* SDCC Debug */
495 case 'Y':
496 ++yflag;
497 break;
498 #endif
501 * Unlisted Options:
502 * -r list line numbers in .hst help file
503 * -rr list line numbers of NON listed lines
504 * -t show internal block allocations
506 case 'r':
507 case 'R':
508 // ++rflag; /* not yet implemented */
509 break;
511 case 't':
512 case 'T':
513 ++tflag;
514 break;
517 * Unknown Options:
519 default:
520 fprintf(stderr, "?ASxxxx-Warning-Unkown option -%c ignored\n", c);
521 //usage(ER_FATAL);
522 break;
525 } else {
526 if (asmc == NULL) {
527 q = p;
528 if (++i < argc) {
529 p = argv[i];
530 if (*p == '-') {
531 usage();
532 fprintf(stderr, "?ASxxxx-Error-Options come first.\n");
533 asexit(ER_FATAL);
536 asmp = (struct asmf *)
537 new (sizeof (struct asmf));
538 asmc = asmp;
539 } else {
540 asmc->next = (struct asmf *)
541 new (sizeof (struct asmf));
542 asmc = asmc->next;
544 asmc->next = NULL;
545 asmc->objtyp = T_ASM;
546 asmc->line = 0;
547 asmc->flevel = 0;
548 asmc->tlevel = 0;
549 asmc->lnlist = LIST_NORM;
550 asmc->fp = afile(p, "", 0);
551 strcpy(asmc->afn,afn);
552 asmc->afp = afp;
555 if (asmp == NULL) {
556 usage();
557 fprintf(stderr, "?ASxxxx-Error-Missing input file(s)\n");
558 asexit(ER_FATAL);
560 if (lflag)
561 lfp = afile(q, "lst", 1);
562 /* sdas specific */
563 if (oflag) {
564 ofp = afile(q, (is_sdas() && p != q) ? "" : "rel", 1);
565 // save the file name if we have to delete it on error
566 strcpy(relFile,afn);
568 /* end sdas specific */
569 if (sflag)
570 tfp = afile(q, "sym", 1);
571 exprmasks(2);
572 syminit();
573 curtim = time(NULL);
574 for (pass=0; pass<3; ++pass) {
575 aserr = 0;
576 if (gflag && pass == 1)
577 symglob();
578 if (aflag && pass == 1)
579 allglob();
580 if (oflag && pass == 2)
581 outgsd();
582 dp = defp;
583 while (dp) {
584 dp->d_dflag = 0;
585 dp = dp->d_dp;
587 flevel = 0;
588 tlevel = 0;
589 lnlist = LIST_NORM;
590 ifcnd[0] = 0;
591 iflvl[0] = 0;
592 radix = 10;
593 page = 0;
594 /* sdas specific */
595 org_cnt = 0;
596 /* end sdas specific */
597 stb[0] = 0;
598 lop = NLPP;
599 incfil = 0;
600 maxinc = 0;
601 srcline = 0;
602 asmline = 0;
603 incline = 0;
604 asmc = asmp;
605 strcpy(afn, asmc->afn);
606 afp = asmc->afp;
607 while (asmc) {
608 if (asmc->fp)
609 rewind(asmc->fp);
610 asmc = asmc->next;
612 asmc = asmp;
613 ap = areap;
614 while (ap) {
615 ap->a_fuzz = 0;
616 ap->a_size = 0;
617 ap = ap->a_ap;
619 fuzz = 0;
620 dot.s_addr = 0;
621 dot.s_area = &dca;
622 outbuf("I");
623 outchk(0,0);
624 symp = &dot;
625 mcrinit();
626 minit();
627 while (nxtline()) {
628 cp = cb;
629 cpt = cbt;
630 ep = eb;
631 ip = ib;
633 /* JLH: if line begins with ";!", then
634 * pass this comment on to the output file
636 if (oflag && (pass == 1) && (ip[0] == ';') && (ip[1] == '!')) {
637 fprintf(ofp, "%s\n", ip );
640 opcycles = OPCY_NONE;
641 if (setjmp(jump_env) == 0)
642 asmbl();
643 if (pass == 2) {
644 diag();
645 list();
648 newdot(dot.s_area); /* Flush area info */
650 if (flevel || tlevel) {
651 err('i');
652 fprintf(stderr, "?ASxxxx-Error-<i> at end of assembly\n");
653 fprintf(stderr, " %s\n", geterr('i'));
655 if (oflag)
656 outchk(ASXHUGE, ASXHUGE); /* Flush */
657 if (sflag) {
658 lstsym(tfp);
659 } else
660 if (lflag) {
661 lstsym(lfp);
663 asexit(aserr ? ER_ERROR : ER_NONE);
664 return(0);
667 /*)Function int intsiz()
669 * The function intsiz() returns the size of INT32
671 * local variables:
672 * none
674 * global variables:
675 * none
677 * functions called:
678 * none
680 * side effects:
681 * none
685 intsiz(void)
687 return(sizeof(INT32));
690 /*)Function VOID asexit(i)
692 * int i exit code
694 * The function asexit() explicitly closes all open
695 * files and then terminates the program.
697 * local variables:
698 * int j loop counter
700 * global variables:
701 * asmf * asmc pointer to current assembler file structure
702 * asmf * asmp pointer to first assembler file structure
703 * FILE * lfp list output file handle
704 * FILE * ofp relocation output file handle
705 * FILE * tfp symbol table output file handle
706 * FILE * stdout standard output handle
707 * int maxinc maximum include file level
708 * int maxmcr maximum macro expansion level
709 * int mcrblk macro allocation in 1K blocks
711 * functions called:
712 * int fclose() c_library
713 * int fprintf() c_library
714 * VOID exit() c_library
716 * side effects:
717 * All files closed. Program terminates.
720 VOID
721 asexit(int i)
723 if (lfp != NULL) fclose(lfp);
724 if (ofp != NULL) fclose(ofp);
725 if (tfp != NULL) fclose(tfp);
727 while (asmc != NULL) {
728 if ((asmc->objtyp == T_INCL) && (asmc->fp != NULL)) {
729 fclose(asmc->fp);
731 asmc = asmc->next;
734 asmc = asmp;
735 while (asmc != NULL) {
736 if ((asmc->objtyp == T_ASM) && (asmc->fp != NULL)) {
737 fclose(asmc->fp);
739 asmc = asmc->next;
741 /* sdas specific */
742 if (i) {
743 /* remove output file */
744 printf ("removing %s\n", relFile);
745 remove(relFile);
747 /* end sdas specific */
749 if (tflag) {
750 fprintf(stderr, "?ASxxxx-Info-maxinc(include file level) = %3d\n", maxinc);
751 fprintf(stderr, "?ASxxxx-Info-maxmcr(macro expansion level) = %3d\n", maxmcr);
752 //fprintf(stderr, "?ASxxxx-Info-asmblk(1K Byte Allocations) = %3d\n", asmblk);
753 fprintf(stderr, "?ASxxxx-Info-mcrblk(1K Byte Allocations) = %3d\n", mcrblk);
754 fprintf(stderr, "\n");
757 exit(i);
760 /*)Function VOID asmbl()
762 * The function asmbl() scans the assembler-source text for
763 * (1) labels, global labels, equates, global equates, and local
764 * symbols, (2) .if, .else, .endif, and .page directives,
765 * (3) machine independent assembler directives, (4) macros and
766 * macro definitions, and (5) machine dependent mnemonics.
768 * local variables:
769 * mne * mp pointer to a mne structure
770 * mne * xp pointer to a mne structure
771 * mcrdef *np pointer to a macro definition structure
772 * sym * sp pointer to a sym structure
773 * tsym * tp pointer to a tsym structure
774 * int c character from assembler-source
775 * text line
776 * area * ap pointer to an area structure
777 * def * dp pointer to a definition structure
778 * expr e1 expression structure
779 * char id[] id string
780 * char opt[] options string
781 * char fn[] filename string
782 * char * p pointer into a string
783 * int d temporary value
784 * int uaf user area options flag
785 * int uf area options
786 * a_uint n temporary value
787 * a_uint v temporary value
788 * int flags temporary flag
789 * FILE * fp include file handle
790 * int m_type mnemonic type
792 * global variables:
793 * area * areap pointer to an area structure
794 * char ctype[] array of character types, one per
795 * ASCII character
796 * int flevel IF-ELSE-ENDIF flag will be non
797 * zero for false conditional case
798 * int ftflevel; IIFF-IIFT-IIFTF FLAG
799 * int lnlist current LIST-NLIST state
800 * a_uint fuzz tracks pass to pass changes in the
801 * address of symbols caused by
802 * variable length instruction formats
803 * int ifcnd[] array of IF statement condition
804 * values (0 = FALSE) indexed by tlevel
805 * int iflvl[] array of IF-ELSE-ENDIF flevel
806 * values indexed by tlevel
807 * int incline current include file line
808 * int incfil current include file count
809 * a_uint laddr address of current assembler line
810 * or value of .if argument
811 * int lmode listing mode
812 * int lop current line number on page
813 * char module[] module name string
814 * int pass assembler pass number
815 * int radix current number conversion radix:
816 * 2 (binary), 8 (octal), 10 (decimal),
817 * 16 (hexadecimal)
818 * char stb[] Subtitle string buffer
819 * sym * symp pointer to a symbol structure
820 * char tb[] Title string buffer
821 * int tlevel current conditional level
822 * int jflag -j, generate debug info flag
824 * functions called:
825 * a_uint absexpr() asexpr.c
826 * area * alookup() assym.c
827 * def * dlookup() assym.c
828 * VOID clrexpr() asexpr.c
829 * int digit() asexpr.c
830 * char endline() aslex.c
831 * VOID equate() asmain.c
832 * VOID err() assubr.c
833 * VOID expr() asexpr.c
834 * FILE * search_path_fopen() asmain.c
835 * int fseek() c_library
836 * int get() aslex.c
837 * VOID getid() aslex.c
838 * int getmap() aslex.c
839 * int getnb() aslex.c
840 * VOID getst() aslex.c
841 * VOID getxstr() asmcro.c
842 * sym * lookup() assym.c
843 * VOID machine() ___mch.c
844 * int macro() asmcro.c
845 * int mcrprc() asmcro.c
846 * mne * mlookup() assym.c
847 * int more() aslex.c
848 * mcrdef *nlookup() asmcro.c
849 * char * new() assym.c
850 * VOID newdot() asmain.c
851 * VOID outall() asout.c
852 * VOID outab() asout.c
853 * VOID outchk() asout.c
854 * VOID outrb() asout.c
855 * VOID outrw() asout.c
856 * VOID phase() asmain.c
857 * VOID qerr() assubr.c
858 * char * strcpy() c_library
859 * char * strncpy() c_library
860 * char * strsto() assym.c
861 * VOID unget() aslex.c
864 VOID
865 asmbl(void)
867 struct mne *mp, *xp;
868 struct mcrdef *np;
869 struct sym *sp;
870 struct tsym *tp;
871 int c;
872 struct area *ap;
873 struct def *dp;
874 struct expr e1;
875 char id[NCPS];
876 char equ[NCPS];
877 char *equ_ip;
878 int equtype;
879 char opt[NCPS];
880 char fn[FILSPC+FILSPC];
881 char *p;
882 int d, uaf, uf;
883 a_uint n, v;
884 int skp, cnt, flags;
885 FILE * fp;
886 int m_type;
887 /* sdas specific */
888 static struct area *abs_ap; /* pointer to current absolute area structure */
889 /* end sdas specific */
891 laddr = dot.s_addr;
892 lmode = SLIST;
895 * Check iiff-iift-iiftf processing
897 if (ftflevel != 0) {
898 flevel = ftflevel - 1;
899 ftflevel = 0;
903 * Check if Building a Macro
904 * Check if Exiting a Macro
906 if (mcrprc(O_CHECK) != 0) {
907 return;
910 loop:
911 if ((c=endline()) == 0) { return; }
914 * If the first character is a digit then assume
915 * a reusable symbol is being specified. The symbol
916 * must end with $: to be valid.
917 * pass 0:
918 * Construct a tsym structure at the first
919 * occurance of the symbol. Flag the symbol
920 * as multiply defined if not the first occurance.
921 * pass 1:
922 * Load area, address, and fuzz values
923 * into structure tsym.
924 * pass 2:
925 * Check for assembler phase error and
926 * multiply defined error.
928 if (ctype[c] & DIGIT) {
929 if (flevel)
930 return;
931 n = 0;
932 while ((d = digit(c, 10)) >= 0) {
933 n = 10*n + d;
934 c = get();
936 if (c != '$' || get() != ':') {
937 qerr();
939 tp = symp->s_tsym;
940 while (tp) {
941 if (n == tp->t_num) {
942 if (pass == 0) {
943 tp->t_flg |= S_MDF;
945 break;
947 tp = tp->t_lnk;
949 if (tp == NULL) {
950 tp=(struct tsym *) new (sizeof(struct tsym));
951 tp->t_area = dot.s_area;
952 tp->t_addr = dot.s_addr;
953 tp->t_lnk = symp->s_tsym;
954 tp->t_num = n;
955 tp->t_flg = 0;
956 symp->s_tsym = tp;
958 if (tp->t_flg & S_MDF)
959 err('m');
960 phase(tp->t_area, tp->t_addr);
961 fuzz = tp->t_addr - dot.s_addr;
962 tp->t_area = dot.s_area;
963 tp->t_addr = dot.s_addr;
964 lmode = ALIST;
965 goto loop;
968 * If the first character is a letter then assume a label,
969 * symbol, assembler directive, or assembler mnemonic is
970 * being processed.
972 if ((ctype[c] & LETTER) == 0) {
973 if (flevel) {
974 return;
975 } else {
976 qerr();
979 getid(id, c);
980 /* Skip white space to next character */
981 c = getnb();
983 * If the next character is a : then a label is being processed.
984 * A double :: defines a global label. If this is a new label
985 * then create a symbol structure.
986 * pass 0:
987 * Flag multiply defined labels.
988 * pass 1:
989 * Load area, address, and fuzz values
990 * into structure symp.
991 * pass 2:
992 * Check for assembler phase error and
993 * multiply defined error.
995 if (c == ':') {
996 if (flevel)
997 return;
998 if ((c = get()) != ':') {
999 unget(c);
1000 c = 0;
1002 symp = lookup(id);
1003 if (symp == &dot)
1004 qerr();
1005 if (pass == 0) {
1006 if ((symp->s_type != S_NEW) && ((symp->s_flag & S_ASG) == 0))
1007 symp->s_flag |= S_MDF;
1009 if (symp->s_flag & S_MDF)
1010 err('m');
1011 symp->s_type = S_USER;
1012 phase(symp->s_area, symp->s_addr);
1013 fuzz = symp->s_addr - dot.s_addr;
1014 symp->s_area = dot.s_area;
1015 symp->s_addr = dot.s_addr;
1016 if (c) {
1017 symp->s_flag |= S_GBL;
1019 lmode = ALIST;
1020 goto loop;
1023 * If the next character is a = then an equate is being processed.
1025 * Syntax:
1026 * [labels] sym = value defines an equate.
1027 * [labels] sym == value defines a global equate.
1028 * [labels] sym =: value defines an internal machine equate.
1029 * If this is a new variable then create a symbol structure.
1031 if (c == '=') {
1032 if (flevel)
1033 return;
1034 switch (c = get()) {
1035 case '=': equtype = O_GBLEQU; break;
1036 case ':': equtype = O_LCLEQU; break;
1037 default: equtype = O_EQU; unget(c); break;
1039 equate(id, &e1, equtype);
1040 goto loop;
1042 unget(c);
1044 * Check for Equates if 'id' is not an Assembler Directive
1046 * Syntax:
1047 * [labels] sym .equ value defines an equate
1048 * [labels] sym .glbequ value defines a global equate
1049 * [labels] sym .lclequ value defines a local equate
1051 if ((mlookup(id) == NULL) && (nlookup(id) == NULL)) {
1052 if (flevel)
1053 return;
1055 * Alternates for =, ==, and =:
1057 equ_ip = ip; /* Save current char pointer for case equate not found. */
1058 if (more() && (ctype[c = getnb()] == LETTER)) {
1059 getid(equ, c);
1060 if ((mp = mlookup(equ)) == NULL || mp->m_type != S_EQU) {
1061 ip = equ_ip;
1062 } else {
1063 equate(id, &e1, mp->m_valu);
1064 goto loop;
1069 * Completed scan for labels , equates, and symbols.
1071 lmode = flevel ? SLIST : CLIST;
1073 * An assembler directive, mnemonic, or macro is
1074 * required to continue processing line.
1076 mp = mlookup(id);
1077 np = nlookup(id);
1078 if ((mp == NULL) && (np == NULL)) {
1079 if (!flevel) {
1080 err('o');
1082 return;
1085 * If we have gotten this far then we have found an
1086 * assembler directive an assembler mnemonic or
1087 * an assembler macro.
1089 * Check for .if[], .iif[], .else, .endif,
1090 * .list, .nlist, and .page directives.
1092 m_type = (mp != NULL) ? mp->m_type : ~0;
1094 switch (m_type) {
1096 case S_CONDITIONAL:
1098 * BGP - .ifeq, .ifne, .ifgt, .iflt, .ifge, .ifle
1100 if (mp->m_valu < O_IFEND) {
1101 if (mp->m_valu == O_IF) {
1103 * Process conditionals of the form
1105 * .if cnd(,) arg1 (, arg2)
1107 * where cnd is one of the following:
1109 * eq ne
1110 * gt lt ge le
1111 * def ndef
1112 * b nb idn dif
1113 * t f tf
1115 p = ip;
1116 strcpy(id,".if");
1117 getid(&id[3],getnb());
1118 xp = mlookup(id);
1119 if ((xp != NULL) &&
1120 (xp->m_type == S_CONDITIONAL) &&
1121 (xp->m_valu != O_IF)) {
1122 mp = xp;
1123 comma(0);
1124 } else {
1125 ip = p;
1128 if (flevel) {
1129 n = 0;
1130 } else {
1131 switch (mp->m_valu) {
1132 case O_IF:
1133 case O_IFNE: /* .if ne,.... */
1134 case O_IFEQ: /* .if eq,.... */
1135 case O_IFGT: /* .if gt,.... */
1136 case O_IFLT: /* .if lt,.... */
1137 case O_IFGE: /* .if ge,.... */
1138 case O_IFLE: /* .if le,.... */
1139 n = absexpr();
1140 switch (mp->m_valu) {
1141 default:
1142 case O_IF:
1143 case O_IFNE: n = (((v_sint) n) != 0); break;
1144 case O_IFEQ: n = (((v_sint) n) == 0); break;
1145 case O_IFGT: n = (((v_sint) n) > 0); break;
1146 case O_IFLT: n = (((v_sint) n) < 0); break;
1147 case O_IFGE: n = (((v_sint) n) >= 0); break;
1148 case O_IFLE: n = (((v_sint) n) <= 0); break;
1150 break;
1152 case O_IFB: /* .if b,.... */
1153 case O_IFNB: /* .if nb,.... */
1154 n = comma(0) ? 0 : 1;
1155 if (n) {
1156 getxstr(id);
1157 if (*id == '\0') {
1158 n = 0;
1160 comma(0);
1162 switch (mp->m_valu) {
1163 default:
1164 case O_IFB: n = (((v_sint) n) == 0); break;
1165 case O_IFNB: n = (((v_sint) n) != 0); break;
1167 break;
1169 case O_IFDEF: /* .if def,.... */
1170 case O_IFNDEF: /* .if ndef,.... */
1171 getid(id, -1);
1172 if (((dp = dlookup(id)) != NULL) && (dp->d_dflag != 0)) {
1173 n = 1;
1174 } else
1175 if ((sp = slookup(id)) != NULL) {
1176 n = (sp->s_type == S_USER) ? 1 : 0;
1177 } else {
1178 n = 0;
1180 switch (mp->m_valu) {
1181 default:
1182 case O_IFDEF: n = (((v_sint) n) != 0); break;
1183 case O_IFNDEF: n = (((v_sint) n) == 0); break;
1185 break;
1187 case O_IFIDN: /* .if idn,.... */
1188 case O_IFDIF: /* .if dif,.... */
1189 getxstr(id);
1190 comma(0);
1191 getxstr(equ);
1192 n = symeq(id, equ, zflag);
1193 switch (mp->m_valu) {
1194 default:
1195 case O_IFIDN: n = (((v_sint) n) != 0); break;
1196 case O_IFDIF: n = (((v_sint) n) == 0); break;
1198 break;
1200 case O_IFF: /* .if f */
1201 case O_IFT: /* .if t */
1202 case O_IFTF: /* .if tf */
1203 n = 0;
1204 break;
1206 default:
1207 n = 0;
1208 qerr();
1209 break;
1212 switch (mp->m_valu) {
1213 default:
1214 if (tlevel < MAXIF) {
1215 ++tlevel;
1216 ifcnd[tlevel] = (int) n;
1217 iflvl[tlevel] = flevel;
1218 if (!n) {
1219 ++flevel;
1221 } else {
1222 err('i');
1224 if (!iflvl[tlevel]) {
1225 lmode = ELIST;
1226 laddr = n;
1227 } else {
1228 lmode = SLIST;
1230 break;
1232 case O_IFF: /* .if f */
1233 case O_IFT: /* .if t */
1234 case O_IFTF: /* .if tf */
1235 if (tlevel == 0) {
1236 err('i');
1237 lmode = SLIST;
1238 break;
1240 if (iflvl[tlevel] == 0) {
1241 if (ifcnd[tlevel]) {
1242 switch (mp->m_valu) {
1243 default:
1244 case O_IFF: flevel = 1; break;
1245 case O_IFT: flevel = 0; break;
1246 case O_IFTF: flevel = 0; break;
1248 } else {
1249 switch (mp->m_valu) {
1250 default:
1251 case O_IFF: flevel = 0; break;
1252 case O_IFT: flevel = 1; break;
1253 case O_IFTF: flevel = 0; break;
1256 lmode = ELIST;
1257 laddr = flevel ? 0 : 1;
1258 } else {
1259 lmode = SLIST;
1261 break;
1263 return;
1264 } else
1265 if (mp->m_valu < O_IIFEND) {
1266 if (mp->m_valu == O_IIF) {
1268 * Process conditionals of the form
1270 * .iif cnd(,) arg1 (, arg2)
1272 * where cnd is one of the following:
1274 * eq ne
1275 * gt lt ge le
1276 * def ndef
1277 * b nb idn dif
1278 * t f tf
1280 p = ip;
1281 strcpy(id,".iif");
1282 getid(&id[4],getnb());
1283 xp = mlookup(id);
1284 if ((xp != NULL) &&
1285 (xp->m_type == S_CONDITIONAL) &&
1286 (xp->m_valu != O_IIF)) {
1287 mp = xp;
1288 comma(0);
1289 } else {
1290 ip = p;
1293 switch (mp->m_valu) {
1294 case O_IIFF: /* .iif f */
1295 case O_IIFT: /* .iif t */
1296 case O_IIFTF: /* .iif tf */
1297 if (tlevel == 0) {
1298 err('i');
1299 lmode = SLIST;
1300 return;
1302 if (iflvl[tlevel] == 0) {
1303 ftflevel = flevel + 1;
1304 if (ifcnd[tlevel] != 0) {
1305 switch (mp->m_valu) {
1306 default:
1307 case O_IIFF: flevel = 1; break;
1308 case O_IIFT: flevel = 0; break;
1309 case O_IIFTF: flevel = 0; break;
1311 } else {
1312 switch (mp->m_valu) {
1313 default:
1314 case O_IIFF: flevel = 0; break;
1315 case O_IIFT: flevel = 1; break;
1316 case O_IIFTF: flevel = 0; break;
1320 n = flevel ? 0 : 1;
1322 * Skip trailing ','
1324 comma(0);
1325 lmode = SLIST;
1326 if (n) {
1327 goto loop;
1329 return;
1331 default:
1332 if (flevel) {
1333 return;
1335 break;
1337 switch (mp->m_valu) {
1338 case O_IIF:
1339 case O_IIFNE: /* .iif ne,.... */
1340 case O_IIFEQ: /* .iif eq,.... */
1341 case O_IIFGT: /* .iif gt,.... */
1342 case O_IIFLT: /* .iif lt,.... */
1343 case O_IIFGE: /* .iif ge,.... */
1344 case O_IIFLE: /* .iif le,.... */
1345 n = absexpr();
1346 switch (mp->m_valu) {
1347 default:
1348 case O_IIF:
1349 case O_IIFNE: n = (((v_sint) n) != 0); break;
1350 case O_IIFEQ: n = (((v_sint) n) == 0); break;
1351 case O_IIFGT: n = (((v_sint) n) > 0); break;
1352 case O_IIFLT: n = (((v_sint) n) < 0); break;
1353 case O_IIFGE: n = (((v_sint) n) >= 0); break;
1354 case O_IIFLE: n = (((v_sint) n) <= 0); break;
1356 break;
1358 case O_IIFB: /* .iif b,.... */
1359 case O_IIFNB: /* .iif nb,.... */
1360 n = comma(0) ? 0 : 1;
1361 if (n) {
1362 getxstr(id);
1363 if (*id == '\0') {
1364 n = 0;
1366 comma(0);
1368 switch (mp->m_valu) {
1369 default:
1370 case O_IIFB: n = (((v_sint) n) == 0); break;
1371 case O_IIFNB: n = (((v_sint) n) != 0); break;
1373 break;
1375 case O_IIFDEF: /* .iif def,.... */
1376 case O_IIFNDEF: /* .iif ndef,.... */
1377 getid(id, -1);
1378 if (((dp = dlookup(id)) != NULL) && (dp->d_dflag != 0)) {
1379 n = 1;
1380 } else
1381 if ((sp = slookup(id)) != NULL) {
1382 n = (sp->s_type == S_USER) ? 1 : 0;
1383 } else {
1384 n = 0;
1386 switch (mp->m_valu) {
1387 default:
1388 case O_IIFDEF: n = (((v_sint) n) != 0); break;
1389 case O_IIFNDEF: n = (((v_sint) n) == 0); break;
1391 break;
1393 case O_IIFIDN: /* .iif idn,.... */
1394 case O_IIFDIF: /* .iif dif,.... */
1395 getxstr(id);
1396 comma(0);
1397 getxstr(equ);
1398 n = symeq(id, equ, zflag);
1399 switch (mp->m_valu) {
1400 default:
1401 case O_IIFIDN: n = (((v_sint) n) != 0); break;
1402 case O_IIFDIF: n = (((v_sint) n) == 0); break;
1404 break;
1406 default:
1407 n = 0;
1408 qerr();
1409 break;
1412 * Skip trailing ','
1414 comma(0);
1415 lmode = SLIST;
1416 if (n) {
1417 goto loop;
1419 return;
1422 switch (mp->m_valu) {
1423 case O_ELSE:
1424 if (tlevel != 0) {
1425 if (ifcnd[tlevel]) {
1426 flevel = iflvl[tlevel] + 1;
1427 ifcnd[tlevel] = 0;
1428 } else {
1429 flevel = iflvl[tlevel];
1430 ifcnd[tlevel] = 1;
1432 if (!iflvl[tlevel]) {
1433 lmode = ELIST;
1434 laddr = ifcnd[tlevel];
1435 return;
1437 } else {
1438 err('i');
1440 lmode = SLIST;
1441 return;
1443 case O_ENDIF:
1444 if (tlevel) {
1445 flevel = iflvl[tlevel--];
1446 } else {
1447 err('i');
1449 lmode = SLIST;
1450 return;
1452 default:
1453 break;
1455 qerr();
1456 break;
1458 case S_LISTING:
1459 flags = 0;
1460 while ((c=endline()) != 0) {
1461 if (c == ',') {
1462 c = getnb();
1464 if (c == '(') {
1465 do {
1466 if ((c = getnb()) == '!') {
1467 flags |= LIST_NOT;
1468 } else {
1469 unget(c);
1470 getid(id, -1);
1471 if (symeq(id, "err", 1)) { flags |= LIST_ERR; } else
1472 if (symeq(id, "loc", 1)) { flags |= LIST_LOC; } else
1473 if (symeq(id, "bin", 1)) { flags |= LIST_BIN; } else
1474 if (symeq(id, "eqt", 1)) { flags |= LIST_EQT; } else
1475 if (symeq(id, "cyc", 1)) { flags |= LIST_CYC; } else
1476 if (symeq(id, "lin", 1)) { flags |= LIST_LIN; } else
1477 if (symeq(id, "src", 1)) { flags |= LIST_SRC; } else
1478 if (symeq(id, "pag", 1)) { flags |= LIST_PAG; } else
1479 if (symeq(id, "lst", 1)) { flags |= LIST_LST; } else
1480 if (symeq(id, "md" , 1)) { flags |= LIST_MD; } else
1481 if (symeq(id, "me" , 1)) { flags |= LIST_ME; } else
1482 if (symeq(id, "meb", 1)) { flags |= LIST_MEB; } else {
1483 err('u');
1486 c = endline();
1487 } while (c == ',') ;
1488 if (c != ')') {
1489 qerr();
1491 } else {
1492 unget(c);
1493 if (absexpr()) {
1494 flags |= LIST_TORF;
1495 } else {
1496 flags &= ~LIST_TORF;
1500 if (!(flags & LIST_TORF) && flevel) {
1501 return;
1503 if (flags & ~LIST_TORF) {
1504 if (flags & LIST_NOT) {
1505 switch(mp->m_valu) {
1506 case O_LIST: lnlist = LIST_NONE; break;
1507 case O_NLIST: lnlist = LIST_NORM; break;
1508 default: break;
1511 if (flags & LIST_BITS) {
1512 switch(mp->m_valu) {
1513 case O_LIST: lnlist |= (flags & LIST_BITS); break;
1514 case O_NLIST: lnlist &= ~(flags & LIST_BITS); break;
1515 default: break;
1518 } else {
1519 switch(mp->m_valu) {
1520 case O_LIST: lnlist = LIST_NORM; break;
1521 case O_NLIST: lnlist = LIST_NONE; break;
1522 default: break;
1525 lmode = (lnlist & LIST_LST) ? SLIST : NLIST;
1526 return;
1528 case S_PAGE:
1529 lmode = NLIST;
1530 if (more()) {
1531 n = absexpr() ? 1 : 0;
1532 } else {
1533 n = 0;
1535 if (!n && flevel)
1536 return;
1538 lop = NLPP;
1539 return;
1541 default:
1542 break;
1544 if (flevel)
1545 return;
1547 * If we are not in a false state for .if/.else then
1548 * process the assembler directives here.
1550 switch (m_type) {
1552 case S_HEADER:
1553 switch(mp->m_valu) {
1554 case O_TITLE:
1555 p = tb;
1556 if ((c = getnb()) != 0) {
1557 do {
1558 if (p < &tb[NTITL-1])
1559 *p++ = c;
1560 } while ((c = get()) != 0);
1562 *p = 0;
1563 unget(c);
1564 lmode = SLIST;
1565 break;
1567 case O_SBTTL:
1568 p = stb;
1569 if ((c = getnb()) != 0) {
1570 do {
1571 if (p < &stb[NSBTL-1])
1572 *p++ = c;
1573 } while ((c = get()) != 0);
1575 *p = 0;
1576 unget(c);
1577 lmode = SLIST;
1578 break;
1580 default:
1581 break;
1583 break;
1585 case S_MODUL:
1586 getst(id, getnb()); // a module can start with a digit
1587 if (pass == 0) {
1588 if (module[0]) {
1589 err('m');
1590 } else {
1591 strncpy(module, id, NCPS);
1594 lmode = SLIST;
1595 break;
1597 case S_INCL:
1598 switch(mp->m_valu) {
1599 case I_CODE:
1600 lmode = SLIST;
1601 if (incfil > maxinc) {
1602 maxinc = incfil;
1605 * Copy the .include file specification
1607 getdstr(fn, FILSPC + FILSPC);
1609 * Open File
1611 if ((fp = search_path_fopen(fn, "r")) == NULL) {
1612 --incfil;
1613 err('i');
1614 } else {
1615 asmi = (struct asmf *) new (sizeof (struct asmf));
1616 asmi->next = asmc;
1617 asmi->objtyp = T_INCL;
1618 asmi->line = srcline;
1619 asmi->flevel = flevel;
1620 asmi->tlevel = tlevel;
1621 asmi->lnlist = lnlist;
1622 asmi->fp = fp;
1623 asmi->afp = afptmp;
1624 strcpy(asmi->afn,afntmp);
1625 if (lnlist & LIST_PAG) {
1626 lop = NLPP;
1629 break;
1631 case I_BNRY:
1633 * Copy the .incbin file specification
1635 getdstr(fn, FILSPC + FILSPC);
1636 /* ported from ASXXXX 5.40 */
1638 * Skip Count
1640 skp = 0;
1641 comma(0);
1642 if (more() && !comma(0))
1643 skp = (int) absexpr();
1645 * Insert Count
1647 #ifdef LONGINT
1648 cnt = 0x7FFFFFFFl;
1649 #else
1650 cnt = 0x7FFFFFFF;
1651 #endif
1652 comma(0);
1653 if (more())
1654 cnt = (int) absexpr();
1656 * Open File
1658 if ((fp = search_path_fopen(fn, "rb")) == NULL) {
1659 xerr('i', "File not found.");
1660 break;
1663 * Skip To Position
1665 fseek(fp, skp, SEEK_SET);
1666 if (fread(&c, 1, 1, fp) != 1) {
1667 xerr('i', "Offset past End-Of-File.");
1668 break;
1670 fseek(fp, skp, SEEK_SET);
1672 * Read Bytes
1674 while (cnt > 0) {
1675 if (fread(&c, 1, 1, fp) == 1) {
1676 outab(c);
1677 } else {
1678 break;
1680 cnt -= 1;
1683 * Close File
1685 fclose(fp);
1686 break;
1688 default:
1689 xerr('i', "Internal ___PST.C Error.");
1690 break;
1692 break;
1694 /* sdas specific */
1695 case S_OPTSDCC:
1696 optsdcc = strsto(ip);
1697 lmode = SLIST;
1698 return; /* line consumed */
1699 /* end sdas specific */
1701 case S_AREA:
1702 getid(id, -1);
1703 uaf = 0;
1704 uf = A_CON|A_REL;
1705 if ((c = getnb()) == '(') {
1706 do {
1707 getid(opt, -1);
1708 mp = mlookup(opt);
1709 if (mp && mp->m_type == S_ATYP) {
1710 ++uaf;
1711 v = mp->m_valu;
1712 uf |= (int) v;
1713 } else {
1714 err('u');
1716 } while ((c = getnb()) == ',');
1717 if (c != ')')
1718 qerr();
1719 } else {
1720 unget(c);
1722 if ((ap = alookup(id)) != NULL) {
1723 if (uaf && uf != ap->a_flag)
1724 err('m');
1725 } else {
1726 ap = (struct area *) new (sizeof(struct area));
1727 ap->a_ap = areap;
1728 ap->a_id = strsto(id);
1729 ap->a_ref = areap->a_ref + 1;
1730 /* sdas specific */
1731 ap->a_addr = 0;
1732 /* end sdas specific */
1733 ap->a_size = 0;
1734 ap->a_fuzz = 0;
1735 ap->a_flag = uaf ? uf : (A_CON|A_REL);
1736 areap = ap;
1738 newdot(ap);
1739 lmode = SLIST;
1740 if (dot.s_area->a_flag & A_ABS)
1741 abs_ap = ap;
1742 break;
1744 case S_ORG:
1745 if ((dot.s_area->a_flag & A_ABS) == A_ABS) {
1746 char buf[NCPS];
1748 outall();
1749 laddr = absexpr();
1750 sprintf(buf, "%s%x", abs_ap->a_id, org_cnt++);
1751 if ((ap = alookup(buf)) == NULL) {
1752 ap = (struct area *) new (sizeof(struct area));
1753 *ap = *areap;
1754 ap->a_ap = areap;
1755 ap->a_id = strsto(buf);
1756 ap->a_ref = areap->a_ref + 1;
1757 ap->a_size = 0;
1758 ap->a_fuzz = 0;
1759 areap = ap;
1761 newdot(ap);
1762 dot.s_addr = dot.s_org = laddr;
1763 } else {
1764 err('o');
1766 outall();
1767 lmode = ALIST;
1768 break;
1770 case S_RADIX:
1771 if (more()) {
1772 switch (ccase[getnb() & 0x7F]) {
1773 case 'b': radix = 2; break; /* B */
1774 case '@': /* @ */
1775 case 'o': /* O */
1776 case 'q': radix = 8; break; /* Q */
1777 case 'd': radix = 10; break; /* D */
1778 case 'h': /* H */
1779 case 'x': radix = 16; break; /* X */
1780 default: /* 2, 8, 10, 16 */
1781 unget(c);
1782 expr(&e1, 0);
1783 if (is_abs(&e1)) {
1784 v = e1.e_addr;
1785 if ((v == 2) || (v == 8) ||
1786 (v == 10) || (v == 16)) {
1787 radix = (int) v;
1788 break;
1791 radix = 10;
1792 qerr();
1793 break;
1795 } else {
1796 radix = 10;
1798 lmode = SLIST;
1799 break;
1801 case S_GLOBL:
1802 do {
1803 getid(id, -1);
1804 sp = lookup(id);
1805 sp->s_flag &= ~S_LCL;
1806 sp->s_flag |= S_GBL;
1807 } while (comma(0));
1808 lmode = SLIST;
1809 break;
1811 case S_LOCAL:
1812 do {
1813 getid(id, -1);
1814 sp = lookup(id);
1815 sp->s_flag &= ~S_GBL;
1816 sp->s_flag |= S_LCL;
1817 } while (comma(0));
1818 lmode = SLIST;
1819 break;
1821 case S_EQU:
1823 * Syntax:
1824 * [labels] .equ sym, value defines an equate
1825 * [labels] .glbequ sym, value defines a global equate
1826 * [labels] .lclequ sym, value defines a local equate
1828 getid(id, -1);
1829 comma(1);
1830 equate(id, &e1, mp->m_valu);
1831 break;
1833 case S_DATA:
1834 switch (mp->m_valu) {
1835 case O_1BYTE:
1836 case O_2BYTE:
1837 do {
1838 clrexpr(&e1);
1839 expr(&e1, 0);
1840 if (mp->m_valu == O_1BYTE) {
1841 outrb(&e1, R_NORM);
1842 } else {
1843 outrw(&e1, R_NORM);
1845 } while ((c = getnb()) == ',');
1846 unget(c);
1847 break;
1848 default:
1849 break;
1851 break;
1853 /* sdas z80 specific */
1854 case S_FLOAT:
1855 do {
1856 double f1, f2;
1857 unsigned int mantissa, exponent;
1858 char readbuffer[80];
1860 getid(readbuffer, ' '); /* Hack :) */
1861 if ((c = getnb()) == '.') {
1862 getid(&readbuffer[strlen(readbuffer)], '.');
1864 else
1865 unget(c);
1867 f1 = strtod(readbuffer, (char **)NULL);
1868 /* Convert f1 to a gb-lib type fp
1869 * 24 bit mantissa followed by 7 bit exp and 1 bit sign
1872 if (f1 != 0) {
1873 f2 = floor(log(fabs(f1)) / log(2)) + 1;
1874 mantissa = (unsigned int) ((0x1000000 * fabs(f1)) / exp(f2 * log(2)));
1875 mantissa &= 0xffffff;
1876 exponent = (unsigned int) (f2 + 0x40) ;
1877 if (f1 < 0)
1878 exponent |=0x80;
1880 else {
1881 mantissa = 0;
1882 exponent = 0;
1885 outab(mantissa & 0xff);
1886 outab((mantissa >> 8) & 0xff);
1887 outab((mantissa >> 16) & 0xff);
1888 outab(exponent & 0xff);
1890 } while ((c = getnb()) == ',');
1891 unget(c);
1892 break;
1893 /* end sdas z80 specific */
1895 /* sdas hc08 specific */
1896 case S_ULEB128:
1897 case S_SLEB128:
1898 do {
1899 a_uint val = absexpr();
1900 int bit = sizeof(val)*8 - 1;
1901 int impliedBit;
1903 if (mp->m_type == S_ULEB128) {
1904 impliedBit = 0;
1905 } else {
1906 impliedBit = (val & (1 << bit)) ? 1 : 0;
1908 while ((bit>0) && (((val & (1 << bit)) ? 1 : 0) == impliedBit)) {
1909 bit--;
1911 if (mp->m_type == S_SLEB128) {
1912 bit++;
1914 while (bit>=0) {
1915 if (bit<7) {
1916 outab(val & 0x7f);
1917 } else {
1918 outab(0x80 | (val & 0x7f));
1920 bit -= 7;
1921 val >>= 7;
1923 } while ((c = getnb()) == ',');
1924 unget(c);
1925 break;
1926 /* end sdas hc08 specific */
1928 case S_BLK:
1929 clrexpr(&e1);
1930 expr(&e1, 0);
1931 outchk(ASXHUGE,ASXHUGE);
1932 dot.s_addr += e1.e_addr*mp->m_valu;
1933 lmode = BLIST;
1934 break;
1936 case S_ASCIX:
1937 switch(mp->m_valu) {
1938 case O_ASCII:
1939 case O_ASCIZ:
1940 if ((d = getnb()) == '\0')
1941 qerr();
1942 while ((c = getmap(d)) >= 0)
1943 outab(c);
1944 if (mp->m_valu == O_ASCIZ)
1945 outab(0);
1946 break;
1948 case O_ASCIS:
1949 if ((d = getnb()) == '\0')
1950 qerr();
1951 c = getmap(d);
1952 while (c >= 0) {
1953 int n2;
1954 if ((n2 = getmap(d)) >= 0) {
1955 outab(c);
1956 } else {
1957 outab(c | 0x80);
1959 n = n2;
1960 c = n2;
1962 break;
1963 default:
1964 break;
1966 break;
1968 case S_DEFINE:
1970 * Extract the .(un)define key word.
1972 getid(id, -1);
1974 switch(mp->m_valu) {
1975 case O_DEF:
1977 * Extract the substitution string
1979 comma(0);
1980 *opt = 0;
1981 if (more()) {
1982 getdstr(opt, NCPS);
1985 * Verify the definition or
1986 * add a new definition.
1988 dp = dlookup(id);
1989 if (dp) {
1990 if (!symeq(opt, dp->d_define, zflag)) {
1991 if (dp->d_dflag) {
1992 err('m');
1994 dp->d_define = strsto(opt);
1996 dp->d_dflag = 1;
1997 } else {
1998 dp = (struct def *) new (sizeof(struct def));
1999 dp->d_dp = defp;
2000 dp->d_id = strsto(id);
2001 dp->d_define = strsto(opt);
2002 dp->d_dflag = 1;
2003 defp = dp;
2005 break;
2007 case O_UNDEF:
2009 * Find and undefine the definition.
2011 dp = dlookup(id);
2012 if (dp) {
2013 dp->d_dflag = 0;
2015 break;
2017 default:
2018 break;
2020 lmode = SLIST;
2021 break;
2023 case S_BOUNDARY:
2024 switch(mp->m_valu) {
2025 case O_EVEN:
2026 outall();
2027 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
2028 lmode = ALIST;
2029 break;
2031 case O_ODD:
2032 outall();
2033 laddr = dot.s_addr |= 1;
2034 lmode = ALIST;
2035 break;
2037 case O_BNDRY:
2038 v = absexpr();
2039 n = dot.s_addr % v;
2040 if (n != 0) {
2041 dot.s_addr += (v - n);
2043 outall();
2044 laddr = dot.s_addr;
2045 lmode = ALIST;
2046 break;
2048 default:
2049 break;
2051 break;
2053 case S_MSG:
2054 lmode = SLIST;
2056 * Print the .msg message
2058 getdstr(fn, FILSPC+FILSPC);
2059 if (pass == 2) {
2060 printf("%s\n", fn);
2062 break;
2064 case S_ERROR:
2065 clrexpr(&e1);
2066 if (more()) {
2067 expr(&e1, 0);
2069 if (e1.e_addr != 0) {
2070 err('e');
2072 lmode = ELIST;
2073 // eqt_area = NULL;
2074 laddr = e1.e_addr;
2075 break;
2077 case S_MACRO:
2078 lmode = SLIST;
2079 mcrprc((int) mp->m_valu);
2080 return;
2083 * If not an assembler directive then go to the
2084 * macro function or machine dependent function
2085 * which handles all the assembler mnemonics.
2087 * MACRO Definitions take precedence
2088 * over machine specific mnemonics.
2090 default:
2091 if (np != NULL) {
2092 macro(np);
2093 } else {
2094 machine(mp);
2098 * Include Files and Macros are not Debugged
2100 if (asmc->objtyp == T_ASM) {
2102 #if NOICE
2104 * NoICE JLH
2105 * if -j, generate a line number symbol
2107 if (jflag && (pass == 1)) {
2108 DefineNoICE_Line();
2110 #endif
2112 #if SDCDB
2114 * SDCC Debug Information
2115 * if cdb information then generate the line info
2117 if (yflag && (pass == 1)) {
2118 DefineSDCC_Line();
2120 #endif
2123 break;
2126 if (is_sdas()) {
2127 if ((c = endline()) != 0) {
2128 err('q');
2131 else {
2132 goto loop;
2136 /*)Function VOID equate(id,e1,equtype)
2138 * char * id ident to equate
2139 * struct expr * e1 value of equate
2140 * a_uint equtype equate type (O_EQU,O_LCLEQU,O_GBLEQU)
2142 * The function equate() installs an equate of a
2143 * given type.
2145 * equate has no return value
2147 * local variables:
2148 * struct sym * sp symbol being equated
2150 * global variables:
2151 * lmode set to ELIST
2153 * functions called:
2154 * VOID clrexpr() asexpr.c
2155 * VOID expr() asexpr.c
2156 * VOID err() assubr.c
2157 * sym * lookup() assym.c
2158 * VOID outall() asout.c
2159 * VOID rerr() assubr.c
2161 * side effects:
2162 * A new symbol may be created.
2163 * Symbol parameters are updated.
2166 VOID
2167 equate(char *id, struct expr *e1, a_uint equtype)
2169 struct sym *sp;
2171 clrexpr(e1);
2172 expr(e1, 0);
2174 sp = lookup(id);
2176 if (sp == &dot) {
2177 outall();
2178 if (e1->e_flag || e1->e_base.e_ap != dot.s_area)
2179 err('.');
2180 } else {
2181 switch(equtype) {
2182 case O_EQU:
2183 default:
2184 break;
2186 case O_GBLEQU:
2187 sp->s_flag &= ~S_LCL;
2188 sp->s_flag |= S_GBL;
2189 break;
2191 case O_LCLEQU:
2192 sp->s_flag &= ~S_GBL;
2193 sp->s_flag |= S_LCL;
2194 break;
2197 if (e1->e_flag && (e1->e_base.e_sp->s_type == S_NEW)) {
2198 rerr();
2199 } else {
2200 sp->s_area = e1->e_base.e_ap;
2202 sp->s_flag |= S_ASG;
2203 sp->s_type = S_USER;
2206 sp->s_addr = laddr = e1->e_addr;
2207 lmode = ELIST;
2210 /*)Function FILE * afile(fn, ft, wf)
2212 * char * fn file specification string
2213 * char * ft file type string
2214 * int wf read(0)/write(1) flag
2216 * The function afile() opens a file for reading or writing.
2218 * afile() returns a file handle for the opened file or aborts
2219 * the assembler on an open error.
2221 * local variables:
2222 * FILE * fp file handle for opened file
2224 * global variables:
2225 * char afn[] afile() constructed filespec
2226 * int afp afile() constructed path length
2227 * char afntmp[] afilex() constructed filespec
2228 * int afptmp afilex() constructed path length
2230 * functions called:
2231 * VOID asexit() asmain.c
2232 * VOID afilex() asmain.c
2233 * FILE * fopen() c_library
2234 * int fprintf() c_library
2235 * char * strcpy() c_library
2237 * side effects:
2238 * File is opened for read or write.
2241 FILE *
2242 afile(char *fn, char *ft, int wf)
2244 FILE *fp;
2245 char *frmt;
2247 afilex(fn, ft);
2250 * Select (Binary) Read/Write
2252 switch(wf) {
2253 default:
2254 case 0: frmt = "r"; break;
2255 /* open file -- use "b" flag to write LF line endings on all host platforms */
2256 /* this is currently set to match old sdas behavior */
2257 case 1: frmt = "wb"; break;
2258 #ifdef DECUS
2259 case 2: frmt = "rn"; break;
2260 case 3: frmt = "wn"; break;
2261 #else
2262 case 2: frmt = "rb"; break;
2263 case 3: frmt = "wb"; break;
2264 #endif
2267 if ((fp = fopen(afntmp, frmt)) == NULL) {
2268 fprintf(stderr, "?ASxxxx-Error-<cannot %s> : \"%s\"\n", (frmt[0] == 'w')?"create":"open", afntmp);
2269 asexit(ER_FATAL);
2272 strcpy(afn, afntmp);
2273 afp = afptmp;
2275 return (fp);
2278 /*)Function VOID afilex(fn, ft)
2280 * char * fn file specification string
2281 * char * ft file type string
2283 * The function afilex() processes the file specification string:
2284 * (1) If the file type specification string ft
2285 * is not NULL then a file specification is
2286 * constructed with the file path\name in fn
2287 * and the extension in ft.
2288 * (2) If the file type specification string ft
2289 * is NULL then the file specification is
2290 * constructed from fn. If fn does not have
2291 * a file type then the default source file
2292 * type dsft is appended to the file specification.
2294 * afilex() aborts the assembler on a file specification length error.
2296 * local variables:
2297 * int c character value
2298 * char * p1 pointer into filespec string afntmp
2299 * char * p2 pointer to filetype string ft
2301 * global variables:
2302 * char afntmp[] afilex() constructed filespec
2303 * int afptmp afilex() constructed path length
2304 * char dsft[] default assembler file type string
2306 * functions called:
2307 * VOID asexit() asmain.c
2308 * int fndidx() asmain.c
2309 * int fprintf() c_library
2310 * char * strcpy() c_library
2311 * int strlen() c_library
2313 * side effects:
2314 * File specification string may be modified.
2317 VOID
2318 afilex(char *fn, char *ft)
2320 char *p1, *p2;
2321 int c;
2323 if (strlen(fn) > (FILSPC-7)) {
2324 fprintf(stderr, "?ASxxxx-Error-<filspc to long> : \"%s\"\n", fn);
2325 asexit(ER_FATAL);
2329 * Save the File Name Index
2331 strcpy(afntmp, fn);
2332 afptmp = fndidx(afntmp);
2335 * Skip to File Extension separator
2337 p1 = strrchr(&afntmp[afptmp], FSEPX);
2340 * Copy File Extension
2342 p2 = ft;
2344 // choose a file-extension
2345 if (*p2 == 0) {
2346 // no extension supplied
2347 if (p1 == NULL) {
2348 // no extension in fn: use default extension
2349 p2 = dsft;
2350 } else {
2351 p2 = strrchr(&fn[afptmp], FSEPX) + 1;
2354 if (p1 == NULL) {
2355 p1 = &afntmp[strlen(afntmp)];
2357 *p1++ = FSEPX;
2358 while ((c = *p2++) != 0) {
2359 if (p1 < &afntmp[FILSPC-1])
2360 *p1++ = c;
2362 *p1++ = 0;
2365 /*)Function int fndidx(str)
2367 * char * str file specification string
2369 * The function fndidx() scans the file specification string
2370 * to find the index to the file name. If the file
2371 * specification contains a 'path' then the index will
2372 * be non zero.
2374 * fndidx() returns the index value.
2376 * local variables:
2377 * char * p1 temporary pointer
2378 * char * p2 temporary pointer
2380 * global variables:
2381 * none
2383 * functions called:
2384 * char * strrchr() c_library
2386 * side effects:
2387 * none
2391 fndidx(char *str)
2393 char *p1, *p2;
2396 * Skip Path Delimiters
2398 p1 = str;
2399 if ((p2 = strrchr(p1, ':')) != NULL) { p1 = p2 + 1; }
2400 if ((p2 = strrchr(p1, '/')) != NULL) { p1 = p2 + 1; }
2401 if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; }
2403 return((int) (p1 - str));
2406 /*)Function VOID newdot(nap)
2408 * area * nap pointer to the new area structure
2410 * The function newdot():
2411 * (1) copies the current values of fuzz and the last
2412 * address into the current area referenced by dot
2413 * (2) loads dot with the pointer to the new area and
2414 * loads the fuzz and last address parameters
2415 * (3) outall() is called to flush any remaining
2416 * bufferred code from the old area to the output
2418 * local variables:
2419 * area * oap pointer to old area
2421 * global variables:
2422 * sym dot defined as sym[0]
2423 * a_uint fuzz tracks pass to pass changes in the
2424 * address of symbols caused by
2425 * variable length instruction formats
2427 * functions called:
2428 * none
2430 * side effects:
2431 * Current area saved, new area loaded, buffers flushed.
2434 VOID
2435 newdot(struct area *nap)
2437 struct area *oap;
2439 oap = dot.s_area;
2440 /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n",
2441 oap->a_id, dot.s_area->a_size, dot.s_addr); */
2442 oap->a_fuzz = fuzz;
2443 if (oap->a_flag & A_OVR) {
2444 // the size of an overlay is the biggest size encountered
2445 if (oap->a_size < dot.s_addr) {
2446 oap->a_size = dot.s_addr;
2449 else if (oap->a_flag & A_ABS) {
2450 oap->a_addr = dot.s_org;
2451 oap->a_size += dot.s_addr - dot.s_org;
2452 dot.s_addr = dot.s_org = 0;
2454 else {
2455 oap->a_addr = 0;
2456 oap->a_size = dot.s_addr;
2458 if (nap->a_flag & A_OVR) {
2459 // a new overlay starts at 0, no fuzz
2460 dot.s_addr = 0;
2461 fuzz = 0;
2463 else if (nap->a_flag & A_ABS) {
2464 // a new absolute starts at org, no fuzz
2465 dot.s_addr = dot.s_org;
2466 fuzz = 0;
2468 else {
2469 dot.s_addr = nap->a_size;
2470 fuzz = nap->a_fuzz;
2472 dot.s_area = nap;
2473 outall();
2476 /*)Function VOID phase(ap, a)
2478 * area * ap pointer to area
2479 * a_uint a address in area
2481 * Function phase() compares the area ap and address a
2482 * with the current area dot.s_area and address dot.s_addr
2483 * to determine if the position of the symbol has changed
2484 * between assembler passes.
2486 * local variables:
2487 * none
2489 * global varaibles:
2490 * sym * dot defined as sym[0]
2492 * functions called:
2493 * none
2495 * side effects:
2496 * The p error is invoked if the area and/or address
2497 * has changed.
2500 VOID
2501 phase(struct area *ap, a_uint a)
2503 if (ap != dot.s_area || a != dot.s_addr)
2504 err('p');
2507 char *usetxt[] = {
2508 "Usage: [-Options] [-Option with arg] file",
2509 "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
2510 " -h or NO ARGUMENTS Show this help list",
2511 "Input:",
2512 " -I Add the named directory to the include file",
2513 " search path. This option may be used more than once.",
2514 " Directories are searched in the order given.",
2515 "Output:",
2516 " -l Create list file/outfile[.lst]",
2517 " -o Create object file/outfile[.rel]",
2518 " -s Create symbol file/outfile[.sym]",
2519 "Listing:",
2520 " -d Decimal listing",
2521 " -q Octal listing",
2522 " -x Hex listing (default)",
2523 " -b Display .define substitutions in listing",
2524 " -bb and display without .define substitutions",
2525 " -c Disable instruction cycle count in listing",
2526 " -f Flag relocatable references by ` in listing file",
2527 " -ff Flag relocatable references by mode in listing file",
2528 " -p Disable automatic listing pagination",
2529 " -u Disable .list/.nlist processing",
2530 " -w Wide listing format for symbol table",
2531 "Assembly:",
2532 " -v Enable out of range signed / unsigned errors",
2533 "Symbols:",
2534 " -a All user symbols made global",
2535 " -g Undefined symbols made global",
2536 " -n Don't resolve global assigned value symbols",
2537 " -z Disable case sensitivity for symbols",
2538 #if (NOICE || SDCDB)
2539 "Debugging:",
2540 #if NOICE
2541 " -j Enable NoICE Debug Symbols",
2542 #endif
2543 #if SDCDB
2544 " -y Enable SDCC Debug Symbols",
2545 #endif
2546 #endif
2548 NULL
2551 /*)Function VOID usage()
2553 * The function usage() outputs to the stderr device the
2554 * assembler name and version and a list of valid assembler options.
2556 * local variables:
2557 * char ** dp pointer to an array of
2558 * text string pointers.
2560 * global variables:
2561 * char cpu[] assembler type string
2562 * char * usetxt[] array of string pointers
2564 * functions called:
2565 * int fprintf() c_library
2567 * side effects:
2568 * none
2571 VOID
2572 usage()
2574 char **dp;
2576 fprintf(stderr, "\n%s Assembler %s (%s)\n\n", is_sdas() ? "sdas" : "ASxxxx", VERSION, cpu);
2577 fprintf(stderr, "\nCopyright (C) %s Alan R. Baldwin", COPYRIGHT);
2578 fprintf(stderr, "\nThis program comes with ABSOLUTELY NO WARRANTY.\n\n");
2579 for (dp = usetxt; *dp; dp++) {
2580 fprintf(stderr, "%s\n", *dp);