better solution for allowing an input stream to be relocated while
reading from it improving prettyprinting of lists of short strings
This commit is contained in:
parent
76edead57b
commit
6c56120669
|
@ -82,6 +82,7 @@ static value_t relocate(value_t v);
|
||||||
typedef struct _readstate_t {
|
typedef struct _readstate_t {
|
||||||
htable_t backrefs;
|
htable_t backrefs;
|
||||||
htable_t gensyms;
|
htable_t gensyms;
|
||||||
|
value_t source;
|
||||||
struct _readstate_t *prev;
|
struct _readstate_t *prev;
|
||||||
} readstate_t;
|
} readstate_t;
|
||||||
static readstate_t *readstate = NULL;
|
static readstate_t *readstate = NULL;
|
||||||
|
@ -470,6 +471,7 @@ void gc(int mustgrow)
|
||||||
rs->backrefs.table[i] = (void*)relocate((value_t)rs->backrefs.table[i]);
|
rs->backrefs.table[i] = (void*)relocate((value_t)rs->backrefs.table[i]);
|
||||||
for(i=0; i < rs->gensyms.size; i++)
|
for(i=0; i < rs->gensyms.size; i++)
|
||||||
rs->gensyms.table[i] = (void*)relocate((value_t)rs->gensyms.table[i]);
|
rs->gensyms.table[i] = (void*)relocate((value_t)rs->gensyms.table[i]);
|
||||||
|
rs->source = relocate(rs->source);
|
||||||
rs = rs->prev;
|
rs = rs->prev;
|
||||||
}
|
}
|
||||||
lasterror = relocate(lasterror);
|
lasterror = relocate(lasterror);
|
||||||
|
@ -1543,6 +1545,8 @@ static value_t argv_list(int argc, char *argv[])
|
||||||
|
|
||||||
int locale_is_utf8;
|
int locale_is_utf8;
|
||||||
|
|
||||||
|
extern value_t fl_file(value_t *args, uint32_t nargs);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
value_t e, v;
|
value_t e, v;
|
||||||
|
@ -1559,17 +1563,20 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
strcat(fname_buf, "system.lsp");
|
strcat(fname_buf, "system.lsp");
|
||||||
|
|
||||||
ios_t fi; ios_t *f = &fi;
|
|
||||||
FL_TRY {
|
FL_TRY {
|
||||||
// install toplevel exception handler
|
// install toplevel exception handler
|
||||||
f = ios_file(f, fname_buf, 1, 0, 0, 0);
|
PUSH(cvalue_static_cstring(fname_buf));
|
||||||
if (f == NULL) lerror(IOError, "file \"%s\" not found", fname_buf);
|
PUSH(symbol(":read"));
|
||||||
|
value_t f = fl_file(&Stack[SP-2], 2);
|
||||||
|
POPN(2);
|
||||||
|
PUSH(f);
|
||||||
while (1) {
|
while (1) {
|
||||||
e = read_sexpr(f);
|
e = read_sexpr(Stack[SP-1]);
|
||||||
if (ios_eof(f)) break;
|
if (ios_eof(value2c(ios_t*,Stack[SP-1]))) break;
|
||||||
v = toplevel_eval(e);
|
v = toplevel_eval(e);
|
||||||
}
|
}
|
||||||
ios_close(f);
|
ios_close(value2c(ios_t*,Stack[SP-1]));
|
||||||
|
(void)POP();
|
||||||
|
|
||||||
PUSH(symbol_value(symbol("__start")));
|
PUSH(symbol_value(symbol("__start")));
|
||||||
PUSH(argv_list(argc, argv));
|
PUSH(argv_list(argc, argv));
|
||||||
|
|
|
@ -120,7 +120,7 @@ enum {
|
||||||
extern value_t NIL, FL_T, FL_F;
|
extern value_t NIL, FL_T, FL_F;
|
||||||
|
|
||||||
/* read, eval, print main entry points */
|
/* read, eval, print main entry points */
|
||||||
value_t read_sexpr(ios_t *f);
|
value_t read_sexpr(value_t f);
|
||||||
void print(ios_t *f, value_t v, int princ);
|
void print(ios_t *f, value_t v, int princ);
|
||||||
value_t toplevel_eval(value_t expr);
|
value_t toplevel_eval(value_t expr);
|
||||||
value_t apply(value_t f, value_t l);
|
value_t apply(value_t f, value_t l);
|
||||||
|
|
|
@ -85,15 +85,8 @@ value_t fl_read(value_t *args, u_int32_t nargs)
|
||||||
PUSH(symbol_value(instrsym));
|
PUSH(symbol_value(instrsym));
|
||||||
args = &Stack[SP-1];
|
args = &Stack[SP-1];
|
||||||
}
|
}
|
||||||
ios_t *s = toiostream(args[0], "read");
|
(void)toiostream(args[0], "read");
|
||||||
// temporarily pin the stream while reading
|
return read_sexpr(args[0]);
|
||||||
ios_t temp = *s;
|
|
||||||
if (s->buf == &s->local[0])
|
|
||||||
temp.buf = &temp.local[0];
|
|
||||||
value_t v = read_sexpr(&temp);
|
|
||||||
s = value2c(ios_t*, args[0]);
|
|
||||||
*s = temp;
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t fl_iogetc(value_t *args, u_int32_t nargs)
|
value_t fl_iogetc(value_t *args, u_int32_t nargs)
|
||||||
|
|
|
@ -139,10 +139,13 @@ static void print_symbol_name(ios_t *f, char *name)
|
||||||
pathological or deeply-nested expressions, but those are difficult
|
pathological or deeply-nested expressions, but those are difficult
|
||||||
to print anyway.
|
to print anyway.
|
||||||
*/
|
*/
|
||||||
|
#define SMALL_STR_LEN 20
|
||||||
static inline int tinyp(value_t v)
|
static inline int tinyp(value_t v)
|
||||||
{
|
{
|
||||||
if (issymbol(v))
|
if (issymbol(v))
|
||||||
return (u8_strwidth(symbol_name(v)) < 20);
|
return (u8_strwidth(symbol_name(v)) < SMALL_STR_LEN);
|
||||||
|
if (isstring(v))
|
||||||
|
return (cv_len((cvalue_t*)ptr(v)) < SMALL_STR_LEN);
|
||||||
return (isfixnum(v) || isbuiltinish(v));
|
return (isfixnum(v) || isbuiltinish(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
femtolisp/read.c
131
femtolisp/read.c
|
@ -6,6 +6,8 @@ enum {
|
||||||
TOK_SHARPSEMI
|
TOK_SHARPSEMI
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define F value2c(ios_t*,readstate->source)
|
||||||
|
|
||||||
// defines which characters are ordinary symbol characters.
|
// defines which characters are ordinary symbol characters.
|
||||||
// exceptions are '.', which is an ordinary symbol character
|
// exceptions are '.', which is an ordinary symbol character
|
||||||
// unless it's the only character in the symbol, and '#', which is
|
// unless it's the only character in the symbol, and '#', which is
|
||||||
|
@ -85,20 +87,20 @@ static u_int32_t toktype = TOK_NONE;
|
||||||
static value_t tokval;
|
static value_t tokval;
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
|
|
||||||
static char nextchar(ios_t *f)
|
static char nextchar()
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
return 0;
|
return 0;
|
||||||
c = (char)ch;
|
c = (char)ch;
|
||||||
if (c == ';') {
|
if (c == ';') {
|
||||||
// single-line comment
|
// single-line comment
|
||||||
do {
|
do {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
return 0;
|
return 0;
|
||||||
} while ((char)ch != '\n');
|
} while ((char)ch != '\n');
|
||||||
|
@ -121,13 +123,13 @@ static void accumchar(char c, int *pi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return: 1 if escaped (forced to be symbol)
|
// return: 1 if escaped (forced to be symbol)
|
||||||
static int read_token(ios_t *f, char c, int digits)
|
static int read_token(char c, int digits)
|
||||||
{
|
{
|
||||||
int i=0, ch, escaped=0, issym=0, first=1;
|
int i=0, ch, escaped=0, issym=0, first=1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
goto terminate;
|
goto terminate;
|
||||||
c = (char)ch;
|
c = (char)ch;
|
||||||
|
@ -139,7 +141,7 @@ static int read_token(ios_t *f, char c, int digits)
|
||||||
}
|
}
|
||||||
else if (c == '\\') {
|
else if (c == '\\') {
|
||||||
issym = 1;
|
issym = 1;
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
goto terminate;
|
goto terminate;
|
||||||
accumchar((char)ch, &i);
|
accumchar((char)ch, &i);
|
||||||
|
@ -151,13 +153,13 @@ static int read_token(ios_t *f, char c, int digits)
|
||||||
accumchar(c, &i);
|
accumchar(c, &i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ios_ungetc(c, f);
|
ios_ungetc(c, F);
|
||||||
terminate:
|
terminate:
|
||||||
buf[i++] = '\0';
|
buf[i++] = '\0';
|
||||||
return issym;
|
return issym;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u_int32_t peek(ios_t *f)
|
static u_int32_t peek()
|
||||||
{
|
{
|
||||||
char c, *end;
|
char c, *end;
|
||||||
fixnum_t x;
|
fixnum_t x;
|
||||||
|
@ -165,8 +167,8 @@ static u_int32_t peek(ios_t *f)
|
||||||
|
|
||||||
if (toktype != TOK_NONE)
|
if (toktype != TOK_NONE)
|
||||||
return toktype;
|
return toktype;
|
||||||
c = nextchar(f);
|
c = nextchar();
|
||||||
if (ios_eof(f)) return TOK_NONE;
|
if (ios_eof(F)) return TOK_NONE;
|
||||||
if (c == '(') {
|
if (c == '(') {
|
||||||
toktype = TOK_OPEN;
|
toktype = TOK_OPEN;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +191,7 @@ static u_int32_t peek(ios_t *f)
|
||||||
toktype = TOK_DOUBLEQUOTE;
|
toktype = TOK_DOUBLEQUOTE;
|
||||||
}
|
}
|
||||||
else if (c == '#') {
|
else if (c == '#') {
|
||||||
ch = ios_getc(f); c = (char)ch;
|
ch = ios_getc(F); c = (char)ch;
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
lerror(ParseError, "read: invalid read macro");
|
lerror(ParseError, "read: invalid read macro");
|
||||||
if (c == '.') {
|
if (c == '.') {
|
||||||
|
@ -200,7 +202,7 @@ static u_int32_t peek(ios_t *f)
|
||||||
}
|
}
|
||||||
else if (c == '\\') {
|
else if (c == '\\') {
|
||||||
uint32_t cval;
|
uint32_t cval;
|
||||||
if (ios_getutf8(f, &cval) == IOS_EOF)
|
if (ios_getutf8(F, &cval) == IOS_EOF)
|
||||||
lerror(ParseError, "read: end of input in character constant");
|
lerror(ParseError, "read: end of input in character constant");
|
||||||
toktype = TOK_NUM;
|
toktype = TOK_NUM;
|
||||||
tokval = mk_wchar(cval);
|
tokval = mk_wchar(cval);
|
||||||
|
@ -212,8 +214,8 @@ static u_int32_t peek(ios_t *f)
|
||||||
lerror(ParseError, "read: unreadable object");
|
lerror(ParseError, "read: unreadable object");
|
||||||
}
|
}
|
||||||
else if (isdigit(c)) {
|
else if (isdigit(c)) {
|
||||||
read_token(f, c, 1);
|
read_token(c, 1);
|
||||||
c = (char)ios_getc(f);
|
c = (char)ios_getc(F);
|
||||||
if (c == '#')
|
if (c == '#')
|
||||||
toktype = TOK_BACKREF;
|
toktype = TOK_BACKREF;
|
||||||
else if (c == '=')
|
else if (c == '=')
|
||||||
|
@ -229,20 +231,20 @@ static u_int32_t peek(ios_t *f)
|
||||||
else if (c == '!') {
|
else if (c == '!') {
|
||||||
// #! single line comment for shbang script support
|
// #! single line comment for shbang script support
|
||||||
do {
|
do {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
} while (ch != IOS_EOF && (char)ch != '\n');
|
} while (ch != IOS_EOF && (char)ch != '\n');
|
||||||
return peek(f);
|
return peek();
|
||||||
}
|
}
|
||||||
else if (c == '|') {
|
else if (c == '|') {
|
||||||
// multiline comment
|
// multiline comment
|
||||||
int commentlevel=1;
|
int commentlevel=1;
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
hashpipe_gotc:
|
hashpipe_gotc:
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
lerror(ParseError, "read: eof within comment");
|
lerror(ParseError, "read: eof within comment");
|
||||||
if ((char)ch == '|') {
|
if ((char)ch == '|') {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if ((char)ch == '#') {
|
if ((char)ch == '#') {
|
||||||
commentlevel--;
|
commentlevel--;
|
||||||
if (commentlevel == 0)
|
if (commentlevel == 0)
|
||||||
|
@ -253,7 +255,7 @@ static u_int32_t peek(ios_t *f)
|
||||||
goto hashpipe_gotc;
|
goto hashpipe_gotc;
|
||||||
}
|
}
|
||||||
else if ((char)ch == '#') {
|
else if ((char)ch == '#') {
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if ((char)ch == '|')
|
if ((char)ch == '|')
|
||||||
commentlevel++;
|
commentlevel++;
|
||||||
else
|
else
|
||||||
|
@ -261,17 +263,17 @@ static u_int32_t peek(ios_t *f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this was whitespace, so keep peeking
|
// this was whitespace, so keep peeking
|
||||||
return peek(f);
|
return peek();
|
||||||
}
|
}
|
||||||
else if (c == ';') {
|
else if (c == ';') {
|
||||||
toktype = TOK_SHARPSEMI;
|
toktype = TOK_SHARPSEMI;
|
||||||
}
|
}
|
||||||
else if (c == ':') {
|
else if (c == ':') {
|
||||||
// gensym
|
// gensym
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if ((char)ch == 'g')
|
if ((char)ch == 'g')
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
read_token(f, (char)ch, 0);
|
read_token((char)ch, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
x = strtol(buf, &end, 10);
|
x = strtol(buf, &end, 10);
|
||||||
if (*end != '\0' || buf[0] == '\0' || errno)
|
if (*end != '\0' || buf[0] == '\0' || errno)
|
||||||
|
@ -280,7 +282,7 @@ static u_int32_t peek(ios_t *f)
|
||||||
tokval = fixnum(x);
|
tokval = fixnum(x);
|
||||||
}
|
}
|
||||||
else if (symchar(c)) {
|
else if (symchar(c)) {
|
||||||
read_token(f, ch, 0);
|
read_token(ch, 0);
|
||||||
|
|
||||||
if (((c == 'b' && (base= 2)) ||
|
if (((c == 'b' && (base= 2)) ||
|
||||||
(c == 'o' && (base= 8)) ||
|
(c == 'o' && (base= 8)) ||
|
||||||
|
@ -300,7 +302,7 @@ static u_int32_t peek(ios_t *f)
|
||||||
}
|
}
|
||||||
else if (c == ',') {
|
else if (c == ',') {
|
||||||
toktype = TOK_COMMA;
|
toktype = TOK_COMMA;
|
||||||
ch = ios_getc(f);
|
ch = ios_getc(F);
|
||||||
if (ch == IOS_EOF)
|
if (ch == IOS_EOF)
|
||||||
return toktype;
|
return toktype;
|
||||||
if ((char)ch == '@')
|
if ((char)ch == '@')
|
||||||
|
@ -308,10 +310,10 @@ static u_int32_t peek(ios_t *f)
|
||||||
else if ((char)ch == '.')
|
else if ((char)ch == '.')
|
||||||
toktype = TOK_COMMADOT;
|
toktype = TOK_COMMADOT;
|
||||||
else
|
else
|
||||||
ios_ungetc((char)ch, f);
|
ios_ungetc((char)ch, F);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!read_token(f, c, 0)) {
|
if (!read_token(c, 0)) {
|
||||||
if (buf[0]=='.' && buf[1]=='\0') {
|
if (buf[0]=='.' && buf[1]=='\0') {
|
||||||
return (toktype=TOK_DOT);
|
return (toktype=TOK_DOT);
|
||||||
}
|
}
|
||||||
|
@ -326,21 +328,21 @@ static u_int32_t peek(ios_t *f)
|
||||||
return toktype;
|
return toktype;
|
||||||
}
|
}
|
||||||
|
|
||||||
static value_t do_read_sexpr(ios_t *f, value_t label);
|
static value_t do_read_sexpr(value_t label);
|
||||||
|
|
||||||
static value_t read_vector(ios_t *f, value_t label, u_int32_t closer)
|
static value_t read_vector(value_t label, u_int32_t closer)
|
||||||
{
|
{
|
||||||
value_t v=alloc_vector(4, 1), elt;
|
value_t v=alloc_vector(4, 1), elt;
|
||||||
u_int32_t i=0;
|
u_int32_t i=0;
|
||||||
PUSH(v);
|
PUSH(v);
|
||||||
if (label != UNBOUND)
|
if (label != UNBOUND)
|
||||||
ptrhash_put(&readstate->backrefs, (void*)label, (void*)v);
|
ptrhash_put(&readstate->backrefs, (void*)label, (void*)v);
|
||||||
while (peek(f) != closer) {
|
while (peek() != closer) {
|
||||||
if (ios_eof(f))
|
if (ios_eof(F))
|
||||||
lerror(ParseError, "read: unexpected end of input");
|
lerror(ParseError, "read: unexpected end of input");
|
||||||
if (i >= vector_size(v))
|
if (i >= vector_size(v))
|
||||||
Stack[SP-1] = vector_grow(v);
|
Stack[SP-1] = vector_grow(v);
|
||||||
elt = do_read_sexpr(f, UNBOUND);
|
elt = do_read_sexpr(UNBOUND);
|
||||||
v = Stack[SP-1];
|
v = Stack[SP-1];
|
||||||
vector_elt(v,i) = elt;
|
vector_elt(v,i) = elt;
|
||||||
i++;
|
i++;
|
||||||
|
@ -350,7 +352,7 @@ static value_t read_vector(ios_t *f, value_t label, u_int32_t closer)
|
||||||
return POP();
|
return POP();
|
||||||
}
|
}
|
||||||
|
|
||||||
static value_t read_string(ios_t *f)
|
static value_t read_string()
|
||||||
{
|
{
|
||||||
char *buf, *temp;
|
char *buf, *temp;
|
||||||
char eseq[10];
|
char eseq[10];
|
||||||
|
@ -370,7 +372,7 @@ static value_t read_string(ios_t *f)
|
||||||
}
|
}
|
||||||
buf = temp;
|
buf = temp;
|
||||||
}
|
}
|
||||||
c = ios_getc(f);
|
c = ios_getc(F);
|
||||||
if (c == IOS_EOF) {
|
if (c == IOS_EOF) {
|
||||||
free(buf);
|
free(buf);
|
||||||
lerror(ParseError, "read: unexpected end of input in string");
|
lerror(ParseError, "read: unexpected end of input in string");
|
||||||
|
@ -378,7 +380,7 @@ static value_t read_string(ios_t *f)
|
||||||
if (c == '"')
|
if (c == '"')
|
||||||
break;
|
break;
|
||||||
else if (c == '\\') {
|
else if (c == '\\') {
|
||||||
c = ios_getc(f);
|
c = ios_getc(F);
|
||||||
if (c == IOS_EOF) {
|
if (c == IOS_EOF) {
|
||||||
free(buf);
|
free(buf);
|
||||||
lerror(ParseError, "read: end of input in escape sequence");
|
lerror(ParseError, "read: end of input in escape sequence");
|
||||||
|
@ -387,9 +389,9 @@ static value_t read_string(ios_t *f)
|
||||||
if (octal_digit(c)) {
|
if (octal_digit(c)) {
|
||||||
do {
|
do {
|
||||||
eseq[j++] = c;
|
eseq[j++] = c;
|
||||||
c = ios_getc(f);
|
c = ios_getc(F);
|
||||||
} while (octal_digit(c) && j<3 && (c!=IOS_EOF));
|
} while (octal_digit(c) && j<3 && (c!=IOS_EOF));
|
||||||
if (c!=IOS_EOF) ios_ungetc(c, f);
|
if (c!=IOS_EOF) ios_ungetc(c, F);
|
||||||
eseq[j] = '\0';
|
eseq[j] = '\0';
|
||||||
wc = strtol(eseq, NULL, 8);
|
wc = strtol(eseq, NULL, 8);
|
||||||
// \DDD and \xXX read bytes, not characters
|
// \DDD and \xXX read bytes, not characters
|
||||||
|
@ -398,12 +400,12 @@ static value_t read_string(ios_t *f)
|
||||||
else if ((c=='x' && (ndig=2)) ||
|
else if ((c=='x' && (ndig=2)) ||
|
||||||
(c=='u' && (ndig=4)) ||
|
(c=='u' && (ndig=4)) ||
|
||||||
(c=='U' && (ndig=8))) {
|
(c=='U' && (ndig=8))) {
|
||||||
c = ios_getc(f);
|
c = ios_getc(F);
|
||||||
while (hex_digit(c) && j<ndig && (c!=IOS_EOF)) {
|
while (hex_digit(c) && j<ndig && (c!=IOS_EOF)) {
|
||||||
eseq[j++] = c;
|
eseq[j++] = c;
|
||||||
c = ios_getc(f);
|
c = ios_getc(F);
|
||||||
}
|
}
|
||||||
if (c!=IOS_EOF) ios_ungetc(c, f);
|
if (c!=IOS_EOF) ios_ungetc(c, F);
|
||||||
eseq[j] = '\0';
|
eseq[j] = '\0';
|
||||||
if (j) wc = strtol(eseq, NULL, 16);
|
if (j) wc = strtol(eseq, NULL, 16);
|
||||||
else {
|
else {
|
||||||
|
@ -432,16 +434,16 @@ static value_t read_string(ios_t *f)
|
||||||
// build a list of conses. this is complicated by the fact that all conses
|
// build a list of conses. this is complicated by the fact that all conses
|
||||||
// can move whenever a new cons is allocated. we have to refer to every cons
|
// can move whenever a new cons is allocated. we have to refer to every cons
|
||||||
// through a handle to a relocatable pointer (i.e. a pointer on the stack).
|
// through a handle to a relocatable pointer (i.e. a pointer on the stack).
|
||||||
static void read_list(ios_t *f, value_t *pval, value_t label)
|
static void read_list(value_t *pval, value_t label)
|
||||||
{
|
{
|
||||||
value_t c, *pc;
|
value_t c, *pc;
|
||||||
u_int32_t t;
|
u_int32_t t;
|
||||||
|
|
||||||
PUSH(NIL);
|
PUSH(NIL);
|
||||||
pc = &Stack[SP-1]; // to keep track of current cons cell
|
pc = &Stack[SP-1]; // to keep track of current cons cell
|
||||||
t = peek(f);
|
t = peek();
|
||||||
while (t != TOK_CLOSE) {
|
while (t != TOK_CLOSE) {
|
||||||
if (ios_eof(f))
|
if (ios_eof(F))
|
||||||
lerror(ParseError, "read: unexpected end of input");
|
lerror(ParseError, "read: unexpected end of input");
|
||||||
c = mk_cons(); car_(c) = cdr_(c) = NIL;
|
c = mk_cons(); car_(c) = cdr_(c) = NIL;
|
||||||
if (iscons(*pc)) {
|
if (iscons(*pc)) {
|
||||||
|
@ -453,16 +455,16 @@ static void read_list(ios_t *f, value_t *pval, value_t label)
|
||||||
ptrhash_put(&readstate->backrefs, (void*)label, (void*)c);
|
ptrhash_put(&readstate->backrefs, (void*)label, (void*)c);
|
||||||
}
|
}
|
||||||
*pc = c;
|
*pc = c;
|
||||||
c = do_read_sexpr(f,UNBOUND); // must be on separate lines due to
|
c = do_read_sexpr(UNBOUND); // must be on separate lines due to
|
||||||
car_(*pc) = c; // undefined evaluation order
|
car_(*pc) = c; // undefined evaluation order
|
||||||
|
|
||||||
t = peek(f);
|
t = peek();
|
||||||
if (t == TOK_DOT) {
|
if (t == TOK_DOT) {
|
||||||
take();
|
take();
|
||||||
c = do_read_sexpr(f,UNBOUND);
|
c = do_read_sexpr(UNBOUND);
|
||||||
cdr_(*pc) = c;
|
cdr_(*pc) = c;
|
||||||
t = peek(f);
|
t = peek();
|
||||||
if (ios_eof(f))
|
if (ios_eof(F))
|
||||||
lerror(ParseError, "read: unexpected end of input");
|
lerror(ParseError, "read: unexpected end of input");
|
||||||
if (t != TOK_CLOSE)
|
if (t != TOK_CLOSE)
|
||||||
lerror(ParseError, "read: expected ')'");
|
lerror(ParseError, "read: expected ')'");
|
||||||
|
@ -473,14 +475,14 @@ static void read_list(ios_t *f, value_t *pval, value_t label)
|
||||||
}
|
}
|
||||||
|
|
||||||
// label is the backreference we'd like to fix up with this read
|
// label is the backreference we'd like to fix up with this read
|
||||||
static value_t do_read_sexpr(ios_t *f, value_t label)
|
static value_t do_read_sexpr(value_t label)
|
||||||
{
|
{
|
||||||
value_t v, sym, oldtokval, *head;
|
value_t v, sym, oldtokval, *head;
|
||||||
value_t *pv;
|
value_t *pv;
|
||||||
u_int32_t t;
|
u_int32_t t;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
t = peek(f);
|
t = peek();
|
||||||
take();
|
take();
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case TOK_CLOSE:
|
case TOK_CLOSE:
|
||||||
|
@ -510,19 +512,19 @@ static value_t do_read_sexpr(ios_t *f, value_t label)
|
||||||
PUSH(v);
|
PUSH(v);
|
||||||
if (label != UNBOUND)
|
if (label != UNBOUND)
|
||||||
ptrhash_put(&readstate->backrefs, (void*)label, (void*)v);
|
ptrhash_put(&readstate->backrefs, (void*)label, (void*)v);
|
||||||
v = do_read_sexpr(f,UNBOUND);
|
v = do_read_sexpr(UNBOUND);
|
||||||
car_(cdr_(Stack[SP-1])) = v;
|
car_(cdr_(Stack[SP-1])) = v;
|
||||||
return POP();
|
return POP();
|
||||||
case TOK_SHARPQUOTE:
|
case TOK_SHARPQUOTE:
|
||||||
// femtoLisp doesn't need symbol-function, so #' does nothing
|
// femtoLisp doesn't need symbol-function, so #' does nothing
|
||||||
return do_read_sexpr(f, label);
|
return do_read_sexpr(label);
|
||||||
case TOK_SHARPSEMI:
|
case TOK_SHARPSEMI:
|
||||||
// datum comment
|
// datum comment
|
||||||
(void)do_read_sexpr(f, UNBOUND); // skip one
|
(void)do_read_sexpr(UNBOUND); // skip one
|
||||||
return do_read_sexpr(f, label);
|
return do_read_sexpr(label);
|
||||||
case TOK_OPEN:
|
case TOK_OPEN:
|
||||||
PUSH(NIL);
|
PUSH(NIL);
|
||||||
read_list(f, &Stack[SP-1], label);
|
read_list(&Stack[SP-1], label);
|
||||||
return POP();
|
return POP();
|
||||||
case TOK_SHARPSYM:
|
case TOK_SHARPSYM:
|
||||||
sym = tokval;
|
sym = tokval;
|
||||||
|
@ -531,34 +533,34 @@ static value_t do_read_sexpr(ios_t *f, value_t label)
|
||||||
else if (sym == fsym || sym == Fsym)
|
else if (sym == fsym || sym == Fsym)
|
||||||
return FL_F;
|
return FL_F;
|
||||||
// constructor notation
|
// constructor notation
|
||||||
c = nextchar(f);
|
c = nextchar();
|
||||||
if (c != '(') {
|
if (c != '(') {
|
||||||
take();
|
take();
|
||||||
lerror(ParseError, "read: expected argument list for %s",
|
lerror(ParseError, "read: expected argument list for %s",
|
||||||
symbol_name(tokval));
|
symbol_name(tokval));
|
||||||
}
|
}
|
||||||
PUSH(NIL);
|
PUSH(NIL);
|
||||||
read_list(f, &Stack[SP-1], UNBOUND);
|
read_list(&Stack[SP-1], UNBOUND);
|
||||||
v = POP();
|
v = POP();
|
||||||
return apply(toplevel_eval(sym), v);
|
return apply(toplevel_eval(sym), v);
|
||||||
case TOK_OPENB:
|
case TOK_OPENB:
|
||||||
return read_vector(f, label, TOK_CLOSEB);
|
return read_vector(label, TOK_CLOSEB);
|
||||||
case TOK_SHARPOPEN:
|
case TOK_SHARPOPEN:
|
||||||
return read_vector(f, label, TOK_CLOSE);
|
return read_vector(label, TOK_CLOSE);
|
||||||
case TOK_SHARPDOT:
|
case TOK_SHARPDOT:
|
||||||
// eval-when-read
|
// eval-when-read
|
||||||
// evaluated expressions can refer to existing backreferences, but they
|
// evaluated expressions can refer to existing backreferences, but they
|
||||||
// cannot see pending labels. in other words:
|
// cannot see pending labels. in other words:
|
||||||
// (... #2=#.#0# ... ) OK
|
// (... #2=#.#0# ... ) OK
|
||||||
// (... #2=#.(#2#) ... ) DO NOT WANT
|
// (... #2=#.(#2#) ... ) DO NOT WANT
|
||||||
v = do_read_sexpr(f,UNBOUND);
|
v = do_read_sexpr(UNBOUND);
|
||||||
return toplevel_eval(v);
|
return toplevel_eval(v);
|
||||||
case TOK_LABEL:
|
case TOK_LABEL:
|
||||||
// create backreference label
|
// create backreference label
|
||||||
if (ptrhash_has(&readstate->backrefs, (void*)tokval))
|
if (ptrhash_has(&readstate->backrefs, (void*)tokval))
|
||||||
lerror(ParseError, "read: label %ld redefined", numval(tokval));
|
lerror(ParseError, "read: label %ld redefined", numval(tokval));
|
||||||
oldtokval = tokval;
|
oldtokval = tokval;
|
||||||
v = do_read_sexpr(f, tokval);
|
v = do_read_sexpr(tokval);
|
||||||
ptrhash_put(&readstate->backrefs, (void*)oldtokval, (void*)v);
|
ptrhash_put(&readstate->backrefs, (void*)oldtokval, (void*)v);
|
||||||
return v;
|
return v;
|
||||||
case TOK_BACKREF:
|
case TOK_BACKREF:
|
||||||
|
@ -573,21 +575,22 @@ static value_t do_read_sexpr(ios_t *f, value_t label)
|
||||||
*pv = gensym(NULL, 0);
|
*pv = gensym(NULL, 0);
|
||||||
return *pv;
|
return *pv;
|
||||||
case TOK_DOUBLEQUOTE:
|
case TOK_DOUBLEQUOTE:
|
||||||
return read_string(f);
|
return read_string();
|
||||||
}
|
}
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t read_sexpr(ios_t *f)
|
value_t read_sexpr(value_t f)
|
||||||
{
|
{
|
||||||
value_t v;
|
value_t v;
|
||||||
readstate_t state;
|
readstate_t state;
|
||||||
state.prev = readstate;
|
state.prev = readstate;
|
||||||
htable_new(&state.backrefs, 8);
|
htable_new(&state.backrefs, 8);
|
||||||
htable_new(&state.gensyms, 8);
|
htable_new(&state.gensyms, 8);
|
||||||
|
state.source = f;
|
||||||
readstate = &state;
|
readstate = &state;
|
||||||
|
|
||||||
v = do_read_sexpr(f, UNBOUND);
|
v = do_read_sexpr(UNBOUND);
|
||||||
|
|
||||||
readstate = state.prev;
|
readstate = state.prev;
|
||||||
free_readstate(&state);
|
free_readstate(&state);
|
||||||
|
|
|
@ -109,7 +109,7 @@ possible optimizations:
|
||||||
. not great, since then it can't be CPS converted
|
. not great, since then it can't be CPS converted
|
||||||
* represent lambda environment as a vector (in lispv)
|
* represent lambda environment as a vector (in lispv)
|
||||||
x setq builtin (didn't help)
|
x setq builtin (didn't help)
|
||||||
(- list builtin, to use cons_reserve)
|
* list builtin, to use cons_reserve
|
||||||
(- let builtin, to further avoid env consing)
|
(- let builtin, to further avoid env consing)
|
||||||
unconventional interpreter builtins that can be used as a compilation
|
unconventional interpreter builtins that can be used as a compilation
|
||||||
target without moving away from s-expressions:
|
target without moving away from s-expressions:
|
||||||
|
@ -939,7 +939,7 @@ consolidated todo list as of 8/30:
|
||||||
|
|
||||||
* make raising a memory error non-consing
|
* make raising a memory error non-consing
|
||||||
- eliminate string copy in lerror() when possible
|
- eliminate string copy in lerror() when possible
|
||||||
- fix printing lists of short strings
|
* fix printing lists of short strings
|
||||||
|
|
||||||
- remaining c types
|
- remaining c types
|
||||||
- remaining cvalues functions
|
- remaining cvalues functions
|
||||||
|
|
Loading…
Reference in New Issue