diff --git a/modules/src/em_code/.distr b/modules/src/em_code/.distr index 7d846a18f..0f60b575f 100644 --- a/modules/src/em_code/.distr +++ b/modules/src/em_code/.distr @@ -6,3 +6,8 @@ k make.em.gen make.fun failed.c +getid.c +insert.c +internerr.c +io.c +insert.h diff --git a/modules/src/em_code/Makefile b/modules/src/em_code/Makefile index ee2fa403f..fbf468394 100644 --- a/modules/src/em_code/Makefile +++ b/modules/src/em_code/Makefile @@ -1,6 +1,9 @@ EMHOME = ../../.. INSTALL = $(EMHOME)/modules/install COMPARE = $(EMHOME)/modules/compare +INCORE = -DINCORE +CFLAGS = -I$(EMHOME)/h -I$(EMHOME)/modules/h -O +OBS = failed.o insert.o internerr.o io.o getid.o all: libeme.a libemk.a em_code.3 rm -f C_*.c @@ -19,15 +22,15 @@ em_code.3: em_code.3X -sh -c 'tbl < em_code.3X > em_code.3' -sh -c 'if test -s em_code.3 ; then : ; else cp em_code.3X em_code.3 ; fi ' -libeme.a: make.sh e/em_private.h e/em.c failed.c +libeme.a: make.sh e/em_private.h e/em.c $(OBS) EMHOME=$(EMHOME); export EMHOME; sh make.sh e -sh -c 'ranlib libeme.a' -libemk.a: make.sh k/em_private.h k/em.c failed.c +libemk.a: make.sh k/em_private.h k/em.c $(OBS) EMHOME=$(EMHOME); export EMHOME; sh make.sh k -sh -c 'ranlib libemk.a' -make.sh: em.gen em.nogen +make.sh: em.gen em.nogen make.fun make.fun em.gen em.nogen | sh em.gen: make.em.gen $(EMHOME)/etc/em_table @@ -50,3 +53,9 @@ lintlib: make.sh lint -I../../h -I../../../h -Ie -Ceme *.c e/*.c lint -I../../h -I../../../h -Ik -Cemk *.c k/*.c mv llib-leme.ln llib-lemk.ln $(EMHOME)/modules/lib + +insert.o: insert.c insert.h + $(CC) $(CFLAGS) -c $(INCORE) insert.c + +io.o: io.c insert.h + $(CC) $(CFLAGS) -c $(INCORE) io.c diff --git a/modules/src/em_code/e/em.c b/modules/src/em_code/e/em.c index 9b0e93e52..a653c831b 100644 --- a/modules/src/em_code/e/em.c +++ b/modules/src/em_code/e/em.c @@ -9,8 +9,6 @@ #include "em_private.h" /* - putbyte(), C_open() and C_close() are the basic routines for - respectively write on, open and close the outpt file. The C_pt_*() functions serve as formatting functions of the various EM language constructs. See "Description of a Machine Architecture for use with @@ -18,65 +16,12 @@ names. */ -static File *ofp = 0; -static char obuf[BUFSIZ]; -static char *opp = obuf; - -static -flush() { - if (sys_write(ofp, &obuf[0], opp - &obuf[0]) == 0) { - C_failed(); - } - opp = &obuf[0]; -} - -#define Xputbyte(c) if (opp == &obuf[BUFSIZ]) flush(); *opp++ = (c) - -static -C_putbyte(b) - int b; -{ - Xputbyte(b); -} - -C_init(w, p) - arith w, p; -{ -} - -C_open(nm) /* open file for readable code outpt */ - char *nm; -{ - if (nm == 0) - ofp = STDOUT; /* standard outpt */ - else - if (sys_open(nm, OP_WRITE, &ofp) == 0) - return 0; - return 1; -} - -C_close() -{ - if (opp != obuf) flush(); - if (ofp != STDOUT) - sys_close(ofp); - ofp = 0; -} - -C_busy() -{ - return ofp != 0; /* true if code is being generated */ -} - C_magic() { } - /*** the readable code generating routines ***/ -static char buf[512]; - static wrs(s) register char *s; @@ -93,6 +38,8 @@ C_pt_dnam(s) C_pt_ilb(l) label l; { + char buf[16]; + sprint(buf, "*%ld", (long) l); wrs(buf); } @@ -110,6 +57,8 @@ C_pt_op(x) C_pt_cst(l) arith l; { + char buf[16]; + sprint(buf, "%ld", (long) l); wrs(buf); } @@ -118,13 +67,12 @@ C_pt_scon(x, y) char *x; arith y; { - char buf[1024]; - char sbuf[1024]; - register char *p, *q = &sbuf[0]; + char xbuf[1024]; + register char *p; char *bts2str(); C_putbyte('\''); - p = bts2str(x, (int) y, buf); + p = bts2str(x, (int) y, xbuf); while (*p) { if (*p == '\'') C_putbyte('\\'); @@ -143,6 +91,8 @@ C_pt_ps(x) C_pt_dlb(l) label l; { + char buf[16]; + sprint(buf, ".%ld", (long) l); wrs(buf); } @@ -151,6 +101,8 @@ C_pt_doff(l, v) label l; arith v; { + char buf[16]; + C_pt_dlb(l); if (v != 0) { sprint(buf,"+%ld", (long) v); @@ -162,6 +114,8 @@ C_pt_noff(s, v) char *s; arith v; { + char buf[16]; + wrs(s); if (v != 0) { sprint(buf,"+%ld", (long) v); @@ -179,6 +133,8 @@ C_pt_pnam(s) C_pt_dfilb(l) label l; { + char buf[16]; + sprint(buf, "%ld", (long) l); wrs(buf); } diff --git a/modules/src/em_code/em_code.3X b/modules/src/em_code/em_code.3X index 5eeefae30..b9c2a71ab 100644 --- a/modules/src/em_code/em_code.3X +++ b/modules/src/em_code/em_code.3X @@ -1,4 +1,4 @@ -.TH EM_CODE 3ACK "86/04/02" +.TH EM_CODE 3ACK "$Revision$" .ad .SH NAME emcode \- EM code interface for compilers @@ -53,6 +53,17 @@ emcode \- EM code interface for compilers .BI C_ mnem _dlb() .BI C_ mnem _dnam() .BI C_ mnem _narg() +.PP +.B C_insertpart(id) +.B int id; +.PP +.B C_beginpart(id) +.B int id; +.PP +.B C_endpart(id) +.B int id; +.PP +.B int C_getid() .fi .SH DESCRIPTION This package provides a procedural EM code interface to be used in @@ -386,6 +397,33 @@ is a numeric label. The latter two routines have the (possibly zero) offset .I o as second parameter. +.PP +The +.IR C_insertpart , +.IR C_beginpart , +and +.I C_endpart +routines together implement a mechanism for re-arranging the generated code. +A call to +.I C_insertpart +indicates that part +.I id +is to be inserted at the current position. +The routines +.I C_beginpart +and +.I C_endpart +indicate begin and end of part +.IR id . +The order in which the parts are defined is not significant. +However, when +.I C_close +is called, all parts that have been inserted, must also be defined. +.PP +The routine +.I C_getid +can be used to obtain a valid and unique part +.IR id . .SH FILES .nf ~em/modules/h/em.h @@ -394,11 +432,11 @@ as second parameter. .fi .SH MODULES .nf -libemk.a: system(3L), string(3L) -libeme.a: print(3L), system(3L), string(3L) +libemk.a: alloc(3), system(3), string(3) +libeme.a: alloc(3), print(3), system(3), string(3) .fi .SH SEE ALSO -read_em(3L), em_mes(3L) +read_em(3), em_mes(3) .SH REFERENCES .IP [EM] 6 Andrew S. Tanenbaum, Hans van Staveren, Ed G. Keizer, Johan W. Stevenson, @@ -410,14 +448,18 @@ Informatica Rapport IR-81, Vrije Universiteit, Amsterdam, 1983. .I C_open returns 1 if the open is successful and 0 if not. .PP -When a write fails, the routine +When a read, write or open fails, the routine .I C_failed is called. The user can override its default definition by supplying his own. The default just gives an error message and quits. +.PP +When an error occurs with the +.I C_insertpart +mechanism, the routine +.I C_internal_error +is called. Again, the user can override its default definition by supplying his +own. Such errors, however, are caused by a programming error of the user. .SH BUGS It is not possible to indicate that the argument of .B C_con_cst () must be seen as an unsigned value. -.PP -.I C_failed -is never called when generating readable EM code. diff --git a/modules/src/em_code/failed.c b/modules/src/em_code/failed.c index 9b3cd21f0..92fe96098 100644 --- a/modules/src/em_code/failed.c +++ b/modules/src/em_code/failed.c @@ -7,6 +7,6 @@ C_failed() { - sys_write(STDERR,"write failed\n",13); + sys_write(STDERR,"read, write, or open failed\n",28); sys_stop(S_EXIT); } diff --git a/modules/src/em_code/getid.c b/modules/src/em_code/getid.c new file mode 100644 index 000000000..4b107bcef --- /dev/null +++ b/modules/src/em_code/getid.c @@ -0,0 +1,11 @@ +/* $Header$ */ + +/* Get a unique id for C_insertpart, etc. +*/ + +C_getid() +{ + static int id = 0; + + return ++id; +} diff --git a/modules/src/em_code/insert.c b/modules/src/em_code/insert.c new file mode 100644 index 000000000..08443cb46 --- /dev/null +++ b/modules/src/em_code/insert.c @@ -0,0 +1,186 @@ +/* $Header$ */ + +/* Implementation of C_insertpart, C_beginpart, and C_endpart. + Basic methodology: place the parts either in memory or on a temporary + file, in the order received, and remember this order. Then, in a second + "pass", write out the code. + An optimization is possible: as long as the order in which the parts + are received corresponds to the order in which they must be written, + they can be written immediately. +*/ + +#include +#include "insert.h" + +#ifdef INCORE +#define C_switchtotmp() (C_ontmpfile = 1) +#define C_switchtoout() (C_ontmpfile = 0) +#endif + +static int +available(part) + int part; +{ + /* See if part "part", and all the parts it consists of, + are available. Return 1 if they are, 0 otherwize + */ + register Part *p = C_findpart(part); + register PartOfPart *pp; + int retval = 1; + + if (p == 0) return 0; + + if (p->p_flags & BUSY) { + /* recursive call ends up here, and this just should + not happen. It is an error of the programmer using + this module. + */ + C_internal_error(); + } + + p->p_flags |= BUSY; + + pp = p->p_parts; + while (pp) { + if (pp->pp_type == INSERT && ! available(pp->pp_id)) { + retval = 0; + break; + } + else pp = pp->pp_next; + } + p->p_flags &= ~BUSY; + return retval; +} + +static Part * +mkpart(part) + int part; +{ + /* Create a Part structure with id "part", and return a + pointer to it, after checking that is does not exist + already. + */ + register Part *p = C_findpart(part); + register int index = part % TABSIZ; + + if (p != 0) { + /* multiple defined part ... */ + C_internal_error(); + } + + p = (Part *) Malloc(sizeof(Part)); + p->p_id = part; + p->p_next = C_stable[index]; + C_stable[index] = p; + p->p_parts = 0; + p->p_flags = 0; + p->p_prevpart = 0; + return p; +} + +static +end_partofpart(p) + register Part *p; +{ + /* End the current chunk of part *p. + */ + + if (p) { + register PartOfPart *pp = p->p_parts; + + pp->pp_end = C_current_out; + if (pp->pp_begin == pp->pp_end) { + /* nothing in this chunk, so give it back */ + p->p_parts = pp->pp_next; + free((char *) pp); + } + } +} + +static +resume(p) + register Part *p; +{ + /* Resume part "p", by creating a new PartOfPart structure + for it. + */ + register PartOfPart *pp = (PartOfPart *) Malloc(sizeof(PartOfPart)); + + C_switchtotmp(); + C_curr_part = p; + pp->pp_next = p->p_parts; + p->p_parts = pp; + pp->pp_type = TEXT; + pp->pp_begin = C_current_out; +} + +C_insertpart(part) + int part; +{ + /* Insert part "part" in the current part. If C_sequential is + still set and the part to be inserted is available now, + just write it out. + */ + register Part *p; + register PartOfPart *pp; + + if (C_sequential && available(part)) { + outpart(part); + return; + } + + if (C_sequential) { + /* stop the sequential stuff, by creating a part */ + C_sequential = 0; + p = mkpart(0); + C_curr_part = p; + } + else { + p = C_curr_part; + end_partofpart(p); + } + + /* Now, add the insertion of "part" to the current part. */ + pp = (PartOfPart *) Malloc(sizeof(PartOfPart)); + pp->pp_next = p->p_parts; + p->p_parts = pp; + pp->pp_type = INSERT; + pp->pp_id = part; + resume(p); +} + +C_beginpart(part) + int part; +{ + /* Now follows the definition for part "part". + Suspend the current part, and add part "part" to the + table. + */ + register Part *p = mkpart(part); + + end_partofpart(C_curr_part); + + p->p_prevpart = C_curr_part; + resume(p); +} + +C_endpart(part) + int part; +{ + /* End the current part. The parameter "part" is just there + for the checking. Do we really need it ??? + */ + register Part *p = C_curr_part; + + if (p->p_id != part) { + /* illegal C_endpart ... */ + C_internal_error(); + } + + end_partofpart(p); + if (p->p_prevpart) resume(p->p_prevpart); + else { + C_curr_part = 0; + C_switchtoout(); + } +} diff --git a/modules/src/em_code/insert.h b/modules/src/em_code/insert.h new file mode 100644 index 000000000..04ac7d85b --- /dev/null +++ b/modules/src/em_code/insert.h @@ -0,0 +1,43 @@ +/* Structures used for the C_insertpart, C_beginpart, and C_endpart + mechanism. Each part consists of a list of chunks. Each chunk is + either another part, or a piece of text limited by a begin- and an + end-pointer. +*/ + +typedef struct partofpart { + struct partofpart *pp_next; + char pp_type; +#define TEXT 0 +#define INSERT 1 + union { + struct { + long ppu_begin, ppu_end; + } ppu_s; + int ppu_id; + } pp_u; +#define pp_begin pp_u.ppu_s.ppu_begin +#define pp_end pp_u.ppu_s.ppu_end +#define pp_id pp_u.ppu_id +} PartOfPart; + +typedef struct part { + struct part *p_next; /* next part in hash chain */ + char p_flags; +#define BUSY 1 + PartOfPart *p_parts; /* chunks of this part */ + struct part *p_prevpart; /* implements stack of active parts */ + int p_id; /* id of this part */ +} Part; + +#define outpart(xxx) C_out_parts(C_findpart(xxx)->p_parts) + +#define TABSIZ 32 + +extern int + C_ontmpfile, C_sequential; +extern Part + *C_curr_part, *C_stable[]; +extern long + C_current_out; +extern Part + *C_findpart(); diff --git a/modules/src/em_code/internerr.c b/modules/src/em_code/internerr.c new file mode 100644 index 000000000..187d72b65 --- /dev/null +++ b/modules/src/em_code/internerr.c @@ -0,0 +1,12 @@ +/* $Header$ */ +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +#include + +C_internal_error() +{ + sys_write(STDERR,"internal error\n",15); + sys_stop(S_EXIT); +} diff --git a/modules/src/em_code/io.c b/modules/src/em_code/io.c new file mode 100644 index 000000000..91b975b58 --- /dev/null +++ b/modules/src/em_code/io.c @@ -0,0 +1,247 @@ +/* $Header$ */ + +/* I/O part of em_code module. + Also contains C_open, C_close +*/ +#include +#include +#include +#include +#include "insert.h" + +int + C_ontmpfile = 0, + C_sequential = 1; +Part + *C_curr_part, *C_stable[TABSIZ]; +long + C_current_out; + +static char *BASE; +static File *ofp; + +#ifndef INCORE +static File *tfr, *old_ofp; +static char *tmpfile; +char *strcpy(), *strcat(), *mktemp(); +static char *ibuf = 0; +#endif + +static char obuf[BUFSIZ]; +static char *opp = obuf; + +static +flush() { + if (opp != obuf && sys_write(ofp, obuf, opp - obuf) == 0) { + C_failed(); + } + opp = obuf; +} + +#define put(c) if (opp == &obuf[BUFSIZ]) flush(); *opp++ = (c) + +C_putbyte(c) + int c; +{ + if (C_ontmpfile) { +#ifdef INCORE + static unsigned sz; + + if (BASE == 0) { + BASE = Malloc(BUFSIZ); + sz = BUFSIZ; + } + else if (C_current_out >= sz) { + BASE = Srealloc(BASE, (sz <<= 1)); + } + *(BASE + C_current_out) = c; +#endif + C_current_out++; +#ifdef INCORE + return; +#endif + } + put(c); +} + +#ifndef INCORE +C_switchtotmp() +{ + if (tmpfile == 0) { + static char tmpbuf[64]; + register char *p = tmpbuf; + + strcpy(p, TMP_DIR); + strcat(p, "/CodeXXXXXX"); + tmpfile = mktemp(p); + if (! sys_open(p, OP_WRITE, &old_ofp)) { + C_failed(); + } + if (! sys_open(p, OP_READ, &tfr)) { + C_failed(); + } + } + if (! C_ontmpfile) { + File *p = ofp; + + flush(); + ofp = old_ofp; + old_ofp = p; + C_ontmpfile = 1; + } +} + +C_switchtoout() +{ + if (C_ontmpfile) { + File *p = ofp; + + flush(); + ofp = old_ofp; + old_ofp = p; + C_ontmpfile = 0; + } +} +#endif + +C_init(w, p) + arith w, p; +{ +} + +C_open(nm) + char *nm; +{ + /* Open file "nm" for output + */ + + if (nm == 0) + ofp = STDOUT; /* standard output */ + else + if (sys_open(nm, OP_WRITE, &ofp) == 0) + return 0; + return 1; +} + +C_close() +{ + /* Finish the code-generation. + */ + +#ifndef INCORE + flush(); + if (tmpfile) { + C_switchtotmp(); + sys_close(ofp); + ofp = old_ofp; +#else + if (BASE) { +#endif + if (C_curr_part) { + C_curr_part->p_parts->pp_end = C_current_out; + } + if (! C_sequential) { + outpart(0); + } +#ifndef INCORE + sys_close(tfr); + sys_remove(tmpfile); + if (ibuf) free(ibuf); +#else + free(BASE); +#endif + } + flush(); + if (ofp != STDOUT) + sys_close(ofp); + ofp = 0; +} + +C_busy() +{ + return ofp != 0; /* true if code is being generated */ +} + +#ifndef INCORE +static int +getbyte(b) + long b; +{ + /* Get the byte at offset "b" from the start of the + temporary file, and try to do so in an efficient way. + */ + static long start_core, curr_pos; + + if (b < start_core || b >= curr_pos) { + /* the block wanted is not in core, so get it */ + long nb = (b & ~(BUFSIZ - 1)); + int n; + + flush(); + if (nb != curr_pos) { + if (sys_seek(tfr, nb, 0, &curr_pos) == 0) { + C_failed(); + } + } + if (! ibuf) { + ibuf = Malloc(BUFSIZ); + } + if (sys_read(tfr, ibuf, BUFSIZ, &n) == 0) { + C_failed(); + } + curr_pos += n; + start_core = nb; + } + + return ibuf[(int) (b - start_core)]; +} +#endif + +C_out_parts(pp) + register PartOfPart *pp; +{ + /* Output the list of chunks started by "pp". + The list is build in reverse order, so this routine is + recursive. + */ + + if (!pp) return; + if (pp->pp_next) C_out_parts(pp->pp_next); + + if (pp->pp_type == INSERT) { + outpart(pp->pp_id); + } + else { + /* copy the chunk to output */ +#ifdef INCORE + register char *s = BASE + pp->pp_begin; + char *se = BASE + pp->pp_end; + + while (s < se) { + put(*s++); + } +#else + register long b = pp->pp_begin; + + while (b < pp->pp_end) { + put(getbyte(b++)); + } +#endif + } +} + +Part * +C_findpart(part) + int part; +{ + /* Look for part "part" in the table. + Return 0 if not present, + */ + register Part *p = C_stable[part % TABSIZ]; + + while (p && p->p_id != part) { + p = p->p_next; + } + return p; +} + diff --git a/modules/src/em_code/k/em.c b/modules/src/em_code/k/em.c index 490600799..4feb42965 100644 --- a/modules/src/em_code/k/em.c +++ b/modules/src/em_code/k/em.c @@ -13,8 +13,6 @@ #define put32(x) put16((int) x); put16((int) (x >> 16)) /* - C_putbyte(), C_open() and C_close() are the basic routines for - respectively write on, open and close the output file. The C_pt_*() functions serve as formatting functions of the various EM language constructs. See "Description of a Machine Architecture for use with @@ -22,59 +20,6 @@ names. */ -/* supply a kind of buffered output */ - -static char obuf[BUFSIZ]; -static char *opp = &obuf[0]; -static File *ofp = 0; - -static -flush() { - if (sys_write(ofp, &obuf[0], opp - &obuf[0]) == 0) { - C_failed(); - } - opp = &obuf[0]; -} - -#define Xputbyte(c) if (opp == &obuf[BUFSIZ]) flush(); *opp++ = (c) - -C_putbyte(b) - int b; -{ - Xputbyte(b); -} - -#define C_putbyte(c) Xputbyte(c) - -C_init(w, p) - arith w, p; -{ -} - -C_open(nm) /* open file for compact code output */ - char *nm; -{ - if (nm == 0) - ofp = STDOUT; /* standard output */ - else - if (sys_open(nm, OP_WRITE, &ofp) == 0) - return 0; - return 1; -} - -C_close() -{ - if (opp != &obuf[0]) flush(); - if (ofp != STDOUT) - sys_close(ofp); - ofp = 0; -} - -C_busy() -{ - return ofp != 0; /* true if code is being generated */ -} - C_magic() { put16(sp_magic); diff --git a/modules/src/em_code/make.fun b/modules/src/em_code/make.fun index e68993aa8..b55b52217 100755 --- a/modules/src/em_code/make.fun +++ b/modules/src/em_code/make.fun @@ -37,16 +37,14 @@ g:^NAME:s:^NAME \(.*\)$:cc -c -O -I$1 -I$EMHOME/modules/h -I$EMHOME/h \1.c: 1i cat >make.sh <<'--EOF--' : script for making lib -rm -f *.o +rm -f C_*.o . $a rm -f libem$1.a -ar rc libem$1.a *.o -cc -c -O -I$1 -I. -I$EMHOME/modules/h -I$EMHOME/h $1/em.c -cc -c -O -I$EMHOME/modules/h -I$EMHOME/h failed.c +cc -c -O -I$1 -I$EMHOME/modules/h -I$EMHOME/h $1/em.c mv em.o em$1.o -ar r libem$1.a em$1.o failed.o -rm -f *.o +ar rc libem$1.a C_*.o em$1.o insert.o io.o failed.o internerr.o getid.o +rm -f C_*.o --EOF-- . 1,$p