home *** CD-ROM | disk | FTP | other *** search
- /* xsread.c - xscheme input routines */
- /* Copyright (c) 1988, by David Michael Betz
- All Rights Reserved
- Permission is granted for unrestricted non-commercial use */
-
- #include "xscheme.h"
-
- /* external variables */
- extern LVAL true_lval;
-
- /* external routines */
- extern double atof();
- extern ITYPE;
-
- /* forward declarations */
- LVAL read_list(),read_quote(),read_comma(),read_symbol();
- LVAL read_radix(),read_string(),read_special();
-
- /* xlread - read an expression */
- int xlread(fptr,pval)
- LVAL fptr,*pval;
- {
- int ch;
-
- /* check the next non-blank character */
- while ((ch = scan(fptr)) != EOF)
- switch (ch) {
- case '(':
- *pval = read_list(fptr);
- return (TRUE);
- case ')':
- xlfail("misplaced right paren");
- case '\'':
- *pval = read_quote(fptr,"QUOTE");
- return (TRUE);
- case '`':
- *pval = read_quote(fptr,"QUASIQUOTE");
- return (TRUE);
- case ',':
- *pval = read_comma(fptr);
- return (TRUE);
- case '"':
- *pval = read_string(fptr);
- return (TRUE);
- case '#':
- *pval = read_special(fptr);
- return (TRUE);
- case ';':
- read_comment(fptr);
- break;
- default:
- xlungetc(fptr,ch);
- *pval = read_symbol(fptr);
- return (TRUE);
- }
- return (FALSE);
- }
-
- /* read_list - read a list */
- LOCAL LVAL read_list(fptr)
- LVAL fptr;
- {
- LVAL last,val;
- int ch;
-
- cpush(NIL); last = NIL;
- while ((ch = scan(fptr)) != EOF)
- switch (ch) {
- case ';':
- read_comment(fptr);
- break;
- case ')':
- return (pop());
- default:
- xlungetc(fptr,ch);
- if (!xlread(fptr,&val))
- xlfail("unexpected EOF");
- if (val == xlenter(".")) {
- if (last == NIL)
- xlfail("misplaced dot");
- read_cdr(fptr,last);
- return (pop());
- }
- else {
- val = cons(val,NIL);
- if (last) rplacd(last,val);
- else settop(val);
- last = val;
- }
- break;
- }
- xlfail("unexpected EOF");
- }
-
- /* read_cdr - read the cdr of a dotted pair */
- LOCAL read_cdr(fptr,last)
- LVAL fptr,last;
- {
- LVAL val;
- int ch;
-
- /* read the cdr expression */
- if (!xlread(fptr,&val))
- xlfail("unexpected EOF");
- rplacd(last,val);
-
- /* check for the close paren */
- while ((ch = scan(fptr)) == ';')
- read_comment(fptr);
- if (ch != ')')
- xlfail("missing right paren");
- }
-
- /* read_comment - read a comment (to end of line) */
- LOCAL read_comment(fptr)
- LVAL fptr;
- {
- int ch;
- while ((ch = xlgetc(fptr)) != EOF && ch != '\n')
- ;
- if (ch != EOF) xlungetc(fptr,ch);
- }
-
- /* read_vector - read a vector */
- LOCAL LVAL read_vector(fptr)
- LVAL fptr;
- {
- int len=0,ch,i;
- LVAL last,val;
-
- cpush(NIL); last = NIL;
- while ((ch = scan(fptr)) != EOF)
- switch (ch) {
- case ';':
- read_comment(fptr);
- break;
- case ')':
- val = newvector(len);
- for (last = pop(), i = 0; i < len; ++i, last = cdr(last))
- setelement(val,i,car(last));
- return (val);
- default:
- xlungetc(fptr,ch);
- if (!xlread(fptr,&val))
- xlfail("unexpected EOF");
- val = cons(val,NIL);
- if (last) rplacd(last,val);
- else settop(val);
- last = val;
- ++len;
- break;
- }
- xlfail("unexpected EOF");
- }
-
- /* read_comma - read a unquote or unquote-splicing expression */
- LOCAL LVAL read_comma(fptr)
- LVAL fptr;
- {
- int ch;
- if ((ch = xlgetc(fptr)) == '@')
- return (read_quote(fptr,"UNQUOTE-SPLICING"));
- else {
- xlungetc(fptr,ch);
- return (read_quote(fptr,"UNQUOTE"));
- }
- }
-
- /* read_quote - parse the tail of a quoted expression */
- LOCAL LVAL read_quote(fptr,sym)
- LVAL fptr; char *sym;
- {
- LVAL val;
- if (!xlread(fptr,&val))
- xlfail("unexpected EOF");
- cpush(cons(val,NIL));
- settop(cons(xlenter(sym),top()));
- return (pop());
- }
-
- /* read_symbol - parse a symbol name (or a number) */
- LOCAL LVAL read_symbol(fptr)
- LVAL fptr;
- {
- char buf[STRMAX+1];
- LVAL val;
- if (!getsymbol(fptr,buf))
- xlfail("expecting symbol name");
- return (isnumber(buf,&val) ? val : xlenter(buf));
- }
-
- /* read_string - parse a string */
- LOCAL LVAL read_string(fptr)
- LVAL fptr;
- {
- char buf[STRMAX+1];
- int ch,i;
-
- /* get symbol name */
- for (i = 0; (ch = checkeof(fptr)) != '"'; ) {
- if (ch == '\\')
- ch = checkeof(fptr);
- if (i < STRMAX)
- buf[i++] = ch;
- }
- buf[i] = '\0';
-
- /* return a string */
- return (cvstring(buf));
- }
-
- /* read_special - parse an atom starting with '#' */
- LOCAL LVAL read_special(fptr)
- LVAL fptr;
- {
- char buf[STRMAX+1],buf2[STRMAX+3];
- int ch;
- switch (ch = checkeof(fptr)) {
- case '!':
- if (getsymbol(fptr,buf)) {
- if (strcmp(buf,"TRUE") == 0)
- return (true_lval);
- else if (strcmp(buf,"FALSE") == 0)
- return (NIL);
- else if (strcmp(buf,"NULL") == 0)
- return (NIL);
- else {
- sprintf(buf2,"#!%s",buf);
- return (xlenter(buf2));
- }
- }
- else
- xlfail("expecting symbol after '#!'");
- break;
- case '\\':
- ch = checkeof(fptr); /* get the next character */
- xlungetc(fptr,ch); /* but allow getsymbol to get it also */
- if (getsymbol(fptr,buf)) {
- if (strcmp(buf,"NEWLINE") == 0)
- ch = '\n';
- else if (strcmp(buf,"SPACE") == 0)
- ch = ' ';
- else if (strlen(buf) > 1)
- xlerror("unexpected symbol after '#\\'",cvstring(buf));
- }
- else /* wasn't a symbol, get the character */
- ch = checkeof(fptr);
- return (cvchar(ch));
- case '(':
- return (read_vector(fptr));
- case 'b':
- case 'B':
- return (read_radix(fptr,2));
- case 'o':
- case 'O':
- return (read_radix(fptr,8));
- case 'd':
- case 'D':
- return (read_radix(fptr,10));
- case 'x':
- case 'X':
- return (read_radix(fptr,16));
- default:
- xlungetc(fptr,ch);
- if (getsymbol(fptr,buf)) {
- if (strcmp(buf,"T") == 0)
- return (true_lval);
- else if (strcmp(buf,"F") == 0)
- return (NIL);
- else
- xlerror("unexpected symbol after '#'",cvstring(buf));
- }
- else
- xlerror("unexpected character after '#'",cvchar(xlgetc(fptr)));
- break;
- }
- }
-
- /* read_radix - read a number in a specified radix */
- LOCAL LVAL read_radix(fptr,radix)
- LVAL fptr; int radix;
- {
- FIXTYPE val;
- int ch;
-
- /* get symbol name */
- for (val = (FIXTYPE)0; (ch = xlgetc(fptr)) != EOF && issym(ch); ) {
- if (islower(ch)) ch = toupper(ch);
- if (!isradixdigit(ch,radix))
- xlerror("invalid digit",cvchar(ch));
- val = val * radix + getdigit(ch);
- }
-
- /* save the break character */
- xlungetc(fptr,ch);
-
- /* return the number */
- return (cvfixnum(val));
- }
-
- /* isradixdigit - check to see if a character is a digit in a radix */
- LOCAL int isradixdigit(ch,radix)
- int ch,radix;
- {
- switch (radix) {
- case 2: return (ch >= '0' && ch <= '1');
- case 8: return (ch >= '0' && ch <= '7');
- case 10: return (ch >= '0' && ch <= '9');
- case 16: return ((ch >= '0' && ch <= '9')
- || (ch >= 'A' && ch <= 'F'));
- }
- }
-
- /* getdigit - convert an ascii code to a digit */
- LOCAL int getdigit(ch)
- int ch;
- {
- return (ch <= '9' ? ch - '0' : ch - 'A' + 10);
- }
-
- /* getsymbol - get a symbol name */
- LOCAL int getsymbol(fptr,buf)
- LVAL fptr; char *buf;
- {
- int ch,i;
-
- /* get symbol name */
- for (i = 0; (ch = xlgetc(fptr)) != EOF && issym(ch); )
- if (i < STRMAX)
- buf[i++] = (islower(ch) ? toupper(ch) : ch);
- buf[i] = '\0';
-
- /* save the break character */
- xlungetc(fptr,ch);
- return (buf[0] != '\0');
- }
-
- /* isnumber - check if this string is a number */
- LOCAL int isnumber(str,pval)
- char *str; LVAL *pval;
- {
- int dl,dot,dr;
- char *p;
-
- /* initialize */
- p = str; dl = dot = dr = 0;
-
- /* check for a sign */
- if (*p == '+' || *p == '-')
- p++;
-
- /* check for a string of digits */
- while (isdigit(*p))
- p++, dl++;
-
- /* check for a decimal point */
- if (*p == '.') {
- p++; dot = 1;
- while (isdigit(*p))
- p++, dr++;
- }
-
- /* check for an exponent */
- if ((dl || dr) && *p == 'E') {
- p++; dot = 1;
-
- /* check for a sign */
- if (*p == '+' || *p == '-')
- p++;
-
- /* check for a string of digits */
- while (isdigit(*p))
- p++, dr++;
- }
-
- /* make sure there was at least one digit and this is the end */
- if ((dl == 0 && dr == 0) || *p)
- return (FALSE);
-
- /* convert the string to an integer and return successfully */
- if (pval) {
- if (*str == '+') ++str;
- if (str[strlen(str)-1] == '.') str[strlen(str)-1] = 0;
- *pval = (dot ? cvflonum(atof(str)) : cvfixnum(ICNV(str)));
- }
- return (TRUE);
- }
-
- /* scan - scan for the first non-blank character */
- LOCAL int scan(fptr)
- LVAL fptr;
- {
- int ch;
-
- /* look for a non-blank character */
- while ((ch = xlgetc(fptr)) != EOF && isspace(ch))
- ;
-
- /* return the character */
- return (ch);
- }
-
- /* checkeof - get a character and check for end of file */
- LOCAL int checkeof(fptr)
- LVAL fptr;
- {
- int ch;
- if ((ch = xlgetc(fptr)) == EOF)
- xlfail("unexpected EOF");
- return (ch);
- }
-
- /* issym - is this a symbol character? */
- LOCAL int issym(ch)
- int ch;
- {
- register char *p;
- if (!isspace(ch)) {
- for (p = "()';"; *p != '\0'; )
- if (*p++ == ch)
- return (FALSE);
- return (TRUE);
- }
- return (FALSE);
- }
-