|
Packit |
df99a1 |
/* -*- C++ -*-
|
|
Packit |
df99a1 |
// -------------------------------------------------------------------
|
|
Packit |
df99a1 |
// MiniLisp - Very small lisp interpreter to demonstrate MiniExp.
|
|
Packit |
df99a1 |
// Copyright (c) 2005 Leon Bottou
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
// GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
// or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
// accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
// from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//
|
|
Packit |
df99a1 |
// This program is distributed in the hope that it will be useful,
|
|
Packit |
df99a1 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
df99a1 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
df99a1 |
// GNU General Public License for more details.
|
|
Packit |
df99a1 |
// -------------------------------------------------------------------
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include <stdlib.h>
|
|
Packit |
df99a1 |
#include <stdio.h>
|
|
Packit |
df99a1 |
#include <string.h>
|
|
Packit |
df99a1 |
#include <signal.h>
|
|
Packit |
df99a1 |
#include <ctype.h>
|
|
Packit |
df99a1 |
#include <math.h>
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "miniexp.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define CAT(a,b) __CAT(a,b)
|
|
Packit |
df99a1 |
#define __CAT(a,b) a ## b
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t s_quote = miniexp_symbol("quote");
|
|
Packit |
df99a1 |
miniexp_t s_true = miniexp_symbol("t");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ error */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef __GNUC__
|
|
Packit |
df99a1 |
void error(const char *msg, miniexp_t v=0) __attribute__ ((noreturn));
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
void error(const char *msg, miniexp_t v=0);
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
error(const char *msg, miniexp_t v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (msg)
|
|
Packit |
df99a1 |
printf("ERROR: %s", msg);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
printf("BREAK");
|
|
Packit |
df99a1 |
if (v)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
printf(": ");
|
|
Packit |
df99a1 |
miniexp_prin(v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
printf("\n");
|
|
Packit |
df99a1 |
throw 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ environment */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
lookup(miniexp_t var, miniexp_t env)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
while (miniexp_consp(env))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_car(env);
|
|
Packit |
df99a1 |
if (miniexp_car(a) == var)
|
|
Packit |
df99a1 |
return a;
|
|
Packit |
df99a1 |
env = miniexp_cdr(env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
minivar_t globalenv;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
defvar(miniexp_t s, miniexp_t w = 0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
if (! globalenv)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t a = miniexp_cons(s_true, s_true);
|
|
Packit |
df99a1 |
globalenv = miniexp_cons(a, 0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (! miniexp_symbolp(s))
|
|
Packit |
df99a1 |
error("defvar: not a symbol", s);
|
|
Packit |
df99a1 |
miniexp_t a = lookup(s, globalenv);
|
|
Packit |
df99a1 |
if (a && w)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
printf("WARNING: redefining '%s\n", miniexp_to_name(s));
|
|
Packit |
df99a1 |
miniexp_rplacd(a, w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
v = miniexp_cons(s, w);
|
|
Packit |
df99a1 |
v = miniexp_cons(v, miniexp_cdr(globalenv));
|
|
Packit |
df99a1 |
miniexp_rplacd(globalenv, v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ evaluate */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool break_request = false;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
struct callable_t : public miniobj_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(callable_t,miniobj_t,"callable");
|
|
Packit |
df99a1 |
virtual miniexp_t call(miniexp_t args, miniexp_t env,
|
|
Packit |
df99a1 |
bool apply=false) = 0;
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(callable_t,miniobj_t,"callable");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
evaluate(miniexp_t expr, miniexp_t env)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_symbolp(expr))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t a = lookup(expr,env);
|
|
Packit |
df99a1 |
if (! a)
|
|
Packit |
df99a1 |
error ("eval: undefined variable", expr);
|
|
Packit |
df99a1 |
return miniexp_cdr(a);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_consp(expr))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t s = miniexp_car(expr);
|
|
Packit |
df99a1 |
minivar_t xs = evaluate(s, env);
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(xs);
|
|
Packit |
df99a1 |
if (break_request)
|
|
Packit |
df99a1 |
error(0);
|
|
Packit |
df99a1 |
if (obj && obj->isa(callable_t::classname))
|
|
Packit |
df99a1 |
return ((callable_t*)obj)->call(miniexp_cdr(expr), env);
|
|
Packit |
df99a1 |
error("apply: cannot apply this object", xs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return expr;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
evaluate_progn(miniexp_t exprs, miniexp_t env)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
while (miniexp_consp(exprs))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
v = evaluate(miniexp_car(exprs),env);
|
|
Packit |
df99a1 |
exprs = miniexp_cdr(exprs);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (exprs)
|
|
Packit |
df99a1 |
v = evaluate(exprs,env);
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
evaluate_list(miniexp_t l, miniexp_t env)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
minivar_t ll = 0;
|
|
Packit |
df99a1 |
miniexp_t lp = ll;
|
|
Packit |
df99a1 |
if (miniexp_consp(l))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
v = evaluate(miniexp_car(l), env);
|
|
Packit |
df99a1 |
lp = ll = miniexp_cons(v, 0);
|
|
Packit |
df99a1 |
l = miniexp_cdr(l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
while (miniexp_consp(l))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
v = evaluate(miniexp_car(l), env);
|
|
Packit |
df99a1 |
miniexp_rplacd(lp, miniexp_cons(v, 0));
|
|
Packit |
df99a1 |
lp = miniexp_cdr(lp);
|
|
Packit |
df99a1 |
l = miniexp_cdr(l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (l)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
v = evaluate(l, env);
|
|
Packit |
df99a1 |
if (lp)
|
|
Packit |
df99a1 |
miniexp_rplacd(lp, v);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
ll = v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return ll;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ special forms */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class specialform_t : public callable_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
typedef miniexp_t (*fptr_t)(miniexp_t, miniexp_t);
|
|
Packit |
df99a1 |
fptr_t fptr;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
specialform_t(const char *name, fptr_t fptr);
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(specialform_t,callable_t,"specialform");
|
|
Packit |
df99a1 |
virtual miniexp_t call(miniexp_t args, miniexp_t env, bool);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(specialform_t,callable_t,"specialform");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
specialform_t::specialform_t(const char *name, fptr_t fptr)
|
|
Packit |
df99a1 |
: fptr(fptr)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t s = miniexp_symbol(name);
|
|
Packit |
df99a1 |
minivar_t v = miniexp_object(this);
|
|
Packit |
df99a1 |
defvar(s, v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
specialform_t::call(miniexp_t args, miniexp_t env, bool)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return (*fptr)(args, env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define DEFSPECIAL(s, n) \
|
|
Packit |
df99a1 |
miniexp_t CAT(f_,n)(miniexp_t, miniexp_t);\
|
|
Packit |
df99a1 |
specialform_t *CAT(p_,n) = new specialform_t(s, CAT(f_,n));\
|
|
Packit |
df99a1 |
miniexp_t CAT(f_,n)(miniexp_t expr, miniexp_t env)
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ primitives */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class primitive_t : public callable_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
typedef miniexp_t (*fptr_t)(int, miniexp_t*, miniexp_t);
|
|
Packit |
df99a1 |
fptr_t fptr;
|
|
Packit |
df99a1 |
const int args;
|
|
Packit |
df99a1 |
const int optargs;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
primitive_t(const char *name, fptr_t fptr, int a, int o);
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(primitive_t,callable_t,"primitive");
|
|
Packit |
df99a1 |
virtual miniexp_t call(miniexp_t args, miniexp_t env, bool);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(primitive_t,callable_t,"primitive");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
primitive_t::primitive_t(const char *n, fptr_t f, int a, int o)
|
|
Packit |
df99a1 |
: fptr(f), args(a), optargs(o)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t s = miniexp_symbol(n);
|
|
Packit |
df99a1 |
minivar_t v = miniexp_object(this);
|
|
Packit |
df99a1 |
defvar(s, v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
primitive_t::call(miniexp_t args, miniexp_t env, bool apply)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int argc = miniexp_length(args);
|
|
Packit |
df99a1 |
if (argc < this->args)
|
|
Packit |
df99a1 |
error("apply(primitive): not enough arguments");
|
|
Packit |
df99a1 |
if (argc > this->args + this->optargs)
|
|
Packit |
df99a1 |
error("apply(primitive): too many arguments");
|
|
Packit |
df99a1 |
minivar_t xargs = apply ? args : evaluate_list(args, env);
|
|
Packit |
df99a1 |
miniexp_t *argv = new miniexp_t[argc];
|
|
Packit |
df99a1 |
miniexp_t a = xargs;
|
|
Packit |
df99a1 |
argc = 0;
|
|
Packit |
df99a1 |
while (miniexp_consp(a))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
argv[argc++] = miniexp_car(a);
|
|
Packit |
df99a1 |
a = miniexp_cdr(a);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
try
|
|
Packit |
df99a1 |
{ v = (*fptr)(argc, argv, env); }
|
|
Packit |
df99a1 |
catch(...)
|
|
Packit |
df99a1 |
{ delete [] argv; throw; }
|
|
Packit |
df99a1 |
delete [] argv;
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define DEFUN(s, n,a,o) \
|
|
Packit |
df99a1 |
miniexp_t CAT(f_,n)(int argc, miniexp_t *argv, miniexp_t env);\
|
|
Packit |
df99a1 |
primitive_t *CAT(p_,n) = new primitive_t(s, CAT(f_,n), a, o);\
|
|
Packit |
df99a1 |
miniexp_t CAT(f_,n)(int argc, miniexp_t *argv, miniexp_t env)
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------- functions */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class function_t : public callable_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
protected:
|
|
Packit |
df99a1 |
miniexp_t args;
|
|
Packit |
df99a1 |
miniexp_t body;
|
|
Packit |
df99a1 |
miniexp_t env;
|
|
Packit |
df99a1 |
static void check_args(miniexp_t a);
|
|
Packit |
df99a1 |
static void match_args(miniexp_t a, miniexp_t v, miniexp_t &env;;
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
function_t(miniexp_t, miniexp_t, miniexp_t);
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(function_t,callable_t,"function");
|
|
Packit |
df99a1 |
virtual miniexp_t call(miniexp_t args, miniexp_t env, bool);
|
|
Packit |
df99a1 |
virtual void mark(minilisp_mark_t action);
|
|
Packit |
df99a1 |
virtual miniexp_t funcdef(miniexp_t name=0);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(function_t,callable_t,"function");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
function_t::check_args(miniexp_t a)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
again:
|
|
Packit |
df99a1 |
if (miniexp_symbolp(a) || !a)
|
|
Packit |
df99a1 |
return;
|
|
Packit |
df99a1 |
if (miniexp_listp(a))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
check_args(miniexp_car(a));
|
|
Packit |
df99a1 |
a = miniexp_cdr(a);
|
|
Packit |
df99a1 |
goto again;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
error("lambda: illegal formal arguments");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
function_t::match_args(miniexp_t a, miniexp_t v, miniexp_t &env)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
again:
|
|
Packit |
df99a1 |
if (miniexp_symbolp(a))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t x = miniexp_cons(a,v);
|
|
Packit |
df99a1 |
env = miniexp_cons(x, env);
|
|
Packit |
df99a1 |
return;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (miniexp_consp(a))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! miniexp_consp(v))
|
|
Packit |
df99a1 |
error("apply: not enough arguments", a);
|
|
Packit |
df99a1 |
match_args(miniexp_car(a), miniexp_car(v), env);
|
|
Packit |
df99a1 |
a = miniexp_cdr(a);
|
|
Packit |
df99a1 |
v = miniexp_cdr(v);
|
|
Packit |
df99a1 |
goto again;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (v)
|
|
Packit |
df99a1 |
error("apply: too many arguments", v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
function_t::function_t(miniexp_t a, miniexp_t b, miniexp_t e)
|
|
Packit |
df99a1 |
: args(a), body(b), env(e)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
check_args(a);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
function_t::call(miniexp_t args, miniexp_t env, bool apply)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t xargs = apply ? args : evaluate_list(args, env);
|
|
Packit |
df99a1 |
minivar_t nenv = this->env;
|
|
Packit |
df99a1 |
match_args(this->args, xargs, nenv);
|
|
Packit |
df99a1 |
return evaluate_progn(body, nenv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
function_t::mark(minilisp_mark_t action)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
action(&args);
|
|
Packit |
df99a1 |
action(&body);
|
|
Packit |
df99a1 |
action(&env;;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
function_t::funcdef(miniexp_t name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t d = miniexp_symbol("defun");
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_cons(name, args);
|
|
Packit |
df99a1 |
return miniexp_cons(d, miniexp_cons(a, body));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t d = miniexp_symbol("lambda");
|
|
Packit |
df99a1 |
return miniexp_cons(d,miniexp_cons(args,body));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------- macros */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class macrofunction_t : public function_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
macrofunction_t(miniexp_t a, miniexp_t b, miniexp_t e);
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(macrofunction_t,function_t,"macrofunction");
|
|
Packit |
df99a1 |
virtual miniexp_t call(miniexp_t args, miniexp_t env, bool);
|
|
Packit |
df99a1 |
virtual miniexp_t funcdef(miniexp_t name=0);
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(macrofunction_t,function_t,"macrofunction");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
macrofunction_t::macrofunction_t(miniexp_t a, miniexp_t b, miniexp_t e)
|
|
Packit |
df99a1 |
: function_t(a,b,e)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
macrofunction_t::call(miniexp_t args, miniexp_t env, bool)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t nenv = this->env;
|
|
Packit |
df99a1 |
match_args(this->args, args, nenv);
|
|
Packit |
df99a1 |
minivar_t e = evaluate_progn(body, nenv);
|
|
Packit |
df99a1 |
return evaluate(e, env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
macrofunction_t::funcdef(miniexp_t name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (name)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t d = miniexp_symbol("defmacro");
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_cons(name, args);
|
|
Packit |
df99a1 |
return miniexp_cons(d, miniexp_cons(a, body));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t d = miniexp_symbol("mlambda");
|
|
Packit |
df99a1 |
return miniexp_cons(d, miniexp_cons(args, body));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ define special forms */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("progn",progn)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return evaluate_progn(expr, env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("list",list)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return evaluate_list(expr, env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("if",if)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (evaluate(miniexp_car(expr), env))
|
|
Packit |
df99a1 |
return evaluate(miniexp_cadr(expr), env);
|
|
Packit |
df99a1 |
return evaluate_progn(miniexp_cddr(expr), env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("setq",setq)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_cddr(expr) || !miniexp_consp(miniexp_cdr(expr)))
|
|
Packit |
df99a1 |
error("setq: syntax error");
|
|
Packit |
df99a1 |
miniexp_t a = lookup(miniexp_car(expr),env);
|
|
Packit |
df99a1 |
if (! a)
|
|
Packit |
df99a1 |
error ("setq: undefined variable", miniexp_car(expr));
|
|
Packit |
df99a1 |
minivar_t v = evaluate(miniexp_cadr(expr), env);
|
|
Packit |
df99a1 |
miniexp_rplacd(a,v);
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("defvar",defvar)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_cddr(expr))
|
|
Packit |
df99a1 |
error("defvar: syntax error");
|
|
Packit |
df99a1 |
minivar_t v = evaluate(miniexp_cadr(expr), env);
|
|
Packit |
df99a1 |
defvar(miniexp_car(expr), v);
|
|
Packit |
df99a1 |
return miniexp_car(expr);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("let",let)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t v = miniexp_car(expr);
|
|
Packit |
df99a1 |
minivar_t nenv = env;
|
|
Packit |
df99a1 |
minivar_t p, w;
|
|
Packit |
df99a1 |
while (miniexp_consp(v))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_car(v);
|
|
Packit |
df99a1 |
v = miniexp_cdr(v);
|
|
Packit |
df99a1 |
if (! (miniexp_consp(a) &&
|
|
Packit |
df99a1 |
miniexp_symbolp(miniexp_car(a)) &&
|
|
Packit |
df99a1 |
!miniexp_cddr(a)))
|
|
Packit |
df99a1 |
error("let: syntax error");
|
|
Packit |
df99a1 |
w = evaluate(miniexp_cadr(a), env);
|
|
Packit |
df99a1 |
p = miniexp_cons(miniexp_car(a), w);
|
|
Packit |
df99a1 |
nenv = miniexp_cons(p, nenv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return evaluate_progn(miniexp_cdr(expr), nenv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("letrec",letrec)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t v = miniexp_car(expr);
|
|
Packit |
df99a1 |
minivar_t nenv = env;
|
|
Packit |
df99a1 |
minivar_t p, w;
|
|
Packit |
df99a1 |
while (miniexp_consp(v))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_car(v);
|
|
Packit |
df99a1 |
v = miniexp_cdr(v);
|
|
Packit |
df99a1 |
if (! (miniexp_consp(a) &&
|
|
Packit |
df99a1 |
miniexp_symbolp(miniexp_car(a)) &&
|
|
Packit |
df99a1 |
!miniexp_cddr(a)))
|
|
Packit |
df99a1 |
error("let: syntax error");
|
|
Packit |
df99a1 |
minivar_t p = miniexp_cons(miniexp_car(a), 0);
|
|
Packit |
df99a1 |
nenv = miniexp_cons(p, nenv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
v = miniexp_car(expr);
|
|
Packit |
df99a1 |
while (miniexp_consp(v))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t a = miniexp_car(v);
|
|
Packit |
df99a1 |
v = miniexp_cdr(v);
|
|
Packit |
df99a1 |
w = evaluate(miniexp_cadr(a), nenv);
|
|
Packit |
df99a1 |
p = lookup(miniexp_car(a), nenv);
|
|
Packit |
df99a1 |
miniexp_rplacd(p,w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return evaluate_progn(miniexp_cdr(expr), nenv);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("lambda",lambda)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t args = miniexp_car(expr);
|
|
Packit |
df99a1 |
miniexp_t body = miniexp_cdr(expr);
|
|
Packit |
df99a1 |
function_t *f = new function_t(args, body, env);
|
|
Packit |
df99a1 |
return miniexp_object(f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("mlambda",mlambda)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_t args = miniexp_car(expr);
|
|
Packit |
df99a1 |
miniexp_t body = miniexp_cdr(expr);
|
|
Packit |
df99a1 |
function_t *f = new macrofunction_t(args, body, env);
|
|
Packit |
df99a1 |
return miniexp_object(f);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("quote",quote)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_cdr(expr))
|
|
Packit |
df99a1 |
error("quote: syntax error");
|
|
Packit |
df99a1 |
return miniexp_car(expr);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFSPECIAL("while",while)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! miniexp_consp(expr))
|
|
Packit |
df99a1 |
error("while: syntax error");
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
while (evaluate(miniexp_car(expr), env))
|
|
Packit |
df99a1 |
v = evaluate_progn(miniexp_cdr(expr), env);
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ define primitive */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("nullp",nullp,1,0) {
|
|
Packit |
df99a1 |
return (!argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("listp",listp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_listp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("consp",consp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_consp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("numberp",numberp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_numberp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("doublep",doublep,1,0) {
|
|
Packit |
df99a1 |
return miniexp_doublep(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("objectp",objectp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_objectp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("symbolp",symbolp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_symbolp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("stringp",stringp,1,0) {
|
|
Packit |
df99a1 |
return miniexp_stringp(argv[0]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("classof",classof,1,0) {
|
|
Packit |
df99a1 |
return miniexp_classof(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("car",car,1,0) {
|
|
Packit |
df99a1 |
return miniexp_car(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("cdr",cdr,1,0) {
|
|
Packit |
df99a1 |
return miniexp_cdr(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("caar",caar,1,0) {
|
|
Packit |
df99a1 |
return miniexp_caar(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("cadr",cadr,1,0) {
|
|
Packit |
df99a1 |
return miniexp_cadr(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("cdar",cdar,1,0) {
|
|
Packit |
df99a1 |
return miniexp_cdar(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("cddr",cddr,1,0) {
|
|
Packit |
df99a1 |
return miniexp_cddr(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("length",length,1,0) {
|
|
Packit |
df99a1 |
return miniexp_number(miniexp_length(argv[0]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("reverse",reverse,1,0) {
|
|
Packit |
df99a1 |
return miniexp_reverse(argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("cons",cons,2,0) {
|
|
Packit |
df99a1 |
return miniexp_cons(argv[0],argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("nth",nth,2,0) {
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[0]))
|
|
Packit |
df99a1 |
error("nth: integer number expected");
|
|
Packit |
df99a1 |
return miniexp_nth(miniexp_to_int(argv[0]), argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("rplaca",rplaca,2,0) {
|
|
Packit |
df99a1 |
return miniexp_rplaca(argv[0],argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("rplacd",rplacd,2,0) {
|
|
Packit |
df99a1 |
return miniexp_rplacd(argv[0],argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("abs",abs,1,0) {
|
|
Packit |
df99a1 |
return miniexp_double(fabs(miniexp_to_double(argv[0])));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("+",plus,0,9999) {
|
|
Packit |
df99a1 |
double s = 0;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!miniexp_doublep(argv[i]))
|
|
Packit |
df99a1 |
error("+: number expected");
|
|
Packit |
df99a1 |
s += miniexp_to_double(argv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return miniexp_double(s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("*",times,0,9999) {
|
|
Packit |
df99a1 |
double s = 1;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!miniexp_doublep(argv[i]))
|
|
Packit |
df99a1 |
error("*: number expected");
|
|
Packit |
df99a1 |
s *= miniexp_to_double(argv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return miniexp_double(s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("-",minus,1,9999) {
|
|
Packit |
df99a1 |
if (! miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
error("-: number expected");
|
|
Packit |
df99a1 |
int i = 0;
|
|
Packit |
df99a1 |
double s = 0;
|
|
Packit |
df99a1 |
if (argc>1 && miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
s = miniexp_to_double(argv[i++]);
|
|
Packit |
df99a1 |
while (i
|
|
Packit |
df99a1 |
s -= miniexp_to_double(argv[i++]);
|
|
Packit |
df99a1 |
if (i < argc)
|
|
Packit |
df99a1 |
error("-: number expected", argv[i]);
|
|
Packit |
df99a1 |
return miniexp_double(s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("/",div,1,9999) {
|
|
Packit |
df99a1 |
if (! miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
error("/: number expected");
|
|
Packit |
df99a1 |
int i = 0;
|
|
Packit |
df99a1 |
double s = 1;
|
|
Packit |
df99a1 |
if (argc>1 && miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
s = miniexp_to_double(argv[i++]);
|
|
Packit |
df99a1 |
while (i
|
|
Packit |
df99a1 |
s /= miniexp_to_double(argv[i++]);
|
|
Packit |
df99a1 |
if (i < argc)
|
|
Packit |
df99a1 |
if (miniexp_doublep(argv[i]))
|
|
Packit |
df99a1 |
error("/: division by zero", argv[i]);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
error("/: number expected", argv[i]);
|
|
Packit |
df99a1 |
return miniexp_double(s);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("==",equalequal,2,0) {
|
|
Packit |
df99a1 |
return (argv[0]==argv[1]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static bool
|
|
Packit |
df99a1 |
equal(miniexp_t a, miniexp_t b)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (a == b)
|
|
Packit |
df99a1 |
return true;
|
|
Packit |
df99a1 |
else if (miniexp_consp(a) && miniexp_consp(b))
|
|
Packit |
df99a1 |
return equal(miniexp_car(a),miniexp_car(b))
|
|
Packit |
df99a1 |
&& equal(miniexp_cdr(a),miniexp_cdr(b));
|
|
Packit |
df99a1 |
else if (miniexp_stringp(a) && miniexp_stringp(b))
|
|
Packit |
df99a1 |
return !strcmp(miniexp_to_str(a), miniexp_to_str(b));
|
|
Packit |
df99a1 |
else if (miniexp_doublep(a) && miniexp_doublep(b))
|
|
Packit |
df99a1 |
return miniexp_to_double(a) == miniexp_to_double(b);
|
|
Packit |
df99a1 |
return false;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("=",equal,2,0) {
|
|
Packit |
df99a1 |
return equal(argv[0],argv[1]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("<>",notequal,2,0) {
|
|
Packit |
df99a1 |
return !equal(argv[0],argv[1]) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int
|
|
Packit |
df99a1 |
compare(miniexp_t a, miniexp_t b)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (miniexp_doublep(a) && miniexp_doublep(b))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
double na = miniexp_to_double(a);
|
|
Packit |
df99a1 |
double nb = miniexp_to_double(b);
|
|
Packit |
df99a1 |
if (na < nb)
|
|
Packit |
df99a1 |
return -1;
|
|
Packit |
df99a1 |
else if (na > nb)
|
|
Packit |
df99a1 |
return 1;
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else if (miniexp_stringp(a) && miniexp_stringp(b))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const char *sa = miniexp_to_str(a);
|
|
Packit |
df99a1 |
const char *sb = miniexp_to_str(b);
|
|
Packit |
df99a1 |
return strcmp(sa, sb);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
error("compare: cannot rank these arguments");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("<=",cmple,2,0) {
|
|
Packit |
df99a1 |
return (compare(argv[0],argv[1])<=0) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("<",cmplt,2,0) {
|
|
Packit |
df99a1 |
return (compare(argv[0],argv[1])<0) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN(">=",cmpge,2,0) {
|
|
Packit |
df99a1 |
return (compare(argv[0],argv[1])>=0) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN(">",cmpgt,2,0) {
|
|
Packit |
df99a1 |
return (compare(argv[0],argv[1])>0) ? s_true : 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("floor",floor,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
error("-: number expected");
|
|
Packit |
df99a1 |
return miniexp_double(floor(miniexp_to_double(argv[0])));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("ceil",ceil,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_doublep(argv[0]))
|
|
Packit |
df99a1 |
error("-: number expected");
|
|
Packit |
df99a1 |
return miniexp_double(ceil(miniexp_to_double(argv[0])));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("strlen",strlen,1,1) {
|
|
Packit |
df99a1 |
if (! miniexp_stringp(argv[0]))
|
|
Packit |
df99a1 |
error("strlen: string expected", argv[0]);
|
|
Packit |
df99a1 |
const char *s = miniexp_to_str(argv[0]);
|
|
Packit |
df99a1 |
return miniexp_number(strlen(s));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("substr",substr,2,1) {
|
|
Packit |
df99a1 |
if (! miniexp_stringp(argv[0]))
|
|
Packit |
df99a1 |
error("substr: string expected", argv[0]);
|
|
Packit |
df99a1 |
const char *s = miniexp_to_str(argv[0]);
|
|
Packit |
df99a1 |
int l = strlen(s);
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[1]))
|
|
Packit |
df99a1 |
error("substr: integer number expected", argv[1]);
|
|
Packit |
df99a1 |
int f = miniexp_to_double(argv[1]);
|
|
Packit |
df99a1 |
f = (l < f) ? l : (f < 0) ? l : f;
|
|
Packit |
df99a1 |
s += f;
|
|
Packit |
df99a1 |
l -= f;
|
|
Packit |
df99a1 |
if (argc>2)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[2]))
|
|
Packit |
df99a1 |
error("substr: integer number expected", argv[2]);
|
|
Packit |
df99a1 |
f = miniexp_to_double(argv[2]);
|
|
Packit |
df99a1 |
l = (f > l) ? l : (f < 0) ? 0 : f;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return miniexp_substring(s,l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("concat",concat,0,9999) {
|
|
Packit |
df99a1 |
minivar_t l = 0;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
if (miniexp_stringp(argv[i]))
|
|
Packit |
df99a1 |
l = miniexp_cons(argv[i],l);
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
error("concat: string expected", argv[i]);
|
|
Packit |
df99a1 |
l = miniexp_reverse(l);
|
|
Packit |
df99a1 |
return miniexp_concat(l);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("prin",prin,1,9999) {
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
v = miniexp_prin(argv[0]);
|
|
Packit |
df99a1 |
for (int i=1; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minilisp_puts(" ");
|
|
Packit |
df99a1 |
v = miniexp_prin(argv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("print",print,1,9999) {
|
|
Packit |
df99a1 |
minivar_t v;
|
|
Packit |
df99a1 |
v = miniexp_prin(argv[0]);
|
|
Packit |
df99a1 |
for (int i=1; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minilisp_puts(" ");
|
|
Packit |
df99a1 |
v = miniexp_prin(argv[i]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
minilisp_puts("\n");
|
|
Packit |
df99a1 |
return v;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("pprint",pprint,1,1) {
|
|
Packit |
df99a1 |
int w = 72;
|
|
Packit |
df99a1 |
if (argc>1)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[1]))
|
|
Packit |
df99a1 |
error("pprint: second argument must be number");
|
|
Packit |
df99a1 |
w = miniexp_to_int(argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return miniexp_pprint(argv[0], w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("pname",pname,1,1) {
|
|
Packit |
df99a1 |
int w = 0;
|
|
Packit |
df99a1 |
if (argc > 1)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[1]))
|
|
Packit |
df99a1 |
error("pprint: second argument must be number");
|
|
Packit |
df99a1 |
w = miniexp_to_int(argv[1]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return miniexp_pname(argv[0],w);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("gc",gc,0,0) {
|
|
Packit |
df99a1 |
minilisp_gc();
|
|
Packit |
df99a1 |
minilisp_info();
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("info",info,0,0) {
|
|
Packit |
df99a1 |
minilisp_info();
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("funcdef",funcdef,1,1) {
|
|
Packit |
df99a1 |
if (! miniexp_isa(argv[0], function_t::classname))
|
|
Packit |
df99a1 |
error("funcdef: expecting function", argv[0]);
|
|
Packit |
df99a1 |
if (argc>1 && ! miniexp_symbolp(argv[1]))
|
|
Packit |
df99a1 |
error("funcdef: expecting symbol", argv[1]);
|
|
Packit |
df99a1 |
function_t *f = (function_t*)miniexp_to_obj(argv[0]);
|
|
Packit |
df99a1 |
return f->funcdef(argc>1 ? argv[1] : 0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("vardef",vardef,1,0) {
|
|
Packit |
df99a1 |
miniexp_t a = lookup(argv[0],globalenv);
|
|
Packit |
df99a1 |
if (! a)
|
|
Packit |
df99a1 |
error("vardef: undefined global variable");
|
|
Packit |
df99a1 |
return miniexp_cdr(a);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("eval",eval,1,0) {
|
|
Packit |
df99a1 |
return evaluate(argv[0],env);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("apply",apply,2,0) {
|
|
Packit |
df99a1 |
miniobj_t *obj = miniexp_to_obj(argv[0]);
|
|
Packit |
df99a1 |
if (obj && obj->isa(callable_t::classname))
|
|
Packit |
df99a1 |
return ((callable_t*)obj)->call(argv[1], env, true);
|
|
Packit |
df99a1 |
error("apply: cannot apply this object", argv[0]);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("error",error,1,1) {
|
|
Packit |
df99a1 |
if (!miniexp_stringp(argv[0]))
|
|
Packit |
df99a1 |
error("error: string expected", argv[0]);
|
|
Packit |
df99a1 |
error(miniexp_to_str(argv[0]), (argc>1) ? argv[1] : 0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("display",display,0,9999) {
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t v = argv[i];
|
|
Packit |
df99a1 |
if (! miniexp_stringp(v))
|
|
Packit |
df99a1 |
v = miniexp_pname(v, 0);
|
|
Packit |
df99a1 |
minilisp_puts(miniexp_to_str(v));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("string->symbol",string2symbol,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_stringp(argv[0]))
|
|
Packit |
df99a1 |
error("string->symbol: string expected",argv[0]);
|
|
Packit |
df99a1 |
return miniexp_symbol(miniexp_to_str(argv[0]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("symbol->string",symbol2string,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_symbolp(argv[0]))
|
|
Packit |
df99a1 |
error("symbol->string: symbol expected",argv[0]);
|
|
Packit |
df99a1 |
return miniexp_string(miniexp_to_name(argv[0]));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("printflags",printflags,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_numberp(argv[0]))
|
|
Packit |
df99a1 |
error("printflags: integer number expected");
|
|
Packit |
df99a1 |
minilisp_print_7bits = miniexp_to_int(argv[0]);
|
|
Packit |
df99a1 |
return argv[0];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ special */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#if defined(_WIN32) || defined(__WIN64)
|
|
Packit |
df99a1 |
# include <process.h>
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class thread_t : public miniobj_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(thread_t, miniobj_t, "thread");
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
uintptr_t thr;
|
|
Packit |
df99a1 |
miniexp_t exp, env, res, run;
|
|
Packit |
df99a1 |
static void start(void *arg) {
|
|
Packit |
df99a1 |
thread_t *pth = (thread_t*) arg;
|
|
Packit |
df99a1 |
try {
|
|
Packit |
df99a1 |
pth->res = evaluate(pth->exp, pth->env);
|
|
Packit |
df99a1 |
pth->run = miniexp_symbol("finished");
|
|
Packit |
df99a1 |
} catch(...) {
|
|
Packit |
df99a1 |
pth->run = miniexp_symbol("error");
|
|
Packit |
df99a1 |
} }
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
thread_t(miniexp_t exp, miniexp_t env) : exp(exp), env(env), res(0), run(0) {
|
|
Packit |
df99a1 |
thr = _beginthread(thread_t::start, 0, (void*)this); }
|
|
Packit |
df99a1 |
void mark(minilisp_mark_t action) {
|
|
Packit |
df99a1 |
action(&exp); action(&env), action(&res;; }
|
|
Packit |
df99a1 |
miniexp_t join() {
|
|
Packit |
df99a1 |
return (run) ? res : miniexp_dummy; }
|
|
Packit |
df99a1 |
miniexp_t status() { return run; }
|
|
Packit |
df99a1 |
~thread_t() { if (!run) abort(); join(); }
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(thread_t, miniobj_t, "thread");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("thread",threadstart,1,0) {
|
|
Packit |
df99a1 |
return miniexp_object(new thread_t(argv[0],env));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
DEFUN("threadp", threadtest,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_isa(argv[0], thread_t::classname)) return 0;
|
|
Packit |
df99a1 |
miniexp_t run = ((thread_t*)miniexp_to_obj(argv[0]))->status();
|
|
Packit |
df99a1 |
return (run) ? run : miniexp_symbol("running");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
DEFUN("join",threadjoin,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_isa(argv[0], thread_t::classname))
|
|
Packit |
df99a1 |
error("join: thread expected");
|
|
Packit |
df99a1 |
return ((thread_t*)miniexp_to_obj(argv[0]))->join();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_PTHREAD
|
|
Packit |
df99a1 |
# include <pthread.h>
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
class thread_t : public miniobj_t
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
MINIOBJ_DECLARE(thread_t, miniobj_t, "thread");
|
|
Packit |
df99a1 |
private:
|
|
Packit |
df99a1 |
pthread_t thr;
|
|
Packit |
df99a1 |
miniexp_t exp, env, res, run;
|
|
Packit |
df99a1 |
bool joined;
|
|
Packit |
df99a1 |
static void* start(void *arg) {
|
|
Packit |
df99a1 |
thread_t *pth = (thread_t*) arg;
|
|
Packit |
df99a1 |
try {
|
|
Packit |
df99a1 |
pth->res = evaluate(pth->exp, pth->env);
|
|
Packit |
df99a1 |
pth->run = miniexp_symbol("finished");
|
|
Packit |
df99a1 |
return 0; }
|
|
Packit |
df99a1 |
catch(...) {
|
|
Packit |
df99a1 |
pth->run = miniexp_symbol("error");
|
|
Packit |
df99a1 |
return (void*)1; } }
|
|
Packit |
df99a1 |
public:
|
|
Packit |
df99a1 |
thread_t(miniexp_t exp, miniexp_t env)
|
|
Packit |
df99a1 |
: exp(exp), env(env), res(0), run(0), joined(false) {
|
|
Packit |
df99a1 |
pthread_create(&this->thr, 0, thread_t::start, (void*)this); }
|
|
Packit |
df99a1 |
void mark(minilisp_mark_t action) {
|
|
Packit |
df99a1 |
action(&exp); action(&env), action(&res;; }
|
|
Packit |
df99a1 |
miniexp_t join() {
|
|
Packit |
df99a1 |
if (! joined) pthread_join(thr, 0); joined=true;
|
|
Packit |
df99a1 |
return (run) ? res : miniexp_dummy; }
|
|
Packit |
df99a1 |
miniexp_t status() { return run; }
|
|
Packit |
df99a1 |
~thread_t() { if (!run) abort(); join(); }
|
|
Packit |
df99a1 |
};
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
MINIOBJ_IMPLEMENT(thread_t, miniobj_t, "thread");
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("thread",threadstart,1,0) {
|
|
Packit |
df99a1 |
return miniexp_object(new thread_t(argv[0],env));
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
DEFUN("threadp", threadtest,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_isa(argv[0], thread_t::classname)) return 0;
|
|
Packit |
df99a1 |
miniexp_t run = ((thread_t*)miniexp_to_obj(argv[0]))->status();
|
|
Packit |
df99a1 |
return (run) ? run : miniexp_symbol("running");
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
DEFUN("join",threadjoin,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_isa(argv[0], thread_t::classname))
|
|
Packit |
df99a1 |
error("join: thread expected");
|
|
Packit |
df99a1 |
return ((thread_t*)miniexp_to_obj(argv[0]))->join();
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ toplevel */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
toplevel(FILE *inp, FILE *out, bool print)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
miniexp_io_t saved_io = miniexp_io;
|
|
Packit |
df99a1 |
minilisp_set_output(out);
|
|
Packit |
df99a1 |
minilisp_set_input(inp);
|
|
Packit |
df99a1 |
for(;;)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t s = miniexp_read();
|
|
Packit |
df99a1 |
if (s == miniexp_dummy)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (feof(inp)) break;
|
|
Packit |
df99a1 |
printf("ERROR: while parsing\n");
|
|
Packit |
df99a1 |
break;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
try
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
break_request = false;
|
|
Packit |
df99a1 |
minivar_t v = evaluate(s, globalenv);
|
|
Packit |
df99a1 |
if (print)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
printf("= ");
|
|
Packit |
df99a1 |
miniexp_print(v);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
catch(...)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
miniexp_io = saved_io;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
parse_comment(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int c = minilisp_getc();
|
|
Packit |
df99a1 |
while (c != EOF && c != '\n')
|
|
Packit |
df99a1 |
c = minilisp_getc();
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
miniexp_t
|
|
Packit |
df99a1 |
parse_quote(void)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
minivar_t l = miniexp_read();
|
|
Packit |
df99a1 |
if (l == miniexp_dummy)
|
|
Packit |
df99a1 |
return miniexp_dummy;
|
|
Packit |
df99a1 |
l = miniexp_cons(s_quote, miniexp_cons(l, miniexp_nil));
|
|
Packit |
df99a1 |
return miniexp_cons(l,miniexp_nil);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
sighandler(int signo)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
break_request = true;
|
|
Packit |
df99a1 |
signal(signo, sighandler);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
DEFUN("load",xload,1,0) {
|
|
Packit |
df99a1 |
if (! miniexp_stringp(argv[0]))
|
|
Packit |
df99a1 |
error("load: string expected");
|
|
Packit |
df99a1 |
FILE *f = fopen(miniexp_to_str(argv[0]), "r");
|
|
Packit |
df99a1 |
if (! f)
|
|
Packit |
df99a1 |
error("load: cannot open file");
|
|
Packit |
df99a1 |
toplevel(f, stdout, false);
|
|
Packit |
df99a1 |
fclose(f);
|
|
Packit |
df99a1 |
return miniexp_nil;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* ------------ toplevel */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int
|
|
Packit |
df99a1 |
main()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
#ifdef DEBUG
|
|
Packit |
df99a1 |
minilisp_debug(1);
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
minilisp_macrochar_parser[(int)';'] = parse_comment;
|
|
Packit |
df99a1 |
minilisp_macrochar_parser[(int)'\''] = parse_quote;
|
|
Packit |
df99a1 |
FILE *f = fopen("minilisp.in","r");
|
|
Packit |
df99a1 |
if (f) {
|
|
Packit |
df99a1 |
toplevel(f, stdout, false);
|
|
Packit |
df99a1 |
fclose(f);
|
|
Packit |
df99a1 |
} else
|
|
Packit |
df99a1 |
printf("WARNING: cannot find 'minilisp.in'\n");
|
|
Packit |
df99a1 |
signal(SIGINT, sighandler);
|
|
Packit |
df99a1 |
while (! feof(stdin))
|
|
Packit |
df99a1 |
toplevel(stdin, stdout, true);
|
|
Packit |
df99a1 |
break_request = true;
|
|
Packit |
df99a1 |
minilisp_finish();
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
}
|