Initial revision
This commit is contained in:
42
util/ego/ca/Makefile
Normal file
42
util/ego/ca/Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
EMH=../../../h
|
||||
EML=../../../lib
|
||||
CFLAGS=
|
||||
SHARE=../share
|
||||
CA=.
|
||||
OBJECTS=ca.o ca_put.o
|
||||
SHOBJECTS=$(SHARE)/get.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/aux.o $(SHARE)/debug.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/files.o $(SHARE)/map.o
|
||||
SRC=ca.h ca_put.h ca.c ca_put.c
|
||||
|
||||
.c.o:
|
||||
cc $(CFLAGS) -c $<
|
||||
all: $(OBJECTS)
|
||||
ca: \
|
||||
$(OBJECTS) $(SHOBJECTS)
|
||||
cc -o ca -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
|
||||
lpr:
|
||||
pr $(SRC) | lpr
|
||||
dumpflop:
|
||||
tar -uf /mnt/ego/ca/ca.tarf $(SRC) Makefile
|
||||
# the next lines are generated automatically
|
||||
# AUTOAUTOAUTOAUTOAUTOAUTO
|
||||
ca.o: ../share/alloc.h
|
||||
ca.o: ../share/debug.h
|
||||
ca.o: ../share/files.h
|
||||
ca.o: ../share/get.h
|
||||
ca.o: ../share/global.h
|
||||
ca.o: ../share/lset.h
|
||||
ca.o: ../share/map.h
|
||||
ca.o: ../share/types.h
|
||||
ca.o: ca.h
|
||||
ca.o: ca_put.h
|
||||
ca_put.o: ../../../h/em_flag.h
|
||||
ca_put.o: ../../../h/em_mes.h
|
||||
ca_put.o: ../../../h/em_mnem.h
|
||||
ca_put.o: ../../../h/em_pseu.h
|
||||
ca_put.o: ../../../h/em_spec.h
|
||||
ca_put.o: ../share/alloc.h
|
||||
ca_put.o: ../share/debug.h
|
||||
ca_put.o: ../share/def.h
|
||||
ca_put.o: ../share/map.h
|
||||
ca_put.o: ../share/types.h
|
||||
ca_put.o: ca.h
|
||||
199
util/ego/ca/ca.c
Normal file
199
util/ego/ca/ca.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* C O M P A C T A S S E M B L Y L A N G U A G E G E N E R A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "ca.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/global.h"
|
||||
#include "../share/lset.h"
|
||||
#include "../share/files.h"
|
||||
#include "../share/map.h"
|
||||
#include "../share/alloc.h"
|
||||
#include "../share/get.h"
|
||||
#include "ca_put.h"
|
||||
|
||||
|
||||
/* This phase transforms the Intermediate Code of the global optimizer
|
||||
* to 'standard' compact assembly language, which will be processed
|
||||
* by the code generator.
|
||||
*/
|
||||
|
||||
|
||||
short dlength;
|
||||
dblock_p *dmap;
|
||||
|
||||
char **dnames, **pnames; /* Dynamically allocated arrays of strings.
|
||||
* pnames[i] contains a pointer to the name
|
||||
* of the procedure with proc_id i.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
STATIC int makedmap(dbl)
|
||||
dblock_p dbl;
|
||||
{
|
||||
/* construct the dmap table */
|
||||
|
||||
dblock_p d;
|
||||
int cnt;
|
||||
|
||||
/* determine the length of the table */
|
||||
|
||||
cnt = 0;
|
||||
for (d = dbl; d != (dblock_p) 0; d = d->d_next) cnt++;
|
||||
dmap = (dblock_p *) newmap(cnt);
|
||||
for (d = dbl; d != (dblock_p) 0; d = d->d_next) {
|
||||
assert(d->d_id) <= cnt;
|
||||
dmap[d->d_id] = d;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC getdnames(dumpd)
|
||||
FILE *dumpd;
|
||||
{
|
||||
/* Read the names of the datalabels from
|
||||
* the dump file.
|
||||
*/
|
||||
|
||||
char str[IDL+1];
|
||||
char *s;
|
||||
int id;
|
||||
register int i;
|
||||
|
||||
dnames = (char **) newnametab(dlength,IDL);
|
||||
for (;;) {
|
||||
if (fscanf(dumpd,"%d %s",&id,str) == EOF) return;
|
||||
assert(id <= dlength);
|
||||
s = dnames[id];
|
||||
for (i = 0; i < IDL; i++) {
|
||||
*s++ = str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC getpnames(dumpp)
|
||||
FILE *dumpp;
|
||||
{
|
||||
/* Read the names of the procedures from
|
||||
* the dump file.
|
||||
*/
|
||||
|
||||
char str[IDL+1];
|
||||
char *s;
|
||||
int id;
|
||||
register int i;
|
||||
|
||||
pnames = (char **) newnametab(plength,IDL);
|
||||
for (;;) {
|
||||
if (fscanf(dumpp,"%d %s",&id,str) == EOF) return;
|
||||
assert(id <= plength);
|
||||
s = pnames[id];
|
||||
for (i = 0; i < IDL; i++) {
|
||||
*s++ = str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC bool name_exists(name,endp,endd)
|
||||
char *name;
|
||||
proc_p endp;
|
||||
dblock_p endd;
|
||||
{
|
||||
/* Search the proctable (from fproc to endp)
|
||||
* and the data block table (from fdblock to endd)
|
||||
* to see if the name is already in use.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
dblock_p d;
|
||||
|
||||
for (p = fproc; p != endp; p = p->p_next) {
|
||||
if (strncmp(name,pnames[p->p_id],IDL) == 0) return TRUE;
|
||||
}
|
||||
for (d = fdblock; d != endd; d = d->d_next) {
|
||||
if (strncmp(name,dnames[d->d_id],IDL) == 0) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int nn = 0;
|
||||
|
||||
STATIC new_name(s)
|
||||
char *s;
|
||||
{
|
||||
s[0] = '_';
|
||||
s[1] = 'I';
|
||||
s[2] = 'I';
|
||||
sprintf(&s[3],"%d",nn);
|
||||
nn++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC uniq_names()
|
||||
{
|
||||
/* The names of all internal procedures and data blocks
|
||||
* are made different. As the optimizer combines several
|
||||
* modules into one, there may be name conflicts between
|
||||
* procedures or data blocks that were internal in
|
||||
* different source modules.
|
||||
*/
|
||||
|
||||
proc_p p;
|
||||
dblock_p d;
|
||||
|
||||
for (p = fproc; p != (proc_p) 0; p = p->p_next) {
|
||||
if (!(p->p_flags1 & PF_EXTERNAL) &&
|
||||
name_exists(pnames[p->p_id],p,fdblock)) {
|
||||
new_name(pnames[p->p_id]);
|
||||
}
|
||||
}
|
||||
for (d = fdblock; d != (dblock_p) 0; d = d->d_next) {
|
||||
if (!(d->d_flags1 & DF_EXTERNAL) &&
|
||||
name_exists(dnames[d->d_id],(proc_p) 0,d) ) {
|
||||
new_name(dnames[d->d_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
/* CA does not output proctable etc. files. Instead, its
|
||||
* pname2 and dname2 arguments contain the names of the
|
||||
* dump files created by IC.
|
||||
*/
|
||||
FILE *f, *f2; /* The EM input and output. */
|
||||
FILE *df, *pf; /* The dump files */
|
||||
line_p lnp;
|
||||
|
||||
fproc = getptable(pname); /* proc table */
|
||||
fdblock = getdtable(dname); /* data block table */
|
||||
dlength = makedmap(fdblock); /* allocate dmap table */
|
||||
df = openfile(dname2,"r");
|
||||
getdnames(df);
|
||||
fclose(df);
|
||||
pf = openfile(pname2,"r");
|
||||
getpnames(pf);
|
||||
fclose(pf);
|
||||
uniq_names();
|
||||
f = openfile(lname,"r");
|
||||
f2 = stdout;
|
||||
cputmagic(f2); /* write magic number */
|
||||
while ((lnp = get_ca_lines(f,&curproc)) != (line_p) 0) {
|
||||
cputlines(lnp,f2);
|
||||
}
|
||||
fclose(f);
|
||||
fclose(f2);
|
||||
exit(0);
|
||||
}
|
||||
15
util/ego/ca/ca.h
Normal file
15
util/ego/ca/ca.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* C O M P A C T A S S E M B L Y L A N G U A G E G E N E R A T I O N
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define PF_SYMOUT 01
|
||||
#define DF_SYMOUT 01
|
||||
|
||||
extern dblock_p *dmap;
|
||||
|
||||
extern char **dnames;
|
||||
extern char **pnames;
|
||||
|
||||
extern byte em_flag[];
|
||||
412
util/ego/ca/ca_put.c
Normal file
412
util/ego/ca/ca_put.c
Normal file
@@ -0,0 +1,412 @@
|
||||
#include <stdio.h>
|
||||
#include "../share/types.h"
|
||||
#include "ca.h"
|
||||
#include "../share/debug.h"
|
||||
#include "../share/def.h"
|
||||
#include "../share/map.h"
|
||||
#include "../../../h/em_spec.h"
|
||||
#include "../../../h/em_pseu.h"
|
||||
#include "../../../h/em_mnem.h"
|
||||
#include "../../../h/em_flag.h"
|
||||
#include "../../../h/em_mes.h"
|
||||
#include "../share/alloc.h"
|
||||
|
||||
#define outbyte(b) putc(b,outfile)
|
||||
|
||||
FILE *outfile;
|
||||
|
||||
STATIC proc_p thispro;
|
||||
|
||||
STATIC outinst(m) {
|
||||
|
||||
outbyte( (byte) m );
|
||||
}
|
||||
|
||||
STATIC coutshort(i) short i; {
|
||||
|
||||
outbyte( (byte) (i&BMASK) );
|
||||
outbyte( (byte) (i>>8) );
|
||||
}
|
||||
|
||||
STATIC coutint(i) short i; {
|
||||
|
||||
if (i>= -sp_zcst0 && i< sp_ncst0-sp_zcst0)
|
||||
outbyte( (byte) (i+sp_zcst0+sp_fcst0) );
|
||||
else {
|
||||
outbyte( (byte) sp_cst2) ;
|
||||
coutshort(i);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC coutoff(off) offset off; {
|
||||
|
||||
if ((short) off == off)
|
||||
coutint((short) off);
|
||||
else {
|
||||
outbyte( (byte) sp_cst4) ;
|
||||
coutshort( (short) (off&0177777L) );
|
||||
coutshort( (short) (off>>16) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outsym(s,t)
|
||||
char *s;
|
||||
int t;
|
||||
{
|
||||
register byte *p;
|
||||
register unsigned num;
|
||||
|
||||
if (s[0] == '.') {
|
||||
num = atoi(&s[1]);
|
||||
if (num < 256) {
|
||||
outbyte( (byte) sp_dlb1) ;
|
||||
outbyte( (byte) (num) );
|
||||
} else {
|
||||
outbyte( (byte) sp_dlb2) ;
|
||||
coutshort((short) num);
|
||||
}
|
||||
} else {
|
||||
p= s;
|
||||
while (*p && p < &s[IDL])
|
||||
p++;
|
||||
num = p - s;
|
||||
outbyte( (byte) t);
|
||||
coutint((short) num);
|
||||
p = s;
|
||||
while (num--)
|
||||
outbyte( (byte) *p++ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outdsym(dbl)
|
||||
dblock_p dbl;
|
||||
{
|
||||
outsym(dnames[dbl->d_id],sp_dnam);
|
||||
}
|
||||
|
||||
|
||||
STATIC outpsym(p)
|
||||
proc_p p;
|
||||
{
|
||||
outsym(pnames[p->p_id],sp_pnam);
|
||||
}
|
||||
|
||||
|
||||
STATIC outddef(id) short id; {
|
||||
|
||||
dblock_p dbl;
|
||||
|
||||
dbl = dmap[id];
|
||||
dbl->d_flags2 |= DF_SYMOUT;
|
||||
if (dbl->d_flags1 & DF_EXTERNAL) {
|
||||
outinst(ps_exa);
|
||||
outdsym(dbl);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC outpdef(p) proc_p p; {
|
||||
p->p_flags2 |= PF_SYMOUT;
|
||||
if (p->p_flags1 & PF_EXTERNAL) {
|
||||
outinst(ps_exp);
|
||||
outpsym(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outdocc(obj) obj_p obj; {
|
||||
dblock_p dbl;
|
||||
|
||||
dbl = obj->o_dblock;
|
||||
if ((dbl->d_flags2 & DF_SYMOUT) == 0) {
|
||||
dbl->d_flags2 |= DF_SYMOUT;
|
||||
if ((dbl->d_flags1 & DF_EXTERNAL) == 0) {
|
||||
outinst(ps_ina);
|
||||
outdsym(dbl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outpocc(p) proc_p p; {
|
||||
if ((p->p_flags2 & PF_SYMOUT) == 0) {
|
||||
p->p_flags2 |= PF_SYMOUT;
|
||||
if ((p->p_flags1 & PF_EXTERNAL) == 0) {
|
||||
outinst(ps_inp);
|
||||
outpsym(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC coutobject(obj)
|
||||
obj_p obj;
|
||||
{
|
||||
/* In general, an object is defined by a global data
|
||||
* label and an offset. There are two special cases:
|
||||
* the label is omitted if the object is part of the current
|
||||
* hol block; the offset is omitted if it is 0 and the label
|
||||
* was not omitted.
|
||||
*/
|
||||
if (dnames[obj->o_dblock->d_id][0] == '\0') {
|
||||
coutoff(obj->o_off);
|
||||
} else {
|
||||
if (obj->o_off == 0) {
|
||||
outdsym(obj->o_dblock);
|
||||
} else {
|
||||
outbyte((byte) sp_doff);
|
||||
outdsym(obj->o_dblock);
|
||||
coutoff(obj->o_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cputstr(abp) register argb_p abp; {
|
||||
register argb_p tbp;
|
||||
register length;
|
||||
|
||||
length = 0;
|
||||
tbp = abp;
|
||||
while (tbp!= (argb_p) 0) {
|
||||
length += tbp->ab_index;
|
||||
tbp = tbp->ab_next;
|
||||
}
|
||||
coutint(length);
|
||||
while (abp != (argb_p) 0) {
|
||||
for (length=0;length<abp->ab_index;length++)
|
||||
outbyte( (byte) abp->ab_contents[length] );
|
||||
abp = abp->ab_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outnum(n)
|
||||
int n;
|
||||
{
|
||||
if (n < 256) {
|
||||
outbyte((byte) sp_ilb1);
|
||||
outbyte((byte) n);
|
||||
} else {
|
||||
outbyte((byte) sp_ilb2);
|
||||
coutshort((short) n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC numlab(n)
|
||||
int n;
|
||||
{
|
||||
if (n < sp_nilb0) {
|
||||
outbyte((byte) (n + sp_filb0));
|
||||
} else {
|
||||
outnum(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC cputargs(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
register arg_p ap;
|
||||
int cnt = 0;
|
||||
ap = ARG(lnp);
|
||||
while (ap != (arg_p) 0) {
|
||||
switch(ap->a_type) {
|
||||
case ARGOFF:
|
||||
coutoff(ap->a_a.a_offset);
|
||||
break;
|
||||
case ARGOBJECT:
|
||||
coutobject(ap->a_a.a_obj);
|
||||
break;
|
||||
case ARGPROC:
|
||||
outpsym(ap->a_a.a_proc);
|
||||
break;
|
||||
case ARGINSTRLAB:
|
||||
outnum(ap->a_a.a_instrlab);
|
||||
break;
|
||||
case ARGSTRING:
|
||||
outbyte((byte) sp_scon);
|
||||
cputstr(&ap->a_a.a_string);
|
||||
break;
|
||||
case ARGICN:
|
||||
outbyte((byte) sp_icon);
|
||||
goto casecon;
|
||||
case ARGUCN:
|
||||
outbyte((byte) sp_ucon);
|
||||
goto casecon;
|
||||
case ARGFCN:
|
||||
outbyte((byte) sp_fcon);
|
||||
casecon:
|
||||
coutint(ap->a_a.a_con.ac_length);
|
||||
cputstr(&ap->a_a.a_con.ac_con);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
ap = ap->a_next;
|
||||
/* Avoid generating extremely long CON or ROM statements */
|
||||
if (cnt++ > 10 && ap != (arg_p) 0 &&
|
||||
(INSTR(lnp) == ps_con || INSTR(lnp) == ps_rom)) {
|
||||
cnt = 0;
|
||||
outbyte((byte) sp_cend);
|
||||
outinst(INSTR(lnp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
STATIC outoperand(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* Output the operand of instruction lnp */
|
||||
|
||||
switch(TYPE(lnp)) {
|
||||
case OPNO:
|
||||
if ((em_flag[INSTR(lnp)-sp_fmnem]&EM_PAR) != PAR_NO) {
|
||||
outbyte((byte) sp_cend);
|
||||
}
|
||||
break;
|
||||
case OPSHORT:
|
||||
if (INSTR(lnp) == ps_sym) {
|
||||
outsym(dnames[SHORT(lnp)],sp_dnam);
|
||||
} else {
|
||||
coutint(SHORT(lnp));
|
||||
}
|
||||
break;
|
||||
case OPOFFSET:
|
||||
coutoff(OFFSET(lnp));
|
||||
break;
|
||||
case OPINSTRLAB:
|
||||
if (INSTR(lnp) == op_lab) {
|
||||
numlab(INSTRLAB(lnp));
|
||||
} else {
|
||||
if (INSTR(lnp) < sp_fpseu) {
|
||||
coutint(INSTRLAB(lnp));
|
||||
} else {
|
||||
numlab(INSTRLAB(lnp));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OPOBJECT:
|
||||
coutobject(OBJ(lnp));
|
||||
break;
|
||||
case OPPROC:
|
||||
outpsym(PROC(lnp));
|
||||
break;
|
||||
case OPLIST:
|
||||
cputargs(lnp);
|
||||
switch(INSTR(lnp)) {
|
||||
case ps_con:
|
||||
case ps_rom:
|
||||
case ps_mes:
|
||||
outbyte((byte) sp_cend);
|
||||
/* list terminator */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC outvisibility(lnp)
|
||||
line_p lnp;
|
||||
{
|
||||
/* In EM names of datalabels and procedures can be made
|
||||
* externally visible, so they can be used in other files.
|
||||
* There are special EM pseudo-instructions to state
|
||||
* explicitly that a certain identifier is externally
|
||||
* visible (ps_exa,ps_exp) or invisible (ps_ina,ps_inp).
|
||||
* If there is no such pseudo for a certain identifier,
|
||||
* the identifier is external only if its first use
|
||||
* in the current file is an applied occurrence.
|
||||
* Unfortunately the global optimizer may change the
|
||||
* order of defining and applied occurrences.
|
||||
* In the first optimizer pass (ic) we record for each identifier
|
||||
* whether it is external or not. If necessary we generate
|
||||
* pseudo instructions here.
|
||||
*/
|
||||
|
||||
arg_p ap;
|
||||
short instr;
|
||||
|
||||
instr = INSTR(lnp);
|
||||
switch(TYPE(lnp)) {
|
||||
case OPOBJECT:
|
||||
outdocc(OBJ(lnp));
|
||||
/* applied occurrence of a data label */
|
||||
break;
|
||||
case OPSHORT:
|
||||
if (instr == ps_sym) {
|
||||
outddef(SHORT(lnp));
|
||||
/* defining occ. data label */
|
||||
}
|
||||
break;
|
||||
case OPPROC:
|
||||
if (instr == ps_pro) {
|
||||
outpdef(PROC(lnp));
|
||||
/* defining occ. procedure */
|
||||
} else {
|
||||
outpocc(PROC(lnp));
|
||||
}
|
||||
break;
|
||||
case OPLIST:
|
||||
for (ap = ARG(lnp); ap != (arg_p) 0; ap = ap->a_next) {
|
||||
switch(ap->a_type) {
|
||||
case ARGOBJECT:
|
||||
outdocc(ap->a_a.a_obj);
|
||||
break;
|
||||
case ARGPROC:
|
||||
outpocc(ap->a_a.a_proc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cputlines(l,lf)
|
||||
line_p l;
|
||||
FILE *lf;
|
||||
{
|
||||
/* Output the lines in Campact assembly language
|
||||
* format.
|
||||
*/
|
||||
|
||||
line_p next,lnp;
|
||||
|
||||
outfile = lf;
|
||||
for (lnp = l; lnp != (line_p) 0; lnp = next) {
|
||||
next = lnp->l_next;
|
||||
outvisibility(lnp); /* take care of visibiltity rules */
|
||||
if (INSTR(lnp) != ps_sym && INSTR(lnp) != op_lab) {
|
||||
outinst(INSTR(lnp));
|
||||
}
|
||||
outoperand(lnp);
|
||||
switch(INSTR(lnp)) {
|
||||
case ps_pro:
|
||||
thispro = PROC(lnp);
|
||||
/* fall through ... */
|
||||
case ps_end:
|
||||
coutoff(thispro->p_localbytes);
|
||||
}
|
||||
oldline(lnp);
|
||||
}
|
||||
if (thispro != (proc_p) 0) {
|
||||
oldmap(lmap,llength);
|
||||
}
|
||||
}
|
||||
|
||||
cputmagic(lf)
|
||||
FILE *lf;
|
||||
{
|
||||
/* write the magic number */
|
||||
|
||||
outfile = lf;
|
||||
coutshort(sp_magic);
|
||||
}
|
||||
9
util/ego/ca/ca_put.h
Normal file
9
util/ego/ca/ca_put.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/* C O M P A C T A S S E M B L Y G E N E R A T I O N
|
||||
*
|
||||
* C A _ P U T . C
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
extern cputlines();
|
||||
extern cputmagic();
|
||||
Reference in New Issue
Block a user