mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-26 06:22:33 -08:00
396 lines
8.6 KiB
D
396 lines
8.6 KiB
D
/*
|
|
cmpaux.c -- Auxiliaries used in compiled Lisp code.
|
|
*/
|
|
/*
|
|
Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
|
|
Copyright (c) 1990, Giuseppe Attardi.
|
|
Copyright (c) 2001, Juan Jose Garcia Ripoll.
|
|
|
|
ECLS is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
See file '../Copyright' for full details.
|
|
*/
|
|
|
|
#include "ecls.h"
|
|
#include "ecls-inl.h"
|
|
|
|
#ifndef CHAR_BIT
|
|
#define CHAR_BIT (sizeof(char)*8)
|
|
#endif
|
|
|
|
cl_object @'&optional';
|
|
cl_object @'&rest';
|
|
cl_object @'&key';
|
|
cl_object @'&allow-other-keys';
|
|
cl_object @'&aux';
|
|
cl_object @':allow-other-keys';
|
|
|
|
cl_object
|
|
make_list(int i)
|
|
{
|
|
cl_object x = Cnil;
|
|
while (i-- > 0)
|
|
x = CONS(Cnil, x);
|
|
return x;
|
|
}
|
|
|
|
@(defun si::specialp (sym)
|
|
@
|
|
@(return ((SYMBOLP(sym) && sym->symbol.stype == stp_special) ?
|
|
Ct : Cnil))
|
|
@)
|
|
|
|
int
|
|
ifloor(int x, int y)
|
|
{
|
|
if (y == 0)
|
|
FEerror("Zero divizor", 0);
|
|
else if (y > 0)
|
|
if (x >= 0)
|
|
return(x/y);
|
|
else
|
|
return(-((-x+y-1))/y);
|
|
else
|
|
if (x >= 0)
|
|
return(-((x-y-1)/(-y)));
|
|
else
|
|
return((-x)/(-y));
|
|
}
|
|
|
|
int
|
|
imod(int x, int y)
|
|
{
|
|
return(x - ifloor(x, y)*y);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------
|
|
* Conversions to C
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
|
|
char
|
|
object_to_char(cl_object x)
|
|
{
|
|
switch (type_of(x)) {
|
|
case t_fixnum:
|
|
return fix(x);
|
|
case t_bignum:
|
|
return big_to_long(x) & (CHCODELIM - 1);
|
|
case t_character:
|
|
return CHAR_CODE(x);
|
|
default:
|
|
FEerror("~S cannot be coerced to a C char.", 1, x);
|
|
}
|
|
}
|
|
|
|
int
|
|
object_to_int(cl_object x)
|
|
{
|
|
switch (type_of(x)) {
|
|
case t_fixnum:
|
|
return fix(x);
|
|
case t_character:
|
|
return CHAR_CODE(x);
|
|
case t_bignum:
|
|
return big_to_long(x);
|
|
case t_ratio:
|
|
return number_to_double(x);
|
|
case t_shortfloat:
|
|
return sf(x);
|
|
case t_longfloat:
|
|
return lf(x);
|
|
default:
|
|
FEerror("~S cannot be coerced to a C int.", 1, x);
|
|
}
|
|
}
|
|
|
|
char *
|
|
object_to_string(cl_object x)
|
|
{
|
|
extern VOID *malloc(size_t size);
|
|
switch (type_of(x)) {
|
|
case t_string:
|
|
case t_symbol:
|
|
return(x->string.self);
|
|
case t_fixnum: {
|
|
char *num = malloc(12);
|
|
sprintf(num, "%ld", (long)fix(x));
|
|
return(num);
|
|
}
|
|
case t_character: {
|
|
char *c = malloc(2);
|
|
c[0] = CHAR_CODE(x);
|
|
c[1] = '\0';
|
|
return c;
|
|
}
|
|
case t_pathname:
|
|
return namestring(x)->string.self;
|
|
default:
|
|
FEerror("~S cannot be coerced to a C string.", 1, x);
|
|
}
|
|
}
|
|
|
|
float
|
|
object_to_float(cl_object x)
|
|
{
|
|
if (FIXNUMP(x)) return(fix(x)); /* Immediate fixnum */
|
|
|
|
switch (type_of(x)) {
|
|
/* case t_fixnum: return fix(x); */
|
|
case t_character:
|
|
return CHAR_CODE(x);
|
|
case t_bignum:
|
|
case t_ratio:
|
|
return number_to_double(x);
|
|
case t_shortfloat:
|
|
return sf(x);
|
|
case t_longfloat:
|
|
return lf(x);
|
|
default:
|
|
FEerror("~S cannot be coerced to a C float.", 1, x);
|
|
}
|
|
}
|
|
|
|
double
|
|
object_to_double(cl_object x)
|
|
{
|
|
|
|
if (FIXNUMP(x)) return(fix(x)); /* Immediate fixnum */
|
|
|
|
switch (type_of(x)) {
|
|
/* case t_fixnum: return fix(x); */
|
|
case t_character:
|
|
return CHAR_CODE(x);
|
|
case t_bignum:
|
|
case t_ratio:
|
|
return number_to_double(x);
|
|
case t_shortfloat:
|
|
return sf(x);
|
|
case t_longfloat:
|
|
return lf(x);
|
|
default:
|
|
FEerror("~S cannot be coerced to a C double.", 1, x);
|
|
}
|
|
}
|
|
|
|
int
|
|
aref_bv(cl_object x, cl_index index)
|
|
{
|
|
index += x->vector.offset;
|
|
return ((x->vector.self.bit[index/CHAR_BIT] & (0200>>index%CHAR_BIT)) != 0);
|
|
}
|
|
|
|
int
|
|
aset_bv(cl_object x, cl_index index, int value)
|
|
{
|
|
index += x->vector.offset;
|
|
if (value == 0)
|
|
x->vector.self.bit[index/CHAR_BIT] &= ~(0200>>index%CHAR_BIT);
|
|
else
|
|
x->vector.self.bit[index/CHAR_BIT] |= 0200>>index%CHAR_BIT;
|
|
return value;
|
|
}
|
|
|
|
void
|
|
throw(cl_object tag)
|
|
{
|
|
frame_ptr fr = frs_sch_catch(tag);
|
|
if (fr == NULL)
|
|
FEcontrol_error("THROW: The catch ~S is undefined.", 1, tag);
|
|
unwind(fr, tag);
|
|
}
|
|
|
|
void
|
|
return_from(cl_object block_id, cl_object block_name)
|
|
{
|
|
frame_ptr fr = frs_sch(block_id);
|
|
if (fr == NULL)
|
|
FEcontrol_error("RETURN-FROM: The block ~S with id ~S is missing.",
|
|
2, block_name, block_id);
|
|
unwind(fr, block_name);
|
|
}
|
|
|
|
void
|
|
go(cl_object tag_id, cl_object label)
|
|
{
|
|
frame_ptr fr = frs_sch(tag_id);
|
|
if (fr == NULL)
|
|
FEcontrol_error("GO: The tagbody ~S is missing.", 1, tag_id);
|
|
unwind(fr, label);
|
|
}
|
|
|
|
#define NOT_YET 10
|
|
#define FOUND 11
|
|
#define NOT_KEYWORD 1
|
|
|
|
void
|
|
parse_key(
|
|
int narg, /* number of actual args */
|
|
cl_object *args, /* actual args */
|
|
int nkey, /* number of keywords */
|
|
cl_object *keys, /* keywords for the function */
|
|
cl_object *vars, /* where to put values (vars[0..nkey-1])
|
|
and suppliedp (vars[nkey..2*nkey-1]) */
|
|
cl_object rest, /* rest variable or NULL */
|
|
bool allow_other_keys) /* whether other key are allowed */
|
|
{
|
|
int i;
|
|
|
|
/* fill in the rest arg list */
|
|
if (rest != OBJNULL) {
|
|
cl_object *p = args;
|
|
for (i = narg; i > 0; i--) {
|
|
CAR(rest) = *(p++);
|
|
rest = CDR(rest);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 2*nkey; i++)
|
|
vars[i] = Cnil; /* default values: NIL, supplied: NIL */
|
|
if (narg <= 0) return;
|
|
|
|
for (; narg>=2; narg-= 2) {
|
|
cl_object keyword = *(args++);
|
|
cl_object value = *(args++);
|
|
for (i = 0; i < nkey; i++) {
|
|
if (keys[i] == keyword) {
|
|
if (vars[nkey+i] == Cnil) {
|
|
vars[i] = value;
|
|
vars[nkey+i] = Ct;
|
|
}
|
|
goto go_on;
|
|
}
|
|
}
|
|
/* the key is a new one */
|
|
if (!allow_other_keys) {
|
|
if (keyword == @':allow-other-keys')
|
|
allow_other_keys = (value != Cnil);
|
|
else {
|
|
cl_object *p = args;
|
|
/* look for :allow-other-keys t */
|
|
for (i = narg-2; i >= 0; i -= 2, p -=2)
|
|
if (*(p++) == @':allow-other-keys') {
|
|
allow_other_keys = (*(p++) != Cnil);
|
|
break;
|
|
}
|
|
if (!allow_other_keys)
|
|
FEprogram_error("Unrecognized key ~a", 1, keyword);
|
|
}
|
|
}
|
|
go_on:
|
|
}
|
|
if (narg != 0) FEprogram_error("Odd number of keys", 0);
|
|
}
|
|
|
|
#ifdef NO_ARGS_ARRAY
|
|
void
|
|
va_parse_key(
|
|
int narg, /* number of actual args */
|
|
va_list args, /* actual args */
|
|
int nkey, /* number of keywords */
|
|
cl_object *keys, /* keywords for the function */
|
|
cl_object *vars, /* where to put values (vars[0..nkey-1])
|
|
and suppliedp (vars[nkey..2*nkey-1]) */
|
|
cl_object rest, /* rest variable or NULL */
|
|
bool allow_other_keys) /* whether other key are allowed */
|
|
{
|
|
int i;
|
|
|
|
/* fill in the rest arg list */
|
|
if (rest != OBJNULL) {
|
|
va_list p = args;
|
|
for (i = narg; i > 0; i--) {
|
|
CAR(rest) = cl_nextarg(p);
|
|
rest = CDR(rest);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 2*nkey; i++)
|
|
vars[i] = Cnil; /* default values: NIL, supplied: NIL */
|
|
if (narg <= 0) return;
|
|
|
|
for (; narg>=2; narg-= 2) {
|
|
cl_object keyword = cl_nextarg(args);
|
|
cl_object value = cl_nextarg(args);
|
|
for (i = 0; i < nkey; i++) {
|
|
if (keys[i] == keyword) {
|
|
if (vars[nkey+i] == Cnil) {
|
|
vars[i] = value;
|
|
vars[nkey+i] = Ct;
|
|
}
|
|
goto go_on;
|
|
}
|
|
}
|
|
/* the key is a new one */
|
|
if (!allow_other_keys) {
|
|
if (keyword == @':allow-other-keys')
|
|
allow_other_keys = (value != Cnil);
|
|
else {
|
|
va_list p = args;
|
|
/* look for :allow-other-keys t */
|
|
for (i = narg-2; i >= 0; i -= 2, p -=2)
|
|
if (cl_nextarg(p) == @':allow-other-keys') {
|
|
allow_other_keys = (cl_nextarg(p) != Cnil);
|
|
break;
|
|
}
|
|
if (!allow_other_keys)
|
|
FEprogram_error("Unrecognized key ~a", 1, keyword);
|
|
}
|
|
}
|
|
go_on:
|
|
}
|
|
if (narg != 0) FEprogram_error("Odd number of keys", 0);
|
|
}
|
|
#endif NO_ARGS_ARRAY
|
|
|
|
/* Used in compiled macros */
|
|
void
|
|
check_other_key(cl_object l, int n, ...)
|
|
{
|
|
cl_object other_key = OBJNULL;
|
|
cl_object k;
|
|
int i;
|
|
bool allow_other_keys = FALSE;
|
|
va_list ap;
|
|
va_start(ap, n); /* extracting arguments */
|
|
|
|
for (; !endp(l); l = CDDR(l)) {
|
|
k = CAR(l);
|
|
if (!keywordp(k))
|
|
FEprogram_error("~S is not a keyword.", 1, k);
|
|
if (endp(CDR(l)))
|
|
FEprogram_error("Odd number of arguments for keywords.",0);
|
|
if (k == @':allow-other-keys' && CADR(l) != Cnil) {
|
|
allow_other_keys = TRUE;
|
|
} else {
|
|
#ifndef NO_ARG_ARRAY
|
|
cl_object *ktab = (cl_object *)ap;
|
|
for (i = 0; i < n; i++)
|
|
if (ktab[i] == k) {
|
|
ktab[i] = Cnil; /* remember seen */
|
|
break;
|
|
}
|
|
if (i >= n) other_key = k;
|
|
#else
|
|
Rewrite this!
|
|
#endif NO_ARG_ARRAY
|
|
}
|
|
}
|
|
if (other_key != OBJNULL && !allow_other_keys)
|
|
FEprogram_error("The keyword ~S is not allowed or is duplicated.",
|
|
1, other_key);
|
|
}
|
|
|
|
void
|
|
init_cmpaux(void)
|
|
{
|
|
make_constant("LAMBDA-LIST-KEYWORDS",
|
|
list(8, @'&optional', @'&rest', @'&key', @'&allow-other-keys', @'&aux',
|
|
make_ordinary("&WHOLE"), make_ordinary("&ENVIRONMENT"), make_ordinary("&BODY")));
|
|
|
|
make_constant("LAMBDA-PARAMETERS-LIMIT", MAKE_FIXNUM(64));
|
|
}
|