3 Copyright (C) 1989-1995 Alan R. Baldwin
4 721 Berkeley St., Kent, Ohio 44240
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 3, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 * Extensions: P. Felber
21 * 13-Feb-08 AD -j and -c as in 8051 as
38 * The module asmain.c includes the command argument parser,
39 * the three pass sequencer, and the machine independent
40 * assembler parsing code.
42 * asmain.c contains the following functions:
43 * VOID main(argc, argv)
46 * FILE * afile(fn, ft, wf)
51 * asmain.c contains the array char *usetxt[] which
52 * references the usage text strings printed by usage().
55 /*)Function VOID main(argc, argv)
57 * int argc argument count
58 * char * argv array of pointers to argument strings
60 * The function main() is the entry point to the assembler.
61 * The purpose of main() is to (1) parse the command line
62 * arguments for options and source file specifications and
63 * (2) to process the source files through the 3 pass assembler.
64 * Before each assembler pass various variables are initialized
65 * and source files are rewound to their beginning. During each
66 * assembler pass each assembler-source text line is processed.
67 * After each assembler pass the assembler information is flushed
68 * to any opened output files and the if-else-endif processing
69 * is checked for proper termination.
71 * The function main() is also responsible for opening all
72 * output files (REL, LST, and SYM), sequencing the global (-g)
73 * and all-global (-a) variable definitions, and dumping the
74 * REL file header information.
77 * char * p pointer to argument string
78 * int c character from argument string
79 * int i argument loop counter
80 * area * ap pointer to area structure
83 * int aflag -a, make all symbols global flag
84 * char afn[] afile() constructed filespec
85 * area * areap pointer to an area structure
86 * int cb[] array of assembler output values
87 * int cbt[] array of assembler relocation types
88 * describing the data in cb[]
89 * int cfile current file handle index
90 * of input assembly files
91 * int * cp pointer to assembler output array cb[]
92 * int * cpt pointer to assembler relocation type
94 * char eb[] array of generated error codes
95 * char * ep pointer into error list array eb[]
96 * int fflag -f(f), relocations flagged flag
97 * int flevel IF-ELSE-ENDIF flag will be non
98 * zero for false conditional case
99 * Addr_T fuzz tracks pass to pass changes in the
100 * address of symbols caused by
101 * variable length instruction formats
102 * int gflag -g, make undefined symbols global flag
103 * char ib[] assembler-source text line
104 * int inpfil count of assembler
105 * input files specified
106 * int ifcnd[] array of IF statement condition
107 * values (0 = FALSE) indexed by tlevel
108 * int iflvl[] array of IF-ELSE-ENDIF flevel
109 * values indexed by tlevel
110 * int incfil current file handle index
112 * char * ip pointer into the assembler-source
114 * jmp_buf jump_env compiler dependent structure
115 * used by setjmp() and longjmp()
116 * int lflag -l, generate listing flag
117 * int line current assembler source
119 * int lop current line number on page
120 * int oflag -o, generate relocatable output flag
121 * int jflag -j, generate debug info flag
122 * int page current page number
123 * int pflag enable listing pagination
124 * int pass assembler pass number
125 * int radix current number conversion radix:
126 * 2 (binary), 8 (octal), 10 (decimal),
128 * int sflag -s, generate symbol table flag
129 * char srcfn[][] array of source file names
130 * int srcline[] current source file line
131 * char stb[] Subtitle string buffer
132 * sym * symp pointer to a symbol structure
133 * int tlevel current conditional level
134 * int xflag -x, listing radix flag
135 * FILE * lfp list output file handle
136 * FILE * ofp relocation output file handle
137 * FILE * tfp symbol table output file handle
138 * FILE * sfp[] array of assembler-source file handles
141 * FILE * afile() asmain.c
142 * VOID allglob() assym.c
143 * VOID asexit() asmain.c
144 * VOID diag() assubr.c
145 * VOID err() assubr.c
146 * int fprintf() c-library
147 * int as_getline() aslex.c
148 * VOID list() aslist.c
149 * VOID lstsym() aslist.c
150 * VOID minit() ___mch.c
151 * VOID newdot() asmain.c
152 * VOID outchk() asout.c
153 * VOID outgsd() asout.c
154 * int rewind() c-library
155 * int setjmp() c-library
156 * VOID symglob() assym.c
157 * VOID syminit() assym.c
158 * VOID usage() asmain.c
161 * Completion of main() completes the assembly process.
162 * REL, LST, and/or SYM files may be generated.
166 main(int argc, char **argv)
172 /* Check to make sure there are the right number of filenames */
173 /* before openning any of them */
179 for (i=1; i<argc; ++i) {
190 fprintf(stdout, "\n");
194 for (i=1; i<argc; ++i) {
200 while ((c = *p++) != 0)
218 case 'j': /* JLH: debug info */
221 ++oflag; /* force object */
271 if (++inpfil == MAXFIL) {
272 fprintf(stderr, "too many input files\n");
275 sfp[inpfil] = afile(p, "", 0);
276 strcpy(srcfn[inpfil],afn);
282 lfp = afile(p, "lst", 1);
284 ofp = afile(p, "", 1);
286 tfp = afile(p, "sym", 1);
291 lfp = afile(p, "LST", 1);
293 ofp = afile(p, "REL", 1);
295 tfp = afile(p, "SYM", 1);
303 for (pass=0; pass<3; ++pass) {
304 if (gflag && pass == 1)
306 if (aflag && pass == 1)
308 if (oflag && pass == 2)
321 for (i = 0; i <= inpfil; i++)
334 while (as_getline()) {
339 if (setjmp(jump_env) == 0)
346 newdot(dot.s_area); /* Flush area info */
347 if (flevel || tlevel)
351 outchk(HUGE, HUGE); /* Flush */
363 /*)Function VOID asexit(i)
367 * The function asexit() explicitly closes all open
368 * files and then terminates the program.
374 * FILE * ifp[] array of include-file file handles
375 * FILE * lfp list output file handle
376 * FILE * ofp relocation output file handle
377 * FILE * tfp symbol table output file handle
378 * FILE * sfp[] array of assembler-source file handles
381 * int fclose() c-library
382 * VOID exit() c-library
385 * All files closed. Program terminates.
393 if (lfp != NULL) fclose(lfp);
394 if (ofp != NULL) fclose(ofp);
395 if (tfp != NULL) fclose(tfp);
397 for (j=0; j<MAXFIL && sfp[j] != NULL; j++) {
401 for (j=0; j<MAXINC && ifp[j] != NULL; j++) {
408 /*)Function VOID asmbl()
410 * The function asmbl() scans the assembler-source text for
411 * (1) labels, global labels, equates, global equates, and local
412 * symbols, (2) .if, .else, .endif, and .page directives,
413 * (3) machine independent assembler directives, and (4) machine
414 * dependent mnemonics.
417 * mne * mp pointer to a mne structure
418 * sym * sp pointer to a sym structure
419 * tsym * tp pointer to a tsym structure
420 * int c character from assembler-source
422 * area * ap pointer to an area structure
423 * expr e1 expression structure
424 * char id[] id string
425 * char opt[] options string
426 * char fn[] filename string
427 * char * p pointer into a string
428 * int d temporary value
429 * int n temporary value
430 * int uaf user area options flag
431 * int uf area options
434 * area * areap pointer to an area structure
435 * char ctype[] array of character types, one per
437 * int flevel IF-ELSE-ENDIF flag will be non
438 * zero for false conditional case
439 * Addr_T fuzz tracks pass to pass changes in the
440 * address of symbols caused by
441 * variable length instruction formats
442 * int ifcnd[] array of IF statement condition
443 * values (0 = FALSE) indexed by tlevel
444 * int iflvl[] array of IF-ELSE-ENDIF flevel
445 * values indexed by tlevel
446 * FILE * ifp[] array of include-file file handles
447 * char incfn[][] array of include file names
448 * int incline[] current include file line
449 * int incfil current file handle index
451 * Addr_T laddr address of current assembler line
452 * or value of .if argument
453 * int lmode listing mode
454 * int lop current line number on page
455 * char module[] module name string
456 * int pass assembler pass number
457 * int radix current number conversion radix:
458 * 2 (binary), 8 (octal), 10 (decimal),
460 * char stb[] Subtitle string buffer
461 * sym * symp pointer to a symbol structure
462 * char tb[] Title string buffer
463 * int tlevel current conditional level
466 * Addr_T absexpr() asexpr.c
467 * area * alookup() assym.c
468 * VOID clrexpr() asexpr.c
469 * int digit() asexpr.c
470 * char endline() aslex.c
471 * VOID err() assubr.c
472 * VOID expr() asexpr.c
473 * FILE * fopen() c-library
475 * VOID getid() aslex.c
476 * int getmap() aslex.c
477 * char getnb() aslex.c
478 * VOID getst() aslex.c
479 * sym * lookup() assym.c
480 * VOID machine() ___mch.c
481 * mne * mlookup() assym.c
483 * VOID * new() assym.c
484 * VOID newdot() asmain.c
485 * VOID outall() asout.c
486 * VOID outab() asout.c
487 * VOID outchk() asout.c
488 * VOID outrb() asout.c
489 * VOID outrw() asout.c
490 * VOID phase() asmain.c
491 * VOID qerr() assubr.c
492 * char * strcpy() c-library
493 * char * strncpy() c-library
494 * VOID unget() aslex.c
500 register struct mne *mp;
501 register struct sym *sp;
502 register struct tsym *tp;
514 unsigned int mantissa, exponent;
515 const char readbuffer[80];
520 if ((c=endline()) == 0) { return; }
522 * If the first character is a digit then assume
523 * a local symbol is being specified. The symbol
524 * must end with $: to be valid.
526 * Construct a tsym structure at the first
527 * occurance of the symbol. Flag the symbol
528 * as multiply defined if not the first occurance.
530 * Load area, address, and fuzz values
531 * into structure tsym.
533 * Check for assembler phase error and
534 * multiply defined error.
536 if (ctype[c] & DIGIT) {
540 while ((d = digit(c, 10)) >= 0) {
544 if (c != '$' || get() != ':')
549 if (n == tp->t_num) {
556 tp=(struct tsym *) new (sizeof(struct tsym));
557 tp->t_lnk = symp->s_tsym;
560 tp->t_area = dot.s_area;
561 tp->t_addr = dot.s_addr;
566 if (n == tp->t_num) {
573 fuzz = tp->t_addr - dot.s_addr;
574 tp->t_area = dot.s_area;
575 tp->t_addr = dot.s_addr;
577 phase(tp->t_area, tp->t_addr);
578 if (tp->t_flg & S_MDF)
589 * If the first character is a letter then assume a label,
590 * symbol, assembler directive, or assembler mnemonic is
593 if ((ctype[c] & LETTER) == 0) {
603 * If the next character is a : then a label is being processed.
604 * A double :: defines a global label. If this is new label
605 * then create a symbol structure.
607 * Flag multiply defined labels.
609 * Load area, address, and fuzz values
610 * into structure symp.
612 * Check for assembler phase error and
613 * multiply defined error.
618 if ((c = get()) != ':') {
626 if ((symp->s_type != S_NEW) &&
627 ((symp->s_flag & S_ASG) == 0))
628 symp->s_flag |= S_MDF;
630 fuzz = symp->s_addr - dot.s_addr;
631 symp->s_type = S_USER;
632 symp->s_area = dot.s_area;
633 symp->s_addr = dot.s_addr;
635 if (symp->s_flag & S_MDF)
637 phase(symp->s_area, symp->s_addr);
640 symp->s_flag |= S_GBL;
646 * If the next character is a = then an equate is being processed.
647 * A double == defines a global equate. If this is new variable
648 * then create a symbol structure.
653 if ((c = get()) != '=') {
662 if (e1.e_flag || e1.e_base.e_ap != dot.s_area)
665 if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) {
669 sp->s_area = e1.e_base.e_ap;
670 sp->s_addr = laddr = e1.e_addr;
679 lmode = flevel ? SLIST : CLIST;
680 if ((mp = mlookup(id)) == NULL) {
686 * If we have gotten this far then we have found an
687 * assembler directive or an assembler mnemonic.
689 * Check for .if, .else, .endif, and .page directives
690 * which are not controlled by the conditional flags
692 switch (mp->m_type) {
696 if (tlevel < MAXIF) {
699 iflvl[tlevel] = flevel;
712 if (++flevel > (iflvl[tlevel]+1)) {
716 if (--flevel < iflvl[tlevel]) {
725 flevel = iflvl[tlevel--];
743 * If we are not in a false state for .if/.else then
744 * process the assembler directives here.
746 switch (mp->m_type) {
750 laddr = dot.s_addr = (dot.s_addr + 1) & ~1;
756 laddr = dot.s_addr |= 1;
765 if (mp->m_type == S_BYTE) {
770 } while ((c = getnb()) == ',');
777 getid( readbuffer, ' ' ); /* Hack :) */
778 if ((c=getnb())=='.')
780 getid(&readbuffer[strlen(readbuffer)],'.');
785 f1 = strtod( readbuffer, (char **)NULL );
786 /* Convert f1 to a gb-lib type fp
787 * 24 bit mantissa followed by 7 bit exp and 1 bit sign
793 f2 = floor(log(fabs(f1))/log(2))+1;
794 mantissa = (unsigned int) ((0x1000000*fabs(f1))/exp(f2*log(2))) ;
796 exponent = (unsigned int) (f2 + 0x40) ;
807 outab(mantissa&0xff);
808 outab((mantissa>>8)&0xff);
809 outab((mantissa>>16)&0xff);
810 outab(exponent&0xff);
812 } while ((c = getnb()) == ',');
819 if ((d = getnb()) == '\0')
821 while ((c = getmap(d)) >= 0)
823 if (mp->m_type == S_ASCIZ)
828 if ((d = getnb()) == '\0')
832 if ((n = getmap(d)) >= 0) {
844 dot.s_addr += e1.e_addr*mp->m_valu;
851 if ((c = getnb()) != 0) {
853 if (p < &tb[NTITL-1])
855 } while ((c = get()) != 0);
864 if ((c = getnb()) != 0) {
866 if (p < &stb[NSBTL-1])
868 } while ((c = get()) != 0);
876 getst(id, getnb()); // a module can start with a digit
881 strncpy(module, id, NCPS);
889 if ((c = getnb()) != 0) {
891 if (p < &optsdcc[NINPUT-1])
893 } while ((c = get()) != 0);
905 } while ((c = getnb()) == ',');
914 if ((c = getnb()) == '(') {
918 if (mp && mp->m_type == S_ATYP) {
924 } while ((c = getnb()) == ',');
930 if ((ap = alookup(id)) != NULL) {
931 if (uaf && uf != ap->a_flag)
934 ap = (struct area *) new (sizeof(struct area));
936 ap->a_id = strsto(id);
937 ap->a_ref = areap->a_ref + 1;
940 ap->a_flag = uaf ? uf : (A_CON|A_REL);
948 if (dot.s_area->a_flag & A_ABS) {
950 laddr = dot.s_addr = absexpr();
996 while ((c = get()) != d) {
997 if (p < &fn[FILSPC-1]) {
1004 if (++incfil == MAXINC ||
1005 (ifp[incfil] = fopen(fn, "r")) == NULL) {
1010 incline[incfil] = 0;
1011 strcpy(incfn[incfil],fn);
1017 * If not an assembler directive then go to
1018 * the machine dependent function which handles
1019 * all the assembler mnemonics.
1022 /* if cdb information then generate the line info */
1023 if (cflag && (pass == 1))
1026 /* JLH: if -j, generate a line number symbol */
1027 if (jflag && (pass == 1))
1038 /*)Function FILE * afile(fn, ft, wf)
1040 * char * fn file specification string
1041 * char * ft file type string
1042 * int wf read(0)/write(1) flag
1044 * The function afile() opens a file for reading or writing.
1045 * (1) If the file type specification string ft
1046 * is not NULL then a file specification is
1047 * constructed with the file path\name in fn
1048 * and the extension in ft.
1049 * (2) If the file type specification string ft
1050 * is NULL then the file specification is
1051 * constructed from fn. If fn does not have
1052 * a file type then the default source file
1053 * type dsft is appended to the file specification.
1055 * afile() returns a file handle for the opened file or aborts
1056 * the assembler on an open error.
1059 * int c character value
1060 * FILE * fp filehandle for opened file
1061 * char * p1 pointer to filespec string fn
1062 * char * p2 pointer to filespec string fb
1063 * char * p3 pointer to filetype string ft
1066 * char afn[] afile() constructed filespec
1067 * char dsft[] default assembler file type string
1068 * char afn[] constructed file specification string
1071 * VOID asexit() asmain.c
1072 * FILE * fopen() c_library
1073 * int fprintf() c_library
1076 * File is opened for read or write.
1080 afile(char *fn, char *ft, int wf)
1082 register char *p2, *p3;
1090 p2 = strrchr (afn, FSEPX); // search last '.'
1092 p2 = afn + strlen (afn);
1093 if (p2 > &afn[FILSPC-4]) // truncate filename, if it's too long
1094 p2 = &afn[FILSPC-4];
1097 // choose a file-extension
1098 if (*p3 == 0) { // extension supplied?
1099 p3 = strrchr (fn, FSEPX); // no: extension in fn?
1103 p3 = dsft; // no: default extension
1106 while ((c = *p3++) != 0) { // strncpy
1107 if (p2 < &afn[FILSPC-1])
1112 if ((fp = fopen(afn, wf?"w":"r")) == NULL) {
1113 fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open");
1119 /*)Function VOID newdot(nap)
1121 * area * nap pointer to the new area structure
1123 * The function newdot():
1124 * (1) copies the current values of fuzz and the last
1125 * address into the current area referenced by dot
1126 * (2) loads dot with the pointer to the new area and
1127 * loads the fuzz and last address parameters
1128 * (3) outall() is called to flush any remaining
1129 * bufferred code from the old area to the output
1132 * area * oap pointer to old area
1135 * sym dot defined as sym[0]
1136 * Addr_T fuzz tracks pass to pass changes in the
1137 * address of symbols caused by
1138 * variable length instruction formats
1144 * Current area saved, new area loaded, buffers flushed.
1148 newdot(struct area *nap)
1150 register struct area *oap;
1154 oap->a_size = dot.s_addr;
1157 dot.s_addr = nap->a_size;
1161 /*)Function VOID phase(ap, a)
1163 * area * ap pointer to area
1164 * Addr_T a address in area
1166 * Function phase() compares the area ap and address a
1167 * with the current area dot.s_area and address dot.s_addr
1168 * to determine if the position of the symbol has changed
1169 * between assembler passes.
1175 * sym * dot defined as sym[0]
1181 * The p error is invoked if the area and/or address
1186 phase(struct area *ap, Addr_T a)
1188 if (ap != dot.s_area || a != dot.s_addr)
1194 "Usage: [-dqxjgalopscf] outfile file1 [file2 file3 ...]",
1196 "Usage: [-dqxjgalopscf] file1 [file2 file3 ...]",
1198 " d decimal listing",
1200 " x hex listing (default)",
1201 " j add line number and debug information to file", /* JLH */
1202 " g undefined symbols made global",
1203 " a all user symbols made global",
1205 " l create list output outfile[LST]",
1206 " o create object output outfile[o]",
1207 " s create symbol output outfile[SYM]",
1209 " l create list output file1[LST]",
1210 " o create object output file1[REL]",
1211 " s create symbol output file1[SYM]",
1213 " c generate sdcdb debug information",
1214 " p disable listing pagination",
1215 " f flag relocatable references by ` in listing file",
1216 " ff flag relocatable references by mode in listing file",
1221 /*)Function VOID usage()
1223 * The function usage() outputs to the stderr device the
1224 * assembler name and version and a list of valid assembler options.
1227 * char ** dp pointer to an array of
1228 * text string pointers.
1231 * char cpu[] assembler type string
1232 * char * usetxt[] array of string pointers
1235 * VOID asexit() asmain.c
1236 * int fprintf() c_library
1239 * program is terminated
1247 fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu);
1248 for (dp = usetxt; *dp; dp++)
1249 fprintf(stderr, "%s\n", *dp);