/* sswf_node.c -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2009 */

/*

Copyright (c) 2002-2009 Made to Order Software Corp.

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and
associated documentation files (the "Software"), to
deal in the Software without restriction, including
without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

#define	SSWF_NEED_ASSERT
#include	"sswf.h"






/* TODO: create an array of nodes we can allocate very quickly from */


/* a global list of all the objects we find while parsing all the source files */
static	struct node_t *		all_objects;


/* allocate a node */
struct node_t *node_init(struct node_t *n, enum node_type_t type, enum node_type_t sub_type)
{
	const char	*filename;
	unsigned long	line;

	if(n != NULL) {
		filename = n->filename;
		line = n->line;
		memset(n, 0, sizeof(struct node_t));
		n->line = line;
		n->filename = filename;

		n->type = type;
		n->sub_type = sub_type;
		n->head = n;
		n->tail = n;

#if DEBUG
		n->serial = 0;

/*printf("*** Initialized node 0x%08lX\n", (long) n);*/
#endif
	}

	return n;
}


struct node_t *node_alloc(enum node_type_t type, enum node_type_t sub_type, unsigned long line)
{
	struct node_t	*n;

	n = sswf_malloc(sizeof(struct node_t), "node_alloc()");

	/*
	 * At the time the node is allocated we are certainly working
	 * on a file and we save that info in that node - we also
	 * save the line # specified by the caller; note that the
	 * init won't modify these info later.
	 */
	n->filename = lex_filename;
	n->line = line;

	return node_init(n, type, sub_type);
}



void node_unparent(struct node_t *p, struct node_t *n, struct node_t *h)
{
	int		idx, pos;

	/* if we have a parent node, we need to unlink ourself from there too */
	if(p != NULL /* && n->previous == NULL */ ) {
		/*
		 * note that only head nodes should be unlinked from their parent
		 * node since none other should be linked there!
		 */
		if(p->left == n) {
#if DEBUG
if(debug_memory > 5) printf("    Left 0x%08lX, header 0x%08lX\n", (long) p->left, (long) h);
#endif
			p->left = h;
		}
		if(p->right == n) {
#if DEBUG
if(debug_memory > 5) printf("    Right 0x%08lX, header 0x%08lX\n", (long) p->right, (long) h);
#endif
			p->right = h;
		}
		if(p->select == n) {
#if DEBUG
if(debug_memory > 5) printf("    Select 0x%08lX, header 0x%08lX\n", (long) p->select, (long) h);
#endif
			p->select = h;
		}
		if(p->list != NULL) {
			idx = p->cnt;
#if DEBUG
if(debug_memory > 5) printf("    List with %d items, header 0x%08lX\n", idx, (long) h);
#endif
			while(idx > 0) {
				idx--;
				if(p->list[idx] == n) {
					/*
					 * we must make sure that the
					 * header isn't already present
					 * in the list, if it is, we just
					 * remove 'n' instead of replacing
					 * 'n' by 'h'!
					 */
					pos = p->cnt;
					while(pos > 0) {
						pos--;
						if(p->list[pos] == h) {
							h = NULL;
							break;
						}
					}
					if(h != NULL) {		/* other node(s) there? */
						p->list[idx] = h;
#if 0 && DEBUG
if(debug_memory > 15) printf("        replaced at position %d (0x%08lX)\n", idx, (long) h);
#endif
					}
					else {
						p->cnt--;
#if 0 && DEBUG
if(debug_memory > 15) printf("        removed from position %d\n", idx);
#endif
						if(idx < p->cnt) {		/* anything needs to be moved? */
							/* move the following pointers down by one entry */
							memmove(p->list + idx, p->list + idx + 1,
								(p->cnt - idx) * sizeof(struct node_t *));
						}
					}
					/* there should be only one reference... */
					break;
				}
			}
		}
	}
}


#if 0
void node_reparent(struct node_t *n, struct node_t *p)
{
	if(n == NULL) {
		return;
	}

	assert(n->previous == NULL, "can't reparent a node which isn't a head node");
	node_unparent(n->parent, n, NULL);

	do {
		n->parent = p;
		n = n->next;
	} while(n != NULL);
}
#endif


void node_unlink(struct node_t *n)
{
	struct node_t	*q, *h;

	if(n == NULL) {
		return;
	}

#if 0 && DEBUG
if(debug_memory > 14) {
	char		*path;
	int		idx;

	q = n;
	while(q->previous != NULL) q = q->previous;
	idx = 0;
	while(q != NULL) idx++, q = q->next;
	path = node_path(n, 1);
	printf("+++ Found %d nodes on \"%s\"\n", idx, path);
	sswf_free(path);
}
#endif

	/* are we unlinking the head? */
	if(n->previous == NULL) {
		q = h = n->next;
		while(q != NULL) {
			q->head = h;
			q = q->next;
		}
	}
	else {
		h = n->head;
		n->previous->next = n->next;
	}

	/* are we unlinking the tail? */
	if(n->next == NULL) {
		q = n->previous;
		if(q != NULL) {
			q->next = NULL;
			while(q != NULL) {
				q->tail = n->previous;
				q = q->previous;
			}
		}
	}
	else {
		n->next->previous = n->previous;
	}

	node_unparent(n->parent,  n, h);
	node_unparent(n->parent2, n, h);

	/* reset the pointers */
	n->head     = n;
	n->tail     = n;
	n->parent   = NULL;
	n->parent2  = NULL;
	n->next     = NULL;
	n->previous = NULL;
}


/* free all the data defined in a node including sub-nodes
 * please, keep sub-nodes and put NULL instead if you wish
 * to keep some of the sub-nodes.
 */
void node_clean(struct node_t *n, const char *spaces)
{
	if(n == NULL) {
		return;
	}
#if DEBUG
if(debug_memory > 0 && spaces == NULL) spaces = "";
#endif

/* remove myself from my parent so it doesn't point to me anymore */
	node_unlink(n);

#if 0
/* the following was put in the node_unlink() entry */
	p = n->parent;
	if(p != NULL) {
		/* if we are in our parent we are the head, so just put the "new" head there (i.e. the next node) */
		if(p->left == n) {
			p->left = n->next;
		}
		if(p->right == n) {
			p->right = n->next;
		}
		if(p->select == n) {
			p->select = n->next;
		}
		/* should we also do that in the p->list? probably! */
		if(p->list != NULL) {
			idx = p->cnt;
			while(idx > 0) {
				idx--;
				if(p->list[idx] == n) {
					if(n->next != NULL) {
						p->list[idx] = n->next;
					}
					else {
						p->cnt--;
						if(idx < p->cnt) {		/* anything needs to be moved? */
							/* move the following pointers down by one entry */
							memmove(p->list + idx, p->list + idx + 1,
								(p->cnt - idx) * sizeof(struct node_t *));
						}
					}
					break;
				}
			}
		}
	}
	/* unlink! */
	if(n->next != NULL) {
		n->next->previous = n->previous;
	}
	else if(n->previous != NULL) {
		/* Ha! The tail is changing */
		l = n->previous;
		l->next = NULL;
		while(l != NULL) {
			l->tail = n->previous;
			l = l->previous;
		}
	}
	if(n->previous != NULL) {
		n->previous->next = n->next;
	}
	else if(n->next != NULL) {
		/* Ha! The head is changing! */
		l = n->next;
		l->previous = NULL;
		while(l != NULL) {
			l->tail = n->tail;
			l->head = n->next;
			l = l->next;
		}
	}
#endif

/* remove the string & data if there are any */
	if(n->string != NULL) {
#if DEBUG
if(debug_memory > 2) {
printf("%s*** Free string 0x%08lX\n", spaces, (long) n->string);
printf("%s*** The string to be freed is [%s]\n", spaces, n->string);
}
#endif
		sswf_clean(&n->string);
	}
	if(n->data != NULL) {
#if DEBUG
if(debug_memory > 2) printf("%s*** Free data 0x%08lX\n", spaces, (long) n->data);
#endif
		sswf_clean(&n->data);
	}

/* free all of our children -- we expect that all children were allocated */
	if((n->flags & NODE_FLAG_SOFTLINK) == 0) {
		/* this is not a reference, so do really delete chidren */
		while(n->left != NULL) {
#if DEBUG
if(debug_memory > 2) printf("%s*** Free left 0x%08lX (parent: 0x%08lX)\n", spaces, (long) n->left, (long) n->left->parent);
#endif
			assert(n->left->parent == n, "one of my left children doesn't have me as parent");
			node_free(n->left);
		}
		while(n->right != NULL) {
#if DEBUG
if(debug_memory > 2) printf("%s*** Free right 0x%08lX (parent: 0x%08lX)\n", spaces, (long) n->right, (long) n->right->parent);
#endif
			assert(n->right->parent == n, "one of my right children doesn't have me as parent");
			node_free(n->right);
		}
		while(n->select != NULL) {
#if DEBUG
if(debug_memory > 2) printf("%s*** Free select 0x%08lX (parent: 0x%08lX)\n", spaces, (long) n->select, (long) n->select->parent);
#endif
			assert(n->select->parent == n, "one of my select children doesn't have me as parent");
			node_free(n->select);
		}
		if(n->list != NULL) {
			while(n->cnt > 0) {
#if DEBUG
if(debug_memory > 2) printf("%s*** Free list item 0x%08lX from 0x%08lX (parent: 0x%08lX/0x%08lX)\n",
		spaces, (long) n->list[n->cnt - 1],
		(long) n,
		(long) n->list[n->cnt - 1]->parent,
		(long) n->list[n->cnt - 1]->parent2);
#endif
				assert(n->list[n->cnt - 1]->parent == n, "one of my list children doesn't have me as parent");
				node_free(n->list[n->cnt - 1]);
			}
			sswf_clean(&n->list);
		}
	}

#if DEBUG
	/*
	 * We do that to make sure we're not re-using the same structure after it was cleaned up.
	 * It is useless if not in DEBUG mode
	 */
	memset(n, 0xAB, sizeof(struct node_t));
#endif
}


void node_free(struct node_t *n)
{
	if(n != NULL) {
#if DEBUG
if(debug_memory > 0) {
		static long	indent = 0;
		char		spaces[256];
		long		max;

		max = indent > sizeof(spaces) - 1 ? sizeof(spaces) - 1 : indent;
		memset(spaces, ' ', max);
		spaces[max] = '\0';
		if(debug_memory > 1) {
			printf("%s*** Freeing node 0x%08lX\n", spaces, (long) n);
		}
		indent += 2;
		node_clean(n, spaces);
		indent -= 2;
		if(debug_memory > 1) {
			printf("%s*** Node 0x%08lX freed\n", spaces, (long) n);
		}
		sswf_free(n);
		return;
}
#endif
		node_clean(n, 0);
		sswf_free(n);
	}
}


void node_free_list(struct node_t *node)
{
	if(node != NULL) {
		while(node->previous != NULL) {
			node_free(node->previous);
		}
		while(node->next != NULL) {
			node_free(node->next);
		}
		node_free(node);
	}
}


void node_link_tail(struct node_t *p, struct node_t *q)
{
	assert(p != NULL, "invalid node pointer to node_link_tail()");

	/* anything to link? */
	if(q == NULL) {
		return;
	}
	/* we could also do q = q->head maybe? */
	assert(q->head == q && q->previous == NULL, "invalid 'q' node in node_link_tail() - not the head");

	/* quick link - watch out, only the head has a proper tail definition! */
	p = p->head;
	p->tail->next = q;
	q->previous = p->tail;
	p->tail = q->tail;		/* q may be a list too */

	/* we've got a new head now */
	while(q != NULL) {
		q->head = p;
		q = q->next;
	}
}



/* while parsing the source we must link all the objects in one large global list
 * later we place these objects where they belong so we can search for them
 */
void node_link_object(struct node_t *object)
{
	if(all_objects == NULL) {
		/*lex_filename = "*object link node*"; -- use whatever is current... */
		all_objects = node_alloc(NODE_TYPE_OBJECT, NODE_SUBTYPE_LIST, 0);

#if 0 && DEBUG
printf("The 'all objects' list is at: 0x%08lX\n", (unsigned long) all_objects);
#endif

		/*
		 * just in case, we name this object so we can easilly
		 * recognize it in the debug output
		 */
		all_objects->left = node_alloc(NODE_TYPE_STRING, NODE_SUBTYPE_UNKNOWN, 0);
		all_objects->left->string = "objects";
		all_objects->left->parent = all_objects;
	}

	node_link_list(all_objects, object);
}


void node_done_object(void)
{
	/* when this is called, we're done with all the objects
	 * thus we can remove the all_objects node.
	 * Note that the list is "emptied" here since the nodes
	 * present in that list are not children of the all_objects
	 * node (and also they should already have been freed).
	 */
	all_objects->cnt = 0;			/* empty list */
	all_objects->left->string = NULL;	/* remove static string pointer */
	node_free(all_objects);
	all_objects = NULL;
}




void node_link_parent(struct node_t *parent, struct node_t *child)
{
	assert(child == NULL || child->previous == NULL, "node_link_parent() called with a child which isn't the header");
	while(child != NULL) {
		assert(child->parent == NULL, "parenting a child which already has a parent (new: 0x%08lX, old: 0x%08lX)",
					(long) parent, (long) child->parent);
		child->parent = parent;
		child = child->next;
	}
}


#if 0
void node_link_parent2(struct node_t *parent2, struct node_t *child)
{
	assert(child->previous == NULL, "node_link_parent2() called with a child which isn't the header");
	while(child != NULL) {
		child->parent2 = parent2;
		child = child->next;
	}
}
#endif


void node_link_list(struct node_t *list, struct node_t *item)
{
	assert((list->flags & NODE_FLAG_SOFTLINK) == 0, "can't link in the list of a softlink node");

	if(list->list == NULL) {
		list->max = 0;
		list->cnt = 0;
	}
	if(list->cnt >= list->max || list->list == NULL) {
		list->max += 256;
		list->list = sswf_remalloc(list->list, list->max * sizeof(struct node_t *), "node_link_list() - enlarge");
	}

	/* should we have item->parent = list ? */
	/* Answer:
	 * at this time that would break the parents of objects
	 * put in the all_objects list
	 */

	list->list[list->cnt] = item;
	list->cnt++;
}


void node_append_list(struct node_t *list, struct node_t *add)
{
	long		cnt;

	assert((list->flags & NODE_FLAG_SOFTLINK) == 0, "can't link in the list of a softlink node");

	if(add == NULL) {
		return;
	}

	/* anything to happen? */
	if(add->list == NULL) {
		return;
	}

	if(list->list == NULL) {
		list->max = 0;
		list->cnt = 0;
	}

	cnt = list->cnt + add->cnt;
	if(cnt > list->max) {
		list->max = (cnt + 255) & -256;
		list->list = sswf_remalloc(list->list, list->max * sizeof(struct node_t *), "node_append_list() - enlarge");
	}

	memcpy(list->list + list->cnt, add->list, add->cnt * sizeof(struct node_t *));
	list->cnt = cnt;
}



struct node_t *node_search_list(struct node_t *obj, const char *name)
{
	struct node_t	*o;
	int		idx;

	if(obj->list != NULL) {
		idx = obj->cnt;
		while(idx > 0) {
			idx--;
			assert(obj->list[idx]->type == NODE_TYPE_OBJECT, "an object in a list of objects within an object is not an object");
			o = obj->list[idx]->left;
			if(o != NULL) {		/* named object at least? */

/*printf("    compare [%s] vs [%s]\n", o->string, name); fflush(stdout);*/

				if(strcasecmp(o->string, name) == 0) {
					/* we found it! */
					return obj->list[idx];
				}
			}
		}
	}

	return NULL;
}



struct node_t *node_find_object(struct node_t *obj, const char *name)
{
	struct node_t	*r;

	/* find an object with a specific name */
	while(obj != NULL) {
		if(obj->type == NODE_TYPE_OBJECT) {
			r = node_search_list(obj, name);
			if(r != NULL) {
				return r;
			}
		}
		obj = obj->parent;
	}

	/* can't find it! */
	return NULL;
}



struct node_t *node_find_block(struct node_t *expr)
{
	while(expr != NULL) {
		if(expr->type == NODE_TYPE_OBJECT) {
			return expr;
		}
		expr = expr->parent;
	}

	return NULL;
}


char *node_path(struct node_t *n, int include_empty)
{
	char		*path, *s;
	const char	*name;

	path = NULL;
	while(n != NULL) {
		if(n->left != NULL && n->left->string != NULL && *n->left->string != '\0') {
			name = n->left->string;
		}
		else if(n->data != NULL && n->data->label != NULL && *n->data->label != '\0') {
			name = n->data->label;
		}
		else if(include_empty) {
			name = "<no name>";
		}
		else {
			name = NULL;
		}
		if(name != NULL) {
			/* except for the first time, add a field separator */
			if(path != NULL) {
				s = sswf_strcat3(name, ".", path);
			}
			else {
				s = sswf_strcat(name, path);
			}
			sswf_free(path);
			path = s;
		}
		n = n->parent;
	}

	return path;
}


/* which is one of NODE_UNIT_... */
/* TODO: in order to know which unit to use we need to have
 * the destination field! that means we can't compute anything
 * until we know what to do with the final value!
 * I think we will forget about the units at this time...
 */
enum node_type_t node_find_unit(struct node_t *n, long which)
{
	static enum node_type_t def_units[NODE_UNIT_MAX] = {
		/* angle */	NODE_SUBTYPE_RAD,
		/* boolean */	NODE_SUBTYPE_OTHER,
		/* color */	NODE_SUBTYPE_FC,
		/* ratio */	NODE_SUBTYPE_RT,
		/* size */	NODE_SUBTYPE_PX,
		/* speed */	NODE_SUBTYPE_FPS,
		/* time */	NODE_SUBTYPE_SEC
	};

	while(n != NULL) {
		if(n->unit[which] >= NODE_TYPE_UNIT) {
			return n->unit[which];
		}
		n = n->next;
	}

	return def_units[which];
}


void link_sub_object(struct node_t *p, struct node_t *obj)
{
	struct node_t	**o, *same, *sub_item;
	int		idx /*, cnt*/;
	char		*on, *sn;

/* Unnamed objects are simply linked as is... */
	if(obj->left == NULL) {
		node_link_list(p, obj);
		assert(obj->parent2 == NULL, "parent2 defined twice");
		obj->parent2 = p;
		return;
	}

/*
 * When there is a name we MUST check for another object named the same way.
 *
 * At this time, only lists and actions can bear the same name (lists are
 * merged and actions are named after what they do, so in the latter it's
 * not really a name).
 */
	same = node_search_list(p, obj->left->string);
	if(same == NULL) {
		/* first object with this name, just link it as is */
		node_link_list(p, obj);
		assert(obj->parent2 == NULL, "parent2 defined twice");
		obj->parent2 = p;
		return;
	}

/* if both are actions, simply link them one after another, that's fine */
	if(same->sub_type == NODE_SUBTYPE_ACTION
	&& obj->sub_type == NODE_SUBTYPE_ACTION) {
		node_link_list(p, obj);
		assert(obj->parent2 == NULL, "parent2 defined twice");
		obj->parent2 = p;
		return;
	}

/* check if we have lists, if not, generate an error and ignore this 2nd definition */
	if(same->sub_type != NODE_SUBTYPE_LIST
	|| obj->sub_type != NODE_SUBTYPE_LIST) {
		on = node_path(obj, 0);
		sn = node_path(same, 0);
fprintf(stderr, "ERROR at line #%ld in file \"%s\": two objects (which are not both lists nor actions) are named the same (\"%s\" and \"%s\", 1st instance at line #%ld in file \"%s\").\n",
				obj->line, obj->filename,
				on, sn,
				same->line, same->filename);
		sswf_free(on);
		sswf_free(sn);
		errcnt++;
		return;
	}

	assert(same->right != NULL, "no definition in a list -- we can't merge anything here");

/* merge lists silently (thus we can have libraries type of things!) */
	/*
	 * Watch out! the lists may have multiple levels with the same name!!!
	 * (such as sswf.fnt.<name1> and sswf.fnt.<name2>)
	 * We have to append <name2> to sswf.fnt instead of the sswf.fnt(.<name2>)
	 * to the 1st sswf list!!!
	 */
#if 0
fprintf(stderr, "merging two lists named \"%s\" and \"%s\" now.\n",
		obj->left->string, same->left->string);
#endif

	/* first make sure the units are exactly the same (or set to "default"?!?) */
	for(idx = 0; idx < NODE_UNIT_MAX; idx++) {
		if(same->unit[idx] != obj->unit[idx]
		/*&& same->unit[idx] != 0 && obj->unit[idx] != 0*/) {
			on = node_path(obj, 0);
			sn = node_path(same, 0);
fprintf(stderr, "ERROR at line #%ld in file \"%s\": can't merge the two lists named \"%s\" and \"%s\" since they use different units (1st list at line #%ld in file \"%s\").\n",
					obj->line, obj->filename,
					on, sn,
					same->line, same->filename);
			sswf_free(on);
			sswf_free(sn);
			errcnt++;
			return;
		}
	}

#if 0
printf("------------------------------ MERGING LISTS\n");
if(0) {
extern struct node_t *top_object;
node_print(top_object);
}
#endif

#if DEBUG
{
	struct node_t		**data;
	struct node_t		*last;

	data = obj->list;
	last = NULL;
#endif
	//for(o = obj->list, cnt = obj->cnt; cnt > 0; cnt--, o++) {
	o = obj->list;
	idx = 0;
	while(idx < obj->cnt) {

#if 0
{
char *on, *l1, *l2, *r;
on = node_path(o[idx], 1);
l1 = node_path(o[idx]->parent, 1);
l2 = node_path(o[idx]->parent2, 1);
r = node_path(obj, 1);
printf("0x%08lX [%s]: Linking lists [%s] (parent: 0x%08lX \"%s\" and 0x%08lX \"%s\", should be 0x%08lX \"%s\")\n",
		(long) o[idx], on,
		obj->left->string,
		(long) o[idx]->parent, l1,
		(long) o[idx]->parent2, l2,
		(long) obj, r);
sswf_free(on);
sswf_free(l1);
sswf_free(l2);
sswf_free(r);
}
assert(last != o[idx], "last object still in the list");
last = o[idx];
#endif

		assert(o[idx]->parent == obj || o[idx]->parent2 == obj,
			"a child object doesn't have the proper parent (while merging lists)");

		/* is this item (to be inserted) duplicated in the "same" list? */
		if(o[idx]->left != NULL) {
#if 0
{ char *a, *b; a = node_path(o[idx], 1); b = node_path(same, 1);
printf("  Compare items [%s] & [(%s)]\n", a, b);
}
#endif
			sub_item = node_search_list(same, o[idx]->left->string);
			if(sub_item != NULL) {
				/*
				 * When duplicated, we have better to call
				 * this function recursively
				 */
				link_sub_object(same, o[idx]);
#if DEBUG
				assert(data == obj->list, "the obj->list pointer changed when we called the link_sub_object() function recursively");
#endif
				/* here we can't unlink o[idx]
				 * instead we increment idx */
				idx++;
				continue;
			}
		}

		/* if there is no name or no duplicates, link the sub-object as is in this list */
#if 0
{ char *a, *b; a = node_path(o[idx], 1); b = node_path(same, 1);
printf("  Appending item [%s] in [(%s)]\n", a, b);
}
#endif
		node_unlink(o[idx]);
		o[idx]->parent = same->right;
		if(same->right->right == NULL) {
			same->right->right = o[idx];
		}
		else {
			node_link_tail(same->right->right, o[idx]);
		}
		node_link_list(same, o[idx]);
		o[idx]->parent2 = same;
	}
#if DEBUG
}
#endif

#if 0
	/* this is code from the old days... */
	if(obj != NULL) {
		sub_item = same;	/* avoid warnings */
		/* First link the objects (really necessary?!) */
		/* This was turned off and everything still worked.
		 * However, with multiple lists levels it could be
		 * that it would be necessary...
		if(same->right == NULL) {
			same->right = obj->right;
		}
		else {
			node_link_tail(same->right, obj->right);
		}
		*/
		/*
		 * Append items of 2nd list to 1st
		 * and now we can forget about the 1st list
		 */
		node_append_list(same, obj);
	}
#endif

	return;
}


/*
 * Call this function once all the parsing of the source files is done, it will
 * re-organize the objects properly.
 */
int node_setup_objects(void)
{
	struct node_t		**o , *obj, *p;
	int			cnt;

	if(all_objects == NULL) {
		fprintf(stderr, "ERROR: no object found. There is nothing we can do with this script.\n");
		return -1;
	}

	o = all_objects->list;
	cnt = all_objects->cnt;
	while(cnt > 0) {
		cnt--;
		obj = p = *o++;

#if 0
printf("Parent object [%s]\n", obj->left == NULL ? "<noname>" : obj->left->string);
#endif

		for(;;) {
			p = p->parent;
			assert(p != NULL, "found an object without a parent object");
			if(p->type == NODE_TYPE_OBJECT) {
				/*
				 * put the object 'obj' in the parent 'p' as
				 * required (i.e. lists and actions are special cases)
				 */
				link_sub_object(p, obj);
				break;
			}
		}
	}

#if 0 && DEBUG
	node_print(all_objects);
#endif

	return 0;
}




#if DEBUG
/*
 * Use the following function in order to print out the complete
 * tree of node from any given node.
 */
static unsigned long		print_serial;

static void node_print_all(struct node_t *n, long indent);
static void node_print_info(struct node_t *n, long indent)
{
	char		spaces[256], *nn;
	int		idx;

	if(n == NULL) {
		return;
	}
	if(n->serial == print_serial) {
		fflush(stdout);
		fprintf(stderr, "WARNING: node 0x%08lX printed twice.\n", (long) n);
		return;
	}
	n->serial = print_serial;

	sprintf(spaces, "0x%08lX  ", (long) n);
	if(indent > sizeof(spaces) - 2 - 12) {
		indent = sizeof(spaces) - 1 - 12;
	}
	memset(spaces + 12, ' ', indent);
	spaces[indent + 12] = '\0';

	/* print info about this node */
	nn = node_path(n, 1);
	printf("%sNode 0x%08lX: \"%s\" (From \"%s\" at line #%ld)\n",
				spaces,
				(long) n, nn,
				n->filename, n->line);
	sswf_free(nn);
	printf("%sParent: 0x%08lX/0x%08lX, head: 0x%08lX, tail: 0x%08lX, next: 0x%08lX, previous: 0x%08lX\n",
				spaces,
				(long) n->parent, (long) n->parent2,
				(long) n->head, (long) n->tail,
				(long) n->next, (long) n->previous);
	printf("%sType: %s (%d), sub-type: %s (%d), data: 0x%08lX\n", spaces,
				node_type_names[n->type].name, n->type,
				node_type_names[n->sub_type].name, n->sub_type,
				(long) n->data);
	if(n->string != NULL) {
		printf("%sString: [%s]\n", spaces, n->string);
	}
	switch(n->type) {
	case NODE_TYPE_INTEGER:
		printf("%sInteger: %ld\n", spaces, n->integer);
		break;

	case NODE_TYPE_RANGE_INTEGER:
		printf("%sInteger: %ld..%ld\n", spaces, n->integer, n->integer2);
		break;

	case NODE_TYPE_FLOAT:
		printf("%sFloat: %g\n", spaces, n->floating_point);
		break;

	case NODE_TYPE_RANGE_FLOAT:
		printf("%sFloat: %g..%g\n", spaces, n->floating_point, n->floating_point2);
		break;

	default:
		/* other types are too complex or a bit useless to print out */
		break;

	}

	if(n->left != NULL) {
		if(n->left->parent != n
		&& n->left->parent2 != n) {
			printf("WARNING: no valid parent for the Left node.\n");
		}
		printf("%sLeft:\n", spaces);
		node_print_all(n->left,   indent + 2);
	}
	if(n->right != NULL) {
		if(n->right->parent != n
		&& n->right->parent2 != n) {
			printf("WARNING: no valid parent for the Right node.\n");
		}
		printf("%sRight:\n", spaces);
		node_print_all(n->right,  indent + 2);
	}
	if(n->select != NULL) {
		if(n->select->parent != n
		&& n->select->parent2 != n) {
			printf("WARNING: no valid parent for the Select node.\n");
		}
		printf("%sSelect:\n", spaces);
		node_print_all(n->select, indent + 2);
	}

	/* now, if there is a list, print it out */
	if(n->list != NULL) {
		printf("%sList with %ld items: (only items which weren't listed before will be here)\n", spaces, n->cnt);
		for(idx = 0; idx < n->cnt; idx++) {
			if(n->list[idx]->parent != n
			&& n->list[idx]->parent2 != n) {
				printf("WARNING: no valid parent for the following List item.\n");
			}
			if(n->list[idx]->serial == print_serial) {
				printf("%s  o Item #%d (0x%08lX already printed)\n", spaces, idx, (long) n->list[idx]);
			}
			else {
				printf("%s  o Item #%d\n", spaces, idx);
				node_print_all(n->list[idx], indent + 2);
			}
		}
	}
}


static void node_print_all(struct node_t *n, long indent)
{
	while(n->previous != NULL) {
		n = n->previous;
	}

	while(n != NULL) {
		printf("------------------\n");
		node_print_info(n, indent);
		n = n->next;
	}
}


void node_print(struct node_t *n)
{
	print_serial++;
	node_print_all(n, 0);
	fflush(stdout);
}
#endif










/*
 * node_execute()
 *
 * Low level expression evaluation.
 * When an expression is being evaluated it can't include an object.
 * Thus if we do find an object, an error is generated.
 */
typedef	int	(*node_exec_func)(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status);

#define	NODE_EXEC_FUNC_INTEGERS		0	/* integer <op> integer and also default when flags != EXEC_LR */
#define	NODE_EXEC_FUNC_FLOATS		1	/* float <op> float, integer <op> float, float <op> integer */
#define	NODE_EXEC_FUNC_STRINGS		2	/* string <op> string */
#define	NODE_EXEC_FUNC_STRINT		3	/* string <op> integer */
#define	NODE_EXEC_FUNC_STRFLT		4	/* string <op> float */
#define	NODE_EXEC_FUNC_max		5

/* define a quick switch macro to directly access two parameters */
#define	EXEC_STRING		0x001
#define	EXEC_INTEGER		0x002
#define	EXEC_FLOAT		0x004
#define	EXEC_LEFT		0x008
#define	EXEC_RIGHT		0x010
#define	EXEC_BOOLEAN_LEFT	0x020		/* the value is first converted to a boolean value */
#define	EXEC_BOOLEAN_RIGHT	0x040
#define	EXEC_SELECT		0x080
#define	EXEC_DEFINITIONS	0x100
#define	EXEC_LR			(EXEC_LEFT | EXEC_RIGHT)
#define	EXEC_BOOLEAN_LR		(EXEC_BOOLEAN_LEFT | EXEC_BOOLEAN_RIGHT)

#define	qs(a, b)		((a) + ((b) << 16))

struct node_exec_types {
	enum node_type_t	type;
	enum node_type_t	sub_type;
	const char *		name;
	int			flags;
	node_exec_func		func[NODE_EXEC_FUNC_max];
};




/* TODO: my point of view is that the current node_exec_field() doesn't make
 * sense - it isn't straight forward and I don't like it. It needs to be fixed.
 */

/*
 * All of the following reduces <name>{.<name>} in an object reference.
 */
static int node_exec_field_name(struct node_t **expr, struct node_t *name, struct node_exec_status_t *status)
{
	int		ec;

	/*
	 * We expect a name, but in case someone writes a whole complex
	 * expression for this name, we have to execute it...
	 */
	if(expr[0]->type != NODE_TYPE_IDENTIFIER && expr[0]->type != NODE_TYPE_STRING) {
		/*
		 * TODO: this is actually wrong, but we keep it for now...
		 * (it needs to return the reference, but it will in fact
		 * execute it and return the contents of that object!!!)
		 * On the other hand, at this time, it should anyway return
		 * an identifier or a string!
		 */
		ec = node_eval(expr[0], name, status);
		if(ec != 0) {
			return ec;
		}
		if(name->type != NODE_TYPE_IDENTIFIER && name->type != NODE_TYPE_STRING) {
			fprintf(stderr, "ERROR: invalid field reference; a name was expected in $(...), got a type %d instead.\n", name->type);
			return 1;
		}
		expr[0] = name;
	}

	return 0;
}


// generate a path determining the name of each field
static long node_exec_complete_field(struct node_t *parent, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t	*n, name;
	char		*path, *old;
	int		ec;

	// path to the parent object
	path = node_path(parent, 0);

	while(r->type == NODE_TYPE_OPERATOR && r->sub_type == NODE_SUBTYPE_FIELD) {
		n = r->left;
		ec = node_exec_field_name(&n, &name, status);
		if(ec != 0) {
			sswf_free(path);
			return ec;
		}
		old = path;
		path = sswf_strcat3(path, ".", n->string);
		sswf_free(old);
		r = r->right;
	}

	ec = node_exec_field_name(&r, &name, status);
	if(ec != 0) {
		return ec;
	}

	old = path;
	path = sswf_strcat3(path, ".", r->string);
	sswf_free(old);

	assert(result->string == NULL, "about to leak memory in result->string");

	result->type =     NODE_TYPE_OBJECT;
	result->sub_type = NODE_SUBTYPE_REFERENCE;
	result->string =   path;

	return 0;
}


/* the return value of the following defines count + 1 or 0 (0 = stop) */
static long node_exec_field_subname(struct node_t *parent, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t			name, *obj, *n;
	int				ec;
	char				*s;

	if(r->type == NODE_TYPE_OPERATOR && r->sub_type == NODE_SUBTYPE_FIELD) {
		/* this is likely to happen! */
		n = r->left;
		ec = node_exec_field_name(&n, &name, status);
		if(ec != 0) {
			return ec;
		}
		obj = node_search_list(parent, n->string);
		if(obj == NULL) {
			if(status->ref) {
				return node_exec_complete_field(parent, r, result, status);
			}
			if(parent->left != 0) {
fprintf(stderr, "ERROR: sub-object named \"%s\" not found in \"%s\" (1).\n", n->string, parent->left->string);
			}
			else {
fprintf(stderr, "ERROR: sub-object named \"%s\" not found (1).\n", n->string);
			}
			errcnt++;
			return 2;
		}
		/* in case there are some more! */
		return node_exec_field_subname(obj, r->right, result, status);
	}

	/* here we certainly have yet another name in r */
	ec = node_exec_field_name(&r, &name, status);
	if(ec != 0) {
		return ec;
	}
	/*
	 * Watch out, with the IMPORT keyword, the parent object may not
	 * include any children, but it still includes references the user
	 * can name.
	 */
	if(parent->type == NODE_TYPE_OBJECT && parent->sub_type == NODE_SUBTYPE_IMPORT) {
		/* in this case we can't just search the list of children */
		if(!status->ref) {
fprintf(stderr, "ERROR: a name (%s) declared in an IMPORT object (%s) can only be used as a reference.\n", r->string, parent->left == NULL ? "<noname>" : parent->left->string);
			errcnt++;
			return 2;
		}
		/*
		 * at the time we arrive here we would have to go through
		 * the list of nodes in parent and compute each expression
		 * to know which one matches the given name; the easiest
		 * way out of this is to accept the IMPORT object even if
		 * the sub-name isn't part of it; the save function will
		 * then come back to this and fix the possible problems;
		 */
		result->type = NODE_TYPE_OBJECT;
		result->sub_type = NODE_SUBTYPE_REFERENCE;
		s = node_path(parent, 0);
		assert(result->string == NULL, "about to leak memory in result->string (0x%08lX)", (long) result);
		result->string = sswf_strcat3(s, ".", r->string);
		sswf_free(s);
		return 0;

		/*
		const struct data_list_t	*list;
		const struct data_common_t	*cd, *str, *type;
		int				max, idx;

		if(parent->data == NULL) {
fprintf(stderr, "ERROR: the IMPORT object \"%s\" has no data definition (invalid?).\n", parent->left == NULL ? "<noname>" : parent->left->string);
			return 2;
		}

		obj = NULL;
		list = dc_list(parent->data);
		max = list->count;
		for(idx = 0; idx < max; idx++) {
			cd = dc_item(list, idx);
			if(list->offset[idx] < 0)
			if(((const struct data_import_t *) cd)->type == IMPORT_TYPE_NAME) {
					idx++;
					assert(idx < max, "expected a string with the external name reference");
					str = dc_item(list, idx);
					assert(str->type == NODE_TYPE_STRING, "expected a string item");
					assert(str->name_len != 0 || str->name[0] == '\0', "a reference name can't be empty in an IMPORT");

					// if there is a 2nd string, that's the type of the item
					if(idx + 1 < max && list->offset[idx + 1] >= 0) {
						type = dc_item(list, idx + 1);
						if(type->type == NODE_TYPE_STRING) {
							idx++;
							assert(type->name_len != 0 || type->name[0] == '\0', "a reference type can't be empty in an IMPORT");
						}
					}

					if(strcasecmp(str->name, r->string) == 0) {
						// that's a reference to the IMPORT
						// object itself when it succeeds
						obj = parent;
						break;
					}
			}
		}
		*/
	}
	else {
		obj = node_search_list(parent, r->string);
	}
	if(obj == NULL) {
		if(status->ref) {
			return node_exec_complete_field(parent, r, result, status);
		}
		if(parent->left != 0) {
fprintf(stderr, "ERROR: sub-object named \"%s\" not found in \"%s\" (2).\n", r->string, parent->left->string);
		}
		else {
fprintf(stderr, "ERROR: sub-object named \"%s\" not found (2).\n", r->string);
		}
		errcnt++;
		return 2;
	}

	/* whatever it is, we need to evaluate it */
	if(obj->sub_type == NODE_SUBTYPE_VARIABLE) {
		/* in case of a variable, we just want the result of the right hand-side */
		return node_eval(obj->right, result, status);
	}

	if(status->ref) {
		/* in this case we only want a reference so we return the object as is! */
		result->type = NODE_TYPE_OBJECT;
		result->sub_type = NODE_SUBTYPE_REFERENCE;
		//result->string = sswf_strdup(r->string);
		assert(result->string == NULL, "about to leak memory in result->string");
		result->string = node_path(obj, 0);
		return 0;
	}

	/* we found the object "execute" it like an inline reference */
	return node_execute(obj, result, status);
}



static int node_exec_field(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t	name, *obj;
	int		ec;

#if 0
/* the following prints out the field being searched (i.e. "sswf.fnt.fotinos.insert") */
	l = expr->left;
	r = expr->right;
	printf("Search for \"%s", l->string);
	while(r->type == NODE_TYPE_OPERATOR && r->sub_type == NODE_SUBTYPE_FIELD) {
		l = r->left;
		ec = node_exec_field_name(&l, &name, status);
		if(ec == 0) {
			printf(".%s", l->string);
		}
		r = r->right;
	}
	ec = node_exec_field_name(&r, &name, status);
	if(ec == 0) {
		printf(".%s", r->string);
	}
	printf("\".\n");
	fflush(stdout);
#endif

	l = expr->left;
	r = expr->right;

/* NOTE: at the first level we can search the object anywhere, after that it has to be
 * a child of whatever we found at the previous level
 */
	ec = node_exec_field_name(&l, &name, status);
	if(ec != 0) {
		return ec;
	}
	/* use the name to find the object from where we currently are */
	obj = node_find_object(expr, l->string);
	if(obj != NULL) {
		ec = node_exec_field_subname(obj, r, result, status);
	}

	if((obj == NULL && ec == 0) || ec == 2) {
		/* print out the "whole name" - i.e. <name>{.<name>} */
		fprintf(stderr, "ERROR: can't find object or variable \"%s", l->string);

		while(r->type == NODE_TYPE_OPERATOR && r->sub_type == NODE_SUBTYPE_FIELD) {
			l = r->left;
			ec = node_exec_field_name(&l, &name, status);
			if(ec == 0) {
				fprintf(stderr, ".%s", l->string);
			}
			r = r->right;
		}
		ec = node_exec_field_name(&r, &name, status);
		if(ec == 0) {
			fprintf(stderr, ".%s", r->string);
		}
		fprintf(stderr, "\".\n");

		errcnt++;
		ec = 1;
	}

	return ec;
}


static int node_exec_subscript(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		from, to, length, idx;

	/*l = expr->left;*/
	/*r = expr->right;*/

printf("l/r->type = %d/%d\n", l->type, r->type); fflush(stdout);

/* the left hand can be either an object or a string */
	if(l->type == NODE_TYPE_STRING) {
		switch(r->type) {
		case NODE_TYPE_INTEGER:
			from = to = r->integer;
			break;

		case NODE_TYPE_RANGE_INTEGER:
			from = r->integer;
			to = r->integer2;
			break;

		case NODE_TYPE_FLOAT:
			from = to = (int) rint(r->floating_point);
			break;

		case NODE_TYPE_RANGE_FLOAT:
			from = (int) rint(r->floating_point);
			to = (int) rint(r->floating_point2);
			break;

		default:
			fprintf(stderr, "ERROR: can't subscript width an index of that type.\n");
			return 1;

		}
		length = strlen(l->string);
		if(from < 0) {
			from += length;
		}
		if(to < 0) {
			to += length;
		}
		if(from >= length || to >= length) {
			fprintf(stderr, "ERROR: subscript out of bounds (%d or %d > %d).\n", from, to, length);
			return 1;
		}
		if(from > to) {
			from++;
			length = from - to;
		}
		else {
			to++;
			length = to - from;
		}
		result->type = NODE_TYPE_STRING;
		result->sub_type = NODE_SUBTYPE_UNKNOWN;
		result->string = sswf_malloc(length + 1, "node_exec_subscript() - string which is the subscript of another string");
		result->string[length] = '\0';
		if(from > to) {
			idx = 0;
			while(from != to) {
				from--;
				result->string[idx] = l->string[from];
				idx++;
			}
printf("\"%s\"[%d..%d] => \"%s\".\n", l->string, to + length - 1, to, result->string); fflush(stdout);
		}
		else {
			memcpy(result->string, l->string + from, length);
printf("\"%s\"[%d..%d] => \"%s\".\n", l->string, from, to - 1, result->string); fflush(stdout);
		}
	}
	else {
		fprintf(stderr, "ERROR: can't subscript this type at this time.\n");
		return 1;
	}

	return 0;
}


static struct node_t *node_find_reference(struct node_t *expr, const char *name, struct node_exec_status_t *status)
{
	struct node_t		*ref;

	assert(name != NULL, "node_find_reference() was called with a null pointer as the name of an object");

	ref = node_find_object(expr, name);
	if(ref != NULL) {
		return (ref);
	}

	/* if we couldn't find it, try in the status object and the parent, etc. */
	do {
		assert(status->obj != 0, "the 'obj' field of the status is NULL");
		ref = node_find_object(status->obj, name);
		if(ref != NULL) {
			return ref;
		}
		status = status->parent;
	} while(status != 0);

	return NULL;
}


static int node_exec_reference(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t			*ref;

	/* fix the EXPAND vs direct reference */
	if(expr->type == NODE_TYPE_IDENTIFIER) {
		l = expr;
	}

	/* first look for the object in all of our parents */
	ref = node_find_reference(expr, l->string, status);
	if(ref == NULL) {
		fprintf(stderr, "ERROR: can't find object or variable \"%s\".\n", l->string);
		errcnt++;
		return 1;
	}

	/* whatever it is, we need to evaluate it */
	if(ref->sub_type == NODE_SUBTYPE_VARIABLE) {
		/* in case of a variable, we just want the result of the right hand-side */
		return node_eval(ref->right, result, status);
	}

	if(status->ref) {
		/* in this case we only want a reference so we return the object as is! */
		result->type = NODE_TYPE_OBJECT;
		result->sub_type = NODE_SUBTYPE_REFERENCE;
		//result->string = sswf_strdup(l->string);
		assert(result->string == NULL, "about to leak memory in result->string");
		result->string = node_path(ref, 0);
		return 0;
	}

	/* in case of an object, we need to actually execute that object */
	/* we can't use node_eval() here otherwise all the objects would be evaluated! */
	return node_execute(ref, result, status);
}



static int node_exec_identity_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer;

	return 0;
}

static int node_exec_identity_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point;

	return 0;
}



static int node_exec_identity_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	char		*s;

	result->string = sswf_strdup(l->string);
	s = result->string;
	while(*s != '\0') {
		*s = toupper((unsigned char) *s);
		s++;
	}

	return 0;
}

static int node_exec_negate_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = -l->integer;

	return 0;
}

static int node_exec_negate_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = -l->floating_point;

	return 0;
}



static int node_exec_negate_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	char		*s;

	result->string = sswf_strdup(l->string);
	s = result->string;
	while(*s != '\0') {
		*s = tolower((unsigned char) *s);
		s++;
	}

	return 0;
}


static int node_exec_logical_not_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = !l->integer;

	return 0;
}





static int node_exec_not_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = ~l->integer;

	return 0;
}

static int node_exec_not_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	char		*s;

	result->string = sswf_strdup(l->string);
	s = result->string;
	while(*s != '\0') {
		if(isupper((unsigned char) *s)) {
			*s = tolower((unsigned char) *s);
		}
		else {
			*s = toupper((unsigned char) *s);
		}
		s++;
	}

	return 0;
}



static int node_exec_group_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->string = sswf_strdup(l->string);

	return 0;
}



struct node_exec_funcinfo {
	const char	*name;		/* return type + name + parameters (prototype if you wish) */
	node_exec_func	func;		/* l = list of parameters */
};



static int node_exec_func_abs(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = fabs(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_acos(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = acos(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_asin(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = asin(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_atan(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = atan(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_atan2(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = atan2(l->list[0]->floating_point, l->list[1]->floating_point);

	return 0;
}


#if HAS_CBRT
static int node_exec_func_cbrt(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = cbrt(l->list[0]->floating_point);

	return 0;
}
#endif


static int node_exec_func_ceil(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = (long) ceil(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_cos(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = cos(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_debug_s(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	fprintf(stderr, "DEBUG: string - [%s]\n", l->list[0]->string);
	result->integer = 0;

	return 0;
}


static int node_exec_func_debug_i(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	fprintf(stderr, "DEBUG: integer - [%ld]\n", l->list[0]->integer);
	result->integer = 0;

	return 0;
}


static int node_exec_func_debug_f(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	fprintf(stderr, "DEBUG: floating point - [%g]\n", l->list[0]->floating_point);
	result->integer = 0;

	return 0;
}


static int node_exec_func_defined(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = node_find_reference(expr, l->list[0]->string, status) != NULL;

	return 0;
}


static int node_exec_func_exp(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = exp(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_floor(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = (long) floor(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_log(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = log(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_log10(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = log10(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_rint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = (long) rint(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_rnd(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = (double) rand() / (double) RAND_MAX;

	return 0;
}


static int node_exec_func_select(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	long		idx;

	idx = l->list[0]->integer;
	if(idx < 0 || idx >= l->cnt) {
		fprintf(stderr, "ERROR: select() index out of bounds (%ld not in [0..%ld) range)\n", idx, l->cnt);
		return -1;
	}
	result->type = l->list[idx]->type;
	switch(result->type) {
	case NODE_TYPE_INTEGER:
		result->integer = l->list[idx]->integer;
		break;

	case NODE_TYPE_FLOAT:
		result->floating_point = l->list[idx]->floating_point;
		break;

	case NODE_TYPE_STRING:
		result->string = sswf_strdup(l->list[idx]->string);
		break;

	case NODE_TYPE_OBJECT:
		fprintf(stderr, "TODO: can't select objects yet...\n");
		abort();

	default:
		fprintf(stderr, "ERROR: trying to select() an object of an unknown type.\n");
		return -1;

	}

	return 0;
}


static int node_exec_func_sin(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = sin(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_sqrt(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = sqrt(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_tan(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = tan(l->list[0]->floating_point);

	return 0;
}


static int node_exec_func_strlen(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strlen(l->list[0]->string);

	return 0;
}





struct fmt_info {
	char		*fmt;			/* input format */
	int		cnt;			/* current number of valid characters */
	int		max;			/* max. number of char. before we need to resize the buffer */
	char		*result;		/* dynamically allocated result */
};


static void strf_put(struct fmt_info *info, char c)
{
	if(info->cnt >= info->max) {
		info->max += 256;
		info->result = sswf_remalloc(info->result, info->max, "node_exec_func_strf() - string");
	}

	info->result[info->cnt] = c;
	info->cnt++;
}





static int node_exec_func_strf(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	char		tmp[256], buf[256];
	char		*d;
	int		idx, c;
	struct fmt_info	info;

	idx = 1;
	buf[0] = '%';
	tmp[sizeof(tmp) - 1] = '\0';
	memset(&info, 0, sizeof(info));
	info.fmt = l->list[0]->string;
	while(*info.fmt != '\0') {
		if(*info.fmt++ == '%') {
			/* we have a format, read chars up to a valid format character */
			/* TODO: the following misses the %<value>$... possibilities! */
			d = buf + 1;
			while(strchr("%diouxXeEfFgGaAcCsSpn", (c = *info.fmt++)) == NULL && c != '\0' && d - buf < sizeof(buf) - 2) {
				*d++ = c;
			}
			if(c == '\0') {
				/* we moved ahead of the null termintor!!! */
				info.fmt--;
				c = 'i';	/* define a default format - certainly wrong! */
			}
			/* we've got to save the format now */
			*d++ = c;
			*d = '\0';
			/* we need to check the index AFTER we parsed the <value>$ entry */
			if(idx < 1 || idx >= l->cnt) {
				fprintf(stderr, "ERROR: invalid strf() format string (%s) - not enough parameters.\n",
						l->list[0]->string);
				sswf_free(info.result);
				return -1;
			}
			switch(d[-1]) {
			case 'd':
			case 'i':
			case 'o':
			case 'u':
			case 'x':
			case 'X':
				if(l->list[idx]->type != NODE_TYPE_INTEGER) {
					fprintf(stderr, "ERROR: invalid type, parameter #%d was expected to be an integer.\n", idx);
					sswf_free(info.result);
					return -1;
				}
				snprintf(tmp, sizeof(tmp) - 1, buf, l->list[idx]->integer);
				break;

			case 'e':
			case 'E':
			case 'f':
			case 'F':
			case 'g':
			case 'G':
			case 'a':
			case 'A':
				if(l->list[idx]->type != NODE_TYPE_FLOAT) {
					fprintf(stderr, "ERROR: invalid type, parameter #%d was expected to be a floating point.\n", idx);
					sswf_free(info.result);
					return -1;
				}
				snprintf(tmp, sizeof(tmp) - 1, buf, l->list[idx]->floating_point);
				break;

			case 'c':
			case 'C':
				if(l->list[idx]->type != NODE_TYPE_STRING) {
					fprintf(stderr, "ERROR: invalid type, parameter #%d was expected to be a string.\n", idx);
					sswf_free(info.result);
					return -1;
				}
				snprintf(tmp, sizeof(tmp) - 1, buf, *l->list[idx]->string);
				break;

			case 's':
			case 'S':
				if(l->list[idx]->type != NODE_TYPE_STRING) {
					fprintf(stderr, "ERROR: invalid type, parameter #%d was expected to be a string.\n", idx);
					sswf_free(info.result);
					return -1;
				}
				snprintf(tmp, sizeof(tmp) - 1, buf, l->list[idx]->string);
				break;

			case 'p':
			case 'n':
				/* ignore these */
				tmp[0] = '\0';
				break;

			}
			idx++;
			d = tmp;
			while(*d != '\0') {
				strf_put(&info, *d++);
			}
		}
		else {
			strf_put(&info, info.fmt[-1]);
		}
	}
	/* insert the null terminator */
	strf_put(&info, '\0');

	result->string = info.result;

	return 0;
}


static int cmp_func_names(const char *format, const char *func)
{
	do {
		if(*format == '*') {
			return 1;
		}
		if(*func != *format) {
			return 0;
		}
		format++;
		func++;
	} while(format[-1] != '\0');

	return 1;
}


static int node_exec_function(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	static const struct node_exec_funcinfo	functions[] = {
		/* MATH */
		{ "fabs/f",		node_exec_func_abs	},
		{ "facos/f",		node_exec_func_acos	},
		{ "fasin/f",		node_exec_func_asin	},
		{ "fatan/f",		node_exec_func_atan	},
		{ "fatan/ff",		node_exec_func_atan2	},
		{ "fatan2/ff",		node_exec_func_atan2	},
#if HAS_CBRT
		{ "fcbrt/f",		node_exec_func_cbrt	},
#endif
		{ "iceil/f",		node_exec_func_ceil	},
		{ "fcos/f",		node_exec_func_cos	},
		{ "fexp/f",		node_exec_func_exp	},
		{ "ifloor/f",		node_exec_func_floor	},
		{ "flog/f",		node_exec_func_log	},
		{ "flog10/f",		node_exec_func_log10	},
		{ "irint/f",		node_exec_func_rint	},
		{ "frnd/",		node_exec_func_rnd	},
		{ "fsin/f",		node_exec_func_sin	},
		{ "fsqrt/f",		node_exec_func_sqrt	},
		{ "ftan/f",		node_exec_func_tan	},

		/* STRING */
		{ "sstrf/s*",		node_exec_func_strf	},
		{ "istrlen/s",		node_exec_func_strlen	},

		/* OTHER */
		{ "idebug/s",		node_exec_func_debug_s	},
		{ "idebug/i",		node_exec_func_debug_i	},
		{ "idebug/f",		node_exec_func_debug_f	},
		{ "idefined/s",		node_exec_func_defined	},
		{ "iselect/i*",		node_exec_func_select	},	/* the return value varies */

		{ NULL, NULL }		/* end of table */
	};
	const struct node_exec_funcinfo	*f;
	char				name[256], *n;
	struct node_t			*p, *e, params;
	int				cnt, ec;

/* no parameters to start with */
	n = name + snprintf(name, sizeof(name) - 1, "%s/", expr->left->string);

/* evaluate the parameters (when there are some!) */
	node_init(&params, NODE_TYPE_OBJECT, NODE_SUBTYPE_LIST);
	cnt = 1;
	p = expr->right;
	while(p != NULL) {
		/* evaluate this expression */
		if(n >= name + sizeof(name) - 1) {
			fprintf(stderr, "ERROR: too many parameters for function call \"%s()\".\n",
					expr->left->string);
			node_clean(&params, 0);
			return -1;
		}
		lex_filename = p->filename;
		e = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, p->line);
		node_link_list(&params, e);
		e->parent = &params;
		/* we can't use node_eval() here otherwise we would get only one result */
		ec = node_execute(p, e, status);
		if(ec != 0) {
			node_clean(&params, 0);
			return -1;
		}
		switch(e->type) {
		case NODE_TYPE_INTEGER:
			*n++ = 'i';
			break;

		case NODE_TYPE_FLOAT:
			*n++ = 'f';
			break;

		case NODE_TYPE_STRING:
			*n++ = 's';
			break;

		case NODE_TYPE_OBJECT:
			*n++ = 'o';
			break;

		default:
			fprintf(stderr, "ERROR: can't properly evaluate parameter #%d for function call \"%s()\".\n",
					cnt, expr->left->string);
			node_clean(&params, 0);
			return -1;

		}
		p = p->next;
		cnt++;
	}
	*n = '\0';

/* name is the function name + parameters -- search our table for a corresponding function */
	ec = -1;
	f = functions;
	while(f->name != NULL) {
		/* TODO: ameliorate this following by accepting: f (in f->name) == i (in name) */
		if(cmp_func_names(f->name + 1, name)) {
			/* we found the function! set the default type of the result for this function call */
			switch(*f->name) {
			case 'i':
				result->type = NODE_TYPE_INTEGER;
				break;

			case 'f':
				result->type = NODE_TYPE_FLOAT;
				break;

			case 'o':
				result->type = NODE_TYPE_OBJECT;
				break;

			case 's':
				result->type = NODE_TYPE_STRING;
				break;

#if DEBUG
			default:
				assert(0, "unknown function return type (%c)", *f->name);
				/*NOTREACHED*/
#endif

			}
			ec = (*f->func)(expr, &params, NULL, result, status);
			break;
		}
		f++;
	}
	if(f->name == NULL) {
		fprintf(stderr, "ERROR: unknown function \"%s\".\n", expr->left->string);
	}

	/* TODO: bugs will most probably be in there in regard to functions until the node_free() works perfectly */
	/*node_clean(&params, 0);*/

	return ec;
}



static int node_exec_power_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	/* we could also use a loop? */
	result->integer = (long) pow((double) l->integer, (double) r->integer);

	return 0;
}


static int node_exec_power_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = pow(l->floating_point, r->floating_point);

	return 0;
}



static int node_exec_mul_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer * r->integer;

	return 0;
}


static int node_exec_mul_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point * r->floating_point;

	return 0;
}


static int node_exec_div_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer / r->integer;

	return 0;
}


static int node_exec_div_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point / r->floating_point;

	return 0;
}


static int node_exec_mod_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer % r->integer;

	return 0;
}


static int node_exec_mod_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = fmod(l->floating_point, r->floating_point);

	return 0;
}





static int node_exec_add_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer + r->integer;

	return 0;
}


static int node_exec_add_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point + r->floating_point;

	return 0;
}



static int node_exec_add_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	assert(l->type == NODE_TYPE_STRING && r->type == NODE_TYPE_STRING, "one of the nodes in node_exec_add_strings() isn't a string");
	assert(l->string != NULL && r->string != NULL, "one of the nodes in node_exec_add_strings() has a NULL string pointer");
	result->string = sswf_malloc(strlen(l->string) + strlen(r->string) + 1, "node_exec_add_strings()");
	sprintf(result->string, "%s%s", l->string, r->string);

	return 0;
}



static int node_exec_add_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	char		buffer[16];

	sprintf(buffer, "%ld", r->integer);
	result->string = sswf_malloc(strlen(l->string) + strlen(buffer) + 1, "node_exec_add_strint()");
	sprintf(result->string, "%s%s", l->string, buffer);

	return 0;
}



static int node_exec_sub_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer - r->integer;

	return 0;
}


static int node_exec_sub_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point - r->floating_point;

	return 0;
}




static int node_exec_min_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer < r->integer ? l->integer : r->integer;

	return 0;
}


static int node_exec_min_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point < r->floating_point ? l->floating_point : r->floating_point;

	return 0;
}


static int node_exec_min_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		len;

	assert(l->type == NODE_TYPE_STRING && r->type == NODE_TYPE_STRING, "one of the nodes in node_exec_add_strings() isn't a string");
	assert(l->string != NULL && r->string != NULL, "one of the nodes in node_exec_add_strings() has a NULL string pointer");
	if(strcmp(l->string, r->string) > 0) {
		l = r;
	}
	len = strlen(l->string) + 1;
	result->string = sswf_malloc(len, "node_exec_min_strings()");
	memcpy(result->string, l->string, len);

	return 0;
}






static int node_exec_max_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer > r->integer ? l->integer : r->integer;

	return 0;
}


static int node_exec_max_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->floating_point = l->floating_point > r->floating_point ? l->floating_point : r->floating_point;

	return 0;
}


static int node_exec_max_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		len;

	assert(l->type == NODE_TYPE_STRING && r->type == NODE_TYPE_STRING, "one of the nodes in node_exec_add_strings() isn't a string");
	assert(l->string != NULL && r->string != NULL, "one of the nodes in node_exec_add_strings() has a NULL string pointer");
	if(strcmp(l->string, r->string) < 0) {
		l = r;
	}
	len = strlen(l->string) + 1;
	result->string = sswf_malloc(len, "node_exec_max_strings()");
	memcpy(result->string, l->string, len);

	return 0;
}






static int node_exec_shift_right_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	if(r->integer < 0) {
		result->integer = l->integer << -r->integer;
	}
	else {
		result->integer = l->integer >> r->integer;
	}

	return 0;
}


static int node_exec_shift_left_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status);
static int node_exec_shift_right_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		len;

	if(r->integer > 0) {
		result->string = sswf_strdup(l->string);
		len = strlen(result->string);
		if(r->integer >= len) {
			if(len > 0) {
				memset(result->string + 1, *result->string, len - 1);
			}
		}
		else if(len > 1) {
			memmove(result->string + r->integer, result->string, len - r->integer);
			memset(result->string + 1, *result->string, r->integer - 1);
		}
	}
	else if(r->integer < 0) {
		r->integer = -r->integer;
		node_exec_shift_left_strint(expr, l, r, result, status);
		r->integer = -r->integer;		/* restore - most probably useless */
	}
	else {
		result->string = sswf_strdup(l->string);
	}

	return 0;
}





static int node_exec_shift_left_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	if(r->integer < 0) {
		result->integer = l->integer >> -r->integer;
	}
	else {
		result->integer = l->integer << r->integer;
	}

	return 0;
}


static int node_exec_shift_left_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		ec, len;

	if(r->integer > 0) {
		result->string = sswf_strdup(l->string);
		len = strlen(result->string);
		if(r->integer >= len) {
			memset(result->string, ' ', len);
		}
		else if(len == 1) {
			*result->string = ' ';
		}
		else if(len > 1) {
			memmove(result->string, result->string + r->integer, len - r->integer);
			memset(result->string + r->integer, ' ', r->integer);
		}
	}
	else if(r->integer < 0) {
		r->integer = -r->integer;
		ec = node_exec_shift_right_strint(expr, l, r, result, status);
		r->integer = -r->integer;		/* restore - most probably useless */
		return ec;
	}
	else {
		result->string = sswf_strdup(l->string);
	}

	return 0;
}




static int node_exec_shift_right_unsigned_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	if(r->integer < 0) {
		result->integer = l->integer << -r->integer;
	}
	else {
		result->integer = (unsigned long) l->integer >> r->integer;
	}

	return 0;
}


static int node_exec_shift_right_unsigned_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		ec, len;

	if(r->integer > 0) {
		result->string = sswf_strdup(l->string);
		len = strlen(result->string);
		if(r->integer >= len) {
			memset(result->string, ' ', len);
		}
		else if(len == 1) {
			*result->string = ' ';
		}
		else if(len > 1) {
			memmove(result->string + r->integer, result->string, len - r->integer);
			memset(result->string, ' ', r->integer);
		}
	}
	else if(r->integer < 0) {
		r->integer = -r->integer;
		ec = node_exec_shift_left_strint(expr, l, r, result, status);
		r->integer = -r->integer;		/* restore - most probably useless */
		return ec;
	}
	else {
		result->string = sswf_strdup(l->string);
	}

	return 0;
}




static int node_exec_rotate_right_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	if(r->integer < 0) {
		result->integer = (l->integer << -r->integer)
			+ ((unsigned long) l->integer >> (sizeof(long) * CHAR_BIT + r->integer));
	}
	else {
		result->integer = (l->integer >> r->integer)
			+ ((unsigned long) l->integer << (sizeof(long) * CHAR_BIT - r->integer));
	}

	return 0;
}


static int node_exec_rotate_right_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int		len;

	len = strlen(l->string);
	result->string = sswf_malloc(len, "node_exec_rotate_right_strint()");
	if(r->integer < 0) {
		r->integer = len - (-r->integer % len);
	}
	else {
		r->integer %= len;
	}
	if(r->integer > 0) {		/* i.e. not zero */
		memcpy(result->string + r->integer, l->string, len - r->integer);
		memcpy(result->string, l->string + len - r->integer, r->integer);
	}

	return 0;
}





static int node_exec_rotate_left_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	if(r->integer < 0) {
		result->integer = (l->integer >> -r->integer)
			+ ((unsigned long) l->integer << (sizeof(long) * CHAR_BIT + r->integer));
	}
	else {
		result->integer = (l->integer << r->integer)
			+ ((unsigned long) l->integer >> (sizeof(long) * CHAR_BIT - r->integer));
	}

	return 0;
}


static int node_exec_rotate_left_strint(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	int	ec;

	r->integer = -r->integer;
	ec = node_exec_rotate_right_strint(expr, l, r, result, status);
	r->integer = -r->integer;

	return ec;
}



static int node_exec_and_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer & r->integer;

	return 0;
}


static int node_exec_or_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer | r->integer;

	return 0;
}



static int node_exec_xor_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer ^ r->integer;

	return 0;
}


static int node_exec_equal_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer == r->integer;

	return 0;
}



static int node_exec_equal_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point == r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_equal_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) == 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_not_equal_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer != r->integer;

	return 0;
}


static int node_exec_not_equal_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point != r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_not_equal_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) != 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_less_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer < r->integer;

	return 0;
}


static int node_exec_less_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point < r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_less_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) < 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}


static int node_exec_less_equal_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer <= r->integer;

	return 0;
}


static int node_exec_less_equal_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point <= r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_less_equal_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) <= 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_greater_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer > r->integer;

	return 0;
}


static int node_exec_greater_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point > r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_greater_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) > 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}


static int node_exec_greater_equal_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->integer >= r->integer;

	return 0;
}


static int node_exec_greater_equal_floats(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = l->floating_point >= r->floating_point;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_greater_equal_strings(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	result->integer = strcmp(l->string, r->string) >= 0;
	result->type = NODE_TYPE_INTEGER;

	return 0;
}



static int node_exec_select_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	return node_eval(l->integer ? expr->left : expr->right, result, status);
}


static int node_exec_let(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t	*block, *var;

	/* create a new variable */
	block = node_find_block(expr);
	if(block != NULL) {		/* should always be true! */
		lex_filename = l->filename;
		var = node_alloc(NODE_TYPE_OBJECT, NODE_SUBTYPE_VARIABLE, l->line);
		var->left = node_alloc(NODE_TYPE_IDENTIFIER, NODE_SUBTYPE_UNKNOWN, l->line);
		var->left->string = sswf_strdup(l->string);
		var->left->parent = var;

		/*
		 * we need to duplicate this node because the variable node can't be a soft link,
		 * (the right node can however be a softlink)
		 */
		lex_filename = expr->filename;
		var->right = node_alloc(expr->right->type, expr->right->sub_type, expr->line);
		memcpy(var->right->unit, expr->right->unit, sizeof(expr->unit));
		var->right->parent         = var;
		var->right->flags         |= NODE_FLAG_SOFTLINK;
		var->right->left           = expr->right->left;
		var->right->right          = expr->right->right;
		var->right->select         = expr->right->select;
#if 0
/* Do we need this? It really doesn't seem to me that we would since the lists have
 * to be emptied whenever an object is exited.
 * Anyway, if we need it, make sure cnt field remains synchronized.
 */
		var->right->list           = expr->right->list;
		var->right->cnt            = expr->right->cnt;	/* XXX: if it changes in the referenced object, this is wrong then! */
		var->right->max            = expr->right->max;
#endif
		var->right->string         = expr->right->string;
		var->right->integer        = expr->right->integer;
		var->right->floating_point = expr->right->floating_point;

		node_link_list(block, var);
		var->parent = block;
	}

	return node_eval(expr->right, result, status);
}







enum def_param_t {
	DEF_PARAM_END = 0,		/* mark the end of a definition */
	DEF_PARAM_NAME,			/* the name of this object type as a string */
	DEF_PARAM_LABEL,		/* a string defining a label */
	DEF_PARAM_TYPE,			/* a NODE_TYPE_... - also marks a new entry */
	DEF_PARAM_UNIT,			/* a NODE_UNIT_... */
	DEF_PARAM_SUBTYPE,		/* a NODE_SUBTYPE_... */
	DEF_PARAM_OFFSET,		/* offset in destination structure (-1 - append dynamically) */
	DEF_PARAM_SIZE,			/* define the size of the structure */
	DEF_PARAM_DEFAULT,		/* default value (always in a string) */
	DEF_PARAM_OPTIONAL,		/* the following offset is optional */
	DEF_PARAM_REPEAT,		/* if right after the LABEL, repeat with ';' as separator */
					/* if right after an entry, repeat with ',' as separator */
	DEF_PARAM_EMPTY,		/* refuse such an object if nothing is defined within */
	DEF_PARAM_SET,			/* forces a value if label was found (that's like a flag!) */
	/*DEF_PARAM_SEPARATOR,		-- add a NODE_SUBTYPE_DEFINITION between each definition */

	DEF_PARAM_max			/* never used - practical to close the enum */
};


union def_data_t {
	long			ignored;
	size_t			size;		/* size of the structure (when there is one) */
	unsigned long		offset;		/* offset where the data is saved in the destination structure */
	long			set;		/* used with the DEF_PARAM_SET */
	double			def_value;	/* default value to reset structure at start */
	enum node_type_t	type;		/* type or sub-type */
	enum node_unit_t	unit;		/* a unit entry */
	const char *		string;		/* the default value, a label... */
};


struct definition_t {
	enum def_param_t	param;
	union def_data_t	data;
};


/* enlarge the following if you find yourself with a HUGE object accepting more than 50 different entries (?!?!) */
struct def_entry_t {
	long			flags;		/* different type of flags - see below */
	enum node_type_t	type;		/* main type: FLOAT, STRING or OBJECT */
	enum node_type_t	sub_type;	/* UNKNOWN or the object sub-type */
	enum node_unit_t	unit;		/* the 'which' parameter, not a specific unit */
	unsigned long		offset;		/* offset to save data in structure (only for FLOAT) */
	double			def_value;	/* the default value used to initialize the structure */
};
#define	DEF_ENTRY_FLAG_REPEAT		0x00000001	/* repeat only this specific type many times, not the whole entry */
#define	DEF_ENTRY_FLAG_DEFINED		0x00000002	/* this entry was defined */
#define	DEF_ENTRY_FLAG_OPTIONAL		0x00000004	/* this entry is optional */
#define	DEF_ENTRY_FLAG_HAS_OFFSET	0x00000008	/* this entry has an offset, use default to reset */
#define	DEF_ENTRY_FLAG_HAS_DEFAULT	0x00000010	/* we can use the def_value field */
#define	DEF_ENTRY_FLAG_REFERENCE	0x00000020	/* we only want a reference to that object - not a copy of the object */

struct def_label_t {
	const char *		label;
	long			flags;
	size_t			size;		/* total size of the structure (one structure per label - require the REPEAT or multiple labels) */
	unsigned long		offset;		/* offset to save the "set" value */
	long			set;		/* forces a value on a label, requires an offset */
	long			count;		/* number of entries in this label */
	struct def_entry_t *	entries;	/* a pointer to the entries */
};

#define	DEF_LABEL_FLAG_REPEAT		0x00000001	/* we accept to repeat this entry many times */
#define	DEF_LABEL_FLAG_DEFINED		0x00000002	/* this label was defined */
#define	DEF_LABEL_FLAG_HAS_SET		0x00000004	/* this entry has a "SET" member, use it */
#define	DEF_LABEL_FLAG_HAS_OFFSET	0x00000008	/* this entry has an offset, use default to reset */


#define	DEF_ENTRY_MAX		50
#define	DEF_LABEL_MAX		25
struct def_object_t {
	const char *		name;			/* name of this object type */
	long			flags;			/* see below */
	enum node_unit_t	default_unit;		/* the default unit for this object */
	long			count;			/* number of labels in use */
	size_t			size;			/* total size of the structure (one structure per object) */
	struct def_label_t	labels[DEF_LABEL_MAX];	/* the list of labels */
	struct def_entry_t	entries[DEF_ENTRY_MAX];	/* all the entries of all the labels */
};

/*#define DEF_OBJECT_FLAG_DEFINITION	0x00000001	-- if set, insert a NEW DEFINITION for each new definition entry */
#define	DEF_OBJECT_FLAG_HAS_LIST	0x00000002	/* if any entry is an object */
#define	DEF_OBJECT_FLAG_EMPTY		0x00000004	/* accepts empty entries */


#ifndef _MSVC
#define	DEF_PARAM(prm, value)		{ param: DEF_PARAM_##prm, { value } }

#define	DEF_START(name)			const struct definition_t node_def_##name[] = {	\
						DEF_PARAM(NAME, string: #name),

#define	DEF_END()			DEF_PARAM(END, ignored: 0) };
#define	DEF_LABEL(label)		DEF_PARAM(LABEL, string: label ),
#define	DEF_NOLABEL()			DEF_PARAM(LABEL, string: NULL ),
#define	DEF_REPEAT()			DEF_PARAM(REPEAT, ignored: 0),
#define	DEF_EMPTY()			DEF_PARAM(EMPTY, ignored: 0),

#define	DEF_OBJECT_REF()								\
	DEF_PARAM(TYPE, type: NODE_TYPE_OBJECT),					\
	DEF_PARAM(SUBTYPE, type: NODE_SUBTYPE_REFERENCE),

#define	DEF_OBJECT(sub_type)								\
	DEF_PARAM(TYPE, type: NODE_TYPE_DATA),						\
	DEF_PARAM(SUBTYPE, type: NODE_SUBTYPE_##sub_type),

#define	DEF_OBJECT_OPT(sub_type)							\
	DEF_OBJECT(sub_type)								\
	DEF_PARAM(OPTIONAL, ignored: 0),

#define	DEF_VALUE0(unit_nm, structure, end_t, field, defval)				\
	DEF_PARAM(TYPE, type: NODE_TYPE_FLOAT),						\
	DEF_PARAM(OFFSET, offset: offsetof(struct data_##structure##end_t, field)),	\
	DEF_PARAM(UNIT, unit: NODE_UNIT_##unit_nm),					\
	DEF_PARAM(DEFAULT, def_value: defval),

#define	DEF_VALUE(unit, structure, field, def_value)					\
	DEF_VALUE0(unit, structure, _t, field, def_value)

#define	DEF_VALUE_OPT(unit, structure, field, def_value)				\
	DEF_VALUE0(unit, structure, _t, field, def_value)				\
	DEF_PARAM(OPTIONAL, ignored: 0),

#define	DEF_STRING()									\
	DEF_PARAM(TYPE, type: NODE_TYPE_STRING),

#define	DEF_STRING_OPT()								\
	DEF_PARAM(TYPE, type: NODE_TYPE_STRING),					\
	DEF_PARAM(OPTIONAL, ignored: 0),

#define	DEF_SET0(structure, end_t, field, value)					\
	DEF_PARAM(SET, set: value),							\
	DEF_PARAM(OFFSET, offset: offsetof(struct data_##structure##end_t, field)),

#define	DEF_SET(structure, field, value)						\
	DEF_SET0(structure, _t, field, value)

#define	DEF_SIZE0(structure, end_t)							\
	DEF_PARAM(SIZE, size: sizeof(struct data_##structure##end_t)),

#define	DEF_SIZE(structure)								\
	DEF_SIZE0(structure, _t)

/*
#define	DEF_SEPARATOR()									\
	DEF_PARAM(SEPARATOR, ignored: 0),
*/
#else


struct def_ignore_t {
	enum def_param_t	param;
	long			pad;
	long			ignored;
	long			align;
};
struct def_size_t {
	enum def_param_t	param;
	long			pad;
	size_t			size;
	long			align;
};
struct def_offset_t {
	enum def_param_t	param;
	long			pad;
	unsigned long		offset;
	long			align;
};
struct def_set_t {
	enum def_param_t	param;
	long			pad;
	long			set;
	long			align;
};
struct def_def_value_t {
	enum def_param_t	param;
	long			pad;
	double			def_value;
};
struct def_type_t {
	enum def_param_t	param;
	long			pad;
	enum node_type_t	type;
	long			align;
};
struct def_unit_t {
	enum def_param_t	param;
	long			pad;
	enum node_unit_t	unit;
	long			align;
};
struct def_string_t {
	enum def_param_t	param;
	long			pad;
	const char *		string;
	long			align;
};


#define	DEF_PARAM(t, name, prm, value)		const struct def_##t##_t name[1] = { DEF_PARAM_##prm, 0, value };
#define	DEF_PARAM_SUB(t, line, prm, value)	DEF_PARAM(t, node_def_line_##line, prm, value)
#define	DEF_PARAM_SUB1(t, line, prm, value)	DEF_PARAM_SUB(t, line, prm, value)
#define	DEF_PARAM_AN(t, prm, value)		DEF_PARAM_SUB1(t, __LINE__, prm, value)
#define	DEF_PARAM_IGNORE(prm)			DEF_PARAM_AN(ignore, prm, 0)

#define	DEF_PARAM_SB(n, t, line, prm, value)	DEF_PARAM(t, node_def_line_##line##n, prm, value)
#define	DEF_PARAM_SB1(n, t, line, prm, value)	DEF_PARAM_SB(n, t, line, prm, value)
#define	DEF_PARAM_AM(n, t, prm, value)		DEF_PARAM_SB1(n, t, __LINE__, prm, value)

#define	DEF_START(name)				DEF_PARAM(string, node_def_##name, NAME, #name)

//const struct definition_t node_def_##name[] = { DEF_PARAM(NAME, string: #name),

#define	DEF_END()			DEF_PARAM_IGNORE(END)
#define	DEF_LABEL(label)		DEF_PARAM_AN(string, LABEL, label)
#define	DEF_NOLABEL()			DEF_PARAM_AN(string, LABEL, NULL)
#define	DEF_REPEAT()			DEF_PARAM_IGNORE(REPEAT)
#define	DEF_EMPTY()			DEF_PARAM_IGNORE(EMPTY)

#define	DEF_OBJECT_REF()								\
	DEF_PARAM_AM(a, type, TYPE, NODE_TYPE_OBJECT)					\
	DEF_PARAM_AM(b, type, SUBTYPE, NODE_SUBTYPE_REFERENCE)

#define	DEF_OBJECT(sub_type)								\
	DEF_PARAM_AM(a, type, TYPE, NODE_TYPE_DATA)					\
	DEF_PARAM_AM(b, type, SUBTYPE, NODE_SUBTYPE_##sub_type)

#define	DEF_OBJECT_OPT(sub_type)							\
	DEF_OBJECT(sub_type)								\
	DEF_PARAM_IGNORE(OPTIONAL)

#define	DEF_VALUE0(unit_nm, structure, end_t, field, defval)				\
	DEF_PARAM_AM(a, type, TYPE, NODE_TYPE_FLOAT)					\
	DEF_PARAM_AM(b, offset, OFFSET, offsetof(struct data_##structure##end_t, field))\
	DEF_PARAM_AM(c, unit, UNIT, NODE_UNIT_##unit_nm)				\
	DEF_PARAM_AM(d, def_value, DEFAULT, defval)

#define	DEF_VALUE(unit, structure, field, def_value)					\
	DEF_VALUE0(unit, structure, _t, field, def_value)

#define	DEF_VALUE_OPT(unit, structure, field, def_value)				\
	DEF_VALUE0(unit, structure, _t, field, def_value)				\
	DEF_PARAM_IGNORE(OPTIONAL)

#define	DEF_STRING()									\
	DEF_PARAM_AN(type, TYPE, NODE_TYPE_STRING)

#define	DEF_STRING_OPT()								\
	DEF_PARAM_AM(a, type, TYPE, NODE_TYPE_STRING)					\
	DEF_PARAM_IGNORE(OPTIONAL)

#define	DEF_SET0(structure, end_t, field, value)					\
	DEF_PARAM_AM(a, set, SET, value)						\
	DEF_PARAM_AM(b, offset, OFFSET, offsetof(struct data_##structure##end_t, field))

#define	DEF_SET(structure, field, value)						\
	DEF_SET0(structure, _t, field, value)

#define	DEF_SIZE0(structure, end_t)							\
	DEF_PARAM_AN(size, SIZE, sizeof(struct data_##structure##end_t))

#define	DEF_SIZE(structure)								\
	DEF_SIZE0(structure, _t)

/*
#define	DEF_SEPARATOR()									\
	DEF_PARAM(SEPARATOR, ignored: 0),
*/
#endif


  DEF_START(action_branch)
	DEF_LABEL("[LABEL|GOTO]")
	DEF_STRING	()
  DEF_END()

  DEF_START(action_dictionary)
	DEF_LABEL("[STRING]")
	DEF_REPEAT()
	DEF_STRING	()
  DEF_END()

  DEF_START(action_goto)
	DEF_SIZE(goto_play)
	DEF_LABEL("[PLAY]")
	DEF_VALUE	(BOOLEAN, goto_play, play, 1.0)
	DEF_LABEL("[FRAME]")
	DEF_STRING	()
  DEF_END()

  DEF_START(action_push_data)
	DEF_LABEL("STRING")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_STRING)
	DEF_STRING	()
	DEF_LABEL("PROPERTY")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_PROPERTY)
	DEF_STRING	()
	DEF_LABEL("BOOLEAN")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_BOOLEAN)
	DEF_VALUE	(BOOLEAN, push_data, value, 0.0)
	DEF_LABEL("INTEGER")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_INTEGER)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("FLOAT")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_FLOAT)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("DOUBLE")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_DOUBLE)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("UNDEFINED")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_UNDEFINED)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("NULL")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_NULL)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("LOOKUP")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_LOOKUP)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
	DEF_LABEL("REGISTER")
	DEF_REPEAT()
	DEF_SIZE(push_data)
	DEF_SET		(push_data, type, PUSHDATA_REGISTER)
	DEF_VALUE	(UNKNOWN, push_data, value, 0.0)
  DEF_END()

  DEF_START(action_set_target)
	DEF_EMPTY()
	DEF_LABEL("[TARGET]")
	DEF_STRING	()
  DEF_END()

  DEF_START(action_url)
	DEF_EMPTY()
	/* NOTE: METHOD should really be seperated, but what's the point here?!? */
	DEF_LABEL("[URL|TARGET|METHOD]")
	DEF_STRING	()
	DEF_STRING_OPT	()
  DEF_END()

  DEF_START(action_store_register)
	DEF_SIZE(register)
	DEF_LABEL("[REGISTER]")
	DEF_VALUE	(UNKNOWN, register, reg, 0.0)
	/* the following ensures we get a list so it's easy to parse in the save
	 * maybe we will have named registers later also!
	 */
	DEF_LABEL("[NAME]")		/* DON'T USE -- THAT'S FORBIDDEN STILL */
	DEF_STRING	()
  DEF_END()

  DEF_START(action_wait_for_frame)
	DEF_LABEL("[FRAME]")
	DEF_STRING	()
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FUNCTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
  DEF_END()

  DEF_START(action_simple)
  DEF_END()

  DEF_START(action_script)
	DEF_NOLABEL()
	DEF_STRING	()
  DEF_END()

  DEF_START(button)
	DEF_SIZE(button_flag)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(STATE)			/* turtle like points */
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)		/* all points are zero based */
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION_SCRIPT)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FUNCTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
	DEF_NOLABEL()
	DEF_OBJECT	(ON_EVENT)
	DEF_LABEL("[MENU|TRACK_AS_MENU|TRACK_MENU]")
	DEF_VALUE	(BOOLEAN, button_flag, menu, 0.0)
	DEF_LABEL("[GRID|SCALING_GRID]")
	DEF_OBJECT	(RECT)
  DEF_END()

  DEF_START(color)
	DEF_SIZE(color)
	DEF_NOLABEL()
	DEF_VALUE	(COLOR, color, red,	0.0)
	DEF_VALUE	(COLOR, color, green,	0.0)
	DEF_VALUE	(COLOR, color, blue,	0.0)
	DEF_VALUE_OPT	(COLOR, color, alpha,	1.0)
  DEF_END()

  DEF_START(color_transform)
	DEF_SIZE(color_transform)
	DEF_LABEL("ADD")
	DEF_VALUE	(COLOR, color_transform, add_red,	0.0)
	DEF_VALUE	(COLOR, color_transform, add_green,	0.0)
	DEF_VALUE	(COLOR, color_transform, add_blue,	0.0)
	DEF_VALUE_OPT	(COLOR, color_transform, add_alpha,	0.0)
	DEF_LABEL("SCALE|MULT|MULTIPLY")
	DEF_VALUE	(RATIO, color_transform, mult_red,	1.0)
	DEF_VALUE	(RATIO, color_transform, mult_green,	1.0)
	DEF_VALUE	(RATIO, color_transform, mult_blue,	1.0)
	DEF_VALUE_OPT	(RATIO, color_transform, mult_alpha,	1.0)
  DEF_END()

  DEF_START(do_action)
	DEF_LABEL("ID|INIT|INITIALIZE|INITIALIZATION")
	DEF_OBJECT_REF	()
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION_SCRIPT)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FUNCTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(TRY)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(CATCH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FINALLY)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LIST)
  DEF_END()

  DEF_START(edges)
	DEF_LABEL("ROTATE")
	DEF_SIZE(edges)
	DEF_SET		(edges, type, EDGE_TYPE_ROTATE)
	DEF_VALUE	(ANGLE, edges, delta_x1, 0.0)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_SIZE(edges)
	DEF_SET		(edges, type, EDGE_TYPE_INTERMEDIATE)
	DEF_VALUE	(SIZE, edges, delta_x1,	0.0)
	DEF_VALUE	(SIZE, edges, delta_y1,	0.0)
	DEF_VALUE_OPT	(SIZE, edges, delta_x2,	-1E+128)
	DEF_VALUE	(SIZE, edges, delta_y2,	-1E+128)
	DEF_LABEL("CLOSE")
	DEF_REPEAT()
	DEF_SIZE(edges)
	DEF_SET		(edges, type, EDGE_TYPE_CLOSE)
	DEF_VALUE	(SIZE, edges, delta_x1,	0.0)
	DEF_VALUE	(SIZE, edges, delta_y1,	0.0)
	DEF_VALUE_OPT	(SIZE, edges, delta_x2,	-1E+128)
	DEF_VALUE	(SIZE, edges, delta_y2,	-1E+128)
  DEF_END()

  DEF_START(edit_text)
	DEF_SIZE(edit_text)
	DEF_LABEL("WORD_WRAP")
	DEF_VALUE	(UNKNOWN, edit_text, word_wrap,    1.0)
	DEF_LABEL("MULTILINE")
	DEF_VALUE	(UNKNOWN, edit_text, multiline,    0.0)
	DEF_LABEL("PASSWORD")
	DEF_VALUE	(UNKNOWN, edit_text, password,     0.0)
	DEF_LABEL("READ_ONLY")
	DEF_VALUE	(UNKNOWN, edit_text, readonly,     0.0)
	DEF_LABEL("NO_SELECT")
	DEF_VALUE	(UNKNOWN, edit_text, no_select,    0.0)
	DEF_LABEL("BORDER")
	DEF_VALUE	(UNKNOWN, edit_text, border,       1.0)
	DEF_LABEL("OUTLINE|OUTLINES")
	DEF_VALUE	(UNKNOWN, edit_text, outline,      0.0)
	DEF_LABEL("HTML")
	DEF_VALUE	(UNKNOWN, edit_text, html,         0.0)
	DEF_LABEL("AUTO_SIZE")
	DEF_VALUE	(UNKNOWN, edit_text, auto_size,    0.0)
	DEF_LABEL("MAX|LENGTH|MAX_LENGTH")
	DEF_VALUE	(UNKNOWN, edit_text, max_length,   -1E+128)
	DEF_LABEL("MARGIN|LAYOUT")
	DEF_VALUE	(SIZE,    edit_text, margin_left,  -1E+128)
	DEF_VALUE	(SIZE,    edit_text, margin_right, -1E+128)
	DEF_VALUE_OPT	(SIZE,    edit_text, indent,       -1E+128)
	DEF_VALUE	(SIZE,    edit_text, leading,      -1E+128)
	DEF_LABEL("ALIASING|THICKNESS_SHARPNESS")
	DEF_VALUE	(SIZE,    edit_text, thickness,    -1E+128)
	DEF_VALUE	(SIZE,    edit_text, sharpness,    -1E+128)
	DEF_LABEL("RENDERER|FONT_ENGINE")
	DEF_VALUE	(SIZE,    edit_text, renderer,     -1E+128)
	DEF_LABEL("GRID|GRID_FIT")
	DEF_VALUE	(SIZE,    edit_text, grid_fit,     -1E+128)
	DEF_LABEL("VAR|VARIABLE")
	DEF_SIZE(edit_text)
	DEF_SET		(edit_text, type, EDIT_TEXT_TYPE_VARIABLE)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("INIT|START")
	DEF_SIZE(edit_text)
	DEF_SET		(edit_text, type, EDIT_TEXT_TYPE_INITIAL_TEXT)
	DEF_STRING	()
	DEF_LABEL("ALIGN|ALIGNMENT")
	DEF_SIZE(edit_text)
	DEF_SET		(edit_text, type, EDIT_TEXT_TYPE_ALIGNMENT)
	DEF_STRING	()
	DEF_LABEL("USED_GLYPHS")
	DEF_SIZE(edit_text)
	DEF_SET		(edit_text, type, EDIT_TEXT_TYPE_USED_GLYPHS)
	DEF_STRING	()
	DEF_LABEL("USED_STRING")
	DEF_REPEAT()
	DEF_SIZE(edit_text)
	DEF_SET		(edit_text, type, EDIT_TEXT_TYPE_USED_STRING)
	DEF_STRING	()
	DEF_NOLABEL()
	DEF_OBJECT	(TEXT_SETUP)		/* we don't use positions here */
	DEF_NOLABEL()
	DEF_OBJECT	(RECT)
  DEF_END()

  DEF_START(end)
  DEF_END()

  DEF_START(envelope)
	DEF_LABEL("[VOLUME]")
	DEF_REPEAT	()
	DEF_SIZE(envelope)
	DEF_VALUE	(TIME,  envelope, position, 0.0)
	DEF_VALUE	(RATIO, envelope, left,     -1E+128)
	DEF_VALUE_OPT	(RATIO, envelope, right,    -1E+128)	// if not present use left
  DEF_END()

  DEF_START(export)
	DEF_LABEL("ID|OBJ")
	DEF_REPEAT	()
	DEF_OBJECT_REF	()
	DEF_STRING	()
	DEF_STRING_OPT	()
  DEF_END()

  DEF_START(fill_style)
	DEF_EMPTY()
	DEF_LABEL("[TYPE]")
	DEF_STRING      ()
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR)
	DEF_OBJECT_OPT	(COLOR)
	DEF_NOLABEL()
	DEF_OBJECT	(GRADIENT)
	DEF_LABEL("ID|IMG")
	DEF_OBJECT_REF	()
	DEF_NOLABEL()
	DEF_OBJECT	(MATRIX)
	DEF_OBJECT_OPT	(MATRIX)
  DEF_END()

  DEF_START(font)
	DEF_SIZE(font)
	/*
	 * DEF_SET(font, type, FONT_TYPE_FONT) -- that's the default!
	 * (lucky us because that's an invalid DEF_SET()!!! well - maybe
	 * I've done it on purpose, who knows?)
	 */
	DEF_LABEL("ID|CHAR")
	DEF_REPEAT()
	DEF_SIZE(font_advance)
	DEF_SET		(font_advance, type, FONT_TYPE_ADVANCE)
	DEF_STRING	()
	DEF_OBJECT_REF	()
	DEF_VALUE_OPT	(SIZE, font_advance, x, -1E+128)
	DEF_LABEL("LANGUAGE")
	DEF_SIZE(font_name)
	DEF_SET		(font_name, type, FONT_TYPE_LANGUAGE)
	DEF_STRING	()
	DEF_LABEL("[NAME]")
	DEF_SIZE(font_name)
	DEF_SET		(font_name, type, FONT_TYPE_NAME)
	DEF_STRING	()
	DEF_LABEL("DISPLAY_NAME")
	DEF_SIZE(font_name)
	DEF_SET		(font_name, type, FONT_TYPE_DISPLAY_NAME)
	DEF_STRING	()
	DEF_LABEL("COPYRIGHT")
	DEF_SIZE(font_name)
	DEF_SET		(font_name, type, FONT_TYPE_COPYRIGHT)
	DEF_STRING	()
	DEF_LABEL("TYPE")
	DEF_SIZE(font_name)
	DEF_SET		(font_name, type, FONT_TYPE_TYPE)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_STRING_OPT	()
	DEF_STRING_OPT	()
	DEF_STRING_OPT	()
	DEF_LABEL("[LAYOUT]")
	DEF_VALUE	(SIZE, font, ascent,         -1E+128)
	DEF_VALUE	(SIZE, font, descent,        -1E+128)
	DEF_VALUE	(SIZE, font, leading_height, -1E+128)
	DEF_VALUE_OPT	(SIZE, font, advance,        -1E+128)
	DEF_LABEL("ADVANCE")
	DEF_VALUE	(SIZE, font, advance,        -1E+128)
	DEF_LABEL("SPACE")
	DEF_VALUE	(SIZE, font, space,          -1E+128)
	DEF_LABEL("[KERNING]")
	DEF_REPEAT()
	DEF_SIZE(font_kerning)
	DEF_SET		(font_kerning, type, FONT_TYPE_KERNING)
	DEF_STRING	()
	DEF_VALUE	(SIZE, font_kerning, x, 0.0)
  DEF_END()

  DEF_START(frame_label)
  DEF_END()

  DEF_START(function)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(TRY)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(CATCH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FINALLY)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FUNCTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LIST)
  DEF_END()

  DEF_START(glyph)
	DEF_LABEL("[MOVE|OFFSET]")
	DEF_REPEAT()
	DEF_SIZE(move)
	DEF_SET		(move, type, 3)
	DEF_VALUE	(SIZE, move, tx, 0.0)		/* we could use a MATRIX object for this? */
	DEF_VALUE	(SIZE, move, ty, 0.0)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(RECT)
	DEF_LABEL("FILL0")
	DEF_REPEAT()
	DEF_SIZE(fill_style)
	DEF_SET		(fill_style, select, 0)
	DEF_OBJECT	(FILL_STYLE)
	DEF_NOLABEL()					/* FILL0 when unspecified */
	DEF_REPEAT()
	DEF_OBJECT	(FILL_STYLE)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(EDGES)				/* turtle like points */
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(POINTS)			/* all points are zero based */
  DEF_END()

  DEF_START(gradient)
	DEF_NOLABEL()
	DEF_OBJECT	(MATRIX)
	DEF_OBJECT_OPT	(MATRIX)
	DEF_NOLABEL()
	DEF_SIZE(gradient)
	DEF_SET		(gradient, type, GRADIENT_TYPE_POSITION)
	DEF_REPEAT()
	DEF_VALUE	(RATIO, gradient, position,     0.0)
	DEF_OBJECT	(COLOR)
	DEF_VALUE_OPT	(RATIO, gradient, to_pos,       -1E+128)
	DEF_OBJECT	(COLOR)
	DEF_NOLABEL()
	DEF_SIZE(gradient)
	DEF_SET		(gradient, type, GRADIENT_TYPE_POSITION)
	DEF_REPEAT()
	DEF_OBJECT	(COLOR)
	DEF_VALUE	(RATIO, gradient, position,     0.0)
	DEF_OBJECT_OPT	(COLOR)
	DEF_VALUE	(RATIO, gradient, to_pos,       -1E+128)
	DEF_LABEL("FOCAL")
	DEF_SIZE(gradient)
	DEF_SET		(gradient, type, GRADIENT_TYPE_FOCAL)
	DEF_VALUE	(SIZE, gradient, position,	0.0)
  DEF_END()

  DEF_START(image)
	DEF_SIZE(image)
	DEF_LABEL("LOSSLESS")
	DEF_SET		(image, format, IMAGE_FORMAT_LOSSLESS)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("LOSSLESS8")
	DEF_SET		(image, format, IMAGE_FORMAT_LOSSLESS_8)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("LOSSLESS16")
	DEF_SET		(image, format, IMAGE_FORMAT_LOSSLESS_16)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("LOSSLESS32")
	DEF_SET		(image, format, IMAGE_FORMAT_LOSSLESS_32)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("JPEG")
	DEF_SET		(image, format, IMAGE_FORMAT_JPEG)
	DEF_STRING	()
	DEF_STRING_OPT	()
	DEF_LABEL("QUALITY")
	DEF_VALUE	(RATIO, image, quality, -1E+128)
  DEF_END()

  DEF_START(import)
	DEF_LABEL("URL")
	DEF_SIZE(import)
	DEF_SET		(import, type, IMPORT_TYPE_URL)
	DEF_STRING	()
	DEF_LABEL("FILENAME")
	DEF_SIZE(import)
	DEF_SET		(import, type, IMPORT_TYPE_FILENAME)
	DEF_STRING	()
	DEF_LABEL("[NAME]")
	DEF_SIZE(import)
	DEF_SET		(import, type, IMPORT_TYPE_NAME)
	DEF_REPEAT	()
	DEF_STRING	()
	DEF_STRING_OPT	()
  DEF_END()

  DEF_START(label)
	DEF_NOLABEL()
	DEF_STRING	()
  DEF_END()

  DEF_START(line_style)
	DEF_EMPTY()
	DEF_SIZE(line_style)
	DEF_LABEL("[WIDTH]")
	DEF_VALUE	(SIZE, line_style, width,	      1.0)
	DEF_VALUE_OPT	(SIZE, line_style, to_width,	     -1.0)
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR)
	DEF_OBJECT_OPT	(COLOR)
	DEF_NOLABEL()
	DEF_OBJECT	(FILL_STYLE)
	DEF_LABEL("CAPS")
	DEF_VALUE	(UNKNOWN, line_style, cap_start,     -1.0)
	DEF_VALUE_OPT	(UNKNOWN, line_style, cap_end,       -1.0)
	DEF_LABEL("JOIN")
	DEF_VALUE	(UNKNOWN, line_style, join,          -1.0)
	DEF_VALUE_OPT	(UNKNOWN, line_style, miter,          0.0)
	DEF_LABEL("SCALE")
	DEF_VALUE	(UNKNOWN, line_style, hscale,        -1.0)
	DEF_VALUE_OPT	(UNKNOWN, line_style, vscale,        -1.0)
	DEF_LABEL("PIXEL_HINTING")
	DEF_VALUE	(UNKNOWN, line_style, pixel_hinting, -1.0)
	DEF_LABEL("NO_CLOSE")
	DEF_VALUE	(UNKNOWN, line_style, no_close,      -1.0)
  DEF_END()

  DEF_START(list)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT(UNKNOWN)
  DEF_END()

  DEF_START(matrix)
	DEF_SIZE(matrix)
	DEF_LABEL("SCALE")
	DEF_VALUE	(RATIO, matrix, sx,    1.0)
	DEF_VALUE_OPT	(RATIO, matrix, sy,    -1E+128)
	DEF_LABEL("ROTATE")
	DEF_VALUE	(ANGLE, matrix, angle, 0.0)
	DEF_LABEL("TRANSLATE")
	DEF_VALUE	(SIZE,  matrix, tx,    0.0)
	DEF_VALUE	(SIZE,  matrix, ty,    0.0)
	DEF_LABEL("SKEW")
	DEF_VALUE	(SIZE,  matrix, skew0, 0.0)
	DEF_VALUE	(SIZE,  matrix, skew1, 0.0)
  DEF_END()

  DEF_START(metadata)
	DEF_EMPTY()
	DEF_LABEL("FILENAME")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_FILENAME)
	DEF_STRING	()
	DEF_LABEL("XML")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_METADATA)
	DEF_STRING	()
	DEF_LABEL("TITLE")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_TITLE)
	DEF_STRING	()
	DEF_LABEL("DESCRIPTION")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_DESCRIPTION)
	DEF_STRING	()
	DEF_LABEL("AUTHOR")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_AUTHOR)
	DEF_STRING	()
	DEF_LABEL("PUBLISHER")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_PUBLISHER)
	DEF_STRING	()
	DEF_LABEL("COPYRIGHT")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_COPYRIGHT)
	DEF_STRING	()
	DEF_LABEL("URL")
	DEF_SIZE(metadata)
	DEF_SET		(metadata, type, METADATA_TYPE_URL)
	DEF_STRING	()
  DEF_END()

  DEF_START(on_event)
	DEF_LABEL("EVENT|EVENTS")
	DEF_SIZE(on_event)
	DEF_SET		(on_event, type, ON_EVENT_TYPE_EVENT)
	DEF_STRING	()
	DEF_LABEL("KEY|KEY_CODE")
	DEF_SIZE(on_event)
	DEF_SET		(on_event, type, ON_EVENT_TYPE_KEY)
	DEF_STRING	()
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FUNCTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(TRY)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(CATCH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FINALLY)
  DEF_END()

  DEF_START(place_object)
	DEF_SIZE(place_object)
	DEF_LABEL("MORPH|POSITION")
	DEF_VALUE	(RATIO,		place_object, position,	-1.0)
	DEF_LABEL("DEPTH|LAYER")
	DEF_VALUE	(UNKNOWN,	place_object, depth,	-1.0)
	DEF_LABEL("CLIP|CLIPPING")
	DEF_VALUE	(UNKNOWN,	place_object, clip,	-1E+128)
	DEF_LABEL("TAB_INDEX")
	DEF_VALUE	(UNKNOWN,	place_object, tab_index,-1E+128)
	DEF_LABEL("CACHE_BITMAP")
	DEF_VALUE	(BOOLEAN,	place_object, bitmap_caching, 0.0)
	DEF_LABEL("ID|OBJ")
	DEF_OBJECT_REF	()
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR)
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR_TRANSFORM)
	DEF_NOLABEL()
	DEF_OBJECT	(MATRIX)
	DEF_NOLABEL()
	DEF_OBJECT	(ON_EVENT)
	DEF_LABEL("[NAME]")
	DEF_SIZE(place_object)
	DEF_SET		(place_object, type, PLACE_OBJECT_TYPE_NAME)
	DEF_STRING	()
	DEF_LABEL("BLEND_MODE")
	DEF_SIZE(place_object)
	DEF_SET		(place_object, type, PLACE_OBJECT_TYPE_BLEND_MODE)
	DEF_STRING	()
  DEF_END()

  DEF_START(points)
	DEF_LABEL("ROTATE")
	DEF_SIZE(edges)
	DEF_SET		(edges, type, EDGE_TYPE_ROTATE)
	DEF_VALUE	(ANGLE, points, x1, 0.0)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_SIZE(points)
	DEF_SET		(points, type, EDGE_TYPE_INTERMEDIATE)
	DEF_VALUE	(SIZE, points, x1,	0.0)
	DEF_VALUE	(SIZE, points, y1,	0.0)
	DEF_VALUE_OPT	(SIZE, points, x2,	-1E+128)
	DEF_VALUE	(SIZE, points, y2,	-1E+128)
	DEF_LABEL("CLOSE")
	DEF_REPEAT()
	DEF_SIZE(points)
	DEF_SET		(points, type, EDGE_TYPE_CLOSE)
	DEF_VALUE	(SIZE, points, x1,	0.0)
	DEF_VALUE	(SIZE, points, y1,	0.0)
	DEF_VALUE_OPT	(SIZE, points, x2,	-1E+128)
	DEF_VALUE	(SIZE, points, y2,	-1E+128)
  DEF_END()

  DEF_START(rect)
	DEF_SIZE(rect)
	DEF_NOLABEL()
	DEF_VALUE	(SIZE, rect, min_x,	0.0)
	DEF_VALUE	(SIZE, rect, min_y,	0.0)
	DEF_VALUE	(SIZE, rect, max_x,	0.0)
	DEF_VALUE	(SIZE, rect, max_y,	0.0)
  DEF_END()

  DEF_START(remove)
	DEF_SIZE(remove)
	DEF_LABEL("[DEPTH|LAYER]")
	DEF_VALUE	(UNKNOWN, remove, depth, -1.0)
	DEF_LABEL("ID|OBJ")
	DEF_REPEAT()
	DEF_OBJECT_REF	()
  DEF_END()

  DEF_START(sceneframedata)
	DEF_LABEL("[FILENAME|DATA]")
	DEF_STRING	()
  DEF_END()

  DEF_START(script_limits)
	DEF_SIZE(script_limits)
	DEF_LABEL("MAX_RECURSION_DEPTH|MAX|RECURSION|DEPTH")
	DEF_VALUE	(UNKNOWN, script_limits, max_recursion_depth, 0)
	DEF_LABEL("TIMEOUT_SECONDS|TIMEOUT|SECONDS")
	DEF_VALUE	(TIME, script_limits, timeout_seconds, 0)
  DEF_END()

  DEF_START(sequence)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(UNKNOWN)
  DEF_END()

  DEF_START(set_background_color)
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR)
	DEF_NOLABEL()
	DEF_SIZE(color)
	DEF_VALUE	(COLOR, color, red,   0.0)
	DEF_VALUE	(COLOR, color, green, 0.0)
	DEF_VALUE	(COLOR, color, blue,  0.0)
  DEF_END()

  DEF_START(set_tab_index)
	DEF_SIZE(set_tab_index)
	DEF_LABEL("DEPTH")
	DEF_VALUE	(UNKNOWN, set_tab_index, depth, 0)
	DEF_LABEL("TAB_INDEX")
	DEF_VALUE	(UNKNOWN, set_tab_index, index, 0)
  DEF_END()

  DEF_START(shape)
	DEF_LABEL("[MOVE|OFFSET]")
	DEF_REPEAT()
	DEF_SIZE(move)
	DEF_SET		(move, type, 3)
	DEF_VALUE	(SIZE, move, tx, 0.0)		/* we could use a MATRIX object for this? */
	DEF_VALUE	(SIZE, move, ty, 0.0)
	DEF_LABEL("MORPH|MODE|MORPH_MODE")
	DEF_REPEAT()
	DEF_SIZE(morph)
	DEF_SET		(morph, type, 5)
	DEF_VALUE	(UNKNOWN, morph, mode, 0.0)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(RECT)
	DEF_LABEL("SHOW_BOUNDS")
	DEF_SIZE(shape)
	DEF_SET		(shape, type, 2)
	DEF_VALUE	(BOOLEAN, shape, show, 0.0)
	DEF_LABEL("SHOW_ORIGIN")
	DEF_SIZE(shape)
	DEF_SET		(shape, type, 4)
	DEF_VALUE	(BOOLEAN, shape, show, 0.0)
	DEF_LABEL("FILL0")
	DEF_REPEAT()
	DEF_SIZE(fill_style)
	DEF_SET		(fill_style, select, 0)
	DEF_OBJECT	(FILL_STYLE)
	DEF_LABEL("FILL1")
	DEF_REPEAT()
	DEF_SIZE(fill_style)
	DEF_SET		(fill_style, select, 1)
	DEF_OBJECT	(FILL_STYLE)
	DEF_NOLABEL()					/* FILL0 when unspecified */
	DEF_REPEAT()
	DEF_OBJECT	(FILL_STYLE)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LINE_STYLE)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(EDGES)				/* turtle like points */
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(POINTS)			/* all points are zero based */
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LIST)
  DEF_END()

  DEF_START(show_frame)
	DEF_SIZE(show_frame)
	DEF_LABEL("[COUNT]")
	DEF_VALUE	(TIME, show_frame, wait, 1)
  DEF_END()

  DEF_START(sound)
	DEF_SIZE(sound)
	DEF_LABEL("[FILENAME]")
	DEF_SIZE(sound)
	DEF_SET		(sound, type, SOUND_TYPE_FILENAME)
	DEF_STRING	()
	DEF_LABEL("FORMAT")
	DEF_SIZE(sound)
	DEF_SET		(sound, type, SOUND_TYPE_FORMAT)
	DEF_STRING	()
	DEF_LABEL("MONO")
	DEF_VALUE	(BOOLEAN, sound, mono, 0.0)
	DEF_LABEL("SET_8_BITS")
	DEF_VALUE	(BOOLEAN, sound, set_8bits, 0.0)
  DEF_END()

  DEF_START(sound_info)
	DEF_SIZE(sound_info)
	DEF_LABEL("ID|OBJ")
	DEF_OBJECT_REF	()
	DEF_LABEL("STOP")
	DEF_VALUE	(BOOLEAN, sound_info, stop, 0.0)
	DEF_LABEL("NO_MULTIPLE")
	DEF_VALUE	(BOOLEAN, sound_info, no_multiple, 0.0)
	DEF_LABEL("RANGE")
	DEF_VALUE	(TIME, sound_info, start, 0.0)
	DEF_VALUE_OPT	(TIME, sound_info, end,   0.0)
	DEF_LABEL("LOOP")
	DEF_VALUE	(UNKNOWN, sound_info, loop, -1E+128)
	DEF_LABEL("[ENVELOPE|ENVELOP|ENVELLOPE|ENVELLOP|ENVELOPPE|ENVELOPP]")	// accept some wrong syntaces for people like me
	DEF_OBJECT	(ENVELOPE)
  DEF_END()

  DEF_START(sprite)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(DO_ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(PLACE_OBJECT)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(REPLACE_OBJECT)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(REMOVE)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(SHOW_FRAME)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(SOUND_INFO)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(FRAME_LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LIST)		/* accepts insertion of lists */
/* Elements still missing
        SoundStreamBlock
        SoundStreamHead
*/
  DEF_END()

  DEF_START(state)
	DEF_SIZE(button)
	DEF_LABEL("FLAGS")
	DEF_VALUE	(UNKNOWN, button, state, 0)
	DEF_LABEL("DEPTH|LAYER")
	DEF_VALUE	(UNKNOWN, button, layer, 0)
	DEF_LABEL("[MATRIX]")
	DEF_OBJECT	(MATRIX)
	DEF_LABEL("ID|OBJ")
	DEF_OBJECT_REF	()
  DEF_END()

  DEF_START(text)
	DEF_SIZE(text)
	DEF_LABEL("ALIASING|THICKNESS_SHARPNESS")
	DEF_VALUE	(SIZE, text, thickness,    -1E+128)
	DEF_VALUE	(SIZE, text, sharpness,    -1E+128)
	DEF_LABEL("RENDERER|FONT_ENGINE")
	DEF_VALUE	(SIZE, text, renderer,     -1E+128)
	DEF_LABEL("GRID|GRID_FIT")
	DEF_VALUE	(SIZE, text, grid_fit,     -1E+128)
	DEF_LABEL("[ADVANCE]")
	DEF_SIZE(text)
	DEF_REPEAT()
	DEF_SET		(text, type, TEXT_TYPE_ADVANCE)
	DEF_STRING	()
	DEF_VALUE_OPT	(SIZE, text, advance, -1E+128)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(TEXT_SETUP)
	DEF_NOLABEL()
	DEF_OBJECT	(MATRIX)
	DEF_NOLABEL()
	DEF_OBJECT	(RECT)
  DEF_END()

  DEF_START(text_setup)
  	DEF_SIZE(text_setup)
	DEF_NOLABEL()
	DEF_OBJECT	(COLOR)
	DEF_LABEL("ID")
	DEF_OBJECT_REF	()
	DEF_VALUE_OPT	(SIZE, text_setup, height, 1024.0 / 20.0)
	DEF_LABEL("[MOVE|OFFSET]")
	DEF_VALUE	(SIZE, text_setup, x,      0)
	DEF_VALUE_OPT	(SIZE, text_setup, y,      0)
  DEF_END()

  DEF_START(with)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(ACTION)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LABEL)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(WITH)
	DEF_NOLABEL()
	DEF_REPEAT()
	DEF_OBJECT	(LIST)
  DEF_END()







static int node_exec_nothing(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	/* copy the result pointer quickly (avoid duplicating the buffer for nothing!) */
	result->type = NODE_TYPE_DATA;
	result->sub_type = r->sub_type;
	assert(result->data == NULL, "result data pointer not NULL");
	result->data = r->data;
	r->data = NULL;

	return 0;
}







static struct def_label_t *node_def_find_label(struct def_object_t *defobj, const char *name)
{
	const char		*s, *d;
	int			skip, cnt;
	struct def_label_t	*label;

	label = defobj->labels;
	cnt = defobj->count;
	while(cnt > 0) {
		s = label->label;
		if(s != NULL) {
			d = name;
			skip = 0;
			while(*s != '\0') {
				/* make _ in the label optional in the user name */
				if(*s == '_' && *d != '_') {
					s++;
					continue;
				}
				/* mandatory label, just skip the [ and ] here */
				if(*s != '[' && *s != ']') {
					if(*s == '|') {
						if(*d == '\0') {
							/* we found a matching label! */
							return label;
						}
						/* just a label separator, check the next label if necessary */
						skip = 0;
						d = name;
					}
					else if(!skip) {
						if(toupper((unsigned char) *s) != toupper((unsigned char) *d)) {
							skip = 1;
						}
						else {
							d++;
						}
					}
				}
				s++;
			}
			if(*d == '\0') {
				/* we found a matching label! */
				return label;
			}
		}
		cnt--;
		label++;
	}

	fprintf(stderr, "ERROR: label \"%s\" not found for this object.\n", name);
	errcnt++;

	return NULL;
}



static struct def_label_t *node_def_print_entries(struct def_object_t *defobj, const char *indent)
{
	struct def_label_t	*label;
	struct def_entry_t	*entry;
	enum node_type_t	type;
	int			cnt, idx;

	label = defobj->labels;
	cnt = defobj->count;
	while(cnt > 0) {
		/* in this case we can't accept labelled entries */
		if(label->label != NULL) {
			fprintf(stderr, "%sLabel(s): %s\n", indent, label->label);
		}
		else {
			fprintf(stderr, "%sNo label:\n", indent);
		}
		entry = label->entries;
		idx = label->count;
		while(idx > 0) {
			type = entry->type;
			fprintf(stderr, "%s  Type: %s [%d]", indent,
					node_type_names[entry->type].name, entry->type);
			if(entry->sub_type != NODE_SUBTYPE_UNKNOWN) {
				fprintf(stderr, " (%s [%d])",
					node_type_names[entry->sub_type].name, entry->sub_type);
			}
			fprintf(stderr, "\n");
			entry++;
			idx--;
		}
		label++;
		cnt--;
	}

	return NULL;
}



static struct def_label_t *node_def_find_entry(struct def_object_t *defobj, struct node_t *result)
{
	struct def_label_t	*label;
	struct def_entry_t	*entry;
	struct node_t		*n;
	enum node_type_t	type;
	int			cnt, idx;

	label = defobj->labels;
	cnt = defobj->count;
	while(cnt > 0) {
		/* in this case we can't accept labelled entries */
		if(label->label == NULL || *label->label == '[') {
			entry = label->entries;
			idx = label->count;
			n = result;
			while(idx > 0 && n != NULL) {
				type = n->type;
				if(type == NODE_TYPE_INTEGER) {
					/* we keep all the values as floating points in these data structures */
					type = NODE_TYPE_FLOAT;
				}
				if(entry->type != type) {
					/* incorrect type... */
					break;
				}
				if(entry->sub_type != NODE_SUBTYPE_UNKNOWN) {
					type = n->sub_type;
					if(type == NODE_SUBTYPE_BLOCK) {
						/* blocks and lists are equivalent! */
						type = NODE_SUBTYPE_LIST;
					}
					if(entry->sub_type != type) {
						/* incorrect sub-type */
						break;
					}
				}
				n = n->next;
				entry++;
				idx--;
			}
			if(n == NULL) {
				if(idx > 0) {
					/* if the current entry is optional, it worked */
					if((entry->flags & DEF_ENTRY_FLAG_OPTIONAL) != 0) {
						idx = 0;
					}
				}
				if(idx == 0) {
					/* we got it! */
					return label;
				}
			}
		}
		label++;
		cnt--;
	}

	return NULL;
}






static void node_init_entry(struct def_entry_t *entry)
{
	entry->type     = NODE_TYPE_UNKNOWN;
	entry->sub_type = NODE_SUBTYPE_UNKNOWN;
	entry->unit     = NODE_UNIT_UNKNOWN;
}


static int node_def2entry(const struct definition_t *p, struct def_object_t *defobj)
{
	int			label_idx, entry_idx, state, first_unit;
	struct def_label_t	*label;
	struct def_entry_t	*entry;

#if _MSVC
	assert(sizeof(struct def_ignore_t) == sizeof(struct definition_t)
		&& sizeof(struct def_size_t) == sizeof(struct definition_t)
		&& sizeof(struct def_offset_t) == sizeof(struct definition_t)
		&& sizeof(struct def_set_t) == sizeof(struct definition_t)
		&& sizeof(struct def_def_value_t) == sizeof(struct definition_t)
		&& sizeof(struct def_type_t) == sizeof(struct definition_t)
		&& sizeof(struct def_unit_t) == sizeof(struct definition_t)
		&& sizeof(struct def_string_t) == sizeof(struct definition_t),
				"a sub-structure used to define the node entries has an invalid size");
	// we should also assert each offset!
	assert(offsetof(struct def_ignore_t, ignored) == offsetof(struct definition_t, data.ignored)
		&& offsetof(struct def_size_t, size) == offsetof(struct definition_t, data.size)
		&& offsetof(struct def_offset_t, offset) == offsetof(struct definition_t, data.offset)
		&& offsetof(struct def_set_t, set) == offsetof(struct definition_t, data.set),
				"a sub-structure used to define the node entries has data at an invalid offset");
#endif

	/* by default all zeroes! */
	memset(defobj, 0, sizeof(struct def_object_t));

	label = defobj->labels;
	entry = defobj->entries;

	first_unit = 1;
	state = 0;
	label_idx = -1;
	entry_idx = -1;
	for(;;) {
#if DEBUG
		switch(p->param) {
		case DEF_PARAM_END:
		case DEF_PARAM_NAME:
		case DEF_PARAM_LABEL:
		case DEF_PARAM_UNIT:
		case DEF_PARAM_SIZE:
		/*case DEF_PARAM_SEPARATOR:*/
		case DEF_PARAM_EMPTY:
			break;

		default:
			assert(state != 0, "a DEF_PARAM_TYPE found without a DEF_PARAM_LABEL");
			break;

		}
#endif
		switch(p->param) {
		case DEF_PARAM_END:
			return 0;

		/*
		case DEF_PARAM_SEPARATOR:
			defobj->flags |= DEF_OBJECT_FLAG_DEFINITION;
			break;
		*/

		case DEF_PARAM_NAME:
			defobj->name = p->data.string;
			break;

		case DEF_PARAM_LABEL:
			/* a new labelled entry */
			label_idx++;
			assert(label_idx < DEF_LABEL_MAX, "too many labels; please enlarge DEF_LABEL_MAX in node.c");
			defobj->count++;
			label[label_idx].label = p->data.string;
			/* no entry required first, we add 1 anyway */
			label[label_idx].entries = entry + entry_idx + 1;
			state = 1;
			break;

		case DEF_PARAM_TYPE:
			entry_idx++;
			// if we have a label, increment the counter
			if(label_idx >= 0) {
				label[label_idx].count++;
			}
			assert(entry_idx < DEF_ENTRY_MAX, "too many entries; please enlarge DEF_ENTRY_MAX in node.c");
			node_init_entry(entry + entry_idx);
			entry[entry_idx].type = p->data.type;
			state = 2;
			switch(p->data.type) {
			case NODE_TYPE_INTEGER:		/* this can't be used at this time... but for the sake of completeness we have it here */
			case NODE_TYPE_FLOAT:
				break;

			/* anything else requires us to have a list */
			case NODE_TYPE_OBJECT:		/* request for an object reference */
				assert(label_idx >= 0 && label[label_idx].label != NULL && strlen(label[label_idx].label) > 0,
							"cannot have an object reference without a label");
				entry[entry_idx].flags |= DEF_ENTRY_FLAG_REFERENCE;
				/*FALLTHROUGH*/
			default:
				defobj->flags |= DEF_OBJECT_FLAG_HAS_LIST;
				break;

			}
			break;

		case DEF_PARAM_SUBTYPE:
			assert(entry_idx >= 0, "cannot define a sub-type without first defining a type");
			entry[entry_idx].sub_type = p->data.type;
			break;

		case DEF_PARAM_UNIT:
			if(first_unit) {
				defobj->default_unit = p->data.unit;
				first_unit = 0;
			}
			assert(entry_idx >= 0, "cannot define a unit without first defining a type");
			entry[entry_idx].unit = p->data.unit;
			break;

		case DEF_PARAM_OFFSET:
			if(state == 1) {
				label[label_idx].offset = p->data.offset;
				label[label_idx].flags |= DEF_LABEL_FLAG_HAS_OFFSET;
			}
			else {
				assert(entry_idx >= 0, "cannot define an offset without first defining a label or a type");
				entry[entry_idx].offset = p->data.offset;
				entry[entry_idx].flags |= DEF_ENTRY_FLAG_HAS_OFFSET;
			}
			break;

		case DEF_PARAM_SIZE:
			if(state == 0) {
				defobj->size = p->data.size;
			}
			else {
				assert(label_idx >= 0, "cannot have a size without a label unless it appears first");
				label[label_idx].size = p->data.size;
			}
			break;

		case DEF_PARAM_SET:
			assert(label_idx >= 0, "cannot set a value without first having a label");
			label[label_idx].set = p->data.set;
			label[label_idx].flags |= DEF_LABEL_FLAG_HAS_SET;
			break;

		case DEF_PARAM_DEFAULT:
			assert(entry_idx >= 0, "cannot define a default value without first defining a type");
			entry[entry_idx].def_value = p->data.def_value;
			entry[entry_idx].flags |= DEF_ENTRY_FLAG_HAS_DEFAULT;
			break;

		case DEF_PARAM_REPEAT:
			if(state == 1) {
				/* the entry as a whole can be repeated */
				label[label_idx].flags |= DEF_LABEL_FLAG_REPEAT;
			}
			else {
				assert(entry_idx >= 0, "cannot define repeatition without first defining a label or a type");
				entry[entry_idx].flags |= DEF_ENTRY_FLAG_REPEAT;
			}
			break;

		case DEF_PARAM_OPTIONAL:
			assert(entry_idx >= 0, "cannot mark a type as optional without first defining said type");
			entry[entry_idx].flags |= DEF_ENTRY_FLAG_OPTIONAL;
			break;

		case DEF_PARAM_EMPTY:
			/* accept empty entry if this flag is set or
			 * defobj->count is zero
			 */
			defobj->flags |= DEF_OBJECT_FLAG_EMPTY;
			break;

		default:
			assert(0, "unsupported DEF_PARAM_... (%d)", p->param);
			/*NOTREACHED*/

		}
		p++;
	}
	/*NOTREACHED*/
}


static void node_label_defaults(const struct def_label_t *label, char *data)
{
	const struct def_entry_t	*entry;
	int				cnt;

	entry = label->entries;
	cnt = label->count;
	while(cnt > 0) {
		cnt--;
		/* if we have a default value and an offset we can save that! */
		if((entry->flags & (DEF_ENTRY_FLAG_HAS_OFFSET | DEF_ENTRY_FLAG_HAS_DEFAULT)) == (DEF_ENTRY_FLAG_HAS_OFFSET | DEF_ENTRY_FLAG_HAS_DEFAULT)) {
			* (double *) (data + entry->offset) = entry->def_value;
		}
		entry++;
	}
}


static struct data_common_t *node_alloc_data(int length, struct node_t *name, const char *nm, enum node_type_t type, struct node_t *node, const char *info)
{
	struct data_common_t	*data;
	int			l;

	if(nm == NULL && name != NULL && name->left != NULL) {
		nm = name->left->string;
	}

	if(nm == NULL || *nm == '\0') {
		l = 0;
	}
	else {
		l = strlen(nm);
		if(l > 0) {
			l = SSWF_MEM_ALIGN(l + 1);
		}
	}
	length += sizeof(struct data_common_t) + l;
	data = sswf_malloc(length, info);
	data->length = length;
	data->type = type;
	data->label = NULL;
	data->node = node;
	data->name_len = l;
	if(l > 0) {
		strcpy(data->name, nm);
	}

	return data;
}


static struct data_common_t *node_def_to_data(struct node_t *expr, const struct def_label_t *label, struct node_t *result, char *data)
{
	const struct def_entry_t	*entry;
	enum node_type_t		type;
	struct data_common_t		*buf;
	struct data_list_t		*list;
	struct node_t			*n;
	char				*dst, *str;
	struct data_common_t		**array, *quick_array[DEF_ENTRY_MAX + 1];
	int				idx, l, length, max, total_size;

	n = result;
	max = 1;
	while(n != NULL) {
		max++;
		n = n->next;
	}

	if(max > DEF_ENTRY_MAX + 1) {
		array = sswf_malloc(max * sizeof(struct data_common_t *), "node_def_to_data() - large array");
	}
	else {
		array = quick_array;
	}

	total_size = 0;

	if(label->size != 0) {
		/* got to allocate one buffer per label for this one! */
		data = sswf_malloc(label->size, "node_def_to_data() - label specific sub-buffer");
		memset(data, 0, label->size);
		node_label_defaults(label, data);
		total_size += SSWF_MEM_ALIGN(label->size);
		array[0] = (struct data_common_t *) data;
		idx = 1;
	}
	else {
		idx = 0;
	}

	if((label->flags & (DEF_LABEL_FLAG_HAS_SET | DEF_LABEL_FLAG_HAS_OFFSET)) == (DEF_LABEL_FLAG_HAS_SET | DEF_LABEL_FLAG_HAS_OFFSET)) {
		/* we have a value SET */
		assert(data != NULL, "DEF_PARAM_SET without a SIZE parameter");
		* (long *) (data + label->offset) = label->set;
	}

	entry = label->entries;
	while(result != NULL) {		/* we don't check the entry counter since that was already done */
		buf = NULL;
		switch(result->type) {
		case NODE_TYPE_OBJECT:
			if(result->sub_type != NODE_SUBTYPE_REFERENCE) {
				goto unknown;
			}
			type = result->sub_type;
			str = result->string;
			goto save_string;

		case NODE_TYPE_FLOAT:
			assert(data != NULL, "DEF_PARAM_VALUE without a SIZE parameter");
			* (double *) (data + entry->offset) = result->floating_point;
			break;

		case NODE_TYPE_INTEGER:
			assert(data != NULL, "DEF_PARAM_VALUE without a SIZE parameter");
			* (double *) (data + entry->offset) = (double) result->integer;
			break;

		case NODE_TYPE_STRING:
			type = NODE_TYPE_STRING;
			str = result->string;
save_string:
			/* save this data in the result so it gets freed once
			 * the result node is being cleaned up */
			assert(result->data == NULL, "result->data isn't null here -- memory leak");
			result->data = node_alloc_data(0, NULL, str, type, expr, "node_def_to_data() - sub-buffer for a string");
			sswf_clean(&result->string);
			result->type = NODE_TYPE_DATA;
			result->sub_type = type;
			/*FALLTHROUGH*/
		case NODE_TYPE_DATA:
			assert(result->data != NULL, "a DATA node without data was found");
			array[idx] = result->data;
			idx++;
			total_size += result->data->length;
			assert(total_size == (int) SSWF_MEM_ALIGN(total_size), "node_def_to_data(): invalid total_size alignment - a result->data->length has an invalid size (label: \"%s\")", result->data->name_len > 0 ? result->data->name : "<no name>");
			break;

		default:
unknown:
			assert(0, "unrecognized type in result for object definition");
			/*NOTREACHED*/

		}
		entry++;
		result = result->next;
	}

	/* it all worked, now we can merge all the buffers in the resulting array */
	if(total_size > 0 || data == NULL) {
		length =
			/* header included in node_alloc_data() (no name) */
			  /*sizeof(struct data_common_t)*/
			/* list header + offsets */
			  SSWF_MEM_ALIGN(sizeof(struct data_list_t) + idx * sizeof(long))
			/* the contents of the list */
			+ total_size;
		buf = node_alloc_data(length, NULL, NULL, NODE_SUBTYPE_DEFINITION, expr, "node_def_to_data() -- list of sub-buffers");
		list = (struct data_list_t *) (buf + 1);	/* == dc_list(buf) */
		list->count = idx;
		dst = (char *) list + SSWF_MEM_ALIGN(sizeof(struct data_list_t) + idx * sizeof(long));

#if 0
printf("  We are creating a sub_data here! (total_size = %d, list->count = %d) %p -> %p\n", total_size, idx,
				array[0], buf);
#endif

		if(label->size != 0) {
			/* the first entry is the label specific data when there is one */
			/* WARNING: negative offset to specify that this entry doesn't have a data_commont_t structure */
			list->offset[0] = (char *) list - dst;
			memcpy(dst, data, label->size);
			sswf_free(data);
			dst += SSWF_MEM_ALIGN(label->size);
			l = 1;
		}
		else {
			l = 0;
		}
		while(l < idx) {
			length = array[l]->length;
			list->offset[l] = dst - (char *) list;
			memcpy(dst, array[l], length);
			dst += length;
			l++;
		}
	}
	else {
		buf = NULL;
	}

	if(array != quick_array) {
		sswf_free(array);
	}

	return buf;
}


/* WARNING: this function frees the sub_data buffer as required */
static struct data_common_t *node_def_merge_data(struct node_t *expr, const struct def_object_t *defobj, struct data_common_t *data, struct data_common_t *sub_data)
{
	struct data_list_t	*src_list, *dst_list;
	struct node_t		*name;
	int			idx, l, l1, l2, length, length1, length2;
	char			*src, *dst, *ptr;

	if(sub_data == NULL) {
		return data;
	}

	/*
	 * NOTE: the sub_data is ALWAYS a NODE_SUBTYPE_DEFINITION so the following works
	 *	 don't call this function otherwise!
	 */
	assert(sub_data->type == NODE_SUBTYPE_DEFINITION, "invalid sub_data type; not a NODE_SUBTYPE_DEFINITION");

	if(data == NULL) {
		/*
		 * No data yet, just return the sub_data with the NODE_SUBTYPE_DEFINITION header
		 * transform in this object entry
		 */
		name = expr->left;
		if(name != NULL) {
			l = strlen(name->string);
			if(l > 0) {
#if 0
fflush(stdout);
fprintf(stderr, "    Merge adding name [%s] to sub_data.\n", name->string);
#endif
				/* we have to add the name! */
				l = SSWF_MEM_ALIGN(l + 1);
				sub_data->name_len = l;
				length = sub_data->length + l;
				sub_data = sswf_remalloc(sub_data, length, "node_def_merge_data() -- name the data buffer");
				memmove((char *) (sub_data + 1) + l, sub_data + 1, sub_data->length - sizeof(struct data_common_t));
				strcpy(sub_data->name, name->string);
				sub_data->length = length;
			}
		}
		sub_data->type = expr->sub_type;
		data = sub_data;
	}
	else {
		/* ha! there is an existing entry, we have to append each sub_data entries in it */
		src_list = dc_list(sub_data);
		dst_list = dc_list(data);
		l1 = src_list->count * sizeof(long);
		l2 = dst_list->count * sizeof(long);
		src = (char *) src_list + SSWF_MEM_ALIGN(l1 + sizeof(struct data_list_t));
								// src point to the 1st entry in the sub_data list
		dst = (char *) dst_list + SSWF_MEM_ALIGN(l2 + sizeof(struct data_list_t));
								// dst points to the 1st entry in the data list
		length1 = sub_data->length - (src - (char *) sub_data);
		length2 = data->length     - (dst - (char *) data);

		assert(length1 == (int) SSWF_MEM_ALIGN(length1), "node_def_merge_data(): length of sub_data not properly aligned");
		assert(length2 == (int) SSWF_MEM_ALIGN(length2), "node_def_merge_data(): length of data not properly aligned");

		/*
		 * The new length is the length of the data & sub_data contents and 
		 * a new list we have to properly align plus the usual common and
		 * list headers.
		 */
		length =
			/* common header + name */
			   sizeof(struct data_common_t)
			 + data->name_len
			/* list header + space for offsets */
			 + SSWF_MEM_ALIGN(sizeof(struct data_list_t) + l1 + l2)
			/* size of the data of both lists */
			 + length1 + length2;

		/*length = data->length + sub_data->length - ((char *) (src_list + 1) - (char *) sub_data);*/

		data = sswf_remalloc(data, length, "node_def_merge_data() -- append sub_data to data buffer");
		data->length = length;

		/*
		 * the dst_list pointer certainly changed with the remalloc() -- we need to fix
		 * all the pointers depending on data (the sizes are still valid!)
		 */
		dst_list = dc_list(data);
		dst = (char *) dst_list + SSWF_MEM_ALIGN(l2 + sizeof(struct data_list_t));


		/* move the existing data and adjust their offsets */
		ptr = (char *) dst_list + SSWF_MEM_ALIGN(l1 + l2 + sizeof(struct data_list_t));
		memmove(ptr, dst, length2);

		l = ptr - dst;
		idx = dst_list->count;
		while(idx > 0) {
			idx--;
			if(dst_list->offset[idx] < 0) {
				dst_list->offset[idx] -= l;
			}
			else {
				dst_list->offset[idx] += l;
			}
		}

		/* copy the sub_data offsets */
		memcpy(dst_list->offset + dst_list->count, src_list->offset, l1);

		/* compute the position where the sub_data contents needs to be copied, copy it & save the new length of data */
		ptr += length2;
		memcpy(ptr, src, length1);

		/* adjust the copied sub_data offsets */
		l = (ptr - (char *) dst_list) - labs(src_list->offset[0]);
		l2 = dst_list->count;
		idx = l2 + src_list->count;
		while(idx > l2) {
			idx--;
			if(dst_list->offset[idx] < 0) {
				dst_list->offset[idx] -= l;
			}
			else {
				dst_list->offset[idx] += l;
			}
		}
		dst_list->count += src_list->count;	/* now that's inserted! */

		/* we're done with sub_data, get rid of it */
		sswf_free(sub_data);
	}

	assert(data->node == expr, "node_def_merge_data() -- node != expr");

	return data;
}



static struct data_common_t *node_def_data(struct node_t *expr, char *obj_struct, size_t size)
{
	struct data_common_t	*data;

	data = node_alloc_data(SSWF_MEM_ALIGN(size), expr, NULL, expr->sub_type, expr, "node_def_data() -- simple object data");
	if(size > 0) {
		memcpy((char *) (data + 1) + data->name_len, obj_struct, size);
	}

	return data;
}


static struct data_common_t *node_def_insertdata(struct node_t *expr, struct data_common_t *data, char *obj_struct, size_t size)
{
	struct data_list_t	*list;
	char			*d, *p;
	int			l, ld, length;

	/* in this case the data is the very first entry in the data list */
	if(data == NULL) {
		/* no data yet, create the whole thing at once */
		length = SSWF_MEM_ALIGN(sizeof(struct data_list_t) + sizeof(long)) + SSWF_MEM_ALIGN(size);
		data = node_alloc_data(length, expr, NULL, expr->sub_type, expr, "node_def_insertdata() -- new data buffer");
		list = dc_list(data);
		d = (char *) list + SSWF_MEM_ALIGN(sizeof(struct data_list_t) + sizeof(long));
		list->count = 1;
		list->offset[0] = (char *) list - d;	/* a negative result! */
		memcpy(d, obj_struct, size);
	}
	else {
		/* in this case we have to actually insert the data within the existing list */
		list = dc_list(data);
		l = (list->count + 1) * sizeof(long);
		ld = (((char *) data + data->length) - ((char *) list + labs(list->offset[0])));
		assert(ld == (int) SSWF_MEM_ALIGN(ld), "node_def_insertdata(): length of sub_data not properly aligned");
		length =
			/* common header + name */
			  sizeof(struct data_common_t)
			+ data->name_len
			/* the list including the new item */
			+ SSWF_MEM_ALIGN(sizeof(struct data_list_t) + l)
			/* the old data */
			+ ld
			/* the new data */
			+ SSWF_MEM_ALIGN(size);

		data = sswf_remalloc(data, length, "node_def_insertdata() -- insert data buffer");
		data->length = length;

		/* the remalloc() most probably changed the data pointer */
		list = dc_list(data);

		/* move the old data to make room for the new one
		 * copy the new data
		 * move the old offsets
		 * compute the new offset
		 */
		d = (char *) list + SSWF_MEM_ALIGN(sizeof(struct data_list_t) + l);
		p = (char *) list + SSWF_MEM_ALIGN(sizeof(struct data_list_t) + l - sizeof(long));
		memmove(d + SSWF_MEM_ALIGN(size), p, ld);
		memcpy(d, obj_struct, size);
		memmove(list->offset + 1, list->offset, sizeof(long) * list->count);
		list->offset[0] = (char *) list - d;		/* a negative result! */

		/* adjust the "old" offsets now */
		ld = (d + SSWF_MEM_ALIGN(size)) - (char *) list - labs(list->offset[1]);
		l = list->count;
		while(l > 0) {
			if(list->offset[l] < 0) {
				list->offset[l] -= ld;
			}
			else {
				list->offset[l] += ld;
			}
			l--;
		}
		list->count++;
	}

	return data;
}


static struct data_common_t *node_def_empty(struct node_t *expr)
{
	return node_alloc_data(0, expr, NULL, expr->sub_type, expr, "node_def_empty() -- empty entry");
}



void node_print_data0(const struct data_common_t *data, int indent)
{
	struct data_type_t {
		enum node_type_t	type;
		const char *		name;
		int			flags;
	};

#define	DATA_TYPE_MASK_DATA		0x000000FF
	enum data_type_struct_t {
		DATA_TYPE_STRUCT_UNKNOWN = 0,
		DATA_TYPE_STRUCT_COLOR,
		DATA_TYPE_STRUCT_COLOR_TRANSFORM,
		DATA_TYPE_STRUCT_EDGES,
		DATA_TYPE_STRUCT_EDIT_TEXT,
		DATA_TYPE_STRUCT_EMPTY,
		DATA_TYPE_STRUCT_FONT,
		DATA_TYPE_STRUCT_GRADIENT,
		DATA_TYPE_STRUCT_IMAGE,
		DATA_TYPE_STRUCT_LINE_STYLE,
		DATA_TYPE_STRUCT_MATRIX,
		DATA_TYPE_STRUCT_ACTION_SCRIPT,
		DATA_TYPE_STRUCT_PLACE_OBJECT,
		DATA_TYPE_STRUCT_POINTS,
		DATA_TYPE_STRUCT_RECT,
		DATA_TYPE_STRUCT_SHAPE_MOVE,
		DATA_TYPE_STRUCT_SHOW_FRAME,
		DATA_TYPE_STRUCT_STATE,
		DATA_TYPE_STRUCT_TEXT,
		DATA_TYPE_STRUCT_TEXT_SETUP,

		DATA_TYPE_STRUCT_max
	};

#define	DATA_TYPE_FLAG_LIST		0x00000100
#define	DATA_TYPE_FLAG_STRING		0x00000200

	static const struct data_type_t		data_names[] = {
		{
			NODE_TYPE_STRING,		/* a special case - the "name" is the actual string */
			"string",
			DATA_TYPE_FLAG_STRING
		},
		{
			NODE_SUBTYPE_ACTION,
			"action",
			0
		},
		{
			NODE_SUBTYPE_ACTION_SCRIPT,
			"action_script",
			DATA_TYPE_STRUCT_ACTION_SCRIPT
		},
		{
			NODE_SUBTYPE_BLOCK,
			"block",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_BUTTON,
			"button",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_CATCH,
			"catch",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_COLOR,
			"color",
			DATA_TYPE_STRUCT_COLOR
		},
		{
			NODE_SUBTYPE_COLOR_TRANSFORM,
			"color transform",
			DATA_TYPE_STRUCT_COLOR_TRANSFORM
		},
		{
			NODE_SUBTYPE_DO_ACTION,
			"do action",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_EDGES,
			"edges",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_EDGES
		},
		{
			NODE_SUBTYPE_EDIT_TEXT,
			"edit text",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_EDIT_TEXT
		},
		{
			NODE_SUBTYPE_FILL_STYLE,
			"fill style",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_FINALLY,
			"finally",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_FONT,
			"font",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_FONT
		},
		{
			NODE_SUBTYPE_FUNCTION,
			"function",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_GRADIENT,
			"gradient",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_GRADIENT
		},
		{
			NODE_SUBTYPE_IMAGE,
			"image",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_IMAGE
		},
		{
			NODE_SUBTYPE_LINE_STYLE,
			"line style",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_LINE_STYLE
		},
		{
			NODE_SUBTYPE_LIST,
			"list",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_MATRIX,
			"matrix",
			DATA_TYPE_STRUCT_MATRIX
		},
		{
			NODE_SUBTYPE_PLACE_OBJECT,
			"place object",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_PLACE_OBJECT
		},
		{
			NODE_SUBTYPE_POINTS,
			"points",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_POINTS
		},
		{
			NODE_SUBTYPE_RECT,
			"rect",
			DATA_TYPE_STRUCT_RECT
		},
		{
			NODE_SUBTYPE_REFERENCE,
			"reference",
			DATA_TYPE_FLAG_STRING
		},
		{
			NODE_SUBTYPE_REMOVE,
			"remove",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_REPLACE_OBJECT,
			"replace object",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_PLACE_OBJECT
		},
		{
			NODE_SUBTYPE_SCRIPT_LIMITS,
			"script limits",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_SEQUENCE,
			"sequence",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_SET_BACKGROUND_COLOR,
			"set background color",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_COLOR
		},
		{
			NODE_SUBTYPE_SET_TAB_INDEX,
			"set tab index",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_SHAPE,
			"shape",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_SHAPE_MOVE
		},
		{
			NODE_SUBTYPE_SHOW_FRAME,
			"show frame",
			DATA_TYPE_STRUCT_SHOW_FRAME
		},
		{
			NODE_SUBTYPE_SPRITE,
			"sprite",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_STATE,
			"state",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_STATE
		},
		{
			NODE_SUBTYPE_TEXT,
			"text",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_TEXT
		},
		{
			NODE_SUBTYPE_TEXT_SETUP,
			"text setup",
			DATA_TYPE_FLAG_LIST | DATA_TYPE_STRUCT_TEXT_SETUP
		},
		{
			NODE_SUBTYPE_TRY,
			"throw",
			DATA_TYPE_FLAG_LIST
		},
		{
			NODE_SUBTYPE_WITH,
			"with",
			DATA_TYPE_FLAG_LIST
		},

		/* the following should probably not appear? */
		{
			NODE_SUBTYPE_REMOVE_ALL,
			"??? remove all ???",
			0
		},
		{
			NODE_SUBTYPE_DEFINITION,
			"??? definition ???",
			0
		},

		/* if we reach the following, we don't know what we are dealing with! */
		{
			NODE_SUBTYPE_UNKNOWN,
			"UNKNOWN",
			0
		}
	};
	char				spaces[256];
	const char			*d, *sub_data;
	const struct data_type_t	*dt;
	const struct data_list_t	*list;
	int				idx;

	/* search the info about this type */
	dt = data_names;
	do {
		if(dt->type == data->type) {
			break;
		}
		dt++;
	} while(dt->type != NODE_SUBTYPE_UNKNOWN);

	memset(spaces, ' ', indent);
	spaces[indent] = '\0';

#if 0
	printf("%sBuffer raw data:\n", spaces);
	for(idx = 0; idx < data->length; ++idx) {
		if((idx & 15) == 0) {
			if(idx != 0) {
				printf("\n");
			}
			printf("%p- ", (unsigned char *) data + idx + 1);
		}
		unsigned char c = ((unsigned char *) data)[idx];
		printf("%02X %c ", c, c >= ' ' && c < 0x7F ? c : '.');
	}
	if((idx & 15) != 0) {
		printf("\n");
	}
#endif

	printf("%sPointer: %p\n", spaces, data);
	printf("%sLength: %d bytes (%.02gKb, %.02gMb)\n", spaces, (int) data->length, (double) data->length / 1024.0, (double) data->length / (1024.0 * 1024.0));
	printf("%sType: %d (%s)\n", spaces, data->type, dt->name);
	if(data->name_len > 0) {
		printf("%s%s: \"%s\"\n", spaces,
			(dt->flags & DATA_TYPE_FLAG_STRING) != 0 ? "String" : "Name", data->name);
	}

	d = (const char *) (data + 1) + data->name_len;
	if((dt->flags & DATA_TYPE_FLAG_LIST) != 0) {
		/* when we have a list the data is incorporated in that list */
		if(data->length - data->name_len == sizeof(struct data_common_t)) {
			/* ha! no list! this is an empty item... */
			return;
		}
		list = (const struct data_list_t *) d;
		printf("%sList of %d item%s.\n", spaces, (int) list->count, list->count > 1 ? "s" : "");
		for(idx = 0; idx < (int) list->count; idx++) {
			printf("%s  ----- offset = %ld\n", spaces, list->offset[idx]);
			sub_data = d + labs(list->offset[idx]);
			if(list->offset[idx] < 0) {
				printf("%s  Direct structure: %p (Type: %d)\n", spaces, sub_data, dt->flags & DATA_TYPE_MASK_DATA);
				switch(dt->flags & DATA_TYPE_MASK_DATA) {
				case DATA_TYPE_STRUCT_UNKNOWN:
					/* this shouldn't happen... */
					break;

				case DATA_TYPE_STRUCT_COLOR:
					printf("%s    Color: %g, %g, %g, %g\n", spaces, ((double *) sub_data)[0], ((double *) sub_data)[1], ((double *) sub_data)[2], ((double *) sub_data)[3]);
					break;

				case DATA_TYPE_STRUCT_EDGES:
				{
					struct data_edges_t *e;

					e = (struct data_edges_t *) sub_data;
					if(e->type == EDGE_TYPE_CLOSE) {
						printf("%s    Closure curve - end point forced equal to start point\n", spaces);
					}
					if(e->delta_x2 != -1E+128) {
						printf("%s    Curve Deltas: (%g, %g)-(%g, %g)\n", spaces,
								e->delta_x1, e->delta_y1, e->delta_x2, e->delta_y2);
					}
					else {
						printf("%s    Line Deltas: (%g, %g)\n", spaces,
										e->delta_x1, e->delta_y1);
					}
				}
					break;

				case DATA_TYPE_STRUCT_EDIT_TEXT:
				{
					struct data_edit_text_t *e;
					int			comma;

					e = (struct data_edit_text_t *) sub_data;
					switch(e->type) {
					case EDIT_TEXT_TYPE_LAYOUT:
						printf("%s    Margin: %g, %g\n", spaces, e->margin_left, e->margin_right);
						printf("%s    Indent: %g, leading: %g\n", spaces, e->indent, e->leading);
						printf("%s    Maximum Length: %g\n", spaces, e->max_length);
						/* flags: */
						printf("%s    ", spaces);
						comma = 0;
						if(e->word_wrap != 0.0) {
							printf("WORD WRAP");
							comma = 1;
						}
						if(e->multiline != 0.0) {
							printf("%sMULTILINE", comma ? ", " : "");
							comma = 1;
						}
						if(e->password != 0.0) {
							printf("%sPASSWORD", comma ? ", " : "");
							comma = 1;
						}
						if(e->readonly != 0.0) {
							printf("%sREADONLY", comma ? ", " : "");
							comma = 1;
						}
						if(e->no_select != 0.0) {
							printf("%sNO_SELECT", comma ? ", " : "");
							comma = 1;
						}
						if(e->border != 0.0) {
							printf("%sBORDER", comma ? ", " : "");
							comma = 1;
						}
						if(e->outline != 0.0) {
							printf("%sOUTLINE", comma ? ", " : "");
							comma = 1;
						}
						if(e->html != 0.0) {
							printf("%sHTML", comma ? ", " : "");
							comma = 1;
						}
						if(e->auto_size != 0.0) {
							printf("%sAUTO-SIZE", comma ? ", " : "");
							comma = 1;
						}
						printf("\n");
						break;

					case EDIT_TEXT_TYPE_VARIABLE:
						printf("%s    The next strings represent the variable name and the optional initial text\n", spaces);
						break;

					case EDIT_TEXT_TYPE_ALIGNMENT:
						printf("%s    The next string represents the justification\n", spaces);
						break;

					case EDIT_TEXT_TYPE_INITIAL_TEXT:
						printf("%s    The next string represents the initial text\n", spaces);
						break;

					}
				}
					break;

				case DATA_TYPE_STRUCT_EMPTY:
					/* mainly show frame at this time */
					break;

				case DATA_TYPE_STRUCT_FONT:
					/* all the font structures have a type */
					switch(* (long *) sub_data) {
					case FONT_TYPE_LAYOUT:
					{
						const struct data_font_t	*f;

						f = (const struct data_font_t *) sub_data;
						printf("%s    Font: ascent: %g, descent: %g, leading height: %g, advance: %g\n", spaces,
							/* TODO: add tests about the -1E+128 - use default */
							f->ascent,
							f->descent,
							f->leading_height,
							f->advance);
					}
						break;

					case FONT_TYPE_ADVANCE:
					{
						const struct data_font_advance_t	*a;

						a = (const struct data_font_advance_t *) sub_data;
						if(a->x != -1E+128) {
							printf("%s    Character advance: %g\n", spaces, a->x);
						}
						else {
							printf("%s    Use default Character advance.\n", spaces);
						}
					}
						break;

					case FONT_TYPE_KERNING:
					{
						const struct data_font_kerning_t	*k;

						k = (const struct data_font_kerning_t *) sub_data;
						printf("%s    Kerning advance: %g\n", spaces, k->x);
					}
						break;

					case FONT_TYPE_NAME:
						printf("%s    The following string is the font name.\n", spaces);
						break;

					default:
						printf("%s    Unknown font type (%ld)\n", spaces, * (long *) sub_data);
						break;

					}
					break;

				case DATA_TYPE_STRUCT_GRADIENT:
					if(((double *) sub_data)[1] == -1E+128) {
						printf("%s    Gradient at: %g\n", spaces, ((double *) sub_data)[0]);
					}
					else {
						printf("%s    Morph Gradient at: %g to: %g\n", spaces, ((double *) sub_data)[0], ((double *) sub_data)[1]);
					}
					break;

				case DATA_TYPE_STRUCT_IMAGE:
					printf("%s    Format: %s.\n", spaces, ((long *) sub_data)[0] == IMAGE_FORMAT_LOSSLESS ? "Lossless" : "JPEG");
					break;

				case DATA_TYPE_STRUCT_LINE_STYLE:
					printf("%s    Width: %g\n", spaces, ((double *) sub_data)[0]);
					printf("%s    To width: %g\n", spaces, ((double *) sub_data)[1]);
					break;

				case DATA_TYPE_STRUCT_PLACE_OBJECT:
					printf("%s    Position: %g\n", spaces, ((double *) sub_data)[0]);
					printf("%s    Depth: %g\n", spaces, ((double *) sub_data)[1]);
					break;

				case DATA_TYPE_STRUCT_POINTS:
				{
					struct data_points_t *p;

					p = (struct data_points_t *) sub_data;
					if(p->type == EDGE_TYPE_CLOSE) {
						printf("%s    Closure point - end point forced equal to start point\n", spaces);
					}
					if(p->x2 != -1E+128) {
						printf("%s    Curve Points: (%g, %g)-(%g, %g)\n", spaces,
								p->x1, p->y1, p->x2, p->y2);
					}
					else {
						printf("%s    Line Points: (%g, %g)\n", spaces, p->x1, p->y1);
					}
				}
					break;

				case DATA_TYPE_STRUCT_SHAPE_MOVE:
					if(idx + 1 < (int) list->count && labs(list->offset[idx + 1]) - labs(list->offset[idx]) == sizeof(long)) {
						printf("%s    Select Fill: %ld\n", spaces, ((long *) sub_data)[0]);
					}
					else {
						printf("%s    Move: +(%g, %g)\n", spaces, ((double *) sub_data)[0], ((double *) sub_data)[1]);
					}
					break;

				case DATA_TYPE_STRUCT_STATE:
					printf("%s    State: %lX\n", spaces, (long) ((double *) sub_data)[0]);
					printf("%s    Layer: %g\n", spaces, ((double *) sub_data)[1]);
					break;

				case DATA_TYPE_STRUCT_TEXT:
				{
					struct data_text_t	*t;

					t = (struct data_text_t *) sub_data;
					switch(t->type) {
					case TEXT_TYPE_ADVANCE:
						if(t->advance == -1E+128) {
							printf("%s    No specific advance.\n", spaces);
						}
						else {
							printf("%s    Specific advance: %g\n", spaces, t->advance);
						}
						break;

					case TEXT_TYPE_INFO:
						if(t->thickness == -1E+128) {
							printf("%s    No specific thickness.\n", spaces);
						}
						else {
							printf("%s    Thickness: %g\n", spaces, t->thickness);
						}
						if(t->sharpness == -1E+128) {
							printf("%s    No specific sharpness.\n", spaces);
						}
						else {
							printf("%s    Sharpness: %g\n", spaces, t->sharpness);
						}
						if(t->renderer == -1E+128) {
							printf("%s    No specific renderer.\n", spaces);
						}
						else {
							printf("%s    Renderer: %d\n", spaces, (int)t->renderer);
						}
						if(t->grid_fit == -1E+128) {
							printf("%s    No grid fit.\n", spaces);
						}
						else {
							printf("%s    Grid fit: %d\n", spaces, (int)t->grid_fit);
						}
						break;

					}
				}
					break;

				case DATA_TYPE_STRUCT_TEXT_SETUP:
					printf("%s    Offset: (%g, %g)\n", spaces, ((double *) sub_data)[0], ((double *) sub_data)[1]);
					printf("%s    Height: %g\n", spaces, ((double *) sub_data)[2]);
					break;

				default:
					assert(0, "don't know the DATA_TYPE_STRUCT_... type #%d (sub-item)", dt->flags & DATA_TYPE_MASK_DATA);
					/*NOTREACHED*/

				}
			}
			else {
				node_print_data0((const struct data_common_t *) sub_data, indent + 2);
			}
		}
	}
	else {
		/* when we don't have a list, the data follows the header as is */
		switch(dt->flags & DATA_TYPE_MASK_DATA) {
		case DATA_TYPE_STRUCT_UNKNOWN:
			/* this is a valid value for empty objects */
			break;

		case DATA_TYPE_STRUCT_COLOR:
			printf("%sColor: %g, %g, %g, %g\n", spaces, ((double *) d)[0], ((double *) d)[1], ((double *) d)[2], ((double *) d)[3]);
			break;

		case DATA_TYPE_STRUCT_COLOR_TRANSFORM:
			printf("%sColor Transform: x (%g, %g, %g, %g) + (%g, %g, %g, %g)\n", spaces,
				((double *) d)[4], ((double *) d)[5], ((double *) d)[6], ((double *) d)[7],
				((double *) d)[0], ((double *) d)[1], ((double *) d)[2], ((double *) d)[3]);
			break;

		case DATA_TYPE_STRUCT_EMPTY:
			break;

		case DATA_TYPE_STRUCT_MATRIX:
			if(((double *) d)[1] == -1E+128) {
				printf("%sScale: %g, %g\n", spaces, ((double *) d)[0], ((double *) d)[0]);
			}
			else {
				printf("%sScale: %g, %g\n", spaces, ((double *) d)[0], ((double *) d)[1]);
			}
			printf("%sRotate: %g (%g degres)\n", spaces, ((double *) d)[4], ((double *) d)[4] * 180.0 / M_PI);
			printf("%sTranslate: %g, %g\n", spaces, ((double *) d)[2], ((double *) d)[3]);
			break;

		case DATA_TYPE_STRUCT_RECT:
			printf("%sRectangle: (%g, %g) - (%g, %g)\n", spaces, ((double *) d)[0], ((double *) d)[1], ((double *) d)[2], ((double *) d)[3]);
			break;

		case DATA_TYPE_STRUCT_SHOW_FRAME:
			printf("%sWait: %g frames\n", spaces, ((double *) d)[0]);
			break;

		case DATA_TYPE_STRUCT_ACTION_SCRIPT:
			printf("%sActioscript:\n", spaces);
			//((as::NodePtr *) d)->Display(stdout);
			break;

		default:
			assert(0, "don't know the DATA_TYPE_STRUCT_... type #%d (direct)", dt->flags & DATA_TYPE_MASK_DATA);
			/*NOTREACHED*/

		}
	}
}


void node_print_data(const struct data_common_t *data)
{
	printf("*******************************************\n");
	if(data == NULL) {
		printf("NO DATA!\n");
	}
	else {
		node_print_data0(data, 0);
	}
	printf("*******************************************\n");
}


static int node_definitions(struct node_t *expr, const struct definition_t *params, struct node_t *definitions, struct node_exec_status_t *parent)
{
	const struct def_label_t	*label;
	const struct def_entry_t	*entry;
	struct node_exec_status_t	status;
	struct node_t			*def, *head, *d, *e;
	enum node_type_t		type;
	struct data_common_t		*data, *sub_data;
	int				ec, bad, cnt;
	struct def_object_t		defobj;
	char				*obj_struct, *path;

	node_init(definitions, NODE_TYPE_DATA, expr->sub_type);

	/* transform the compressed parameters in a set of entries */
#if 0
printf(">>> Create entries for object 0x%08lX: [%s] (%d/%d) [right = %p]...\n",
		(unsigned long) expr,
		expr->left != NULL ? expr->left->string : "<no name>",
		expr->type, expr->sub_type, expr->right);
fflush(stdout);
#endif

	ec = node_def2entry(params, &defobj);
	if(ec != 0) {
		return ec;		/* there are only assert()'s at this time anyway... */
	}

	if(defobj.size != 0) {
		/* got to allocate a structure for this object */
		obj_struct = sswf_malloc(defobj.size, "node_definitions() -- object specific sub-buffer");
		memset(obj_struct, 0, defobj.size);

#if 0
printf("Object [%s] has a struct of %d bytes\n", expr->left != NULL ? expr->left->string : "<no name>", defobj.size);
#endif

		/* whenever this happens we have to set the defaults so parse all the structures for them */
		label = defobj.labels;
		cnt = defobj.count;
		while(cnt > 0) {
			cnt--;
			if(label->size == 0) {
				node_label_defaults(label, obj_struct);
			}
			label++;
		}
	}
	else {
		obj_struct = NULL;
	}

	data = NULL;

	/*
	 * We have a list of definitions which include a list of expressions
	 *
	 * definition: { [ <name> ':' ] group_expr }
	 */
	bad = 0;
	def = expr->right;
	while(def != NULL) {
		e = def->right;
		/* if e == NULL then the parser balently failed!?!? */
		assert(e != NULL, "no definition within a definition list");

		/* skip variables since we can't execute them */
		if(e->type == NODE_TYPE_OBJECT && e->sub_type == NODE_SUBTYPE_VARIABLE) {
			def = def->next;
			continue;
		}

		/* reset the status each time (should it be a copy of the status when coming in?) */
		memset(&status, 0, sizeof(status));
		status.parent = parent;
		status.obj = expr;
		head = NULL;
#if 0
printf("A label? [%s] (e = %p - %d/%d)\n", def->left == NULL ? "<no label>" : def->left->string, e, e->type, e->sub_type);
#endif
		if(def->left == NULL) {
			/* no label, use the default UNIT mode and compute the list of expressions */
			do {
				/* make sure the status is proper on entry */
				status.unit = defobj.default_unit;
				status.ref = 0;
				lex_filename = e->filename;
				d = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, e->line);
				ec = node_execute(e, d, &status);
#if 0
printf("  Executed %d/%d -> %d/%d (object: %s - %d/%d)\n", e->type, e->sub_type, d->type, d->sub_type,
					expr->left != NULL ? expr->left->string : "<no name>",
					expr->type, expr->sub_type);
fflush(stdout);
#endif
				if(ec != 0) {
					bad = 1;
				}
				if(d->type == NODE_TYPE_UNKNOWN) {
					/* This happens when there is an IF() without an ELSE.
					 * Obviously the validity will depend on the object within
					 * which the IF() is included. Most of the time we will
					 * expect IF()'s within lists, however, if there is an
					 * ELSE statement they can be used virtually anywhere.
					 */
					node_free(d);
				}
				else {
					if(head == NULL) {
						head = d;
					}
					else {
						node_link_tail(head, d);
					}
				}
				e = e->next;
			} while(e != NULL);

			/* we have a valid set of results, look for a corresponding entry */
			label = node_def_find_entry(&defobj, head);

#if 0
printf("Label = %p + head = %p (%d/%d)\n", label, head, head->type, head->sub_type);
#endif

			if(label == NULL) {
				bad = 1;
				e = def->right;
				path = node_path(e, 0);
fprintf(stderr, "ERROR: at line #%ld in file \"%s\": cannot determine what this entry is about.\n"
		"  (Object: \"%s\" of type %s [%d] and subtype %s [%d])\n"
		"  We expected one of the following for \"%s\":\n",
							e->line, e->filename, path,
							node_type_names[e->type].name, e->type,
							node_type_names[e->sub_type].name, e->sub_type,
							defobj.name);
				sswf_free(path);
				node_def_print_entries(&defobj, "    ");
				errcnt++;
			}
		}
		else {
			/* a label, find it! */
			label = node_def_find_label(&defobj, def->left->string);
			if(label == NULL) {
				return -1;
			}
			entry = label->entries;
			cnt = label->count;
#if 0
fprintf(stderr, "Label = %p {%s} %d entries\n", label, label->label, cnt);
#endif
			do {
				/* we got a label so the unit may change with each entry! */
				status.unit = entry->unit;
				status.ref = (entry->flags & DEF_ENTRY_FLAG_REFERENCE) != 0;
				lex_filename = e->filename;
				d = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, e->line);
				ec = node_execute(e, d, &status);

#if 0
fprintf(stderr, "  Executed %d/%d -> %d/%d (object: %s, ec = %d)\n",
		e->type, e->sub_type, d->type, d->sub_type,
		expr->left != NULL ? expr->left->string : "<no name>", ec);
#endif

				if(ec != 0) {
					bad = 1;
					node_free(d);
				}
				else {
					if(head == NULL) {
						head = d;
					}
					else {
						node_link_tail(head, d);
					}
					/* in this case we can straight away test the validity of arguments */
					type = d->type;
					if(type == NODE_TYPE_INTEGER) {
						/* we keep all the values as floating points in these data structures */
						type = NODE_TYPE_FLOAT;
					}
					if(type != entry->type) {
						/* arg! that's bad... */
						bad = 1;
						fprintf(stderr, "ERROR: invalid parameter for the label \"%s\" in object of type \"%s\" (type %s [%d] expected, found %s [%d] instead).\n",
								label->label, defobj.name,
								node_type_names[entry->type].name, entry->type,
								node_type_names[type].name, type);
						errcnt++;
					}
					else if(entry->sub_type != NODE_SUBTYPE_UNKNOWN) {
						type = entry->sub_type;
						if(type == NODE_SUBTYPE_BLOCK) {
							type = NODE_SUBTYPE_LIST;
						}
						if(d->sub_type != type) {
							/* arg! good type but not so good on the sub-type... */
							bad = 1;
							fprintf(stderr, "ERROR: invalid parameter for the label \"%s\" in object of type \"%s\" (sub-type %s [%d] expected, found %s [%d] instead).\n",
									label->label, defobj.name,
									node_type_names[type].name, type,
									node_type_names[d->sub_type].name, d->sub_type);
							errcnt++;
						}
					}
				}
				entry++;
				cnt--;
				e = e->next;
			} while(e != NULL && cnt > 0);
			if(cnt > 0) {
				if((entry->flags & DEF_ENTRY_FLAG_OPTIONAL) == 0) {
					/* if this entry isn't optional, something's missing */
					bad = 1;
					fprintf(stderr, "ERROR: not enough parameters.\n");
					errcnt++;
				}
			}
			else if(e != NULL) {
				/* more params but no entry... that's too much! */
				bad = 1;
				fprintf(stderr, "ERROR: too many parameters.\n");
				errcnt++;
			}
		}
		if(!bad) {

#if 0
printf("  Definition to data (label size: %d, \"%s\")\n",
		label->size, label->label ? label->label : "<no label>");
#endif

			sub_data = node_def_to_data(expr, label, head, obj_struct);

#if 0
printf("==== DATA\n");
if(data) node_print_data(data);
printf("==== SUB-DATA\n");
if(sub_data) node_print_data(sub_data);
printf("  Merge now (0x%08lX, 0x%08lX)\n", (long) sub_data, (long) data);
#endif

			data = node_def_merge_data(expr, &defobj, data, sub_data);

#if 0
printf("==== MERGED DATA\n");
if(data) node_print_data(data);
printf("  Merged at 0x%08lX\n", (long) data);
#endif

		}
		node_free_list(head);
		def = def->next;
	}

	if(!bad) {
		if(defobj.count == 0) {
			/* special case of empty entries such as the SHOW_FRAME object */
			data = node_def_empty(expr);
		}
		else {
			if((defobj.flags & DEF_OBJECT_FLAG_HAS_LIST) == 0 && data == NULL) {
				assert(obj_struct != NULL, "there is no data and no obj_struct");

#if 0
printf("  Create the 'data' buffer from obj_struct only!\n");
#endif

				/* in this case we have no list */
				data = node_def_data(expr, obj_struct, defobj.size);
			}
			else if(obj_struct != NULL) {
				/* got to add this one structure too, insert it first */

#if 0
printf("  Need to insert the obj_struct data too... (Data = %p)\n", data);
#endif

				data = node_def_insertdata(expr, data, obj_struct, defobj.size);
			}
			else if(data == NULL) {
				/* special case of empty entries such as the FILL STYLE { }; */
				if((defobj.flags & DEF_OBJECT_FLAG_EMPTY) == 0) {
fprintf(stderr, "ERROR: the object \"%s\" of type \"%s\" can't be empty.\n",
						expr->left == NULL ? "<no name>" : expr->left->string,
						defobj.name);
					errcnt++;
				}
				data = node_def_empty(expr);
			}
		}
	}

	sswf_free(obj_struct);

	definitions->data = data;

#if 0
node_print_data(data);
printf(">>> .......................................... <<< (%p)\n", data);
//getchar();
fflush(stdout);
#endif

	return bad ? -1 : 0;
}









static int node_boolean(struct node_t *result, struct node_t *l)
{
	switch(result->type) {
	case NODE_TYPE_INTEGER:
		result->integer = l->integer != 0;
		break;

	case NODE_TYPE_FLOAT:
		result->integer = l->floating_point != 0.0;
		break;

	case NODE_TYPE_STRING:
		if(l->string == NULL) {
			result->integer = 0;	/* false in this case */
		}
		else {
			result->integer = l->string != '\0';
			if(result == l) {
				/* save some memory quick */
				sswf_clean(&l->string);
			}
		}
		break;

	default:
		assert(0, "invalid node type for a boolean value check");

	}

	result->type = NODE_TYPE_INTEGER;

	return 0;
}


static int node_exec_if_integers(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t		*e, *head;
	int			ec;
	struct data_common_t	*sub_data;
	struct def_object_t	defobj;

	node_init(result, NODE_TYPE_DATA, NODE_SUBTYPE_BLOCK);

	ec = node_def2entry((const struct definition_t *) node_def_list, &defobj);
	if(ec != 0) {
		return ec;
	}

	e = l->integer ? expr->left : expr->right;

	head = NULL;
	while(e != NULL) {
		lex_filename = e->filename;
		r = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, e->line);
		ec = node_execute(e, r, status);
		if(ec != 0) {
			node_free(r);
			node_free_list(head);
			return ec;
		}
		if(head == NULL) {
			head = r;
		}
		else {
			node_link_tail(head, r);
		}
		e = e->next;
	}

	sub_data = node_def_to_data(expr, defobj.labels, head, NULL);
	result->data = node_def_merge_data(expr, &defobj, NULL, sub_data);
	result->data->type = NODE_SUBTYPE_BLOCK;

	node_free_list(head);

	return 0;
}


static int node_exec_for(struct node_t *expr, struct node_t *l, struct node_t *r, struct node_t *result, struct node_exec_status_t *status)
{
	struct node_t		*variable, *start_expr, *test_expr, *next_expr, *definitions_expr;
	struct node_t		test, *head;
	struct def_object_t	defobj;
	struct data_common_t	*sub_data;
	int			ec;

	/* TODO: The following code is really bad in regard to memory leaks!!! fix it please! */

	/*
	 * TODO: At this time a for() loop generates a block which only a few objects understand.
	 * This will automatically be fixed when the main loop ensures we don't make use of such
	 * lists but instead copy their contents in the parent object!
	 */

	node_init(result, NODE_TYPE_DATA, NODE_SUBTYPE_BLOCK);

	/* get the list of nodes to work with */
	variable = expr->right;				/* the loop variable and it's expression */
	start_expr = variable->next;			/* value used to set variable for the first loop */
	test_expr = start_expr->next;			/* repeat as long as not zero */
	next_expr = test_expr->next;			/* execute once after each loop */
	definitions_expr = next_expr->next;		/* what we want to repeat */

	/* we save the result directory in the variable! */
	/*node_clean(variable->right, 0);*/
	/* TODO: we need to test whether we really need the node_init() here */
	node_init(variable->right, NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN);
	ec = node_execute(start_expr, variable->right, status);
	if(ec != 0) {
		return ec;
	}

	ec = node_def2entry((const struct definition_t *) node_def_list, &defobj);
	if(ec != 0) {
		return ec;
	}

//printf(">>> FOR STARTED!\n");

	node_init(&test, NODE_TYPE_DATA, NODE_SUBTYPE_BLOCK);

	head = NULL;
repeat:
	/* test to see if we should continue the loop */
	ec = node_execute(test_expr, &test, status);
	if(ec != 0) {
		node_free_list(head);
		return ec;
	}
	switch(test.type) {
	case NODE_TYPE_INTEGER:
	case NODE_TYPE_FLOAT:
	case NODE_TYPE_STRING:
		node_boolean(&test, &test);
		if(test.integer == 0) {
			goto done;
		}
		break;

	default:
		fprintf(stderr, "ERROR: a test in a loop must return a boolean value. (variable: \"%s\")\n", variable->left == NULL ? "<no name>" : variable->left->string);
		errcnt++;
		node_free_list(head);
		return -1;

	}

	lex_filename = definitions_expr->filename;
	r = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, definitions_expr->line);
	ec = node_execute(definitions_expr, r, status);
	if(ec != 0) {
		fprintf(stderr, "ERROR: execution failed in a for loop (%d).\n", ec);
		node_free(r);
		node_free_list(head);
		return ec;
	}
	if(head == NULL) {
		head = r;
	}
	else {
		node_link_tail(head, r);
	}

	/*
	 * because the expression next_expr may (should!) reference variable->right
	 * we can't use it directly as the result
	 */
	lex_filename = next_expr->filename;
	r = node_alloc(NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN, next_expr->line);
	ec = node_execute(next_expr, r, status);
	if(ec != 0) {
		node_free(r);
		node_free_list(head);
		return ec;
	}
	node_free(variable->right);
	variable->right = r;
	goto repeat;
done:

	sub_data = node_def_to_data(expr, defobj.labels, head, NULL);
	result->data = node_def_merge_data(expr, &defobj, NULL, sub_data);
	result->data->type = NODE_SUBTYPE_BLOCK;

#if 0
printf(">>> FOR DONE! (%d, %d)\n", result->type, result->sub_type);
#endif

	node_free_list(head);

	return 0;
}







int strcmp_action(const char *name, const char *pattern)
{
	int		r;

	while(isspace((unsigned char) *name) || *name == '_' || *name == '.') {
		name++;
	}

	while(*pattern != '\0') {
		if(*pattern == '.') {
			/* we accept a word separator in this case or none */
			switch(*name) {
			case '-':
			case ' ':
			case '_':
			case '.':
				name++;
				break;

			}
		}
		else {
			r = (unsigned char) toupper((unsigned char) *name) - (unsigned char) *pattern;
			if(r != 0) {
				return r;
			}
			name++;
		}
		pattern++;
	}

	while(isspace((unsigned char) *name) || *name == '_' || *name == '.') {
		name++;
	}

	return (unsigned char) *name;
}







int node_execute(struct node_t *expr, struct node_t *result, struct node_exec_status_t *status)
{
	static const struct node_exec_types	all_types[] = {
		{		/*** field operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_FIELD,
			NULL,
			0,
			{
				node_exec_field,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** subscript operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SUBSCRIPT,
			NULL,
			EXEC_LR,
			{
				node_exec_subscript,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** expand $(...) operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_EXPAND,
			NULL,
			EXEC_LEFT,
			{
				NULL,
				NULL,
				node_exec_reference,	/* indirect object or variable access */
				NULL,
				NULL
			}
		},
		{		/*** unary + operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_IDENTITY,
			NULL,
			EXEC_LEFT,
			{
				node_exec_identity_integers,
				node_exec_identity_floats,
				node_exec_identity_strings,	/* uppercase */
				NULL,
				NULL
			}
		},
		{		/*** unary - operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_NEGATE,
			NULL,
			EXEC_LEFT,
			{
				node_exec_negate_integers,
				node_exec_negate_floats,
				node_exec_negate_strings,	/* lowercase */
				NULL,
				NULL
			}
		},
		{		/*** unary ! operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LOGICAL_NOT,
			NULL,
			EXEC_BOOLEAN_LEFT,
			{
				node_exec_logical_not_integers,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** unary ~ operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_NOT,
			NULL,
			EXEC_LEFT,
			{
				node_exec_not_integers,
				NULL,
				node_exec_not_strings,		/* swap case */
				NULL,
				NULL
			}
		},
		{		/*** group () operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_GROUP,
			NULL,
			EXEC_LEFT,
			{
				node_exec_identity_integers,
				node_exec_identity_floats,
				node_exec_group_strings,	/* do nothing to the string */
				NULL,
				NULL
			}
		},
		{		/*** function <name>(<params>) operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_FUNCTION,
			NULL,
			0,		/* left is an identifier, don't want to evaluate */
			{		/* right is a list of parameters, need to evaluate one by one */
				node_exec_function,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary ** operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_POWER,
			NULL,
			EXEC_LR,
			{
				node_exec_power_integers,
				node_exec_power_floats,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary * operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_MULTIPLY,
			NULL,
			EXEC_LR,
			{
				node_exec_mul_integers,
				node_exec_mul_floats,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary / operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_DIVIDE,
			NULL,
			EXEC_LR,
			{
				node_exec_div_integers,
				node_exec_div_floats,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary % operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_MODULO,
			NULL,
			EXEC_LR,
			{
				node_exec_mod_integers,
				node_exec_mod_floats,		/* not a C operator! */
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary + operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_ADD,
			NULL,
			EXEC_LR,
			{
				node_exec_add_integers,
				node_exec_add_floats,
				node_exec_add_strings,			/* not a C operator */
				node_exec_add_strint,
				NULL
			}
		},
		{		/*** binary - operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SUBTRACT,
			NULL,
			EXEC_LR,
			{
				node_exec_sub_integers,
				node_exec_sub_floats,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary <? operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_MINIMUM,
			NULL,
			EXEC_LR,
			{
				node_exec_min_integers,
				node_exec_min_floats,
				node_exec_min_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary >? operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_MAXIMUM,
			NULL,
			EXEC_LR,
			{
				node_exec_max_integers,
				node_exec_max_floats,
				node_exec_max_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary >> operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SHIFT_RIGHT,
			NULL,
			EXEC_LR,
			{
				node_exec_shift_right_integers,
				NULL,
				NULL,
				node_exec_shift_right_strint,
				NULL
			}
		},
		{		/*** binary << operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SHIFT_LEFT,
			NULL,
			EXEC_LR,
			{
				node_exec_shift_left_integers,
				NULL,
				NULL,
				node_exec_shift_left_strint,
				NULL
			}
		},
		{		/*** binary >>> operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SHIFT_RIGHT_UNSIGNED,
			NULL,
			EXEC_LR,
			{
				node_exec_shift_right_unsigned_integers,
				NULL,
				NULL,
				node_exec_shift_right_unsigned_strint,
				NULL
			}
		},
		{		/*** binary !> operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_ROTATE_RIGHT,
			NULL,
			EXEC_LR,
			{
				node_exec_rotate_right_integers,
				NULL,
				NULL,
				node_exec_rotate_right_strint,
				NULL
			}
		},
		{		/*** binary !< operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_ROTATE_LEFT,
			NULL,
			EXEC_LR,
			{
				node_exec_rotate_left_integers,
				NULL,
				NULL,
				node_exec_rotate_left_strint,
				NULL
			}
		},
		{		/*** binary & operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_AND,
			NULL,
			EXEC_LR,
			{
				node_exec_and_integers,
				NULL,
				node_exec_add_strings,
				node_exec_add_strint,
				NULL
			}
		},
		{		/*** binary | operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_OR,
			NULL,
			EXEC_LR,
			{
				node_exec_or_integers,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary ^ operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_XOR,
			NULL,
			EXEC_LR,
			{
				node_exec_xor_integers,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary && operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LOGICAL_AND,
			NULL,
			EXEC_BOOLEAN_LR,
			{
				node_exec_and_integers,		/* the boolean are 0 or 1 only, the bitwise operator works as well! */
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary || operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LOGICAL_OR,
			NULL,
			EXEC_BOOLEAN_LR,
			{
				node_exec_or_integers,		/* the boolean are 0 or 1 only, the bitwise operator works as well! */
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary ^^ operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LOGICAL_XOR,
			NULL,
			EXEC_BOOLEAN_LR,
			{
				node_exec_xor_integers,		/* the boolean are 0 or 1 only, the bitwise operator works as well! */
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary == operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_EQUAL,
			NULL,
			EXEC_LR,
			{
				node_exec_equal_integers,
				node_exec_equal_floats,
				node_exec_equal_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary != operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_NOT_EQUAL,
			NULL,
			EXEC_LR,
			{
				node_exec_not_equal_integers,
				node_exec_not_equal_floats,
				node_exec_not_equal_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary < operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LESS,
			NULL,
			EXEC_LR,
			{
				node_exec_less_integers,
				node_exec_less_floats,
				node_exec_less_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary <= operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LESS_EQUAL,
			NULL,
			EXEC_LR,
			{
				node_exec_less_equal_integers,
				node_exec_less_equal_floats,
				node_exec_less_equal_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary > operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_GREATER,
			NULL,
			EXEC_LR,
			{
				node_exec_greater_integers,
				node_exec_greater_floats,
				node_exec_greater_strings,
				NULL,
				NULL
			}
		},
		{		/*** binary >= operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_GREATER_EQUAL,
			NULL,
			EXEC_LR,
			{
				node_exec_greater_equal_integers,
				node_exec_greater_equal_floats,
				node_exec_greater_equal_strings,
				NULL,
				NULL
			}
		},
		{		/*** trinary ?: operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_SELECT,
			NULL,
			EXEC_SELECT,
			{
				node_exec_select_integers,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** binary = operator ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_LET,
			NULL,
			EXEC_LEFT,		/* determine the name, but keep the other expression as is */
			{
				node_exec_let,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "ADD" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"ADD",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "ADD CAST" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"ADD.CAST",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "AND" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"AND",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "BRANCH" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"BRANCH",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_branch,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "BRANCH ALWAYS" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"BRANCH.ALWAYS",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_branch,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "BRANCH IF TRUE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"BRANCH.IF.TRUE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_branch,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CALL FRAME" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CALL.FRAME",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CALL FUNCTION" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CALL.FUNCTION",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CALL METHOD" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CALL.METHOD",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CAST OBJECT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CAST.OBJECT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CHR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CHR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CONCATENATE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CONCATENATE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CONCATENATE STRING" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CONCATENATE.STRING",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "CONSTANT POOL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"CONSTANT.POOL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_dictionary,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DECLARE ARRAY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DECLARE.ARRAY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DECLARE LOCAL VARIABLE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DECLARE.LOCAL.VARIABLE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DECLARE OBJECT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DECLARE.OBJECT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DECREMENT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DECREMENT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DELETE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DELETE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DICTIONARY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DICTIONARY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_dictionary,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DIVIDE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DIVIDE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DUPLICATE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DUPLICATE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "DUPLICATE SPRITE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"DUPLICATE.SPRITE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "ENUMERATE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"ENUMERATE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "ENUMERATE OBJECT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"ENUMERATE.OBJECT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "EQUAL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"EQUAL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "EQUAL CAST" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"EQUAL.CAST",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "EXTENDS" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"EXTENDS",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GET MEMBER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GET.MEMBER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GET PROPERTY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GET.PROPERTY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GET TARGET" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GET.TARGET",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GET TIMER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GET.TIMER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GET VARIABLE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GET.VARIABLE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GOTO" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GOTO",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_goto,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GOTO EXPRESSION" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GOTO.EXPRESSION",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_goto,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GOTO FRAME" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GOTO.FRAME",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_goto,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GOTO LABEL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GOTO.LABEL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_goto,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "GREATER THAN" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"GREATER.THAN",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "IF TRUE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"IF.TRUE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_branch,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "IMPLEMENTS" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"IMPLEMENTS",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "INCREMENT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"INCREMENT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "INSTANCE OF" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"INSTANCE.OF",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "INT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"INT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "INTEGRAL PART" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"INTEGRAL.PART",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "LESS THAN" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LESS.THAN",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "LESS THAN CAST" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LESS.THAN.CAST",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "LOGICAL AND" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LOGICAL.AND",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "LOGICAL NOT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LOGICAL.NOT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "LOGICAL OR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LOGICAL.OR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
#if 0
// seems I mistakingly defined XOR instead of NOT
		{		/*** object: ACTION "LOGICAL XOR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"LOGICAL.XOR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
#endif
		{		/*** object: ACTION "MB CHAR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"MB.CHAR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "MB ORD" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"MB.ORD",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "MB STRING LENGTH" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"MB.STRING.LENGTH",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "MODULO" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"MODULO",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "MULTIPLY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"MULTIPLY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "NEW" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"NEW",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "NEW METHOD" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"NEW.METHOD",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "NEXT FRAME" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"NEXT.FRAME",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "NUMBER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"NUMBER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "OR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"OR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "ORD" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"ORD",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "PLAY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"PLAY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "POP" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"POP",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "PREVIOUS FRAME" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"PREVIOUS.FRAME",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "PUSH DATA" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"PUSH.DATA",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_push_data,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "RANDOM" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"RANDOM",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "REMOVE SPRITE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"REMOVE.SPRITE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "RETURN" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"RETURN",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SCENE FRAME DATA ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SCENE_FRAME_DATA,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_sceneframedata,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SET LOCAL VARIABLE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SET.LOCAL.VARIABLE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SET MEMBER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SET.MEMBER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SET PROPERTY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SET.PROPERTY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SET TARGET" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SET.TARGET",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_set_target,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SET VARIABLE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SET.VARIABLE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SHIFT LEFT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SHIFT.LEFT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SHIFT RIGHT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SHIFT.RIGHT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SHIFT RIGHT UNSIGNED" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SHIFT.RIGHT.UNSIGNED",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SHL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SHL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SHR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SHR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "START DRAG" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"START.DRAG",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STOP" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STOP",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STOP DRAG" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STOP.DRAG",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STOP SOUND" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STOP.SOUND",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STORE REGISTER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STORE.REGISTER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_store_register,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRICT EQUAL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRICT.EQUAL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRING" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRING",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRING EQUAL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRING.EQUAL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRING GREATER" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRING.GREATER",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRING LENGTH" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRING.LENGTH",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "STRING LESS THAN" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"STRING.LESS.THAN",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SUB MBSTRING" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SUB.MBSTRING",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SUB STRING" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SUB.STRING",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		/* NOTE: I'm keeping the wrong syntax, but the correct keyword is now SUBTRACT */
		{		/*** object: ACTION "SUBSTRACT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SUBSTRACT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SUBTRACT" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SUBTRACT",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "SWAP" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"SWAP",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "THROW" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"THROW",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "TOGGLE QUALITY" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"TOGGLE.QUALITY",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "TRACE" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"TRACE",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "TYPE OF" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"TYPE.OF",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "URL" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"URL",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_url,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "USHR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"USHR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "WAIT FOR FRAME" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"WAIT.FOR.FRAME",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_wait_for_frame,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION "XOR" ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION,
			"XOR",
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_simple,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ACTION SCRIPT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ACTION_SCRIPT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_action_script,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: BLOCK ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_BLOCK,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_list,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: BUTTON ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_BUTTON,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_button,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: CATCH ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_CATCH,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_function,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: COLOR ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_COLOR,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_color,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: COLOR_TRANSFORM ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_COLOR_TRANSFORM,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_color_transform,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: DO_ACTION ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_DO_ACTION,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_do_action,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: EDGES ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_EDGES,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_edges,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: EDIT_TEXT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_EDIT_TEXT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_edit_text,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: END ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_END,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_end,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ENVELOPE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ENVELOPE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_envelope,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: EXPORT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_EXPORT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_export,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FILL_STYLE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FILL_STYLE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_fill_style,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FINALLY ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FINALLY,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_function,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FONT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FONT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_font,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FOR -- this actually repeats some definitions ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FOR,
			NULL,
			0,
			{
				node_exec_for,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FRAME LABEL ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FRAME_LABEL,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_frame_label,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: FUNCTION ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_FUNCTION,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_function,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: GLYPH ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_GLYPH,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_glyph,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: GRADIENT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_GRADIENT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_gradient,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: IF ***/
			NODE_TYPE_OPERATOR,
			NODE_SUBTYPE_IF,
			NULL,
			EXEC_SELECT,
			{
				node_exec_if_integers,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: IMAGE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_IMAGE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_image,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: IMPORT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_IMPORT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_import,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: LABEL ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_LABEL,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_label,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: LINE_STYLE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_LINE_STYLE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_line_style,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: LIST ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_LIST,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_list,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: MATRIX ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_MATRIX,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_matrix,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: METADATA ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_METADATA,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_metadata,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: ON EVENT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_ON_EVENT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_on_event,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: PLACE OBJECT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_PLACE_OBJECT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_place_object,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: POINTS ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_POINTS,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_points,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: RECT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_RECT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_rect,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: REMOVE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_REMOVE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_remove,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: REPLACE OBJECT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_REPLACE_OBJECT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_place_object,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SCRIPT LIMITS ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SCRIPT_LIMITS,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_script_limits,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SEQUENCE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SEQUENCE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_sequence,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SET BACKGROUND COLOR ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SET_BACKGROUND_COLOR,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_set_background_color,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SET TAB INDEX ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SET_TAB_INDEX,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_set_tab_index,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SHAPE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SHAPE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_shape,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SHOW FRAME ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SHOW_FRAME,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_show_frame,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SOUND ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SOUND,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_sound,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SOUND INFO ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SOUND_INFO,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_sound_info,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: SPRITE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_SPRITE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_sprite,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: STATE ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_STATE,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_state,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: TEXT ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_TEXT,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_text,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: TRY ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_TRY,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_function,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object: TEXT SETUP ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_TEXT_SETUP,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_text_setup,
				NULL,
				NULL,
				NULL
			}
		},
#if 0
		{		/*** object: VARIABLE -- just skip those! ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_VARIABLE,
			NULL,
			0,
			{
				node_exec_nothing,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
#endif
		{		/*** object: WITH ***/
			NODE_TYPE_OBJECT,
			NODE_SUBTYPE_WITH,
			NULL,
			EXEC_DEFINITIONS,
			{
				node_exec_nothing,
				(node_exec_func) node_def_with,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** object or variable reference ***/
			NODE_TYPE_IDENTIFIER,
			NODE_SUBTYPE_UNKNOWN,
			NULL,
			0,
			{
				node_exec_reference,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** immediate value ***/
			NODE_TYPE_INTEGER,
			NODE_SUBTYPE_UNKNOWN,
			NULL,
			EXEC_INTEGER,
			{
				NULL,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** immediate value ***/
			NODE_TYPE_FLOAT,
			NODE_SUBTYPE_UNKNOWN,
			NULL,
			EXEC_FLOAT,
			{
				NULL,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},
		{		/*** immediate string ***/
			NODE_TYPE_STRING,
			NODE_SUBTYPE_UNKNOWN,
			NULL,
			EXEC_STRING,
			{
				NULL,
				NULL,
				NULL,
				NULL,
				NULL
			}
		},




		/* end of table */
		{
			NODE_TYPE_UNKNOWN,
			NODE_SUBTYPE_UNKNOWN,
			NULL,
			0,
			{
				NULL,
				NULL,
				NULL,
				NULL,
				NULL
			}
		}
	};
	const struct node_exec_types	*t;
	const struct definition_t	*def;
	struct node_t			l, r;
	int				ec, idx;

	/* ensure the node is clean-able */
	/* things changed and we don't actually want this here anymore
	node_init(result, NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN);
	*/

	idx = 0;
	t = all_types;
	while(t->type != NODE_TYPE_UNKNOWN) {
		if(t->type == expr->type && t->sub_type == expr->sub_type) {
			if(t->name != NULL) {
				/*
				 * In this case we know that expr is an object
				 * and expect the name on the left node
				 */
				assert(expr->left != NULL, "this object is expected to have a name");
				if(strcmp_action(expr->left->string, t->name) != 0) {
					/* not yet a valid entry */
					goto skip;
				}
			}
			/* we found a match, execute the operation */
			if((t->flags & EXEC_STRING) != 0) {
				/* NOTE: the sswf_strdup() can duplicate NULL pointers! */
				result->type = NODE_TYPE_STRING;
				result->string = sswf_strdup(expr->string);
			}
			else if((t->flags & EXEC_INTEGER) != 0) {
				result->type = NODE_TYPE_INTEGER;
				result->integer = expr->integer;
			}
			else if((t->flags & EXEC_FLOAT) != 0) {
				result->type = NODE_TYPE_FLOAT;
				result->floating_point = expr->floating_point;
			}
			else {
				l.type = NODE_TYPE_INTEGER;	/* by default, just in case */

				/* select, left or right */
				if((t->flags & EXEC_SELECT) != 0) {
					assert((t->flags & (EXEC_LEFT | EXEC_BOOLEAN_LEFT)) == 0, "EXEC_SELECT and EXEC_LEFT or EXEC_BOOLEAN_LEFT are incompatible");
					node_init(&l, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
					ec = node_eval(expr->select, &l, status);
					if(ec != 0) {
						return ec;
					}
					node_boolean(&l, &l);
				}
				else if((t->flags & (EXEC_LEFT | EXEC_BOOLEAN_LEFT)) != 0) {
					node_init(&l, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
					ec = node_eval(expr->left, &l, status);
					if(ec != 0) {
						return ec;
					}
					if((t->flags & EXEC_BOOLEAN_LEFT) != 0) {
						node_boolean(&l, &l);
					}
				}
				if((t->flags & (EXEC_RIGHT | EXEC_BOOLEAN_RIGHT)) != 0) {
					node_init(&r, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
					ec = node_eval(expr->right, &r, status);
					if(ec != 0) {
						if((t->flags & (EXEC_LEFT | EXEC_BOOLEAN_LEFT | EXEC_SELECT)) != 0) {
							node_clean(&l, 0);
						}
						return ec;
					}
					if((t->flags & EXEC_BOOLEAN_RIGHT) != 0) {
						node_boolean(&r, &r);
					}
					if((t->flags & (EXEC_LEFT | EXEC_BOOLEAN_LEFT)) == 0) {
						l.type = r.type;
					}
				}
				else {
					r.type = l.type;
				}

				/*
				 * For objects, "all" of them have definitions, we have
				 * a special way to parse these; we assume that EXEC_LEFT,
				 * EXEC_RIGHT and the corresponding boolean flags are all
				 * zero.
				 */
				if((t->flags & EXEC_DEFINITIONS) != 0) {
					assert((t->flags & (EXEC_LR | EXEC_BOOLEAN_LR)) == 0, "flags cannot include both EXEC_[SUB_]DEFINITIONS & one or more of EXEC_LEFT, RIGHT, BOOLEAN_LEFT, BOOLEAN_RIGHT");
					def = (const struct definition_t *) t->func[1];
					ec = node_definitions(expr, def, &r, status);
					if(ec != 0) {
						goto err;
					}
					/* if there is something more to do, use the default function */
					idx = NODE_EXEC_FUNC_INTEGERS;
				}
				/* when we are ready to execute a function we need to know which one to call */
				else switch(qs(l.type, r.type)) {
				case qs(NODE_TYPE_INTEGER, NODE_TYPE_INTEGER):
					idx = NODE_EXEC_FUNC_INTEGERS;
					result->type = NODE_TYPE_INTEGER;
					break;

				case qs(NODE_TYPE_INTEGER, NODE_TYPE_FLOAT):
					/* change left handside into a floating point */
					l.floating_point = (double) l.integer;
					l.type = NODE_TYPE_FLOAT;
					idx = NODE_EXEC_FUNC_FLOATS;
					result->type = NODE_TYPE_FLOAT;
					break;

				case qs(NODE_TYPE_FLOAT, NODE_TYPE_INTEGER):
					/* change right handside into a floating point */
					r.floating_point = (double) r.integer;
					r.type = NODE_TYPE_FLOAT;
					idx = NODE_EXEC_FUNC_FLOATS;
					result->type = NODE_TYPE_FLOAT;
					break;

				case qs(NODE_TYPE_FLOAT, NODE_TYPE_FLOAT):
					idx = NODE_EXEC_FUNC_FLOATS;
					result->type = NODE_TYPE_FLOAT;
					break;

				case qs(NODE_TYPE_STRING, NODE_TYPE_INTEGER):
					idx = NODE_EXEC_FUNC_STRINT;
					result->type = NODE_TYPE_STRING;
					break;

				case qs(NODE_TYPE_STRING, NODE_TYPE_FLOAT):
					idx = NODE_EXEC_FUNC_STRFLT;
					result->type = NODE_TYPE_STRING;
					break;

				case qs(NODE_TYPE_STRING, NODE_TYPE_STRING):
					idx = NODE_EXEC_FUNC_STRINGS;
					result->type = NODE_TYPE_STRING;
					break;

				default:
					if((t->flags & EXEC_LR) != 0) {
						fprintf(stderr, "ERROR: expression types mismatch!\n");
						ec = -1;
						goto err;
					}
					/* a default function is in this entry */
					idx = NODE_EXEC_FUNC_INTEGERS;
					result->type = expr->type;
					break;

				}
				if(t->func[idx] == NULL) {
					if(t->func[NODE_EXEC_FUNC_INTEGERS] == NULL
					|| idx == NODE_EXEC_FUNC_STRINT) {
						fprintf(stderr, "ERROR: at line #%ld in filename \"%s\": sswf doesn't know how to handle this expression.\n",
								expr->line, expr->filename);
						errcnt++;
						/* we can't continue */
						ec = -1;
						goto err;
					}
					idx = NODE_EXEC_FUNC_INTEGERS;
				}
				ec = (*t->func[idx])(expr, &l, &r, result, status);
err:
				if((t->flags & (EXEC_LEFT | EXEC_BOOLEAN_LEFT | EXEC_SELECT)) != 0) {
					node_clean(&l, 0);
				}
				if((t->flags & (EXEC_RIGHT | EXEC_BOOLEAN_RIGHT | EXEC_DEFINITIONS)) != 0) {
					node_clean(&r, 0);
				}
				if(ec != 0) {
					/* now the result is never cleaner here 
					 * the caller is responsible!
					node_clean(result, 0);
					 */
					return ec;
				}
			}
			return 0;
		}
skip:
		t++;
	}

#if DEBUG
	printf("ERROR: at line #%ld in file \"%s\": can't execute expression. (%d, %d, %s)\n",
							expr->line, expr->filename,
							expr->type, expr->sub_type,
							expr->left == 0 ? "<no name>" : expr->left->string);
	abort();
#endif

	return 1;
}


int node_eval(struct node_t *expr, struct node_t *result, struct node_exec_status_t *status)
{
	int		ec;

	if(expr == NULL) {	/* this happens in the IF statement without an ELSE */
		/* should we change the result types?!?
		node_init(result, NODE_TYPE_UNKNOWN, NODE_SUBTYPE_UNKNOWN);
		*/
		return 0;
	}

	/* evaluate one group of expressions and return the result of the last */
	ec = node_execute(expr, result, status);

	expr = expr->next;
	while(expr != NULL && ec == 0) {
		node_clean(result, 0);
		node_init(result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
		ec = node_execute(expr, result, status);
		expr = expr->next;
	}

	return ec;
}


