stk/Src/read.c

353 lines
8.9 KiB
C
Raw Normal View History

1996-09-27 06:29:02 -04:00
/*
* r e a d . c -- reading stuff
*
1999-09-05 07:16:41 -04:00
* Copyright <EFBFBD> 1993-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
1996-09-27 06:29:02 -04:00
*
*
1999-09-05 07:16:41 -04:00
* Permission to use, copy, modify, distribute,and license this
* software and its documentation for any purpose is hereby granted,
* provided that existing copyright notices are retained in all
* copies and that this notice is included verbatim in any
* distributions. No written agreement, license, or royalty fee is
* required for any of the authorized uses.
* This software is provided ``AS IS'' without express or implied
* warranty.
1998-04-10 06:59:06 -04:00
*
1996-09-27 06:29:02 -04:00
* Author: Erick Gallesio [eg@unice.fr]
* Creation date: ??-Oct-1993 ??:??
1999-09-05 07:16:41 -04:00
* Last file update: 3-Sep-1999 20:22 (eg)
1996-09-27 06:29:02 -04:00
*
*/
#include <ctype.h>
#include "stk.h"
1998-04-10 06:59:06 -04:00
#include "module.h"
1996-09-27 06:29:02 -04:00
1998-06-09 07:07:40 -04:00
static SCM cycles = NULL; /* used for reading circular data */
static char *proc_name = "read"; /* for Serror macro */
1999-02-02 06:13:40 -05:00
static SCM read_rec(SCM port, int case_significant);
1996-09-27 06:29:02 -04:00
1999-02-02 06:13:40 -05:00
static int flush_ws(SCM port, char *message)
1996-09-27 06:29:02 -04:00
{
1998-04-10 06:59:06 -04:00
int c;
1996-09-27 06:29:02 -04:00
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
for ( ; ; ) {
switch (c) {
1998-06-09 07:07:40 -04:00
case EOF: if (message) Serror(message,NIL); else return(c);
1996-09-27 06:29:02 -04:00
case ';': do
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
while (c != '\n' && c != EOF);
continue;
case '\n': STk_line_counter += 1; break;
default: if (!isspace(c)) return(c);
}
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
}
}
1999-02-02 06:13:40 -05:00
static SCM read_list(SCM port, char delim, int case_significant)
1996-09-27 06:29:02 -04:00
/* Read a list ended by the `delim' char */
{
int c;
SCM tmp;
1999-02-02 06:13:40 -05:00
c = flush_ws(port, "End of file inside list");
1996-09-27 06:29:02 -04:00
if (c == delim) return(NIL);
/* Read the car */
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
tmp = read_rec(port, case_significant);
1996-09-27 06:29:02 -04:00
/* Read the cdr */
if (EQ(tmp, Sym_dot)) {
1999-02-02 06:13:40 -05:00
tmp = read_rec(port, case_significant);
c = flush_ws(port, "End of file inside list");
1998-06-09 07:07:40 -04:00
if (c != delim) Serror("missing close parenthesis", NIL);
1996-09-27 06:29:02 -04:00
return(tmp);
}
1999-02-02 06:13:40 -05:00
return(Cons(tmp, read_list(port, delim, case_significant)));
1996-09-27 06:29:02 -04:00
}
1999-02-02 06:13:40 -05:00
static void read_word(SCM port, int c, int case_significant)
1996-09-27 06:29:02 -04:00
/* read an item whose 1st char is in c */
{
register int j = 0;
int allchars = 0;
for( ; ; ) {
allchars ^= (c == '|');
if (c != '|')
STk_tkbuffer[j++] = (allchars || case_significant) ? c : tolower(c);
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
if (c == EOF) break;
if (!allchars) {
if (strchr("()[]'`,;\"\n", c)) {
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
1996-09-27 06:29:02 -04:00
break;
}
if (isspace(c)) break;
}
1998-06-09 07:07:40 -04:00
if (j >= TKBUFFERN-1) Serror("token too large", NIL);
1996-09-27 06:29:02 -04:00
}
STk_tkbuffer[j] = '\0';
}
1999-02-02 06:13:40 -05:00
static void read_char(SCM port, int c)
1996-09-27 06:29:02 -04:00
/* read an char (or a char name) item whose 1st char is in c */
{
register int j = 0;
for( ; ; ) {
STk_tkbuffer[j++] = c;
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
if (c == EOF || isspace(c)) break;
if (strchr("()[]'`,;\"", c)) {
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
1996-09-27 06:29:02 -04:00
break;
}
1998-06-09 07:07:40 -04:00
if (j >= TKBUFFERN-1) Serror("token too large", NIL);
1996-09-27 06:29:02 -04:00
}
STk_tkbuffer[j] = '\0';
}
1999-02-02 06:13:40 -05:00
static SCM read_token(SCM port, int c, int case_significant)
1996-09-27 06:29:02 -04:00
{
SCM z;
1999-02-02 06:13:40 -05:00
read_word(port, c, case_significant);
1996-09-27 06:29:02 -04:00
z = STk_Cstr2number(STk_tkbuffer, 10L);
if (z == Ntruth)
/* It is not a number */
1998-04-10 06:59:06 -04:00
switch (*STk_tkbuffer) {
case ':': return STk_makekey(STk_tkbuffer);
1998-06-09 07:07:40 -04:00
case '#': Serror("bad # syntax", STk_makestring(STk_tkbuffer));
1998-04-10 06:59:06 -04:00
default : return Intern(STk_tkbuffer);
}
1996-09-27 06:29:02 -04:00
/* Return the number read */
return z;
}
1999-02-02 06:13:40 -05:00
static SCM read_cycle(SCM port, int c, int case_significant)
1998-06-09 07:07:40 -04:00
/* read a #xx# or #xx= cycle item whose 1st char is in c. */
{
register int j = 0;
for( ; ; ) {
STk_tkbuffer[j++] = c;
1999-02-02 06:13:40 -05:00
c = Getc(port);
1998-06-09 07:07:40 -04:00
if (c == EOF || !isdigit(c)) break;
if (j >= TKBUFFERN-1) Serror("token too large", NIL);
}
STk_tkbuffer[j] = '\0';
switch (c) {
case '#': {
SCM tmp, k = STk_makeinteger(atoi(STk_tkbuffer));
if ((tmp = STk_assv(k, cycles)) != Ntruth) {
return CDR(tmp);
}
else {
char buffer[70];
sprintf(buffer, "key ``#%d='' not defined", atoi(STk_tkbuffer));
Serror(buffer, NIL);
}
}
case '=': {
SCM val, tmp, k = STk_makeinteger(atoi(STk_tkbuffer));
if ((tmp = STk_assv(k, cycles)) == Ntruth) {
/* This is a little bit tricky here: We create a fake cell
* that could be referenced by the further read. Once the read
* is finished, we overwrite the fake cell with the value
* returned by the read. So, the fake cell becomes the real
* result (not too clear :-).
* ATTENTION: the value returned the next read can be of
* any type (e.g. '(1 2 #0="ab" #0#) ). But all our cells
* have the same size => no problem.
*/
1999-02-02 06:13:40 -05:00
tmp = Cons(UNBOUND, UNBOUND); /* The fake cell */
cycles = Cons(Cons(k, tmp), cycles); /* For next read */
val = read_rec(port, case_significant);/* Read item */
*tmp = *val; /*Overwrt fake cell*/
1998-06-09 07:07:40 -04:00
return tmp;
}
else {
char buffer[70];
sprintf(buffer, "key ``#%d='' already defined",
atoi(STk_tkbuffer))
;
Serror(buffer, NIL);
}
}
1999-02-02 06:13:40 -05:00
default: Ungetc(c, port); Serror("bad # syntax", STk_makestring(STk_tkbuffer));
1998-06-09 07:07:40 -04:00
}
return UNBOUND; /* for the compiler */
}
1999-02-02 06:13:40 -05:00
static SCM read_string(SCM port)
1996-09-27 06:29:02 -04:00
{
1999-02-02 06:13:40 -05:00
int k ,c,n;
size_t j, len;
1996-09-27 06:29:02 -04:00
char *p, *buffer;
SCM z;
j = 0;
len = 100;
p = buffer = must_malloc(len);
1999-02-02 06:13:40 -05:00
while(((c = Getc(port)) != '"') && (c != EOF)) {
1996-09-27 06:29:02 -04:00
if (c == '\\') {
1999-02-02 06:13:40 -05:00
c = Getc(port);
1998-06-09 07:07:40 -04:00
if (c == EOF) Serror("eof encountered after \\", NIL);
1996-09-27 06:29:02 -04:00
switch(c) {
case 'b' : c = '\b'; break; /* Bs */
case 'e' : c = 0x1b; break; /* Esc */
case 'n' : c = '\n'; break; /* Lf */
case 'r' : c = '\r'; break; /* Cr */
case 't' : c = '\t'; break; /* Tab */
case '\n': STk_line_counter += 1; continue;
case '0' : for( k=n=0 ; ; k++ ) {
1999-02-02 06:13:40 -05:00
c = Getc(port);
1998-06-09 07:07:40 -04:00
if (c == EOF) Serror("eof encountered after \\0", NIL);
1996-09-27 06:29:02 -04:00
if (isdigit(c) && (c < '8') && k < 3) /* Max = 3 digits */
n = n * 8 + c - '0';
else {
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
1996-09-27 06:29:02 -04:00
break;
}
}
c = n & 0xff;
}
}
else
if (c == '\n') STk_line_counter += 1;
if ((j + 1) >= len) {
len = len + len / 2;
buffer = must_realloc(buffer, len);
p = buffer + j;
}
j++;
*p++ = c;
}
1998-06-09 07:07:40 -04:00
if (c == EOF) Serror("end of file while reading a string", NIL);
1996-09-27 06:29:02 -04:00
*p = '\0';
z = STk_makestrg(j, buffer);
free(buffer);
return z;
}
1999-02-02 06:13:40 -05:00
static SCM read_rec(SCM port, int case_significant)
1996-09-27 06:29:02 -04:00
{
int c;
for ( ; ; ) {
1999-02-02 06:13:40 -05:00
c = flush_ws(port, "end of file inside read encountered");
1996-09-27 06:29:02 -04:00
switch (c) {
case '(':
1999-02-02 06:13:40 -05:00
return(read_list(port, ')', case_significant));
1996-09-27 06:29:02 -04:00
case '[':
1999-02-02 06:13:40 -05:00
return(read_list(port, ']', case_significant));
1996-09-27 06:29:02 -04:00
case ')':
case ']':
1999-02-02 06:13:40 -05:00
Puts("\nread: unexpected close parenthesis", STk_curr_eport);
1996-09-27 06:29:02 -04:00
if (STk_current_filename != UNBOUND)
1999-02-02 06:13:40 -05:00
Fprintf(STk_curr_eport, " at line %d in file %s",
1996-09-27 06:29:02 -04:00
STk_line_counter, CHARS(STk_current_filename));
1999-02-02 06:13:40 -05:00
Putc('\n', STk_curr_eport);
Flush(STk_curr_eport);
1996-09-27 06:29:02 -04:00
break;
case '\'':
1999-02-02 06:13:40 -05:00
return LIST2(Sym_quote, read_rec(port, case_significant));
1996-09-27 06:29:02 -04:00
case '`':
1999-02-02 06:13:40 -05:00
return LIST2(Sym_quasiquote, read_rec(port, case_significant));
1996-09-27 06:29:02 -04:00
case '#':
1999-02-02 06:13:40 -05:00
switch(c=Getc(port)) {
1996-09-27 06:29:02 -04:00
case 't':
case 'T': return Truth;
case 'f':
case 'F': return Ntruth;
1999-02-02 06:13:40 -05:00
case '\\': read_char(port, Getc(port));
1996-09-27 06:29:02 -04:00
return STk_makechar(STk_string2char(STk_tkbuffer));
case '(' : {
1999-02-02 06:13:40 -05:00
SCM l = read_list(port, ')', case_significant);
1996-09-27 06:29:02 -04:00
return STk_vector(l, STk_llength(l));
}
1999-02-02 06:13:40 -05:00
case '!' : while ((c=Getc(port)) != '\n')
1998-04-10 06:59:06 -04:00
if (c == EOF) return STk_eof_object;
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
1996-09-27 06:29:02 -04:00
continue;
1998-04-10 06:59:06 -04:00
case '|': do
do
if (c == '\n') STk_line_counter += 1;
1999-02-02 06:13:40 -05:00
while ((c != EOF) && (c = Getc(port)) != '|');
while ((c != EOF) && (c = Getc(port)) != '#');
1998-04-10 06:59:06 -04:00
1999-02-02 06:13:40 -05:00
c = flush_ws(port, (char *) NULL);
1998-04-10 06:59:06 -04:00
if (c == EOF) return STk_eof_object;
1999-02-02 06:13:40 -05:00
Ungetc(c,port);
1998-04-10 06:59:06 -04:00
continue;
1996-09-27 06:29:02 -04:00
case 'p':
1999-02-02 06:13:40 -05:00
case 'P': read_word(port, Getc(port), TRUE);
1996-09-27 06:29:02 -04:00
return STk_address2object(STk_tkbuffer);
1999-02-02 06:13:40 -05:00
case '.': return STk_eval(read_rec(port, case_significant),
1998-04-10 06:59:06 -04:00
MOD_ENV(STk_selected_module));
1998-06-09 07:07:40 -04:00
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
1999-02-02 06:13:40 -05:00
case '9': return read_cycle(port, c, case_significant);
default: Ungetc(c, port); return read_token(port, '#', FALSE);
1996-09-27 06:29:02 -04:00
}
case ',': {
SCM symb;
1999-02-02 06:13:40 -05:00
c = Getc(port);
1996-09-27 06:29:02 -04:00
if (c == '@')
symb = Sym_unq_splicing;
else {
symb = Sym_unquote;
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
1996-09-27 06:29:02 -04:00
}
1999-02-02 06:13:40 -05:00
return LIST2(symb, read_rec(port, case_significant));
1996-09-27 06:29:02 -04:00
}
case '"':
1999-02-02 06:13:40 -05:00
return read_string(port);
1996-09-27 06:29:02 -04:00
default:
1999-02-02 06:13:40 -05:00
return read_token(port, c, case_significant);
1996-09-27 06:29:02 -04:00
}
}
}
1999-02-02 06:13:40 -05:00
SCM STk_readf(SCM port, int case_significant)
1996-09-27 06:29:02 -04:00
{
int c;
1998-06-09 07:07:40 -04:00
if (cycles == NULL) STk_gc_protect(&cycles);
cycles = NIL;
1999-02-02 06:13:40 -05:00
c = flush_ws(port, (char *) NULL);
1996-09-27 06:29:02 -04:00
if (c == EOF) return(STk_eof_object);
1999-02-02 06:13:40 -05:00
Ungetc(c, port);
return read_rec(port, case_significant);
1996-09-27 06:29:02 -04:00
}