aboutsummaryrefslogtreecommitdiff
path: root/system/kernel/pdp_forth.c
diff options
context:
space:
mode:
authorPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
committerPablo Martín <caedesv@users.sourceforge.net>2003-09-07 21:39:37 +0000
commit599a8e20c02fa48bab5102d15fab79dd6b631c95 (patch)
tree80e8760e6a8fdc7d9144370dc569b38232b2b315 /system/kernel/pdp_forth.c
parentb509942daafa671a5b5ede267b6e786619ce8173 (diff)
Updating to last version of pdp 0.12.2
svn path=/trunk/externals/pdp/; revision=940
Diffstat (limited to 'system/kernel/pdp_forth.c')
-rw-r--r--system/kernel/pdp_forth.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/system/kernel/pdp_forth.c b/system/kernel/pdp_forth.c
new file mode 100644
index 0000000..1764004
--- /dev/null
+++ b/system/kernel/pdp_forth.c
@@ -0,0 +1,541 @@
+/*
+ * Pure Data Packet header file. Packet processor system
+ * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "pdp.h"
+#include "pdp_forth.h"
+
+#define D if (0)
+
+
+
+t_pdp_stack *pdp_stack_new(void) {return pdp_list_new(0);}
+
+void pdp_stack_free(t_pdp_stack *s) {
+ pdp_tree_strip_packets(s);
+ pdp_list_free(s);
+}
+
+
+/* some stack manips */
+t_pdp_word_error pdp_stack_dup(t_pdp_stack *s)
+{
+ if (!s->first) return e_underflow;
+ pdp_list_add(s, s->first->t, s->first->w);
+
+ /* copy it properly if its a packet */
+ if (s->first->t == a_packet){
+ s->first->w.w_packet = pdp_packet_copy_ro(s->first->w.w_packet);
+ }
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_drop(t_pdp_stack *s)
+{
+ if (!s->first) return e_underflow;
+
+ /* delete it properly if its a packet */
+ if (s->first->t == a_packet){
+ pdp_packet_mark_unused(s->first->w.w_packet);
+ }
+ pdp_list_pop(s);
+
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_over(t_pdp_stack *s)
+{
+ if (s->elements < 2) return e_underflow;
+ pdp_list_add(s, s->first->next->t, s->first->next->w);
+
+ /* copy it properly if its a packet */
+ if (s->first->t == a_packet){
+ s->first->w.w_packet = pdp_packet_copy_ro(s->first->w.w_packet);
+ }
+
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_swap(t_pdp_stack *s)
+{
+ t_pdp_word w;
+ t_pdp_word_type t;
+ if (s->elements < 2) return e_underflow;
+ w = s->first->w;
+ t = s->first->t;
+ s->first->w = s->first->next->w;
+ s->first->t = s->first->next->t;
+ s->first->next->w = w;
+ s->first->next->t = t;
+ return e_ok;
+
+}
+
+/* pushing and popping the stack */
+
+t_pdp_word_error pdp_stack_push_float(t_pdp_stack *s, float f) {pdp_list_add(s, a_float, (t_pdp_word)f); return e_ok;}
+t_pdp_word_error pdp_stack_push_int(t_pdp_stack *s, int i) {pdp_list_add(s, a_int, (t_pdp_word)i); return e_ok;}
+t_pdp_word_error pdp_stack_push_pointer(t_pdp_stack *s, void *x) {pdp_list_add(s, a_pointer, (t_pdp_word)x); return e_ok;}
+t_pdp_word_error pdp_stack_push_symbol(t_pdp_stack *s, t_pdp_symbol *x) {pdp_list_add(s, a_symbol, (t_pdp_word)x); return e_ok;}
+
+/* note: packets pushed stack are owned by the stack. if a caller wants to keep a packet that
+ will be deleted by the word, it should make a copy before transferring it to the stack.
+ if a stack processor wants to write to a packet, it should replace it with a writable copy first */
+
+t_pdp_word_error pdp_stack_push_packet(t_pdp_stack *s, int p) {pdp_list_add(s, a_packet, (t_pdp_word)p); return e_ok;}
+
+
+
+
+
+t_pdp_word_error pdp_stack_pop_float(t_pdp_stack *s, float *f)
+{
+ if (!s->first) return e_underflow;
+
+ if (s->first->t == a_float) *f = s->first->w.w_float;
+ else if (s->first->t == a_int) *f = (float)s->first->w.w_int;
+ else *f = 0.0f;
+ pdp_stack_drop(s);
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_pop_int(t_pdp_stack *s, int *i)
+{
+ if (!s->first) return e_underflow;
+ if (s->first->t == a_int) *i = s->first->w.w_int;
+ else if (s->first->t == a_float) *i = (int)s->first->w.w_float;
+ else *i = 0;
+ pdp_stack_drop(s);
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_pop_pointer(t_pdp_stack *s, void **x)
+{
+ if (!s->first) return e_underflow;
+ *x = (s->first->t == a_pointer) ? s->first->w.w_pointer : 0;
+ pdp_stack_drop(s);
+ return e_ok;
+}
+
+t_pdp_word_error pdp_stack_pop_symbol(t_pdp_stack *s, t_pdp_symbol **x)
+{
+ if (!s->first) return e_underflow;
+ *x = (s->first->t == a_symbol) ? s->first->w.w_symbol : pdp_gensym("invalid");
+ pdp_stack_drop(s);
+ return e_ok;
+}
+
+/* packets popped from the stack are owned by the caller */
+
+t_pdp_word_error pdp_stack_pop_packet(t_pdp_stack *s, int *p)
+{
+ if (!s->first) return e_underflow;
+ *p = (s->first->t == a_packet) ? s->first->w.w_packet : -1;
+ pdp_list_pop(s); //ownership is transferred to receiver, drop kills the packet
+ return e_ok;
+}
+
+
+t_pdp_word_error pdp_stack_mov(t_pdp_stack *s)
+{
+ int position;
+ t_pdp_atom *a, *a_before;
+ if (s->elements < 2) return e_underflow;
+ if (s->first->t != a_int) return e_type;
+
+ pdp_stack_pop_int(s, &position); // get insert point
+ if (position < 1) return e_ok; // < 0 : invalid; do nothing, 0 : nop (= insert at start, but already at start)
+ if ((s->elements-1) < position) return e_underflow;
+
+ a = s->first; // get first atom
+ s->first = a->next;
+
+ if (s->elements-1 == position){ //insert at end
+ s->last->next = a;
+ a->next = 0;
+ s->last = a;
+ }
+ else { //insert somewhere in the middle
+ a_before = s->first;
+ while (--position) a_before = a_before->next;
+ a->next = a_before->next;
+ a_before->next = a;
+ }
+ return e_ok;
+}
+
+/* rotate stack down (tos -> bottom) */
+t_pdp_word_error pdp_stack_rdown(t_pdp_stack *s)
+{
+ t_pdp_word_type t = s->first->t;
+ t_pdp_word w = s->first->w;
+ pdp_list_pop(s);
+ pdp_list_add_back(s, t, w);
+ return e_ok;
+}
+
+
+/* convert to int */
+t_pdp_word_error pdp_stack_int(t_pdp_stack *s)
+{
+ int i;
+ pdp_stack_pop_int(s, &i);
+ pdp_stack_push_int(s, i);
+ return e_ok;
+}
+
+/* convert to float */
+t_pdp_word_error pdp_stack_float(t_pdp_stack *s)
+{
+ float f;
+ pdp_stack_pop_float(s, &f);
+ pdp_stack_push_float(s, f);
+ return e_ok;
+}
+
+
+#define OP1(name, type, op) \
+t_pdp_word_error pdp_stack_##name##_##type (t_pdp_stack *s) \
+{ \
+ type x0; \
+ pdp_stack_pop_##type (s, &(x0)); \
+ pdp_stack_push_##type (s, op (x0)); \
+ return e_ok; \
+}
+
+#define OP2(name, type, op) \
+t_pdp_word_error pdp_stack_##name##_##type (t_pdp_stack *s) \
+{ \
+ type x0, x1; \
+ pdp_stack_pop_##type (s, &(x0)); \
+ pdp_stack_pop_##type (s, &(x1)); \
+ pdp_stack_push_##type (s, x1 op x0); \
+ return e_ok; \
+}
+
+/* some floating point and integer stuff */
+
+OP2(add, float, +);
+OP2(sub, float, -);
+OP2(mul, float, *);
+OP2(div, float, /);
+
+OP1(sin, float, sin);
+OP1(cos, float, cos);
+
+OP2(add, int, +);
+OP2(sub, int, -);
+OP2(mul, int, *);
+OP2(div, int, /);
+OP2(mod, int, %);
+
+OP2(and, int, &);
+OP2(or, int, |);
+OP2(xor, int, ^);
+
+
+/* some integer stuff */
+
+t_pdp_word_error pdp_stack_push_invalid_packet(t_pdp_stack *s)
+{
+ pdp_stack_push_packet(s, -1);
+ return e_ok;
+}
+
+/* dictionary manipulation */
+
+void pdp_forth_word_print_debug(t_pdp_symbol *s)
+{
+ t_pdp_atom *a;
+ if (!s->s_word_spec){
+ post("%s is not a forth word", s->s_name);
+ }
+ else{
+ post("");
+ post("forth word %s", s->s_name);
+ post("\tinput: %d", s->s_word_spec->input_size);
+ post("\toutput: %d", s->s_word_spec->output_size);
+ post("\ttype index: %d", s->s_word_spec->type_index);
+
+ post("\nimplementations:");
+ for(a=s->s_word_spec->implementations->first; a; a=a->next){
+ t_pdp_forthword_imp *i = a->w.w_pointer;
+ startpost("\t%s\t", i->type ? i->type->s_name : "anything");
+ pdp_list_print(i->def);
+
+ }
+ post("");
+ }
+}
+
+/* add a definition (list of high level words (symbols) or primitive routines) */
+void pdp_forthdict_add_word(t_pdp_symbol *name, t_pdp_list *def, int input_size, int output_size,
+ int type_index, t_pdp_symbol *type)
+{
+ t_pdp_forthword_spec *spec = 0;
+ t_pdp_forthword_imp *imp = 0;
+ t_pdp_forthword_imp *old_imp = 0;
+ t_pdp_atom *a;
+ /* check if the word complies to a previously defined word spec with the same name */
+ if (spec = name->s_word_spec){
+ if ((spec->input_size != input_size)
+ ||(spec->output_size != output_size)
+ ||(spec->type_index != type_index)){
+ post("ERROR: pdp_forthdict_add_word: new implementation of [%s] does not comply to old spec",
+ name->s_name);
+ return;
+ }
+
+ }
+ /* no previous word spec with this name, so create a new spec */
+ else{
+ spec = name->s_word_spec = (t_pdp_forthword_spec *)pdp_alloc(sizeof(t_pdp_forthword_spec));
+ spec->name = name;
+ spec->input_size = input_size;
+ spec->output_size = output_size;
+ spec->type_index = type_index;
+ spec->implementations = pdp_list_new(0);
+ }
+
+ /* create the new implementation and add it */
+ imp = (t_pdp_forthword_imp *)pdp_alloc(sizeof(t_pdp_forthword_imp));
+ imp->name = name;
+ imp->def = def;
+ imp->type = type;
+
+ /* can't delete old implemetations because of thread safety */
+ pdp_list_add_pointer(spec->implementations, imp);
+
+}
+
+/* add a primitive */
+void pdp_forthdict_add_primitive(t_pdp_symbol *name, t_pdp_forthword w, int input_size, int output_size,
+ int type_index, t_pdp_symbol *type)
+{
+ t_pdp_list *def = pdp_list_new(1);
+ def->first->t = a_pointer;
+ def->first->w.w_pointer = w;
+ pdp_forthdict_add_word(name, def, input_size, output_size, type_index, type);
+}
+
+/* parse a new definition from a null terminated string */
+t_pdp_list *pdp_forth_compile_def(char *chardef)
+{
+ t_pdp_list *l;
+ char *c;
+
+ if (!(l = pdp_list_from_cstring(chardef, &c))){
+ post ("ERROR: pdp_forth_compile_def: parse error parsing: %s", chardef);
+ if (*c) post ("ERROR: remaining input: %s", c);
+ }
+ if (*c){
+ post ("WARNING: pdp_forth_compile_def: parsing: %s", chardef);
+ if (*c) post ("garbage at end of string: %s", c);
+ }
+
+ return l;
+
+}
+
+void pdp_forthdict_compile_word(t_pdp_symbol *name, char *chardef, int input_size, int output_size,
+ int type_index, t_pdp_symbol *type)
+{
+ /* add the definition list to the dictionary */
+ t_pdp_list *def;
+
+ if (def = pdp_forth_compile_def (chardef))
+ pdp_forthdict_add_word(name, def, input_size, output_size, type_index, type);
+
+
+}
+
+
+
+/* execute a definition list
+ a def list is a list of primitives, immediates or symbolic words */
+t_pdp_word_error pdp_forth_execute_def(t_pdp_stack *stack, t_pdp_list *def)
+{
+ t_pdp_atom *a;
+ t_pdp_word_error e;
+ t_pdp_forthword w;
+ float f;
+ int i,p;
+
+ D post("pdp_forth_execute_def %x %x", stack, def);
+ D pdp_list_print(def);
+
+ for (a = def->first; a; a=a->next){
+ switch(a->t){
+ case a_float: // an immidiate float
+ f = a->w.w_float;
+ D post("pushing %f onto the stack", f);
+ pdp_stack_push_float(stack, f);
+ break;
+ case a_int: // an immidiate int
+ i = a->w.w_int;
+ D post("pushing %d onto the stack", i);
+ pdp_stack_push_int(stack, i);
+ break;
+ case a_packet: // an immidiate int
+ p = a->w.w_packet;
+ D post("pushing packet %d onto the stack", p);
+ pdp_stack_push_packet(stack, pdp_packet_copy_ro(p));
+ break;
+ case a_symbol: // a high level word or an immediate symbol
+ D post("interpeting symbol %s", a->w.w_symbol->s_name);
+ if (e = pdp_forth_execute_word(stack, a->w.w_symbol)) return e;
+ break;
+ case a_pointer: // a primitive
+ w = a->w.w_pointer;
+ D post("exec primitive %x", w);
+ if (e = (w(stack))) return e;
+ break;
+ default:
+ return e_internal;
+
+ }
+ }
+ return e_ok;
+}
+
+/* execute a symbol (a high level word or an immediate)
+ this routine does the type based word multiplexing and stack checking */
+t_pdp_word_error pdp_forth_execute_word(t_pdp_stack *stack, t_pdp_symbol *word)
+{
+ t_pdp_symbol *type = 0;
+ t_pdp_atom *a;
+ t_pdp_forthword_spec *spec;
+ t_pdp_forthword_imp *imp = 0;
+ int i;
+
+ D post("pdp_forth_execute_word %x %x", stack, word);
+
+ /* first check if the word is defined. if not, the symbol will be loaded
+ onto the stack as an immidiate symbol */
+
+ if (!(spec = word->s_word_spec)){
+ D post ("pushing symbol %s on the stack", word->s_name);
+ pdp_stack_push_symbol(stack, word);
+ return e_ok;
+ }
+
+ D post("exec high level word [%s]", word->s_name);
+
+ /* it is a word. check the stack size */
+ if (stack->elements < spec->input_size){
+ D post ("error executing [%s]: stack underflow", word->s_name);
+ return e_underflow;
+ }
+
+ /* if the word is type oblivious, symply execute the first (only)
+ implementation in the list */
+ if (spec->type_index < 0){
+ D post("exec type oblivious word [%s]", word->s_name);
+ imp = spec->implementations->first->w.w_pointer;
+ return pdp_forth_execute_def(stack , imp->def);
+ }
+
+ /* if it is not type oblivious, find the type template
+ to determine the correct implementation */
+
+ for(i=spec->type_index,a=stack->first; i--; a=a->next);
+ switch (a->t){
+ /* get type description from first item on*/
+ case a_packet:
+ type = pdp_packet_get_description(a->w.w_packet); break;
+ case a_symbol:
+ type = a->w.w_symbol; break;
+ case a_float:
+ type = pdp_gensym("float"); break;
+ case a_int:
+ type = pdp_gensym("int"); break;
+ case a_pointer:
+ type = pdp_gensym("pointer"); break;
+ default:
+ /* no type description found on top of stack. */
+ type = pdp_gensym("unknown");
+ break;
+ }
+
+ /* scan the implementation list until a definition with matching type is found
+ if the type spec for a word is NULL, it counts as a match (for generic words) */
+ for (a = spec->implementations->first; a; a = a->next){
+ imp = a->w.w_pointer;
+ if ((!imp->type) || pdp_type_description_match(type, imp->type)){
+ return pdp_forth_execute_def(stack , imp->def);
+ }
+ }
+ D post("ERROR: pdp_forth_execute_word: type error executing [%s] (2). stack:",word->s_name);
+ D pdp_list_print(stack);
+
+ return e_type; // type error
+
+}
+
+
+static void _add_2op(char *name, t_pdp_forthword w, char *type){
+ pdp_forthdict_add_primitive(pdp_gensym(name), w, 2, 1, 0, pdp_gensym(type));
+}
+
+static void _add_1op(char *name, t_pdp_forthword w, char *type){
+ pdp_forthdict_add_primitive(pdp_gensym(name), w, 1, 1, 0, pdp_gensym(type));
+}
+
+
+void pdp_forth_setup(void)
+{
+
+ /* add type oblivious (type_index = -1, type = NULL) stack manip primitives */
+ pdp_forthdict_add_primitive(pdp_gensym("dup"), (t_pdp_forthword)pdp_stack_dup, 1, 2, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("swap"), (t_pdp_forthword)pdp_stack_swap, 2, 2, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("drop"), (t_pdp_forthword)pdp_stack_drop, 1, 0, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("over"), (t_pdp_forthword)pdp_stack_over, 2, 3, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("mov"), (t_pdp_forthword)pdp_stack_mov, 2, 1, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("down"), (t_pdp_forthword)pdp_stack_rdown, 1, 1, -1, 0);
+
+ /* type converters (casts) */
+ pdp_forthdict_add_primitive(pdp_gensym("int"), (t_pdp_forthword)pdp_stack_int, 1, 1, -1, 0);
+ pdp_forthdict_add_primitive(pdp_gensym("float"), (t_pdp_forthword)pdp_stack_float, 1, 1, -1, 0);
+
+ /* add floating point ops */
+ _add_2op("add", (t_pdp_forthword)pdp_stack_add_float, "float");
+ _add_2op("sub", (t_pdp_forthword)pdp_stack_sub_float, "float");
+ _add_2op("mul", (t_pdp_forthword)pdp_stack_mul_float, "float");
+ _add_2op("div", (t_pdp_forthword)pdp_stack_div_float, "float");
+
+ _add_1op("sin", (t_pdp_forthword)pdp_stack_sin_float, "float");
+ _add_1op("cos", (t_pdp_forthword)pdp_stack_cos_float, "float");
+
+ /* add integer ops */
+ _add_2op("add", (t_pdp_forthword)pdp_stack_add_int, "int");
+ _add_2op("sub", (t_pdp_forthword)pdp_stack_sub_int, "int");
+ _add_2op("mul", (t_pdp_forthword)pdp_stack_mul_int, "int");
+ _add_2op("div", (t_pdp_forthword)pdp_stack_div_int, "int");
+ _add_2op("mod", (t_pdp_forthword)pdp_stack_mod_int, "int");
+
+ _add_2op("and", (t_pdp_forthword)pdp_stack_and_int, "int");
+ _add_2op("or", (t_pdp_forthword)pdp_stack_or_int, "int");
+ _add_2op("xor", (t_pdp_forthword)pdp_stack_xor_int, "int");
+
+ /* some immidiates */
+ pdp_forthdict_add_primitive(pdp_gensym("ip"), (t_pdp_forthword)pdp_stack_push_invalid_packet, 0, 1, -1, 0);
+
+}