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 = ˙
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