4 * (C) Copyright 1989-1995
13 * Extensions: P. Felber
20 //#if !defined(_MSC_VER)
33 * The module asmain.c includes the command argument parser,
34 * the three pass sequencer, and the machine independent
35 * assembler parsing code.
37 * asmain.c contains the following functions:
38 * VOID main(argc, argv)
41 * FILE * afile(fn, ft, wf)
46 * asmain.c contains the array char *usetxt[] which
47 * references the usage text strings printed by usage().
50 /*)Function VOID main(argc, argv)
52 * int argc argument count
53 * char * argv array of pointers to argument strings
55 * The function main() is the entry point to the assembler.
56 * The purpose of main() is to (1) parse the command line
57 * arguments for options and source file specifications and
58 * (2) to process the source files through the 3 pass assembler.
59 * Before each assembler pass various variables are initialized
60 * and source files are rewound to their beginning. During each
61 * assembler pass each assembler-source text line is processed.
62 * After each assembler pass the assembler information is flushed
63 * to any opened output files and the if-else-endif processing
64 * is checked for proper termination.
66 * The function main() is also responsible for opening all
67 * output files (REL, LST, and SYM), sequencing the global (-g)
68 * and all-global (-a) variable definitions, and dumping the
69 * REL file header information.
72 * char * p pointer to argument string
73 * int c character from argument string
74 * int i argument loop counter
75 * area * ap pointer to area structure
78 * int aflag -a, make all symbols global flag
79 * char afn[] afile() constructed filespec
80 * area * areap pointer to an area structure
81 * int cb[] array of assembler output values
82 * int cbt[] array of assembler relocation types
83 * describing the data in cb[]
84 * int cfile current file handle index
85 * of input assembly files
86 * int * cp pointer to assembler output array cb[]
87 * int * cpt pointer to assembler relocation type
89 * char eb[] array of generated error codes
90 * char * ep pointer into error list array eb[]
91 * int fflag -f(f), relocations flagged flag
92 * int flevel IF-ELSE-ENDIF flag will be non
93 * zero for false conditional case
94 * Addr_T fuzz tracks pass to pass changes in the
95 * address of symbols caused by
96 * variable length instruction formats
97 * int gflag -g, make undefined symbols global flag
98 * char ib[] assembler-source text line
99 * int inpfil count of assembler
100 * input files specified
101 * int ifcnd[] array of IF statement condition
102 * values (0 = FALSE) indexed by tlevel
103 * int iflvl[] array of IF-ELSE-ENDIF flevel
104 * values indexed by tlevel
105 * int incfil current file handle index
107 * char * ip pointer into the assembler-source
109 * jmp_buf jump_env compiler dependent structure
110 * used by setjmp() and longjmp()
111 * int lflag -l, generate listing flag
112 * int line current assembler source
114 * int lop current line number on page
115 * int oflag -o, generate relocatable output flag
116 * int page current page number
117 * int pflag enable listing pagination
118 * int pass assembler pass number
119 * int radix current number conversion radix:
120 * 2 (binary), 8 (octal), 10 (decimal),
122 * int sflag -s, generate symbol table flag
123 * char srcfn[][] array of source file names
124 * int srcline[] current source file line
125 * char stb[] Subtitle string buffer
126 * sym * symp pointer to a symbol structure
127 * int tlevel current conditional level
128 * int xflag -x, listing radix flag
129 * FILE * lfp list output file handle
130 * FILE * ofp relocation output file handle
131 * FILE * tfp symbol table output file handle
132 * FILE * sfp[] array of assembler-source file handles
135 * FILE * afile() asmain.c
136 * VOID allglob() assym.c
137 * VOID asexit() asmain.c
138 * VOID diag() assubr.c
139 * VOID err() assubr.c
140 * int fprintf() c-library
141 * int getline() aslex.c
142 * VOID list() aslist.c
143 * VOID lstsym() aslist.c
144 * VOID minit() ___mch.c
145 * VOID newdot() asmain.c
146 * VOID outchk() asout.c
147 * VOID outgsd() asout.c
148 * int rewind() c-library
149 * int setjmp() c-library
150 * VOID symglob() assym.c
151 * VOID syminit() assym.c
152 * VOID usage() asmain.c
155 * Completion of main() completes the assembly process.
156 * REL, LST, and/or SYM files may be generated.
160 main(int argc, char **argv)
169 fprintf(stdout, "\n");
173 for (i=1; i<argc; ++i) {
179 while ((c = *p++) != 0)
239 if (++inpfil == MAXFIL) {
240 fprintf(stderr, "too many input files\n");
243 sfp[inpfil] = afile(p, "", 0);
244 strcpy(srcfn[inpfil],afn);
250 lfp = afile(p, "lst", 1);
252 ofp = afile(p, "", 1);
254 tfp = afile(p, "sym", 1);
259 lfp = afile(p, "LST", 1);
261 ofp = afile(p, "REL", 1);
263 tfp = afile(p, "SYM", 1);
271 for (pass=0; pass<3; ++pass) {
272 if (gflag && pass == 1)
274 if (aflag && pass == 1)
276 if (oflag && pass == 2)
289 for (i = 0; i <= inpfil; i++)
307 if (setjmp(jump_env) == 0)
314 newdot(dot.s_area); /* Flush area info */
315 if (flevel || tlevel)
319 outchk(HUGE, HUGE); /* Flush */
331 /*)Function VOID asexit(i)
335 * The function asexit() explicitly closes all open
336 * files and then terminates the program.
342 * FILE * ifp[] array of include-file file handles
343 * FILE * lfp list output file handle
344 * FILE * ofp relocation output file handle
345 * FILE * tfp symbol table output file handle
346 * FILE * sfp[] array of assembler-source file handles
349 * int fclose() c-library
350 * VOID exit() c-library
353 * All files closed. Program terminates.
362 if (lfp != NULL) fclose(lfp);
363 if (ofp != NULL) fclose(ofp);
364 if (tfp != NULL) fclose(tfp);
366 for (j=0; j<MAXFIL && sfp[j] != NULL; j++) {
370 for (j=0; j<MAXINC && ifp[j] != NULL; j++) {
377 /*)Function VOID asmbl()
379 * The function asmbl() scans the assembler-source text for
380 * (1) labels, global labels, equates, global equates, and local
381 * symbols, (2) .if, .else, .endif, and .page directives,
382 * (3) machine independent assembler directives, and (4) machine
383 * dependent mnemonics.
386 * mne * mp pointer to a mne structure
387 * sym * sp pointer to a sym structure
388 * tsym * tp pointer to a tsym structure
389 * int c character from assembler-source
391 * area * ap pointer to an area structure
392 * expr e1 expression structure
393 * char id[] id string
394 * char opt[] options string
395 * char fn[] filename string
396 * char * p pointer into a string
397 * int d temporary value
398 * int n temporary value
399 * int uaf user area options flag
400 * int uf area options
403 * area * areap pointer to an area structure
404 * char ctype[] array of character types, one per
406 * int flevel IF-ELSE-ENDIF flag will be non
407 * zero for false conditional case
408 * Addr_T fuzz tracks pass to pass changes in the
409 * address of symbols caused by
410 * variable length instruction formats
411 * int ifcnd[] array of IF statement condition
412 * values (0 = FALSE) indexed by tlevel
413 * int iflvl[] array of IF-ELSE-ENDIF flevel
414 * values indexed by tlevel
415 * FILE * ifp[] array of include-file file handles
416 * char incfn[][] array of include file names
417 * int incline[] current include file line
418 * int incfil current file handle index
420 * Addr_T laddr address of current assembler line
421 * or value of .if argument
422 * int lmode listing mode
423 * int lop current line number on page
424 * char module[] module name string
425 * int pass assembler pass number
426 * int radix current number conversion radix:
427 * 2 (binary), 8 (octal), 10 (decimal),
429 * char stb[] Subtitle string buffer
430 * sym * symp pointer to a symbol structure
431 * char tb[] Title string buffer
432 * int tlevel current conditional level
435 * Addr_T absexpr() asexpr.c
436 * area * alookup() assym.c
437 * VOID clrexpr() asexpr.c
438 * int digit() asexpr.c
439 * char endline() aslex.c
440 * VOID err() assubr.c
441 * VOID expr() asexpr.c
442 * FILE * fopen() c-library
444 * VOID getid() aslex.c
445 * int getmap() aslex.c
446 * char getnb() aslex.c
447 * VOID getst() aslex.c
448 * sym * lookup() assym.c
449 * VOID machin() ___mch.c
450 * mne * mlookup() assym.c
452 * VOID * new() assym.c
453 * VOID newdot() asmain.c
454 * VOID outall() asout.c
455 * VOID outab() asout.c
456 * VOID outchk() asout.c
457 * VOID outrb() asout.c
458 * VOID outrw() asout.c
459 * VOID phase() asmain.c
460 * VOID qerr() assubr.c
461 * char * strcpy() c-library
462 * char * strncpy() c-library
463 * VOID unget() aslex.c
469 register struct mne *mp;
470 register struct sym *sp;
471 register struct tsym *tp;
483 unsigned int mantissa, exponent;
484 const signed char readbuffer[80];
489 if ((c=endline()) == 0) { return; }
491 * If the first character is a digit then assume
492 * a local symbol is being specified. The symbol
493 * must end with $: to be valid.
495 * Construct a tsym structure at the first
496 * occurance of the symbol. Flag the symbol
497 * as multiply defined if not the first occurance.
499 * Load area, address, and fuzz values
500 * into structure tsym.
502 * Check for assembler phase error and
503 * multiply defined error.
505 if (ctype[c] & DIGIT) {
509 while ((d = digit(c, 10)) >= 0) {
513 if (c != '$' || get() != ':')
518 if (n == tp->t_num) {
525 tp=(struct tsym *) new (sizeof(struct tsym));
526 tp->t_lnk = symp->s_tsym;
529 tp->t_area = dot.s_area;
530 tp->t_addr = dot.s_addr;
535 if (n == tp->t_num) {
542 fuzz = tp->t_addr - dot.s_addr;
543 tp->t_area = dot.s_area;
544 tp->t_addr = dot.s_addr;
546 phase(tp->t_area, tp->t_addr);
547 if (tp->t_flg & S_MDF)
558 * If the first character is a letter then assume a lable,
559 * symbol, assembler directive, or assembler mnemonic is
562 if ((ctype[c] & LETTER) == 0)
571 * If the next character is a : then a label is being processed.
572 * A double :: defines a global label. If this is new label
573 * then create a symbol structure.
575 * Flag multiply defined labels.
577 * Load area, address, and fuzz values
578 * into structure symp.
580 * Check for assembler phase error and
581 * multiply defined error.
586 if ((c = get()) != ':') {
594 if ((symp->s_type != S_NEW) &&
595 ((symp->s_flag & S_ASG) == 0))
596 symp->s_flag |= S_MDF;
598 fuzz = symp->s_addr - dot.s_addr;
599 symp->s_type = S_USER;
600 symp->s_area = dot.s_area;
601 symp->s_addr = dot.s_addr;
603 if (symp->s_flag & S_MDF)
605 phase(symp->s_area, symp->s_addr);
608 symp->s_flag |= S_GBL;
614 * If the next character is a = then an equate is being processed.
615 * A double == defines a global equate. If this is new variable
616 * then create a symbol structure.
621 if ((c = get()) != '=') {
630 if (e1.e_flag || e1.e_base.e_ap != dot.s_area)
633 if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) {
637 sp->s_area = e1.e_base.e_ap;
638 sp->s_addr = laddr = e1.e_addr;
647 lmode = flevel ? SLIST : CLIST;
648 if ((mp = mlookup(id)) == NULL) {
654 * If we have gotten this far then we have found an
655 * assembler directive or an assembler mnemonic.
657 * Check for .if, .else, .endif, and .page directives
658 * which are not controlled by the conditional flags
660 switch (mp->m_type) {
664 if (tlevel < MAXIF) {
667 iflvl[tlevel] = flevel;
680 if (++flevel > (iflvl[tlevel]+1)) {
684 if (--flevel < iflvl[tlevel]) {
693 flevel = iflvl[tlevel--];
711 * If we are not in a false state for .if/.else then
712 * process the assembler directives here.
714 switch (mp->m_type) {
718 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
724 laddr = dot.s_addr |= 1;
733 if (mp->m_type == S_BYTE) {
738 } while ((c = getnb()) == ',');
745 getid( readbuffer, ' ' ); /* Hack :) */
746 if ((c=getnb())=='.')
748 getid(&readbuffer[strlen(readbuffer)],'.');
753 f1 = strtod( readbuffer, (char **)NULL );
754 /* Convert f1 to a gb-lib type fp
755 * 24 bit mantissa followed by 7 bit exp and 1 bit sign
761 f2 = floor(log(fabs(f1))/log(2))+1;
762 mantissa = (0x1000000*fabs(f1))/exp(f2*log(2));
764 exponent = f2 + 0x40;
775 outab(mantissa&0xff);
776 outab((mantissa>>8)&0xff);
777 outab((mantissa>>16)&0xff);
778 outab(exponent&0xff);
780 } while ((c = getnb()) == ',');
787 if ((d = getnb()) == '\0')
789 while ((c = getmap(d)) >= 0)
791 if (mp->m_type == S_ASCIZ)
796 if ((d = getnb()) == '\0')
800 if ((n = getmap(d)) >= 0) {
812 dot.s_addr += e1.e_addr*mp->m_valu;
819 if ((c = getnb()) != 0) {
821 if (p < &tb[NTITL-1])
823 } while ((c = get()) != 0);
832 if ((c = getnb()) != 0) {
834 if (p < &stb[NSBTL-1])
836 } while ((c = get()) != 0);
849 strncpy(module, id, NCPS);
860 } while ((c = getnb()) == ',');
869 if ((c = getnb()) == '(') {
873 if (mp && mp->m_type == S_ATYP) {
879 } while ((c = getnb()) == ',');
885 if ((ap = alookup(id)) != NULL) {
886 if (uaf && uf != ap->a_flag)
889 ap = (struct area *) new (sizeof(struct area));
891 strncpy(ap->a_id, id, NCPS);
892 ap->a_ref = areap->a_ref + 1;
895 ap->a_flag = uaf ? uf : (A_CON|A_REL);
903 if (dot.s_area->a_flag & A_ABS) {
905 laddr = dot.s_addr = absexpr();
951 while ((c = get()) != d) {
952 if (p < &fn[FILSPC-1]) {
959 if (++incfil == MAXINC ||
960 (ifp[incfil] = fopen(fn, "r")) == NULL) {
966 strcpy(incfn[incfil],fn);
972 * If not an assembler directive then go to
973 * the machine dependent function which handles
974 * all the assembler mnemonics.
982 /*)Function FILE * afile(fn, ft, wf)
984 * char * fn file specification string
985 * char * ft file type string
986 * int wf read(0)/write(1) flag
988 * The function afile() opens a file for reading or writing.
989 * (1) If the file type specification string ft
990 * is not NULL then a file specification is
991 * constructed with the file path\name in fn
992 * and the extension in ft.
993 * (2) If the file type specification string ft
994 * is NULL then the file specification is
995 * constructed from fn. If fn does not have
996 * a file type then the default source file
997 * type dsft is appended to the file specification.
999 * afile() returns a file handle for the opened file or aborts
1000 * the assembler on an open error.
1003 * int c character value
1004 * FILE * fp filehandle for opened file
1005 * char * p1 pointer to filespec string fn
1006 * char * p2 pointer to filespec string fb
1007 * char * p3 pointer to filetype string ft
1010 * char afn[] afile() constructed filespec
1011 * char dsft[] default assembler file type string
1012 * char afn[] constructed file specification string
1015 * VOID asexit() asmain.c
1016 * FILE * fopen() c_library
1017 * int fprintf() c_library
1020 * File is opened for read or write.
1029 register char *p1, *p2, *p3;
1036 while ((c = *p1++) != 0 && c != FSEPX) {
1037 if (p2 < &afn[FILSPC-4])
1048 while ((c = *p3++) != 0) {
1049 if (p2 < &afn[FILSPC-1])
1053 if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1054 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1060 /*)Function VOID newdot(nap)
1062 * area * nap pointer to the new area structure
1064 * The function newdot():
1065 * (1) copies the current values of fuzz and the last
1066 * address into the current area referenced by dot
1067 * (2) loads dot with the pointer to the new area and
1068 * loads the fuzz and last address parameters
1069 * (3) outall() is called to flush any remaining
1070 * bufferred code from the old area to the output
1073 * area * oap pointer to old area
1076 * sym dot defined as sym[0]
1077 * Addr_T fuzz tracks pass to pass changes in the
1078 * address of symbols caused by
1079 * variable length instruction formats
1085 * Current area saved, new area loaded, buffers flushed.
1090 register struct area *nap;
1092 register struct area *oap;
1096 oap->a_size = dot.s_addr;
1099 dot.s_addr = nap->a_size;
1103 /*)Function VOID phase(ap, a)
1105 * area * ap pointer to area
1106 * Addr_T a address in area
1108 * Function phase() compares the area ap and address a
1109 * with the current area dot.s_area and address dot.s_addr
1110 * to determine if the position of the symbol has changed
1111 * between assembler passes.
1117 * sym * dot defined as sym[0]
1123 * The p error is invoked if the area and/or address
1132 if (ap != dot.s_area || a != dot.s_addr)
1138 "Usage: [-dqxgalopsf] outfile file1 [file2 file3 ...]",
1140 "Usage: [-dqxgalopsf] file1 [file2 file3 ...]",
1142 " d decimal listing",
1144 " x hex listing (default)",
1145 " g undefined symbols made global",
1146 " a all user symbols made global",
1148 " l create list output outfile[LST]",
1149 " o create object output outfile[o]",
1150 " s create symbol output outfile[SYM]",
1152 " l create list output file1[LST]",
1153 " o create object output file1[REL]",
1154 " s create symbol output file1[SYM]",
1156 " p disable listing pagination",
1157 " f flag relocatable references by ` in listing file",
1158 " ff flag relocatable references by mode in listing file",
1163 /*)Function VOID usage()
1165 * The function usage() outputs to the stderr device the
1166 * assembler name and version and a list of valid assembler options.
1169 * char ** dp pointer to an array of
1170 * text string pointers.
1173 * char cpu[] assembler type string
1174 * char * usetxt[] array of string pointers
1177 * VOID asexit() asmain.c
1178 * int fprintf() c_library
1181 * program is terminated
1189 fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu);
1190 for (dp = usetxt; *dp; dp++)
1191 fprintf(stderr, "%s\n", *dp);