pcs/sread.c

873 lines
27 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* TIPC Scheme '84 Runtime Support - S-Expression Reading
(C) Copyright 1984,1985 by Texas Instruments Incorporated.
All rights reserved.
Author: Mark E. Meyer
Installation: Texas Instruments Incorporated, Dallas, Texas
Division: Central Research Laboratories
Cost Center: Computer Science Laboratory
Project: Computer Architecture Branch
Date Written: 12 June 1984
Last Modification: 18 October 1985 by John Jensen
*/
#include "scheme.h"
#include "schars.h"
extern char decpoint; /* Current decimal point character */
#define ATOM 0 /* Codes returned by FINDTASK function */
#define NIL 1
#define LPAREN 2
#define RPAREN 3
#define QUOTE 4
#define DOT 5
#define DS 0 /* Register array subscripts */
#define PG 1
/************
static int scan = 0;
static char ch = ' '; /* Most recently received character */
static int *mainreg = NULL; /* Main register */
/** static int init_stk = 0; /* Initial Scheme top-of-stack */ **/
static int limit; /* Current size of atom buffer */
static char *atomb; /* Atom buffer */
static int flag_eof; /* Whether to flag end-of-file */
/**************************************************************/
/* REG2REG(sor,dest) */
/* Copy the contents from one regsiter to another. */
/**************************************************************/
#define reg2reg(sor,dest) (dest)[DS] = (sor)[DS]; (dest)[PG] = (sor)[PG];
/**************************************************************/
/* SKIPSPACE() */
/* Skip over spaces in the input stream, and get a new */
/* line of input if necessary */
/**************************************************************/
#define skipspace() do {rcvchar();} while (isspace(ch));
**************/
/**************************************************************/
/* SREAD(reg,pg,ds) */
/* Given a pointer to a register, SREAD constructs a */
/* list structure, based on input from the port at (PG,DS), */
/* leaving in the register a pointer to the structure. This */
/* memory-efficient algorithm has return pointers kept */
/* within the structure itself, both minimizing overhead and */
/* making the structure garbage-collector-compatible. */
/* Throughout this source, pointers in the registers use */
/* doubled pages, CORRected to single only when necessary. */
/* Aside from setting PORT once, a SUBSREAD routine is */
/* used so that two additional registers known to the garabge */
/* collector can be easily utilized. This means that READ */
/* may only be called with one of the R-registers. */
/**************************************************************/
/***** Code for 'read' turned off 16 July 1985 (JCJ) *****
sread(reg,pg,ds)
int *reg;
int pg,ds;
{
setabort();
if (setadr(pg,ds,1)) /* Set the read port */
abort(PORTERR);
flag_eof = TRUE; limit = 0;
mainreg = reg; /* Save pointer to main register */
if (reg < &regs[3])
subsread(reg, reg + 2, reg + 4);
else
{
subsread(reg, reg - 2, reg - 4);
}
return(0);
}
***** Code for 'read' turned off 16 July 1985 (JCJ) *****/
/***********
/**************************************************************/
/* SREAD_ATOM(reg,pg,ds) */
/* Setup for the operation of reading a single atom from */
/* the given port. Special characters such as ')' are parsed */
/* as lists(!) to tell them from ordianry atoms. */
/**************************************************************/
sread_atom(reg,pg,ds)
int *reg;
int pg,ds;
{
setabort();
if (setadr(pg,ds,1))
abort(PORTERR);
mainreg = reg; /* Save pointer to result register */
flag_eof = TRUE; limit = /* init_stk = */ 0;
do
{
skipspace(); skipcomments();
} while (!ch); /* if ch = '\0', flush it */
return(read_atom(reg));
}
***************/
/***** Code for 'read' turned off 16 July 1985 (JCJ) *****
/**************************************************************/
/* SUBSREAD(reg,pres,prev) */
/**************************************************************/
subsread(reg,pres,prev)
int reg[2];
int pres[2]; /* Pointer to the present cons cell */
int prev[2]; /* Ptr. to cell whose car is list containing [PRES] */
{
int task;
C_push(pres); /* Save old register values */
C_push(prev);
init_stk = TOS; /* Save initial top of stack pointer */
prev[PG] = prev[DS] = pres[PG] = pres[DS] = 0;
start:
task = findtask(); /* Determine next action to take, */
switch (task) /* depending on what's coming up */
{
case NIL: /* If atom coming, read it & leave */
case ATOM:
read_atom(reg);
goto fastexit;
case LPAREN: /* Grab cons cell */
descend(reg,pres,prev);
C_push(pres); /* Save start of list structure */
reg[PG] = fixpage; /* Bottom of stack for dot-lparens */
C_push(reg);
goto fillcar; /* Read in the car */
case QUOTE: /* Form quote structure */
buildq(pres,reg,&task);
C_push(reg); /* Save start */
reg[PG] = fixpage; /* Bottom of stack */
C_push(reg);
while (task == QUOTE) /* Handle nested quotes */
buildq(pres,reg,&task);
switch (task)
{
case NIL: /* Read atom and leave */
case ATOM:
read_atom(reg);
reg2ptr(reg,pres);
goto exit;
case LPAREN: /* Start reading list */
listquote:
grabcell(reg);
reg2ptr(reg,pres);
reg2reg(reg,pres);
goto fillcar;
default: /* Anything else is wrong! */
abortread(QUOTERR);
}
case RPAREN: /* Can't start with )! */
abortread(RPARERR);
case DOT: /* Nor with .! */
abortread(DOTERR);
}
fillcar:
task = findtask();
fillcar2:
switch (task)
{
case NIL: /* Deposit atom in car and read in cdr */
case ATOM:
read_atom(reg);
reg2ptr(reg,pres);
goto cross;
case LPAREN: /* Save PREV in cdr field and update PRES & PREV */
reg2cdr(prev,pres);
descend(reg,pres,prev);
goto fillcar;
case QUOTE:
C_push(prev); /* Save PREV & PRES */
reg2reg(pres,prev);
do /* Build quote structure */
buildq(pres,reg,&task);
while (task == QUOTE);
switch(task)
{
case NIL: /* If atom, read in, restore PRES & PREV, and cross */
case ATOM:
read_atom(reg);
reg2ptr(reg,pres);
reg2reg(prev,pres);
C_pop(prev);
goto cross;
case LPAREN: /* If list, save old PREV in cdr of old PRES */
C_pop(reg);
reg2cdr(reg,prev);
goto listquote;
default:
abortread(QUOTERR);
}
default: /* This is the case of (. */
abortread(DOTERR);
}
cross:
task = findtask();
switch (task)
{
case RPAREN: /* Try to ascend to higher list */
tryascend:
C_pop(reg);
while ((reg[PG] == prev[PG]) && (reg[DS] == prev[DS]))
/* Do while there are dot-lparens to be closed */
if (findtask() == RPAREN)
C_pop(reg);
else /* Some dot-lparen wasn't closed */
{
abortread(DOTERR);
}
C_push(reg); /* Restore stack */
if (prev[PG]) /* Not done if not at top level of list */
{
ascend(pres,prev);
goto cross;
}
else /* Else exit */
{
goto exit;
}
case DOT:
task = findtask();
switch (task)
{
case NIL: /* Fill cdr field */
case ATOM:
read_atom(reg);
reg2cdr(reg,pres);
dotatom:
if (findtask() == RPAREN) /* Ascend only if ) follows */
goto tryascend;
else /* more than one thing after dot */
{
abortread(DOTERR);
}
case LPAREN: /* Push PREV onto stack */
C_push(prev);
buildcdr(reg,pres); /* And treat as if dot-lparen */
goto fillcar; /* didn't happen */
case QUOTE:
task = -1; /* Fill cdr field first */
do
buildq(pres,reg,&task);
while (task == QUOTE);
switch (task)
{
case NIL: /* If atom, go fill space in quote structure */
case ATOM:
read_atom(reg);
reg2ptr(reg,pres);
goto dotatom;
case LPAREN:
C_push(prev); /* Save dot syntax indicator */
goto listquote;
default:
abortread(QUOTERR);
}
default:
abortread(DOTERR);
}
default: /* Otherwise, affix a cons cell to the cdr of PRES */
buildcdr(reg,pres);
goto fillcar2;
}
exit:
TOS -= PTRSIZE; /* Discard fixnum */
C_pop(reg); /* Get ptr to structure */
fastexit:
C_pop(prev); /* Restore old values */
C_pop(pres);
}
/**************************************************************/
/* FINDTASK() */
/* Scan the input stream and find out what's coming up */
/* (atom, ", (, etc.). */
/**************************************************************/
findtask()
{
char *stpchr();
skipspace();
skipcomments();
switch (ch)
{
case '(':
skipspace();
skipcomments();
if (ch == ')')
{
ch = ' '; return(NIL);
}
else
{
pushchar();
return(LPAREN);
}
case ')':
return(RPAREN);
case '\'':
return(QUOTE);
case '.':
rcvchar();
if (isspace(ch))
return(DOT);
else
{
pushchar();
if (stpchr( "()'|\";[]{}" , ch))
{
return(DOT); /* because dot is followed by non-atomic char */
}
else /* the dot is the first char of a symbol */
{
ch = '.'; /* Restore initial dot */
return(ATOM);
}
}
default:
return(ATOM);
}
}
/***************************************************************/
/* BUILDQ(pres,reg,task) */
/* BUILDQ's purpose is to build a list of the form (quote */
/* nil), and point the field pointed to by PRES to the list. */
/* On exit, PRES points to the cdr of the (quote nil), */
/* enabling easy handling of nested quotes; REG points to the */
/* (quote nil) itself, and TASK is set by FINDTASK(). */
/***************************************************************/
buildq(pres,reg,task)
int pres[2];
int reg[2];
int *task;
{
int temp[2]; /* Temporary register */
C_push(pres); /* Save destination pointer field */
grabcell(reg); /* Grab a cell and point its car to quote */
pres[PG] = ADJPAGE(QUOTE_PAGE);
pres[DS] = QUOTE_DISP;
reg2ptr(pres,reg);
grabcell(pres); /* Grab another cell, point cdr(reg) to it */
reg2cdr(pres,reg);
reg2reg(pres,temp); /* Save second cell address */
C_pop(pres); /* Point destination field to the quote list */
if (pres[PG]) /* if the field exists */
{
if (*task<0)
reg2cdr(reg,pres); /* Place in PRES's cdr field */
else
{
reg2ptr(reg,pres); /* Place in car field */
}
}
reg2reg(temp,pres); /* Recover second cell address */
*task = findtask();
}
***** Code for 'read' turned off 16 July 1985 (JCJ) *****/
/**************
/***************************************************************/
/* READ_ATOM(reg) */
/* Read in an atom (symbol, string, number), using REG as */
/* a scratch register, and store the pointer to the atom in */
/* REG. Special characters such as ')' or ',' are read as */
/* atoms themselves. Normal atoms will end in a whitespace or */
/* a terminating macro character; strings end with the closing */
/* '"'. Numbers in the requested base are interpreted as */
/* such. On exit, the next character in the buffer is the one */
/* following the last character of the atom. */
/***************************************************************/
read_atom(reg)
int reg[2];
{
register int i = 0; /* Index within buffer */
register char c;
char k;
char *bignum; /* Bignum workspace */
char *getmem();
char *stpchr();
int inputch = FALSE; /* Whether the #\ macro is in effect */
int escaped = FALSE; /* Whether an escape character has been used */
int j,pg,ds,siz,base,neg;
double inflo;
extern int CXFERR_status;
CXFERR_status = 0; /* set error code for normal return */
if (ch==' ') /* If ch is a space, form NIL */
{
reg[PG] = reg[DS] = 0;
goto end_of_function;
}
flag_eof = FALSE;
if (!(atomb = getmem(BUFSIZE))) /* Create buffer if possible */
abortread(HEAPERR);
limit = BUFSIZE; /* Initialize buffer size */
base = 10; /* Default base */
switch (ch) /* Read atom into buffer */
{
/* Special-character cases */
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
case '\'':
case '`': *atomb=ch; i++; goto speccase;
/* String case */
case '"': i = delimby('"',i);
alloc_block(reg, STRTYPE, i); /* Allocate string space */
toblock(reg, 3, atomb, i);
goto bye_now;
/* Comma case */
case ',': *atomb=','; i++;
rcvchar();
if ((ch=='@') || (ch=='.'))
{
atomb[1]=ch; i++; goto speccase;
}
goto norcvspec;
/* Macro case */
case '#': flag_eof = TRUE;
while ((ch=='#') && (!i))
{
rcvchar();
if (isspace(ch)) abortread(SHARPERR);
switch (tolower(ch))
{
case 'b': base=2; break;
case 'd': base=10; break;
case 'x':
case 'h': base=16; break;
case 'o': base=8; break;
case '\\': rcvchar();
addchar(i++,ch);
inputch=TRUE; escaped=TRUE;
/* Fall through to BREAK below */
case 'i': /* Ignore (currently) meaningless macros */
case 'e':
case 's':
case 'l': break;
case '<':
case ')': abortread(SHARPERR);
default: *atomb = '#';
atomb[1] = ch;
i = 2;
if (ch=='(') goto speccase;
break;
}
rcvchar();
}
flag_eof = FALSE;
/* Else a symbol */
default: while (!isspace(ch) &&
!stpchr( "()'`;,\"[]{}" , ch) &&
(ch!='\032'))
{
switch (ch=toupper(ch))
{
/* Multiple-escape: read chars until next | */
case '|': escaped = TRUE;
i = delimby('|',i);
break;
/* Single-escape: get next char and put it in */
case '\\': escaped = flag_eof = TRUE;
rcvchar();
flag_eof = FALSE;
default: addchar(i++,ch);
}
rcvchar();
}
} /* End of switch (ch) */
endatom:
addchar(i,'\0'); /* Put null at end of token */
/* Now check for single, unescaped dot (SPECIAL!) */
if ((i==1) && (*atomb=='.') && !escaped) goto norcvspec;
/* At this point a token has been accumulated. Check for number */
j = scannum(atomb,base);
if ((j) && !escaped) /* If a number */
{
if (j>0) /* integer of some size */
{
siz = (j + 9)/2; /* How many bytes needed for int? */
if (!(bignum = getmem(siz)))
{
abortread(HEAPERR);
}
bignum[3] = '\0';
bignum[4] = '\0';
buildint(bignum,atomb,base); /* Form integer */
alloc_int(reg,bignum);
rlsmem(bignum,siz);
}
else /* scan the flonum */
{
scanflo(atomb,&inflo,base);
alloc_flonum(reg,inflo);
}
}
else /* allocate character or interned symbol */
{
if (inputch)
{
reg[PG] = SPECCHAR*2;
if (i==1) reg[DS]=*atomb;
else /* check for a multichar character constant */
{
*atomb = toupper(*atomb); /* convert 1st symbol to uppercase */
for (j=0; j<test_num; j++)
{
if (!strcmp(atomb, test_string[j]))
{
reg[DS]=test_char[j]; break;
}
if (j == test_num-1)
{
alloc_string(tmp_reg, atomb);
set_error(0,"Invalid character constant",tmp_reg);
reg[DS] = '?';
CXFERR_status = -1;
}
} /* end of for(j=0; j<test_num; j++) */
}
}
else /* not a character, but a symbol */
{
intern(reg,atomb,i);
}
}
goto release;
speccase: /* Process the special cases */
intern(reg,atomb,i); /* Intern the symbol and encase in a list */
cons(reg,reg,nil_reg);
goto bye_now;
norcvspec:
intern(reg,atomb,i); /* Intern the symbol and encase in a list */
cons(reg,reg,nil_reg);
release:
if (ch!='\032') pushchar(); /* Put post-atom char back into buffer */
bye_now:
rlsmem(atomb,limit); /* Release the buffer space */
flag_eof = TRUE;
limit = 0;
end_of_function:
return(CXFERR_status);
}
******************************/
/**************************************************************/
/* SCANFLO(s,flo,base) */
/* The string S, which ends in a control char, holds a */
/* representation of a floating-point number. The value of */
/* this number is stored in *FLO. */
/**************************************************************/
scanflo(s,flo,base)
char *s;
double *flo;
int base;
{
int i=0;
int neg=0;
int x=0;
double place;
switch (*s)
{
case '-': neg=-1;
case '+': i++; break;
default: break;
}
while (s[i]=='#') i+=2;
*flo = 0.0;
while (isdig(s[i],base))
{
*flo = (*flo * base) + digval(s[i++]);
}
if (!(s[i]==decpoint)) goto EXPON;
POINT:
i++; place = 1.0;
while (isdig(s[i],base))
{
place /= base;
*flo += place*digval(s[i++]);
}
if (s[i]<' ') goto GOTFLO;
EXPON:
i++;
if (s[i]=='-')
{
i++; place = 1.0/base;
}
else place=base;
while (isdigit(s[i]))
x = (x*10) + digval(s[i++]);
while (x)
{
if (x!=(x>>1)<<1)
*flo *= place;
if (place<1.0e153) place*=place;
x >>= 1;
}
GOTFLO:
if (neg)
*flo = -*flo;
}
/**************************************************************/
/* ALLOC_INT(reg,buf) */
/* This allocates an integer, either a fixnum or a */
/* bignum, depending on the size of the integer, i.e., if */
/* the absolute value < 16384, then a fixnum is allocated. */
/* The value is read from BUF. */
/**************************************************************/
alloc_int(reg,buf)
int reg[2];
char *buf;
{
unsigned i,j;
int pg;
i = 256*buf[1] + buf[0];
j = 256*buf[4] + buf[3];
pg = buf[2] & 1;
if ((i == 1) && (j <= 16383+pg)) /* If fixnum */
alloc_fixnum(reg, (pg ? -j : j));
else
{
alloc_block(reg, BIGTYPE, 2*i + 1);
toblock(reg, 3, buf+2, 2*i +1);
}
}
/**************
/**************************************************************/
/* DELIMBY(c,i) */
/* DELIMBY takes characters from the input stream and */
/* places them in the buffer ATOMB, starting at offset I and */
/* ending when the delimiting character C is reached. This */
/* returns the number of characters stored in ATOMB, and CH */
/* is left equal to C. */
/**************************************************************/
delimby(c,i)
char c;
int i;
{
flag_eof = TRUE; /* Signal any end-of-file error */
rcvchar();
while (ch != c)
{
if (ch != '\r')
{
if (ch == '\\') rcvchar();
addchar(i++,ch);
}
rcvchar();
}
flag_eof = FALSE;
return(i);
}
/**************************************************************/
/* ADDCHAR(i,c) */
/* ADDCHAR takes the character C and places it in the */
/* dynamic atom buffer ATOMB, at offset I. If the buffer can */
/* not contain any more characters, additional space is */
/* allocated, and LIMIT is adjusted accordingly. */
/**************************************************************/
addchar(i,c)
int i;
char c;
{
int j; /* Scratch FOR variable */
char *atom2; /* New atom buffer, if necessary */
char *getmem(); /* Additional memory allocator */
if (i < limit) /* If room for character, put it in */
atomb[i] = c;
else /* Else create a new, larger buffer */
{
if (!(atom2 = getmem(limit + BUFSIZE)))
{
abortread(HEAPERR);
}
for (j = 0; j < limit; j++) atom2[j] = atomb[j];
rlsmem(atomb,limit); /* Discard the old buffer */
atomb = atom2;
atomb[i] = c;
limit += BUFSIZE;
}
}
********************************/
/***** Code for 'read' turned off 16 July 1985 (JCJ) *****
/**************************************************************/
/* DESCEND(reg,pres,prev) */
/* Get a new cons cell, point the car field of [PRES] to */
/* the cell, and update PREV and PRES. */
/**************************************************************/
descend(reg,pres,prev)
int reg[2];
int pres[2];
int prev[2];
{
grabcell(reg);
if (pres[PG]) /* Do only if PRES points to something */
reg2ptr(reg,pres);
reg2reg(pres,prev);
reg2reg(reg,pres);
}
/**************************************************************/
/* BUILDCDR(reg,pres) */
/* Grab a cons cell, point the cdr field of [PRES] to */
/* it, and update PRES. */
/**************************************************************/
buildcdr(reg,pres)
int reg[2];
int pres[2];
{
grabcell(reg);
pres[DS] += PTRSIZE;
reg2ptr(reg,pres);
reg2reg(reg,pres);
}
/**************************************************************/
/* ASCEND(pres,prev) */
/* Set PRES to PREV, and pluck the new value for PREV */
/* from the cdr field of [PREV], replacing it with NIL. */
/**************************************************************/
ascend(pres,prev)
int pres[2];
int prev[2];
{
int i,j; /* Scratch integers */
reg2reg(prev,pres);
j = pres[DS] + PTRSIZE;
i = CORRPAGE(pres[PG]);
/* note: put_byte/put_word return to contents of the byte/word replaced */
prev[PG] = put_byte(i, j++, 0);
prev[DS] = put_word(i, j, 0);
}
/**************************************************************/
/* GRABCELL(reg) */
/* Grab a cons cell, point REG to it, and set it to */
/* (nil . nil). */
/**************************************************************/
grabcell(reg)
int reg[2];
{
int i;
alloc_list_cell(reg);
i = CORRPAGE(reg[PG]);
put_word(i, reg[DS], 0);
put_word(i, reg[DS]+2, 0);
put_word(i, reg[DS]+4, 0);
}
/**************************************************************/
/* REG2PTR(reg,ptr) */
/* Transfer the contents of REG to the pointer field */
/* pointed to by PTR. */
/**************************************************************/
reg2ptr(reg,ptr)
int reg[2];
int ptr[2];
{
put_byte(CORRPAGE(ptr[PG]), (ptr[DS])++, reg[PG]);
put_word(CORRPAGE(ptr[PG]), (ptr[DS])--, reg[DS]);
}
/**************************************************************/
/* REG2CDR(reg,ptr) */
/* Transfer the contents of REG to the cdr field of the */
/* cell pointed to by PTR. */
/**************************************************************/
reg2cdr(reg,ptr)
int reg[2];
int ptr[2];
{
ptr[DS] += PTRSIZE;
reg2ptr(reg,ptr);
ptr[DS] -= PTRSIZE;
}
***** Code for 'read' turned off 16 July 1985 (JCJ) *****/
/*************
/**************************************************************/
/* RCVCHAR() */
/* This fetches a character from the input stream */
/**************************************************************/
rcvchar()
{
register int i;
i = take_ch();
if ((i<256) && (i!=26))
ch = i;
else
{
if (flag_eof) abortread(EOFERR);
else
{
ch = '\032'; /* EOF character */
}
}
}
/**************************************************************/
/* ABORTREAD(code) */
/* Cancels the entire read operation via ABORT, after */
/* resetting some vital registers. */
/**************************************************************/
abortread(code)
int code;
{
if (code == EOFERR)
{
mainreg[PG] = EOF_PAGE*2; /* return "eof" indicator */
mainreg[DS] = EOF_DISP;
}
else
{
mainreg[PG] = mainreg[DS] = 0; /* NILify main register */
}
if (limit) rlsmem(atomb,limit); /* Release buffer memory */
/*****
if (init_stk)
{
TOS = init_stk;
C_pop((mainreg < &regs[3]) ? (mainreg + 4) : (mainreg - 4));
C_pop((mainreg < &regs[3]) ? (mainreg + 2) : (mainreg - 2));
}
*****/
abort(code);
}
/****************************************************************/
/* Skip over Comments */
/****************************************************************/
skipcomments()
{
while (ch == ';')
{
while (ch != '\r') rcvchar();
skipspace();
}
} /* end of function: skipcomments() */
****************************************************/