home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v941.tgz
/
icon.v941src.tar
/
icon.v941src
/
src
/
common
/
rtdb.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-01-18
|
48KB
|
1,693 lines
/*
* Routines to read a data base of run-time information.
*/
#include "../h/gsupport.h"
#include "../h/version.h"
#include "icontype.h"
/*
* GetInt - the next thing in the data base is an integer. Get it.
*/
#define GetInt(n, c)\
n = 0;\
while (isdigit(c)) {\
n = n * 10 + (c - '0');\
c = getc(db);\
}
/*
* SkipWhSp - skip white space characters in the data base.
*/
#define SkipWhSp(c)\
while (isspace(c)) {\
if (c == '\n')\
++dbline;\
c = getc(db);\
}
/*
* prototypes for static functions.
*/
static int cmp_1_pre (int p1, int p2);
static struct il_code *db_abstr (void);
static void db_case (struct il_code *il, int num_cases);
static void db_err3 (int fatal,char *s1,char *s2,char *s3);
static int db_icntyp (void);
static struct il_c *db_ilc (void);
static struct il_c *db_ilcret (int il_c_type);
static struct il_code *db_inlin (void);
static struct il_code *db_ilvar (void);
static int db_rtflg (void);
static int db_tndtyp (void);
static struct il_c *new_ilc (int il_c_type);
static void quoted (int delim);
extern char *progname; /* name of program using this module */
static char *dbname; /* data base name */
static FILE *db; /* data base file */
static int dbline; /* line number current position in data base */
static struct str_buf db_sbuf; /* string buffer */
static int *type_map; /* map data base type codes to internal ones */
static int *compnt_map; /* map data base component codes to internal */
/*
* opendb - open data base and do other house keeping.
*/
int db_open(s, lrgintflg)
char *s;
char **lrgintflg;
{
char *msg_buf;
char *id;
int i, n;
register int c;
static int first_time = 1;
if (first_time) {
first_time = 0;
init_sbuf(&db_sbuf);
}
dbname = s;
dbline = 0;
*lrgintflg = NULL;
db = fopen(dbname, "rb");
if (db == NULL)
return 0;
++dbline;
/*
* Make sure the version number in the data base is what is expected.
*/
s = db_string();
if (strcmp(s, DVersion) != 0) {
msg_buf = alloc(35 + strlen(s) + strlen(progname) + strlen(DVersion));
sprintf(msg_buf, "found version %s, %s requires version %s",
s, progname, DVersion);
db_err1(1, msg_buf);
}
*lrgintflg = db_string(); /* large integer flag */
/*
* Create tables for mapping type codes and type component codes in
* the data base to those compiled into this program. The codes may
* be different if types have been added to the program since the
* data base was created.
*/
type_map = alloc(num_typs * sizeof(int));
db_chstr("", "types"); /* verify section header */
c = getc(db);
SkipWhSp(c)
while (c == 'T') {
c = getc(db);
if (!isdigit(c))
db_err1(1, "expected type code");
GetInt(n, c)
if (n >= num_typs)
db_err1(1, "data base inconsistant with program, rebuild data base");
SkipWhSp(c)
if (c != ':')
db_err1(1, "expected ':'");
id = db_string();
for (i = 0; strcmp(id, icontypes[i].id) != 0; ++i)
if (i >= num_typs)
db_err2(1, "unknown type:", id);
type_map[n] = i;
c = getc(db);
SkipWhSp(c)
}
db_chstr("", "endsect");
compnt_map = alloc(num_cmpnts * sizeof(int));
db_chstr("", "components"); /* verify section header */
c = getc(db);
SkipWhSp(c)
while (c == 'C') {
c = getc(db);
if (!isdigit(c))
db_err1(1, "expected type component code");
GetInt(n, c)
if (n >= num_cmpnts)
db_err1(1, "data base inconsistant with program, rebuild data base");
SkipWhSp(c)
if (c != ':')
db_err1(1, "expected ':'");
id = db_string();
for (i = 0; strcmp(id, typecompnt[i].id) != 0; ++i)
if (i >= num_cmpnts)
db_err2(1, "unknown type component:", id);
compnt_map[n] = i;
c = getc(db);
SkipWhSp(c)
}
db_chstr("", "endsect");
return 1;
}
/*
* db_close - close data base.
*/
void db_close()
{
if (fclose(db) != 0)
db_err2(0, "cannot close", dbname);
}
/*
* db_string - get a white-space delimited string from the data base.
*/
char *db_string()
{
register int c;
/*
* Look for the start of the string; '$' starts a special indicator.
* Copy characters into string buffer until white space is found.
*/
c = getc(db);
SkipWhSp(c);
if (c == EOF)
db_err1(1, "unexpected EOF");
if (c == '$')
return NULL;
while (!isspace(c) && c != EOF) {
AppChar(db_sbuf, c);
c = getc(db);
}
if (c == '\n')
++dbline;
return str_install(&db_sbuf); /* put string in string table */
}
/*
* db_impl - read basic header information for an operation into a structure
* and return it.
*/
struct implement *db_impl(oper_typ)
int oper_typ;
{
register struct implement *ip;
register int c;
int i;
char *name;
long n;
/*
* Get operation name.
*/
if ((name = db_string()) == NULL)
return NULL;
/*
* Create an internal structure to hold the data base entry.
*/
ip = NewStruct(implement);
ip->blink = NULL;
ip->iconc_flgs = 0; /* reserved for internal use by compiler */
ip->oper_typ = oper_typ;
ip->name = name;
ip->op = NULL;
/*
* Get the function name prefix assigned to this operation.
*/
c = getc(db);
SkipWhSp(c)
if (isalpha(c) || isdigit(c))
ip->prefix[0] = c;
else
db_err2(1, "invalid prefix for", ip->name);
c = getc(db);
if (isalpha(c) || isdigit(c))
ip->prefix[1] = c;
else
db_err2(1, "invalid prefix for", ip->name);
/*
* Get the number of parameters.
*/
c = getc(db);
SkipWhSp(c)
if (!isdigit(c))
db_err2(1, "number of parameters missing for", ip->name);
GetInt(n, c)
ip->nargs = n;
/*
* Get the flags that indicate whether each parameter requires a dereferenced
* and/or undereferenced value, and whether the last parameter represents
* the end of a varargs list. Store the flags in an array.
*/
if (n == 0)
ip->arg_flgs = NULL;
else
ip->arg_flgs = alloc(n * sizeof(int));
if (c != '(')
db_err2(1, "parameter flags missing for", ip->name);
c = getc(db);
for (i = 0; i < n; ++i) {
if (c == ',' || c == ')')
db_err2(1, "parameter flag missing for", ip->name);
ip->arg_flgs[i] = 0;
while (c != ',' && c != ')') {
switch (c) {
case 'u':
ip->arg_flgs[i] |= RtParm;
break;
case 'd':
ip->arg_flgs[i] |= DrfPrm;
break;
case 'v':
ip->arg_flgs[i] |= VarPrm;
break;
default:
db_err2(1, "invalid parameter flag for", ip->name);
}
c = getc(db);
}
if (c == ',')
c = getc(db);
}
if (c != ')')
db_err2(1, "invalid parameter flag list for", ip->name);
/*
* Get the result sequence indicator for the operation.
*/
c = getc(db);
SkipWhSp(c)
if (c != '{')
db_err2(1, "result sequence missing for", ip->name);
c = getc(db);
ip->resume = 0;
if (c == '}') {
ip->min_result = NoRsltSeq;
ip->max_result = NoRsltSeq;
}
else {
if (!isdigit(c))
db_err2(1, "invalid result sequence for", ip->name);
GetInt(n, c)
ip->min_result = n;
if (c != ',')
db_err2(1, "invalid result sequence for", ip->name);
c = getc(db);
if (c == '*') {
ip->max_result = UnbndSeq;
c = getc(db);
}
else if (isdigit(c)) {
GetInt(n, c)
ip->max_result = n;
}
else
db_err2(1, "invalid result sequence for", ip->name);
if (c == '+') {
ip->resume = 1;
c = getc(db);
}
if (c != '}')
db_err2(1, "invalid result sequence for", ip->name);
}
/*
* Get the flag indicating whether the operation contains returns, fails,
* or suspends.
*/
ip->ret_flag = db_rtflg();
/*
* Get the t/f flag that indicates whether the operation explicitly
* uses the 'result' location.
*/
c = getc(db);
SkipWhSp(c)
switch (c) {
case 't':
ip->use_rslt = 1;
break;
case 'f':
ip->use_rslt = 0;
break;
default:
db_err2(1, "invalid 'result' use indicator for", ip->name);
}
return ip;
}
/*
* db_code - read the RTL code for the body of an operation.
*/
void db_code(ip)
struct implement *ip;
{
register int c;
char *s;
word n;
int var_type;
int i;
/*
* read the descriptive string.
*/
c = getc(db);
SkipWhSp(c)
if (c != '"')
db_err1(1, "operation description expected");
for (c = getc(db); c != '"' && c != '\n' && c != EOF; c = getc(db)) {
if (c == '\\') {
AppChar(db_sbuf, c);
c = getc(db);
}
AppChar(db_sbuf, c);
}
if (c != '"')
db_err1(1, "expected '\"'");
ip->comment = str_install(&db_sbuf);
/*
* Get the number of tended variables in the declare clause.
*/
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
ip->ntnds = n;
/*
* Read information about the tended variables into an array.
*/
if (n == 0)
ip->tnds = NULL;
else
ip->tnds = alloc(n * sizeof(struct tend_var));
for (i = 0; i < n; ++i) {
var_type = db_tndtyp(); /* type of tended declaration */
ip->tnds[i].var_type = var_type;
ip->tnds[i].blk_name = NULL;
if (var_type == TndBlk) {
/*
* Tended block pointer declarations include a block type or '*' to
* indicate 'union block *'.
*/
s = db_string();
if (s == NULL)
db_err1(1, "block name expected");
if (*s != '*')
ip->tnds[i].blk_name = s;
}
ip->tnds[i].init = db_ilc(); /* C code for declaration initializer */
}
/*
* Get the number of non-tended variables in the declare clause.
*/
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
ip->nvars = n;
/*
* Get each non-tended declaration and store it in an array.
*/
if (n == 0)
ip->vars = NULL;
else
ip->vars = alloc(n * sizeof(struct ord_var));
for (i = 0; i < n; ++i) {
s = db_string(); /* variable name */
if (s == NULL)
db_err1(1, "variable name expected");
ip->vars[i].name = s;
ip->vars[i].dcl = db_ilc(); /* full declaration including name */
}
/*
* Get the executable RTL code.
*/
ip->in_line = db_inlin();
/*
* We should be at the end of the operation.
*/
c = getc(db);
SkipWhSp(c)
if (c != '$')
db_err1(1, "expected $end");
}
/*
* db_inlin - read in the in-line code (executable RTL code) for an operation.
*/
static struct il_code *db_inlin()
{
struct il_code *il = NULL;
register int c;
int i;
int indx;
int fall_thru;
int n, n1;
/*
* The following nested switch statements act as a trie for recognizing
* the prefix form of RTL code in the data base.
*/
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'a':
switch (getc(db)) {
case 'b': {
db_chstr("ab", "str");
il = new_il(IL_Abstr, 2); /* abstract type computation */
il->u[0].fld = db_abstr(); /* side effects */
il->u[1].fld = db_abstr(); /* return type */
break;
}
case 'c': {
db_chstr("ac", "ase");
il = new_il(IL_Acase, 5); /* arith_case */
il->u[0].fld = db_ilvar(); /* first variable */
il->u[1].fld = db_ilvar(); /* second variable */
il->u[2].fld = db_inlin(); /* C_integer action */
il->u[3].fld = db_inlin(); /* integer action */
il->u[4].fld = db_inlin(); /* C_double action */
break;
}
default:
db_err1(1, "expected abstr or acase");
}
break;
case 'b':
db_chstr("b", "lock");
c = getc(db);
SkipWhSp(c)
if (c == 't')
fall_thru = 1;
else
fall_thru = 0;
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il = new_il(IL_Block, 3 + n); /* block of in-line C code */
il->u[0].n = fall_thru;
il->u[1].n = n; /* number of local tended */
for (i = 2; i - 2 < n; ++i)
il->u[i].n = db_tndtyp(); /* tended declaration */
il->u[i].c_cd = db_ilc(); /* C code */
break;
case 'c':
switch (getc(db)) {
case 'a': {
char prfx3;
int ret_val = 0;
int ret_flag;
int rslt = 0;
int num_sbuf;
int num_cbuf;
db_chstr("ca", "ll");
/*
* Call to body function. Get the letter used as the 3rd
* character of the function prefix.
*/
c = getc(db);
SkipWhSp(c)
prfx3 = c;
/*
* Determine what the body function returns directly.
*/
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'i':
ret_val = RetInt; /* returns C integer */
break;
case 'd':
ret_val = RetDbl; /* returns C double */
break;
case 'n':
ret_val = RetNoVal; /* returns nothing directly */
break;
case 's':
ret_val = RetSig; /* returns a signal */
break;
default:
db_err1(1, "invalid indicator for type of return value");
}
/*
* Get the return/suspend/fail/fall-through flag.
*/
c = getc(db);
ret_flag = db_rtflg();
/*
* Get the flag indicating whether the body function expects
* to have an explicit result location passed to it.
*/
c = getc(db);
SkipWhSp(c)
switch (c) {
case 't':
rslt = 1;
break;
case 'f':
rslt = 0;
break;
default:
db_err1(1, "t or f expected");
}
c = getc(db);
SkipWhSp(c)
GetInt(num_sbuf, c) /* number of cset buffers */
c = getc(db);
SkipWhSp(c)
GetInt(num_cbuf, c) /* number of string buffers */
c = getc(db);
SkipWhSp(c)
GetInt(n, c) /* num args */
il = new_il(IL_Call, 8 + n * 2);
il->u[0].n = 0; /* reserved for internal use by compiler */
il->u[1].n = prfx3;
il->u[2].n = ret_val;
il->u[3].n = ret_flag;
il->u[4].n = rslt;
il->u[5].n = num_sbuf;
il->u[6].n = num_cbuf;
il->u[7].n = n;
indx = 8;
/*
* get the prototype parameter declarations and actual arguments.
*/
n *= 2;
while (n--)
il->u[indx++].c_cd = db_ilc();
}
break;
case 'n':
if (getc(db) != 'v')
db_err1(1, "expected cnv1 or cnv2");
switch (getc(db)) {
case '1':
il = new_il(IL_Cnv1, 2);
il->u[0].n = db_icntyp(); /* type code */
il->u[1].fld = db_ilvar(); /* source */
break;
case '2':
il = new_il(IL_Cnv2, 3);
il->u[0].n = db_icntyp(); /* type code */
il->u[1].fld = db_ilvar(); /* source */
il->u[2].c_cd = db_ilc(); /* destination */
break;
default:
db_err1(1, "expected cnv1 or cnv2");
}
break;
case 'o':
db_chstr("co", "nst");
il = new_il(IL_Const, 2); /* constant keyword */
il->u[0].n = db_icntyp(); /* type code */
c = getc(db);
SkipWhSp(c)
if (c == '"' || c == '\'') {
quoted(c);
c = getc(db); /* quoted literal without quotes */
}
else
while (c != EOF && !isspace(c)) {
AppChar(db_sbuf, c);
c = getc(db);
}
il->u[1].s = str_install(&db_sbuf); /* non-quoted values */
break;
default:
db_err1(1, "expected call, const, cnv1, or cnv2");
}
break;
case 'd':
if (getc(db) != 'e' || getc(db) != 'f')
db_err1(1, "expected def1 or def2");
switch (getc(db)) {
case '1':
il = new_il(IL_Def1, 3); /* defaulting, no dest. field */
il->u[0].n = db_icntyp(); /* type code */
il->u[1].fld = db_ilvar(); /* source */
il->u[2].c_cd = db_ilc(); /* default value */
break;
case '2':
il = new_il(IL_Def2, 4); /* defaulting, with dest. field */
il->u[0].n = db_icntyp(); /* type code */
il->u[1].fld = db_ilvar(); /* source */
il->u[2].c_cd = db_ilc(); /* default value */
il->u[3].c_cd = db_ilc(); /* destination */
break;
default:
db_err1(1, "expected dflt1 or dflt2");
}
break;
case 'r':
if (getc(db) != 'u' || getc(db) != 'n' || getc(db) != 'e' ||
getc(db) != 'r' || getc(db) != 'r')
db_err1(1, "expected runerr1 or runerr2");
switch (getc(db)) {
case '1':
il = new_il(IL_Err1, 1); /* runerr, no offending value */
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il->u[0].n = n; /* error number */
break;
case '2':
il = new_il(IL_Err2, 2); /* runerr, with offending value */
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il->u[0].n = n; /* error number */
il->u[1].fld = db_ilvar(); /* variable */
break;
default:
db_err1(1, "expected runerr1 or runerr2");
}
break;
case 'i':
switch (getc(db)) {
case 'f':
switch (getc(db)) {
case '1':
il = new_il(IL_If1, 2); /* if-then */
il->u[0].fld = db_inlin(); /* condition */
il->u[1].fld = db_inlin(); /* then clause */
break;
case '2':
il = new_il(IL_If2, 3); /* if-then-else */
il->u[0].fld = db_inlin(); /* condition */
il->u[1].fld = db_inlin(); /* then clause */
il->u[2].fld = db_inlin(); /* else clause */
break;
default:
db_err1(1, "expected if1 or if2");
}
break;
case 's':
il = new_il(IL_Is, 2); /* type check */
il->u[0].n = db_icntyp(); /* type code */
il->u[1].fld = db_ilvar(); /* variable */
break;
default:
db_err1(1, "expected if1, if2, or is");
}
break;
case 'l':
switch (getc(db)) {
case 'c':
db_chstr("lc", "ase");
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il = new_il(IL_Lcase, 2 + 2 * n); /* length case */
il->u[0].n = n; /* number of cases */
indx = 1;
while (n--) {
c = getc(db);
SkipWhSp(c)
GetInt(n1, c)
il->u[indx++].n = n1; /* selection number */
il->u[indx++].fld = db_inlin(); /* action */
}
il->u[indx].fld = db_inlin(); /* default */
break;
case 's':
if (getc(db) != 't')
db_err1(1, "expected lst");
il = new_il(IL_Lst, 2); /* sequence of code parts */
il->u[0].fld = db_inlin(); /* 1st part */
il->u[1].fld = db_inlin(); /* 2nd part */
break;
default:
db_err1(1, "expected lcase or lst");
}
break;
case 'n':
db_chstr("n", "il");
il = NULL;
break;
case 't': {
struct il_code *var;
if (getc(db) != 'c' || getc(db) != 'a' || getc(db) != 's' ||
getc(db) != 'e')
db_err1(1, "expected tcase1 or tcase2");
switch (getc(db)) {
case '1':
var = db_ilvar();
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il = new_il(IL_Tcase1, 3 * n + 2); /* type case, no default */
il->u[0].fld = var; /* variable */
db_case(il, n); /* get cases */
break;
case '2':
var = db_ilvar();
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il = new_il(IL_Tcase2, 3 * n + 3); /* type case, with default */
il->u[0].fld = var; /* variable */
db_case(il, n); /* get cases */
il->u[3 * n + 2].fld = db_inlin(); /* default */
break;
default:
db_err1(1, "expected tcase1 or tcase2");
}
}
break;
case '!':
il = new_il(IL_Bang, 1); /* negated condition */
il->u[0].fld = db_inlin(); /* condition */
break;
case '&':
if (getc(db) != '&')
db_err1(1, "expected &&");
il = new_il(IL_And, 2); /* && (conjunction) */
il->u[0].fld = db_inlin(); /* 1st operand */
il->u[1].fld = db_inlin(); /* 2nd operand */
break;
default:
db_err1(1, "syntax error");
}
return il;
}
/*
* db_rtflg - get the sequence of 4 [or 5] flags that indicate whether code
* for a operation [or body function] returns, fails, suspends, has error
* failure, [or execution falls through the code].
*/
static int db_rtflg()
{
register int c;
int ret_flag;
/*
* The presence of each flag is indicated by a unique character. Its absence
* indicated by '_'.
*/
ret_flag = 0;
c = getc(db);
SkipWhSp(c)
if (c == 'f')
ret_flag |= DoesFail;
else if (c != '_')
db_err1(1, "invalid return indicator");
c = getc(db);
if (c == 'r')
ret_flag |= DoesRet;
else if (c != '_')
db_err1(1, "invalid return indicator");
c = getc(db);
if (c == 's')
ret_flag |= DoesSusp;
else if (c != '_')
db_err1(1, "invalid return indicator");
c = getc(db);
if (c == 'e')
ret_flag |= DoesEFail;
else if (c != '_')
db_err1(1, "invalid return indicator");
c = getc(db);
if (c == 't')
ret_flag |= DoesFThru;
else if (c != '_' && c != ' ')
db_err1(1, "invalid return indicator");
return ret_flag;
}
/*
* db_case - get the cases for a type_case statement from the data base.
*/
static void db_case(il, num_cases)
struct il_code *il;
int num_cases;
{
register int c;
int *typ_vect;
int i, j;
int num_types;
int indx;
il->u[1].n = num_cases; /* number of cases */
indx = 2;
for (i = 0; i < num_cases; ++i) {
/*
* Determine the number of types in this case then store the
* type codes in an array.
*/
c = getc(db);
SkipWhSp(c)
GetInt(num_types, c)
il->u[indx++].n = num_types;
typ_vect = alloc(num_types * sizeof(int));
il->u[indx++].vect = typ_vect;
for (j = 0; j < num_types; ++j)
typ_vect[j] = db_icntyp(); /* type code */
il->u[indx++].fld = db_inlin(); /* action */
}
}
/*
* db_ilvar - get a symbol table index for a simple variable or a
* subscripted variable from the data base.
*/
static struct il_code *db_ilvar()
{
struct il_code *il;
register int c;
int n;
c = getc(db);
SkipWhSp(c)
if (isdigit(c)) {
/*
* Simple variable: just a symbol table index.
*/
il = new_il(IL_Var, 1);
GetInt(n, c)
il->u[0].n = n; /* symbol table index */
}
else {
if (c != '[')
db_err1(1, "expected symbol table index or '['");
/*
* Subscripted variable: symbol table index and subscript.
*/
il = new_il(IL_Subscr, 2);
c = getc(db);
SkipWhSp(c);
GetInt(n, c)
il->u[0].n = n; /* symbol table index */
c = getc(db);
SkipWhSp(c)
GetInt(n, c)
il->u[1].n = n; /* subscripting index */
}
return il;
}
/*
* db_abstr - get abstract type computations from the data base.
*/
static struct il_code *db_abstr()
{
struct il_code *il = NULL;
register int c;
word typcd;
word indx;
int n;
int nargs;
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'l':
db_chstr("l", "st");
il = new_il(IL_Lst, 2); /* sequence of code parts */
il->u[0].fld = db_abstr(); /* 1st part */
il->u[1].fld = db_abstr(); /* 2nd part */
break;
case 'n':
switch (getc(db)) {
case 'e':
if (getc(db) != 'w')
db_err1(1, "expected new");
typcd = db_icntyp();
c = getc(db);
SkipWhSp(c)
GetInt(nargs, c)
il = new_il(IL_New, 2 + nargs); /* new structure create here */
il->u[0].n = typcd; /* type code */
il->u[1].n = nargs; /* number of args */
indx = 2;
while (nargs--)
il->u[indx++].fld = db_abstr(); /* argument for component */
break;
case 'i':
if (getc(db) != 'l')
db_err1(1, "expected nil");
il = NULL;
break;
default:
db_err1(1, "expected new or nil");
}
break;
case 's':
db_chstr("s", "tore");
il = new_il(IL_Store, 1); /* abstract store */
il->u[0].fld = db_abstr(); /* type to "dereference" */
break;
case 't':
db_chstr("t", "yp");
il = new_il(IL_IcnTyp, 1); /* explicit type */
il->u[0].n = db_icntyp(); /* type code */
break;
case 'v':
db_chstr("v", "artyp");
il = new_il(IL_VarTyp, 1); /* variable */
il->u[0].fld = db_ilvar(); /* symbol table index, etc */
break;
case '.':
il = new_il(IL_Compnt, 2); /* component access */
il->u[0].fld = db_abstr(); /* type being accessed */
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'f':
il->u[1].n = CM_Fields;
break;
case 'C':
c = getc(db);
GetInt(n, c)
il->u[1].n = compnt_map[n];
break;
default:
db_err1(1, "expected component code");
}
break;
case '=':
il = new_il(IL_TpAsgn, 2); /* assignment (side effect) */
il->u[0].fld = db_abstr(); /* left-hand-side */
il->u[1].fld = db_abstr(); /* right-hand-side */
break;
case '+':
if (getc(db) != '+')
db_err1(1, "expected ++");
il = new_il(IL_Union, 2); /* ++ (union) */
il->u[0].fld = db_abstr(); /* 1st operand */
il->u[1].fld = db_abstr(); /* 2nd operand */
break;
case '*':
if (getc(db) != '*')
db_err1(1, "expected **");
il = new_il(IL_Inter, 2); /* ** (intersection) */
il->u[0].fld = db_abstr(); /* 1st operand */
il->u[1].fld = db_abstr(); /* 2nd operand */
break;
}
return il;
}
/*
* db_ilc - read a piece of in-line C code.
*/
static struct il_c *db_ilc()
{
register int c;
int old_c;
word n;
struct il_c *base = NULL;
struct il_c **nxtp = &base;
c = getc(db);
SkipWhSp(c)
switch (c) {
case '$':
/*
* This had better be the starting $c.
*/
c = getc(db);
if (c == 'c') {
c = getc(db);
for (;;) {
SkipWhSp(c)
if (c == '$') {
c = getc(db);
switch (c) {
case 'c': /* $cb or $cgoto <cond> <lbl num> */
c = getc(db);
switch (c) {
case 'b':
*nxtp = new_ilc(ILC_CBuf);
c = getc(db);
break;
case 'g':
db_chstr("$cg", "oto");
*nxtp = new_ilc(ILC_CGto);
#ifdef MultiThread
#undef code
#endif /* MultiThead */
(*nxtp)->code[0] = db_ilc();
c = getc(db);
SkipWhSp(c);
if (!isdigit(c))
db_err1(1, "$cgoto: expected label number");
GetInt(n, c);
(*nxtp)->n = n;
break;
default:
db_err1(1, "expected $cb or $cgoto");
}
break;
case 'e':
c = getc(db);
if (c == 'f') { /* $efail */
db_chstr("$ef", "ail");
*nxtp = new_ilc(ILC_EFail);
c = getc(db);
break;
}
else
return base; /* $e */
case 'f': /* $fail */
db_chstr("$f", "ail");
*nxtp = new_ilc(ILC_Fail);
c = getc(db);
break;
case 'g': /* $goto <lbl num> */
db_chstr("$g", "oto");
*nxtp = new_ilc(ILC_Goto);
c = getc(db);
SkipWhSp(c);
if (!isdigit(c))
db_err1(1, "$goto: expected label number");
GetInt(n, c);
(*nxtp)->n = n;
break;
case 'l': /* $lbl <lbl num> */
db_chstr("$l", "bl");
*nxtp = new_ilc(ILC_Lbl);
c = getc(db);
SkipWhSp(c);
if (!isdigit(c))
db_err1(1, "$lbl: expected label number");
GetInt(n, c);
(*nxtp)->n = n;
break;
case 'm': /* $m[d]<indx> */
*nxtp = new_ilc(ILC_Mod);
c = getc(db);
if (c == 'd') {
(*nxtp)->s = "d";
c = getc(db);
}
if (isdigit(c)) {
GetInt(n, c);
(*nxtp)->n = n;
}
else if (c == 'r') {
(*nxtp)->n = RsltIndx;
c = getc(db);
}
else
db_err1(1, "$m: expected symbol table index");
break;
case 'r': /* $r[d]<indx> or $ret ... */
c = getc(db);
if (isdigit(c) || c == 'd') {
*nxtp = new_ilc(ILC_Ref);
if (c == 'd') {
(*nxtp)->s = "d";
c = getc(db);
}
GetInt(n, c);
(*nxtp)->n = n;
}
else if (c == 'r') {
*nxtp = new_ilc(ILC_Ref);
(*nxtp)->n = RsltIndx;
c = getc(db);
}
else {
if (c != 'e' || getc(db) != 't')
db_err1(1, "expected $ret");
*nxtp = db_ilcret(ILC_Ret);
c = getc(db);
}
break;
case 's': /* $sb or $susp ... */
c = getc(db);
switch (c) {
case 'b':
*nxtp = new_ilc(ILC_SBuf);
c = getc(db);
break;
case 'u':
db_chstr("$su", "sp");
*nxtp = db_ilcret(ILC_Susp);
c = getc(db);
break;
default:
db_err1(1, "expected $sb or $susp");
}
break;
case 't': /* $t[d]<indx> */
*nxtp = new_ilc(ILC_Tend);
c = getc(db);
if (!isdigit(c))
db_err1(1, "$t: expected index");
GetInt(n, c);
(*nxtp)->n = n;
break;
case '{':
*nxtp = new_ilc(ILC_LBrc);
c = getc(db);
break;
case '}':
*nxtp = new_ilc(ILC_RBrc);
c = getc(db);
break;
default:
db_err1(1, "invalid $ escape in C code");
}
}
else {
/*
* Arbitrary code - gather into a string.
*/
while (c != '$') {
if (c == '"' || c == '\'') {
quoted(c);
c = getc(db);
}
if (c == '\n')
++dbline;
if (c == EOF)
db_err1(1, "unexpected EOF in C code");
old_c = c;
AppChar(db_sbuf, c);
c = getc(db);
if (old_c == ' ')
while (c == ' ')
c = getc(db);
}
*nxtp = new_ilc(ILC_Str);
(*nxtp)->s = str_install(&db_sbuf);
}
nxtp = &(*nxtp)->next;
}
}
break;
case 'n':
db_chstr("n", "il");
return NULL;
}
db_err1(1, "expected C code of the form $c ... $e or nil");
/*NOTREACHED*/
return 0; /* avoid gcc warning */
}
/*
* quoted - get the string for a quoted literal. The first quote mark
* has been read.
*/
static void quoted(delim)
int delim;
{
register int c;
AppChar(db_sbuf, delim);
c = getc(db);
while (c != delim && c != EOF) {
if (c == '\\') {
AppChar(db_sbuf, c);
c = getc(db);
if (c == EOF)
db_err1(1, "unexpected EOF in quoted literal");
}
AppChar(db_sbuf, c);
c = getc(db);
}
if (c == EOF)
db_err1(1, "unexpected EOF in quoted literal");
AppChar(db_sbuf, c);
}
/*
* db_ilcret - get the in-line C code on a return or suspend statement.
*/
static struct il_c *db_ilcret(il_c_type)
int il_c_type;
{
struct il_c *ilc;
int c;
int n;
int i;
ilc = new_ilc(il_c_type);
ilc->n = db_icntyp(); /* kind of return expression */
c = getc(db);
SkipWhSp(c)
GetInt(n, c) /* number of arguments in this expression */
for (i = 0; i < n; ++i)
ilc->code[i] = db_ilc(); /* an argument to the return expression */
return ilc;
}
/*
* db_tndtyp - get the indication for the type of a tended declaration.
*/
static int db_tndtyp()
{
int c;
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'b':
db_chstr("b", "lkptr");
return TndBlk; /* tended block pointer */
case 'd':
db_chstr("d", "esc");
return TndDesc; /* tended descriptor */
case 's':
db_chstr("s", "tr");
return TndStr; /* tended string */
default:
db_err1(1, "expected blkptr, desc, or str");
/* NOTREACHED */
}
/* NOTREACHED */
return 0; /* avoid gcc warning */
}
/*
* db_icntyp - get a type code from the data base.
*/
static int db_icntyp()
{
int c;
int n;
c = getc(db);
SkipWhSp(c)
switch (c) {
case 'T':
c = getc(db);
GetInt(n, c)
if (n < num_typs)
return type_map[n]; /* type code from specification system */
break;
case 'a':
return TypAny; /* a - any type */
case 'c':
switch (getc(db)) {
case 'i':
return TypCInt; /* ci - C integer */
case 'd':
return TypCDbl; /* cd - C double */
case 's':
return TypCStr; /* cs - C string */
}
break;
case 'd':
return RetDesc; /* d - descriptor on return statement */
case 'e':
switch (getc(db)) {
case 'c':
if (getc(db) == 'i')
return TypECInt; /* eci - exact C integer */
break;
case 'i':
return TypEInt; /* ei - exact integer */
case ' ':
case '\n':
case '\t':
return TypEmpty; /* e - empty type */
}
break;
case 'n':
if (getc(db) == 'v')
return RetNVar; /* nv - named variable on return */
break;
case 'r':
if (getc(db) == 'n')
return RetNone; /* rn - nothing explicitly returned */
break;
case 's':
if (getc(db) == 'v')
return RetSVar; /* sv - structure variable on return */
break;
case 't':
switch (getc(db)) {
case 'c':
return TypTCset; /* tc - temporary cset */
case 's':
return TypTStr; /* ts - temporary string */
}
break;
case 'v':
return TypVar; /* v - variable */
}
db_err1(1, "invalid type code");
/* NOTREACHED */
return 0; /* avoid gcc warning */
}
/*
* new_ilc - allocate a new structure to hold a piece of in-line C code.
*/
static struct il_c *new_ilc(il_c_type)
int il_c_type;
{
struct il_c *ilc;
int i;
ilc = NewStruct(il_c);
ilc->next = NULL;
ilc->il_c_type = il_c_type;
for (i = 0; i < 3; ++i)
ilc->code[i] = NULL;
ilc->n = 0;
ilc->s = NULL;
return ilc;
}
/*
* new_il - allocate a new structure with "size" fields to hold a piece of
* RTL code.
*/
struct il_code *new_il(il_type, size)
int il_type;
int size;
{
struct il_code *il;
il = alloc(sizeof(struct il_code) + (size-1) * sizeof(union il_fld));
il->il_type = il_type;
return il;
}
/*
* db_dscrd - discard an implementation up to $end, skipping the in-line
* RTL code.
*/
void db_dscrd(ip)
struct implement *ip;
{
char state; /* how far along we are at recognizing $end */
free(ip);
state = '\0';
for (;;) {
switch (getc(db)) {
case '$':
state = '$';
continue;
case 'e':
if (state == '$') {
state = 'e';
continue;
}
break;
case 'n':
if (state == 'e') {
state = 'n';
continue;
}
break;
case 'd':
if (state == 'n')
return;
break;
case '\n':
++dbline;
break;
case EOF:
db_err1(1, "unexpected EOF");
}
state = '\0';
}
}
/*
* db_chstr - we are expecting a specific string. We may already have
* read a prefix of it.
*/
void db_chstr(prefix, suffix)
char *prefix;
char *suffix;
{
int c;
c = getc(db);
SkipWhSp(c)
for (;;) {
if (*suffix == '\0' && (isspace(c) || c == EOF)) {
if (c == '\n')
++dbline;
return;
}
else if (*suffix != c)
break;
c = getc(db);
++suffix;
}
db_err3(1, "expected:", prefix, suffix);
}
/*
* db_tbl - fill in a hash table of implementation information for the
* given section.
*/
int db_tbl(section, tbl)
char *section;
struct implement **tbl;
{
struct implement *ip;
int num_added = 0;
unsigned hashval;
/*
* Get past the section header.
*/
db_chstr("", section);
/*
* Create an entry in the hash table for each entry in the data base.
* If multiple data bases are loaded into one hash table, use the
* first entry encountered for each operation.
*/
while ((ip = db_impl(toupper(section[0]))) != NULL) {
if (db_ilkup(ip->name, tbl) == NULL) {
db_code(ip);
hashval = IHasher(ip->name);
ip->blink = tbl[hashval];
tbl[hashval] = ip;
++num_added;
db_chstr("", "end");
}
else
db_dscrd(ip);
}
db_chstr("", "endsect");
return num_added;
}
/*
* db_ilkup - look up id in a table of implementation information and return
* pointer it or NULL if it is not there.
*/
struct implement *db_ilkup(id, tbl)
char *id;
struct implement **tbl;
{
register struct implement *ptr;
ptr = tbl[IHasher(id)];
while (ptr != NULL && ptr->name != id)
ptr = ptr->blink;
return ptr;
}
/*
* nxt_pre - assign next prefix. A prefix consists of n characters each from
* the range 0-9 and a-z, at least one of which is a digit.
*
*/
void nxt_pre(pre, nxt, n)
char *pre;
char *nxt;
int n;
{
int i, num_dig;
if (nxt[0] == '\0') {
fprintf(stderr, "out of unique prefixes\n");
exit(EXIT_FAILURE);
}
/*
* copy the next prefix into the output string.
*/
for (i = 0; i < n; ++i)
pre[i] = nxt[i];
/*
* Increment next prefix. First, determine how many digits there are in
* the current prefix.
*/
num_dig = 0;
for (i = 0; i < n; ++i)
if (isdigit(nxt[i]))
++num_dig;
for (i = n - 1; i >= 0; --i) {
switch (nxt[i]) {
case '9':
/*
* If there is at least one other digit, increment to a letter.
* Otherwise, start over at zero and continue to the previous
* character in the prefix.
*/
if (num_dig > 1) {
nxt[i] = 'a';
return;
}
else
nxt[i] = '0';
break;
case 'z':
/*
* Start over at zero and continue to previous character in the
* prefix.
*/
nxt[i] = '0';
++num_dig;
break;
default:
++nxt[i];
return;
}
}
/*
* Indicate that there are no more prefixes.
*/
nxt[0] = '\0';
}
/*
* cmp_pre - lexically compare 2-character prefixes.
*/
int cmp_pre(pre1, pre2)
char *pre1;
char *pre2;
{
int cmp;
cmp = cmp_1_pre(pre1[0], pre2[0]);
if (cmp == 0)
return cmp_1_pre(pre1[1], pre2[1]);
else
return cmp;
}
/*
* cmp_1_pre - lexically compare 1 character of a prefix.
*/
static int cmp_1_pre(p1, p2)
int p1;
int p2;
{
if (isdigit(p1)) {
if (isdigit(p2))
return p1 - p2;
else
return -1;
}
else {
if (isdigit(p2))
return 1;
else
return p1 - p2;
}
}
/*
* db_err1 - print a data base error message in the form of 1 string.
*/
void db_err1(fatal, s)
int fatal;
char *s;
{
if (fatal)
fprintf(stderr, "error, ");
else
fprintf(stderr, "warning, ");
fprintf(stderr, "data base \"%s\", line %d - %s\n", dbname, dbline, s);
if (fatal)
exit(EXIT_FAILURE);
}
/*
* db_err2 - print a data base error message in the form of 2 strings.
*/
void db_err2(fatal, s1, s2)
int fatal;
char *s1;
char *s2;
{
if (fatal)
fprintf(stderr, "error, ");
else
fprintf(stderr, "warning, ");
fprintf(stderr, "data base \"%s\", line %d - %s %s\n", dbname, dbline, s1,
s2);
if (fatal)
exit(EXIT_FAILURE);
}
/*
* db_err3 - print a data base error message in the form of 3 strings.
*/
static void db_err3(fatal, s1, s2, s3)
int fatal;
char *s1;
char *s2;
char *s3;
{
if (fatal)
fprintf(stderr, "error, ");
else
fprintf(stderr, "warning, ");
fprintf(stderr, "data base \"%s\", line %d - %s %s%s\n", dbname, dbline, s1,
s2, s3);
if (fatal)
exit(EXIT_FAILURE);
}