5 * Copyright (C) 1998-2000 Mark Probst
6 * Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
30 #include "app/globals.h"
31 #include "app/setup.h"
32 #include "utils/lispreader.h"
34 #define TOKEN_ERROR -1
36 #define TOKEN_OPEN_PAREN 1
37 #define TOKEN_CLOSE_PAREN 2
38 #define TOKEN_SYMBOL 3
39 #define TOKEN_STRING 4
40 #define TOKEN_INTEGER 5
42 #define TOKEN_PATTERN_OPEN_PAREN 7
45 #define TOKEN_FALSE 10
48 #define MAX_TOKEN_LENGTH 4096
50 static char token_string[MAX_TOKEN_LENGTH + 1] = "";
51 static int token_length = 0;
53 static lisp_object_t end_marker = { LISP_TYPE_EOF, {{0, 0}} };
54 static lisp_object_t error_object = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
55 static lisp_object_t close_paren_marker = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
56 static lisp_object_t dot_marker = { LISP_TYPE_PARSE_ERROR , {{0,0}} };
61 token_string[0] = '\0';
66 _token_append (char c)
68 if (token_length >= MAX_TOKEN_LENGTH)
69 throw LispReaderException("_token_append()", __FILE__, __LINE__);
71 token_string[token_length++] = c;
72 token_string[token_length] = '\0';
76 _next_char (lisp_stream_t *stream)
80 case LISP_STREAM_FILE :
81 return getc(stream->v.file);
83 case LISP_STREAM_STRING :
85 char c = stream->v.string.buf[stream->v.string.pos];
90 ++stream->v.string.pos;
96 return stream->v.any.next_char(stream->v.any.data);
99 throw LispReaderException("_next_char()", __FILE__, __LINE__);
104 _unget_char (char c, lisp_stream_t *stream)
106 switch (stream->type)
108 case LISP_STREAM_FILE :
109 ungetc(c, stream->v.file);
112 case LISP_STREAM_STRING :
113 --stream->v.string.pos;
116 case LISP_STREAM_ANY:
117 stream->v.any.unget_char(c, stream->v.any.data);
121 throw LispReaderException("_unget_char()", __FILE__, __LINE__);
126 _scan (lisp_stream_t *stream)
128 static char *delims = "\"();";
136 c = _next_char(stream);
139 else if (c == ';') /* comment start */
142 c = _next_char(stream);
154 return TOKEN_OPEN_PAREN;
157 return TOKEN_CLOSE_PAREN;
162 c = _next_char(stream);
169 c = _next_char(stream);
191 c = _next_char(stream);
204 c = _next_char(stream);
209 return TOKEN_PATTERN_OPEN_PAREN;
216 if (isdigit(c) || c == '-')
218 int have_nondigits = 0;
220 int have_floating_point = 0;
227 have_floating_point++;
230 c = _next_char(stream);
232 if (c != EOF && !isdigit(c) && !isspace(c) && c != '.' && !strchr(delims, c))
235 while (c != EOF && !isspace(c) && !strchr(delims, c));
238 _unget_char(c, stream);
240 if (have_nondigits || !have_digits || have_floating_point > 1)
242 else if (have_floating_point == 1)
245 return TOKEN_INTEGER;
251 c = _next_char(stream);
252 if (c != EOF && !isspace(c) && !strchr(delims, c))
256 _unget_char(c, stream);
263 c = _next_char(stream);
265 while (c != EOF && !isspace(c) && !strchr(delims, c));
267 _unget_char(c, stream);
273 throw LispReaderException("_scan()", __FILE__, __LINE__);
277 static lisp_object_t*
278 lisp_object_alloc (int type)
280 lisp_object_t *obj = (lisp_object_t*)malloc(sizeof(lisp_object_t));
288 lisp_stream_init_file (lisp_stream_t *stream, FILE *file)
290 stream->type = LISP_STREAM_FILE;
291 stream->v.file = file;
297 lisp_stream_init_string (lisp_stream_t *stream, char *buf)
299 stream->type = LISP_STREAM_STRING;
300 stream->v.string.buf = buf;
301 stream->v.string.pos = 0;
307 lisp_stream_init_any (lisp_stream_t *stream, void *data,
308 int (*next_char) (void *data),
309 void (*unget_char) (char c, void *data))
311 if (next_char == 0 || unget_char == 0)
312 throw LispReaderException("lisp_stream_init_any()", __FILE__, __LINE__);
314 stream->type = LISP_STREAM_ANY;
315 stream->v.any.data = data;
316 stream->v.any.next_char= next_char;
317 stream->v.any.unget_char = unget_char;
323 lisp_make_integer (int value)
325 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_INTEGER);
327 obj->v.integer = value;
333 lisp_make_real (float value)
335 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_REAL);
343 lisp_make_symbol (const char *value)
345 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_SYMBOL);
347 obj->v.string = strdup(value);
353 lisp_make_string (const char *value)
355 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_STRING);
357 obj->v.string = strdup(value);
363 lisp_make_cons (lisp_object_t *car, lisp_object_t *cdr)
365 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_CONS);
367 obj->v.cons.car = car;
368 obj->v.cons.cdr = cdr;
374 lisp_make_boolean (int value)
376 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_BOOLEAN);
378 obj->v.integer = value ? 1 : 0;
383 static lisp_object_t*
384 lisp_make_pattern_cons (lisp_object_t *car, lisp_object_t *cdr)
386 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_PATTERN_CONS);
388 obj->v.cons.car = car;
389 obj->v.cons.cdr = cdr;
394 static lisp_object_t*
395 lisp_make_pattern_var (int type, int index, lisp_object_t *sub)
397 lisp_object_t *obj = lisp_object_alloc(LISP_TYPE_PATTERN_VAR);
399 obj->v.pattern.type = type;
400 obj->v.pattern.index = index;
401 obj->v.pattern.sub = sub;
407 lisp_read (lisp_stream_t *in)
409 int token = _scan(in);
410 lisp_object_t *obj = lisp_nil();
412 if (token == TOKEN_EOF)
418 return &error_object;
423 case TOKEN_OPEN_PAREN :
424 case TOKEN_PATTERN_OPEN_PAREN :
426 lisp_object_t *last = lisp_nil(), *car;
431 if (car == &error_object || car == &end_marker)
434 return &error_object;
436 else if (car == &dot_marker)
438 if (lisp_nil_p(last))
441 return &error_object;
445 if (car == &error_object || car == &end_marker)
452 last->v.cons.cdr = car;
454 if (_scan(in) != TOKEN_CLOSE_PAREN)
457 return &error_object;
460 car = &close_paren_marker;
463 else if (car != &close_paren_marker)
465 if (lisp_nil_p(last))
466 obj = last = (token == TOKEN_OPEN_PAREN ? lisp_make_cons(car, lisp_nil()) : lisp_make_pattern_cons(car, lisp_nil()));
468 last = last->v.cons.cdr = lisp_make_cons(car, lisp_nil());
471 while (car != &close_paren_marker);
475 case TOKEN_CLOSE_PAREN :
476 return &close_paren_marker;
479 return lisp_make_symbol(token_string);
482 return lisp_make_string(token_string);
485 return lisp_make_integer(atoi(token_string));
488 return lisp_make_real((float)atof(token_string));
494 return lisp_make_boolean(1);
497 return lisp_make_boolean(0);
500 throw LispReaderException("lisp_read()", __FILE__, __LINE__);
501 return &error_object;
505 lisp_free (lisp_object_t *obj)
510 /** We have to use this iterative code, because the recursive function
511 * produces a stack overflow and crashs on OSX 10.2
513 std::vector<lisp_object_t*> objs;
516 while(!objs.empty()) {
517 lisp_object_t* obj = objs.back();
521 case LISP_TYPE_INTERNAL :
522 case LISP_TYPE_PARSE_ERROR :
526 case LISP_TYPE_SYMBOL :
527 case LISP_TYPE_STRING :
531 case LISP_TYPE_CONS :
532 case LISP_TYPE_PATTERN_CONS :
534 objs.push_back(obj->v.cons.car);
536 objs.push_back(obj->v.cons.cdr);
539 case LISP_TYPE_PATTERN_VAR :
540 if(obj->v.pattern.sub)
541 objs.push_back(obj->v.pattern.sub);
550 lisp_read_from_string (const char *buf)
552 lisp_stream_t stream;
554 lisp_stream_init_string(&stream, (char*)buf);
555 return lisp_read(&stream);
559 _compile_pattern (lisp_object_t **obj, int *index)
564 switch (lisp_type(*obj))
566 case LISP_TYPE_PATTERN_CONS :
575 { "any", LISP_PATTERN_ANY },
576 { "symbol", LISP_PATTERN_SYMBOL },
577 { "string", LISP_PATTERN_STRING },
578 { "integer", LISP_PATTERN_INTEGER },
579 { "real", LISP_PATTERN_REAL },
580 { "boolean", LISP_PATTERN_BOOLEAN },
581 { "list", LISP_PATTERN_LIST },
582 { "or", LISP_PATTERN_OR },
588 lisp_object_t *pattern;
591 if (lisp_type(lisp_car(*obj)) != LISP_TYPE_SYMBOL)
594 type_name = lisp_symbol(lisp_car(*obj));
595 for (i = 0; types[i].name != 0; ++i)
597 if (strcmp(types[i].name, type_name) == 0)
599 type = types[i].type;
604 if (types[i].name == 0)
607 if (type != LISP_PATTERN_OR && lisp_cdr(*obj) != 0)
610 pattern = lisp_make_pattern_var(type, (*index)++, lisp_nil());
612 if (type == LISP_PATTERN_OR)
614 lisp_object_t *cdr = lisp_cdr(*obj);
616 if (!_compile_pattern(&cdr, index))
622 pattern->v.pattern.sub = cdr;
624 (*obj)->v.cons.cdr = lisp_nil();
633 case LISP_TYPE_CONS :
634 if (!_compile_pattern(&(*obj)->v.cons.car, index))
636 if (!_compile_pattern(&(*obj)->v.cons.cdr, index))
645 lisp_compile_pattern (lisp_object_t **obj, int *num_subs)
650 result = _compile_pattern(obj, &index);
652 if (result && num_subs != 0)
658 static int _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars);
661 _match_pattern_var (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
663 if (lisp_type(pattern) != LISP_TYPE_PATTERN_VAR)
664 throw LispReaderException("_match_pattern_var", __FILE__, __LINE__);
666 switch (pattern->v.pattern.type)
668 case LISP_PATTERN_ANY :
671 case LISP_PATTERN_SYMBOL :
672 if (obj == 0 || lisp_type(obj) != LISP_TYPE_SYMBOL)
676 case LISP_PATTERN_STRING :
677 if (obj == 0 || lisp_type(obj) != LISP_TYPE_STRING)
681 case LISP_PATTERN_INTEGER :
682 if (obj == 0 || lisp_type(obj) != LISP_TYPE_INTEGER)
686 case LISP_PATTERN_REAL :
687 if (obj == 0 || lisp_type(obj) != LISP_TYPE_REAL)
691 case LISP_PATTERN_BOOLEAN :
692 if (obj == 0 || lisp_type(obj) != LISP_TYPE_BOOLEAN)
696 case LISP_PATTERN_LIST :
697 if (obj == 0 || lisp_type(obj) != LISP_TYPE_CONS)
701 case LISP_PATTERN_OR :
706 for (sub = pattern->v.pattern.sub; sub != 0; sub = lisp_cdr(sub))
708 if (lisp_type(sub) != LISP_TYPE_CONS)
709 throw LispReaderException("_match_pattern_var()", __FILE__, __LINE__);
711 if (_match_pattern(lisp_car(sub), obj, vars))
721 throw LispReaderException("_match_pattern_var()", __FILE__, __LINE__);
725 vars[pattern->v.pattern.index] = obj;
731 _match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars)
739 if (lisp_type(pattern) == LISP_TYPE_PATTERN_VAR)
740 return _match_pattern_var(pattern, obj, vars);
742 if (lisp_type(pattern) != lisp_type(obj))
745 switch (lisp_type(pattern))
747 case LISP_TYPE_SYMBOL :
748 return strcmp(lisp_symbol(pattern), lisp_symbol(obj)) == 0;
750 case LISP_TYPE_STRING :
751 return strcmp(lisp_string(pattern), lisp_string(obj)) == 0;
753 case LISP_TYPE_INTEGER :
754 return lisp_integer(pattern) == lisp_integer(obj);
756 case LISP_TYPE_REAL :
757 return lisp_real(pattern) == lisp_real(obj);
759 case LISP_TYPE_CONS :
761 int result1, result2;
763 result1 = _match_pattern(lisp_car(pattern), lisp_car(obj), vars);
764 result2 = _match_pattern(lisp_cdr(pattern), lisp_cdr(obj), vars);
766 return result1 && result2;
771 throw LispReaderException("_match_pattern()", __FILE__, __LINE__);
778 lisp_match_pattern (lisp_object_t *pattern, lisp_object_t *obj, lisp_object_t **vars, int num_subs)
783 for (i = 0; i < num_subs; ++i)
784 vars[i] = &error_object;
786 return _match_pattern(pattern, obj, vars);
790 lisp_match_string (const char *pattern_string, lisp_object_t *obj, lisp_object_t **vars)
792 lisp_object_t *pattern;
796 pattern = lisp_read_from_string(pattern_string);
798 if (pattern != 0 && (lisp_type(pattern) == LISP_TYPE_EOF
799 || lisp_type(pattern) == LISP_TYPE_PARSE_ERROR))
802 if (!lisp_compile_pattern(&pattern, &num_subs))
808 result = lisp_match_pattern(pattern, obj, vars, num_subs);
816 lisp_type (lisp_object_t *obj)
819 return LISP_TYPE_NIL;
824 lisp_integer (lisp_object_t *obj)
826 if (obj->type != LISP_TYPE_INTEGER)
827 throw LispReaderException("lisp_integer()", __FILE__, __LINE__);
829 return obj->v.integer;
833 lisp_symbol (lisp_object_t *obj)
835 if (obj->type != LISP_TYPE_SYMBOL)
836 throw LispReaderException("lisp_symbol()", __FILE__, __LINE__);
838 return obj->v.string;
842 lisp_string (lisp_object_t *obj)
844 if (obj->type != LISP_TYPE_STRING)
845 throw LispReaderException("lisp_string()", __FILE__, __LINE__);
847 return obj->v.string;
851 lisp_boolean (lisp_object_t *obj)
853 if (obj->type != LISP_TYPE_BOOLEAN)
854 throw LispReaderException("lisp_boolean()", __FILE__, __LINE__);
856 return obj->v.integer;
860 lisp_real (lisp_object_t *obj)
862 if (obj->type != LISP_TYPE_REAL && obj->type != LISP_TYPE_INTEGER)
863 throw LispReaderException("lisp_real()", __FILE__, __LINE__);
865 if (obj->type == LISP_TYPE_INTEGER)
866 return obj->v.integer;
871 lisp_car (lisp_object_t *obj)
873 if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
874 throw LispReaderException("lisp_car()", __FILE__, __LINE__);
876 return obj->v.cons.car;
880 lisp_cdr (lisp_object_t *obj)
882 if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
883 throw LispReaderException("lisp_cdr()", __FILE__, __LINE__);
885 return obj->v.cons.cdr;
889 lisp_cxr (lisp_object_t *obj, const char *x)
893 for (i = strlen(x) - 1; i >= 0; --i)
896 else if (x[i] == 'd')
899 throw LispReaderException("lisp_cxr()", __FILE__, __LINE__);
905 lisp_list_length (lisp_object_t *obj)
911 if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
912 throw LispReaderException("lisp_list_length()", __FILE__, __LINE__);
915 obj = obj->v.cons.cdr;
922 lisp_list_nth_cdr (lisp_object_t *obj, int index)
927 throw LispReaderException("lisp_list_nth_cdr()", __FILE__, __LINE__);
928 if (obj->type != LISP_TYPE_CONS && obj->type != LISP_TYPE_PATTERN_CONS)
929 throw LispReaderException("lisp_list_nth_cdr()", __FILE__, __LINE__);
932 obj = obj->v.cons.cdr;
939 lisp_list_nth (lisp_object_t *obj, int index)
941 obj = lisp_list_nth_cdr(obj, index);
944 throw LispReaderException("lisp_list_nth()", __FILE__, __LINE__);
946 return obj->v.cons.car;
950 lisp_dump (lisp_object_t *obj, FILE *out)
958 switch (lisp_type(obj))
961 fputs("#<eof>", out);
964 case LISP_TYPE_PARSE_ERROR :
965 fputs("#<error>", out);
968 case LISP_TYPE_INTEGER :
969 fprintf(out, "%d", lisp_integer(obj));
972 case LISP_TYPE_REAL :
973 fprintf(out, "%f", lisp_real(obj));
976 case LISP_TYPE_SYMBOL :
977 fputs(lisp_symbol(obj), out);
980 case LISP_TYPE_STRING :
985 for (p = lisp_string(obj); *p != 0; ++p)
987 if (*p == '"' || *p == '\\')
995 case LISP_TYPE_CONS :
996 case LISP_TYPE_PATTERN_CONS :
997 fputs(lisp_type(obj) == LISP_TYPE_CONS ? "(" : "#?(", out);
1000 lisp_dump(lisp_car(obj), out);
1001 obj = lisp_cdr(obj);
1004 if (lisp_type(obj) != LISP_TYPE_CONS
1005 && lisp_type(obj) != LISP_TYPE_PATTERN_CONS)
1008 lisp_dump(obj, out);
1018 case LISP_TYPE_BOOLEAN :
1019 if (lisp_boolean(obj))
1026 throw LispReaderException("lisp_dump()", __FILE__, __LINE__);
1030 using namespace std;
1032 LispReader::LispReader (lisp_object_t* l)
1037 LispReader::~LispReader()
1044 LispReader::load(const std::string& filename, const std::string& toplevellist)
1046 lisp_object_t* obj = lisp_read_from_file(filename);
1048 if(obj->type == LISP_TYPE_EOF || obj->type == LISP_TYPE_PARSE_ERROR) {
1050 throw LispReaderException("LispReader::load", __FILE__, __LINE__);
1053 if(toplevellist != lisp_symbol(lisp_car(obj))) {
1055 throw LispReaderException("LispReader::load wrong toplevel symbol",
1056 __FILE__, __LINE__);
1059 LispReader* reader = new LispReader(lisp_cdr(obj));
1060 reader->owner = obj;
1066 LispReader::search_for(const char* name)
1068 //std::cout << "LispReader::search_for(" << name << ")" << std::endl;
1069 lisp_object_t* cursor = lst;
1071 while(!lisp_nil_p(cursor))
1073 lisp_object_t* cur = lisp_car(cursor);
1075 if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
1077 lisp_dump(cur, stdout);
1078 //throw ConstruoError (std::string("LispReader: Read error in search_for ") + name);
1079 printf("LispReader: Read error in search\n");
1083 if (strcmp(lisp_symbol(lisp_car(cur)), name) == 0)
1085 return lisp_cdr(cur);
1089 cursor = lisp_cdr (cursor);
1095 LispReader::read_int (const char* name, int& i)
1097 lisp_object_t* obj = search_for (name);
1101 if (!lisp_integer_p(lisp_car(obj)))
1104 i = lisp_integer(lisp_car(obj));
1109 LispReader::read_lisp(const char* name, lisp_object_t*& b)
1111 lisp_object_t* obj = search_for (name);
1120 LispReader::read_lisp(const char* name)
1122 return search_for(name);
1126 LispReader::read_float (const char* name, float& f)
1128 lisp_object_t* obj = search_for (name);
1132 if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
1133 st_abort("LispReader expected type real at token: ", name);
1135 f = lisp_real(lisp_car(obj));
1140 LispReader::read_string_vector (const char* name, std::vector<std::string>& vec)
1142 lisp_object_t* obj = search_for (name);
1147 while(!lisp_nil_p(obj))
1149 if (!lisp_string_p(lisp_car(obj)))
1150 st_abort("LispReader expected type string at token: ", name);
1151 vec.push_back(lisp_string(lisp_car(obj)));
1152 obj = lisp_cdr(obj);
1158 LispReader::read_int_vector (const char* name, std::vector<int>& vec)
1160 lisp_object_t* obj = search_for (name);
1165 while(!lisp_nil_p(obj))
1167 if (!lisp_integer_p(lisp_car(obj)))
1168 st_abort("LispReader expected type integer at token: ", name);
1169 vec.push_back(lisp_integer(lisp_car(obj)));
1170 obj = lisp_cdr(obj);
1176 LispReader::read_int_vector (const char* name, std::vector<unsigned int>& vec)
1178 lisp_object_t* obj = search_for (name);
1183 while(!lisp_nil_p(obj))
1185 if (!lisp_integer_p(lisp_car(obj)))
1186 st_abort("LispReader expected type integer at token: ", name);
1187 vec.push_back(lisp_integer(lisp_car(obj)));
1188 obj = lisp_cdr(obj);
1194 LispReader::read_char_vector (const char* name, std::vector<char>& vec)
1196 lisp_object_t* obj = search_for (name);
1201 while(!lisp_nil_p(obj))
1203 vec.push_back(*lisp_string(lisp_car(obj)));
1204 obj = lisp_cdr(obj);
1210 LispReader::read_string (const char* name, std::string& str, bool translatable)
1215 /* Internationalization support: check for the suffix: str + "-" + $LANG variable.
1216 If not found, use the regular string.
1217 So, translating a string in a Lisp file would result in something like:
1218 (text "Hello World!")
1219 (text-fr "Bonjour Monde!")
1220 being fr the value of LANG (echo $LANG) for the language we want to translate to */
1222 char* lang = getenv("LANG");
1224 char str_[1024]; // check, for instance, for (title-fr_FR "Bonjour")
1225 sprintf(str_, "%s-%s", name, lang);
1227 obj = search_for (str_);
1229 if(!obj) // check, for instance, for (title-fr "Bonjour")
1231 if(lang != NULL && strlen(lang) >= 2)
1234 strncpy(lang_, lang, 2);
1236 sprintf(str_, "%s-%s", name, lang_);
1238 obj = search_for (str_);
1244 if(!obj) // check, for instance, for (title "Hello")
1245 obj = search_for (name);
1248 obj = search_for (name);
1253 if (!lisp_string_p(lisp_car(obj)))
1254 st_abort("LispReader expected type string at token: ", name);
1255 str = lisp_string(lisp_car(obj));
1260 LispReader::read_bool (const char* name, bool& b)
1262 lisp_object_t* obj = search_for (name);
1266 if (!lisp_boolean_p(lisp_car(obj)))
1267 st_abort("LispReader expected type bool at token: ", name);
1268 b = lisp_boolean(lisp_car(obj));
1273 LispReader::get_lisp()
1278 lisp_object_t* lisp_read_from_file(const std::string& filename)
1280 FILE* in = fopen(filename.c_str(), "r");
1285 lisp_stream_t stream;
1286 lisp_stream_init_file(&stream, in);
1287 lisp_object_t* obj = lisp_read(&stream);