make.em.gen
make.fun
failed.c
+getid.c
+insert.c
+internerr.c
+io.c
+insert.h
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
-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
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
#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
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;
C_pt_ilb(l)
label l;
{
+ char buf[16];
+
sprint(buf, "*%ld", (long) l);
wrs(buf);
}
C_pt_cst(l)
arith l;
{
+ char buf[16];
+
sprint(buf, "%ld", (long) l);
wrs(buf);
}
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('\\');
C_pt_dlb(l)
label l;
{
+ char buf[16];
+
sprint(buf, ".%ld", (long) l);
wrs(buf);
}
label l;
arith v;
{
+ char buf[16];
+
C_pt_dlb(l);
if (v != 0) {
sprint(buf,"+%ld", (long) v);
char *s;
arith v;
{
+ char buf[16];
+
wrs(s);
if (v != 0) {
sprint(buf,"+%ld", (long) v);
C_pt_dfilb(l)
label l;
{
+ char buf[16];
+
sprint(buf, "%ld", (long) l);
wrs(buf);
}
-.TH EM_CODE 3ACK "86/04/02"
+.TH EM_CODE 3ACK "$Revision$"
.ad
.SH NAME
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
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
.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,
.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.
C_failed()
{
- sys_write(STDERR,"write failed\n",13);
+ sys_write(STDERR,"read, write, or open failed\n",28);
sys_stop(S_EXIT);
}
--- /dev/null
+/* $Header$ */
+
+/* Get a unique id for C_insertpart, etc.
+*/
+
+C_getid()
+{
+ static int id = 0;
+
+ return ++id;
+}
--- /dev/null
+/* $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 <alloc.h>
+#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();
+ }
+}
--- /dev/null
+/* 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();
--- /dev/null
+/* $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 <system.h>
+
+C_internal_error()
+{
+ sys_write(STDERR,"internal error\n",15);
+ sys_stop(S_EXIT);
+}
--- /dev/null
+/* $Header$ */
+
+/* I/O part of em_code module.
+ Also contains C_open, C_close
+*/
+#include <system.h>
+#include <alloc.h>
+#include <em_path.h>
+#include <em_arith.h>
+#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;
+}
+
#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
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);
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