Esempio n. 1
0
LISPTR lisp_read(FILE* in)
{
	LISPTR s = NIL;
	wchar_t ch = fgetwc(in);
	while (iswspace(ch)) {
		ch = fgetwc(in);
	}
	if (ch == '(') {
		// start of cons
		LISPTR last = s = cons(lisp_read(in), NIL);
		while (true) {
			ch = fgetwc(in); while (iswspace(ch)) { ch = fgetwc(in); }
			if (ch==WEOF || ch==')') { break; }
			ungetwc(ch, in);
			LISPTR e = lisp_read(in);
			rplacd(last, cons(e, NIL));
			last = cdr(last);
		}
	} else if (ch == '\'') {
		// '<expr>, sugar for (QUOTE <expr>)
		s = cons(QUOTE, cons(lisp_read(in), NIL));
	} else if (ch == '#') {
		// so-called sharpsign or 'dispatching macro character'
		// http://www.lispworks.com/documentation/HyperSpec/Body/02_dh.htm
		ch = fgetwc(in);
		switch (ch) {
		case '\'':				// function-quote
			s = cons(FUNCTION, cons(lisp_read(in), NIL));
			break;
		default:
			lisp_error(L"invalid char after #");
			break;
		} // switch
	} else if (ch == WEOF) {
		// end of file, return NIL.
	} else {
		// must be an atom - number, symbol or string
		wchar_t name[MAX_ATOM_CHARS];
		int n = 0;
		while (true) {
			if (n < MAX_ATOM_CHARS) {
				name[n++] = towupper(ch);
			}
			ch = fgetwc(in);
			if (ch==WEOF) break;				// better not be inside a string, eh?
			if (name[0] != '"') {
				// not a string
				if (iswspace(ch)) break;
				if (ch==')' || ch=='(') {
					ungetwc(ch, in);
					break;
				}
			} else {
				// collecting a string
				if (ch=='\\') {
					ch = fgetwc(in);
					if (ch==WEOF) break;		// bad luck er bad string syntax
				} else if (ch=='"') {
					break;				// end of string
				}
			}
		} // while (true)
		name[n] = 0;
		if (name[0] == '"') {
			s = intern_string(name+1);
		} else if (isnumber(name)) {
			s = intern_number(name);
		} else {
			s = intern(name);
		}
	}
	return s;
}
Esempio n. 2
0
struct lisp_object *c_eval(struct lisp_object *obj) {
  if (!obj) {
    lisp_error();
    return NULL;
  }
  
  if (obj->quoted) {
    struct lisp_object *new_obj = lisp_object_deep_copy(obj);
    new_obj->quoted = C_FALSE;
    return new_obj;
  }

  switch (obj->obj_type) {
  case LIST:
  {
    struct lisp_object *ret = make_lisp_object(LIST, NULL);
    
    struct lisp_object *head = HEAD(obj);

    if (!head) {
      // It already is nil
      return ret;
    }

    struct lisp_object *func = c_eval(head);

    if (!func) {
      set_error("Function %s doesn't exist.", TOSTR(head));
      return NULL;
    }

    if (func->obj_type != BUILTIN && func->obj_type != FUNCTION) {
      set_error("First object in list is not a function.", SYM_NAME(head));
      return NULL;
    }

    /* Allocate an object to be used to store the copied arguments list */
    struct lisp_object *args = make_lisp_object(LIST, NULL);
    
    if (head->next) {
      struct lisp_object *args_head;

      if (func->obj_type == BUILTIN && (TOBUILTIN(func)->spec & UNEVAL_ARGS)) {
        args_head = lisp_object_deep_copy(head->next);
      }
      else {
	       args_head = c_eval(head->next);

         if (!args_head) {
           return NULL;
         }
      }

      args_head->next = NULL;
      args_head->prev = NULL;
      struct lisp_object *current = head->next->next;

      struct lisp_object *args_current = NULL;

      struct lisp_object *args_prev = args_head;

      while (current) {
        if (func->obj_type == BUILTIN && (TOBUILTIN(func)->spec & UNEVAL_ARGS)) {
          args_current = lisp_object_deep_copy(current);
        }
        else {
          args_current = c_eval(current);
          if (!args_current) {
            return NULL;
          }
        }

        args_current->prev = args_prev;
        args_current->next = NULL;
        args_prev->next = args_current;

        args_prev = args_current;
        current = current->next;
      }

      /* Finish constructing the arguments list */
      args->data = args_head;
    }

    /* Perform the function call. */
    if (func->obj_type == BUILTIN) {
      int count = list_length(args);

      struct lisp_builtin *builtin = TOBUILTIN(func);

      if (builtin->max_params != -1 && count > builtin->max_params) {
        set_error("Incorrect number of arguments (%d) to function %s!", count, TOSTR(head));
      }

      if (builtin->min_params != -1 && count < builtin->min_params) {
        set_error("Incorrect number of arguments (%d) to function %s!", count, TOSTR(head));
      }

      return builtin->func(args);
    }
    else if (func->obj_type == FUNCTION) {
      struct lisp_function *func_obj = TOFUNC(func);

      int count = list_length(args);

      char *func_name = head->obj_type == SYMBOL ? TOSTR(head) : "<unnamed lambda>";

      if (count != func_obj->numparams) {
        set_error("Incorrect number of arguments (%d) to function %s!", count, func_name);
        return NULL;
      }

      int i = 0;
      struct lisp_object *params_current = HEAD(func_obj->params);
      struct lisp_object *args_current = HEAD(args);
      struct symbol *syms = malloc(sizeof(struct symbol)*count);

      while (params_current) {
        syms[i].symbol_name = SYM_NAME(params_current);
        syms[i].value = args_current;

        i++;
        params_current = params_current->next;
        args_current = args_current->next;
      }

      set_local_symbols(syms, count);

      struct lisp_object *form_current = func_obj->forms;

      struct lisp_object *sub = nil;

      while (form_current) {
        sub = c_eval(form_current);

        if (!sub) {
          return NULL;
        }

        // Keep track of the return value
        ret = sub;

        form_current = form_current->next;
      }

      unset_local_symbols();

      free(syms);

      return ret;
    }
  }
  case SYMBOL:
  {
    /* Do a lookup of the symbol and return the value. */
    struct lisp_object *value = symbol_value(SYM_NAME(obj));

    if (!value) {
      set_error("Symbol %s does not exist!", SYM_NAME(obj));
    }

    return value;
  }
  default:
  {
    return lisp_object_deep_copy(obj);
  }
  }
}