Added C_insertpart mechanism

This commit is contained in:
ceriel 1987-07-01 17:24:10 +00:00
parent 19897803d4
commit 83bc77ad51
12 changed files with 586 additions and 132 deletions

View file

@ -6,3 +6,8 @@ k
make.em.gen
make.fun
failed.c
getid.c
insert.c
internerr.c
io.c
insert.h

View file

@ -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

View file

@ -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);
}

View file

@ -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.

View file

@ -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);
}

View file

@ -0,0 +1,11 @@
/* $Header$ */
/* Get a unique id for C_insertpart, etc.
*/
C_getid()
{
static int id = 0;
return ++id;
}

View file

@ -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 <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();
}
}

View file

@ -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();

View file

@ -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 <system.h>
C_internal_error()
{
sys_write(STDERR,"internal error\n",15);
sys_stop(S_EXIT);
}

247
modules/src/em_code/io.c Normal file
View file

@ -0,0 +1,247 @@
/* $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;
}

View file

@ -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);

View file

@ -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