Initial revision

This commit is contained in:
ceriel 1987-01-05 17:20:13 +00:00
parent 0de3e4a0af
commit eb28fd80f9
20 changed files with 1180 additions and 0 deletions

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

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

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

View file

@ -0,0 +1,8 @@
#include <em.h>
#include <em_mes.h>
C_ms_err()
{
C_mes_begin(ms_err);
C_mes_end();
}

View file

@ -0,0 +1,8 @@
#include <em.h>
#include <em_mes.h>
C_ms_flt()
{
C_mes_begin(ms_flt);
C_mes_end();
}

View file

@ -0,0 +1,8 @@
#include <em.h>
#include <em_mes.h>
C_ms_gto()
{
C_mes_begin(ms_gto);
C_mes_end();
}

View file

@ -0,0 +1,8 @@
#include <em.h>
#include <em_mes.h>
C_ms_opt()
{
C_mes_begin(ms_opt);
C_mes_end();
}

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

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

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

View 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 = &notch->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;
}
}

View 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)

View 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;
}

View 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;
}

View 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;
}

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