Initial revision
This commit is contained in:
parent
0de3e4a0af
commit
eb28fd80f9
9
modules/src/em_mes/C_ms_com.c
Normal file
9
modules/src/em_mes/C_ms_com.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_com(str)
|
||||
char *str;
|
||||
{
|
||||
C_mes_begin(ms_com);
|
||||
C_mes_end();
|
||||
}
|
14
modules/src/em_mes/C_ms_ego.c
Normal file
14
modules/src/em_mes/C_ms_ego.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_ego(hint, offs, siz, regno)
|
||||
int hint, regno;
|
||||
arith offs, siz;
|
||||
{
|
||||
C_mes_begin(ms_ego);
|
||||
C_cst((arith)hint);
|
||||
C_cst(offs);
|
||||
C_cst(siz);
|
||||
C_cst((arith)regno);
|
||||
C_mes_end();
|
||||
}
|
11
modules/src/em_mes/C_ms_emx.c
Normal file
11
modules/src/em_mes/C_ms_emx.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_emx(wsiz, psiz)
|
||||
arith wsiz, psiz;
|
||||
{
|
||||
C_mes_begin(ms_emx);
|
||||
C_cst(wsiz);
|
||||
C_cst(psiz);
|
||||
C_mes_end();
|
||||
}
|
8
modules/src/em_mes/C_ms_err.c
Normal file
8
modules/src/em_mes/C_ms_err.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_err()
|
||||
{
|
||||
C_mes_begin(ms_err);
|
||||
C_mes_end();
|
||||
}
|
8
modules/src/em_mes/C_ms_flt.c
Normal file
8
modules/src/em_mes/C_ms_flt.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_flt()
|
||||
{
|
||||
C_mes_begin(ms_flt);
|
||||
C_mes_end();
|
||||
}
|
8
modules/src/em_mes/C_ms_gto.c
Normal file
8
modules/src/em_mes/C_ms_gto.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_gto()
|
||||
{
|
||||
C_mes_begin(ms_gto);
|
||||
C_mes_end();
|
||||
}
|
8
modules/src/em_mes/C_ms_opt.c
Normal file
8
modules/src/em_mes/C_ms_opt.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_opt()
|
||||
{
|
||||
C_mes_begin(ms_opt);
|
||||
C_mes_end();
|
||||
}
|
10
modules/src/em_mes/C_ms_par.c
Normal file
10
modules/src/em_mes/C_ms_par.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_par(nparams)
|
||||
arith nparams;
|
||||
{
|
||||
C_mes_begin(ms_par);
|
||||
C_cst(nparams);
|
||||
C_mes_end();
|
||||
}
|
14
modules/src/em_mes/C_ms_reg.c
Normal file
14
modules/src/em_mes/C_ms_reg.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_reg(offs, siz, class, prior)
|
||||
arith offs, siz;
|
||||
int class, prior;
|
||||
{
|
||||
C_mes_begin(ms_reg);
|
||||
C_cst(offs);
|
||||
C_cst(siz);
|
||||
C_cst((arith)class);
|
||||
C_cst((arith)prior);
|
||||
C_mes_end();
|
||||
}
|
12
modules/src/em_mes/C_ms_src.c
Normal file
12
modules/src/em_mes/C_ms_src.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <em.h>
|
||||
#include <em_mes.h>
|
||||
|
||||
C_ms_src(nlines, filnam)
|
||||
int nlines;
|
||||
char *filnam;
|
||||
{
|
||||
C_mes_begin(ms_src);
|
||||
C_cst((arith)nlines);
|
||||
C_scon(filnam, strlen(filnam) + 1);
|
||||
C_mes_end();
|
||||
}
|
146
modules/src/em_mes/em_mes.3
Normal file
146
modules/src/em_mes/em_mes.3
Normal file
|
@ -0,0 +1,146 @@
|
|||
.TH EM_MES 3ACK "86/03/18"
|
||||
.SH NAME
|
||||
em_mes \- EM-message generating routines
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
.B #include <em.h>
|
||||
.PP
|
||||
.B C_ms_err()
|
||||
.PP
|
||||
.B C_ms_opt()
|
||||
.PP
|
||||
.B C_ms_emx(wsiz, psiz)
|
||||
.B arith wsiz, psiz;
|
||||
.PP
|
||||
.B #include <em_reg.h>
|
||||
.B C_ms_reg(offs, siz, class, prior)
|
||||
.B arith offs, siz;
|
||||
.B int class, prior;
|
||||
.PP
|
||||
.B C_ms_src(nlines, filnam)
|
||||
.B int nlines;
|
||||
.B char *filnam;
|
||||
.PP
|
||||
.B C_ms_flt()
|
||||
.PP
|
||||
.B C_ms_com(str)
|
||||
.B char *str;
|
||||
.PP
|
||||
.B C_ms_par(nparams)
|
||||
.B arith nparams;
|
||||
.PP
|
||||
.B #include <em_ego.h>
|
||||
.B C_ms_ego(hint, offs, siz, regno)
|
||||
.B int hint, regno;
|
||||
.B arith offs, siz;
|
||||
.PP
|
||||
.B C_ms_gto()
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
This set of routines forms a front end for the
|
||||
.IR em_code (3L)
|
||||
module.
|
||||
The philosophy behind this package is to provide a single routine for
|
||||
each type of EM message that is generated by a front-end compiler.
|
||||
Each routine internally builds a message instruction by using the
|
||||
.BR C_mes_begin ,
|
||||
.B C_mes_end
|
||||
and the
|
||||
.BI C_ cstp
|
||||
routines from the
|
||||
.I em_code
|
||||
module.
|
||||
The actions taken by these functions depend on the type of
|
||||
.I em_code
|
||||
module that is loaded together with this module.
|
||||
The routines described here do not prevent the user from directly
|
||||
composing EM messages himself.
|
||||
.PP
|
||||
.BR C_ms_err ()
|
||||
generates a message that indicates some error during the compilation.
|
||||
.PP
|
||||
.BR C_ms_opt ()
|
||||
causes any optimization to be suppressed.
|
||||
.PP
|
||||
.BR C_ms_emx ()
|
||||
indicates the wordsize
|
||||
.I wsiz
|
||||
and pointersize
|
||||
.IR psiz .
|
||||
This must be the first code generated, or the generated code is illegal.
|
||||
.PP
|
||||
.BR C_ms_reg ()
|
||||
can be used to indicate that a local variable, having offset
|
||||
.I offs
|
||||
and size (in bytes)
|
||||
.IR siz ,
|
||||
may be stored in a register.
|
||||
.I Class
|
||||
indicates the use of the variable.
|
||||
The following classes are allowed (the names are defined in em_reg.h):
|
||||
.RS
|
||||
.IP reg_any 12
|
||||
no specific type
|
||||
.IP reg_loop 12
|
||||
loop control variable
|
||||
.IP reg_pointer 12
|
||||
pointer variable
|
||||
.IP reg_float 12
|
||||
floating point variable
|
||||
.LP
|
||||
.RE
|
||||
.I Prior
|
||||
is taken to be the priority of the variable; higher numbers indicate
|
||||
better candidates.
|
||||
.PP
|
||||
.BR C_ms_src ()
|
||||
produces an indication of the number of source lines,
|
||||
.IR nlines ,
|
||||
in file
|
||||
.IR filnam .
|
||||
This information can be used by a profiler.
|
||||
.PP
|
||||
.BR C_ms_flt ()
|
||||
produces an indication that floating-point operations are used.
|
||||
.PP
|
||||
.BR C_ms_com ()
|
||||
causes the string
|
||||
.I str
|
||||
to be inserted as comment in the resulting output.
|
||||
Note that this routine does not provide the full semantics of EM in this
|
||||
area, but the user himself can build a comment message with other types
|
||||
of comment if he likes.
|
||||
.PP
|
||||
.BR C_ms_par ()
|
||||
produces an indication that no more than
|
||||
.I nbytes
|
||||
of parameters are accessed, either directly or indirectly.
|
||||
.PP
|
||||
.BR C_ms_ego ()
|
||||
produces a hint from the EM global optimizer.
|
||||
The parameters needed are conform to the format of the message.
|
||||
.PP
|
||||
.BR C_ms_gto ()
|
||||
can be invoked to indicate that a procedure uses a non-local goto.
|
||||
.SH FILES
|
||||
.nf
|
||||
~em/modules/h/em.h
|
||||
~em/h/em_reg.h
|
||||
~em/h/em_ego.h
|
||||
~em/modules/lib/libem_mes.a
|
||||
.fi
|
||||
.SH MODULES
|
||||
em_code(3)
|
||||
.SH SEE ALSO
|
||||
em_code(3), read_em(3)
|
||||
.SH DIAGNOSTICS
|
||||
None of the functions return a value.
|
||||
.SH BUGS
|
||||
The
|
||||
.BR C_ms_ext ()
|
||||
routine has not yet been implemented, since this message uses
|
||||
a variable number of arguments.
|
||||
.PP
|
||||
Please report other bugs to the author.
|
||||
.SH AUTHOR
|
||||
Erik Baalbergen <erikb@vu44.UUCP>
|
17
modules/src/idf/Makefile
Normal file
17
modules/src/idf/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
|||
EMHOME = ../../..
|
||||
INSTALL = $(EMHOME)/modules/install
|
||||
COMPARE = $(EMHOME)/modules/compare
|
||||
|
||||
all:
|
||||
|
||||
install: all
|
||||
$(INSTALL) pkg/idf_pkg.body
|
||||
$(INSTALL) pkg/idf_pkg.spec
|
||||
$(INSTALL) man/idf.3
|
||||
|
||||
cmp: all
|
||||
$(COMPARE) pkg/idf_pkg.body
|
||||
$(COMPARE) pkg/idf_pkg.spec
|
||||
$(COMPARE) man/idf.3
|
||||
|
||||
clean:
|
88
modules/src/idf/idf.3
Normal file
88
modules/src/idf/idf.3
Normal file
|
@ -0,0 +1,88 @@
|
|||
.TH IDF 3ACK "March 17, 1986"
|
||||
.UC
|
||||
.SH NAME
|
||||
init_idf, str2idf\ \-\ a namelist module
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
.B init_idf()
|
||||
.PP
|
||||
.B struct idf *str2idf(tag, cpy)
|
||||
.br
|
||||
.B char *tag;
|
||||
.PP
|
||||
.B struct idf *findidf(tag)
|
||||
.br
|
||||
.B char *tag;
|
||||
.SH DESCRIPTION
|
||||
This is a generic namelist module. It provides a fast mechanism for
|
||||
associating information with identifiers. To get an instantiation, the
|
||||
user must provide two files \fIidf.h\fR and \fIidf.c\fR.
|
||||
\fIidf.h\fR could contain the following:
|
||||
.br
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
#define IDF_TYPE struct id_info
|
||||
#define IDF_HSIZE 8
|
||||
|
||||
#include <idf_pkg.spec>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
and \fIidf.c\fR could contain:
|
||||
.br
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
#include "id_info.h" /* contains definition for struct id_info */
|
||||
#include "idf.h"
|
||||
#include <idf_pkg.body>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
IDF_TYPE denotes a type containing all information associated with
|
||||
an identifier. If it is not defined, the instantiation will not contain
|
||||
any user-defined information.
|
||||
.PP
|
||||
IDF_HSIZE denotes the number of significant characters for the hashing
|
||||
function. It's default value is 64. Notice that this value does \fBnot\fP
|
||||
denote the number of significant characters, but only the number of characters
|
||||
that are used for hashing.
|
||||
.PP
|
||||
The user can also define IDF_NAME, to give a name to the selector in the
|
||||
idf-structure. It's default value is \fIid_user\fP.
|
||||
.PP
|
||||
The routine \fIinit_idf\fR initializes the namelist.
|
||||
.PP
|
||||
The function
|
||||
\fIstr2idf\fR searches for the string \fItag\fR in the namelist, and
|
||||
creates an entry for it if necessary. A pointer to this entry is
|
||||
returned. If \fIcpy\fR is non-zero, a copy of the \fItag\fR is made,
|
||||
otherwise the \fItag\fR itself is used.
|
||||
The entry has the following structure, defined in \fIinp_pkg.spec\fR:
|
||||
.PP
|
||||
.nf
|
||||
struct idf {
|
||||
struct idf *next; \kx/* links idf-structures together */
|
||||
char *id_text;\h'|\nxu'/* string representing the name */
|
||||
#ifdef IDF_TYPE
|
||||
IDF_TYPE IDF_NAME;\h'|\nxu'/* user defined type */
|
||||
#endif
|
||||
};
|
||||
.fi
|
||||
.PP
|
||||
The field \fIid_text\fR will point to a copy of \fItag\fR, or
|
||||
to the \fItag\fR itself, depending on \fIcpy\fR.
|
||||
The field \fInext\fR is used for internal information and must not
|
||||
be changed by the user of this module.
|
||||
.PP
|
||||
The function \fIfindidf\fP searches for the string \fItag\fP in the
|
||||
namelist, but returns 0 when it is'nt present.
|
||||
.SH "MODULES USED"
|
||||
alloc(3)
|
||||
.SH FILES
|
||||
~em/modules/pkg/idf_pkg.spec
|
||||
.br
|
||||
~em/modules/pkg/idf_pkg.body
|
||||
.SH DIAGNOSTICS
|
||||
\fIstr2idf\fP returns a null pointer if there is no memory available.
|
159
modules/src/idf/idf_pkg.body
Normal file
159
modules/src/idf/idf_pkg.body
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* SYMBOL TABLE HANDLING */
|
||||
|
||||
#include <alloc.h>
|
||||
|
||||
/* Each character of the identifier is xored with an 8-bit mask which
|
||||
depends on the position of the character; the sum of these results
|
||||
is the hash value. The random masks are obtained from a
|
||||
congruence generator.
|
||||
*/
|
||||
|
||||
#define HASHSIZE 256 /* size of hashtable, must be a power of 2 */
|
||||
#ifndef IDF_HSIZE
|
||||
#define IDF_HSIZE 64 /* # of significant characters for hashing.
|
||||
This is NOT the number of significant
|
||||
characters!
|
||||
*/
|
||||
#endif
|
||||
#define HASH_X 0253 /* Knuth's X */
|
||||
#define HASH_A 77 /* Knuth's a */
|
||||
#define HASH_C 153 /* Knuth's c */
|
||||
|
||||
#define HASHMASK (HASHSIZE-1) /* since it is a power of 2 */
|
||||
#define STARTHASH() (0)
|
||||
#define ENHASH(hs,ch,hm) (hs + (ch ^ hm))
|
||||
#define STOPHASH(hs) (hs & HASHMASK)
|
||||
|
||||
static char hmask[IDF_HSIZE];
|
||||
|
||||
static struct idf *id_hashtable[HASHSIZE];
|
||||
/* All identifiers can in principle be reached through
|
||||
id_hashtable; id_hashtable[hc] is the start of a chain of
|
||||
idf's whose tags all hash to hc.
|
||||
Any identifier is entered into this
|
||||
list, regardless of the nature of its declaration
|
||||
(variable, selector, structure tag, etc.).
|
||||
*/
|
||||
|
||||
static struct idf *
|
||||
new_idf(tg, size, cpy)
|
||||
register char *tg;
|
||||
register int size;
|
||||
{
|
||||
static int nidf;
|
||||
static struct idf *pidf;
|
||||
#define NIDS 50
|
||||
#define IBUFSIZ 2048
|
||||
static unsigned int icnt;
|
||||
static char *ip;
|
||||
register char *p;
|
||||
|
||||
|
||||
if (! nidf--) {
|
||||
nidf += NIDS;
|
||||
pidf = (struct idf *) Malloc(NIDS * sizeof (struct idf));
|
||||
clear((char *) pidf, NIDS * sizeof(struct idf));
|
||||
}
|
||||
|
||||
if (cpy) {
|
||||
if (size > icnt) {
|
||||
icnt = size > IBUFSIZ ? size : IBUFSIZ;
|
||||
p = Malloc(icnt);
|
||||
}
|
||||
else p = ip;
|
||||
icnt -= size;
|
||||
pidf->id_text = p;
|
||||
while (size--) {
|
||||
*p++ = *tg++;
|
||||
}
|
||||
ip = p;
|
||||
}
|
||||
else pidf->id_text = tg;
|
||||
return pidf++;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
hash_stat()
|
||||
{
|
||||
register int i;
|
||||
|
||||
print("Hash table tally:\n");
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
register struct idf *notch = id_hashtable[i];
|
||||
register int cnt = 0;
|
||||
|
||||
while (notch) {
|
||||
cnt++;
|
||||
notch = notch->next;
|
||||
}
|
||||
print("%d %d\n", i, cnt);
|
||||
}
|
||||
print("End hash table tally\n");
|
||||
}
|
||||
#endif DEBUG
|
||||
|
||||
struct idf *
|
||||
str2idf(tg, cpy)
|
||||
char tg[];
|
||||
{
|
||||
/* str2idf() returns an entry in the symbol table for the
|
||||
identifier tg. If necessary, an entry is created.
|
||||
*/
|
||||
register char *cp = tg;
|
||||
register char *phm = &hmask[0];
|
||||
struct idf **hook;
|
||||
register struct idf *notch;
|
||||
register int hash;
|
||||
int size;
|
||||
|
||||
hash = STARTHASH();
|
||||
while (*cp && phm < &hmask[IDF_HSIZE]) {
|
||||
hash = ENHASH(hash, *cp++, *phm++);
|
||||
}
|
||||
hash = STOPHASH(hash);
|
||||
while (*cp++) /* nothing. Find end of string */ ;
|
||||
size = cp - tg;
|
||||
|
||||
/* The tag tg with length size and known hash value hash is
|
||||
looked up in the identifier table; if not found, it is
|
||||
entered if cpy >= 0. A pointer to it is returned.
|
||||
Notice that the chains of idf's are sorted alphabetically.
|
||||
*/
|
||||
hook = &id_hashtable[hash];
|
||||
|
||||
while ((notch = *hook)) {
|
||||
register char *s1 = tg;
|
||||
int cmp;
|
||||
|
||||
cp = notch->id_text;
|
||||
|
||||
while (!(cmp = (*s1 - *cp++))) {
|
||||
if (*s1++ == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp == 0) return notch;
|
||||
if (cmp < 0) break;
|
||||
hook = ¬ch->next;
|
||||
}
|
||||
/* a new struct idf must be inserted at the hook */
|
||||
if (cpy < 0) return 0;
|
||||
notch = new_idf(tg, size, cpy);
|
||||
notch->next = *hook;
|
||||
*hook = notch; /* hooked in */
|
||||
return notch;
|
||||
}
|
||||
|
||||
init_idf() {
|
||||
/* A simple congruence random number generator, as
|
||||
described in Knuth, vol 2.
|
||||
*/
|
||||
int rnd = HASH_X;
|
||||
register char *phm;
|
||||
|
||||
for (phm = &hmask[0]; phm < &hmask[IDF_HSIZE];) {
|
||||
*phm++ = rnd;
|
||||
rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
|
||||
}
|
||||
}
|
42
modules/src/idf/idf_pkg.spec
Normal file
42
modules/src/idf/idf_pkg.spec
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* $Header$ */
|
||||
/* IDENTIFIER DESCRIPTOR */
|
||||
|
||||
/* This a generic package for maintaining a name list */
|
||||
|
||||
/* Instantiation parameters, supplied by #define, are :
|
||||
IDF_TYPE: the type of the user-defined part of the idf-structure,
|
||||
IDF_NAME: the selector name for this field in the idf_structure, and
|
||||
IDF_HSIZE: the number of significant characters for hashing
|
||||
*/
|
||||
|
||||
#ifndef IDF_NAME
|
||||
#define IDF_NAME id_user
|
||||
#endif
|
||||
|
||||
struct idf {
|
||||
struct idf *next; /* links idf-structures together */
|
||||
char *id_text; /* string representing the name */
|
||||
#ifdef IDF_TYPE
|
||||
IDF_TYPE IDF_NAME; /* user defined type and selector */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* init_idf()
|
||||
|
||||
Initializes the namelist
|
||||
*/
|
||||
extern init_idf();
|
||||
|
||||
/* struct idf * str2idf(tg, cp)
|
||||
char *tg;
|
||||
int cp;
|
||||
|
||||
Adds the string indicated by "tg" to the namelist, and returns a
|
||||
pointer to the entry.
|
||||
If cp > 0, a copy of tg is made for id_text, otherwise tg itself
|
||||
is used.
|
||||
If cp < 0, the string is not entered, but only looked for.
|
||||
*/
|
||||
extern struct idf * str2idf();
|
||||
|
||||
#define findidf(tg) str2idf(tg, -1)
|
10
modules/src/input/AtEoIF.c
Normal file
10
modules/src/input/AtEoIF.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* AtEoIF : a routine doing nothing. It is called at the end of an
|
||||
inserted file.
|
||||
*/
|
||||
int
|
||||
AtEoIF()
|
||||
{
|
||||
return 0;
|
||||
}
|
10
modules/src/input/AtEoIT.c
Normal file
10
modules/src/input/AtEoIT.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* AtEoIT : a routine doing nothing. It is called at the end of an
|
||||
inserted text.
|
||||
*/
|
||||
int
|
||||
AtEoIT()
|
||||
{
|
||||
return 0;
|
||||
}
|
413
modules/src/input/inp_pkg.body
Normal file
413
modules/src/input/inp_pkg.body
Normal file
|
@ -0,0 +1,413 @@
|
|||
/* INPUT AND BUFFER HANDLING MODULE */
|
||||
|
||||
/*
|
||||
[input.X inp_pkg.spec input.h]
|
||||
Input buffering module: this module contains the routines that
|
||||
offers an input buffering mechanism to the user.
|
||||
|
||||
This module exports the following objects:
|
||||
input.h : an include-file, which must be included when using
|
||||
this module
|
||||
InsertFile() : suspend input from current buffer and obtain the
|
||||
next input characters from the specified file
|
||||
InsertText() : suspend input from current buffer and take the
|
||||
specified text as stream of input characters
|
||||
LoadChar() : (defined in input.h) read next character from
|
||||
the input ; LoadChar() invokes loadbuf() on
|
||||
encounting a ASCII NUL character
|
||||
PushBack() : (defined in input.h) push last character back onto
|
||||
the input stream; NPUSHBACK characters of pushback
|
||||
are guaranteed, provided that they have all been read
|
||||
from the current input stream
|
||||
AtEoIT() : this routine is called at the end of an inserted text.
|
||||
A default one is provided, which does nothing.
|
||||
AtEoIF() : this routine is called at the end of an inserted file.
|
||||
A default one is provided, which does nothing.
|
||||
|
||||
Imported objects are:
|
||||
INP_NPUSHBACK, INP_READ_IN_ONE, INP_TYPE, INP_VAR,
|
||||
routines from the "alloc" package, routines from the "storage"
|
||||
package, and routines from the "system" package.
|
||||
|
||||
INP_READ_IN_ONE defined: every input file is read into memory completely
|
||||
and made an input buffer. Only use it if the size of a file
|
||||
fits always fits in an integer and you have lots of memory.
|
||||
INP_READ_IN_ONE not defined: the input from files is buffered in
|
||||
a fixed length input buffer
|
||||
INP_NPUSHBACK: the number of characters pushback
|
||||
*/
|
||||
|
||||
#include <alloc.h>
|
||||
#include <system.h>
|
||||
|
||||
#ifndef INP_NPUSHBACK
|
||||
#define INP_NPUSHBACK 1
|
||||
#endif
|
||||
|
||||
#if INP_NPUSHBACK < 1
|
||||
#define INP_NPUSHBACK 1
|
||||
#endif
|
||||
|
||||
#ifndef INP_BUFSIZE
|
||||
#define INP_BUFSIZE BUFSIZ
|
||||
#endif
|
||||
|
||||
#if INP_NPUSHBACK > INP_BUFSIZE/2
|
||||
Now this is really ridiculous! You deserve what you get!!
|
||||
#endif
|
||||
|
||||
#ifdef INP_TYPE
|
||||
extern INP_TYPE INP_VAR;
|
||||
#endif INP_TYPE
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRIVATE
|
||||
#else
|
||||
#define PRIVATE static
|
||||
#endif
|
||||
|
||||
struct buffer_header {
|
||||
struct buffer_header *next;
|
||||
int bh_size; /* = strlen (text), should be unsigned */
|
||||
char *bh_text; /* pointer to buffer containing text */
|
||||
char *bh_ipp; /* current read pointer (= stacked ipp) */
|
||||
#ifdef INP_TYPE
|
||||
INP_TYPE bh_i; /* user defined */
|
||||
#endif INP_TYPE
|
||||
File *bh_fd; /* A file descriptor in case of a file */
|
||||
char bh_eofreturned; /* set if we returned eof for this buffer */
|
||||
};
|
||||
|
||||
#ifndef INP_READ_IN_ONE
|
||||
struct i_buf {
|
||||
struct i_buf *next;
|
||||
char ib_text[INP_BUFSIZE+INP_NPUSHBACK-1];
|
||||
};
|
||||
|
||||
# endif not INP_READ_IN_ONE
|
||||
|
||||
char *_ipp;
|
||||
PRIVATE struct buffer_header *head;
|
||||
|
||||
#ifdef INP_READ_IN_ONE
|
||||
/* readfile() creates a buffer in which the text of the file
|
||||
is situated. A pointer to the start of this text is
|
||||
returned. *size is initialized with the buffer length.
|
||||
*/
|
||||
|
||||
PRIVATE int
|
||||
readfile(fd, fn, size, pbuf)
|
||||
register File *fd;
|
||||
char *fn; /* file name */
|
||||
register long *size;
|
||||
extern long sys_filesize();
|
||||
char **pbuf; /* output parameter */
|
||||
{
|
||||
int rsize;
|
||||
|
||||
if (
|
||||
(*size = sys_filesize(fn)) < 0
|
||||
||
|
||||
((unsigned) (*size + 1) != (*size + 1))
|
||||
||
|
||||
!(*pbuf = malloc((unsigned) (*size + 1)))) {
|
||||
sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (
|
||||
!sys_read(fd, *pbuf, (int) *size, &rsize)
|
||||
||
|
||||
*size != rsize
|
||||
) {
|
||||
sys_close(fd);
|
||||
free(*pbuf);
|
||||
return 0;
|
||||
}
|
||||
sys_close(fd);
|
||||
(*pbuf)[*size] = '\0'; /* invoke loadbuf() at end */
|
||||
return 1;
|
||||
}
|
||||
#endif INP_READ_IN_ONE
|
||||
|
||||
#ifndef INP_READ_IN_ONE
|
||||
/* Input buffer supplying routines: pushbuf()
|
||||
*/
|
||||
|
||||
PRIVATE struct i_buf *i_ptr;
|
||||
|
||||
PRIVATE char *
|
||||
pushbuf()
|
||||
{
|
||||
register struct i_buf *ib =
|
||||
(struct i_buf *) malloc(sizeof(struct i_buf));
|
||||
|
||||
if (!ib) return 0;
|
||||
ib->next = i_ptr;
|
||||
i_ptr = ib;
|
||||
|
||||
/* Don't give him all of it, we need some to implement a good
|
||||
PushBack
|
||||
*/
|
||||
return &(ib->ib_text[INP_NPUSHBACK-1]);
|
||||
}
|
||||
#endif not INP_READ_IN_ONE
|
||||
|
||||
/* Input buffer administration: push_bh() and pop_bh()
|
||||
*/
|
||||
PRIVATE struct buffer_header *
|
||||
push_bh()
|
||||
{
|
||||
register struct buffer_header *bh;
|
||||
|
||||
if (bh = head) {
|
||||
bh->bh_ipp = _ipp;
|
||||
#ifdef INP_TYPE
|
||||
bh->bh_i = INP_VAR;
|
||||
#endif INP_TYPE
|
||||
}
|
||||
if (!(bh = (struct buffer_header *)malloc(sizeof(struct buffer_header)))) return 0;
|
||||
bh->next = head;
|
||||
bh->bh_eofreturned = 0;
|
||||
head = bh;
|
||||
return bh;
|
||||
}
|
||||
|
||||
/* pop_bh() uncovers the previous inputbuffer on the stack
|
||||
of headers. 0 is returned if there are no more
|
||||
inputbuffers on the stack, 1 is returned in the other case.
|
||||
*/
|
||||
PRIVATE int
|
||||
pop_bh()
|
||||
{
|
||||
register struct buffer_header *bh = head;
|
||||
|
||||
if (bh->bh_fd) { /* unstack a file */
|
||||
#ifndef INP_READ_IN_ONE
|
||||
struct i_buf *ib;
|
||||
|
||||
ib = i_ptr->next;
|
||||
free((char *) i_ptr);
|
||||
i_ptr = ib;
|
||||
#else INP_READ_IN_ONE
|
||||
free(bh->bh_text);
|
||||
#endif INP_READ_IN_ONE
|
||||
}
|
||||
|
||||
bh = bh->next;
|
||||
free((char *) head);
|
||||
head = bh;
|
||||
|
||||
if (!bh) { /* no more entries */
|
||||
head = (struct buffer_header *) 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ipp = bh->bh_ipp; /* restore previous input pointer */
|
||||
#ifdef INP_TYPE
|
||||
INP_VAR = bh->bh_i;
|
||||
#endif INP_TYPE
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef INP_READ_IN_ONE
|
||||
/* low level I/O routine : read one block from current input
|
||||
stream : readblock
|
||||
*/
|
||||
|
||||
PRIVATE int
|
||||
readblock(fd, buf, n)
|
||||
File *fd;
|
||||
char buf[];
|
||||
int *n;
|
||||
{
|
||||
|
||||
if (!sys_read(fd, buf, INP_BUFSIZE, n)) {
|
||||
return 0;
|
||||
}
|
||||
buf[*n] = '\0';
|
||||
return 1;
|
||||
}
|
||||
#endif not INP_READ_IN_ONE
|
||||
|
||||
/* Miscellaneous routines :
|
||||
mk_filename()
|
||||
*/
|
||||
|
||||
/* mk_filename() concatenates a dir and filename.
|
||||
*/
|
||||
PRIVATE int
|
||||
mk_filename(dir, file, newname)
|
||||
register char *dir, *file;
|
||||
char **newname;
|
||||
{
|
||||
|
||||
register char *dst;
|
||||
|
||||
dst = malloc((unsigned) (strlen(dir) + strlen(file) + 2));
|
||||
if (!dst) return 0;
|
||||
*newname = dst;
|
||||
while (*dst++ = *dir++);
|
||||
*--dst = '/';
|
||||
while (*++dst = *file++);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Interface routines : InsertFile, InsertText, and loadbuf
|
||||
*/
|
||||
|
||||
int
|
||||
InsertFile(filnam, table, result)
|
||||
char *filnam;
|
||||
char *table[];
|
||||
char **result;
|
||||
{
|
||||
char *newfn = 0;
|
||||
|
||||
#ifdef INP_READ_IN_ONE
|
||||
char *text;
|
||||
long size;
|
||||
#endif INP_READ_IN_ONE
|
||||
File *fd = 0;
|
||||
|
||||
if (!filnam) fd = STDIN;
|
||||
else {
|
||||
if (table == 0 || filnam[0] == '/') {
|
||||
/* don't look in the table! */
|
||||
if (!sys_open(filnam, OP_READ, &fd)) return 0;
|
||||
}
|
||||
else {
|
||||
while (*table) {
|
||||
/* look in the directory table */
|
||||
if (!mk_filename(*table++, filnam, &newfn)) {
|
||||
return 0;
|
||||
}
|
||||
if (sys_open(newfn, OP_READ, &fd)) {
|
||||
/* free filnam ??? NO we don't know
|
||||
where it comes from!
|
||||
*/
|
||||
filnam = newfn;
|
||||
break;
|
||||
}
|
||||
free(newfn);
|
||||
newfn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd) {
|
||||
struct buffer_header *push_bh();
|
||||
register struct buffer_header *bh = push_bh();
|
||||
|
||||
if (!bh) {
|
||||
if (fd != STDIN) sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
#ifdef INP_READ_IN_ONE
|
||||
if (fd == STDIN) return 0; /* illegal */
|
||||
if (!readfile(fd, filnam, &size, &text)) {
|
||||
sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
bh->bh_size = size;
|
||||
_ipp = bh->bh_text = text;
|
||||
#else not INP_READ_IN_ONE
|
||||
if (
|
||||
!(_ipp = bh->bh_text = pushbuf())
|
||||
||
|
||||
!readblock(fd,_ipp,&(bh->bh_size))) {
|
||||
if (fd != STDIN) sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif INP_READ_IN_ONE
|
||||
bh->bh_fd = fd; /* this is a file */
|
||||
*result = filnam;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
InsertText(text, length)
|
||||
char *text;
|
||||
{
|
||||
struct buffer_header *push_bh();
|
||||
register struct buffer_header *bh = push_bh();
|
||||
|
||||
if (!bh) return 0;
|
||||
bh->bh_size = (long) length;
|
||||
_ipp = bh->bh_text = text;
|
||||
bh->bh_fd = 0; /* No file! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* loadbuf() is called if LoadChar meets a '\0' character
|
||||
which may be the end-of-buffer mark of the current input
|
||||
buffer. The '\0' could be genuine although not likely.
|
||||
Note: this routine is exported due to its occurence in the definition
|
||||
of LoadChar [input.h], that is defined as a macro.
|
||||
*/
|
||||
int
|
||||
loadbuf()
|
||||
{
|
||||
register struct buffer_header *bh = head;
|
||||
static char buf[INP_NPUSHBACK + 1];
|
||||
int FromFile;
|
||||
|
||||
if (!bh) { /* stack exhausted, EOF on sourcefile */
|
||||
return EOI;
|
||||
}
|
||||
|
||||
if (_ipp < &(bh->bh_text[bh->bh_size])) {
|
||||
/* a genuine '\0' character has been seen */
|
||||
return '\0';
|
||||
}
|
||||
|
||||
FromFile = (bh->bh_fd != 0);
|
||||
|
||||
#ifndef INP_READ_IN_ONE
|
||||
if (FromFile) {
|
||||
#if INP_PUSHBACK > 1
|
||||
register char *so = &(bh->bh_text[bh->bh_size]);
|
||||
register char *de = bh->bh_text;
|
||||
register int i = INP_NPUSHBACK - 1;
|
||||
|
||||
while (i-- > 0) {
|
||||
/* make sure PushBack will work */
|
||||
*--de = *--so;
|
||||
}
|
||||
#endif
|
||||
if (
|
||||
readblock(bh->bh_fd, bh->bh_text, &(bh->bh_size))
|
||||
&&
|
||||
bh->bh_size > 0
|
||||
) {
|
||||
_ipp = bh->bh_text;
|
||||
return *_ipp++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif not INP_READ_IN_ONE
|
||||
|
||||
if (!bh->bh_eofreturned) {
|
||||
bh->bh_eofreturned = 1;
|
||||
_ipp--;
|
||||
if (FromFile) {
|
||||
if (AtEoIF()) return EOI;
|
||||
}
|
||||
else {
|
||||
if (AtEoIT()) return EOI;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef INP_READ_IN_ONE
|
||||
if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
|
||||
#endif not INP_READ_IN_ONE
|
||||
|
||||
if (pop_bh()) {
|
||||
if (*_ipp) return *_ipp++;
|
||||
return loadbuf();
|
||||
}
|
||||
_ipp = &buf[INP_NPUSHBACK];
|
||||
return EOI;
|
||||
}
|
53
modules/src/input/inp_pkg.spec
Normal file
53
modules/src/input/inp_pkg.spec
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* This is the specification of the generic part of the input package.
|
||||
It can be instantiated by #defining or not #defining
|
||||
INP_TYPE, INP_VAR, INP_READ_IN_ONE, and INP_NPUSHBACK.
|
||||
INP_TYPE is the type of the variable INP_VAR, which contains
|
||||
all values the user wants to save when an InsertFile is done,
|
||||
and restored when an input stream is continued after a suspend.
|
||||
For instance, line numbers and position within a line might
|
||||
be interesting.
|
||||
Not defining INP_TYPE has the effect that the instantiation is
|
||||
done without saving and restoring INP_VAR.
|
||||
Defining INP_READ_IN_ONE has the effect that files will be read
|
||||
completely with one "read". Only use this if you have lots of
|
||||
memory. Not defining it causes files to be read in blocks, with
|
||||
a suitable blocksize.
|
||||
INP_NPUSHBACK is the number of PushBacks that are guaranteed
|
||||
to work. Its default value is 1.
|
||||
*/
|
||||
|
||||
/* INPUT PRIMITIVES */
|
||||
|
||||
#define LoadChar(dest) ((dest = *_ipp++) || (dest = loadbuf()))
|
||||
#define PushBack() (--_ipp)
|
||||
|
||||
/* EOF may be defined as -1 in most programs but the character -1 may
|
||||
be expanded to the int -1 which causes troubles at the indexing in
|
||||
the class or boolean arrays.
|
||||
*/
|
||||
#define EOI (0200)
|
||||
|
||||
extern char *_ipp;
|
||||
|
||||
/* int InsertFile(filename, table, result)
|
||||
char *filename;
|
||||
char **table;
|
||||
char **result;
|
||||
|
||||
This function suspends input from the current input stream. The next
|
||||
characters are obtained from the file indicated by "filename". This file
|
||||
will be looked for in the directories, mentioned in the null-terminated
|
||||
list indicated by "table". It returns 1 if it succeeds, 0 if it fails.
|
||||
"result" will contain the full path if InsertFile returns 1.
|
||||
*/
|
||||
extern int InsertFile();
|
||||
|
||||
/* int InsertText(text, length)
|
||||
char *text;
|
||||
int length;
|
||||
This funtion suspends input from the current input stream. The next
|
||||
input characters are obtained from the string indicated by "text",
|
||||
whose length is indicated by "length".
|
||||
It returns 1 if it succeeds, 0 if it fails.
|
||||
*/
|
||||
extern int InsertText();
|
140
modules/src/input/input.3
Normal file
140
modules/src/input/input.3
Normal file
|
@ -0,0 +1,140 @@
|
|||
.TH INPUT 3 "March 25, 1986"
|
||||
.SH NAME
|
||||
LoadChar, PushBack, InsertFile, InsertText, AtEoIF, AtEoIT\ \-\ input
|
||||
module for compilers
|
||||
.SH SYNOPSIS
|
||||
.B LoadChar(ch)
|
||||
.br
|
||||
.B int ch;
|
||||
.PP
|
||||
.B PushBack()
|
||||
.PP
|
||||
.B int InsertFile(filename, table, result)
|
||||
.br
|
||||
.B char *filename;
|
||||
.br
|
||||
.B char *table[];
|
||||
.br
|
||||
.B char **result;
|
||||
.PP
|
||||
.B int InsertText(text, length)
|
||||
.br
|
||||
.B char *text;
|
||||
.br
|
||||
.B int length;
|
||||
.PP
|
||||
.B int AtEoIF()
|
||||
.PP
|
||||
.B int AtEoIT()
|
||||
.SH DESCRIPTION
|
||||
This set of variables, macros and routines provides a fast input mechanism
|
||||
for use by compilers.
|
||||
They also provide a means of inserting new input streams,
|
||||
thereby temporarily suspending an input
|
||||
stream to read another one.
|
||||
The \fBcurrent input stream\fR is the last inserted input stream that
|
||||
has not reached its end.
|
||||
.PP
|
||||
The module is generic: it must be instantiated by #defining INP_TYPE,
|
||||
INP_VAR, INP_READ_IN_ONE, INP_BUFSIZE, and INP_NPUSHBACK.
|
||||
An instantiation can be obtained by creating two files: \fIinput.c\fR and
|
||||
\fIinput.h\fR.
|
||||
\fIinput.h\fR could contain the following:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
#define INP_NPUSHBACK 2
|
||||
#define INP_TYPE struct f_info
|
||||
#define INP_VAR file_info
|
||||
#define INP_BUFSIZE 4096
|
||||
|
||||
#include <inp_pkg.spec>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
and \fIinput.c\fR could contain:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
#include "f_info.h" /* contains definition for struct f_info */
|
||||
#include "input.h"
|
||||
#include <inp_pkg.body>
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
The user may associate certain data with each input stream. The input module
|
||||
has a facility to save these data when inserting a new input stream, and
|
||||
restoring them when restoring the suspended input stream. Examples of these
|
||||
data are for instance a linenumber, a filename, etc.
|
||||
These data must be collected in a variable INP_VAR of type INP_TYPE.
|
||||
INP_VAR and INP_TYPE must be preprocessor-#defined.
|
||||
Not #defining INP_TYPE has the effect that an instantiation will be created
|
||||
that does not save and restore these data.
|
||||
.PP
|
||||
INP_NPUSHBACK is the number of PushBacks that are guaranteed to work.
|
||||
Its default value is 1. It is expected to be small.
|
||||
.PP
|
||||
INP_READ_IN_ONE can either be defined or not defined. Defining it has the
|
||||
effect that files will be read completely with one read-system call. This
|
||||
should only be used on machines with lots of memory.
|
||||
.PP
|
||||
INP_BUFSIZE defines the input buffer size that is used when INP_READ_IN_ONE
|
||||
is not defined. Its default value is BUFSIZ, from the \fIsystem\fP(3) module.
|
||||
.PP
|
||||
The macro \fILoadChar\fR stores the next character from the current input stream
|
||||
in the variable \fIch\fR,
|
||||
which is passed as a parameter.
|
||||
Note that this simulates an output parameter!
|
||||
When the end of the current input stream is reached, the next character from
|
||||
the last suspended input stream will be stored, etc.
|
||||
If there are no suspended input streams left, the constant EOI,
|
||||
which is defined in \fIinp_pkg.spec\fR, is returned.
|
||||
.PP
|
||||
The macro \fIPushBack\fR pushes the last character read back onto the
|
||||
input stream.
|
||||
.PP
|
||||
The routine \fIInsertFile\fR suspends input from the current input stream.
|
||||
The next input characters will be obtained from the specified file
|
||||
\fIfilename\fR.
|
||||
This file will be looked for in the directories, mentioned in the
|
||||
null-terminated list \fItable\fR.
|
||||
If \fIfilename\fR is a null pointer, standard input is used. In this case,
|
||||
the package may not have been instantiated with INP_READ_IN_ONE defined.
|
||||
\fIInsertFile\fR returns 1 if it succeeds, 0 if it fails.
|
||||
When it succeeds, it stores the file name in the \fIresult\fR parameter.
|
||||
.PP
|
||||
The routine \fIInsertText\fR also suspends input from the current input stream.
|
||||
The next input characters will be obtained from the string \fItext\fR,
|
||||
which is \fIlength\fR characters long.
|
||||
\fIInsertText\fR returns 1 if it succeeds, 0 if it fails.
|
||||
.PP
|
||||
The routine \fIAtEoIF\fR is called at the end of the input stream
|
||||
inserted by \fIInsertFile\fR.
|
||||
If it returns 1, the LoadChar causing the call returns EOI, otherwize
|
||||
the LoadChar returns the next character of the suspended and now restored
|
||||
input stream.
|
||||
A default \fIAtEoIF\fR is provided. It does nothing, and returns 0,
|
||||
making the "unstacking" completely transparent.
|
||||
The user of the module can write his own if this is not what he wants.
|
||||
.PP
|
||||
The routine \fIAtEoIT\fR is called at the end of the string
|
||||
inserted by \fIInsertText\fR.
|
||||
If it returns 1, the LoadChar causing the call returns EOI, otherwise
|
||||
the LoadChar returns the next character of the suspended and now restored
|
||||
input stream.
|
||||
A default \fIAtEoIT\fR is provided. It does nothing, and returns 0,
|
||||
making the "unstacking" completely transparent.
|
||||
The user of the module can write his own if this is not what he wants.
|
||||
.SH FILES
|
||||
~em/modules/pkg/inp_pkg.spec
|
||||
.br
|
||||
~em/modules/pkg/inp_pkg.body
|
||||
.br
|
||||
~em/modules/lib/libinput.a
|
||||
.SH MODULES
|
||||
system(3), alloc(3)
|
||||
.SH "SEE ALSO"
|
||||
\fIGeneric Packages in C\fR by Dick Grune.
|
||||
.SH BUGS
|
||||
A \fILoadChar\fR-call does look like a function call,
|
||||
but behaves differently. All for the sake of speed of course ...
|
Loading…
Reference in a new issue