]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Initial code for lisp interpreter
authorJaroslav Kysela <perex@perex.cz>
Tue, 24 Jun 2003 19:30:08 +0000 (19:30 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 24 Jun 2003 19:30:08 +0000 (19:30 +0000)
15 files changed:
Makefile.am
alsalisp/Makefile.am [new file with mode: 0644]
alsalisp/alsalisp.c [new file with mode: 0644]
configure.in
include/Makefile.am
include/alisp.h [new file with mode: 0644]
include/asoundlib.h
include/local.h
include/output.h
src/Makefile.am
src/Versions
src/alisp/Makefile.am [new file with mode: 0644]
src/alisp/alisp.c [new file with mode: 0644]
src/alisp/alisp_local.h [new file with mode: 0644]
src/output.c

index 61d82e0ebfbe332476ac9de6d20cf59d6de8e1ef..ba193959819ff19cd7204694f833da29a5bc555f 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=doc include src aserver test utils
+SUBDIRS=doc include src aserver alsalisp test utils
 EXTRA_DIST=ChangeLog INSTALL TODO configure cvscompile libtool depcomp version
 
 INCLUDES=-I$(top_srcdir)/include
diff --git a/alsalisp/Makefile.am b/alsalisp/Makefile.am
new file mode 100644 (file)
index 0000000..398261c
--- /dev/null
@@ -0,0 +1,8 @@
+bin_PROGRAMS = alsalisp
+
+alsalisp_SOURCES = alsalisp.c
+alsalisp_LDADD = ../src/libasound.la
+
+all: alsalisp
+
+INCLUDES=-I$(top_srcdir)/include -I$(top_srcdir)/src/alisp
diff --git a/alsalisp/alsalisp.c b/alsalisp/alsalisp.c
new file mode 100644 (file)
index 0000000..0dad484
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  ALSA lisp implementation
+ *  Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "asoundlib.h"
+#include "alisp.h"
+
+static int verbose = 0;
+static int warning = 0;
+static int debug = 0;
+
+static void interpret_filename(const char *file)
+{
+       struct alisp_cfg cfg;
+       snd_input_t *in;
+       snd_output_t *out;
+       snd_config_t *root;
+       int err;
+
+       memset(&cfg, 0, sizeof(cfg));
+       if (file != NULL && strcmp(file, "-") != 0) {
+               if ((err = snd_input_stdio_open(&in, file, "r")) < 0) {
+                       fprintf(stderr, "unable to open filename '%s' (%s)\n", file, snd_strerror(err));
+                       return;
+               }
+       } else {
+               if ((err = snd_input_stdio_attach(&in, stdin, 0)) < 0) {
+                       fprintf(stderr, "unable to attach stdin '%s' (%s)\n", file, snd_strerror(err));
+                       return;
+               }
+       }
+       if (snd_output_stdio_attach(&out, stdout, 0) < 0) {
+               snd_input_close(in);
+               fprintf(stderr, "unable to attach stdout (%s)\n", strerror(errno));
+               return;
+       }
+       err = snd_config_top(&root);
+       if (err < 0)
+               fprintf(stderr, "unable to allocate config root\n");
+       else {
+               cfg.verbose = verbose;
+               cfg.warning = warning;
+               cfg.debug = debug;
+               cfg.in = in;
+               cfg.out = cfg.vout = cfg.wout = cfg.dout = out;
+               cfg.root = root;
+               cfg.node = root;
+               err = alsa_lisp(&cfg);
+       }
+       if (err < 0)
+               fprintf(stderr, "alsa lisp returned error %i (%s)\n", err, strerror(err));
+       else if (verbose)
+               printf("file %s passed ok via alsa lisp interpreter", file);
+       snd_config_save(root, out);
+       snd_output_close(out);
+       snd_input_close(in);
+       snd_config_delete(root);
+}
+
+static void usage(void)
+{
+       fprintf(stderr, "usage: alsalisp [-vdw] [file...]\n");
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "vdw")) != -1) {
+               switch (c) {
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 'd':
+                       debug = 1;
+                       break;
+               case 'w':
+                       warning = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1)
+               interpret_filename(NULL);
+       else
+               while (*argv)
+                       interpret_filename(*argv++);
+
+       return 0;
+}
index b229b95e847a3433c8730d79a49404e431d0b34d..67715323560953c9f86dc53dc0afa9890200aa62 100644 (file)
@@ -165,7 +165,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile include/Makefile
          src/pcm/Makefile src/pcm/ext/Makefile src/pcm/scopes/Makefile src/ordinary_pcm/Makefile \
          src/rawmidi/Makefile src/timer/Makefile \
           src/hwdep/Makefile src/seq/Makefile src/instr/Makefile \
-          src/compat/Makefile src/conf/Makefile \
+          src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
          src/conf/cards/Makefile src/conf/pcm/Makefile \
-         aserver/Makefile test/Makefile utils/Makefile \
+         alsalisp/Makefile aserver/Makefile test/Makefile utils/Makefile \
           utils/alsa-lib.spec utils/alsa.pc)
index e078eca4bc41e3839a81819ea57bafcca0d1cec6..948b71bee1d5c99a4ad50e5633c4fdb31a05bde4 100644 (file)
@@ -9,7 +9,8 @@ alsainclude_HEADERS = asoundlib.h asoundef.h \
                      hwdep.h control.h mixer.h \
                      seq_event.h seq.h seqmid.h seq_midi_event.h \
                      conv.h instr.h iatomic.h \
-                     pcm_ordinary.h mixer_ordinary.h
+                     pcm_ordinary.h mixer_ordinary.h \
+                     alisp.h
 
 noinst_HEADERS = sys.h search.h list.h aserver.h local.h alsa-symbols.h
 
diff --git a/include/alisp.h b/include/alisp.h
new file mode 100644 (file)
index 0000000..e81e2d0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  ALSA lisp implementation
+ *  Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+struct alisp_cfg {
+       int verbose: 1,
+           warning: 1,
+           debug: 1;
+       snd_input_t *in;        /* program code */
+       snd_output_t *out;      /* program output */
+       snd_output_t *vout;     /* verbose output */
+       snd_output_t *wout;     /* warning output */
+       snd_output_t *dout;     /* debug output */
+       snd_config_t *root;
+       snd_config_t *node;
+};
+
+int alsa_lisp(struct alisp_cfg *cfg);
+
+extern struct alisp_object alsa_lisp_nil;
+extern struct alisp_object alsa_lisp_t;
index a96507bfd7b46d1d820dbdf347c310648dc6476d..c8560f69c00777645c0488a1eedeb9e146cb31c4 100644 (file)
@@ -35,6 +35,7 @@
 #include <fcntl.h>
 #include <assert.h>
 #include <endian.h>
+#include <stdarg.h>
 #include <sys/poll.h>
 #include <errno.h>
 
index e04c8c15fe7169747cd7c6c14235342592110088..f57cc1825d81312810177b3ff68d07fdf805941a 100644 (file)
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <assert.h>
 #include <endian.h>
+#include <stdarg.h>
 #include <sys/poll.h>
 #include <errno.h>
 
index 492d712c759dde960043c90a480f223d30bccb08..6c7fdca841ed0a7743cdb10e1fefdc9882113d18 100644 (file)
@@ -71,6 +71,7 @@ int snd_output_printf(snd_output_t *output, const char *format, ...)
        __attribute__ ((format (printf, 2, 3)))
 #endif
        ;
+int snd_output_vprintf(snd_output_t *output, const char *format, va_list args);
 int snd_output_puts(snd_output_t *output, const char *str);
 int snd_output_putc(snd_output_t *output, int c);
 int snd_output_flush(snd_output_t *output);
index d8b5e00f2a134dfdcc70e9d5923d353e79ebabfa..2851d22262c2afe1e2ace5e8e5407742183b01c3 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=control mixer ordinary_mixer pcm ordinary_pcm rawmidi timer hwdep seq instr compat conf
+SUBDIRS=control mixer ordinary_mixer pcm ordinary_pcm rawmidi timer hwdep seq instr compat conf alisp
 EXTRA_DIST=Versions
 COMPATNUM=@LIBTOOL_VERSION_INFO@
 
@@ -15,7 +15,7 @@ libasound_la_LIBADD = control/libcontrol.la \
                      pcm/libpcm.la ordinary_pcm/libordinarypcm.la \
                       rawmidi/librawmidi.la timer/libtimer.la \
                      hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
-                     compat/libcompat.la -lm -ldl -lpthread
+                     compat/libcompat.la alisp/libalisp.la -lm -ldl -lpthread
 
 libasound_la_LDFLAGS = -version-info $(COMPATNUM)
 LDFLAGS = $(VSYMS)
@@ -53,4 +53,7 @@ instr/libinstr.la:
 compat/libcompat.la:
        $(MAKE) -C compat libcompat.la
 
+alisp/libalisp.la:
+       $(MAKE) -C alisp libalisp.la
+
 INCLUDES=-I$(top_srcdir)/include
index 0ca00aa20150dd7c49687d02b97f951cfc3b1815..d3906ffbdd674db74def5d748eef71f8bf92d235 100644 (file)
@@ -108,3 +108,9 @@ ALSA_0.9.3 {
     snd_ctl_elem_info_get_dimensions;
     snd_ctl_elem_info_get_dimension;
 } ALSA_0.9.0;
+
+ALSA_0.9.5 {
+  global:
+
+    alsa_lisp;
+} ALSA_0.9.3;
diff --git a/src/alisp/Makefile.am b/src/alisp/Makefile.am
new file mode 100644 (file)
index 0000000..eaca125
--- /dev/null
@@ -0,0 +1,9 @@
+EXTRA_LTLIBRARIES = libalisp.la
+
+libalisp_la_SOURCES = alisp.c
+
+noinst_HEADERS = alisp_local.h
+
+all: libalisp.la
+
+INCLUDES=-I$(top_srcdir)/include
diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c
new file mode 100644 (file)
index 0000000..1c72314
--- /dev/null
@@ -0,0 +1,1628 @@
+/*
+ *  ALSA lisp implementation
+ *  Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *  Based on work of Sandro Sigala (slisp-1.2)
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <assert.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "local.h"
+#include "alisp.h"
+#include "alisp_local.h"
+
+struct alisp_object alsa_lisp_nil;
+struct alisp_object alsa_lisp_t;
+
+/* parser prototypes */
+static struct alisp_object * parse_object(struct alisp_instance *instance, int havetoken);
+static void princ_object(snd_output_t *out, struct alisp_object * p);
+static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_object * p);
+
+/* functions */
+static struct alisp_object *F_eval(struct alisp_instance *instance, struct alisp_object *);
+static struct alisp_object *F_progn(struct alisp_instance *instance, struct alisp_object *);
+
+/*
+ *  object handling
+ */
+
+static void nomem(void)
+{
+       SNDERR("alisp: no enough memory");
+}
+
+static void lisp_verbose(struct alisp_instance *instance, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!instance->verbose)
+               return;
+       va_start(ap, fmt);
+       snd_output_printf(instance->vout, "alisp: ");
+       snd_output_vprintf(instance->vout, fmt, ap);
+       va_end(ap);
+}
+
+static void lisp_warn(struct alisp_instance *instance, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!instance->warning)
+               return;
+       va_start(ap, fmt);
+       snd_output_printf(instance->wout, "alisp warning: ");
+       snd_output_vprintf(instance->wout, fmt, ap);
+       va_end(ap);
+}
+
+static void lisp_debug(struct alisp_instance *instance, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!instance->debug)
+               return;
+       va_start(ap, fmt);
+       snd_output_printf(instance->dout, "alisp debug: ");
+       snd_output_vprintf(instance->dout, fmt, ap);
+       va_end(ap);
+}
+
+static struct alisp_object * new_object(struct alisp_instance *instance, int type)
+{
+       struct alisp_object * p;
+
+       if (instance->free_objs_list == NULL) {
+               p = (struct alisp_object *)malloc(sizeof(struct alisp_object));
+               if (p == NULL) {
+                       nomem();
+                       return NULL;
+               }
+               lisp_debug(instance, "allocating cons %p", p);
+       } else {
+               p = instance->free_objs_list;
+               instance->free_objs_list = instance->free_objs_list->next;
+               --instance->free_objs;
+               lisp_debug(instance, "recycling cons %p", p);
+       }
+
+       p->next = instance->used_objs_list;
+       instance->used_objs_list = p;
+
+       p->type = type;
+       if (type == ALISP_OBJ_CONS) {
+               p->value.c.car = &alsa_lisp_nil;
+               p->value.c.cdr = &alsa_lisp_nil;
+       }
+       p->gc = 0;
+
+       ++instance->used_objs;
+
+       return p;
+}
+
+static struct alisp_object * search_object_identifier(struct alisp_instance *instance, const char *s)
+{
+       struct alisp_object * p;
+
+       for (p = instance->used_objs_list; p != NULL; p = p->next)
+               if (p->type == ALISP_OBJ_IDENTIFIER && !strcmp(p->value.id, s))
+                       return p;
+
+       return NULL;
+}
+
+static struct alisp_object * search_object_string(struct alisp_instance *instance, const char *s)
+{
+       struct alisp_object * p;
+
+       for (p = instance->used_objs_list; p != NULL; p = p->next)
+               if (p->type == ALISP_OBJ_STRING && !strcmp(p->value.s, s))
+                       return p;
+
+       return NULL;
+}
+
+static struct alisp_object * search_object_integer(struct alisp_instance *instance, int in)
+{
+       struct alisp_object * p;
+
+       for (p = instance->used_objs_list; p != NULL; p = p->next)
+               if (p->type == ALISP_OBJ_INTEGER && p->value.i == in)
+                       return p;
+
+       return NULL;
+}
+
+void alsa_lisp_init_objects(void) __attribute__ ((constructor));
+
+void alsa_lisp_init_objects(void)
+{
+       memset(&alsa_lisp_nil, 0, sizeof(alsa_lisp_nil));
+       alsa_lisp_nil.type = ALISP_OBJ_NIL;
+       memset(&alsa_lisp_t, 0, sizeof(alsa_lisp_t));
+       alsa_lisp_t.type = ALISP_OBJ_T;
+}
+
+/*
+ * lexer
+ */ 
+
+static int xgetc(struct alisp_instance *instance)
+{
+       if (instance->lex_bufp > instance->lex_buf)
+               *--(instance->lex_bufp);
+       instance->charno++;
+       return snd_input_getc(instance->in);
+}
+
+static inline void xungetc(struct alisp_instance *instance, int c)
+{
+       *(instance->lex_bufp)++ = c;
+       instance->charno--;
+}
+
+static int init_lex(struct alisp_instance *instance)
+{
+       instance->charno = instance->lineno = 1;
+       instance->token_buffer_max = 10;
+       if ((instance->token_buffer = (char *)malloc(instance->token_buffer_max)) == NULL) {
+               nomem();
+               return -ENOMEM;
+       }
+       instance->lex_bufp = instance->lex_buf;
+       return 0;
+}
+
+static void done_lex(struct alisp_instance *instance)
+{
+       if (instance->token_buffer)
+               free(instance->token_buffer);
+}
+
+static char * extend_buf(struct alisp_instance *instance, char *p)
+{
+       int off = p - instance->token_buffer;
+
+       instance->token_buffer_max += 10;
+       instance->token_buffer = (char *)realloc(instance->token_buffer, instance->token_buffer_max);
+       if (instance->token_buffer == NULL) {
+               nomem();
+               return NULL;
+       }
+
+       return instance->token_buffer + off;
+}
+
+static int gettoken(struct alisp_instance *instance)
+{
+       char *p;
+       int c;
+
+       for (;;) {
+               c = xgetc(instance);
+               switch (c) {
+               case '\n':
+                       ++instance->lineno;
+                       break;
+
+               case ' ': case '\f': case '\t': case '\v': case '\r':
+                       break;
+
+               case ';':
+                       /* Comment: ";".*"\n" */
+                       while ((c = xgetc(instance)) != '\n' && c != EOF)
+                               ;
+                       if (c != EOF)
+                               ++instance->lineno;
+                       break;
+
+               case '?':
+                       /* Character: "?". */
+                       c = xgetc(instance);
+                       sprintf(instance->token_buffer, "%d", c);
+                       return instance->thistoken = ALISP_INTEGER;
+
+               case '-':
+                       /* Minus sign: "-". */
+                       c = xgetc(instance);
+                       if (!isdigit(c)) {
+                               xungetc(instance, c);
+                               c = '-';
+                               goto got_id;
+                       }
+                       xungetc(instance, c);
+                       c = '-';
+                       /* FALLTRHU */
+
+               case '0':
+               case '1': case '2': case '3':
+               case '4': case '5': case '6':
+               case '7': case '8': case '9':
+                       /* Integer: [0-9]+ */
+                       p = instance->token_buffer;
+                       do {
+                               if (p - instance->token_buffer >= instance->token_buffer_max) {
+                                       p = extend_buf(instance, p);
+                                       if (p == NULL)
+                                               return instance->thistoken = EOF;
+                               }
+                               *p++ = c;
+                               c = xgetc(instance);
+                       } while (isdigit(c));
+                       xungetc(instance, c);
+                       *p = '\0';
+                       return instance->thistoken = ALISP_INTEGER;
+
+               got_id:
+               case '_': case '+': case '*': case '/': case '%':
+               case '<': case '>': case '=': case '&':
+               case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+               case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+               case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+               case 'y': case 'z':
+               case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+               case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+               case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+               case 'Y': case 'Z':
+                       /* Identifier: [-/+*%<>=&a-zA-Z_][-/+*%<>=&a-zA-Z_0-9]* */
+                       p = instance->token_buffer;
+                       do {
+                               if (p - instance->token_buffer >= instance->token_buffer_max) {
+                                       p = extend_buf(instance, p);
+                                       if (p == NULL)
+                                               return instance->thistoken = EOF;
+                               }
+                               *p++ = c;
+                               c = xgetc(instance);
+                       } while (isalnum(c) || strchr("_-+*/%<>=&", c) != NULL);
+                       xungetc(instance, c);
+                       *p = '\0';
+                       return instance->thistoken = ALISP_IDENTIFIER;
+
+               case '"':
+                       /* String: "\""([^"]|"\\".)*"\"" */
+                       p = instance->token_buffer;
+                       while ((c = xgetc(instance)) != '"' && c != EOF) {
+                               if (p - instance->token_buffer >= instance->token_buffer_max) {
+                                       p = extend_buf(instance, p);
+                                       if (p == NULL)
+                                               return instance->thistoken = EOF;
+                               }
+                               if (c == '\\') {
+                                       c = xgetc(instance);
+                                       switch (c) {
+                                       case '\n': ++instance->lineno; break;
+                                       case 'a': *p++ = '\a'; break;
+                                       case 'b': *p++ = '\b'; break;
+                                       case 'f': *p++ = '\f'; break;
+                                       case 'n': *p++ = '\n'; break;
+                                       case 'r': *p++ = '\r'; break;
+                                       case 't': *p++ = '\t'; break;
+                                       case 'v': *p++ = '\v'; break;
+                                       default: *p++ = c;
+                                       }
+                               } else {
+                                       if (c == '\n')
+                                               ++instance->lineno;
+                                       *p++ = c;
+                               }
+                       }
+                       *p = '\0';
+                       return instance->thistoken = ALISP_STRING;
+
+               default:
+                       return instance->thistoken = c;
+               }
+       }
+}
+
+/*
+ *  parser
+ */
+
+static struct alisp_object * parse_form(struct alisp_instance *instance)
+{
+       int thistoken;
+       struct alisp_object * p, * first = NULL, * prev = NULL;
+
+       while ((thistoken = gettoken(instance)) != ')' && thistoken != EOF) {
+               /*
+                * Parse a dotted pair notation.
+                */
+               if (thistoken == '.') {
+                       thistoken = gettoken(instance);
+                       if (prev == NULL)
+                               errx(1, "unexpected `.'");
+                       prev->value.c.cdr = parse_object(instance, 1);
+                       if (prev->value.c.cdr == NULL)
+                               return NULL;
+                       if ((thistoken = gettoken(instance)) != ')')
+                               errx(1, "expected `)'");
+                       break;
+               }
+
+               p = new_object(instance, ALISP_OBJ_CONS);
+               if (p == NULL)
+                       return NULL;
+
+               if (first == NULL)
+                       first = p;
+               if (prev != NULL)
+                       prev->value.c.cdr = p;
+
+               p->value.c.car = parse_object(instance, 1);
+               if (p->value.c.car == NULL)
+                       return NULL;
+               prev = p;
+       };
+
+       if (first == NULL)
+               return &alsa_lisp_nil;
+       else
+               return first;
+}
+
+static struct alisp_object * parse_quote(struct alisp_instance *instance)
+{
+       struct alisp_object * p;
+
+       p = new_object(instance, ALISP_OBJ_CONS);
+       if (p == NULL)
+               return NULL;
+
+       p->value.c.car = new_object(instance, ALISP_OBJ_IDENTIFIER);
+       if (p->value.c.car == NULL)
+               return NULL;
+       if ((p->value.c.car->value.id = strdup("quote")) == NULL) {
+               nomem();
+               return NULL;
+       }
+       p->value.c.cdr = new_object(instance, ALISP_OBJ_CONS);
+       if (p->value.c.cdr == NULL)
+               return NULL;
+       p->value.c.cdr->value.c.car = parse_object(instance, 0);
+       if (p->value.c.cdr->value.c.car == NULL)
+               return NULL;
+
+       return p;
+}
+
+static struct alisp_object * parse_object(struct alisp_instance *instance, int havetoken)
+{
+       int thistoken;
+       struct alisp_object * p = NULL;
+       int i;
+
+       if (!havetoken)
+               thistoken = gettoken(instance);
+       else
+               thistoken = instance->thistoken;
+
+       switch (thistoken) {
+       case EOF:
+               break;
+       case '(':
+               p = parse_form(instance);
+               break;
+       case '\'':
+               p = parse_quote(instance);
+               break;
+       case ALISP_IDENTIFIER:
+               if (!strcmp(instance->token_buffer, "t"))
+                       p = &alsa_lisp_t;
+               else if (!strcmp(instance->token_buffer, "nil"))
+                       p = &alsa_lisp_nil;
+               else {
+                       if ((p = search_object_identifier(instance, instance->token_buffer)) == NULL) {
+                               p = new_object(instance, ALISP_OBJ_IDENTIFIER);
+                               if (p) {
+                                       if ((p->value.id = strdup(instance->token_buffer)) == NULL) {
+                                               nomem();
+                                               return NULL;
+                                       }
+                               }
+                       }
+               }
+               break;
+       case ALISP_INTEGER:
+               i = atoi(instance->token_buffer);
+               if ((p = search_object_integer(instance, i)) == NULL) {
+                       p = new_object(instance, ALISP_OBJ_INTEGER);
+                       if (p)
+                               p->value.i = i;
+               }
+               break;
+       case ALISP_STRING:
+               if ((p = search_object_string(instance, instance->token_buffer)) == NULL) {
+                       p = new_object(instance, ALISP_OBJ_STRING);
+                       if (p) {
+                               if ((p->value.s = strdup(instance->token_buffer)) == NULL) {
+                                       nomem();
+                                       return NULL;
+                               }
+                       }
+               }
+               break;
+       default:
+               lisp_warn(instance, "%d:%d: unexpected character `%c'", instance->lineno, instance->charno, thistoken);
+               break;
+       }
+
+       return p;
+}
+
+/*
+ *  object manipulation
+ */
+
+static int set_object(struct alisp_instance *instance, struct alisp_object * name, struct alisp_object * value)
+{
+       struct alisp_object_pair *p;
+
+       if (name->value.id == NULL)
+               return 0;
+
+       for (p = instance->setobjs_list; p != NULL; p = p->next)
+               if (p->name->value.id != NULL &&
+                   !strcmp(name->value.id, p->name->value.id)) {
+                       p->value = value;
+                       return 0;
+               }
+
+       p = (struct alisp_object_pair *)malloc(sizeof(struct alisp_object_pair));
+       if (p == NULL) {
+               nomem();
+               return -ENOMEM;
+       }
+       p->next = instance->setobjs_list;
+       instance->setobjs_list = p;
+       p->name = name;
+       p->value = value;
+       return 0;
+}
+
+static struct alisp_object * get_object(struct alisp_instance *instance, struct alisp_object * name)
+{
+       struct alisp_object_pair *p;
+
+       for (p = instance->setobjs_list; p != NULL; p = p->next)
+               if (p->name->value.id != NULL &&
+                   !strcmp(name->value.id, p->name->value.id))
+                       return p->value;
+
+       return &alsa_lisp_nil;
+}
+
+static void dump_objects(struct alisp_instance *instance, const char *fname)
+{
+       struct alisp_object_pair *p;
+       snd_output_t *out;
+       int err;
+
+       if (!strcmp(fname, "-"))
+               err = snd_output_stdio_attach(&out, stdout, 0);
+       else
+               err = snd_output_stdio_open(&out, fname, "w+");
+       if (err < 0) {
+               SNDERR("alisp: cannot open file '%s' for writting (%s)", fname, snd_strerror(errno));
+               return;
+       }
+
+       for (p = instance->setobjs_list; p != NULL; p = p->next) {
+               snd_output_printf(out, "(setq %s '", p->name->value.id);
+               princ_object(out, p->value);
+               snd_output_printf(out, ")\n");
+       }
+       
+       snd_output_close(out);
+}
+
+static const char *obj_type_str(struct alisp_object * p)
+{
+       switch (p->type) {
+       case ALISP_OBJ_NIL: return "nil";
+       case ALISP_OBJ_T: return "t";
+       case ALISP_OBJ_INTEGER: return "integer";
+       case ALISP_OBJ_IDENTIFIER: return "identifier";
+       case ALISP_OBJ_STRING: return "string";
+       case ALISP_OBJ_CONS: return "cons";
+       default: assert(0);
+       }
+}
+
+static void print_obj_lists(struct alisp_instance *instance, snd_output_t *out)
+{
+       struct alisp_object * p;
+
+       snd_output_printf(out, "** used objects");
+       for (p = instance->used_objs_list; p != NULL; p = p->next)
+               snd_output_printf(out, "**   %p (%s)", p, obj_type_str(p));
+       snd_output_printf(out, "** free objects");
+       for (p = instance->free_objs_list; p != NULL; p = p->next)
+               snd_output_printf(out, "**   %p (%s)", p, obj_type_str(p));
+}
+
+static void dump_obj_lists(struct alisp_instance *instance, const char *fname)
+{
+       snd_output_t *out;
+       int err;
+
+       if (!strcmp(fname, "-"))
+               err = snd_output_stdio_attach(&out, stdout, 0);
+       else
+               err = snd_output_stdio_open(&out, fname, "w+");
+       if (err < 0) {
+               SNDERR("alisp: cannot open file '%s' for writting (%s)", fname, snd_strerror(errno));
+               return;
+       }
+
+       print_obj_lists(instance, out);
+
+       snd_output_close(out);
+}
+
+/*
+ *  garbage collection
+ */
+
+static void tag_tree(struct alisp_instance *instance, struct alisp_object * p)
+{
+       if (p->gc == instance->gc_id)
+               return;
+
+       p->gc = instance->gc_id;
+
+       if (p->type == ALISP_OBJ_CONS) {
+               tag_tree(instance, p->value.c.car);
+               tag_tree(instance, p->value.c.cdr);
+       }
+}
+
+static void tag_whole_tree(struct alisp_instance *instance)
+{
+       struct alisp_object_pair *p;
+
+       for (p = instance->setobjs_list; p != NULL; p = p->next) {
+               tag_tree(instance, p->name);
+               tag_tree(instance, p->value);
+       }
+}
+       
+static void do_garbage_collect(struct alisp_instance *instance)
+{
+       struct alisp_object * p, * new_used_objs_list = NULL, * next;
+
+       tag_whole_tree(instance);
+
+       /*
+        * Search in the object vector.
+        */
+       for (p = instance->used_objs_list; p != NULL; p = next) {
+               next = p->next;
+               if (p->gc != instance->gc_id) {
+                       /* Remove unreferenced object. */
+                       lisp_debug(instance, "** collecting cons %p", p);
+                       switch (p->type) {
+                       case ALISP_OBJ_STRING:
+                               free(p->value.s);
+                               break;
+                       case ALISP_OBJ_IDENTIFIER:
+                               free(p->value.id);
+                               break;
+                       }
+
+                       p->next = instance->free_objs_list;
+                       instance->free_objs_list = p;
+
+                       ++instance->free_objs;
+                       --instance->used_objs;
+               } else {
+                       /* The object is referenced somewhere. */
+                       p->next = new_used_objs_list;
+                       new_used_objs_list = p;
+               }
+       }
+
+       instance->used_objs_list = new_used_objs_list;
+}
+
+static void garbage_collect(struct alisp_instance *instance)
+{
+       if (++instance->gc_id == INT_MAX)
+               instance->gc_id = 1;
+       do_garbage_collect(instance);
+}
+
+/*
+ *  functions
+ */
+
+static int count_list(struct alisp_object * p)
+{
+       int i = 0;
+
+       while (p != &alsa_lisp_nil && p->type == ALISP_OBJ_CONS)
+               p = p->value.c.cdr, ++i;
+
+       return i;
+}
+
+static inline struct alisp_object * car(struct alisp_object * p)
+{
+       if (p->type == ALISP_OBJ_CONS)
+               return p->value.c.car;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (car expr)
+ */
+static struct alisp_object * F_car(struct alisp_instance *instance, struct alisp_object * args)
+{
+       return car(eval(instance, car(args)));
+}
+
+static inline struct alisp_object * cdr(struct alisp_object * p)
+{
+       if (p->type == ALISP_OBJ_CONS)
+               return p->value.c.cdr;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (cdr expr)
+ */
+static struct alisp_object * F_cdr(struct alisp_instance *instance, struct alisp_object * args)
+{
+       return cdr(eval(instance, car(args)));
+}
+
+/*
+ * Syntax: (+ expr...)
+ */
+static struct alisp_object * F_add(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+       int v = 0;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1->type == ALISP_OBJ_INTEGER)
+                       v += p1->value.i;
+               else
+                       lisp_warn(instance, "sum with a non integer operand");
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       p1 = new_object(instance, ALISP_OBJ_INTEGER);
+       if (p1)
+               p1->value.i = v;
+
+       return p1;
+}
+
+/*
+ * Syntax: (- expr...)
+ */
+static struct alisp_object * F_sub(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+       int v = 0;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1->type == ALISP_OBJ_INTEGER) {
+                       if (p == args && cdr(p) != &alsa_lisp_nil)
+                               v = p1->value.i;
+                       else
+                               v -= p1->value.i;
+               } else
+                       lisp_warn(instance, "difference with a non integer operand");
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       p1 = new_object(instance, ALISP_OBJ_INTEGER);
+       if (p1)
+               p1->value.i = v;
+
+       return p1;
+}
+
+/*
+ * Syntax: (* expr...)
+ */
+static struct alisp_object * F_mul(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+       int v = 1;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1->type == ALISP_OBJ_INTEGER)
+                       v *= p1->value.i;
+               else
+                       lisp_warn(instance, "product with a non integer operand");
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       p1 = new_object(instance, ALISP_OBJ_INTEGER);
+       if (p1)
+               p1->value.i = v;
+
+       return p1;
+}
+
+/*
+ * Syntax: (/ expr...)
+ */
+static struct alisp_object * F_div(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+       int v = 0;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1->type == ALISP_OBJ_INTEGER) {
+                       if (p == args && cdr(p) != &alsa_lisp_nil)
+                               v = p1->value.i;
+                       else {
+                               if (p1->value.i == 0) {
+                                       lisp_warn(instance, "division by zero");
+                                       v = 0;
+                                       break;
+                               } else
+                                       v /= p1->value.i;
+                       }
+               } else
+                       lisp_warn(instance, "quotient with a non integer operand");
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       p1 = new_object(instance, ALISP_OBJ_INTEGER);
+       if (p1)
+               p1->value.i = v;
+
+       return p1;
+}
+
+/*
+ * Syntax: (% expr1 expr2)
+ */
+static struct alisp_object * F_mod(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2, * p3;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "module with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       p3 = new_object(instance, ALISP_OBJ_INTEGER);
+       if (p2->value.i == 0) {
+               lisp_warn(instance, "module by zero");
+               if (p3)
+                       p3->value.i = 0;
+       } else
+               if (p3)
+                       p3->value.i = p1->value.i % p2->value.i;
+
+       return p3;
+}
+
+/*
+ * Syntax: (< expr1 expr2)
+ */
+static struct alisp_object * F_lt(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "comparison with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       if (p1->value.i < p2->value.i)
+               return &alsa_lisp_t;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (> expr1 expr2)
+ */
+static struct alisp_object * F_gt(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "comparison with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       if (p1->value.i > p2->value.i)
+               return &alsa_lisp_t;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (<= expr1 expr2)
+ */
+static struct alisp_object * F_le(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "comparison with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       if (p1->value.i <= p2->value.i)
+               return &alsa_lisp_t;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (>= expr1 expr2)
+ */
+static struct alisp_object * F_ge(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "comparison with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       if (p1->value.i >= p2->value.i)
+               return &alsa_lisp_t;
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (= expr1 expr2)
+ */
+static struct alisp_object * F_numeq(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1->type != ALISP_OBJ_INTEGER || p2->type != ALISP_OBJ_INTEGER) {
+               lisp_warn(instance, "comparison with a non integer operand");
+               return &alsa_lisp_nil;
+       }
+
+       if (p1->value.i == p2->value.i)
+               return &alsa_lisp_t;
+
+       return &alsa_lisp_nil;
+}
+
+static void princ_string(snd_output_t *out, char *s)
+{
+       char *p;
+
+       snd_output_putc(out, '"');
+       for (p = s; *p != '\0'; ++p)
+               switch (*p) {
+               case '\a': snd_output_putc(out, '\\'); snd_output_putc(out, 'a'); break;
+               case '\b': snd_output_putc(out, '\\'); snd_output_putc(out, 'b'); break;
+               case '\f': snd_output_putc(out, '\\'); snd_output_putc(out, 'f'); break;
+               case '\n': snd_output_putc(out, '\\'); snd_output_putc(out, 'n'); break;
+               case '\r': snd_output_putc(out, '\\'); snd_output_putc(out, 'r'); break;
+               case '\t': snd_output_putc(out, '\\'); snd_output_putc(out, 't'); break;
+               case '\v': snd_output_putc(out, '\\'); snd_output_putc(out, 'v'); break;
+               default: snd_output_putc(out, *p);
+               }
+       snd_output_putc(out, '"');
+}
+
+static void princ_object(snd_output_t *out, struct alisp_object * p)
+{
+       struct alisp_object * p1;
+
+       switch (p->type) {
+       case ALISP_OBJ_NIL:
+               snd_output_printf(out, "nil");
+               break;
+       case ALISP_OBJ_T:
+               snd_output_putc(out, 't');
+               break;
+       case ALISP_OBJ_IDENTIFIER:
+               snd_output_printf(out, "%s", p->value.id);
+               break;
+       case ALISP_OBJ_STRING:
+               princ_string(out, p->value.s);
+               break;
+       case ALISP_OBJ_INTEGER:
+               snd_output_printf(out, "%d", p->value.i);
+               break;
+       case ALISP_OBJ_CONS:
+               snd_output_putc(out, '(');
+               p1 = p;
+               do {
+                       princ_object(out, p1->value.c.car);
+                       p1 = p1->value.c.cdr;
+                       if (p1 != &alsa_lisp_nil) {
+                               snd_output_putc(out, ' ');
+                               if (p1->type != ALISP_OBJ_CONS) {
+                                       snd_output_printf(out, ". ");
+                                       princ_object(out, p1);
+                               }
+                       }
+               } while (p1 != &alsa_lisp_nil && p1->type == ALISP_OBJ_CONS);
+               snd_output_putc(out, ')');
+       }
+}
+
+/*
+ * Syntax: (princ expr...)
+ */
+static struct alisp_object * F_princ(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1->type == ALISP_OBJ_STRING)
+                       snd_output_printf(instance->out, "%s", p1->value.s);
+               else
+                       princ_object(instance->out, p1);
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return p1;
+}
+
+/*
+ * Syntax: (atom expr)
+ */
+static struct alisp_object * F_atom(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p;
+
+       p = eval(instance, car(args));
+
+       switch (p->type) {
+       case ALISP_OBJ_T:
+       case ALISP_OBJ_NIL:
+       case ALISP_OBJ_INTEGER:
+       case ALISP_OBJ_STRING:
+       case ALISP_OBJ_IDENTIFIER:
+               return &alsa_lisp_t;
+       }
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (cons expr1 expr2)
+ */
+static struct alisp_object * F_cons(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p;
+
+       p = new_object(instance, ALISP_OBJ_CONS);
+       if (p) {
+               p->value.c.car = eval(instance, car(args));
+               p->value.c.cdr = eval(instance, car(cdr(args)));
+       }
+
+       return p;
+}
+
+/*
+ * Syntax: (list expr1...)
+ */
+static struct alisp_object * F_list(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * first = NULL, * prev = NULL, * p1;
+
+       if (p == &alsa_lisp_nil)
+               return &alsa_lisp_nil;
+
+       do {
+               p1 = new_object(instance, ALISP_OBJ_CONS);
+               if (p1 == NULL)
+                       return NULL;
+               p1->value.c.car = eval(instance, car(p));
+               if (first == NULL)
+                       first = p1;
+               if (prev != NULL)
+                       prev->value.c.cdr = p1;
+               prev = p1;
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return first;
+}
+
+/*
+ * Syntax: (eq expr1 expr2)
+ */
+static struct alisp_object * F_eq(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = eval(instance, car(args));
+       p2 = eval(instance, car(cdr(args)));
+
+       if (p1 == p2)
+               return &alsa_lisp_t;
+
+       if (p1->type == ALISP_OBJ_CONS || p2->type == ALISP_OBJ_CONS)
+               return &alsa_lisp_nil;
+
+       if (p1->type == p2->type)
+               switch (p1->type) {
+               case ALISP_IDENTIFIER:
+                       if (!strcmp(p1->value.id, p2->value.id))
+                               return &alsa_lisp_t;
+                       return &alsa_lisp_nil;
+               case ALISP_OBJ_STRING:
+                       if (!strcmp(p1->value.s, p2->value.s))
+                               return &alsa_lisp_t;
+                       return &alsa_lisp_nil;
+               case ALISP_OBJ_INTEGER:
+                       if (p1->value.i == p2->value.i)
+                               return &alsa_lisp_t;
+                       return &alsa_lisp_nil;
+               }
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (quote expr)
+ */
+static struct alisp_object * F_quote(struct alisp_instance *instance ATTRIBUTE_UNUSED, struct alisp_object * args)
+{
+       return car(args);
+}
+
+/*
+ * Syntax: (and expr...)
+ */
+static struct alisp_object * F_and(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1 == &alsa_lisp_nil)
+                       return &alsa_lisp_nil;
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return p1;
+}
+
+/*
+ * Syntax: (or expr...)
+ */
+static struct alisp_object * F_or(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (p1 != &alsa_lisp_nil)
+                       return p1;
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (not expr)
+ * Syntax: (null expr)
+ */
+static struct alisp_object * F_not(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = eval(instance, car(args));
+
+       if (p != &alsa_lisp_nil)
+               return &alsa_lisp_nil;
+
+       return &alsa_lisp_t;
+}
+
+/*
+ * Syntax: (cond (expr1 [expr2])...)
+ */
+static struct alisp_object * F_cond(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1, * p2, * p3;
+
+       do {
+               p1 = car(p);
+               if ((p2 = eval(instance, car(p1))) != &alsa_lisp_nil) {
+                       if ((p3 = cdr(p1)) != &alsa_lisp_nil)
+                               return F_progn(instance, p3);
+                       return p2;
+               }
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (if expr then-expr else-expr...)
+ */
+static struct alisp_object * F_if(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2, * p3;
+
+       p1 = car(args);
+       p2 = car(cdr(args));
+       p3 = cdr(cdr(args));
+
+       if (eval(instance, p1) != &alsa_lisp_nil)
+               return eval(instance, p2);
+
+       return F_progn(instance, p3);
+}
+
+/*
+ * Syntax: (when expr then-expr...)
+ */
+static struct alisp_object * F_when(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = car(args);
+       p2 = cdr(args);
+       if (eval(instance, p1) != &alsa_lisp_nil)
+               return F_progn(instance, p2);
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (unless expr else-expr...)
+ */
+static struct alisp_object * F_unless(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = car(args);
+       p2 = cdr(args);
+       if (eval(instance, p1) == &alsa_lisp_nil)
+               return F_progn(instance, p2);
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (while expr exprs...)
+ */
+static struct alisp_object * F_while(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2;
+
+       p1 = car(args);
+       p2 = cdr(args);
+
+       while (eval(instance, p1) != &alsa_lisp_nil)
+               F_progn(instance, p2);
+
+       return &alsa_lisp_nil;
+}
+
+/*
+ * Syntax: (progn expr...)
+ */
+static struct alisp_object * F_progn(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1;
+
+       do {
+               p1 = eval(instance, car(p));
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       return p1;
+}
+
+/*
+ * Syntax: (prog1 expr...)
+ */
+static struct alisp_object * F_prog1(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * first = NULL, * p1;
+
+       do {
+               p1 = eval(instance, car(p));
+               if (first == NULL)
+                       first = p1;
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       if (first == NULL)
+               first = &alsa_lisp_nil;
+
+       return first;
+}
+
+/*
+ * Syntax: (prog2 expr...)
+ */
+static struct alisp_object * F_prog2(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * second = NULL, * p1;
+       int i = 0;
+
+       do {
+               ++i;
+               p1 = eval(instance, car(p));
+               if (i == 2)
+                       second = p1;
+               p = cdr(p);
+       } while (p != &alsa_lisp_nil);
+
+       if (second == NULL)
+               second = &alsa_lisp_nil;
+
+       return second;
+}
+
+/*
+ * Syntax: (set name value)
+ */
+static struct alisp_object * F_set(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1 = eval(instance, car(args)), * p2 = eval(instance, car(cdr(args)));
+
+       if (p1 == &alsa_lisp_nil) {
+               lisp_warn(instance, "setting the value of a nil object");
+       } else
+               if (set_object(instance, p1, p2))
+                       return NULL;
+
+       return p2;
+}
+
+/*
+ * Syntax: (setq name value...)
+ * Syntax: (setf name value...)
+ * `name' is not evalled
+ */
+static struct alisp_object * F_setq(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = args, * p1, * p2;
+
+       do {
+               p1 = car(p);
+               p2 = eval(instance, car(cdr(p)));
+               if (set_object(instance, p1, p2))
+                       return NULL;
+               p = cdr(cdr(p));
+       } while (p != &alsa_lisp_nil);
+
+       return p2;
+}
+
+/*
+ * Syntax: (defun name arglist expr...)
+ * `name' is not evalled
+ * `arglist' is not evalled
+ */
+static struct alisp_object * F_defun(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p1 = car(args), * p2 = car(cdr(args)), * p3 = cdr(cdr(args));
+       struct alisp_object * lexpr;
+
+       lexpr = new_object(instance, ALISP_OBJ_CONS);
+       if (lexpr) {
+               lexpr->value.c.car = new_object(instance, ALISP_IDENTIFIER);
+               if (lexpr->value.c.car == NULL)
+                       return NULL;
+               if ((lexpr->value.c.car->value.id = strdup("lambda")) == NULL) {
+                       nomem();
+                       return NULL;
+               }
+               if ((lexpr->value.c.cdr = new_object(instance, ALISP_OBJ_CONS)) == NULL)
+                       return NULL;
+               lexpr->value.c.cdr->value.c.car = p2;
+               lexpr->value.c.cdr->value.c.cdr = p3;
+
+               if (set_object(instance, p1, lexpr))
+                       return NULL;
+       }
+
+       return lexpr;
+}
+
+static struct alisp_object * eval_func(struct alisp_instance *instance, struct alisp_object * p, struct alisp_object * args)
+{
+       struct alisp_object * p1, * p2, * p3, * p4, * p5;
+       struct alisp_object * eval_objs[64], * save_objs[64];
+       int i;
+
+       p1 = car(p);
+       if (p1->type == ALISP_IDENTIFIER && !strcmp(p1->value.id, "lambda")) {
+               p2 = car(cdr(p));
+               p3 = args;
+
+               if (count_list(p2) != count_list(p3)) {
+                       lisp_warn(instance, "wrong number of parameters");
+                       return &alsa_lisp_nil;
+               }
+
+               /*
+                * Save the new variable values.
+                */
+               i = 0;
+               do {
+                       p5 = eval(instance, car(p3));
+                       eval_objs[i++] = p5;
+                       p3 = cdr(p3);
+               } while (p3 != &alsa_lisp_nil);
+
+               /*
+                * Save the old variable values and set the new ones.
+                */
+               i = 0;
+               do {
+                       p4 = car(p2);
+                       save_objs[i] = get_object(instance, p4);
+                       if (set_object(instance, p4, eval_objs[i]))
+                               return NULL;
+                       p2 = cdr(p2);
+                       ++i;
+               } while (p2 != &alsa_lisp_nil);
+
+               p5 = F_progn(instance, cdr(cdr(p)));
+
+               /*
+                * Restore the old variable values.
+                */
+               p2 = car(cdr(p));
+               i = 0;
+               do {
+                       p4 = car(p2);
+                       if (set_object(instance, p4, save_objs[i++]))
+                               return NULL;
+                       p2 = cdr(p2);
+               } while (p2 != &alsa_lisp_nil);
+
+               return p5;
+       }
+
+       return &alsa_lisp_nil;
+}
+
+struct alisp_object * F_gc(struct alisp_instance *instance, struct alisp_object * args ATTRIBUTE_UNUSED)
+{
+       garbage_collect(instance);
+
+       return &alsa_lisp_t;
+}
+
+static struct alisp_object * F_dump_memory(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = car(args);
+
+       if (p != &alsa_lisp_nil && cdr(args) == &alsa_lisp_nil && p->type == ALISP_OBJ_STRING) {
+               if (strlen(p->value.s) > 0) {
+                       dump_objects(instance, p->value.s);
+                       return &alsa_lisp_t;
+               } else
+                       lisp_warn(instance, "expected filename");
+       } else
+               lisp_warn(instance, "wrong number of parameters (expected string)");
+
+       return &alsa_lisp_nil;
+}
+
+static struct alisp_object * F_dump_objects(struct alisp_instance *instance, struct alisp_object * args)
+{
+       struct alisp_object * p = car(args);
+
+       if (p != &alsa_lisp_nil && cdr(args) == &alsa_lisp_nil && p->type == ALISP_OBJ_STRING) {
+               if (strlen(p->value.s) > 0) {
+                       dump_obj_lists(instance, p->value.s);
+                       return &alsa_lisp_t;
+               } else
+                       lisp_warn(instance, "expected filename");
+       } else
+               lisp_warn(instance, "wrong number of parameters (expected string)");
+
+       return &alsa_lisp_nil;
+}
+
+struct intrinsic {
+       const char *name;
+       struct alisp_object * (*func)(struct alisp_instance *instance, struct alisp_object * args);
+};
+
+static struct intrinsic intrinsics[] = {
+       { "%", F_mod },
+       { "&dump-memory", F_dump_memory },
+       { "&dump-objects", F_dump_objects },
+       { "*", F_mul },
+       { "+", F_add },
+       { "-", F_sub },
+       { "/", F_div },
+       { "<", F_lt },
+       { "<=", F_le },
+       { "=", F_numeq },
+       { ">", F_gt },
+       { ">=", F_ge },
+       { "and", F_and },
+       { "atom", F_atom },
+       { "car", F_car },
+       { "cdr", F_cdr },
+       { "cond", F_cond },
+       { "cons", F_cons },
+       { "defun", F_defun },
+       { "eq", F_eq },
+       { "eval", F_eval },
+       { "garbage-collect", F_gc },
+       { "gc", F_gc },
+       { "if", F_if },
+       { "list", F_list },
+       { "not", F_not },
+       { "null", F_not },
+       { "or", F_or },
+       { "princ", F_princ },
+       { "prog1", F_prog1 },
+       { "prog2", F_prog2 },
+       { "progn", F_progn },
+       { "quote", F_quote },
+       { "set", F_set },
+       { "setf", F_setq },
+       { "setq", F_setq },
+       { "unless", F_unless },
+       { "when", F_when },
+       { "while", F_while },
+};
+
+static int compar(const void *p1, const void *p2)
+{
+       return strcmp(((struct intrinsic *)p1)->name,
+                     ((struct intrinsic *)p2)->name);
+}
+
+static struct alisp_object * eval_cons(struct alisp_instance *instance, struct alisp_object * p)
+{
+       struct alisp_object * p1 = car(p), * p2 = cdr(p), * p3;
+
+       if (p1 != &alsa_lisp_nil && p1->type == ALISP_IDENTIFIER) {
+               struct intrinsic key, *item;
+
+               if (!strcmp(p1->value.id, "lambda"))
+                       return p;
+               key.name = p1->value.id;
+               if ((item = bsearch(&key, intrinsics,
+                                   sizeof intrinsics / sizeof intrinsics[0],
+                                   sizeof intrinsics[0], compar)) != NULL)
+                       return item->func(instance, p2);
+
+               if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil)
+                       return eval_func(instance, p3, p2);
+               else
+                       lisp_warn(instance, "function `%s' is undefined", p1->value.id);
+       }
+
+       return &alsa_lisp_nil;
+}
+
+static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_object * p)
+{
+       switch (p->type) {
+       case ALISP_OBJ_IDENTIFIER:
+               return get_object(instance, p);
+       case ALISP_OBJ_INTEGER:
+       case ALISP_OBJ_STRING:
+               return p;
+       case ALISP_OBJ_CONS:
+               return eval_cons(instance, p);
+       }
+
+       return p;
+}
+
+static struct alisp_object * F_eval(struct alisp_instance *instance, struct alisp_object * args)
+{
+       return eval(instance, eval(instance, car(args)));
+}
+
+/*
+ *  main routine
+ */
+int alsa_lisp(struct alisp_cfg *cfg)
+{
+       struct alisp_instance *instance;
+       struct alisp_object *p, *p1;
+       
+       instance = (struct alisp_instance *)malloc(sizeof(struct alisp_instance));
+       if (instance == NULL) {
+               nomem();
+               return -ENOMEM;
+       }
+       instance->verbose = cfg->verbose && cfg->vout;
+       instance->warning = cfg->warning && cfg->wout;
+       instance->debug = cfg->debug && cfg->dout;
+       instance->in = cfg->in;
+       instance->out = cfg->out;
+       instance->vout = cfg->vout;
+       instance->wout = cfg->wout;
+       instance->dout = cfg->dout;
+       
+       init_lex(instance);
+
+       for (;;) {
+               if ((p = parse_object(instance, 0)) == NULL)
+                       break;
+               if (instance->verbose)
+                       princ_object(instance->vout, p);
+               p1 = eval(instance, p);
+               if (instance->verbose)
+                       princ_object(instance->vout, p1);
+               if (instance->debug) {
+                       lisp_debug(instance, "** objects before collection");
+                       print_obj_lists(instance, instance->dout);
+               }
+               garbage_collect(instance);
+               if (instance->debug) {
+                       lisp_debug(instance, "** objects after collection");
+                       print_obj_lists(instance, instance->dout);
+               }
+       }
+
+       done_lex(instance);
+       free(instance);
+       
+       return 0;
+}
diff --git a/src/alisp/alisp_local.h b/src/alisp/alisp_local.h
new file mode 100644 (file)
index 0000000..d5361e9
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  ALSA lisp implementation
+ *  Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *  Based on work of Sandro Sigala (slisp-1.2)
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as
+ *   published by the Free Software Foundation; either version 2.1 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+enum alisp_tokens {
+       ALISP_IDENTIFIER,
+       ALISP_INTEGER,
+       ALISP_STRING
+};
+
+enum alisp_objects {
+       ALISP_OBJ_NIL,
+       ALISP_OBJ_T,
+       ALISP_OBJ_INTEGER,
+       ALISP_OBJ_IDENTIFIER,
+       ALISP_OBJ_STRING,
+       ALISP_OBJ_CONS
+};
+
+struct alisp_object {
+       int     type;
+       int     gc;
+       union {
+               char    *id;
+               char    *s;
+               int     i;
+               struct {
+                       struct alisp_object *car;
+                       struct alisp_object *cdr;
+               } c;
+       } value;
+       struct alisp_object *next;
+};
+
+struct alisp_object_pair {
+       struct alisp_object *name;
+       struct alisp_object *value;
+       struct alisp_object_pair *next;
+};
+
+#define ALISP_LEX_BUF_MAX 16
+
+struct alisp_instance {
+       int verbose: 1,
+           warning: 1,
+           debug: 1;
+       /* i/o */
+       snd_input_t *in;
+       snd_output_t *out;
+       snd_output_t *vout;     /* verbose output */
+       snd_output_t *wout;     /* warning output */
+       snd_output_t *dout;     /* debug output */
+       /* lexer */
+       int charno;
+       int lineno;
+       int lex_buf[ALISP_LEX_BUF_MAX];
+       int *lex_bufp;
+       char *token_buffer;
+       int token_buffer_max;
+       int thistoken;
+       /* object allocator */
+       int free_objs;
+       int used_objs;
+       struct alisp_object *free_objs_list;
+       struct alisp_object *used_objs_list;
+       /* set object */
+       struct alisp_object_pair *setobjs_list;
+       /* garbage collect */
+       int gc_id;
+       /* alsa configuration */
+       snd_config_t *root;     /* configuration root */
+       snd_config_t *node;     /* result */
+};
index 2804b20f4c120ecab18abf83fc86e6de9df00a0c..3bf112f3639edbf3e531da5c0515acba162c9fd2 100644 (file)
@@ -78,6 +78,18 @@ int snd_output_printf(snd_output_t *output, const char *format, ...)
        return result;
 }
 
+/**
+ * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
+ * \param output The output handle.
+ * \param format Format string in \c fprintf format.
+ * \param args Other \c fprintf arguments.
+ * \return The number of characters written, or a negative error code.
+ */
+int snd_output_vprintf(snd_output_t *output, const char *format, va_list args)
+{
+       return output->ops->print(output, format, args);
+}
+
 /**
  * \brief Writes a string to an output handle (like \c fputs(3)).
  * \param output The output handle.