Update of /cvsroot/alsa/alsa-lib/src/alisp In directory sc8-pr-cvs1:/tmp/cvs-serv25356/src/alisp
Added Files: .cvsignore Makefile.am alisp.c alisp_local.h Log Message: Initial code for lisp interpreter --- NEW FILE: .cvsignore --- .deps .libs Makefile Makefile.in *.la *.lo --- NEW FILE: Makefile.am --- EXTRA_LTLIBRARIES = libalisp.la libalisp_la_SOURCES = alisp.c noinst_HEADERS = alisp_local.h all: libalisp.la INCLUDES=-I$(top_srcdir)/include --- NEW FILE: alisp.c --- /* * ALSA lisp implementation * Copyright (c) 2003 by Jaroslav Kysela <[EMAIL PROTECTED]> * * 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; } --- NEW FILE: alisp_local.h --- /* * ALSA lisp implementation * Copyright (c) 2003 by Jaroslav Kysela <[EMAIL PROTECTED]> * * 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 */ }; ------------------------------------------------------- This SF.Net email is sponsored by: INetU Attention Web Developers & Consultants: Become An INetU Hosting Partner. Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission! INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog