4 * (C) Copyright 1989-1995
13 * Extensions: P. Felber
30 * The module asmain.c includes the command argument parser,
31 * the three pass sequencer, and the machine independent
32 * assembler parsing code.
34 * asmain.c contains the following functions:
35 * VOID main(argc, argv)
38 * FILE * afile(fn, ft, wf)
43 * asmain.c contains the array char *usetxt[] which
44 * references the usage text strings printed by usage().
47 /*)Function VOID main(argc, argv)
49 * int argc argument count
50 * char * argv array of pointers to argument strings
52 * The function main() is the entry point to the assembler.
53 * The purpose of main() is to (1) parse the command line
54 * arguments for options and source file specifications and
55 * (2) to process the source files through the 3 pass assembler.
56 * Before each assembler pass various variables are initialized
57 * and source files are rewound to their beginning. During each
58 * assembler pass each assembler-source text line is processed.
59 * After each assembler pass the assembler information is flushed
60 * to any opened output files and the if-else-endif processing
61 * is checked for proper termination.
63 * The function main() is also responsible for opening all
64 * output files (REL, LST, and SYM), sequencing the global (-g)
65 * and all-global (-a) variable definitions, and dumping the
66 * REL file header information.
69 * char * p pointer to argument string
70 * int c character from argument string
71 * int i argument loop counter
72 * area * ap pointer to area structure
75 * int aflag -a, make all symbols global flag
76 * char afn[] afile() constructed filespec
77 * area * areap pointer to an area structure
78 * int cb[] array of assembler output values
79 * int cbt[] array of assembler relocation types
80 * describing the data in cb[]
81 * int cfile current file handle index
82 * of input assembly files
83 * int * cp pointer to assembler output array cb[]
84 * int * cpt pointer to assembler relocation type
86 * char eb[] array of generated error codes
87 * char * ep pointer into error list array eb[]
88 * int fflag -f(f), relocations flagged flag
89 * int flevel IF-ELSE-ENDIF flag will be non
90 * zero for false conditional case
91 * Addr_T fuzz tracks pass to pass changes in the
92 * address of symbols caused by
93 * variable length instruction formats
94 * int gflag -g, make undefined symbols global flag
95 * char ib[] assembler-source text line
96 * int inpfil count of assembler
97 * input files specified
98 * int ifcnd[] array of IF statement condition
99 * values (0 = FALSE) indexed by tlevel
100 * int iflvl[] array of IF-ELSE-ENDIF flevel
101 * values indexed by tlevel
102 * int incfil current file handle index
104 * char * ip pointer into the assembler-source
106 * jmp_buf jump_env compiler dependent structure
107 * used by setjmp() and longjmp()
108 * int lflag -l, generate listing flag
109 * int line current assembler source
111 * int lop current line number on page
112 * int oflag -o, generate relocatable output flag
113 * int page current page number
114 * int pflag enable listing pagination
115 * int pass assembler pass number
116 * int radix current number conversion radix:
117 * 2 (binary), 8 (octal), 10 (decimal),
119 * int sflag -s, generate symbol table flag
120 * char srcfn[][] array of source file names
121 * int srcline[] current source file line
122 * char stb[] Subtitle string buffer
123 * sym * symp pointer to a symbol structure
124 * int tlevel current conditional level
125 * int xflag -x, listing radix flag
126 * FILE * lfp list output file handle
127 * FILE * ofp relocation output file handle
128 * FILE * tfp symbol table output file handle
129 * FILE * sfp[] array of assembler-source file handles
132 * FILE * afile() asmain.c
133 * VOID allglob() assym.c
134 * VOID asexit() asmain.c
135 * VOID diag() assubr.c
136 * VOID err() assubr.c
137 * int fprintf() c-library
138 * int as_getline() aslex.c
139 * VOID list() aslist.c
140 * VOID lstsym() aslist.c
141 * VOID minit() ___mch.c
142 * VOID newdot() asmain.c
143 * VOID outchk() asout.c
144 * VOID outgsd() asout.c
145 * int rewind() c-library
146 * int setjmp() c-library
147 * VOID symglob() assym.c
148 * VOID syminit() assym.c
149 * VOID usage() asmain.c
152 * Completion of main() completes the assembly process.
153 * REL, LST, and/or SYM files may be generated.
157 main(int argc, char **argv)
163 /* Check to make sure there are the right number of filenames */
164 /* before openning any of them */
170 for (i=1; i<argc; ++i) {
181 fprintf(stdout, "\n");
185 for (i=1; i<argc; ++i) {
191 while ((c = *p++) != 0)
251 if (++inpfil == MAXFIL) {
252 fprintf(stderr, "too many input files\n");
255 sfp[inpfil] = afile(p, "", 0);
256 strcpy(srcfn[inpfil],afn);
262 lfp = afile(p, "lst", 1);
264 ofp = afile(p, "", 1);
266 tfp = afile(p, "sym", 1);
271 lfp = afile(p, "LST", 1);
273 ofp = afile(p, "REL", 1);
275 tfp = afile(p, "SYM", 1);
283 for (pass=0; pass<3; ++pass) {
284 if (gflag && pass == 1)
286 if (aflag && pass == 1)
288 if (oflag && pass == 2)
301 for (i = 0; i <= inpfil; i++)
314 while (as_getline()) {
319 if (setjmp(jump_env) == 0)
326 newdot(dot.s_area); /* Flush area info */
327 if (flevel || tlevel)
331 outchk(HUGE, HUGE); /* Flush */
343 /*)Function VOID asexit(i)
347 * The function asexit() explicitly closes all open
348 * files and then terminates the program.
354 * FILE * ifp[] array of include-file file handles
355 * FILE * lfp list output file handle
356 * FILE * ofp relocation output file handle
357 * FILE * tfp symbol table output file handle
358 * FILE * sfp[] array of assembler-source file handles
361 * int fclose() c-library
362 * VOID exit() c-library
365 * All files closed. Program terminates.
374 if (lfp != NULL) fclose(lfp);
375 if (ofp != NULL) fclose(ofp);
376 if (tfp != NULL) fclose(tfp);
378 for (j=0; j<MAXFIL && sfp[j] != NULL; j++) {
382 for (j=0; j<MAXINC && ifp[j] != NULL; j++) {
389 /*)Function VOID asmbl()
391 * The function asmbl() scans the assembler-source text for
392 * (1) labels, global labels, equates, global equates, and local
393 * symbols, (2) .if, .else, .endif, and .page directives,
394 * (3) machine independent assembler directives, and (4) machine
395 * dependent mnemonics.
398 * mne * mp pointer to a mne structure
399 * sym * sp pointer to a sym structure
400 * tsym * tp pointer to a tsym structure
401 * int c character from assembler-source
403 * area * ap pointer to an area structure
404 * expr e1 expression structure
405 * char id[] id string
406 * char opt[] options string
407 * char fn[] filename string
408 * char * p pointer into a string
409 * int d temporary value
410 * int n temporary value
411 * int uaf user area options flag
412 * int uf area options
415 * area * areap pointer to an area structure
416 * char ctype[] array of character types, one per
418 * int flevel IF-ELSE-ENDIF flag will be non
419 * zero for false conditional case
420 * Addr_T fuzz tracks pass to pass changes in the
421 * address of symbols caused by
422 * variable length instruction formats
423 * int ifcnd[] array of IF statement condition
424 * values (0 = FALSE) indexed by tlevel
425 * int iflvl[] array of IF-ELSE-ENDIF flevel
426 * values indexed by tlevel
427 * FILE * ifp[] array of include-file file handles
428 * char incfn[][] array of include file names
429 * int incline[] current include file line
430 * int incfil current file handle index
432 * Addr_T laddr address of current assembler line
433 * or value of .if argument
434 * int lmode listing mode
435 * int lop current line number on page
436 * char module[] module name string
437 * int pass assembler pass number
438 * int radix current number conversion radix:
439 * 2 (binary), 8 (octal), 10 (decimal),
441 * char stb[] Subtitle string buffer
442 * sym * symp pointer to a symbol structure
443 * char tb[] Title string buffer
444 * int tlevel current conditional level
447 * Addr_T absexpr() asexpr.c
448 * area * alookup() assym.c
449 * VOID clrexpr() asexpr.c
450 * int digit() asexpr.c
451 * char endline() aslex.c
452 * VOID err() assubr.c
453 * VOID expr() asexpr.c
454 * FILE * fopen() c-library
456 * VOID getid() aslex.c
457 * int getmap() aslex.c
458 * char getnb() aslex.c
459 * VOID getst() aslex.c
460 * sym * lookup() assym.c
461 * VOID machine() ___mch.c
462 * mne * mlookup() assym.c
464 * VOID * new() assym.c
465 * VOID newdot() asmain.c
466 * VOID outall() asout.c
467 * VOID outab() asout.c
468 * VOID outchk() asout.c
469 * VOID outrb() asout.c
470 * VOID outrw() asout.c
471 * VOID phase() asmain.c
472 * VOID qerr() assubr.c
473 * char * strcpy() c-library
474 * char * strncpy() c-library
475 * VOID unget() aslex.c
481 register struct mne *mp;
482 register struct sym *sp;
483 register struct tsym *tp;
495 unsigned int mantissa, exponent;
496 const char readbuffer[80];
501 if ((c=endline()) == 0) { return; }
503 * If the first character is a digit then assume
504 * a local symbol is being specified. The symbol
505 * must end with $: to be valid.
507 * Construct a tsym structure at the first
508 * occurance of the symbol. Flag the symbol
509 * as multiply defined if not the first occurance.
511 * Load area, address, and fuzz values
512 * into structure tsym.
514 * Check for assembler phase error and
515 * multiply defined error.
517 if (ctype[c] & DIGIT) {
521 while ((d = digit(c, 10)) >= 0) {
525 if (c != '$' || get() != ':')
530 if (n == tp->t_num) {
537 tp=(struct tsym *) new (sizeof(struct tsym));
538 tp->t_lnk = symp->s_tsym;
541 tp->t_area = dot.s_area;
542 tp->t_addr = dot.s_addr;
547 if (n == tp->t_num) {
554 fuzz = tp->t_addr - dot.s_addr;
555 tp->t_area = dot.s_area;
556 tp->t_addr = dot.s_addr;
558 phase(tp->t_area, tp->t_addr);
559 if (tp->t_flg & S_MDF)
570 * If the first character is a letter then assume a lable,
571 * symbol, assembler directive, or assembler mnemonic is
574 if ((ctype[c] & LETTER) == 0) {
584 * If the next character is a : then a label is being processed.
585 * A double :: defines a global label. If this is new label
586 * then create a symbol structure.
588 * Flag multiply defined labels.
590 * Load area, address, and fuzz values
591 * into structure symp.
593 * Check for assembler phase error and
594 * multiply defined error.
599 if ((c = get()) != ':') {
607 if ((symp->s_type != S_NEW) &&
608 ((symp->s_flag & S_ASG) == 0))
609 symp->s_flag |= S_MDF;
611 fuzz = symp->s_addr - dot.s_addr;
612 symp->s_type = S_USER;
613 symp->s_area = dot.s_area;
614 symp->s_addr = dot.s_addr;
616 if (symp->s_flag & S_MDF)
618 phase(symp->s_area, symp->s_addr);
621 symp->s_flag |= S_GBL;
627 * If the next character is a = then an equate is being processed.
628 * A double == defines a global equate. If this is new variable
629 * then create a symbol structure.
634 if ((c = get()) != '=') {
643 if (e1.e_flag || e1.e_base.e_ap != dot.s_area)
646 if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) {
650 sp->s_area = e1.e_base.e_ap;
651 sp->s_addr = laddr = e1.e_addr;
660 lmode = flevel ? SLIST : CLIST;
661 if ((mp = mlookup(id)) == NULL) {
667 * If we have gotten this far then we have found an
668 * assembler directive or an assembler mnemonic.
670 * Check for .if, .else, .endif, and .page directives
671 * which are not controlled by the conditional flags
673 switch (mp->m_type) {
677 if (tlevel < MAXIF) {
680 iflvl[tlevel] = flevel;
693 if (++flevel > (iflvl[tlevel]+1)) {
697 if (--flevel < iflvl[tlevel]) {
706 flevel = iflvl[tlevel--];
724 * If we are not in a false state for .if/.else then
725 * process the assembler directives here.
727 switch (mp->m_type) {
731 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
737 laddr = dot.s_addr |= 1;
746 if (mp->m_type == S_BYTE) {
751 } while ((c = getnb()) == ',');
758 getid( readbuffer, ' ' ); /* Hack :) */
759 if ((c=getnb())=='.')
761 getid(&readbuffer[strlen(readbuffer)],'.');
766 f1 = strtod( readbuffer, (char **)NULL );
767 /* Convert f1 to a gb-lib type fp
768 * 24 bit mantissa followed by 7 bit exp and 1 bit sign
774 f2 = floor(log(fabs(f1))/log(2))+1;
775 mantissa = (unsigned int) ((0x1000000*fabs(f1))/exp(f2*log(2))) ;
777 exponent = (unsigned int) (f2 + 0x40) ;
788 outab(mantissa&0xff);
789 outab((mantissa>>8)&0xff);
790 outab((mantissa>>16)&0xff);
791 outab(exponent&0xff);
793 } while ((c = getnb()) == ',');
800 if ((d = getnb()) == '\0')
802 while ((c = getmap(d)) >= 0)
804 if (mp->m_type == S_ASCIZ)
809 if ((d = getnb()) == '\0')
813 if ((n = getmap(d)) >= 0) {
825 dot.s_addr += e1.e_addr*mp->m_valu;
832 if ((c = getnb()) != 0) {
834 if (p < &tb[NTITL-1])
836 } while ((c = get()) != 0);
845 if ((c = getnb()) != 0) {
847 if (p < &stb[NSBTL-1])
849 } while ((c = get()) != 0);
857 getst(id, getnb()); // a module can start with a digit
862 strncpy(module, id, NCPS);
870 if ((c = getnb()) != 0) {
872 if (p < &optsdcc[NINPUT-1])
874 } while ((c = get()) != 0);
886 } while ((c = getnb()) == ',');
895 if ((c = getnb()) == '(') {
899 if (mp && mp->m_type == S_ATYP) {
905 } while ((c = getnb()) == ',');
911 if ((ap = alookup(id)) != NULL) {
912 if (uaf && uf != ap->a_flag)
915 ap = (struct area *) new (sizeof(struct area));
917 strncpy(ap->a_id, id, NCPS);
918 ap->a_ref = areap->a_ref + 1;
921 ap->a_flag = uaf ? uf : (A_CON|A_REL);
929 if (dot.s_area->a_flag & A_ABS) {
931 laddr = dot.s_addr = absexpr();
977 while ((c = get()) != d) {
978 if (p < &fn[FILSPC-1]) {
985 if (++incfil == MAXINC ||
986 (ifp[incfil] = fopen(fn, "r")) == NULL) {
992 strcpy(incfn[incfil],fn);
998 * If not an assembler directive then go to
999 * the machine dependent function which handles
1000 * all the assembler mnemonics.
1008 /*)Function FILE * afile(fn, ft, wf)
1010 * char * fn file specification string
1011 * char * ft file type string
1012 * int wf read(0)/write(1) flag
1014 * The function afile() opens a file for reading or writing.
1015 * (1) If the file type specification string ft
1016 * is not NULL then a file specification is
1017 * constructed with the file path\name in fn
1018 * and the extension in ft.
1019 * (2) If the file type specification string ft
1020 * is NULL then the file specification is
1021 * constructed from fn. If fn does not have
1022 * a file type then the default source file
1023 * type dsft is appended to the file specification.
1025 * afile() returns a file handle for the opened file or aborts
1026 * the assembler on an open error.
1029 * int c character value
1030 * FILE * fp filehandle for opened file
1031 * char * p1 pointer to filespec string fn
1032 * char * p2 pointer to filespec string fb
1033 * char * p3 pointer to filetype string ft
1036 * char afn[] afile() constructed filespec
1037 * char dsft[] default assembler file type string
1038 * char afn[] constructed file specification string
1041 * VOID asexit() asmain.c
1042 * FILE * fopen() c_library
1043 * int fprintf() c_library
1046 * File is opened for read or write.
1055 register char *p2, *p3;
1063 p2 = strrchr (afn, FSEPX); // search last '.'
1065 p2 = afn + strlen (afn);
1066 if (p2 > &afn[FILSPC-4]) // truncate filename, if it's too long
1067 p2 = &afn[FILSPC-4];
1070 // choose a file-extension
1071 if (*p3 == 0) { // extension supplied?
1072 p3 = strrchr (fn, FSEPX); // no: extension in fn?
1076 p3 = dsft; // no: default extension
1079 while ((c = *p3++) != 0) { // strncpy
1080 if (p2 < &afn[FILSPC-1])
1085 if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1086 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1092 /*)Function VOID newdot(nap)
1094 * area * nap pointer to the new area structure
1096 * The function newdot():
1097 * (1) copies the current values of fuzz and the last
1098 * address into the current area referenced by dot
1099 * (2) loads dot with the pointer to the new area and
1100 * loads the fuzz and last address parameters
1101 * (3) outall() is called to flush any remaining
1102 * bufferred code from the old area to the output
1105 * area * oap pointer to old area
1108 * sym dot defined as sym[0]
1109 * Addr_T fuzz tracks pass to pass changes in the
1110 * address of symbols caused by
1111 * variable length instruction formats
1117 * Current area saved, new area loaded, buffers flushed.
1122 register struct area *nap;
1124 register struct area *oap;
1128 oap->a_size = dot.s_addr;
1131 dot.s_addr = nap->a_size;
1135 /*)Function VOID phase(ap, a)
1137 * area * ap pointer to area
1138 * Addr_T a address in area
1140 * Function phase() compares the area ap and address a
1141 * with the current area dot.s_area and address dot.s_addr
1142 * to determine if the position of the symbol has changed
1143 * between assembler passes.
1149 * sym * dot defined as sym[0]
1155 * The p error is invoked if the area and/or address
1164 if (ap != dot.s_area || a != dot.s_addr)
1170 "Usage: [-dqxgalopsf] outfile file1 [file2 file3 ...]",
1172 "Usage: [-dqxgalopsf] file1 [file2 file3 ...]",
1174 " d decimal listing",
1176 " x hex listing (default)",
1177 " g undefined symbols made global",
1178 " a all user symbols made global",
1180 " l create list output outfile[LST]",
1181 " o create object output outfile[o]",
1182 " s create symbol output outfile[SYM]",
1184 " l create list output file1[LST]",
1185 " o create object output file1[REL]",
1186 " s create symbol output file1[SYM]",
1188 " p disable listing pagination",
1189 " f flag relocatable references by ` in listing file",
1190 " ff flag relocatable references by mode in listing file",
1195 /*)Function VOID usage()
1197 * The function usage() outputs to the stderr device the
1198 * assembler name and version and a list of valid assembler options.
1201 * char ** dp pointer to an array of
1202 * text string pointers.
1205 * char cpu[] assembler type string
1206 * char * usetxt[] array of string pointers
1209 * VOID asexit() asmain.c
1210 * int fprintf() c_library
1213 * program is terminated
1221 fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu);
1222 for (dp = usetxt; *dp; dp++)
1223 fprintf(stderr, "%s\n", *dp);