4 * (C) Copyright 1989-1995
11 * 29-Oct-97 JLH pass ";!" comments to output file
23 * The module asmain.c includes the command argument parser,
24 * the three pass sequencer, and the machine independent
25 * assembler parsing code.
27 * asmain.c contains the following functions:
28 * VOID main(argc, argv)
31 * FILE * afile(fn, ft, wf)
36 * asmain.c contains the array char *usetxt[] which
37 * references the usage text strings printed by usage().
40 /*)Function VOID main(argc, argv)
42 * int argc argument count
43 * char * argv array of pointers to argument strings
45 * The function main() is the entry point to the assembler.
46 * The purpose of main() is to (1) parse the command line
47 * arguments for options and source file specifications and
48 * (2) to process the source files through the 3 pass assembler.
49 * Before each assembler pass various variables are initialized
50 * and source files are rewound to their beginning. During each
51 * assembler pass each assembler-source text line is processed.
52 * After each assembler pass the assembler information is flushed
53 * to any opened output files and the if-else-endif processing
54 * is checked for proper termination.
56 * The function main() is also responsible for opening all
57 * output files (REL, LST, and SYM), sequencing the global (-g)
58 * and all-global (-a) variable definitions, and dumping the
59 * REL file header information.
62 * char * p pointer to argument string
63 * int c character from argument string
64 * int i argument loop counter
65 * area * ap pointer to area structure
68 * int aflag -a, make all symbols global flag
69 * char afn[] afile() constructed filespec
70 * area * areap pointer to an area structure
71 * int cb[] array of assembler output values
72 * int cbt[] array of assembler relocation types
73 * describing the data in cb[]
74 * int cfile current file handle index
75 * of input assembly files
76 * int * cp pointer to assembler output array cb[]
77 * int * cpt pointer to assembler relocation type
79 * char eb[] array of generated error codes
80 * char * ep pointer into error list array eb[]
81 * int fflag -f(f), relocations flagged flag
82 * int flevel IF-ELSE-ENDIF flag will be non
83 * zero for false conditional case
84 * Addr_T fuzz tracks pass to pass changes in the
85 * address of symbols caused by
86 * variable length instruction formats
87 * int gflag -g, make undefined symbols global flag
88 * char ib[] assembler-source text line
89 * int inpfil count of assembler
90 * input files specified
91 * int ifcnd[] array of IF statement condition
92 * values (0 = FALSE) indexed by tlevel
93 * int iflvl[] array of IF-ELSE-ENDIF flevel
94 * values indexed by tlevel
95 * int incfil current file handle index
97 * char * ip pointer into the assembler-source
99 * jmp_buf jump_env compiler dependent structure
100 * used by setjmp() and longjmp()
101 * int lflag -l, generate listing flag
102 * int line current assembler source
104 * int lop current line number on page
105 * int oflag -o, generate relocatable output flag
106 * int jflag -j, generate debug info flag
107 * int page current page number
108 * int pflag enable listing pagination
109 * int pass assembler pass number
110 * int radix current number conversion radix:
111 * 2 (binary), 8 (octal), 10 (decimal),
113 * int sflag -s, generate symbol table flag
114 * char srcfn[][] array of source file names
115 * int srcline[] current source file line
116 * char stb[] Subtitle string buffer
117 * sym * symp pointer to a symbol structure
118 * int tlevel current conditional level
119 * int xflag -x, listing radix flag
120 * FILE * lfp list output file handle
121 * FILE * ofp relocation output file handle
122 * FILE * tfp symbol table output file handle
123 * FILE * sfp[] array of assembler-source file handles
126 * FILE * afile() asmain.c
127 * VOID allglob() assym.c
128 * VOID asexit() asmain.c
129 * VOID diag() assubr.c
130 * VOID err() assubr.c
131 * int fprintf() c-library
132 * int as_getline() aslex.c
133 * VOID list() aslist.c
134 * VOID lstsym() aslist.c
135 * VOID minit() ___mch.c
136 * VOID newdot() asmain.c
137 * VOID outchk() asout.c
138 * VOID outgsd() asout.c
139 * int rewind() c-library
140 * int setjmp() c-library
141 * VOID symglob() assym.c
142 * VOID syminit() assym.c
143 * VOID usage() asmain.c
146 * Completion of main() completes the assembly process.
147 * REL, LST, and/or SYM files may be generated.
161 /*fprintf(stdout, "\n");*/
164 for (i=1; i<argc; ++i) {
170 while ((c = *p++) != 0)
188 case 'j': /* JLH: debug info */
191 ++oflag; /* force object */
238 if (++inpfil == MAXFIL) {
239 fprintf(stderr, "too many input files\n");
242 sfp[inpfil] = afile(p, "", 0);
243 strcpy(srcfn[inpfil],afn);
246 lfp = afile(p, "lst", 1);
248 ofp = afile(p, "rel", 1);
249 // save the file name if we have to delete it on error
253 tfp = afile(p, "sym", 1);
260 for (pass=0; pass<3; ++pass) {
261 if (gflag && pass == 1)
263 if (aflag && pass == 1)
265 if (oflag && pass == 2)
278 for (i = 0; i <= inpfil; i++)
291 while (as_getline()) {
297 /* JLH: if line begins with ";!", then
298 * pass this comment on to the output file
300 if (oflag && (pass == 1) &&
301 (ip[0] == ';') && (ip[1] == '!'))
303 fprintf(ofp, "%s\n", ip );
306 if (setjmp(jump_env) == 0)
314 newdot(dot.s_area); /* Flush area info */
315 if (flevel || tlevel)
319 outchk(HUGE, HUGE); /* Flush */
326 //printf ("aserr: %d\n", aserr);
327 //printf ("fatalErrors: %d\n", fatalErrors);
329 return 0; // hush the compiler
332 /*)Function VOID asexit(i)
336 * The function asexit() explicitly closes all open
337 * files and then terminates the program.
343 * FILE * ifp[] array of include-file file handles
344 * FILE * lfp list output file handle
345 * FILE * ofp relocation output file handle
346 * FILE * tfp symbol table output file handle
347 * FILE * sfp[] array of assembler-source file handles
350 * int fclose() c-library
351 * VOID exit() c-library
354 * All files closed. Program terminates.
363 if (lfp != NULL) fclose(lfp);
364 if (ofp != NULL) fclose(ofp);
365 if (tfp != NULL) fclose(tfp);
367 for (j=0; j<MAXFIL && sfp[j] != NULL; j++) {
371 /*for (j=0; j<MAXINC && ifp[j] != NULL; j++) {
375 // remove output file
376 printf ("removing %s\n", relFile);
382 /*)Function VOID asmbl()
384 * The function asmbl() scans the assembler-source text for
385 * (1) labels, global labels, equates, global equates, and local
386 * symbols, (2) .if, .else, .endif, and .page directives,
387 * (3) machine independent assembler directives, and (4) machine
388 * dependent mnemonics.
391 * mne * mp pointer to a mne structure
392 * sym * sp pointer to a sym structure
393 * tsym * tp pointer to a tsym structure
394 * int c character from assembler-source
396 * area * ap pointer to an area structure
397 * expr e1 expression structure
398 * char id[] id string
399 * char opt[] options string
400 * char fn[] filename string
401 * char * p pointer into a string
402 * int d temporary value
403 * int n temporary value
404 * int uaf user area options flag
405 * int uf area options
408 * area * areap pointer to an area structure
409 * char ctype[] array of character types, one per
411 * int flevel IF-ELSE-ENDIF flag will be non
412 * zero for false conditional case
413 * Addr_T fuzz tracks pass to pass changes in the
414 * address of symbols caused by
415 * variable length instruction formats
416 * int ifcnd[] array of IF statement condition
417 * values (0 = FALSE) indexed by tlevel
418 * int iflvl[] array of IF-ELSE-ENDIF flevel
419 * values indexed by tlevel
420 * FILE * ifp[] array of include-file file handles
421 * char incfn[][] array of include file names
422 * int incline[] current include file line
423 * int incfil current file handle index
425 * Addr_T laddr address of current assembler line
426 * or value of .if argument
427 * int lmode listing mode
428 * int lop current line number on page
429 * char module[] module name string
430 * int pass assembler pass number
431 * int radix current number conversion radix:
432 * 2 (binary), 8 (octal), 10 (decimal),
434 * char stb[] Subtitle string buffer
435 * sym * symp pointer to a symbol structure
436 * char tb[] Title string buffer
437 * int tlevel current conditional level
440 * Addr_T absexpr() asexpr.c
441 * area * alookup() assym.c
442 * VOID clrexpr() asexpr.c
443 * int digit() asexpr.c
444 * char endline() aslex.c
445 * VOID err() assubr.c
446 * VOID expr() asexpr.c
447 * FILE * fopen() c-library
449 * VOID getid() aslex.c
450 * int getmap() aslex.c
451 * char getnb() aslex.c
452 * VOID getst() aslex.c
453 * sym * lookup() assym.c
454 * VOID machine() ___mch.c
455 * mne * mlookup() assym.c
457 * VOID * new() assym.c
458 * VOID newdot() asmain.c
459 * VOID outall() asout.c
460 * VOID outab() asout.c
461 * VOID outchk() asout.c
462 * VOID outrb() asout.c
463 * VOID outrw() asout.c
464 * VOID phase() asmain.c
465 * VOID qerr() assubr.c
466 * char * strcpy() c-library
467 * char * strncpy() c-library
468 * VOID unget() aslex.c
474 register struct mne *mp;
475 register struct sym *sp;
476 register struct tsym *tp;
485 static struct area *abs_ap; /* pointer to current absolute area structure */
490 if ((c=endline()) == 0) { return; }
492 * If the first character is a digit then assume
493 * a local symbol is being specified. The symbol
494 * must end with $: to be valid.
496 * Construct a tsym structure at the first
497 * occurance of the symbol. Flag the symbol
498 * as multiply defined if not the first occurance.
500 * Load area, address, and fuzz values
501 * into structure tsym.
503 * Check for assembler phase error and
504 * multiply defined error.
506 if (ctype[c] & DIGIT) {
510 while ((d = digit(c, 10)) >= 0) {
514 if (c != '$' || get() != ':')
519 if (n == tp->t_num) {
526 tp=(struct tsym *) new (sizeof(struct tsym));
527 tp->t_lnk = symp->s_tsym;
530 tp->t_area = dot.s_area;
531 tp->t_addr = dot.s_addr;
536 if (n == tp->t_num) {
543 fuzz = tp->t_addr - dot.s_addr;
544 tp->t_area = dot.s_area;
545 tp->t_addr = dot.s_addr;
547 phase(tp->t_area, tp->t_addr);
548 if (tp->t_flg & S_MDF)
559 * If the first character is a letter then assume a label,
560 * symbol, assembler directive, or assembler mnemonic is
563 if ((ctype[c] & LETTER) == 0) {
573 * If the next character is a : then a label is being processed.
574 * A double :: defines a global label. If this is new label
575 * then create a symbol structure.
577 * Flag multiply defined labels.
579 * Load area, address, and fuzz values
580 * into structure symp.
582 * Check for assembler phase error and
583 * multiply defined error.
588 if ((c = get()) != ':') {
596 if ((symp->s_type != S_NEW) &&
597 ((symp->s_flag & S_ASG) == 0))
598 symp->s_flag |= S_MDF;
600 fuzz = symp->s_addr - dot.s_addr;
601 symp->s_type = S_USER;
602 symp->s_area = dot.s_area;
603 symp->s_addr = dot.s_addr;
605 if (symp->s_flag & S_MDF)
607 phase(symp->s_area, symp->s_addr);
610 symp->s_flag |= S_GBL;
616 * If the next character is a = then an equate is being processed.
617 * A double == defines a global equate. If this is new variable
618 * then create a symbol structure.
623 if ((c = get()) != '=') {
632 if (e1.e_flag || e1.e_base.e_ap != dot.s_area)
635 if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) {
639 sp->s_area = e1.e_base.e_ap;
640 sp->s_addr = laddr = e1.e_addr;
649 lmode = flevel ? SLIST : CLIST;
650 if ((mp = mlookup(id)) == NULL) {
656 * If we have gotten this far then we have found an
657 * assembler directive or an assembler mnemonic.
659 * Check for .if, .else, .endif, and .page directives
660 * which are not controlled by the conditional flags
662 switch (mp->m_type) {
666 if (tlevel < MAXIF) {
669 iflvl[tlevel] = flevel;
682 if (++flevel > (iflvl[tlevel]+1)) {
686 if (--flevel < iflvl[tlevel]) {
695 flevel = iflvl[tlevel--];
713 * If we are not in a false state for .if/.else then
714 * process the assembler directives here.
716 switch (mp->m_type) {
720 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
726 laddr = dot.s_addr |= 1;
735 if (mp->m_type == S_BYTE) {
740 } while ((c = getnb()) == ',');
746 if ((d = getnb()) == '\0')
748 while ((c = getmap(d)) >= 0)
750 if (mp->m_type == S_ASCIZ)
755 if ((d = getnb()) == '\0')
759 if ((n = getmap(d)) >= 0) {
772 dot.s_addr += e1.e_addr*mp->m_valu;
778 if ((c = getnb()) != 0) {
780 if (p < &tb[NTITL-1])
782 } while ((c = get()) != 0);
791 if ((c = getnb()) != 0) {
793 if (p < &stb[NSBTL-1])
795 } while ((c = get()) != 0);
803 getst(id, getnb()); // a module can start with a digit
808 strncpy(module, id, NCPS);
816 if ((c = getnb()) != 0) {
818 if (p < &optsdcc[NINPUT-1])
820 } while ((c = get()) != 0);
825 /*if (pass == 0) printf("optsdcc=%s\n", optsdcc);*/
833 } while ((c = getnb()) == ',');
842 if ((c = getnb()) == '(') {
846 if (mp && mp->m_type == S_ATYP) {
852 } while ((c = getnb()) == ',');
858 if ((ap = alookup(id)) != NULL) {
859 if (uaf && uf != ap->a_flag)
862 ap = (struct area *) new (sizeof(struct area));
864 strncpy(ap->a_id, id, NCPS);
865 ap->a_ref = areap->a_ref + 1;
868 ap->a_flag = uaf ? uf : (A_CON|A_REL);
873 if (dot.s_area->a_flag & A_ABS)
878 if (dot.s_area->a_flag & A_ABS) {
881 sprintf(buf, "%s%x", abs_ap->a_id, laddr);
882 if ((ap = alookup(buf)) == NULL) {
883 ap = (struct area *) new (sizeof(struct area));
886 strncpy(ap->a_id, buf, NCPS);
887 ap->a_ref = areap->a_ref + 1;
894 dot.s_addr = dot.s_org = laddr;
938 while ((c = get()) != d) {
939 if (p < &fn[PATH_MAX-1]) {
946 if ((++incfil == MAXINC) ||
947 (ifp[incfil] = fopen(fn, "r")) == NULL) {
953 strcpy(incfn[incfil],fn);
963 if (!as_strcmpi(id, "on"))
965 /* Quick sanity check: size of
966 * Addr_T must be at least 24 bits.
968 if (sizeof(Addr_T) < 3)
972 "Cannot enable Flat24 mode: "
973 "host system must have 24 bit "
974 "or greater integers.\n");
981 else if (!as_strcmpi(id, "off"))
996 printf("as8051: ds390 flat mode %sabled.\n",
997 flat24Mode ? "en" : "dis");
1003 * If not an assembler directive then go to
1004 * the machine dependent function which handles
1005 * all the assembler mnemonics.
1009 /* if cdb information the generate the line info */
1010 if (cflag && (pass == 1))
1013 /* JLH: if -j, generate a line number symbol */
1014 if (jflag && (pass == 1))
1023 /*)Function FILE * afile(fn, ft, wf)
1025 * char * fn file specification string
1026 * char * ft file type string
1027 * int wf read(0)/write(1) flag
1029 * The function afile() opens a file for reading or writing.
1030 * (1) If the file type specification string ft
1031 * is not NULL then a file specification is
1032 * constructed with the file path\name in fn
1033 * and the extension in ft.
1034 * (2) If the file type specification string ft
1035 * is NULL then the file specification is
1036 * constructed from fn. If fn does not have
1037 * a file type then the default source file
1038 * type dsft is appended to the file specification.
1040 * afile() returns a file handle for the opened file or aborts
1041 * the assembler on an open error.
1044 * int c character value
1045 * FILE * fp filehandle for opened file
1046 * char * p1 pointer to filespec string fn
1047 * char * p2 pointer to filespec string fb
1048 * char * p3 pointer to filetype string ft
1051 * char afn[] afile() constructed filespec
1052 * char dsft[] default assembler file type string
1053 * char afn[] constructed file specification string
1056 * VOID asexit() asmain.c
1057 * FILE * fopen() c_library
1058 * int fprintf() c_library
1061 * File is opened for read or write.
1070 register char *p2, *p3;
1078 p2 = strrchr (afn, FSEPX); // search last '.'
1080 p2 = afn + strlen (afn);
1081 if (p2 > &afn[PATH_MAX-4]) // truncate filename, if it's too long
1082 p2 = &afn[PATH_MAX-4];
1085 // choose a file-extension
1086 if (*p3 == 0) { // extension supplied?
1087 p3 = strrchr (fn, FSEPX); // no: extension in fn?
1091 p3 = dsft; // no: default extension
1094 while ((c = *p3++) != 0) { // strncpy
1095 if (p2 < &afn[PATH_MAX-1])
1100 if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1101 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1107 /*)Function VOID newdot(nap)
1109 * area * nap pointer to the new area structure
1111 * The function newdot():
1112 * (1) copies the current values of fuzz and the last
1113 * address into the current area referenced by dot
1114 * (2) loads dot with the pointer to the new area and
1115 * loads the fuzz and last address parameters
1116 * (3) outall() is called to flush any remaining
1117 * bufferred code from the old area to the output
1120 * area * oap pointer to old area
1123 * sym dot defined as sym[0]
1124 * Addr_T fuzz tracks pass to pass changes in the
1125 * address of symbols caused by
1126 * variable length instruction formats
1132 * Current area saved, new area loaded, buffers flushed.
1137 register struct area *nap;
1139 register struct area *oap;
1142 /* fprintf (stderr, "%s dot.s_area->a_size: %d dot.s_addr: %d\n",
1143 oap->a_id, dot.s_area->a_size, dot.s_addr); */
1145 if (oap->a_flag & A_OVR) {
1146 // the size of an overlay is the biggest size encountered
1147 if (oap->a_size < dot.s_addr) {
1148 oap->a_size = dot.s_addr;
1150 } else if (oap->a_flag & A_ABS) {
1151 oap->a_addr = dot.s_org;
1152 oap->a_size += dot.s_addr - dot.s_org;
1153 dot.s_addr = dot.s_org = 0;
1156 oap->a_size = dot.s_addr;
1158 if (nap->a_flag & A_OVR) {
1159 // a new overlay starts at 0, no fuzz
1162 } else if (nap->a_flag & A_ABS) {
1163 // a new absolute starts at org, no fuzz
1164 dot.s_addr = dot.s_org;
1167 dot.s_addr = nap->a_size;
1174 /*)Function VOID phase(ap, a)
1176 * area * ap pointer to area
1177 * Addr_T a address in area
1179 * Function phase() compares the area ap and address a
1180 * with the current area dot.s_area and address dot.s_addr
1181 * to determine if the position of the symbol has changed
1182 * between assembler passes.
1188 * sym * dot defined as sym[0]
1194 * The p error is invoked if the area and/or address
1203 if (ap != dot.s_area || a != dot.s_addr)
1208 "Usage: [-dqxjgalopsf] file1 [file2 file3 ...]",
1209 " d decimal listing",
1211 " x hex listing (default)",
1212 " j add line number and debug information to file", /* JLH */
1213 " g undefined symbols made global",
1214 " a all user symbols made global",
1215 " l create list output file1[LST]",
1216 " o create object output file1[REL]",
1217 " s create symbol output file1[SYM]",
1218 " p disable listing pagination",
1219 " f flag relocatable references by ` in listing file",
1220 " ff flag relocatable references by mode in listing file",
1225 /*)Function VOID usage()
1227 * The function usage() outputs to the stderr device the
1228 * assembler name and version and a list of valid assembler options.
1231 * char ** dp pointer to an array of
1232 * text string pointers.
1235 * char cpu[] assembler type string
1236 * char * usetxt[] array of string pointers
1239 * VOID asexit() asmain.c
1240 * int fprintf() c_library
1243 * program is terminated
1251 fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu);
1252 for (dp = usetxt; *dp; dp++)
1253 fprintf(stderr, "%s\n", *dp);