/* 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; /* 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); 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); 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); }