Initial revision

This commit is contained in:
ceriel 1987-01-06 13:42:33 +00:00
parent 0f42cf1bd9
commit 9cb5c80981
6 changed files with 758 additions and 0 deletions

143
modules/src/em_code/e/em.c Normal file
View file

@ -0,0 +1,143 @@
/* EM CODE OUTPUT ROUTINES */
#include <system.h>
#include "em_private.h"
/*
putbyte(), C_open() and C_close() are the basic routines for
respectively write on, open and close the output file.
The put_*() functions serve as formatting functions of the
various EM language constructs.
See "Description of a Machine Architecture for use with
Block Structured Languages" par. 11.2 for the meaning of these
names.
*/
static File *ofp = 0;
C_open(nm) /* open file for readable 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 (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 ***/
put_ilb(l)
label l;
{
_prnt("*%ld", (long) l);
}
extern char em_mnem[][4];
extern char em_pseu[][4];
put_op(x)
{
_prnt(" %s ", em_mnem[x - sp_fmnem]);
}
put_cst(l)
arith l;
{
_prnt("%ld", (long) l);
}
put_scon(x, y)
char *x;
arith y;
{
char buf[1024];
char sbuf[1024];
register char *p, *q = &sbuf[0];
char *bts2str();
p = bts2str(x, (int) y, buf);
while (*p) {
if (*p == '\'')
*q++ = '\\';
*q++ = *p++;
}
*q = '\0';
_prnt("'%s'", buf);
}
put_ps(x)
{
_prnt(" %s ", em_pseu[x - sp_fpseu]);
}
put_dlb(l)
label l;
{
_prnt(".%ld", (long) l);
}
put_doff(l, v)
label l;
arith v;
{
if (v == 0) put_dlb(l);
else _prnt(".%ld+%ld", (long) l, (long) v);
}
put_noff(s, v)
char *s;
arith v;
{
if (v == 0) _prnt(s);
else _prnt("%s+%ld", s, (long) v);
}
put_pnam(s)
char *s;
{
_prnt("$%s", s);
}
put_dfilb(l)
label l;
{
_prnt("%ld", (long) l);
}
put_wcon(sp, v, sz) /* sp_icon, sp_ucon or sp_fcon with int repr */
int sp;
char *v;
arith sz;
{
_prnt("%s%c%ld", v, sp == sp_icon ? 'I' : sp == sp_ucon ? 'U' : 'F',
(long) sz);
}
_prnt(fmt, args)
char *fmt;
int args;
{
doprnt(ofp, fmt, (int *)&args);
}
put_nl() { _prnt("\n"); }
put_comma() { _prnt(","); }
put_ccend() { _prnt(" ?"); }

View file

@ -0,0 +1,33 @@
/* private inclusion file */
#include <em_arith.h>
#include <em_label.h>
#include <em_code.h>
/* include the EM description files */
#include <em_spec.h>
#include <em_pseu.h>
#include <em_mnem.h>
#include <em_reg.h>
/* macros used in the definitions of the interface functions C_* */
#define OP(x) put_op(x)
#define CST(x) put_cst(x)
#define DCST(x) put_cst(x)
#define SCON(x,y) put_scon((x), (y))
#define PS(x) put_ps(x)
#define DLB(x) put_dlb(x)
#define DFDLB(x) put_dlb(x)
#define ILB(x) put_ilb(x)
#define DFILB(x) put_dfilb(x)
#define NOFF(x,y) put_noff((x), (y))
#define DOFF(x,y) put_doff((x), (y))
#define PNAM(x) put_pnam(x)
#define DNAM(x) _prnt(x)
#define DFDNAM(x) _prnt(x)
#define CEND()
#define CCEND() put_ccend()
#define WCON(x,y,z) put_wcon((x), (y), (z))
#define COMMA() put_comma()
#define NL() put_nl()
#define CILB(x) put_ilb(x)

View file

@ -0,0 +1,106 @@
% Definition of EM procedural interface: hand-written definitions
% C_open | char *:filename | <hand-written>
% C_busy | | <hand-written>
% C_close | | <hand-written>
% C_magic | | <hand-written>
C_df_dlb | label:l | DFDLB(l); NL()
C_df_dnam | char *:s | DFDNAM(s); NL()
C_df_ilb | label:l | DFILB(l); NL()
C_pro | char *:s arith:l |
PS(ps_pro); PNAM(s); COMMA(); CST(l); NL()
C_pro_narg | char *:s |
PS(ps_pro); PNAM(s); COMMA(); CCEND(); NL()
C_end | arith:l | PS(ps_end); CST(l); NL()
C_end_narg | | PS(ps_end); CCEND(); NL()
C_exa_dnam | char *:s | PS(ps_exa); DNAM(s); NL()
C_exa_dlb | label:l | PS(ps_exa); DLB(l); NL()
C_exp | char *:s | PS(ps_exp); PNAM(s); NL()
C_ina_dnam | char *:s | PS(ps_ina); DNAM(s); NL()
C_ina_dlb | label:l | PS(ps_ina); DLB(l); NL()
C_inp | char *:s | PS(ps_inp); PNAM(s); NL()
C_bss_cst | arith:n arith:w int:i |
PS(ps_bss); DCST(n); COMMA(); CST(w); COMMA(); CST((arith) i); NL()
C_bss_icon | arith:n char *:s arith:sz int:i |
PS(ps_bss); DCST(n); COMMA(); WCON(sp_icon, s, sz); COMMA(); CST((arith) i); NL()
C_bss_ucon | arith:n char *:s arith:sz int:i |
PS(ps_bss); DCST(n); COMMA(); WCON(sp_ucon, s, sz); COMMA(); CST((arith) i); NL()
C_bss_fcon | arith:n char *:s arith:sz int:i |
PS(ps_bss); DCST(n); COMMA(); WCON(sp_fcon, s, sz); COMMA(); CST((arith) i); NL()
C_bss_dnam | arith:n char *:s arith:offs int:i |
PS(ps_bss); DCST(n); COMMA(); NOFF(s, offs); COMMA(); CST((arith) i); NL()
C_bss_dlb | arith:n label:l arith:offs int:i |
PS(ps_bss); DCST(n); COMMA(); DOFF(l, offs); COMMA(); CST((arith) i); NL()
C_bss_ilb | arith:n label:l int:i |
PS(ps_bss); DCST(n); COMMA(); ILB(l); COMMA(); CST((arith) i); NL()
C_bss_pnam | arith:n char *:s int:i |
PS(ps_bss); DCST(n); COMMA(); PNAM(s); COMMA(); CST((arith) i); NL()
C_hol_cst | arith:n arith:w int:i |
PS(ps_hol); DCST(n); COMMA(); CST(w); COMMA(); CST((arith) i); NL()
C_hol_icon | arith:n char *:s arith:sz int:i |
PS(ps_hol); DCST(n); COMMA(); WCON(sp_icon, s, sz); COMMA(); CST((arith) i); NL()
C_hol_ucon | arith:n char *:s arith:sz int:i |
PS(ps_hol); DCST(n); COMMA(); WCON(sp_ucon, s, sz); COMMA(); CST((arith) i); NL()
C_hol_fcon | arith:n char *:s arith:sz int:i |
PS(ps_hol); DCST(n); COMMA(); WCON(sp_fcon, s, sz); COMMA(); CST((arith) i); NL()
C_hol_dnam | arith:n char *:s arith:offs int:i |
PS(ps_hol); DCST(n); COMMA(); NOFF(s, offs); COMMA(); CST((arith) i); NL()
C_hol_dlb | arith:n label:l arith:offs int:i |
PS(ps_hol); DCST(n); COMMA(); DOFF(l, offs); COMMA(); CST((arith) i); NL()
C_hol_ilb | arith:n label:l int:i |
PS(ps_hol); DCST(n); COMMA(); ILB(l); COMMA(); CST((arith) i); NL()
C_hol_pnam | arith:n char *:s int:i |
PS(ps_hol); DCST(n); COMMA(); PNAM(s); COMMA(); CST((arith) i); NL()
C_con_cst | arith:l | PS(ps_con); CST(l); CEND(); NL()
C_con_icon | char *:val arith:siz |
PS(ps_con); WCON(sp_icon, val, siz); CEND(); NL()
C_con_ucon | char *:val arith:siz |
PS(ps_con); WCON(sp_ucon, val, siz); CEND(); NL()
C_con_fcon | char *:val arith:siz |
PS(ps_con); WCON(sp_fcon, val, siz); CEND(); NL()
C_con_scon | char *:str arith:siz |
PS(ps_con); SCON(str, siz); CEND(); NL()
C_con_dnam | char *:str arith:val |
PS(ps_con); NOFF(str, val); CEND(); NL()
C_con_dlb | label:l arith:val |
PS(ps_con); DOFF(l, val); CEND(); NL()
C_con_ilb | label:l | PS(ps_con); ILB(l); CEND(); NL()
C_con_pnam | char *:str | PS(ps_con); PNAM(str); CEND(); NL()
C_rom_cst | arith:l | PS(ps_rom); CST(l); CEND(); NL()
C_rom_icon | char *:val arith:siz |
PS(ps_rom); WCON(sp_icon, val, siz); CEND(); NL()
C_rom_ucon | char *:val arith:siz |
PS(ps_rom); WCON(sp_ucon, val, siz); CEND(); NL()
C_rom_fcon | char *:val arith:siz |
PS(ps_rom); WCON(sp_fcon, val, siz); CEND(); NL()
C_rom_scon | char *:str arith:siz |
PS(ps_rom); SCON(str, siz); CEND(); NL()
C_rom_dnam | char *:str arith:val |
PS(ps_rom); NOFF(str, val); CEND(); NL()
C_rom_dlb | label:l arith:val |
PS(ps_rom); DOFF(l, val); CEND(); NL()
C_rom_ilb | label:l | PS(ps_rom); ILB(l); CEND(); NL()
C_rom_pnam | char *:str | PS(ps_rom); PNAM(str); CEND(); NL()
C_cst | arith:l | COMMA(); CST(l)
C_icon | char *:val arith:siz | COMMA(); WCON(sp_icon, val, siz)
C_ucon | char *:val arith:siz | COMMA(); WCON(sp_ucon, val, siz)
C_fcon | char *:val arith:siz | COMMA(); WCON(sp_fcon, val, siz)
C_scon | char *:str arith:siz | COMMA(); SCON(str, siz)
C_dnam | char *:str arith:val | COMMA(); NOFF(str, val)
C_dlb | label:l arith:val | COMMA(); DOFF(l, val)
C_ilb | label:l | COMMA(); ILB(l)
C_pnam | char *:str | COMMA(); PNAM(str)
C_mes_begin | int:ms | PS(ps_mes); CST((arith)ms)
C_mes_end | | CEND(); NL()
% Yes, there really is a C_exc routine...
C_exc | arith:c1 arith:c2 | PS(ps_exc); CST(c1); COMMA(); CST(c2); NL()

View file

@ -0,0 +1,408 @@
.TH EM_CODE 3ACK "86/04/02"
.SH NAME
emcode \- EM code interface for compilers
.SH SYNOPSIS
.nf
.B #include <em.h>
.PP
.B int C_open(filename)
.B C_close()
.B int C_busy()
.B char *filename;
.PP
.B C_magic()
.PP
.B C_df_dlb(l)
.B C_df_dnam(s)
.B C_df_ilb(l)
.B label l; char *s;
.PP
.B C_pro(s, l)
.B C_pro_narg(s)
.B C_end(l)
.B C_end_narg()
.B char *s; arith l;
.PP
.B C_exa_dlb(l)
.B C_exa_dnam(s)
.B C_exp(s)
.B C_ina_dlb(l)
.B C_ina_dnam(s)
.B C_inp(s)
.B char *s; label l;
.PP
.BI C_bss_ cstp ()
.BI C_hol_ cstp ()
.BI C_con_ cstp ()
.BI C_rom_ cstp ()
.PP
.B #include <em_mes.h>
.B C_mes_begin(ms)
.BI C_ cstp ()
.B C_mes_end()
.B int ms;
.PP
.B C_exc(c1, c2)
.B arith c1, c2;
.PP
.BI C_ mnem ()
.BI C_ mnem _dlb()
.BI C_ mnem _dnam()
.BI C_ mnem _narg()
.fi
.SH DESCRIPTION
This package provides a procedural EM code interface to be used in
compilers and other EM code producing programs.
The basic idea behind this package is to simplify the program writer's task
of producing EM code in any form, either compact or human-readable
EM assembly code or a sequence of procedure calls.
.PP
The named types
.B arith
and
.B label
refer to types on the local
machine that are suitable for doing arithmetics and storing EM numeric labels
respectively.
Common definitions are
.B long
for
.B arith
and
.B
unsigned int
for
.BR label .
.PP
.BI C_open( filename )
should be invoked as initialiser for
a sequence of calls that produce EM code on file
.IR filename .
When
.I filename
is a null pointer, the code is produced on standard output.
Some implementations, such as fast back ends, may ignore the parameter.
.B C_close
causes some internal buffers to be flushed and the output file to be closed.
All subsequent routines, except for
.BR C_busy ,
must be invoked between the calls to
.B C_open
and
.BR C_close .
.PP
.B C_busy
can be invoked in order
to detect whether EM code is currently being generated, i.e. whether you are
in between calls to
.B C_open
and
.BR C_close .
If this is the case,
.B C_busy
returns a 1.
.PP
.B C_magic()
produces the EM magic word.
.PP
Two routines can be used to generate code for the definitions of global data
labels:
.BI C_df_dlb( l )
for numeric labels
.BI . l
and
.BI C_df_dnam( s )
for alphanumeric labels
.IR s .
.PP
.BI C_df_ilb( l )
produces EM code for instruction label
.IR l .
.PP
The routines for producing the EM procedure delimiters are:
.PP
.RS
.TS
box;
l|l.
routine EM pattern
=
\&\fBC_pro(\fP\fIs\fP\fB,\ \fP\fIl\fP\fB)\fP \fBpro\ \fP\fIs\fP\fB,\ \fP\fIl\fP
_
\&\fBC_pro_narg(\fP\fIs\fP\fB)\fP \fBpro\ \fP\fIs\fP\fB,\ ?\fP
_
\&\fBC_end(\fP\fIl\fP\fB)\fP \fBend\ \fP\fIl\fP
_
\&\fBC_end_narg()\fP \fBend\ ?\fP
.TE
.RE
.PP
A set of routines, concerning the scope definition pseudo instructions, is:
.PP
.RS
.TS
box;
l|l.
routine EM pattern
=
\&\fBC_exa_dnam(\fP\fIs\fP\fB)\fP \fBexa \fP\fIs\fP
_
\&\fBC_exa_dlb(\fP\fIl\fP\fB)\fP \fBexa .\fP\fIl\fP
_
\&\fBC_exp(\fP\fIs\fP\fB)\fP \fBexp $\fP\fIs\fP
_
\&\fBC_ina_dnam(\fP\fIs\fP\fB)\fP \fBina \fP\fIs\fP
_
\&\fBC_ina_dlb(\fP\fIl\fP\fB)\fP \fBina .\fP\fIl\fP
_
\&\fBC_inp(\fP\fIs\fP\fB)\fP \fBinp $\fP\fIs\fP
.TE
.RE
.PP
In the set of
.B storage-declaration
pseudo instructions, we can
distinguish four groups, one for each type of storage declaration:
.BR con ,
.BR rom ,
.B bss
and
.BR hol .
.PP
The
.BR con / rom
instructions are generated by
.BI C_con_ cstp
and
.BI C_rom_ cstp ,
respectively.
The type of the initialization value and the number and type of the parameters
are determined by
.I cstp
according to the following table:
.PP
.RS
.TS
box;
l|l|l|l
l|l|l|l
l|n|l|l.
\&\fIcstp\fP number of type of description
parameters parameters
=
\&\fBcst\fP 1 \fBarith\fP word-sized integer of \fBarith\fP-type
_
\&\fBicon\fP 2 \fBchar *\fP integer in string representation
\fBarith\fP number of bytes on target machine
_
\&\fBucon\fP 2 \fBchar *\fP unsigned integer in string representation
\fBarith\fP number of bytes on target machine
_
\&\fBfcon\fP 2 \fBchar *\fP floating in string representation
\fBarith\fP number of bytes on target machine
_
\&\fBscon\fP 2 \fBchar *\fP row of bytes
\fBarith\fP length of the row of bytes
_
\&\fBdnam\fP 2 \fBchar *\fP alphanumeric global data label
\fBarith\fP offset (possibly 0)
_
\&\fBdlb\fP 2 \fBlabel\fP numeric global data label
\fBarith\fP offset (possibly 0)
_
\&\fBilb\fP 1 \fBlabel\fP instruction label
_
\&\fBpnam\fP 1 \fBchar *\fP procedure identifier
.TE
.RE
.PP
As an example of the use of the
.BR con / rom
routines, consider the
following
.B con
instruction:
.RS
con 23I4, "hello world", .12, table + 12, *33
.RE
A sequence of calls to get this, is
.RS
.nf
C_con_icon("23", (arith)4);
C_con_scon("hello world");
C_con_dlb((label)12, (arith)0);
C_con_dnam("table", (arith)12);
C_con_ilb((label)33);
.fi
.RE
.PP
A
.B bss
or
.B hol
instruction is produced by invoking
.BI C_bss_ cstp
or
.BI C_hol_ cstp
where
.I cstp
indicates the type of value that is used at initialisation.
The parameter list of
.BI C_bss_ cstp
and
.BI C_hol_ cstp
is similar to that of the corresponding
.BI C_con_ cstp,
except that it is preceeded by an
.BR arith -typed
operand
.I nbytes,
and followed by an
.BR int -typed
operand
.IR init ;
.I nbytes
indicates the number of bytes to reserve for the data;
.I init
has value 1 if the initialization is strictly necessary and 0 if not.
Note that, according to the EM definition, an initialisation type of
.B scon
is not allowed in the
.BR bss / hol
instruction.
.PP
Another set of routines is that of the EM
.B mes
pseudo instructions.
As there is an undefined number of messages and each type of message has
its own number of parameters and each parameter its own type,
the user is responsible for building his own message lists.
Such a list consists of a list of
.BI C_ cstp
routine calls enclosed
by
.BI C_mes_begin( ms )
where
.I ms
is the message number,
and
.BR C_mes_end() .
.PP
.I C_exc
produces the EM
.B exc
.IR c1 , c2
instruction.
The use of this function may cause trouble in some implementations of this
module.
A fast back end, for instance, may refuse to implement
.IR C_exc .
The use of this function is therefore not recommended.
.PP
The final class of routines is that of the EM machine-instruction generating
routines
.BI C_ mnem,
.BI C_ mnem _dlb ,
.BI C_ mnem _dnam
and
.BI C_ mnem _narg .
The best way to describe them is according to section 11.3 of [EM].
Depending on the class of the argument (as indicated by a letter), one
or more routines are available for each machine instruction.
The following table gives an overview of the available routines for
the EM machine instruction
.IR mnem :
.PP
.RS
.TS
box;
l|l|l|l
l|l|l|l
l|l|n|l.
class routine(s) number of type of
parameters parameter(s)
=
[\fBcdflnorsz\fP] \fBC_\fP\fImnem\fP 1 \fBarith\fP
_
\&\fBw\fP \fBC_\fP\fImnem\fP 1 \fBarith\fP
\fBC_\fP\fImnem\fP\fB_narg\fP 0
_
\&\fBg\fP \fBC_\fP\fImnem\fP 1 \fBarith\fP
\fBC_\fP\fImnem\fP\fB_dnam\fP 2 \fBchar *\fP
\fBarith\fP
\fBC_\fP\fImnem\fP\fB_dlb\fP 2 \fBlabel\fP
\fBarith\fP
_
\&\fBp\fP \fBC_\fP\fImnem\fP 1 \fBchar *\fP
_
\&\fBb\fP \fBC_\fP\fImnem\fP 1 \fBlabel\fP
_
\&\fB\-\fP \fBC_\fP\fImnem\fP 0
.TE
.RE
.PP
The available routines for, for example, the EM machine instruction
.B adi
(with argument class
.BR w )
are
.BI C_adi( w )
for
.B adi
with a given argument, and
.B C_adi_narg()
for
.B adi
with an argument on top of the stack.
Likewise are the available routines for
.BR loe
(which instruction has argument class
.BR g ):
.BI C_loe( g )
where
.I g
is a constant,
.BI C_loe_dnam( g , o )
where
.I g
is an alphanumeric label, and
.BI C_loe_dlb( g , o )
where
.I g
is a numeric label.
The latter two routines have the (possibly zero) offset
.I o
as second parameter.
.SH FILES
.nf
~em/modules/h/em.h
~em/modules/lib/libemk.a: library for generating compact EM code
~em/modules/lib/libeme.a: library for generating human-readable EM code
.fi
.SH MODULES
.nf
libemk.a: system(3L), string(3L)
libeme.a: print(3L), system(3L), string(3L)
.fi
.SH SEE ALSO
read_em(3L), em_mes(3L)
.SH REFERENCES
.IP [EM] 6
Andrew S. Tanenbaum, Hans van Staveren, Ed G. Keizer, Johan W. Stevenson,
.B
"Description of a Machine Architecture for use with Block Structured Languages",
Informatica Rapport IR-81, Vrije Universiteit, Amsterdam, 1983.
.LP
.SH DIAGNOSTICS
.I C_open
returns 1 if the open is successful and 0 if not.
The other routines do not give any information about their completion.
.SH BUGS
.IP \(bu
Feel free to report them to the author.
.IP \(bu
It is not possible to indicate that the argument of
.B C_con_cst ()
must be seen as an unsigned value.
.SH AUTHOR
Erik Baalbergen <erikb@vu44.UUCP>

17
modules/src/em_code/make.em.gen Executable file
View file

@ -0,0 +1,17 @@
echo '% this part is generated from ../../../etc/em_table at: ' `date`
ed - ../../../etc/em_table <<'EOI'
1,/^$/d
1,/^$/d
1,$s/^\(...\) \(.\).*/\1:\2/
g/:d/s/^\(...\):\(.\).*/C_\1 | arith:\2 | OP(op_\1); DCST(\2); NL()/
g/:[cslnfzor]/s/^\(...\):\(.\).*/C_\1 | arith:\2 | OP(op_\1); CST(\2); NL()/
g/:w/s/^\(...\).*/C_\1 | arith:w | OP(op_\1); CST(w); NL()\
C_\1_narg | | OP(op_\1); CCEND(); NL()/
g/:g/s/^\(...\).*/C_\1 | arith:g | OP(op_\1); CST(g); NL()\
C_\1_dnam | char *:g arith:o | OP(op_\1); NOFF(g,o); NL()\
C_\1_dlb | label:g arith:o | OP(op_\1); DOFF(g,o); NL()/
g/:p/s/^\(...\).*/C_\1 | char *:p | OP(op_\1); PNAM(p); NL()/
g/:b/s/^\(...\).*/C_\1 | label:b | OP(op_\1); CILB(b); NL()/
g/:-/s/^\(...\).*/C_\1 | | OP(op_\1); NL()/
1,$p
EOI

51
modules/src/em_code/make.fun Executable file
View file

@ -0,0 +1,51 @@
TMP=tmp$$
cat $* >$TMP
ed - $TMP <<'--EOI--'
g/^%/d
g/^$/d
g/^ /.-1,.j
1,$s/[ ]*|[ ]*/|/g
g/NOTIMPLEMENTED/d
1,$s/\([^|]*\)|\([^|]*\)|\(.*\)$/\
NAME \1\
HEAD \1\
PLST \2\
DECL \2\
BODY \3/
$a
END
.
g/^NAME/m$
g/^PLST/s/[ ][ ]*\([^:]*\):\([^ ]*\)/,\2/g
g/^PLST,/s//PLST /
g/^PLST /s/^PLST \(.*\)$/(\1)/
g/^HEAD/.,.+1j
g/^HEAD /s/^HEAD \([^(]*\)\(.*\)$/cat >\1.c <<'--EOF--'\
#include "em_private.h"\
\
\1\2/
g/^DECL/s/[ ][ ]*\([^:]*\):\([^ ]*\)/\
\1 \2;/g
g/^DECL/d
g/^BODY/s/^BODY \(.*\)$/{\
\1;\
}\
--EOF--/
1,/^END/-1p
1,/^END/d
g:^NAME:s:^NAME \(.*\)$:cc -c -O -I$1 -I../../h -I../../../h \1.c:
1i
cat >make.sh <<'--EOF--'
: script for making lib
rm -f *.o
.
$a
cc -c -O -I$1 -I../../h -I../../../h $1/em.c
mv em.o em$1.o
rm -f libem$1.a
ar rc libem$1.a *.o
--EOF--
.
1,$p
--EOI--
rm -f $TMP