Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 626f9079bcffdfbce27d2e92f138ae9ce8e4c650)
+++ boot/Makefile.common	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -66,4 +66,5 @@
 	$(USPACEDIR)/app/klog/klog \
 	$(USPACEDIR)/app/mkfat/mkfat \
+	$(USPACEDIR)/app/sbi/sbi \
 	$(USPACEDIR)/app/redir/redir \
 	$(USPACEDIR)/app/taskdump/taskdump \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 626f9079bcffdfbce27d2e92f138ae9ce8e4c650)
+++ uspace/Makefile	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -41,4 +41,5 @@
 	app/mkfat \
 	app/redir \
+	app/sbi \
 	app/taskdump \
 	app/tester \
Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/Makefile	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIB_PREFIX)/clui/libclui.a
+EXTRA_CFLAGS = -D__HELENOS__ -I$(LIB_PREFIX)/clui
+
+BINARY = sbi
+
+SOURCES = \
+	src/builtin/bi_fun.c \
+	src/builtin/bi_textfile.c \
+	src/os/helenos.c \
+	src/ancr.c \
+	src/builtin.c \
+	src/imode.c \
+	src/input.c \
+	src/intmap.c \
+	src/lex.c \
+	src/list.c \
+	src/main.c \
+	src/p_expr.c \
+	src/p_type.c \
+	src/parse.c \
+	src/rdata.c \
+	src/run.c \
+	src/run_expr.c \
+	src/run_texpr.c \
+	src/stree.c \
+	src/strtab.c \
+	src/stype.c \
+	src/stype_expr.c \
+	src/symbol.c \
+	src/tdata.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/sbi/src/ancr.c
===================================================================
--- uspace/app/sbi/src/ancr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/ancr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Ancestry resolver.
+ *
+ * A chicken-and-egg problem is that in order to match identifiers to CSI
+ * definitions we need to know CSI ancestry. To know CSI ancestry we need
+ * to match identifiers to CSI definitions. Thus both must be done at the
+ * same time. Once we know the ancestry of some CSI, we are able to resolve
+ * symbols referenced within the scope of that CSI (but not in nested scopes).
+ *
+ * Here lies probably the most complicated (although not so complicated)
+ * algorithm. To process node N we must first process outer(N). This allows
+ * us to find all base(N) nodes and process them.
+ *
+ * To ensure all nodes get processed correctly, we use a two-layer walk.
+ * In the lower layer (ancr_csi_process) we follow the dependencies.
+ * ancr_csi_process(N) ensures N (and possibly other nodes) get resolved.
+ *
+ * In the second layer we simply do a DFS of the CSI tree, calling
+ * ancr_csi_process() on each node. This ensures that eventually all
+ * nodes get processed.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "builtin.h"
+#include "list.h"
+#include "mytypes.h"
+#include "stree.h"
+#include "strtab.h"
+#include "symbol.h"
+
+#include "ancr.h"
+
+static void ancr_csi_dfs(stree_program_t *prog, stree_csi_t *csi);
+static void ancr_csi_process(stree_program_t *prog, stree_csi_t *node);
+static void ancr_csi_print_cycle(stree_program_t *prog, stree_csi_t *node);
+
+/** Process ancestry of all CSIs in a module.
+ *
+ * Note that currently we expect there to be exactly one module in the
+ * whole program.
+ *
+ * @param prog		Program being processed.
+ * @param module	Module to process.
+ */
+void ancr_module_process(stree_program_t *prog, stree_module_t *module)
+{
+	list_node_t *node;
+	stree_modm_t *modm;
+
+	(void) module;
+	node = list_first(&prog->module->members);
+
+	while (node != NULL) {
+		modm = list_node_data(node, stree_modm_t *);
+		assert(modm->mc == mc_csi); /* XXX */
+		ancr_csi_dfs(prog, modm->u.csi);
+
+		node = list_next(&prog->module->members, node);
+	}
+}
+
+/** Walk CSI node tree depth-first.
+ *
+ * This is the outer depth-first walk whose purpose is to eventually
+ * process all CSI nodes by calling ancr_csi_process() on them.
+ * (Which causes that and possibly some other nodes to be processed).
+ *
+ * @param prog		Program being processed.
+ * @param csi		CSI node to visit.
+ */
+static void ancr_csi_dfs(stree_program_t *prog, stree_csi_t *csi)
+{
+	list_node_t *node;
+	stree_csimbr_t *csimbr;
+
+	/* Process this node first. */
+	ancr_csi_process(prog, csi);
+
+	/* Now visit all children. */
+	node = list_first(&csi->members);
+	while (node != NULL) {
+		csimbr = list_node_data(node, stree_csimbr_t *);
+		if (csimbr->cc == csimbr_csi)
+			ancr_csi_dfs(prog, csimbr->u.csi);
+
+		node = list_next(&csi->members, node);
+	}
+}
+
+/** Process csi node.
+ *
+ * Fist processes the pre-required nodes (outer CSI and base CSIs),
+ * then processes @a node. This is the core 'outward-and-baseward' walk.
+ *
+ * @param prog		Program being processed.
+ * @param node		CSI node to process.
+ */
+static void ancr_csi_process(stree_program_t *prog, stree_csi_t *node)
+{
+	stree_symbol_t *base_sym;
+	stree_csi_t *base_csi, *outer_csi;
+	stree_csi_t *gf_class;
+
+	if (node->ancr_state == ws_visited) {
+		/* Node already processed */
+		return;
+	}
+
+	if (node->ancr_state == ws_active) {
+		/* Error, closed reference loop. */
+		printf("Error: Circular class, struct or interface chain: ");
+		ancr_csi_print_cycle(prog, node);
+		printf(".\n");
+		exit(1);
+	}
+
+	node->ancr_state = ws_active;
+
+	outer_csi = csi_to_symbol(node)->outer_csi;
+	gf_class = builtin_get_gf_class(prog->builtin);
+
+	/* Process outer CSI */
+	if (outer_csi != NULL)
+		ancr_csi_process(prog, outer_csi);
+
+	if (node->base_csi_ref != NULL) {
+		/* Resolve base CSI. */
+		base_sym = symbol_xlookup_in_csi(prog, outer_csi,
+			node->base_csi_ref);
+		base_csi = symbol_to_csi(base_sym);
+		assert(base_csi != NULL);
+
+		/* Process base CSI. */
+		ancr_csi_process(prog, base_csi);
+	} else if (node != gf_class) {
+		/* Implicit inheritance from grandfather class. */
+		base_csi = gf_class;
+	} else {
+		/* Grandfather class has no base class. */
+		base_csi = NULL;
+	}
+
+	/* Store base CSI and update node state. */
+	node->ancr_state = ws_visited;
+	node->base_csi = base_csi;
+}
+
+/** Print loop in CSI ancestry.
+ *
+ * We have detected a loop in CSI ancestry. Traverse it (by following the
+ * nodes in ws_active state and print it.
+ *
+ * @param prog		Program.
+ * @param node		CSI node participating in an ancestry cycle.
+ */
+static void ancr_csi_print_cycle(stree_program_t *prog, stree_csi_t *node)
+{
+	stree_csi_t *n;
+	stree_symbol_t *base_sym, *node_sym;
+	stree_csi_t *base_csi, *outer_csi;
+
+	n = node;
+	do {
+		node_sym = csi_to_symbol(node);
+		symbol_print_fqn(node_sym);
+		printf(", ");
+
+		outer_csi = node_sym->outer_csi;
+
+		if (outer_csi != NULL && outer_csi->ancr_state == ws_active) {
+			node = outer_csi;
+		} else if (node->base_csi_ref != NULL) {
+			/* Resolve base CSI. */
+			base_sym = symbol_xlookup_in_csi(prog, outer_csi,
+				node->base_csi_ref);
+			base_csi = symbol_to_csi(base_sym);
+			assert(base_csi != NULL);
+
+			assert(base_csi->ancr_state == ws_active);
+			node = base_csi;
+		} else {
+			assert(b_false);
+		}
+	} while (n != node);
+
+	node_sym = csi_to_symbol(node);
+	symbol_print_fqn(node_sym);
+}
Index: uspace/app/sbi/src/ancr.h
===================================================================
--- uspace/app/sbi/src/ancr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/ancr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANCR_H_
+#define ANCR_H_
+
+#include "mytypes.h"
+
+void ancr_module_process(stree_program_t *prog, stree_module_t *module);
+
+#endif
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Builtin symbol binding.
+ *
+ * 'Builtin' symbols are implemented outside of the language itself.
+ * Here we refer to entities residing within the interpreted universe
+ * as 'internal', while anything implemented outside this universe
+ * as 'external'. This module facilitates declaration of builtin
+ * symbols and the binding of these symbols to their external
+ * implementation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "ancr.h"
+#include "builtin/bi_fun.h"
+#include "builtin/bi_textfile.h"
+#include "input.h"
+#include "intmap.h"
+#include "lex.h"
+#include "list.h"
+#include "mytypes.h"
+#include "os/os.h"
+#include "parse.h"
+#include "run.h"
+#include "stree.h"
+#include "strtab.h"
+#include "symbol.h"
+
+#include "builtin.h"
+
+static builtin_t *builtin_new(void);
+
+/** Declare builtin symbols in the program.
+ *
+ * Declares symbols that will be hooked to builtin interpreter procedures.
+ *
+ * @param program	Program in which to declare builtin symbols.
+ */
+void builtin_declare(stree_program_t *program)
+{
+	builtin_t *bi;
+
+	bi = builtin_new();
+	bi->program = program;
+	program->builtin = bi;
+
+	/*
+	 * Declare grandfather class.
+	 */
+
+	builtin_code_snippet(bi,
+		"class Object is\n"
+		"end\n");
+	bi->gf_class = builtin_find_lvl0(bi, "Object");
+
+	/*
+	 * Declare other builtin classes/functions.
+	 */
+
+	bi_fun_declare(bi);
+	bi_textfile_declare(bi);
+
+	/* Need to process ancestry so that symbol lookups work. */
+	ancr_module_process(program, program->module);
+
+	bi_fun_bind(bi);
+	bi_textfile_bind(bi);
+}
+
+/** Get grandfather class.
+ *
+ * Grandfather class is the class from which all other classes are
+ * (directly or indirectly) derived.
+ *
+ * @param builtin	Builtin context (corresponsds to program).
+ * @return		Grandfather class (CSI).
+ */
+stree_csi_t *builtin_get_gf_class(builtin_t *builtin)
+{
+	if (builtin->gf_class == NULL)
+		return NULL;
+
+	return symbol_to_csi(builtin->gf_class);
+}
+
+/** Allocate new builtin context object.
+ *
+ * @return	Builtin context object.
+ */
+static builtin_t *builtin_new(void)
+{
+	builtin_t *builtin;
+
+	builtin = calloc(1, sizeof(builtin_t));
+	if (builtin == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return builtin;
+}
+
+/** Parse a declaration code snippet.
+ *
+ * Parses a piece of code from a string at the module level. This can be
+ * used to declare builtin symbols easily and without need for an external
+ * file.
+ */
+void builtin_code_snippet(builtin_t *bi, const char *snippet)
+{
+	input_t *input;
+	lex_t lex;
+	parse_t parse;
+
+	input_new_string(&input, snippet);
+	lex_init(&lex, input);
+	parse_init(&parse, bi->program, &lex);
+	parse_module(&parse);
+}
+
+/** Simplifed search for a global symbol.
+ *
+ * The specified symbol must exist.
+ *
+ * @param bi		Builtin context object.
+ * @param sym_name	Name of symbol to find.
+ * @return		Symbol.
+ */
+stree_symbol_t *builtin_find_lvl0(builtin_t *bi, const char *sym_name)
+{
+	stree_symbol_t *sym;
+	stree_ident_t *ident;
+
+	ident = stree_ident_new();
+
+	ident->sid = strtab_get_sid(sym_name);
+	sym = symbol_lookup_in_csi(bi->program, NULL, ident);
+	assert(sym != NULL);
+
+	return sym;
+}
+
+/** Simplifed search for a level 1 symbol.
+ *
+ * The specified symbol must exist.
+ *
+ * @param bi		Builtin context object.
+ * @param csi_name	CSI in which to look for symbol.
+ * @param sym_name	Name of symbol to find.
+ * @return		Symbol.
+ */
+stree_symbol_t *builtin_find_lvl1(builtin_t *bi, const char *csi_name,
+    const char *sym_name)
+{
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+
+	stree_symbol_t *mbr_sym;
+	stree_ident_t *ident;
+
+	ident = stree_ident_new();
+
+	ident->sid = strtab_get_sid(csi_name);
+	csi_sym = symbol_lookup_in_csi(bi->program, NULL, ident);
+	assert(csi_sym != NULL);
+	csi = symbol_to_csi(csi_sym);
+	assert(csi != NULL);
+
+	ident->sid = strtab_get_sid(sym_name);
+	mbr_sym = symbol_lookup_in_csi(bi->program, csi, ident);
+	assert(mbr_sym != NULL);
+
+	return mbr_sym;
+}
+
+/** Bind level 1 member function to external implementation.
+ *
+ * Binds a member function (of a global class) to external implementation.
+ * The specified CSI and member function must exist.
+ *
+ * @param bi		Builtin context object.
+ * @param csi_name	CSI which contains the function.
+ * @param sym_name	Function name.
+ * @param bproc		Pointer to C function implementation.
+ */
+void builtin_fun_bind(builtin_t *bi, const char *csi_name,
+    const char *sym_name, builtin_proc_t bproc)
+{
+	stree_symbol_t *fun_sym;
+	stree_fun_t *fun;
+
+	fun_sym = builtin_find_lvl1(bi, csi_name, sym_name);
+	assert(fun_sym != NULL);
+	fun = symbol_to_fun(fun_sym);
+	assert(fun != NULL);
+
+	fun->proc->bi_handler = bproc;
+}
+
+/** Execute a builtin procedure.
+ *
+ * Executes a procedure that has an external implementation.
+ *
+ * @param run		Runner object.
+ * @param proc		Procedure that has an external implementation.
+ */
+void builtin_run_proc(run_t *run, stree_proc_t *proc)
+{
+	stree_symbol_t *fun_sym;
+	builtin_t *bi;
+	builtin_proc_t bproc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run builtin procedure.\n");
+#endif
+	fun_sym = proc->outer_symbol;
+	bi = run->program->builtin;
+
+	bproc = proc->bi_handler;
+	if (bproc == NULL) {
+		printf("Error: Unrecognized builtin function '");
+		symbol_print_fqn(fun_sym);
+		printf("'.\n");
+		exit(1);
+	}
+
+	/* Run the builtin procedure handler. */
+	(*bproc)(run);
+}
+
+/** Get pointer to member var of current object.
+ *
+ * Returns the var node that corresponds to a member of the currently
+ * active object with the given name. This member must exist.
+ *
+ * @param run		Runner object.
+ * @param mbr_name	Name of member to find.
+ * @return		Var node of the member.
+ */
+rdata_var_t *builtin_get_self_mbr_var(run_t *run, const char *mbr_name)
+{
+	run_proc_ar_t *proc_ar;
+	rdata_object_t *object;
+	sid_t mbr_name_sid;
+	rdata_var_t *mbr_var;
+
+	proc_ar = run_get_current_proc_ar(run);
+	assert(proc_ar->obj->vc == vc_object);
+	object = proc_ar->obj->u.object_v;
+
+	mbr_name_sid = strtab_get_sid(mbr_name);
+	mbr_var = intmap_get(&object->fields, mbr_name_sid);
+	assert(mbr_var != NULL);
+
+	return mbr_var;
+}
+
+/** Declare a builtin function in @a csi.
+ *
+ * Declare a builtin function member of CSI @a csi. Deprecated in favor
+ * of builtin_code_snippet().
+ *
+ * @param csi		CSI in which to declare function.
+ * @param name		Name of member function to declare.
+ * @return		Symbol of newly declared function.
+ */
+stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name)
+{
+	stree_ident_t *ident;
+	stree_fun_t *fun;
+	stree_csimbr_t *csimbr;
+	stree_symbol_t *fun_sym;
+
+	ident = stree_ident_new();
+	ident->sid = strtab_get_sid(name);
+
+	fun = stree_fun_new();
+	fun->name = ident;
+	fun->proc = stree_proc_new();
+	fun->proc->body = NULL;
+	list_init(&fun->args);
+
+	csimbr = stree_csimbr_new(csimbr_fun);
+	csimbr->u.fun = fun;
+
+	fun_sym = stree_symbol_new(sc_fun);
+	fun_sym->u.fun = fun;
+	fun_sym->outer_csi = csi;
+	fun->symbol = fun_sym;
+	fun->proc->outer_symbol = fun_sym;
+
+	list_append(&csi->members, csimbr);
+
+	return fun_sym;
+}
+
+/** Add one formal parameter to function.
+ *
+ * Used to incrementally construct formal parameter list of a builtin
+ * function. Deprecated in favor of builtin_code_snippet(). Does not
+ * support type checking.
+ *
+ * @param fun_sym	Symbol of function to add parameters to.
+ * @param name		Name of parameter to add.
+ */
+void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name)
+{
+	stree_proc_arg_t *proc_arg;
+	stree_fun_t *fun;
+
+	fun = symbol_to_fun(fun_sym);
+	assert(fun != NULL);
+
+	proc_arg = stree_proc_arg_new();
+	proc_arg->name = stree_ident_new();
+	proc_arg->name->sid = strtab_get_sid(name);
+	proc_arg->type = NULL; /* XXX */
+
+	list_append(&fun->args, proc_arg);
+}
Index: uspace/app/sbi/src/builtin.h
===================================================================
--- uspace/app/sbi/src/builtin.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BUILTIN_H_
+#define BUILTIN_H_
+
+#include "mytypes.h"
+
+void builtin_declare(stree_program_t *program);
+void builtin_code_snippet(builtin_t *bi, const char *snippet);
+
+stree_csi_t *builtin_get_gf_class(builtin_t *builtin);
+void builtin_run_proc(run_t *run, stree_proc_t *proc);
+
+rdata_var_t *builtin_get_self_mbr_var(run_t *run, const char *mbr_name);
+
+stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name);
+void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name);
+
+stree_symbol_t *builtin_find_lvl0(builtin_t *bi, const char *sym_name);
+stree_symbol_t *builtin_find_lvl1(builtin_t *bi, const char *csi_name,
+    const char *sym_name);
+
+void builtin_fun_bind(builtin_t *bi, const char *csi_name,
+    const char *sym_name, builtin_proc_t bproc);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_fun.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin/bi_fun.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Builtin functions. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../builtin.h"
+#include "../list.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../run.h"
+#include "../stree.h"
+#include "../strtab.h"
+#include "../symbol.h"
+
+#include "bi_fun.h"
+
+static void bi_fun_builtin_writeline(run_t *run);
+static void bi_fun_task_exec(run_t *run);
+
+/** Declare builtin functions. */
+void bi_fun_declare(builtin_t *bi)
+{
+	stree_modm_t *modm;
+	stree_csi_t *csi;
+	stree_ident_t *ident;
+	stree_symbol_t *symbol;
+	stree_symbol_t *fun_sym;
+
+	/* Declare class Builtin */
+
+	ident = stree_ident_new();
+	ident->sid = strtab_get_sid("Builtin");
+
+	csi = stree_csi_new(csi_class);
+	csi->name = ident;
+	list_init(&csi->members);
+
+	modm = stree_modm_new(mc_csi);
+	modm->u.csi = csi;
+
+	symbol = stree_symbol_new(sc_csi);
+	symbol->u.csi = csi;
+	symbol->outer_csi = NULL;
+	csi->symbol = symbol;
+
+	list_append(&bi->program->module->members, modm);
+
+	/* Declare Builtin.WriteLine(). */
+
+	fun_sym = builtin_declare_fun(csi, "WriteLine");
+	builtin_fun_add_arg(fun_sym, "arg");
+
+	/* Declare class Task. */
+
+	builtin_code_snippet(bi,
+		"class Task is\n"
+			"fun Exec(args : string[], packed), builtin;\n"
+		"end\n");
+}
+
+/** Bind builtin functions. */
+void bi_fun_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Builtin", "WriteLine", bi_fun_builtin_writeline);
+	builtin_fun_bind(bi, "Task", "Exec", bi_fun_task_exec);
+}
+
+/** Write a line of output. */
+static void bi_fun_builtin_writeline(run_t *run)
+{
+	rdata_var_t *var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Builtin.WriteLine()\n");
+#endif
+	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
+	assert(var);
+
+	switch (var->vc) {
+	case vc_int:
+		printf("%d\n", var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("%s\n", var->u.string_v->value);
+		break;
+	default:
+		printf("Unimplemented: writeLine() with unsupported type.\n");
+		exit(1);
+	}
+}
+
+/** Start an executable and wait for it to finish. */
+static void bi_fun_task_exec(run_t *run)
+{
+	rdata_var_t *args;
+	rdata_var_t *var;
+	rdata_array_t *array;
+	rdata_var_t *arg;
+	int idx, dim;
+	char **cmd;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Task.Exec()\n");
+#endif
+	args = run_local_vars_lookup(run, strtab_get_sid("args"));
+
+	assert(args);
+	assert(args->vc == vc_ref);
+
+	var = args->u.ref_v->vref;
+	assert(var->vc == vc_array);
+
+	array = var->u.array_v;
+	assert(array->rank == 1);
+	dim = array->extent[0];
+
+	if (dim == 0) {
+		printf("Error: Builtin.Exec() expects at least one argument.\n");
+		exit(1);
+	}
+
+	cmd = calloc(dim + 1, sizeof(char *));
+	if (cmd == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	for (idx = 0; idx < dim; ++idx) {
+		arg = array->element[idx];
+		if (arg->vc != vc_string) {
+			printf("Error: Argument to Builtin.Exec() must be "
+			    "string (found %d).\n", arg->vc);
+			exit(1);
+		}
+
+		cmd[idx] = arg->u.string_v->value;
+	}
+
+	cmd[dim] = '\0';
+
+	if (os_exec(cmd) != EOK) {
+		printf("Error: Exec failed.\n");
+		exit(1);
+	}
+}
Index: uspace/app/sbi/src/builtin/bi_fun.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin/bi_fun.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BI_FUN_H_
+#define BI_FUN_H_
+
+#include "../mytypes.h"
+
+void bi_fun_declare(builtin_t *bi);
+void bi_fun_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_textfile.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin/bi_textfile.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file TextFile builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../builtin.h"
+#include "../debug.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../rdata.h"
+#include "../run.h"
+#include "../strtab.h"
+
+#include "bi_textfile.h"
+
+#define LINE_BUF_SIZE 256
+static char line_buf[LINE_BUF_SIZE];
+
+static void bi_textfile_openread(run_t *run);
+static void bi_textfile_openwrite(run_t *run);
+static void bi_textfile_close(run_t *run);
+static void bi_textfile_readline(run_t *run);
+static void bi_textfile_writeline(run_t *run);
+static void bi_textfile_is_eof(run_t *run);
+
+/** Declare TextFile builtin. */
+void bi_textfile_declare(builtin_t *bi)
+{
+	/* Declare class TextFile. */
+
+	builtin_code_snippet(bi,
+		"class TextFile is\n"
+			"var f : resource;\n"
+			"\n"
+			"fun OpenRead(fname : string), builtin;\n"
+			"fun OpenWrite(fname : string), builtin;\n"
+			"fun Close(), builtin;\n"
+			"fun ReadLine() : string, builtin;\n"
+			"fun WriteLine(line : string), builtin;\n"
+			"\n"
+			"prop EOF : int is\n"
+				"get is\n"
+					"return is_eof();\n"
+				"end\n"
+			"end\n"
+			"\n"
+			"fun is_eof() : int, builtin;\n"
+		"end\n");
+
+}
+
+/** Bind TextFile builtin. */
+void bi_textfile_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "TextFile", "OpenRead", bi_textfile_openread);
+	builtin_fun_bind(bi, "TextFile", "OpenWrite", bi_textfile_openwrite);
+	builtin_fun_bind(bi, "TextFile", "Close", bi_textfile_close);
+	builtin_fun_bind(bi, "TextFile", "ReadLine", bi_textfile_readline);
+	builtin_fun_bind(bi, "TextFile", "WriteLine", bi_textfile_writeline);
+	builtin_fun_bind(bi, "TextFile", "is_eof", bi_textfile_is_eof);
+}
+
+/** Open a text file for reading. */
+static void bi_textfile_openread(run_t *run)
+{
+	rdata_var_t *fname_var;
+	char *fname;
+	FILE *file;
+
+	rdata_resource_t *resource;
+	rdata_var_t *res_var;
+	rdata_value_t *res_val;
+	rdata_var_t *self_f_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called TextFile.OpenRead()\n");
+#endif
+	fname_var = run_local_vars_lookup(run, strtab_get_sid("fname"));
+	assert(fname_var);
+	assert(fname_var->vc == vc_string);
+
+	fname = fname_var->u.string_v->value;
+	file = fopen(fname, "rt");
+	if (file == NULL) {
+		printf("Error: Failed opening file '%s' for reading.\n",
+		    fname);
+		exit(1);
+	}
+
+	resource = rdata_resource_new();
+	resource->data = (void *) file;
+	res_var = rdata_var_new(vc_resource);
+	res_var->u.resource_v = resource;
+
+	res_val = rdata_value_new();
+	res_val->var = res_var;
+
+	/* Store resource handle into self.f */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	rdata_var_write(self_f_var, res_val);
+}
+
+/** Open a text file for writing. */
+static void bi_textfile_openwrite(run_t *run)
+{
+	rdata_var_t *fname_var;
+	char *fname;
+	FILE *file;
+
+	rdata_resource_t *resource;
+	rdata_var_t *res_var;
+	rdata_value_t *res_val;
+	rdata_var_t *self_f_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called TextFile.OpenWrite()\n");
+#endif
+	fname_var = run_local_vars_lookup(run, strtab_get_sid("fname"));
+	assert(fname_var);
+	assert(fname_var->vc == vc_string);
+
+	fname = fname_var->u.string_v->value;
+	file = fopen(fname, "wt");
+	if (file == NULL) {
+		printf("Error: Failed opening file '%s' for writing.\n",
+		    fname);
+		exit(1);
+	}
+
+	resource = rdata_resource_new();
+	resource->data = (void *) file;
+	res_var = rdata_var_new(vc_resource);
+	res_var->u.resource_v = resource;
+
+	res_val = rdata_value_new();
+	res_val->var = res_var;
+
+	/* Store resource handle into self.f */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	rdata_var_write(self_f_var, res_val);
+}
+
+/** Close a text file. */
+static void bi_textfile_close(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+	run_proc_ar_t *proc_ar;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for Close.\n");
+		exit(1);
+	}
+
+	/* Close the file. */
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Close text file.\n");
+#endif
+	if (fclose(file) != 0) {
+		printf("Error: I/O error while closing file.\n");
+		exit(1);
+	}
+
+	/* Invalidate the resource handle. */
+	self_f_var->u.resource_v->data = NULL;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = NULL;
+}
+
+
+/** Read one line from a text file. */
+static void bi_textfile_readline(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+
+	rdata_string_t *str;
+	rdata_var_t *str_var;
+	rdata_value_t *str_val;
+	rdata_item_t *str_item;
+
+	run_proc_ar_t *proc_ar;
+	char *cp;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for ReadLine.\n");
+		exit(1);
+	}
+
+	/* Check and read. */
+
+	if (feof(file)) {
+		printf("Error: Reading beyond end of file.\n");
+		exit(1);
+	}
+
+	if (fgets(line_buf, LINE_BUF_SIZE, file) == NULL)
+		line_buf[0] = '\0';
+
+	if (ferror(file)) {
+		printf("Error: I/O error while reading file.\n");
+		exit(1);
+	}
+
+	/* Remove trailing newline, if present. */
+
+	cp = line_buf;
+	while (*cp != '\0')
+		++cp;
+
+	if (cp != line_buf && cp[-1] == '\n')
+		cp[-1] = '\0';
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read '%s' from file.\n", line_buf);
+#endif
+	/* Construct return value. */
+	str = rdata_string_new();
+	str->value = os_str_dup(line_buf);
+
+	str_var = rdata_var_new(vc_string);
+	str_var->u.string_v = str;
+	str_val = rdata_value_new();
+	str_val->var = str_var;
+
+	str_item = rdata_item_new(ic_value);
+	str_item->u.value = str_val;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = str_item;
+}
+
+/** Write one line to a text file. */
+static void bi_textfile_writeline(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+	rdata_var_t *line_var;
+	char *line;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Get 'line' argument. */
+	line_var = run_local_vars_lookup(run, strtab_get_sid("line"));
+	assert(line_var);
+	assert(line_var->vc == vc_string);
+	line = line_var->u.string_v->value;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for WriteLine.\n");
+		exit(1);
+	}
+
+	/* Write and check. */
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Write '%s' to file.\n", line);
+#endif
+	if (fprintf(file, "%s\n", line) < 0) {
+		printf("Error: I/O error while writing file.\n");
+		exit(1);
+	}
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = NULL;
+}
+
+/** Return value of EOF flag. */
+static void bi_textfile_is_eof(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+
+	int eof_flag;
+	rdata_int_t *eof_int;
+	rdata_var_t *eof_var;
+	rdata_value_t *eof_val;
+	rdata_item_t *eof_item;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for EOF check.\n");
+		exit(1);
+	}
+
+	/* Get status of EOF flag. */
+
+	eof_flag = feof(file) ? 1 : 0;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read EOF flag '%d'.\n", eof_flag);
+#endif
+	/* Construct return value. */
+	eof_int = rdata_int_new();
+	eof_int->value = eof_flag;
+
+	eof_var = rdata_var_new(vc_int);
+	eof_var->u.int_v = eof_int;
+	eof_val = rdata_value_new();
+	eof_val->var = eof_var;
+
+	eof_item = rdata_item_new(ic_value);
+	eof_item->u.value = eof_val;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = eof_item;
+}
Index: uspace/app/sbi/src/builtin/bi_textfile.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin/bi_textfile.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BI_TEXTFILE_H_
+#define BI_TEXTFILE_H_
+
+#include "../mytypes.h"
+
+void bi_textfile_declare(builtin_t *bi);
+void bi_textfile_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin_t.h
===================================================================
--- uspace/app/sbi/src/builtin_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/builtin_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BUILTIN_T_H_
+#define BUILTIN_T_H_
+
+#include "run_t.h"
+
+/** Builtin symbols object
+ *
+ * Aggregates references to builtin symbols.
+ */
+typedef struct builtin {
+	/** Containing program object */
+	struct stree_program *program;
+
+	/** Grandfather object */
+	struct stree_symbol *gf_class;
+} builtin_t;
+
+/** Callback to run for a builtin procedure */
+typedef void (*builtin_proc_t)(run_t *);
+
+#endif
Index: uspace/app/sbi/src/compat.h
===================================================================
--- uspace/app/sbi/src/compat.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/compat.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file HelenOS compatibility hacks.
+ *
+ * This must be included later than HelenOS's list.h.
+ * XXX A better way must be found than this.
+ */
+
+#ifndef COMPAT_H_
+#define COMPAT_H_
+
+#ifdef __HELENOS__
+
+/*
+ * Avoid name conflicts with ADT library.
+ */
+#define list_append sbi_list_append
+#define list_prepend sbi_list_prepend
+#define list_remove sbi_list_remove
+
+#endif
+
+#endif
Index: uspace/app/sbi/src/debug.h
===================================================================
--- uspace/app/sbi/src/debug.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/debug.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+/** Uncomment this to get verbose debugging messages during parsing. */
+//#define DEBUG_PARSE_TRACE
+
+/**
+ *Uncomment this to get extra verbose messages from parser's lexing
+ * primitives.
+ */
+//#define DEBUG_LPARSE_TRACE
+
+/** Uncomment this to get verbose debugging messagges during typing. */
+//#define DEBUG_TYPE_TRACE
+
+/** Uncomment this to get verbose debugging messages during execution. */
+//#define DEBUG_RUN_TRACE
+
+#endif
Index: uspace/app/sbi/src/imode.c
===================================================================
--- uspace/app/sbi/src/imode.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/imode.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Interactive mode.
+ *
+ * In interactive mode the user types in statements. As soon as the outermost
+ * statement is complete (terminated with ';' or 'end'), the interpreter
+ * executes it. Otherwise it prompts the user until the entire statement
+ * is read in.
+ *
+ * The user interface depends on the OS. In HelenOS we use the CLUI library
+ * which gives us rich line editing capabilities.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ancr.h"
+#include "assert.h"
+#include "builtin.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "rdata.h"
+#include "stree.h"
+#include "strtab.h"
+#include "stype.h"
+#include "input.h"
+#include "lex.h"
+#include "parse.h"
+#include "run.h"
+
+#include "imode.h"
+
+/** Run in interactive mode.
+ *
+ * Repeatedly read in statements from the user and execute them.
+ */
+void imode_run(void)
+{
+	input_t *input;
+	lex_t lex;
+	parse_t parse;
+	stree_program_t *program;
+	stree_stat_t *stat;
+	stree_proc_t *proc;
+	stree_fun_t *fun;
+	stree_symbol_t *fun_sym;
+	stype_t stype;
+	stype_block_vr_t *block_vr;
+	list_node_t *bvr_n;
+	rdata_item_t *rexpr;
+	rdata_item_t *rexpr_vi;
+
+	run_t run;
+	run_proc_ar_t *proc_ar;
+
+	bool_t quit_im;
+
+	/* Create an empty program. */
+	program = stree_program_new();
+	program->module = stree_module_new();
+
+	/* Declare builtin symbols. */
+	builtin_declare(program);
+
+	/* Resolve ancestry. */
+	ancr_module_process(program, program->module);
+
+	/* Construct typing context. */
+	stype.program = program;
+	stype.proc_vr = stype_proc_vr_new();
+	list_init(&stype.proc_vr->block_vr);
+	stype.current_csi = NULL;
+	proc = stree_proc_new();
+
+	fun = stree_fun_new();
+	fun_sym = stree_symbol_new(sc_fun);
+	fun_sym->u.fun = fun;
+	fun->name = stree_ident_new();
+	fun->name->sid = strtab_get_sid("$imode");
+
+	stype.proc_vr->proc = proc;
+	fun->symbol = fun_sym;
+	proc->outer_symbol = fun_sym;
+
+	/* Create block visit record. */
+	block_vr = stype_block_vr_new();
+	intmap_init(&block_vr->vdecls);
+
+	/* Add block visit record to the stack. */
+	list_append(&stype.proc_vr->block_vr, block_vr);
+
+	/* Construct run context. */
+	run.thread_ar = run_thread_ar_new();
+	list_init(&run.thread_ar->proc_ar);
+	run_proc_ar_create(&run, NULL, proc, &proc_ar);
+	list_append(&run.thread_ar->proc_ar, proc_ar);
+
+	quit_im = b_false;
+	while (quit_im != b_true) {
+		parse.error = b_false;
+		stype.error = b_false;
+
+		input_new_interactive(&input);
+
+		/* Parse input. */
+		lex_init(&lex, input);
+		parse_init(&parse, program, &lex);
+
+		if (lcur_lc(&parse) == lc_eof)
+			break;
+
+		stat = parse_stat(&parse);
+
+		if (parse.error != b_false)
+			continue;
+
+		/* Type statement. */
+		stype_stat(&stype, stat, b_true);
+
+		if (stype.error != b_false)
+			continue;
+
+		/* Run statement. */
+		run_init(&run);
+		run.program = program;
+		run_stat(&run, stat, &rexpr);
+
+		if (rexpr != NULL) {
+			/* Convert expression result to value item. */
+			run_cvt_value_item(&run, rexpr, &rexpr_vi);
+			assert(rexpr_vi->ic == ic_value);
+
+			/* Print result. */
+			printf("Result: ");
+			rdata_value_print(rexpr_vi->u.value);
+			printf("\n");
+		}
+	}
+
+	/* Remove block visit record from the stack, */
+	bvr_n = list_last(&stype.proc_vr->block_vr);
+	assert(list_node_data(bvr_n, stype_block_vr_t *) == block_vr);
+	list_remove(&stype.proc_vr->block_vr, bvr_n);
+
+	printf("\nBye!\n");
+}
Index: uspace/app/sbi/src/imode.h
===================================================================
--- uspace/app/sbi/src/imode.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/imode.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMODE_H_
+#define IMODE_H_
+
+void imode_run(void);
+
+#endif
Index: uspace/app/sbi/src/input.c
===================================================================
--- uspace/app/sbi/src/input.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/input.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Input module
+ *
+ * Reads source code. Currently input can be read from a file (standard
+ * case), from a string literal (when parsing builtin code) or interactively
+ * from the user.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mytypes.h"
+#include "os/os.h"
+#include "strtab.h"
+
+#include "input.h"
+
+/** Size of input buffer. XXX This limits the maximum line length. */
+#define INPUT_BUFFER_SIZE 256
+
+static int input_init_file(input_t *input, char *fname);
+static void input_init_interactive(input_t *input);
+static void input_init_string(input_t *input, const char *str);
+
+/** Create new input object for reading from file.
+ *
+ * @param input		Place to store pointer to new input object.
+ * @param fname		Name of file to read from.
+ *
+ * @return		EOK on success, ENOMEM when allocation fails,
+ *			ENOENT when opening file fails.
+ */
+int input_new_file(input_t **input, char *fname)
+{
+	*input = malloc(sizeof(input_t));
+	if (*input == NULL)
+		return ENOMEM;
+
+	return input_init_file(*input, fname);
+}
+
+/** Create new input object for reading from interactive input.
+ *
+ * @param input		Place to store pointer to new input object.
+ * @return		EOK on success, ENOMEM when allocation fails.
+ */
+int input_new_interactive(input_t **input)
+{
+	*input = malloc(sizeof(input_t));
+	if (*input == NULL)
+		return ENOMEM;
+
+	input_init_interactive(*input);
+	return EOK;
+}
+
+/** Create new input object for reading from string.
+ *
+ * @param input		Place to store pointer to new input object.
+ * @param str		String literal from which to read input.
+ * @return		EOK on success, ENOMEM when allocation fails.
+ */
+int input_new_string(input_t **input, const char *str)
+{
+	*input = malloc(sizeof(input_t));
+	if (*input == NULL)
+		return ENOMEM;
+
+	input_init_string(*input, str);
+	return EOK;
+}
+
+/** Initialize input object for reading from file.
+ *
+ * @param input		Input object.
+ * @param fname		Name of file to read from.
+ *
+ * @return		EOK on success, ENOENT when opening file fails.
+*/
+static int input_init_file(input_t *input, char *fname)
+{
+	FILE *f;
+
+	f = fopen(fname, "rt");
+	if (f == NULL)
+		return ENOENT;
+
+	input->buffer = malloc(INPUT_BUFFER_SIZE);
+	if (input->buffer == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	input->str = NULL;
+	input->line_no = 0;
+	input->fin = f;
+	return EOK;
+}
+
+/** Initialize input object for reading from interactive input.
+ *
+ * @param input		Input object.
+ */
+static void input_init_interactive(input_t *input)
+{
+	input->buffer = malloc(INPUT_BUFFER_SIZE);
+	if (input->buffer == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	input->str = NULL;
+	input->line_no = 0;
+	input->fin = NULL;
+}
+
+/** Initialize input object for reading from string.
+ *
+ * @param input		Input object.
+ * @param str		String literal from which to read input.
+ */
+static void input_init_string(input_t *input, const char *str)
+{
+	input->buffer = malloc(INPUT_BUFFER_SIZE);
+	if (input->buffer == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	input->str = str;
+	input->line_no = 0;
+	input->fin = NULL;
+}
+
+/** Get next line of input.
+ *
+ * The pointer stored in @a line is owned by @a input and is valid until the
+ * next call to input_get_line(). The caller is not to free it. The returned
+ * line is terminated with '\n' if another line is coming (potentially empty).
+ * An empty line ("") signals end of input.
+ *
+ * @param input		Input object.
+ * @param line		Place to store pointer to next line.
+ *
+ * @return		EOK on success, EIO on failure.
+ */
+int input_get_line(input_t *input, char **line)
+{
+	const char *sp;
+	char *dp;
+	char *line_p;
+	size_t cnt;
+
+	if (input->fin != NULL) {
+		/* Reading from file. */
+		if (fgets(input->buffer, INPUT_BUFFER_SIZE, input->fin) == NULL)
+			input->buffer[0] = '\0';
+
+		if (ferror(input->fin))
+			return EIO;
+
+		*line = input->buffer;
+	} else if (input->str != NULL) {
+		/* Reading from a string constant. */
+
+		/* Copy one line. */
+		sp = input->str;
+		dp = input->buffer;
+		cnt = 0;
+		while (*sp != '\n' && *sp != '\0' &&
+		    cnt < INPUT_BUFFER_SIZE - 2) {
+			*dp++ = *sp++;
+		}
+
+		/* Advance to start of next line. */
+		if (*sp == '\n')
+			*dp++ = *sp++;
+
+		*dp++ = '\0';
+		input->str = sp;
+		*line = input->buffer;
+	} else {
+		/* Interactive mode */
+		if (input->line_no == 0)
+			printf("sbi> ");
+		else
+			printf("...  ");
+
+		fflush(stdout);
+		if (os_input_line(&line_p) != EOK)
+			return EIO;
+
+		*line = line_p;
+	}
+
+	++input->line_no;
+	return EOK;
+}
+
+/** Get number of the last provided line of input.
+ *
+ * @param input		Input module.
+ * @return		Line number of the last provided input line (counting
+ *			from 1 up).
+ */
+int input_get_line_no(input_t *input)
+{
+	return input->line_no;
+}
Index: uspace/app/sbi/src/input.h
===================================================================
--- uspace/app/sbi/src/input.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/input.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INPUT_H_
+#define INPUT_H_
+
+#include "mytypes.h"
+
+int input_new_file(input_t **input, char *fname);
+int input_new_interactive(input_t **input);
+int input_new_string(input_t **input, const char *str);
+
+int input_get_line(input_t *input, char **line);
+int input_get_line_no(input_t *input);
+
+#endif
Index: uspace/app/sbi/src/input_t.h
===================================================================
--- uspace/app/sbi/src/input_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/input_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INPUT_T_H_
+#define INPUT_T_H_
+
+#include <stdio.h>
+
+/** Input state object */
+typedef struct input {
+	/** Input file if reading from file. */
+	FILE *fin;
+
+	/** Input string if reading from string. */
+	const char *str;
+
+	/** Buffer holding current line. */
+	char *buffer;
+
+	/** Current line number */
+	int line_no;
+} input_t;
+
+#endif
Index: uspace/app/sbi/src/intmap.c
===================================================================
--- uspace/app/sbi/src/intmap.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/intmap.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Integer map.
+ *
+ * Maps integers to pointers (void *). Current implementation is trivial
+ * (linked list of key-value pairs).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "list.h"
+#include "mytypes.h"
+
+#include "intmap.h"
+
+/** Initialize map.
+ *
+ * @param intmap	Map to initialize.
+ */
+void intmap_init(intmap_t *intmap)
+{
+	list_init(&intmap->elem);
+}
+
+/** Set value corresponding to a key.
+ *
+ * If there already exists a mapping for @a key in the map, it is
+ * silently replaced. If @a value is @c NULL, the mapping for @a key
+ * is removed from the map.
+ *
+ * @param intmap	Map.
+ * @param key		Key (integer).
+ * @param value		Value (must be a pointer) or @c NULL.
+ */
+void intmap_set(intmap_t *intmap, int key, void *value)
+{
+	list_node_t *node;
+	map_elem_t *elem;
+
+	node = list_first(&intmap->elem);
+	while (node != NULL) {
+		elem = list_node_data(node, map_elem_t *);
+		if (elem->key == key) {
+			if (value != NULL) {
+				/* Replace existing value. */
+				elem->value = value;
+			} else {
+				/* Remove map element. */
+				list_remove(&intmap->elem, node);
+				node->data = NULL;
+				free(node);
+			}
+			return;
+		}
+		node = list_next(&intmap->elem, node);
+	}
+
+	/* Allocate new map element and add it to the list. */
+
+	elem = calloc(1, sizeof(map_elem_t));
+	if (elem == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	elem->key = key;
+	elem->value = value;
+	list_append(&intmap->elem, elem);
+}
+
+/** Get value corresponding to a key.
+ *
+ * @param intmap	Map.
+ * @param key		Key for which to retrieve mapping.
+ *
+ * @return		Value correspoding to @a key or @c NULL if no mapping
+ *			exists.
+ */
+void *intmap_get(intmap_t *intmap, int key)
+{
+	list_node_t *node;
+	map_elem_t *elem;
+
+	node = list_first(&intmap->elem);
+	while (node != NULL) {
+		elem = list_node_data(node, map_elem_t *);
+		if (elem->key == key) {
+			return elem->value;
+		}
+		node = list_next(&intmap->elem, node);
+	}
+
+	/* Not found */
+	return NULL;
+}
Index: uspace/app/sbi/src/intmap.h
===================================================================
--- uspace/app/sbi/src/intmap.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/intmap.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INTMAP_H_
+#define INTMAP_H_
+
+#include "mytypes.h"
+
+void intmap_init(intmap_t *intmap);
+void intmap_set(intmap_t *intmap, int key, void *data);
+void *intmap_get(intmap_t *intmap, int key);
+
+#endif
Index: uspace/app/sbi/src/intmap_t.h
===================================================================
--- uspace/app/sbi/src/intmap_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/intmap_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INTMAP_T_H_
+#define INTMAP_T_H_
+
+#include "list_t.h"
+
+typedef struct {
+	int key;
+	void *value;
+} map_elem_t;
+
+typedef struct intmap {
+	list_t elem; /* of (map_elem_t *) */
+} intmap_t;
+
+#endif
Index: uspace/app/sbi/src/lex.c
===================================================================
--- uspace/app/sbi/src/lex.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/lex.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Lexer (lexical analyzer).
+ *
+ * Consumes a text file and produces a sequence of lexical elements (lems).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mytypes.h"
+#include "input.h"
+#include "os/os.h"
+#include "strtab.h"
+
+#include "lex.h"
+
+#define TAB_WIDTH 8
+
+static void lex_touch(lex_t *lex);
+static bool_t lex_read_try(lex_t *lex);
+
+static void lex_skip_comment(lex_t *lex);
+static void lex_skip_ws(lex_t *lex);
+static bool_t is_wstart(char c);
+static bool_t is_wcont(char c);
+static bool_t is_digit(char c);
+static void lex_word(lex_t *lex);
+static void lex_number(lex_t *lex);
+static void lex_string(lex_t *lex);
+static int digit_value(char c);
+
+/* Note: This imposes an implementation limit on identifier length. */
+#define IBUF_SIZE 128
+static char ident_buf[IBUF_SIZE + 1];
+
+/* XXX This imposes an implementation limit on string literal length. */
+#define SLBUF_SIZE 128
+static char strlit_buf[SLBUF_SIZE + 1];
+
+/** Lclass-string pair */
+struct lc_name {
+	lclass_t lclass;
+	const char *name;
+};
+
+/** Keyword names. Used both for printing and recognition. */
+static struct lc_name keywords[] = {
+	{ lc_as,	"as" },
+	{ lc_builtin,	"builtin" },
+	{ lc_class,	"class" },
+	{ lc_constructor,	"constructor" },
+	{ lc_do,	"do" },
+	{ lc_else,	"else" },
+	{ lc_end,	"end" },
+	{ lc_except,	"except" },
+	{ lc_finally,	"finally" },
+	{ lc_for,	"for" },
+	{ lc_fun,	"fun" },
+	{ lc_get,	"get" },
+	{ lc_if,	"if" },
+	{ lc_in,	"in" },
+	{ lc_int,	"int" },
+	{ lc_interface,	"interface" },
+	{ lc_is,	"is" },
+	{ lc_new,	"new" },
+	{ lc_nil,	"nil" },
+	{ lc_override,	"override" },
+	{ lc_packed,	"packed" },
+	{ lc_private,	"private" },
+	{ lc_prop,	"prop" },
+	{ lc_protected,	"protected" },
+	{ lc_public,	"public" },
+	{ lc_raise,	"raise" },
+	{ lc_resource,	"resource" },
+	{ lc_return,	"return" },
+	{ lc_self,	"self" },
+	{ lc_set,	"set" },
+	{ lc_static,	"static" },
+	{ lc_string,	"string" },
+	{ lc_struct,	"struct" },
+	{ lc_then,	"then" },
+	{ lc_this,	"this" },
+	{ lc_var,	"var" },
+	{ lc_with,	"with" },
+	{ lc_while,	"while" },
+	{ lc_yield,	"yield" },
+
+	{ 0,		NULL }
+};
+
+/** Other simple lclasses. Only used for printing. */
+static struct lc_name simple_lc[] = {
+	{ lc_invalid,	"INVALID" },
+	{ lc_eof,	"EOF" },
+
+	/* Operators */
+	{ lc_period,	"." },
+	{ lc_slash,	"/" },
+	{ lc_lparen,	"(" },
+	{ lc_rparen,	")" },
+	{ lc_lsbr,	"[" },
+	{ lc_rsbr,	"]" },
+	{ lc_equal,	"==" },
+	{ lc_notequal,	"!=" },
+	{ lc_lt,	"<" },
+	{ lc_gt,	">" },
+	{ lc_lt_equal,	"<=" },
+	{ lc_gt_equal,	">=" },
+	{ lc_assign,	"=" },
+	{ lc_plus,	"+" },
+	{ lc_increase,	"+=" },
+
+	/* Punctuators */
+	{ lc_comma,	"," },
+	{ lc_colon,	":" },
+	{ lc_scolon,	";" },
+
+	{ 0,		NULL },
+};
+
+/** Print lclass value.
+ *
+ * Prints lclass (lexical element class) value in human-readable form
+ * (for debugging).
+ *
+ * @param lclass	Lclass value for display.
+ */
+void lclass_print(lclass_t lclass)
+{
+	struct lc_name *dp;
+
+	dp = keywords;
+	while (dp->name != NULL) {
+		if (dp->lclass == lclass) {
+			printf("%s", dp->name);
+			return;
+		}
+		++dp;
+	}
+
+	dp = simple_lc;
+	while (dp->name != NULL) {
+		if (dp->lclass == lclass) {
+			printf("%s", dp->name);
+			return;
+		}
+		++dp;
+	}
+
+	switch (lclass) {
+	case lc_ident:
+		printf("ident");
+		break;
+	case lc_lit_int:
+		printf("int_literal");
+		break;
+	case lc_lit_string:
+		printf("string_literal");
+		break;
+	default:
+		printf("<unknown?>");
+		break;
+	}
+}
+
+/** Print lexical element.
+ *
+ * Prints lexical element in human-readable form (for debugging).
+ *
+ * @param lem		Lexical element for display.
+ */
+void lem_print(lem_t *lem)
+{
+	lclass_print(lem->lclass);
+
+	switch (lem->lclass) {
+	case lc_ident:
+		printf("(%d)", lem->u.ident.sid);
+		break;
+	case lc_lit_int:
+		printf("(%d)", lem->u.lit_int.value);
+		break;
+	case lc_lit_string:
+		printf("(\"%s\")", lem->u.lit_string.value);
+	default:
+		break;
+	}
+}
+
+/** Print lem coordinates.
+ *
+ * Print the coordinates (line number, column number) of a lexical element.
+ *
+ * @param lem		Lexical element for coordinate printing.
+ */
+void lem_print_coords(lem_t *lem)
+{
+	printf("%d:%d", lem->line_no, lem->col_0);
+}
+
+/** Initialize lexer instance.
+ *
+ * @param lex		Lexer object to initialize.
+ * @param input		Input to associate with lexer.
+ */
+void lex_init(lex_t *lex, struct input *input)
+{
+	int rc;
+
+	lex->input = input;
+
+	rc = input_get_line(lex->input, &lex->inbuf);
+	if (rc != EOK) {
+		printf("Error reading input.\n");
+		exit(1);
+	}
+
+	lex->ibp = lex->inbuf;
+	lex->col_adj = 0;
+	lex->current_valid = b_true;
+}
+
+/** Advance to next lexical element.
+ *
+ * The new element is read in lazily then it is actually accessed.
+ *
+ * @param lex		Lexer object.
+ */
+void lex_next(lex_t *lex)
+{
+	/* Make sure the current lem has already been read in. */
+	lex_touch(lex);
+
+	/* Force a new lem to be read on next access. */
+	lex->current_valid = b_false;
+}
+
+/** Get current lem.
+ *
+ * The returned pointer is invalidated by next call to lex_next()
+ *
+ * @param lex		Lexer object.
+ */
+lem_t *lex_get_current(lex_t *lex)
+{
+	lex_touch(lex);
+	return &lex->current;
+}
+
+/** Read in the current lexical element (unless already read in).
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_touch(lex_t *lex)
+{
+	bool_t got_lem;
+
+	if (lex->current_valid == b_true)
+		return;
+
+	do {
+		got_lem = lex_read_try(lex);
+	} while (got_lem == b_false);
+
+	lex->current_valid = b_true;
+}
+
+/** Try reading next lexical element.
+ *
+ * Attemps to read the next lexical element. In some cases (such as a comment)
+ * this function will need to give it another try and returns @c b_false
+ * in such case.
+ *
+ * @param lex		Lexer object.
+ * @return		@c b_true on success or @c b_false if it needs
+ *			restarting. On success the lem is stored to
+ *			the current lem in @a lex.
+ */
+static bool_t lex_read_try(lex_t *lex)
+{
+	char *bp;
+
+	lex_skip_ws(lex);
+
+	/*
+	 * Record lem coordinates. Line number we already have. For column
+	 * number we start with position in the input buffer. This works
+	 * for all characters except tab. Thus we keep track of tabs
+	 * separately using col_adj.
+	 */
+	lex->current.line_no = input_get_line_no(lex->input);
+	lex->current.col_0 = 1 + lex->col_adj + (lex->ibp - lex->inbuf);
+
+	bp = lex->ibp;
+
+	if (bp[0] == '\0') {
+		/* End of input */
+		lex->current.lclass = lc_eof;
+		return b_true;
+	}
+
+	if (is_wstart(bp[0])) {
+		lex_word(lex);
+		return b_true;
+	}
+
+	if (is_digit(bp[0])) {
+		lex_number(lex);
+		return b_true;
+	}
+
+	if (bp[0] == '"') {
+		lex_string(lex);
+		return b_true;
+	}
+
+	if (bp[0] == '-' && bp[1] == '-') {
+		lex_skip_comment(lex);
+		return b_false;
+	}
+
+	switch (bp[0]) {
+	case ',': lex->current.lclass = lc_comma; ++bp; break;
+	case ':': lex->current.lclass = lc_colon; ++bp; break;
+	case ';': lex->current.lclass = lc_scolon; ++bp; break;
+
+	case '.': lex->current.lclass = lc_period; ++bp; break;
+	case '/': lex->current.lclass = lc_slash; ++bp; break;
+	case '(': lex->current.lclass = lc_lparen; ++bp; break;
+	case ')': lex->current.lclass = lc_rparen; ++bp; break;
+	case '[': lex->current.lclass = lc_lsbr; ++bp; break;
+	case ']': lex->current.lclass = lc_rsbr; ++bp; break;
+
+	case '=':
+		if (bp[1] == '=') {
+			lex->current.lclass = lc_equal; bp += 2; break;
+		}
+		lex->current.lclass = lc_assign; ++bp; break;
+
+	case '!':
+		if (bp[1] == '=') {
+			lex->current.lclass = lc_notequal; bp += 2; break;
+		}
+		goto invalid;
+
+	case '+':
+		if (bp[1] == '=') {
+			lex->current.lclass = lc_increase; bp += 2; break;
+		}
+		lex->current.lclass = lc_plus; ++bp; break;
+
+	case '<':
+		if (bp[1] == '=') {
+			lex->current.lclass = lc_lt_equal; bp += 2; break;
+		}
+		lex->current.lclass = lc_lt; ++bp; break;
+
+	case '>':
+		if (bp[1] == '=') {
+			lex->current.lclass = lc_gt_equal; bp += 2; break;
+		}
+		lex->current.lclass = lc_gt; ++bp; break;
+
+	default:
+		goto invalid;
+	}
+
+	lex->ibp = bp;
+	return b_true;
+
+invalid:
+	lex->current.lclass = lc_invalid;
+	++bp;
+	lex->ibp = bp;
+
+	return b_true;
+}
+
+/** Lex a word (identifier or keyword).
+ *
+ * Read in a word. This may later turn out to be a keyword or a regular
+ * identifier. It is stored in the current lem in @a lex.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_word(lex_t *lex)
+{
+	struct lc_name *dp;
+	char *bp;
+	int idx;
+
+	bp = lex->ibp;
+	ident_buf[0] = bp[0];
+	idx = 1;
+
+	while (is_wcont(bp[idx])) {
+		if (idx >= IBUF_SIZE) {
+			printf("Error: Identifier too long.\n");
+			exit(1);
+		}
+
+		ident_buf[idx] = bp[idx];
+		++idx;
+	}
+
+	lex->ibp = bp + idx;
+
+	ident_buf[idx] = '\0';
+
+	dp = keywords;
+	while (dp->name != NULL) {
+		if (os_str_cmp(ident_buf, dp->name) == 0) {
+			/* Match */
+			lex->current.lclass = dp->lclass;
+			return;
+		}
+		++dp;
+	}
+
+	/* No matching keyword -- it must be an identifier. */
+	lex->current.lclass = lc_ident;
+	lex->current.u.ident.sid = strtab_get_sid(ident_buf);
+}
+
+/** Lex a numeric literal.
+ *
+ * Reads in a numeric literal and stores it in the current lem in @a lex.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_number(lex_t *lex)
+{
+	char *bp;
+	int value;
+
+	bp = lex->ibp;
+	value = 0;
+
+	while (is_digit(*bp)) {
+		value = value * 10 + digit_value(*bp);
+		++bp;
+	}
+
+	lex->ibp = bp;
+
+	lex->current.lclass = lc_lit_int;
+	lex->current.u.lit_int.value = value;
+}
+
+/** Lex a string literal.
+ *
+ * Reads in a string literal and stores it in the current lem in @a lex.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_string(lex_t *lex)
+{
+	char *bp;
+	int idx;
+
+	bp = lex->ibp + 1;
+	idx = 0;
+
+	while (bp[idx] != '"') {
+		if (idx >= SLBUF_SIZE) {
+			printf("Error: String literal too long.\n");
+			exit(1);
+		}
+
+		if (bp[idx] == '\0') {
+			printf("Error: Unterminated string literal.\n");
+			exit(1);
+		}
+
+		strlit_buf[idx] = bp[idx];
+		++idx;
+	}
+
+	lex->ibp = bp + idx + 1;
+
+	strlit_buf[idx] = '\0';
+
+	lex->current.lclass = lc_lit_string;
+	lex->current.u.lit_string.value = os_str_dup(strlit_buf);
+}
+
+/** Lex a single-line comment.
+ *
+ * This does not produce any lem. The comment is just skipped.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_skip_comment(lex_t *lex)
+{
+	char *bp;
+
+	bp = lex->ibp + 2;
+
+	while (*bp != '\n' && *bp != '\0') {
+		++bp;
+	}
+
+	lex->ibp = bp;
+}
+
+/** Skip whitespace characters.
+ *
+ * This does not produce any lem. The whitespace is just skipped.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_skip_ws(lex_t *lex)
+{
+	char *bp;
+	int rc;
+
+	bp = lex->ibp;
+
+	while (b_true) {
+		while (*bp == ' ' || *bp == '\t') {
+			if (*bp == '\t') {
+				/* XXX This is too simplifed. */
+				lex->col_adj += (TAB_WIDTH - 1);
+			}
+			++bp;
+		}
+
+		if (*bp != '\n')
+			break;
+
+		/* Read next line */
+		rc = input_get_line(lex->input, &lex->inbuf);
+		if (rc != EOK) {
+			printf("Error reading input.\n");
+			exit(1);
+		}
+
+		bp = lex->inbuf;
+		lex->col_adj = 0;
+	}
+
+	lex->ibp = bp;
+}
+
+/** Determine if character can start a word.
+ *
+ * @param c 	Character.
+ * @return	@c b_true if @a c can start a word, @c b_false otherwise.
+ */
+static bool_t is_wstart(char c)
+{
+	return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ||
+	    (c == '_');
+}
+
+/** Determine if character can continue a word.
+ *
+ * @param c 	Character.
+ * @return	@c b_true if @a c can start continue word, @c b_false
+ *		otherwise.
+ */
+static bool_t is_wcont(char c)
+{
+	return is_digit(c) || is_wstart(c);
+}
+
+/** Determine if character is a numeric digit.
+ *
+ * @param c 	Character.
+ * @return	@c b_true if @a c is a numeric digit, @c b_false otherwise.
+ */
+static bool_t is_digit(char c)
+{
+	return ((c >= '0') && (c <= '9'));
+}
+
+/** Determine numeric value of digit character.
+ *
+ * @param c 	Character, must be a valid decimal digit.
+ * @return	Value of the digit (0-9).
+ */
+static int digit_value(char c)
+{
+	return (c - '0');
+}
Index: uspace/app/sbi/src/lex.h
===================================================================
--- uspace/app/sbi/src/lex.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/lex.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LEX_H_
+#define LEX_H_
+
+#include "mytypes.h"
+
+void lclass_print(lclass_t lclass);
+void lem_print(lem_t *lem);
+void lem_print_coords(lem_t *lem);
+
+void lex_init(lex_t *lex, struct input *input);
+void lex_next(lex_t *lex);
+lem_t *lex_get_current(lex_t *lex);
+
+#endif
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/lex_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LEX_T_H_
+#define LEX_T_H_
+
+/** Lexical element class */
+typedef enum {
+	lc_invalid,
+	lc_eof,
+
+	lc_ident,
+	lc_lit_int,
+	lc_lit_string,
+
+	/* Keywords */
+	lc_as,
+	lc_builtin,
+	lc_class,
+	lc_constructor,
+	lc_do,
+	lc_else,
+	lc_end,
+	lc_except,
+	lc_finally,
+	lc_for,
+	lc_fun,
+	lc_new,
+	lc_get,
+	lc_if,
+	lc_in,
+	lc_int,
+	lc_interface,
+	lc_is,
+	lc_nil,
+	lc_override,
+	lc_packed,
+	lc_private,
+	lc_prop,
+	lc_protected,
+	lc_public,
+	lc_raise,
+	lc_resource,
+	lc_return,
+	lc_self,
+	lc_set,
+	lc_static,
+	lc_string,
+	lc_struct,
+	lc_then,
+	lc_this,
+	lc_var,
+	lc_with,
+	lc_while,
+	lc_yield,
+
+	/* Operators */
+	lc_period,
+	lc_slash,
+	lc_lparen,
+	lc_rparen,
+	lc_lsbr,
+	lc_rsbr,
+	lc_equal,
+	lc_notequal,
+	lc_lt,
+	lc_gt,
+	lc_lt_equal,
+	lc_gt_equal,
+	lc_assign,
+	lc_plus,
+	lc_increase,
+
+	/* Punctuators */
+	lc_comma,
+	lc_colon,
+	lc_scolon,
+
+	lc__limit
+} lclass_t;
+
+typedef struct {
+	/* String ID */
+	int sid;
+} lem_ident_t;
+
+typedef struct {
+	/* Integer value */
+	int value;
+} lem_lit_int_t;
+
+typedef struct {
+	/* String value */
+	char *value;
+} lem_lit_string_t;
+
+/** Lexical element */
+typedef struct {
+	/* Lexical element class */
+	lclass_t lclass;
+
+	union {
+		lem_ident_t ident;
+		lem_lit_int_t lit_int;
+		lem_lit_string_t lit_string;
+	} u;
+
+	/** Coordinates of this lexical element */
+	int line_no, col_0;
+} lem_t;
+
+/** Lexer state object */
+typedef struct lex {
+	/** Input object */
+	struct input *input;
+
+	/** Lexing buffer */
+	char *inbuf;
+
+	/** Pointer to current position in lexing buffer */
+	char *ibp;
+
+	/** Number of the line currently in inbuf */
+	int ib_line;
+
+	/** Column number adjustment (due to tabs) */
+	int col_adj;
+
+	/** @c b_true if we have the next lem in @c current */
+	bool_t current_valid;
+
+	/** Curent lem (only valid if @c current_valid is true) */
+	lem_t current;
+} lex_t;
+
+#endif
Index: uspace/app/sbi/src/list.c
===================================================================
--- uspace/app/sbi/src/list.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/list.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Doubly linked list.
+ *
+ * Circular, with a head. Nodes structures are allocated separately from data.
+ * Data is stored as 'void *'. We implement several sanity checks to prevent
+ * common usage errors.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "mytypes.h"
+
+#include "list.h"
+
+static list_node_t *list_node_new(void *data);
+static void list_node_delete(list_node_t *node);
+static void list_node_insert_between(list_node_t *n, list_node_t *a, list_node_t *b);
+static void list_node_unlink(list_node_t *n);
+static bool_t list_node_present(list_t *list, list_node_t *node);
+
+/** Initialize list.
+ *
+ * @param list	List to initialize.
+ */
+void list_init(list_t *list)
+{
+	list->head.prev = &list->head;
+	list->head.next = &list->head;
+}
+
+/** Append data to list.
+ *
+ * Create a new list node and append it at the end of the list.
+ *
+ * @param list	Linked list.
+ * @param data	Data for the new node.
+ */
+void list_append(list_t *list, void *data)
+{
+	list_node_t *node;
+
+	node = list_node_new(data);
+	list_node_insert_between(node, list->head.prev, &list->head);
+}
+
+/** Prepend data to list.
+ *
+ * Create a new list node and prepend it at the beginning of the list.
+ *
+ * @param list	Linked list.
+ * @param data	Data for the new node.
+ */
+void list_prepend(list_t *list, void *data)
+{
+	list_node_t *node;
+
+	node = list_node_new(data);
+	list_node_insert_between(node, list->head.prev, &list->head);
+}
+
+/** Remove data from list.
+ *
+ * Removes the given node from a list and destroys it. Any data the node might
+ * have is ignored. If asserts are on, we check wheter node is really present
+ * in the list the caller is requesting us to remove it from.
+ *
+ * @param list	Linked list.
+ * @param node	List node to remove.
+ */
+void list_remove(list_t *list, list_node_t *node)
+{
+	/* Check whether node is in the list as claimed. */
+	assert(list_node_present(list, node));
+	list_node_unlink(node);
+	node->data = NULL;
+	list_node_delete(node);
+}
+
+/** Return first list node or NULL if list is empty.
+ *
+ * @param list	Linked list.
+ * @return	First node of the list or @c NULL if the list is empty.
+ */
+list_node_t *list_first(list_t *list)
+{
+	list_node_t *node;
+
+	assert(list != NULL);
+	node = list->head.next;
+
+	return (node != &list->head) ? node : NULL;
+}
+
+/** Return last list node or NULL if list is empty.
+ *
+ * @param list	Linked list.
+ * @return	Last node of the list or @c NULL if the list is empty.
+ */
+list_node_t *list_last(list_t *list)
+{
+	list_node_t *node;
+
+	assert(list != NULL);
+	node = list->head.prev;
+
+	return (node != &list->head) ? node : NULL;
+}
+
+/** Return next list node or NULL if this was the last one.
+ *
+ * @param list	Linked list.
+ * @param node	Node whose successor we are interested in.
+ * @return	Following list node or @c NULL if @a node is last.
+ */
+list_node_t *list_next(list_t *list, list_node_t *node)
+{
+	(void) list;
+	assert(list != NULL);
+	assert(node != NULL);
+
+	return (node->next != &list->head) ? node->next : NULL;
+}
+
+/** Return previous list node or NULL if this was the last one.
+ *
+ * @param list	Linked list.
+ * @param node	Node whose predecessor we are interested in.
+ * @return	Preceding list node or @c NULL if @a node is last.
+ */
+list_node_t *list_prev(list_t *list, list_node_t *node)
+{
+	(void) list;
+	assert(list != NULL);
+	assert(node != NULL);
+
+	return (node->prev != &list->head) ? node->prev : NULL;
+}
+
+/** Return b_true if list is empty.
+ *
+ * @param list	Linked list.
+ * @return	@c b_true if list is empty, @c b_false otherwise.
+ */
+bool_t list_is_empty(list_t *list)
+{
+	return (list_first(list) == NULL);
+}
+
+/** Change node data.
+ *
+ * Change the data associated with a node.
+ *
+ * @param node	List node.
+ * @param data	New data for node.
+ */
+void list_node_setdata(list_node_t *node, void *data)
+{
+	node->data = data;
+}
+
+/** Create new node.
+ *
+ * @param data	Initial data for node.
+ * @return	New list node.
+ */
+static list_node_t *list_node_new(void *data)
+{
+	list_node_t *node;
+
+	node = malloc(sizeof(list_node_t));
+	if (node == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	node->prev = NULL;
+	node->next = NULL;
+	node->data = data;
+
+	return node;
+}
+
+/** Delete node.
+ *
+ * @param node	List node. Must not take part in any list.
+ */
+static void list_node_delete(list_node_t *node)
+{
+	assert(node->prev == NULL);
+	assert(node->next == NULL);
+	assert(node->data == NULL);
+	free(node);
+}
+
+/** Insert node between two other nodes.
+ *
+ * Inserts @a n between neighboring nodes @a a and @a b.
+ *
+ * @param n	Node to insert.
+ * @param a	Node to precede @a n.
+ * @param b	Node to follow @a n.
+ */
+static void list_node_insert_between(list_node_t *n, list_node_t *a,
+    list_node_t *b)
+{
+	assert(n->prev == NULL);
+	assert(n->next == NULL);
+	n->prev = a;
+	n->next = b;
+
+	assert(a->next == b);
+	assert(b->prev == a);
+	a->next = n;
+	b->prev = n;
+}
+
+/** Unlink node.
+ *
+ * Unlink node from the list it is currently in.
+ * 
+ * @param n	Node to unlink from its current list.
+ */
+static void list_node_unlink(list_node_t *n)
+{
+	list_node_t *a, *b;
+	assert(n->prev != NULL);
+	assert(n->next != NULL);
+
+	a = n->prev;
+	b = n->next;
+
+	assert(a->next == n);
+	assert(b->prev == n);
+
+	a->next = b;
+	b->prev = a;
+
+	n->prev = NULL;
+	n->next = NULL;
+}
+
+/** Check whether @a node is in list @a list.
+ *
+ * @param list	Linked list.
+ * @param node	Node.
+ * @return	@c b_true if @a node is part of @a list, @c b_false otherwise.
+ */
+static bool_t list_node_present(list_t *list, list_node_t *node)
+{
+	list_node_t *m;
+
+	m = list->head.next;
+	while (m != &list->head) {
+		if (m == node)
+			return b_true;
+		m = m->next;
+	}
+
+	return b_false;
+}
Index: uspace/app/sbi/src/list.h
===================================================================
--- uspace/app/sbi/src/list.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/list.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIST_H_
+#define LIST_H_
+
+#include "mytypes.h"
+#include "compat.h"
+
+void list_init(list_t *list);
+void list_append(list_t *list, void *data);
+void list_prepend(list_t *list, void *data);
+void list_remove(list_t *list, list_node_t *node);
+
+list_node_t *list_first(list_t *list);
+list_node_t *list_last(list_t *list);
+list_node_t *list_next(list_t *list, list_node_t *node);
+list_node_t *list_prev(list_t *list, list_node_t *node);
+bool_t list_is_empty(list_t *list);
+
+void list_node_setdata(list_node_t *node, void *data);
+
+#define list_node_data(node, dtype) ((dtype)(node->data))
+
+#endif
Index: uspace/app/sbi/src/list_t.h
===================================================================
--- uspace/app/sbi/src/list_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/list_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIST_T_H_
+#define LIST_T_H_
+
+typedef struct list_node {
+	struct list_node *prev, *next;
+	void *data;
+} list_node_t;
+
+typedef struct list {
+	/** Empty head (no data) */
+	list_node_t head;
+} list_t;
+
+#endif
Index: uspace/app/sbi/src/main.c
===================================================================
--- uspace/app/sbi/src/main.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/main.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Main module.
+ *
+ * Main entry point for SBI, the Sysel Bootstrap Interpreter.
+ * When run without parameters, the interpreter will enter interactive
+ * mode.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ancr.h"
+#include "builtin.h"
+#include "imode.h"
+#include "mytypes.h"
+#include "strtab.h"
+#include "stree.h"
+#include "stype.h"
+#include "input.h"
+#include "lex.h"
+#include "parse.h"
+#include "run.h"
+
+void syntax_print(void);
+
+/** Main entry point.
+ *
+ * @return	Zero on success, non-zero on error.
+ */
+int main(int argc, char *argv[])
+{
+	input_t *input;
+	lex_t lex;
+	parse_t parse;
+	stree_program_t *program;
+	stype_t stype;
+	run_t run;
+	int rc;
+
+	if (argc == 1) {
+		/* Enter interactive mode */
+		strtab_init();
+		imode_run();
+		return 0;
+	}
+
+	if (argc != 2) {
+		syntax_print();
+		exit(1);
+	}
+
+	rc = input_new_file(&input, argv[1]);
+	if (rc != EOK) {
+		printf("Failed opening source file '%s'.\n", argv[1]);
+		exit(1);
+	}
+
+	strtab_init();
+	program = stree_program_new();
+	program->module = stree_module_new();
+
+	/* Declare builtin symbols. */
+	builtin_declare(program);
+
+	/* Parse input file. */
+	lex_init(&lex, input);
+	parse_init(&parse, program, &lex);
+	parse_module(&parse);
+
+	if (parse.error)
+		return 1;
+
+	/* Resolve ancestry. */
+	ancr_module_process(program, parse.cur_mod);
+
+	/* Type program. */
+	stype.program = program;
+	stype.error = b_false;
+	stype_module(&stype, program->module);
+
+	if (stype.error)
+		return 1;
+
+	/* Run program. */
+	run_init(&run);
+	run_program(&run, program);
+
+	return 0;
+}
+
+/** Print command-line syntax help. */
+void syntax_print(void)
+{
+	printf("Missing or invalid arguments.\n");
+	printf("Syntax: sbi <source_file.sy>\n");
+}
Index: uspace/app/sbi/src/mytypes.h
===================================================================
--- uspace/app/sbi/src/mytypes.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/mytypes.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MYTYPES_H_
+#define MYTYPES_H_
+
+/** Boolean type compatible with builtin C 'boolean' operators. */
+typedef enum {
+	b_false = 0,
+	b_true = 1
+} bool_t;
+
+/** Node state for walks. */
+typedef enum {
+	ws_unvisited,
+	ws_active,
+	ws_visited
+} walk_state_t;
+
+/** Error return codes. */
+#include <errno.h>
+#define EOK 0
+
+#include "builtin_t.h"
+#include "input_t.h"
+#include "intmap_t.h"
+#include "lex_t.h"
+#include "list_t.h"
+#include "parse_t.h"
+#include "rdata_t.h"
+#include "run_t.h"
+#include "stree_t.h"
+#include "strtab_t.h"
+#include "stype_t.h"
+#include "tdata_t.h"
+
+#endif
Index: uspace/app/sbi/src/os/helenos.c
===================================================================
--- uspace/app/sbi/src/os/helenos.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/os/helenos.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file HelenOS-specific code. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <task.h>
+#include <tinput.h>
+
+#include "os.h"
+
+/*
+ * Using HelenOS-specific string API.
+ */
+
+static tinput_t *tinput = NULL;
+
+/** Concatenate two strings. */
+char *os_str_acat(const char *a, const char *b)
+{
+	int a_size, b_size;
+	char *str;
+
+	a_size = str_size(a);
+	b_size = str_size(b);
+
+	str = malloc(a_size + b_size + 1);
+	if (str == NULL) {
+		printf("Memory allocation error.\n");
+		exit(1);
+	}
+
+	memcpy(str, a, a_size);
+	memcpy(str + a_size, b, b_size);
+	str[a_size + b_size] = '\0';
+
+	return str;
+}
+
+/** Compare two strings. */
+int os_str_cmp(const char *a, const char *b)
+{
+	return str_cmp(a, b);
+}
+
+/** Duplicate string. */
+char *os_str_dup(const char *str)
+{
+	return str_dup(str);
+}
+
+/** Get character from string at the given index. */
+int os_str_get_char(const char *str, int index, int *out_char)
+{
+	size_t offset;
+	int i;
+	wchar_t c;
+
+	if (index < 0)
+		return EINVAL;
+
+	offset = 0;
+	for (i = 0; i <= index; ++i) {
+		c = str_decode(str, &offset, STR_NO_LIMIT);
+		if (c == '\0')
+			return EINVAL;
+		if (c == U_SPECIAL)
+			return EIO;
+	}
+
+	*out_char = (int) c;
+	return EOK;
+}
+
+/** Read one line of input from the user. */
+int os_input_line(char **ptr)
+{
+	char *line;
+
+	if (tinput == NULL) {
+		tinput = tinput_new();
+		if (tinput == NULL)
+			return EIO;
+	}
+
+	line = tinput_read(tinput);
+	if (line == NULL)
+		return EIO;
+
+	/* XXX Input module needs trailing newline to keep going. */
+	*ptr = os_str_acat(line, "\n");
+	free(line);
+
+	return EOK;
+}
+
+/** Simple command execution. */
+int os_exec(char *const cmd[])
+{
+	task_id_t tid;
+	task_exit_t texit;
+	int retval;
+
+	tid = task_spawn(cmd[0], (char const * const *) cmd);
+	if (tid == 0) {
+		printf("Error: Failed spawning '%s'.\n", cmd[0]);
+		exit(1);
+	}
+
+	/* XXX Handle exit status and return value. */
+	task_wait(tid, &texit, &retval);
+
+	return EOK;
+}
Index: uspace/app/sbi/src/os/os.h
===================================================================
--- uspace/app/sbi/src/os/os.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/os/os.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OS_H_
+#define OS_H_
+
+char *os_str_acat(const char *a, const char *b);
+int os_str_cmp(const char *a, const char *b);
+char *os_str_dup(const char *str);
+int os_str_get_char(const char *str, int index, int *out_char);
+int os_input_line(char **ptr);
+int os_exec(char *const cmd[]);
+
+
+#endif
Index: uspace/app/sbi/src/os/posix.c
===================================================================
--- uspace/app/sbi/src/os/posix.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/os/posix.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file POSIX-specific code. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include "../mytypes.h"
+
+#include "os.h"
+
+/*
+ * The string functions are in fact standard C, but would not work under
+ * HelenOS.
+ */
+
+/** Concatenate two strings. */
+char *os_str_acat(const char *a, const char *b)
+{
+	int a_len, b_len;
+	char *str;
+
+	a_len = strlen(a);
+	b_len = strlen(b);
+
+	str = malloc(a_len + b_len + 1);
+	if (str == NULL) {
+		printf("Memory allocation error.\n");
+		exit(1);
+	}
+
+	memcpy(str, a, a_len);
+	memcpy(str + a_len, b, b_len);
+	str[a_len + b_len] = '\0';
+
+	return str;
+}
+
+/** Compare two strings. */
+int os_str_cmp(const char *a, const char *b)
+{
+	return strcmp(a, b);
+}
+
+/** Duplicate string. */
+char *os_str_dup(const char *str)
+{
+	return strdup(str);
+}
+
+/** Get character from string at the given index. */
+int os_str_get_char(const char *str, int index, int *out_char)
+{
+	size_t len;
+
+	len = strlen(str);
+	if (index < 0 || (size_t) index >= len)
+		return EINVAL;
+
+	*out_char = str[index];
+	return EOK;
+}
+
+#define OS_INPUT_BUFFER_SIZE 256
+static char os_input_buffer[OS_INPUT_BUFFER_SIZE];
+
+/** Read one line of input from the user. */
+int os_input_line(char **ptr)
+{
+	if (fgets(os_input_buffer, OS_INPUT_BUFFER_SIZE, stdin) == NULL)
+		os_input_buffer[0] = '\0';
+
+	if (ferror(stdin)) {
+		*ptr = NULL;
+		return EIO;
+	}
+
+	*ptr = strdup(os_input_buffer);
+	return EOK;
+}
+
+/** Simple command execution. */
+int os_exec(char *const cmd[])
+{
+	pid_t pid;
+	int status;
+
+	pid = vfork();
+
+	if (pid == 0) {
+		execvp(cmd[0], cmd);
+		/* If we get here, exec failed. */
+		exit(1);
+	} else if (pid == -1) {
+		/* fork() failed */
+		return EBUSY;
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		/* waitpid() failed */
+		printf("Error: Waitpid failed.\n");
+		exit(1);
+	}
+
+	if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+		printf("Error: Exec failed or child returned non-zero "
+		    "exit status.\n");
+	}
+
+	return EOK;
+}
Index: uspace/app/sbi/src/p_expr.c
===================================================================
--- uspace/app/sbi/src/p_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/p_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Parse arithmetic expressions. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "debug.h"
+#include "lex.h"
+#include "list.h"
+#include "mytypes.h"
+#include "p_type.h"
+#include "parse.h"
+#include "stree.h"
+
+#include "p_expr.h"
+
+static stree_expr_t *parse_assign(parse_t *parse);
+static stree_expr_t *parse_comparative(parse_t *parse);
+static stree_expr_t *parse_additive(parse_t *parse);
+static stree_expr_t *parse_prefix(parse_t *parse);
+static stree_expr_t *parse_prefix_new(parse_t *parse);
+static stree_expr_t *parse_postfix(parse_t *parse);
+static stree_expr_t *parse_pf_access(parse_t *parse, stree_expr_t *a);
+static stree_expr_t *parse_pf_call(parse_t *parse, stree_expr_t *a);
+static stree_expr_t *parse_pf_index(parse_t *parse, stree_expr_t *a);
+static stree_expr_t *parse_pf_as(parse_t *parse, stree_expr_t *a);
+static stree_expr_t *parse_primitive(parse_t *parse);
+static stree_expr_t *parse_nameref(parse_t *parse);
+static stree_expr_t *parse_lit_int(parse_t *parse);
+static stree_expr_t *parse_lit_ref(parse_t *parse);
+static stree_expr_t *parse_lit_string(parse_t *parse);
+static stree_expr_t *parse_self_ref(parse_t *parse);
+
+static stree_expr_t *parse_recovery_expr(parse_t *parse);
+
+/** Parse expression.
+ *
+ * Input is read from the input object associated with @a parse. If any
+ * error occurs, parse->error will @c b_true when this function
+ * returns. parse->error_bailout will be @c b_true if the error has not
+ * been recovered yet. Similar holds for other parsing functions in this
+ * module.
+ *
+ * @param parse		Parser object.
+ */
+stree_expr_t *parse_expr(parse_t *parse)
+{
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse expression.\n");
+#endif
+	if (parse_is_error(parse))
+		return parse_recovery_expr(parse);
+
+	return parse_assign(parse);
+}
+
+/** Parse assignment expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_assign(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_assign_t *assign;
+
+	a = parse_comparative(parse);
+
+	switch (lcur_lc(parse)) {
+	case lc_assign:
+		assign = stree_assign_new(ac_set);
+		break;
+	case lc_increase:
+		assign = stree_assign_new(ac_increase);
+		break;
+	default:
+		return a;
+	}
+
+	lskip(parse);
+	b = parse_comparative(parse);
+
+	assign->dest = a;
+	assign->src = b;
+
+	tmp = stree_expr_new(ec_assign);
+	tmp->u.assign = assign;
+	return tmp;
+}
+
+/** Parse comparative expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_comparative(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	binop_class_t bc;
+
+	a = parse_additive(parse);
+
+	while (lcur_lc(parse) == lc_equal || lcur_lc(parse) == lc_notequal ||
+	    lcur_lc(parse) == lc_lt || lcur_lc(parse) == lc_gt ||
+	    lcur_lc(parse) == lc_lt_equal || lcur_lc(parse) == lc_gt_equal) {
+
+		if (parse_is_error(parse))
+			break;
+
+		switch (lcur_lc(parse)) {
+		case lc_equal: bc = bo_equal; break;
+		case lc_notequal: bc = bo_notequal; break;
+		case lc_lt: bc = bo_lt; break;
+		case lc_gt: bc = bo_gt; break;
+		case lc_lt_equal: bc = bo_lt_equal; break;
+		case lc_gt_equal: bc = bo_gt_equal; break;
+		default: assert(b_false);
+		}
+
+		lskip(parse);
+		b = parse_additive(parse);
+
+		binop = stree_binop_new(bc);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		a = tmp;
+	}
+
+	return a;
+}
+
+/** Parse additive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_additive(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+
+	a = parse_prefix(parse);
+	while (lcur_lc(parse) == lc_plus) {
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_prefix(parse);
+
+		binop = stree_binop_new(bo_plus);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		a = tmp;
+	}
+
+	return a;
+}
+
+/** Parse prefix expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_prefix(parse_t *parse)
+{
+	stree_expr_t *a;
+
+	switch (lcur_lc(parse)) {
+	case lc_plus:
+		printf("Unimplemented: Unary plus.\n");
+		a = parse_recovery_expr(parse);
+		parse_note_error(parse);
+		break;
+	case lc_new:
+		a = parse_prefix_new(parse);
+		break;
+	default:
+		a = parse_postfix(parse);
+		break;
+	}
+
+	return a;
+}
+
+/** Parse @c new operator.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_prefix_new(parse_t *parse)
+{
+	stree_texpr_t *texpr;
+	stree_new_t *new_op;
+	stree_expr_t *expr;
+
+	lmatch(parse, lc_new);
+	texpr = parse_texpr(parse);
+
+	/* Parenthesis should be present except for arrays. */
+	if (texpr->tc != tc_tindex) {
+		lmatch(parse, lc_lparen);
+		lmatch(parse, lc_rparen);
+	}
+
+	new_op = stree_new_new();
+	new_op->texpr = texpr;
+	expr = stree_expr_new(ec_new);
+	expr->u.new_op = new_op;
+
+	return expr;
+}
+
+/** Parse postfix expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_postfix(parse_t *parse)
+{
+	stree_expr_t *a;
+	stree_expr_t *tmp;
+
+	a = parse_primitive(parse);
+
+	while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lparen ||
+	    lcur_lc(parse) == lc_lsbr || lcur_lc(parse) == lc_as) {
+
+		if (parse_is_error(parse))
+			break;
+
+		switch (lcur_lc(parse)) {
+		case lc_period:
+			tmp = parse_pf_access(parse, a);
+			break;
+		case lc_lparen:
+			tmp = parse_pf_call(parse, a);
+			break;
+		case lc_lsbr:
+			tmp = parse_pf_index(parse, a);
+			break;
+		case lc_as:
+			tmp = parse_pf_as(parse, a);
+			break;
+		default:
+			assert(b_false);
+		}
+
+		a = tmp;
+	}
+
+	return a;
+}
+
+/** Parse member access expression
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_pf_access(parse_t *parse, stree_expr_t *a)
+{
+	stree_ident_t *ident;
+	stree_expr_t *expr;
+	stree_access_t *access;
+
+	lmatch(parse, lc_period);
+	ident = parse_ident(parse);
+
+	access = stree_access_new();
+	access->arg = a;
+	access->member_name = ident;
+
+	expr = stree_expr_new(ec_access);
+	expr->u.access = access;
+
+	return expr;
+}
+
+/** Parse function call expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_pf_call(parse_t *parse, stree_expr_t *a)
+{
+	stree_expr_t *expr;
+	stree_call_t *call;
+	stree_expr_t *arg;
+
+	lmatch(parse, lc_lparen);
+
+	call = stree_call_new();
+	call->fun = a;
+	list_init(&call->args);
+
+	/* Parse function arguments */
+
+	if (lcur_lc(parse) != lc_rparen) {
+		while (!parse_is_error(parse)) {
+			arg = parse_expr(parse);
+			list_append(&call->args, arg);
+
+			if (lcur_lc(parse) == lc_rparen)
+				break;
+			lmatch(parse, lc_comma);
+		}
+	}
+
+	lmatch(parse, lc_rparen);
+
+	expr = stree_expr_new(ec_call);
+	expr->u.call = call;
+
+	return expr;
+}
+
+/** Parse index expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_pf_index(parse_t *parse, stree_expr_t *a)
+{
+	stree_expr_t *expr;
+	stree_index_t *index;
+	stree_expr_t *arg;
+
+	lmatch(parse, lc_lsbr);
+
+	index = stree_index_new();
+	index->base = a;
+	list_init(&index->args);
+
+	/* Parse indices */
+
+	if (lcur_lc(parse) != lc_rsbr) {
+		while (!parse_is_error(parse)) {
+			arg = parse_expr(parse);
+			list_append(&index->args, arg);
+
+			if (lcur_lc(parse) == lc_rsbr)
+				break;
+			lmatch(parse, lc_comma);
+		}
+	}
+
+	lmatch(parse, lc_rsbr);
+
+	expr = stree_expr_new(ec_index);
+	expr->u.index = index;
+
+	return expr;
+}
+
+/** Parse @c as operator.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_pf_as(parse_t *parse, stree_expr_t *a)
+{
+	stree_expr_t *expr;
+	stree_texpr_t *texpr;
+	stree_as_t *as_op;
+
+	lmatch(parse, lc_as);
+	texpr = parse_texpr(parse);
+
+	as_op = stree_as_new();
+	as_op->arg = a;
+	as_op->dtype = texpr;
+	expr = stree_expr_new(ec_as);
+	expr->u.as_op = as_op;
+
+	return expr;
+}
+
+/** Parse primitive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_primitive(parse_t *parse)
+{
+	stree_expr_t *expr;
+
+	switch (lcur_lc(parse)) {
+	case lc_ident:
+		expr = parse_nameref(parse);
+		break;
+	case lc_lit_int:
+		expr = parse_lit_int(parse);
+		break;
+	case lc_nil:
+		expr = parse_lit_ref(parse);
+		break;
+	case lc_lit_string:
+		expr = parse_lit_string(parse);
+		break;
+	case lc_self:
+		expr = parse_self_ref(parse);
+		break;
+	default:
+		lunexpected_error(parse);
+		expr = parse_recovery_expr(parse);
+	}
+
+	return expr;
+}
+
+/** Parse name reference.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_nameref(parse_t *parse)
+{
+	stree_nameref_t *nameref;
+	stree_expr_t *expr;
+
+	nameref = stree_nameref_new();
+	nameref->name = parse_ident(parse);
+	expr = stree_expr_new(ec_nameref);
+	expr->u.nameref = nameref;
+
+	return expr;
+}
+
+/** Parse integer literal.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_lit_int(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+
+	lcheck(parse, lc_lit_int);
+
+	literal = stree_literal_new(ltc_int);
+	literal->u.lit_int.value = lcur(parse)->u.lit_int.value;
+
+	lskip(parse);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+
+	return expr;
+}
+
+/** Parse reference literal (@c nil).
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_lit_ref(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+
+	lmatch(parse, lc_nil);
+
+	literal = stree_literal_new(ltc_ref);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+
+	return expr;
+}
+
+/** Parse string literal.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_lit_string(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+
+	lcheck(parse, lc_lit_string);
+
+	literal = stree_literal_new(ltc_string);
+	literal->u.lit_string.value = lcur(parse)->u.lit_string.value;
+
+	lskip(parse);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+
+	return expr;
+}
+
+/** Parse @c self keyword.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_self_ref(parse_t *parse)
+{
+	stree_self_ref_t *self_ref;
+	stree_expr_t *expr;
+
+	lmatch(parse, lc_self);
+
+	self_ref = stree_self_ref_new();
+
+	expr = stree_expr_new(ec_self_ref);
+	expr->u.self_ref = self_ref;
+
+	return expr;
+}
+
+/** Construct a special recovery expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_recovery_expr(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+
+	(void) parse;
+
+	literal = stree_literal_new(ltc_ref);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+
+	return expr;
+}
Index: uspace/app/sbi/src/p_expr.h
===================================================================
--- uspace/app/sbi/src/p_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/p_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef P_EXPR_H_
+#define P_EXPR_H_
+
+#include "mytypes.h"
+
+stree_expr_t *parse_expr(parse_t *parse);
+
+#endif
Index: uspace/app/sbi/src/p_type.c
===================================================================
--- uspace/app/sbi/src/p_type.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/p_type.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Parse arithmetic expressions. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "debug.h"
+#include "lex.h"
+#include "list.h"
+#include "mytypes.h"
+#include "parse.h"
+#include "p_expr.h"
+#include "stree.h"
+
+#include "p_type.h"
+
+static stree_texpr_t *parse_tapply(parse_t *parse);
+static stree_texpr_t *parse_tpostfix(parse_t *parse);
+static stree_texpr_t *parse_pf_taccess(parse_t *parse, stree_texpr_t *a);
+static stree_texpr_t *parse_pf_tindex(parse_t *parse, stree_texpr_t *a);
+static stree_texpr_t *parse_tprimitive(parse_t *parse);
+static stree_tliteral_t *parse_tliteral(parse_t *parse);
+static stree_tnameref_t *parse_tnameref(parse_t *parse);
+
+static stree_texpr_t *parse_recovery_texpr(parse_t *parse);
+
+/** Parse type expression.
+ *
+ * Input is read from the input object associated with @a parse. If any
+ * error occurs, parse->error will @c b_true when this function
+ * returns. parse->error_bailout will be @c b_true if the error has not
+ * been recovered yet. Similar holds for other parsing functions in this
+ * module.
+ *
+ * @param parse		Parser object.
+ */
+stree_texpr_t *parse_texpr(parse_t *parse)
+{
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse type expression.\n");
+#endif
+	if (parse_is_error(parse))
+		return parse_recovery_texpr(parse);
+
+	return parse_tapply(parse);
+}
+
+/** Parse type application expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tapply(parse_t *parse)
+{
+	stree_texpr_t *a, *b, *tmp;
+	stree_tapply_t *tapply;
+
+	a = parse_tpostfix(parse);
+	while (lcur_lc(parse) == lc_slash) {
+
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_tpostfix(parse);
+
+		tapply = stree_tapply_new();
+		tapply->gtype = a;
+		tapply->targ = b;
+
+		tmp = stree_texpr_new(tc_tapply);
+		tmp->u.tapply = tapply;
+		a = tmp;
+	}
+
+	return a;
+}
+
+/** Parse postfix type expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tpostfix(parse_t *parse)
+{
+	stree_texpr_t *a;
+	stree_texpr_t *tmp;
+
+	a = parse_tprimitive(parse);
+
+	while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lsbr) {
+
+		if (parse_is_error(parse))
+			break;
+
+		switch (lcur_lc(parse)) {
+		case lc_period:
+			tmp = parse_pf_taccess(parse, a);
+			break;
+		case lc_lsbr:
+			tmp = parse_pf_tindex(parse, a);
+			break;
+		default:
+			lunexpected_error(parse);
+			tmp = parse_recovery_texpr(parse);
+			break;
+		}
+
+		a = tmp;
+	}
+
+	return a;
+}
+
+/** Parse access type expression.
+ *
+ * @param parse		Parser object.
+ * @param a		Base expression.
+ */
+static stree_texpr_t *parse_pf_taccess(parse_t *parse, stree_texpr_t *a)
+{
+	stree_texpr_t *texpr;
+	stree_ident_t *ident;
+	stree_taccess_t *taccess;
+
+	lmatch(parse, lc_period);
+	ident = parse_ident(parse);
+
+	taccess = stree_taccess_new();
+	taccess->arg = a;
+	taccess->member_name = ident;
+
+	texpr = stree_texpr_new(tc_taccess);
+	texpr->u.taccess = taccess;
+
+	return texpr;
+}
+
+/** Parse index type expression.
+ *
+ * @param parse		Parser object.
+ * @param a		Base expression.
+ */
+static stree_texpr_t *parse_pf_tindex(parse_t *parse, stree_texpr_t *a)
+{
+	stree_texpr_t *texpr;
+	stree_tindex_t *tindex;
+	stree_expr_t *expr;
+
+	tindex = stree_tindex_new();
+	tindex->base_type = a;
+
+	tindex->n_args = 0;
+	list_init(&tindex->args);
+
+	lmatch(parse, lc_lsbr);
+
+	if (lcur_lc(parse) != lc_rsbr && lcur_lc(parse) != lc_comma) {
+		while (b_true) {
+			if (parse_is_error(parse))
+				break;
+			expr = parse_expr(parse);
+			tindex->n_args += 1;
+			list_append(&tindex->args, expr);
+
+			if (lcur_lc(parse) == lc_rsbr)
+				break;
+
+			lmatch(parse, lc_comma);
+		}
+	} else {
+		tindex->n_args = 1;
+		while (lcur_lc(parse) == lc_comma) {
+			if (parse_is_error(parse))
+				break;
+			lskip(parse);
+			tindex->n_args += 1;
+		}
+	}
+
+	lmatch(parse, lc_rsbr);
+
+	texpr = stree_texpr_new(tc_tindex);
+	texpr->u.tindex = tindex;
+
+	return texpr;
+}
+
+/** Parse primitive type expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tprimitive(parse_t *parse)
+{
+	stree_texpr_t *texpr;
+
+	switch (lcur_lc(parse)) {
+	case lc_ident:
+		texpr = stree_texpr_new(tc_tnameref);
+		texpr->u.tnameref = parse_tnameref(parse);
+		break;
+	case lc_int:
+	case lc_string:
+	case lc_resource:
+		texpr = stree_texpr_new(tc_tliteral);
+		texpr->u.tliteral = parse_tliteral(parse);
+		break;
+	default:
+		lunexpected_error(parse);
+		texpr = parse_recovery_texpr(parse);
+		break;
+	}
+
+	return texpr;
+}
+
+/** Parse type literal.
+ *
+ * @param parse		Parser object.
+ */
+static stree_tliteral_t *parse_tliteral(parse_t *parse)
+{
+	stree_tliteral_t *tliteral;
+	tliteral_class_t tlc;
+
+	switch (lcur_lc(parse)) {
+	case lc_int:
+		tlc = tlc_int;
+		break;
+	case lc_string:
+		tlc = tlc_string;
+		break;
+	case lc_resource:
+		tlc = tlc_resource;
+		break;
+	default:
+		assert(b_false);
+	}
+
+	lskip(parse);
+
+	tliteral = stree_tliteral_new(tlc);
+	return tliteral;
+}
+
+/** Parse type identifier.
+ *
+ * @param parse		Parser object.
+ */
+static stree_tnameref_t *parse_tnameref(parse_t *parse)
+{
+	stree_tnameref_t *tnameref;
+
+	tnameref = stree_tnameref_new();
+	tnameref->name = parse_ident(parse);
+
+	return tnameref;
+}
+
+/** Construct a special type expression fore recovery.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_recovery_texpr(parse_t *parse)
+{
+	stree_tliteral_t *tliteral;
+	stree_texpr_t *texpr;
+
+	(void) parse;
+
+	tliteral = stree_tliteral_new(tlc_int);
+
+	texpr = stree_texpr_new(tc_tliteral);
+	texpr->u.tliteral = tliteral;
+
+	return texpr;
+}
Index: uspace/app/sbi/src/p_type.h
===================================================================
--- uspace/app/sbi/src/p_type.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/p_type.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef P_TYPE_H_
+#define P_TYPE_H_
+
+#include "mytypes.h"
+
+stree_texpr_t *parse_texpr(parse_t *parse);
+
+#endif
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/parse.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,934 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Parser
+ *
+ * Consumes a sequence of lexical elements and produces a syntax tree (stree).
+ * Parsing primitives, module members, statements.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "debug.h"
+#include "lex.h"
+#include "list.h"
+#include "mytypes.h"
+#include "p_expr.h"
+#include "p_type.h"
+#include "stree.h"
+#include "strtab.h"
+#include "symbol.h"
+
+#include "parse.h"
+
+/*
+ * Module members
+ */
+static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
+    stree_csi_t *outer_csi);
+static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi);
+static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi);
+static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse);
+
+static stree_proc_arg_t *parse_proc_arg(parse_t *parse);
+static stree_arg_attr_t *parse_arg_attr(parse_t *parse);
+
+/*
+ * Statements
+ */
+static stree_block_t *parse_block(parse_t *parse);
+
+static stree_vdecl_t *parse_vdecl(parse_t *parse);
+static stree_if_t *parse_if(parse_t *parse);
+static stree_while_t *parse_while(parse_t *parse);
+static stree_for_t *parse_for(parse_t *parse);
+static stree_raise_t *parse_raise(parse_t *parse);
+static stree_return_t *parse_return(parse_t *parse);
+static stree_wef_t *parse_wef(parse_t *parse);
+static stree_exps_t *parse_exps(parse_t *parse);
+
+static stree_except_t *parse_except(parse_t *parse);
+
+void parse_init(parse_t *parse, stree_program_t *prog, struct lex *lex)
+{
+	parse->program = prog;
+	parse->cur_mod = parse->program->module;
+	parse->lex = lex;
+
+	parse->error = b_false;
+	parse->error_bailout = b_false;
+
+	lex_next(parse->lex);
+}
+
+/** Parse module. */
+void parse_module(parse_t *parse)
+{
+	stree_csi_t *csi;
+	stree_modm_t *modm;
+
+	while (lcur_lc(parse) != lc_eof && !parse_is_error(parse)) {
+		switch (lcur_lc(parse)) {
+		case lc_class:
+		case lc_struct:
+		case lc_interface:
+			csi = parse_csi(parse, lcur_lc(parse), NULL);
+			modm = stree_modm_new(mc_csi);
+			modm->u.csi = csi;
+
+			list_append(&parse->cur_mod->members, modm);
+			break;
+		default:
+			lunexpected_error(parse);
+			lex_next(parse->lex);
+			break;
+		}
+
+	}
+}
+
+/** Parse class, struct or interface declaration. */
+static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
+    stree_csi_t *outer_csi)
+{
+	stree_csi_t *csi;
+	csi_class_t cc;
+	stree_csimbr_t *csimbr;
+	stree_symbol_t *symbol;
+
+	switch (dclass) {
+	case lc_class: cc = csi_class; break;
+	case lc_struct: cc = csi_struct; break;
+	case lc_interface: cc = csi_interface; break;
+	default: assert(b_false);
+	}
+
+	lskip(parse);
+
+	csi = stree_csi_new(cc);
+	csi->name = parse_ident(parse);
+
+	symbol = stree_symbol_new(sc_csi);
+	symbol->u.csi = csi;
+	symbol->outer_csi = outer_csi;
+	csi->symbol = symbol;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("parse_csi: csi=%p, csi->name = %p (%s)\n", csi, csi->name,
+	    strtab_get_str(csi->name->sid));
+#endif
+	if (lcur_lc(parse) == lc_colon) {
+		/* Inheritance list */
+		lskip(parse);
+		csi->base_csi_ref = parse_texpr(parse);
+	} else {
+		csi->base_csi_ref = NULL;
+	}
+
+	lmatch(parse, lc_is);
+	list_init(&csi->members);
+
+	/* Parse class, struct or interface members. */
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
+		csimbr = parse_csimbr(parse, csi);
+		list_append(&csi->members, csimbr);
+	}
+
+	lmatch(parse, lc_end);
+
+	return csi;
+}
+
+/** Parse class, struct or interface member. */
+static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_csimbr_t *csimbr;
+
+	stree_csi_t *csi;
+	stree_fun_t *fun;
+	stree_var_t *var;
+	stree_prop_t *prop;
+
+	switch (lcur_lc(parse)) {
+	case lc_class:
+	case lc_struct:
+	case lc_interface:
+		csi = parse_csi(parse, lcur_lc(parse), outer_csi);
+		csimbr = stree_csimbr_new(csimbr_csi);
+		csimbr->u.csi = csi;
+		break;
+	case lc_fun:
+		fun = parse_fun(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_fun);
+		csimbr->u.fun = fun;
+		break;
+	case lc_var:
+		var = parse_var(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_var);
+		csimbr->u.var = var;
+		break;
+	case lc_prop:
+		prop = parse_prop(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_prop);
+		csimbr->u.prop = prop;
+		break;
+	default:
+		lunexpected_error(parse);
+		lex_next(parse->lex);
+	}
+
+	return csimbr;
+}
+
+
+/** Parse member function. */
+static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_fun_t *fun;
+	stree_proc_arg_t *arg;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
+
+	fun = stree_fun_new();
+	symbol = stree_symbol_new(sc_fun);
+
+	symbol->u.fun = fun;
+	symbol->outer_csi = outer_csi;
+	fun->symbol = symbol;
+
+	lmatch(parse, lc_fun);
+	fun->name = parse_ident(parse);
+	lmatch(parse, lc_lparen);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
+#endif
+
+	list_init(&fun->args);
+
+	if (lcur_lc(parse) != lc_rparen) {
+
+		/* Parse formal parameters. */
+		while (!parse_is_error(parse)) {
+			arg = parse_proc_arg(parse);
+
+			if (stree_arg_has_attr(arg, aac_packed)) {
+				fun->varg = arg;
+				break;
+			} else {
+				list_append(&fun->args, arg);
+			}
+
+			if (lcur_lc(parse) == lc_rparen)
+				break;
+
+			lmatch(parse, lc_scolon);
+		}
+	}
+
+	lmatch(parse, lc_rparen);
+
+	if (lcur_lc(parse) == lc_colon) {
+	    	lskip(parse);
+		fun->rtype = parse_texpr(parse);
+	} else {
+		fun->rtype = NULL;
+	}
+
+	list_init(&symbol->attr);
+
+	/* Parse attributes. */
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
+		lskip(parse);
+		attr = parse_symbol_attr(parse);
+		list_append(&symbol->attr, attr);
+	}
+
+	fun->proc = stree_proc_new();
+	fun->proc->outer_symbol = symbol;
+
+	if (lcur_lc(parse) == lc_scolon) {
+		lskip(parse);
+
+		/* This function has no body. */
+		if (!stree_symbol_has_attr(symbol, sac_builtin)) {
+			printf("Error: Function '");
+			symbol_print_fqn(symbol);
+			printf("' has no body.\n");
+			parse_note_error(parse);
+		}
+		fun->proc->body = NULL;
+	} else {
+		lmatch(parse, lc_is);
+		fun->proc->body = parse_block(parse);
+		lmatch(parse, lc_end);
+	}
+
+	return fun;
+}
+
+/** Parse member variable. */
+static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_var_t *var;
+	stree_symbol_t *symbol;
+
+	var = stree_var_new();
+	symbol = stree_symbol_new(sc_var);
+	symbol->u.var = var;
+	symbol->outer_csi = outer_csi;
+	var->symbol = symbol;
+
+	lmatch(parse, lc_var);
+	var->name = parse_ident(parse);
+	lmatch(parse, lc_colon);
+	var->type =  parse_texpr(parse);
+	lmatch(parse, lc_scolon);
+
+	return var;
+}
+
+/** Parse member property. */
+static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_prop_t *prop;
+	stree_symbol_t *symbol;
+
+	stree_ident_t *ident;
+	stree_proc_arg_t *arg;
+
+	prop = stree_prop_new();
+	list_init(&prop->args);
+
+	symbol = stree_symbol_new(sc_prop);
+	symbol->u.prop = prop;
+	symbol->outer_csi = outer_csi;
+	prop->symbol = symbol;
+
+	lmatch(parse, lc_prop);
+
+	if (lcur_lc(parse) == lc_self) {
+		/* Indexed property set */
+
+		/* Use some name that is impossible as identifier. */
+		ident = stree_ident_new();
+		ident->sid = strtab_get_sid(INDEXER_IDENT);
+		prop->name = ident;
+
+		lskip(parse);
+		lmatch(parse, lc_lsbr);
+
+		/* Parse formal parameters. */
+		while (!parse_is_error(parse)) {
+			arg = parse_proc_arg(parse);
+			if (stree_arg_has_attr(arg, aac_packed)) {
+				prop->varg = arg;
+				break;
+			} else {
+				list_append(&prop->args, arg);
+			}
+
+			if (lcur_lc(parse) == lc_rsbr)
+				break;
+
+			lmatch(parse, lc_scolon);
+		}
+
+		lmatch(parse, lc_rsbr);
+	} else {
+		/* Named property */
+		prop->name = parse_ident(parse);
+	}
+
+	lmatch(parse, lc_colon);
+	prop->type = parse_texpr(parse);
+	lmatch(parse, lc_is);
+
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
+		switch (lcur_lc(parse)) {
+		case lc_get:
+			lskip(parse);
+			lmatch(parse, lc_is);
+			if (prop->getter != NULL) {
+				printf("Error: Duplicate getter.\n");
+				(void) parse_block(parse); /* XXX Free */
+				lmatch(parse, lc_end);
+				parse_note_error(parse);
+				break;
+			}
+
+			/* Create setter procedure */
+			prop->getter = stree_proc_new();
+			prop->getter->body = parse_block(parse);
+			prop->getter->outer_symbol = symbol;
+
+			lmatch(parse, lc_end);
+			break;
+		case lc_set:
+			lskip(parse);
+			prop->setter_arg = stree_proc_arg_new();
+			prop->setter_arg->name = parse_ident(parse);
+			prop->setter_arg->type = prop->type;
+			lmatch(parse, lc_is);
+			if (prop->setter != NULL) {
+				printf("Error: Duplicate setter.\n");
+				(void) parse_block(parse); /* XXX Free */
+				lmatch(parse, lc_end);
+				parse_note_error(parse);
+			}
+
+			/* Create setter procedure */
+			prop->setter = stree_proc_new();
+			prop->setter->body = parse_block(parse);
+			prop->setter->outer_symbol = symbol;
+
+			lmatch(parse, lc_end);
+			break;
+		default:
+			lunexpected_error(parse);
+		}
+	}
+
+	lmatch(parse, lc_end);
+
+	return prop;
+}
+
+/** Parse symbol attribute. */
+static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse)
+{
+	stree_symbol_attr_t *attr;
+
+	if (lcur_lc(parse) != lc_builtin) {
+		printf("Error: Unexpected attribute '");
+		lem_print(lcur(parse));
+		printf("'.\n");
+		parse_note_error(parse);
+	}
+
+	lskip(parse);
+
+	attr = stree_symbol_attr_new(sac_builtin);
+	return attr;
+}
+
+/** Parse formal function argument. */
+static stree_proc_arg_t *parse_proc_arg(parse_t *parse)
+{
+	stree_proc_arg_t *arg;
+	stree_arg_attr_t *attr;
+
+	arg = stree_proc_arg_new();
+	arg->name = parse_ident(parse);
+	lmatch(parse, lc_colon);
+	arg->type = parse_texpr(parse);
+
+	list_init(&arg->attr);
+
+	/* Parse attributes. */
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
+		lskip(parse);
+		attr = parse_arg_attr(parse);
+		list_append(&arg->attr, attr);
+	}
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsed arg attr, type=%p.\n", arg->type);
+#endif
+	return arg;
+}
+
+/** Parse argument attribute. */
+static stree_arg_attr_t *parse_arg_attr(parse_t *parse)
+{
+	stree_arg_attr_t *attr;
+
+	if (lcur_lc(parse) != lc_packed) {
+		printf("Error: Unexpected attribute '");
+		lem_print(lcur(parse));
+		printf("'.\n");
+		parse_note_error(parse);
+	}
+
+	lskip(parse);
+
+	attr = stree_arg_attr_new(aac_packed);
+	return attr;
+}
+
+/** Parse statement block. */
+static stree_block_t *parse_block(parse_t *parse)
+{
+	stree_block_t *block;
+	stree_stat_t *stat;
+
+	block = stree_block_new();
+	list_init(&block->stats);
+
+	/* Avoid peeking if there is an error condition. */
+	if (parse_is_error(parse))
+		return block;
+
+	while (terminates_block(lcur_lc(parse)) != b_true &&
+	    !parse_is_error(parse)) {
+
+		stat = parse_stat(parse);
+		list_append(&block->stats, stat);
+	}
+
+	return block;
+}
+
+/** Parse statement. */
+stree_stat_t *parse_stat(parse_t *parse)
+{
+	stree_stat_t *stat;
+
+	stree_vdecl_t *vdecl_s;
+	stree_if_t *if_s;
+	stree_while_t *while_s;
+	stree_for_t *for_s;
+	stree_raise_t *raise_s;
+	stree_return_t *return_s;
+	stree_wef_t *wef_s;
+	stree_exps_t *exp_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse statement.\n");
+#endif
+	switch (lcur_lc(parse)) {
+	case lc_var:
+		vdecl_s = parse_vdecl(parse);
+		stat = stree_stat_new(st_vdecl);
+		stat->u.vdecl_s = vdecl_s;
+		break;
+	case lc_if:
+		if_s = parse_if(parse);
+		stat = stree_stat_new(st_if);
+		stat->u.if_s = if_s;
+		break;
+	case lc_while:
+		while_s = parse_while(parse);
+		stat = stree_stat_new(st_while);
+		stat->u.while_s = while_s;
+		break;
+	case lc_for:
+		for_s = parse_for(parse);
+		stat = stree_stat_new(st_for);
+		stat->u.for_s = for_s;
+		break;
+	case lc_raise:
+		raise_s = parse_raise(parse);
+		stat = stree_stat_new(st_raise);
+		stat->u.raise_s = raise_s;
+		break;
+	case lc_return:
+		return_s = parse_return(parse);
+		stat = stree_stat_new(st_return);
+		stat->u.return_s = return_s;
+		break;
+	case lc_do:
+	case lc_with:
+		wef_s = parse_wef(parse);
+		stat = stree_stat_new(st_wef);
+		stat->u.wef_s = wef_s;
+		break;
+	default:
+		exp_s = parse_exps(parse);
+		stat = stree_stat_new(st_exps);
+		stat->u.exp_s = exp_s;
+		break;
+	}
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsed statement %p\n", stat);
+#endif
+	return stat;
+}
+
+/** Parse variable declaration statement. */
+static stree_vdecl_t *parse_vdecl(parse_t *parse)
+{
+	stree_vdecl_t *vdecl;
+
+	vdecl = stree_vdecl_new();
+
+	lmatch(parse, lc_var);
+	vdecl->name = parse_ident(parse);
+	lmatch(parse, lc_colon);
+	vdecl->type = parse_texpr(parse);
+
+	if (lcur_lc(parse) == lc_assign) {
+		lskip(parse);
+		(void) parse_expr(parse);
+	}
+
+	lmatch(parse, lc_scolon);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsed vdecl for '%s'\n", strtab_get_str(vdecl->name->sid));
+	printf("vdecl = %p, vdecl->name = %p, sid=%d\n",
+	    vdecl, vdecl->name, vdecl->name->sid);
+#endif
+	return vdecl;
+}
+
+/** Parse @c if statement, */
+static stree_if_t *parse_if(parse_t *parse)
+{
+	stree_if_t *if_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'if' statement.\n");
+#endif
+	if_s = stree_if_new();
+
+	lmatch(parse, lc_if);
+	if_s->cond = parse_expr(parse);
+	lmatch(parse, lc_then);
+	if_s->if_block = parse_block(parse);
+
+	if (lcur_lc(parse) == lc_else) {
+		lskip(parse);
+		if_s->else_block = parse_block(parse);
+	} else {
+		if_s->else_block = NULL;
+	}
+
+	lmatch(parse, lc_end);
+	return if_s;
+}
+
+/** Parse @c while statement. */
+static stree_while_t *parse_while(parse_t *parse)
+{
+	stree_while_t *while_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'while' statement.\n");
+#endif
+	while_s = stree_while_new();
+
+	lmatch(parse, lc_while);
+	while_s->cond = parse_expr(parse);
+	lmatch(parse, lc_do);
+	while_s->body = parse_block(parse);
+	lmatch(parse, lc_end);
+
+	return while_s;
+}
+
+/** Parse @c for statement. */
+static stree_for_t *parse_for(parse_t *parse)
+{
+	stree_for_t *for_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'for' statement.\n");
+#endif
+	for_s = stree_for_new();
+
+	lmatch(parse, lc_for);
+	lmatch(parse, lc_ident);
+	lmatch(parse, lc_colon);
+	(void) parse_texpr(parse);
+	lmatch(parse, lc_in);
+	(void) parse_expr(parse);
+	lmatch(parse, lc_do);
+	for_s->body = parse_block(parse);
+	lmatch(parse, lc_end);
+
+	return for_s;
+}
+
+/** Parse @c raise statement. */
+static stree_raise_t *parse_raise(parse_t *parse)
+{
+	stree_raise_t *raise_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'raise' statement.\n");
+#endif
+	raise_s = stree_raise_new();
+	lmatch(parse, lc_raise);
+	raise_s->expr = parse_expr(parse);
+	lmatch(parse, lc_scolon);
+
+	return raise_s;
+}
+
+/** Parse @c return statement. */
+static stree_return_t *parse_return(parse_t *parse)
+{
+	stree_return_t *return_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'return' statement.\n");
+#endif
+	return_s = stree_return_new();
+
+	lmatch(parse, lc_return);
+	return_s->expr = parse_expr(parse);
+	lmatch(parse, lc_scolon);
+
+	return return_s;
+}
+
+/* Parse @c with-except-finally statement. */
+static stree_wef_t *parse_wef(parse_t *parse)
+{
+	stree_wef_t *wef_s;
+	stree_except_t *except_c;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse WEF statement.\n");
+#endif
+	wef_s = stree_wef_new();
+	list_init(&wef_s->except_clauses);
+
+	if (lcur_lc(parse) == lc_with) {
+		lmatch(parse, lc_with);
+		lmatch(parse, lc_ident);
+		lmatch(parse, lc_colon);
+		(void) parse_texpr(parse);
+		lmatch(parse, lc_assign);
+		(void) parse_expr(parse);
+	}
+
+	lmatch(parse, lc_do);
+	wef_s->with_block = parse_block(parse);
+
+	while (lcur_lc(parse) == lc_except && !parse_is_error(parse)) {
+		except_c = parse_except(parse);
+		list_append(&wef_s->except_clauses, except_c);
+	}
+
+	if (lcur_lc(parse) == lc_finally) {
+		lmatch(parse, lc_finally);
+		lmatch(parse, lc_do);
+		wef_s->finally_block = parse_block(parse);
+	} else {
+		wef_s->finally_block = NULL;
+	}
+
+	lmatch(parse, lc_end);
+
+	return wef_s;
+}
+
+/* Parse expression statement. */
+static stree_exps_t *parse_exps(parse_t *parse)
+{
+	stree_expr_t *expr;
+	stree_exps_t *exps;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse expression statement.\n");
+#endif
+	expr = parse_expr(parse);
+	lmatch(parse, lc_scolon);
+
+	exps = stree_exps_new();
+	exps->expr = expr;
+
+	return exps;
+}
+
+/* Parse @c except clause. */
+static stree_except_t *parse_except(parse_t *parse)
+{
+	stree_except_t *except_c;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'except' statement.\n");
+#endif
+	except_c = stree_except_new();
+
+	lmatch(parse, lc_except);
+	except_c->evar = parse_ident(parse);
+	lmatch(parse, lc_colon);
+	except_c->etype = parse_texpr(parse);
+	lmatch(parse, lc_do);
+
+	except_c->block = parse_block(parse);
+
+	return except_c;
+}
+
+/** Parse identifier. */
+stree_ident_t *parse_ident(parse_t *parse)
+{
+	stree_ident_t *ident;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse identifier.\n");
+#endif
+	lcheck(parse, lc_ident);
+	ident = stree_ident_new();
+	ident->sid = lcur(parse)->u.ident.sid;
+	lskip(parse);
+
+	return ident;
+}
+
+/** Signal a parse error, start bailing out from parser. */
+void parse_raise_error(parse_t *parse)
+{
+	parse->error = b_true;
+	parse->error_bailout = b_true;
+}
+
+/** Note a parse error that has been immediately recovered. */
+void parse_note_error(parse_t *parse)
+{
+	parse->error = b_true;
+}
+
+/** Check if we are currently bailing out of parser due to a parse error. */
+bool_t parse_is_error(parse_t *parse)
+{
+	return parse->error_bailout;
+}
+
+/** Recover from parse error bailout.
+ *
+ * Still remember that there was an error, but stop bailing out.
+ */
+void parse_recover_error(parse_t *parse)
+{
+	assert(parse->error == b_true);
+	assert(parse->error_bailout == b_true);
+
+	parse->error_bailout = b_false;
+}
+
+/** Return current lem. */
+lem_t *lcur(parse_t *parse)
+{
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lcur()\n");
+#endif
+	return lex_get_current(parse->lex);
+}
+
+/** Retturn current lem lclass. */
+lclass_t lcur_lc(parse_t *parse)
+{
+	lem_t *lem;
+
+	/*
+	 * This allows us to skip error checking in many places. If there is an
+	 * active error, lcur_lc() returns lc_invalid without reading input.
+	 *
+	 * Without this measure we would have to check for error all the time
+	 * or risk requiring extra input from the user (in interactive mode)
+	 * before actually bailing out from the parser.
+	 */
+	if (parse_is_error(parse))
+		return lc_invalid;
+
+	lem = lcur(parse);
+	return lem->lclass;
+}
+
+/** Skip to next lem. */
+void lskip(parse_t *parse)
+{
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lskip()\n");
+#endif
+	lex_next(parse->lex);
+}
+
+/** Verify that lclass of current lem is @a lc. */
+void lcheck(parse_t *parse, lclass_t lc)
+{
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lcheck(");
+	lclass_print(lc);
+	printf(")\n");
+#endif
+	if (lcur(parse)->lclass != lc) {
+		lem_print_coords(lcur(parse));
+		printf(" Error: expected '"); lclass_print(lc);
+		printf("', got '"); lem_print(lcur(parse));
+		printf("'.\n");
+		parse_raise_error(parse);
+	}
+}
+
+/** Verify that lclass of current lem is @a lc and go to next lem. */
+void lmatch(parse_t *parse, lclass_t lc)
+{
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lmatch(");
+	lclass_print(lc);
+	printf(")\n");
+#endif
+	/*
+	 * This allows us to skip error checking in many places. If there is an
+	 * active error, lmatch() does nothing (similar to parse_block(), etc.
+	 *
+	 * Without this measure we would have to check for error all the time
+	 * or risk requiring extra input from the user (in interactive mode)
+	 * before actually bailing out from the parser.
+	 */
+	if (parse_is_error(parse))
+		return;
+
+	lcheck(parse, lc);
+	lskip(parse);
+}
+
+/** Display generic parsing error. */
+void lunexpected_error(parse_t *parse)
+{
+	lem_print_coords(lcur(parse));
+	printf(" Error: unexpected token '");
+	lem_print(lcur(parse));
+	printf("'.\n");
+	parse_raise_error(parse);
+}
+
+/** Basically tells us whether @a lclass is in next(block). */
+bool_t terminates_block(lclass_t lclass)
+{
+	switch (lclass) {
+	case lc_else:
+	case lc_end:
+	case lc_except:
+	case lc_finally:
+		return b_true;
+	default:
+		return b_false;
+	}
+}
Index: uspace/app/sbi/src/parse.h
===================================================================
--- uspace/app/sbi/src/parse.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/parse.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PARSE_H_
+#define PARSE_H_
+
+#include "mytypes.h"
+
+void parse_init(parse_t *parse, struct stree_program *prog, struct lex *lex);
+void parse_module(parse_t *parse);
+
+stree_stat_t *parse_stat(parse_t *parse);
+stree_ident_t *parse_ident(parse_t *parse);
+
+void parse_raise_error(parse_t *parse);
+void parse_note_error(parse_t *parse);
+bool_t parse_is_error(parse_t *parse);
+void parse_recover_error(parse_t *parse);
+
+/*
+ * Parsing primitives
+ */
+lem_t *lcur(parse_t *parse);
+lclass_t lcur_lc(parse_t *parse);
+void lskip(parse_t *parse);
+void lcheck(parse_t *parse, lclass_t lc);
+void lmatch(parse_t *parse, lclass_t lc);
+void lunexpected_error(parse_t *parse);
+
+bool_t terminates_block(lclass_t lclass);
+
+#endif
Index: uspace/app/sbi/src/parse_t.h
===================================================================
--- uspace/app/sbi/src/parse_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/parse_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PARSE_T_H_
+#define PARSE_T_H_
+
+/** Parser state object */
+typedef struct {
+	/** Lexer object */
+	struct lex *lex;
+
+	/** Program being parsed */
+	struct stree_program *program;
+
+	/** Module currently being parsed */
+	struct stree_module *cur_mod;
+
+	/** @c b_true if an error occured. */
+	bool_t error;
+
+	/** @c b_true if bailing out due to an error. */
+	bool_t error_bailout;
+} parse_t;
+
+#endif
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/rdata.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Run-time data representation. */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "mytypes.h"
+#include "stree.h"
+
+#include "rdata.h"
+
+static void rdata_int_copy(rdata_int_t *src, rdata_int_t **dest);
+static void rdata_string_copy(rdata_string_t *src, rdata_string_t **dest);
+static void rdata_ref_copy(rdata_ref_t *src, rdata_ref_t **dest);
+static void rdata_deleg_copy(rdata_deleg_t *src, rdata_deleg_t **dest);
+static void rdata_array_copy(rdata_array_t *src, rdata_array_t **dest);
+static void rdata_object_copy(rdata_object_t *src, rdata_object_t **dest);
+static void rdata_resource_copy(rdata_resource_t *src,
+    rdata_resource_t **dest);
+
+static int rdata_array_get_dim(rdata_array_t *array);
+
+static void rdata_address_print(rdata_address_t *address);
+static void rdata_var_print(rdata_var_t *var);
+
+
+rdata_item_t *rdata_item_new(item_class_t ic)
+{
+	rdata_item_t *item;
+
+	item = calloc(1, sizeof(rdata_item_t));
+	if (item == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	item->ic = ic;
+	return item;
+}
+
+rdata_addr_var_t *rdata_addr_var_new(void)
+{
+	rdata_addr_var_t *addr_var;
+
+	addr_var = calloc(1, sizeof(rdata_addr_var_t));
+	if (addr_var == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return addr_var;
+}
+
+rdata_aprop_named_t *rdata_aprop_named_new(void)
+{
+	rdata_aprop_named_t *aprop_named;
+
+	aprop_named = calloc(1, sizeof(rdata_aprop_named_t));
+	if (aprop_named == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return aprop_named;
+}
+
+rdata_aprop_indexed_t *rdata_aprop_indexed_new(void)
+{
+	rdata_aprop_indexed_t *aprop_indexed;
+
+	aprop_indexed = calloc(1, sizeof(rdata_aprop_indexed_t));
+	if (aprop_indexed == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return aprop_indexed;
+}
+
+rdata_addr_prop_t *rdata_addr_prop_new(aprop_class_t apc)
+{
+	rdata_addr_prop_t *addr_prop;
+
+	addr_prop = calloc(1, sizeof(rdata_addr_prop_t));
+	if (addr_prop == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	addr_prop->apc = apc;
+	return addr_prop;
+}
+
+rdata_address_t *rdata_address_new(address_class_t ac)
+{
+	rdata_address_t *address;
+
+	address = calloc(1, sizeof(rdata_address_t));
+	if (address == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	address->ac = ac;
+	return address;
+}
+
+rdata_value_t *rdata_value_new(void)
+{
+	rdata_value_t *value;
+
+	value = calloc(1, sizeof(rdata_value_t));
+	if (value == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return value;
+}
+
+rdata_var_t *rdata_var_new(var_class_t vc)
+{
+	rdata_var_t *var;
+
+	var = calloc(1, sizeof(rdata_var_t));
+	if (var == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	var->vc = vc;
+	return var;
+}
+
+rdata_ref_t *rdata_ref_new(void)
+{
+	rdata_ref_t *ref;
+
+	ref = calloc(1, sizeof(rdata_ref_t));
+	if (ref == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return ref;
+}
+
+rdata_deleg_t *rdata_deleg_new(void)
+{
+	rdata_deleg_t *deleg;
+
+	deleg = calloc(1, sizeof(rdata_deleg_t));
+	if (deleg == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return deleg;
+}
+
+rdata_array_t *rdata_array_new(int rank)
+{
+	rdata_array_t *array;
+
+	array = calloc(1, sizeof(rdata_array_t));
+	if (array == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	array->rank = rank;
+	array->extent = calloc(rank, sizeof(int));
+	if (array == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return array;
+}
+
+rdata_object_t *rdata_object_new(void)
+{
+	rdata_object_t *object;
+
+	object = calloc(1, sizeof(rdata_object_t));
+	if (object == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return object;
+}
+
+rdata_int_t *rdata_int_new(void)
+{
+	rdata_int_t *int_v;
+
+	int_v = calloc(1, sizeof(rdata_int_t));
+	if (int_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return int_v;
+}
+
+rdata_string_t *rdata_string_new(void)
+{
+	rdata_string_t *string_v;
+
+	string_v = calloc(1, sizeof(rdata_string_t));
+	if (string_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return string_v;
+}
+
+rdata_resource_t *rdata_resource_new(void)
+{
+	rdata_resource_t *resource_v;
+
+	resource_v = calloc(1, sizeof(rdata_resource_t));
+	if (resource_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return resource_v;
+}
+
+void rdata_array_alloc_element(rdata_array_t *array)
+{
+	int dim, idx;
+
+	dim = rdata_array_get_dim(array);
+
+	array->element = calloc(dim, sizeof(rdata_var_t *));
+	if (array->element == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	for (idx = 0; idx < dim; ++idx) {
+		array->element[idx] = calloc(1, sizeof(rdata_var_t));
+		if (array->element[idx] == NULL) {
+			printf("Memory allocation failed.\n");
+			exit(1);
+		}
+	}
+}
+
+/** Get array dimension.
+ *
+ * Dimension is the total number of elements in an array, in other words,
+ * the product of all extents.
+ */
+static int rdata_array_get_dim(rdata_array_t *array)
+{
+	int didx, dim;
+
+	dim = 1;
+	for (didx = 0; didx < array->rank; ++didx)
+		dim = dim * array->extent[didx];
+
+	return dim;
+}
+
+/** Make copy of a variable. */
+void rdata_var_copy(rdata_var_t *src, rdata_var_t **dest)
+{
+	rdata_var_t *nvar;
+
+	nvar = rdata_var_new(src->vc);
+
+	switch (src->vc) {
+	case vc_int:
+		rdata_int_copy(src->u.int_v, &nvar->u.int_v);
+		break;
+	case vc_string:
+		rdata_string_copy(src->u.string_v, &nvar->u.string_v);
+		break;
+	case vc_ref:
+		rdata_ref_copy(src->u.ref_v, &nvar->u.ref_v);
+		break;
+	case vc_deleg:
+		rdata_deleg_copy(src->u.deleg_v, &nvar->u.deleg_v);
+		break;
+	case vc_array:
+		rdata_array_copy(src->u.array_v, &nvar->u.array_v);
+		break;
+	case vc_object:
+		rdata_object_copy(src->u.object_v, &nvar->u.object_v);
+		break;
+	case vc_resource:
+		rdata_resource_copy(src->u.resource_v, &nvar->u.resource_v);
+		break;
+	}
+
+	*dest = nvar;
+}
+
+static void rdata_int_copy(rdata_int_t *src, rdata_int_t **dest)
+{
+	*dest = rdata_int_new();
+	(*dest)->value = src->value;
+}
+
+static void rdata_string_copy(rdata_string_t *src, rdata_string_t **dest)
+{
+	*dest = rdata_string_new();
+	(*dest)->value = src->value;
+}
+
+static void rdata_ref_copy(rdata_ref_t *src, rdata_ref_t **dest)
+{
+	*dest = rdata_ref_new();
+	(*dest)->vref = src->vref;
+}
+
+static void rdata_deleg_copy(rdata_deleg_t *src, rdata_deleg_t **dest)
+{
+	(void) src; (void) dest;
+	printf("Unimplemented: Copy delegate.\n");
+	exit(1);
+}
+
+static void rdata_array_copy(rdata_array_t *src, rdata_array_t **dest)
+{
+	(void) src; (void) dest;
+	printf("Unimplemented: Copy array.\n");
+	exit(1);
+}
+
+static void rdata_object_copy(rdata_object_t *src, rdata_object_t **dest)
+{
+	(void) src; (void) dest;
+	printf("Unimplemented: Copy object.\n");
+	exit(1);
+}
+
+static void rdata_resource_copy(rdata_resource_t *src, rdata_resource_t **dest)
+{
+	*dest = rdata_resource_new();
+	(*dest)->data = src->data;
+}
+
+/** Read data from a variable.
+ *
+ * Return value stored in variable @a var.
+ */
+void rdata_var_read(rdata_var_t *var, rdata_item_t **ritem)
+{
+	rdata_value_t *value;
+	rdata_var_t *rvar;
+
+	/* Perform a shallow copy of @a var. */
+	rdata_var_copy(var, &rvar);
+
+	value = rdata_value_new();
+	value->var = rvar;
+	*ritem = rdata_item_new(ic_value);
+	(*ritem)->u.value = value;
+}
+
+/** Write data to a variable.
+ *
+ * Store @a value to variable @a var.
+ */
+void rdata_var_write(rdata_var_t *var, rdata_value_t *value)
+{
+	rdata_var_t *nvar;
+
+	/* Perform a shallow copy of @c value->var. */
+	rdata_var_copy(value->var, &nvar);
+
+	/* XXX do this in a prettier way. */
+
+	var->vc = nvar->vc;
+	switch (nvar->vc) {
+	case vc_int: var->u.int_v = nvar->u.int_v; break;
+	case vc_string: var->u.string_v = nvar->u.string_v; break;
+	case vc_ref: var->u.ref_v = nvar->u.ref_v; break;
+	case vc_deleg: var->u.deleg_v = nvar->u.deleg_v; break;
+	case vc_array: var->u.array_v = nvar->u.array_v; break;
+	case vc_object: var->u.object_v = nvar->u.object_v; break;
+	case vc_resource: var->u.resource_v = nvar->u.resource_v; break;
+	}
+
+	/* XXX We should free some stuff around here. */
+}
+
+void rdata_item_print(rdata_item_t *item)
+{
+	if (item == NULL) {
+		printf("none");
+		return;
+	}
+
+	switch (item->ic) {
+	case ic_address:
+		printf("address:");
+		rdata_address_print(item->u.address);
+		break;
+	case ic_value:
+		printf("value:");
+		rdata_value_print(item->u.value);
+		break;
+	}
+}
+
+static void rdata_address_print(rdata_address_t *address)
+{
+	switch (address->ac) {
+	case ac_var:
+		rdata_var_print(address->u.var_a->vref);
+		break;
+	case ac_prop:
+		printf("Warning: Unimplemented: Print property address.\n");
+		break;
+	}
+}
+
+void rdata_value_print(rdata_value_t *value)
+{
+	rdata_var_print(value->var);
+}
+
+static void rdata_var_print(rdata_var_t *var)
+{
+	switch (var->vc) {
+	case vc_int:
+		printf("int(%d)", var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("string(\"%s\")", var->u.string_v->value);
+		break;
+	case vc_ref:
+		printf("ref");
+		break;
+	case vc_deleg:
+		printf("deleg");
+		break;
+	case vc_object:
+		printf("object");
+		break;
+	default:
+		printf("print(%d)\n", var->vc);
+		assert(b_false);
+	}
+}
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/rdata.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RDATA_H_
+#define RDATA_H_
+
+#include "mytypes.h"
+
+rdata_item_t *rdata_item_new(item_class_t ic);
+rdata_addr_var_t *rdata_addr_var_new(void);
+rdata_aprop_named_t *rdata_aprop_named_new(void);
+rdata_aprop_indexed_t *rdata_aprop_indexed_new(void);
+rdata_addr_prop_t *rdata_addr_prop_new(aprop_class_t apc);
+rdata_address_t *rdata_address_new(address_class_t ac);
+rdata_value_t *rdata_value_new(void);
+
+rdata_var_t *rdata_var_new(var_class_t vc);
+rdata_ref_t *rdata_ref_new(void);
+rdata_deleg_t *rdata_deleg_new(void);
+rdata_array_t *rdata_array_new(int rank);
+rdata_object_t *rdata_object_new(void);
+rdata_int_t *rdata_int_new(void);
+rdata_string_t *rdata_string_new(void);
+rdata_resource_t *rdata_resource_new(void);
+
+void rdata_array_alloc_element(rdata_array_t *array);
+void rdata_var_copy(rdata_var_t *src, rdata_var_t **dest);
+
+void rdata_var_read(rdata_var_t *var, rdata_item_t **ritem);
+void rdata_var_write(rdata_var_t *var, rdata_value_t *value);
+
+void rdata_item_print(rdata_item_t *item);
+void rdata_value_print(rdata_value_t *value);
+
+#endif
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/rdata_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Run-time data representation. */
+
+
+#ifndef RDATA_T_H_
+#define RDATA_T_H_
+
+#include "intmap_t.h"
+
+/** Integer variable */
+typedef struct {
+	/*
+	 * Note: Sysel int type should be able to store arbitrarily large
+	 * numbers. But for now we can live with limited width.
+	 */
+	int value;
+} rdata_int_t;
+
+
+/** String variable */
+typedef struct {
+	char *value;
+} rdata_string_t;
+
+/** Reference variable */
+typedef struct {
+	struct rdata_var *vref;
+} rdata_ref_t;
+
+/** Delegate variable
+ *
+ * A delegate variable points to a static or non-static symbol. If the
+ * symbol is non static, @c obj points to the object the symbol instance
+ * belongs to.
+ */
+typedef struct {
+	/** Object or @c NULL if deleg. points to a CSI or static member. */
+	struct rdata_var *obj;
+
+	/** Member symbol. */
+	struct stree_symbol *sym;
+} rdata_deleg_t;
+
+/** Array variable */
+typedef struct {
+	/** Rank */
+	int rank;
+
+	/** Extents (@c rank entries) */
+	int *extent;
+
+	/**
+	 * Elements (extent[0] * extent[1] * ... extent[rank - 1] entries)
+	 * stored in lexicographical order. Each element is (rdata_var_t *).
+	 */
+	struct rdata_var **element;
+} rdata_array_t;
+
+/** Object variable */
+typedef struct {
+	/** Class of this object (symbol) */
+	struct stree_symbol *class_sym;
+
+	/** Map field name SID to field data */
+	intmap_t fields; /* of (rdata_var_t *) */
+} rdata_object_t;
+
+/** Resource handle
+ *
+ * Binding to external data. This type can be used to refer to data used
+ * by builtin functions (such as files).
+ */
+typedef struct {
+	/** Only understood by the right builtin function. */
+	void *data;
+} rdata_resource_t;
+
+typedef enum var_class {
+	/** Integer */
+	vc_int,
+
+	/** String */
+	vc_string,
+
+	/** Reference */
+	vc_ref,
+
+	/** Delegate */
+	vc_deleg,
+
+	/** Array */
+	vc_array,
+
+	/** Object */
+	vc_object,
+
+	/** Interpreter builtin resource */
+	vc_resource
+} var_class_t;
+
+/** Variable.
+ *
+ * A piece of memory holding one of the basic types of data element.
+ * It is addressable (via rdata_var_t *) and mutable, at least from
+ * internal point of view of the interpreter.
+ */
+typedef struct rdata_var {
+	var_class_t vc;
+
+	union {
+		rdata_int_t *int_v;
+		rdata_string_t *string_v;
+		rdata_ref_t *ref_v;
+		rdata_deleg_t *deleg_v;
+		rdata_array_t *array_v;
+		rdata_object_t *object_v;
+		rdata_resource_t *resource_v;
+	} u;
+} rdata_var_t;
+
+/** Address class */
+typedef enum {
+	/** Variable address */
+	ac_var,
+
+	/** Property address */
+	ac_prop
+} address_class_t;
+
+/** Variable address */
+typedef struct {
+	/** Targeted variable */
+	rdata_var_t *vref;
+} rdata_addr_var_t;
+
+/** Named property address */
+typedef struct {
+	/** Delegate to the property */
+	rdata_deleg_t *prop_d;
+} rdata_aprop_named_t;
+
+/** Indexed property address */
+typedef struct {
+	/** Delegate to the object (or CSI) which is being indexed. */
+	rdata_deleg_t *object_d;
+
+	/** Arguments (indices) */
+	list_t args; /* of rdata_item_t */
+} rdata_aprop_indexed_t;
+
+typedef enum {
+	/* Named property address */
+	apc_named,
+
+	/* Indexed property address */
+	apc_indexed
+} aprop_class_t;
+
+/** Property address.
+ *
+ * When an access or index operation is performed on a property, the getter
+ * is run and the prefetched value is stored in @c tvalue. If the property
+ * is a non-scalar value type (a struct), then we might want to point to
+ * the proper @c var node inside it. @c tpos is used for this purpose.
+ *
+ * The assignment operator will modify @c tvalue and at the end the setter
+ * is called to store @c tvalue back into the property.
+ */
+typedef struct {
+	aprop_class_t apc;
+
+	/** Temporary copy of property value or @c NULL when not used. */
+	struct rdata_value *tvalue;
+
+	/**
+	 * Points to the specific var node within @c tvalue that is addressed
+	 * or @c NULL when @c tvalue is not used.
+	 */
+	rdata_var_t *tpos;
+
+	union {
+		rdata_aprop_named_t *named;
+		rdata_aprop_indexed_t *indexed;
+	} u;
+} rdata_addr_prop_t;
+
+/** Address item */
+typedef struct rdata_address {
+	address_class_t ac;
+
+	union {
+		rdata_addr_var_t *var_a;
+		rdata_addr_prop_t *prop_a;
+	} u;
+} rdata_address_t;
+
+/** Value item. */
+typedef struct rdata_value {
+	/**
+	 * Read-only Variable holding a copy of the data. The same @c var
+	 * can be shared between different instances of @c rdata_value_t.
+	 */
+	rdata_var_t *var;
+} rdata_value_t;
+
+typedef enum {
+	/** Address of a variable. */
+	ic_address,
+	/** Value */
+	ic_value
+} item_class_t;
+
+/** Data item.
+ *
+ * Data item is the result of evaluating an expression. An address expression
+ * yields an address item (a.k.a. L-value), a value expression yields a data
+ * item (a.k.a. R-value). This model is used to accomodate semantics of the
+ * assignment operator.
+ */
+typedef struct rdata_item {
+	item_class_t ic;
+
+	union {
+		rdata_address_t *address;
+		rdata_value_t *value;
+	} u;
+} rdata_item_t;
+
+#endif
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Runner (executes the code). */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "builtin.h"
+#include "debug.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "rdata.h"
+#include "run_expr.h"
+#include "run_texpr.h"
+#include "stree.h"
+#include "strtab.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "run.h"
+
+static void run_block(run_t *run, stree_block_t *block);
+static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res);
+static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
+static void run_if(run_t *run, stree_if_t *if_s);
+static void run_while(run_t *run, stree_while_t *while_s);
+static void run_raise(run_t *run, stree_raise_t *raise_s);
+static void run_return(run_t *run, stree_return_t *return_s);
+static void run_wef(run_t *run, stree_wef_t *wef_s);
+
+static bool_t run_exc_match(run_t *run, stree_except_t *except_c);
+static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *aprop);
+
+static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
+    rdata_item_t **ritem);
+static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
+    rdata_value_t *value);
+
+/** Initialize runner instance. */
+void run_init(run_t *run)
+{
+	(void) run;
+}
+
+/** Run program */
+void run_program(run_t *run, stree_program_t *prog)
+{
+	stree_symbol_t *main_fun_sym;
+	stree_fun_t *main_fun;
+	stree_ident_t *fake_ident;
+	list_t main_args;
+	run_proc_ar_t *proc_ar;
+	rdata_item_t *res;
+
+	/* Note down link to program code. */
+	run->program = prog;
+
+	/* Initialize thread activation record. */
+	run->thread_ar = run_thread_ar_new();
+	list_init(&run->thread_ar->proc_ar);
+	run->thread_ar->bo_mode = bm_none;
+
+	/*
+	 * Find entry point @c Main().
+	 */
+	fake_ident = stree_ident_new();
+	fake_ident->sid = strtab_get_sid("Main");
+	main_fun_sym = symbol_find_epoint(prog, fake_ident);
+	if (main_fun_sym == NULL) {
+		printf("Error: Entry point 'Main' not found.\n");
+		exit(1);
+	}
+
+	main_fun = symbol_to_fun(main_fun_sym);
+	assert(main_fun != NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found function '"); symbol_print_fqn(main_fun_sym);
+	printf("'.\n");
+#endif
+
+	/* Run function @c main. */
+	list_init(&main_args);
+	run_proc_ar_create(run, NULL, main_fun->proc, &proc_ar);
+	run_proc_ar_set_args(run, proc_ar, &main_args);
+	run_proc(run, proc_ar, &res);
+
+	/* Check for unhandled exceptions. */
+	if (run->thread_ar->bo_mode != bm_none) {
+		assert(run->thread_ar->bo_mode == bm_exc);
+		printf("Error: Unhandled exception.\n");
+		exit(1);
+	}
+}
+
+/** Run procedure. */
+void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res)
+{
+	stree_proc_t *proc;
+	list_node_t *node;
+
+	proc = proc_ar->proc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Start executing function '");
+	symbol_print_fqn(proc->outer_symbol);
+	printf("'.\n");
+#endif
+	/* Add procedure AR to the stack. */
+	list_append(&run->thread_ar->proc_ar, proc_ar);
+
+	/* Run main procedure block. */
+	if (proc->body != NULL) {
+		run_block(run, proc->body);
+	} else {
+		builtin_run_proc(run, proc);
+	}
+
+	/* Handle bailout. */
+	switch (run->thread_ar->bo_mode) {
+	case bm_stat:
+		printf("Error: Misplaced 'break' statement.\n");
+		exit(1);
+	case bm_proc:
+		run->thread_ar->bo_mode = bm_none;
+		break;
+	default:
+		break;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Done executing procedure '");
+	symbol_print_fqn(proc->outer_symbol);
+	printf("'.\n");
+
+	run_print_fun_bt(run);
+#endif
+	/* Remove procedure activation record from the stack. */
+	node = list_last(&run->thread_ar->proc_ar);
+	assert(list_node_data(node, run_proc_ar_t *) == proc_ar);
+	list_remove(&run->thread_ar->proc_ar, node);
+
+	/* Procedure should not return an address. */
+	assert(proc_ar->retval == NULL || proc_ar->retval->ic == ic_value);
+	*res = proc_ar->retval;
+}
+
+/** Run code block */
+static void run_block(run_t *run, stree_block_t *block)
+{
+	run_proc_ar_t *proc_ar;
+	run_block_ar_t *block_ar;
+	list_node_t *node;
+	stree_stat_t *stat;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing one code block.\n");
+#endif
+
+	/* Create block activation record. */
+	block_ar = run_block_ar_new();
+	intmap_init(&block_ar->vars);
+
+	/* Add block activation record to the stack. */
+	proc_ar = run_get_current_proc_ar(run);
+	list_append(&proc_ar->block_ar, block_ar);
+
+	node = list_first(&block->stats);
+	while (node != NULL) {
+		stat = list_node_data(node, stree_stat_t *);
+		run_stat(run, stat, NULL);
+
+		if (run->thread_ar->bo_mode != bm_none)
+			break;
+
+		node = list_next(&block->stats, node);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Done executing code block.\n");
+#endif
+
+	/* Remove block activation record from the stack. */
+	node = list_last(&proc_ar->block_ar);
+	assert(list_node_data(node, run_block_ar_t *) == block_ar);
+	list_remove(&proc_ar->block_ar, node);
+}
+
+/** Run statement.
+ *
+ * Executes a statement. If @a res is not NULL and the statement is an
+ * expression statement with a value, the value item will be stored to
+ * @a res.
+ *
+ * @param run	Runner object.
+ * @param stat	Statement to run.
+ * @param res	Place to store exps result or NULL if not interested.
+ */
+void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing one statement %p.\n", stat);
+#endif
+
+	if (res != NULL)
+		*res = NULL;
+
+	switch (stat->sc) {
+	case st_exps:
+		run_exps(run, stat->u.exp_s, res);
+		break;
+	case st_vdecl:
+		run_vdecl(run, stat->u.vdecl_s);
+		break;
+	case st_if:
+		run_if(run, stat->u.if_s);
+		break;
+	case st_while:
+		run_while(run, stat->u.while_s);
+		break;
+	case st_raise:
+		run_raise(run, stat->u.raise_s);
+		break;
+	case st_return:
+		run_return(run, stat->u.return_s);
+		break;
+	case st_wef:
+		run_wef(run, stat->u.wef_s);
+		break;
+	case st_for:
+		printf("Ignoring unimplemented statement type %d.\n", stat->sc);
+		break;
+	default:
+		assert(b_false);
+	}
+}
+
+/** Run expression statement.
+ *
+ * Executes an expression statement. If @a res is not NULL then the value
+ * of the expression (or NULL if it has no value) will be stored to @a res.
+ *
+ * @param run	Runner object.
+ * @param exps	Expression statement to run.
+ * @param res	Place to store exps result or NULL if not interested.
+ */
+static void run_exps(run_t *run, stree_exps_t *exps, rdata_item_t **res)
+{
+	rdata_item_t *rexpr;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing expression statement.\n");
+#endif
+	run_expr(run, exps->expr, &rexpr);
+
+	if (res != NULL)
+		*res = rexpr;
+}
+
+/** Run variable declaration statement. */
+static void run_vdecl(run_t *run, stree_vdecl_t *vdecl)
+{
+	run_block_ar_t *block_ar;
+	rdata_var_t *var, *old_var;
+	rdata_int_t *int_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing variable declaration statement.\n");
+#endif
+
+	/* XXX Need to support other variables than int. */
+
+	var = rdata_var_new(vc_int);
+	int_v = rdata_int_new();
+
+	var->u.int_v = int_v;
+	int_v->value = 0;
+
+	block_ar = run_get_current_block_ar(run);
+	old_var = (rdata_var_t *) intmap_get(&block_ar->vars, vdecl->name->sid);
+
+	if (old_var != NULL) {
+		printf("Error: Duplicate variable '%s'\n",
+		    strtab_get_str(vdecl->name->sid));
+		exit(1);
+	}
+
+	intmap_set(&block_ar->vars, vdecl->name->sid, var);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Declared variable '%s'\n", strtab_get_str(vdecl->name->sid));
+#endif
+}
+
+/** Run @c if statement. */
+static void run_if(run_t *run, stree_if_t *if_s)
+{
+	rdata_item_t *rcond;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing if statement.\n");
+#endif
+	run_expr(run, if_s->cond, &rcond);
+
+	if (run_item_boolean_value(run, rcond) == b_true) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking true path.\n");
+#endif
+		run_block(run, if_s->if_block);
+	} else {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking false path.\n");
+#endif
+        	if (if_s->else_block != NULL)
+			run_block(run, if_s->else_block);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("If statement terminated.\n");
+#endif
+}
+
+/** Run @c while statement. */
+static void run_while(run_t *run, stree_while_t *while_s)
+{
+	rdata_item_t *rcond;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing while statement.\n");
+#endif
+	run_expr(run, while_s->cond, &rcond);
+
+	while (run_item_boolean_value(run, rcond) == b_true) {
+		run_block(run, while_s->body);
+		run_expr(run, while_s->cond, &rcond);
+
+		if (run->thread_ar->bo_mode != bm_none)
+			break;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("While statement terminated.\n");
+#endif
+}
+
+/** Run @c raise statement. */
+static void run_raise(run_t *run, stree_raise_t *raise_s)
+{
+	rdata_item_t *rexpr;
+	rdata_item_t *rexpr_vi;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing raise statement.\n");
+#endif
+	run_expr(run, raise_s->expr, &rexpr);
+	run_cvt_value_item(run, rexpr, &rexpr_vi);
+
+	/* Store expression result in thread AR. */
+	run->thread_ar->exc_payload = rexpr_vi->u.value;
+
+	/* Start exception bailout. */
+	run->thread_ar->bo_mode = bm_exc;
+}
+
+/** Run @c return statement. */
+static void run_return(run_t *run, stree_return_t *return_s)
+{
+	rdata_item_t *rexpr;
+	rdata_item_t *rexpr_vi;
+	run_proc_ar_t *proc_ar;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing return statement.\n");
+#endif
+	run_expr(run, return_s->expr, &rexpr);
+	run_cvt_value_item(run, rexpr, &rexpr_vi);
+
+	/* Store expression result in function AR. */
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = rexpr_vi;
+
+	/* Force control to ascend and leave the procedure. */
+	if (run->thread_ar->bo_mode == bm_none)
+		run->thread_ar->bo_mode = bm_proc;
+}
+
+/** Run @c with-except-finally statement. */
+static void run_wef(run_t *run, stree_wef_t *wef_s)
+{
+	list_node_t *except_n;
+	stree_except_t *except_c;
+	rdata_value_t *exc_payload;
+	run_bailout_mode_t bo_mode;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing with-except-finally statement.\n");
+#endif
+	run_block(run, wef_s->with_block);
+
+	if (run->thread_ar->bo_mode == bm_exc) {
+#ifdef DEBUG_RUN_TRACE
+		printf("With statement detected exception.\n");
+#endif
+		/* Reset to normal execution. */
+		run->thread_ar->bo_mode = bm_none;
+
+		/* Look for an except block. */
+		except_n = list_first(&wef_s->except_clauses);
+		while (except_n != NULL) {
+			except_c = list_node_data(except_n, stree_except_t *);
+			if (run_exc_match(run, except_c))
+				break;
+
+			except_n = list_next(&wef_s->except_clauses, except_n);
+		}
+
+		/* If one was found, execute it. */
+		if (except_n != NULL)
+			run_block(run, except_c->block);
+
+		/* Execute finally block */
+		if (wef_s->finally_block != NULL) {
+			/* Put exception on the side temporarily. */
+			bo_mode = run->thread_ar->bo_mode;
+			exc_payload = run->thread_ar->exc_payload;
+
+			run->thread_ar->bo_mode = bm_none;
+			run->thread_ar->exc_payload = NULL;
+
+			run_block(run, wef_s->finally_block);
+
+			if (bo_mode == bm_exc) {
+				/*
+				 * Restore the original exception. If another
+				 * exception occured in the finally block (i.e.
+				 * double fault), it is forgotten.
+				 */
+				run->thread_ar->bo_mode = bm_exc;
+				run->thread_ar->exc_payload = exc_payload;
+			}
+		}
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("With-except-finally statement terminated.\n");
+#endif
+}
+
+/** Determine whether currently active exception matches @c except clause.
+ *
+ * Checks if the currently active exception in the runner object @c run
+ * matches except clause @c except_c. Generates an error if the exception
+ * payload has invalid type (i.e. not an object).
+ *
+ * @param run		Runner object.
+ * @param except_c	@c except clause.
+ * @return		@c b_true if there is a match, @c b_false otherwise.
+ */
+static bool_t run_exc_match(run_t *run, stree_except_t *except_c)
+{
+	rdata_value_t *payload;
+	rdata_var_t *payload_v;
+	rdata_object_t *payload_o;
+	tdata_item_t *etype;
+
+	payload = run->thread_ar->exc_payload;
+	assert(payload != NULL);
+
+	if (payload->var->vc != vc_ref) {
+		printf("Error: Exception payload must be an object "
+		    "(found type %d).\n", payload->var->vc);
+		exit(1);
+	}
+
+	payload_v = payload->var->u.ref_v->vref;
+	if (payload_v->vc != vc_object) {
+		printf("Error: Exception payload must be an object "
+		    "(found type %d).\n", payload_v->vc);
+		exit(1);
+	}
+
+	payload_o = payload_v->u.object_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Active exception: '");
+	symbol_print_fqn(payload_o->class_sym);
+	printf("'.\n");
+#endif
+	assert(payload_o->class_sym != NULL);
+	assert(payload_o->class_sym->sc == sc_csi);
+
+	/* Evaluate type expression in except clause. */
+	run_texpr(run->program, run_get_current_csi(run), except_c->etype,
+	    &etype);
+
+	return tdata_is_csi_derived_from_ti(payload_o->class_sym->u.csi,
+	    etype);
+}
+
+/** Raise an irrecoverable run-time error, start bailing out.
+ *
+ * Raises an error that cannot be handled by the user program.
+ */
+void run_raise_error(run_t *run)
+{
+	run->thread_ar->bo_mode = bm_error;
+	run->thread_ar->error = b_true;
+}
+
+/** Construct a special recovery item. */
+rdata_item_t *run_recovery_item(run_t *run)
+{
+	(void) run;
+	return NULL;
+}
+
+/** Find a local variable in the currently active function. */
+rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name)
+{
+	run_proc_ar_t *proc_ar;
+	run_block_ar_t *block_ar;
+	rdata_var_t *var;
+	list_node_t *node;
+
+	proc_ar = run_get_current_proc_ar(run);
+	node = list_last(&proc_ar->block_ar);
+
+	/* Walk through all block activation records. */
+	while (node != NULL) {
+		block_ar = list_node_data(node, run_block_ar_t *);
+		var = intmap_get(&block_ar->vars, name);
+		if (var != NULL)
+			return var;
+
+		node = list_prev(&proc_ar->block_ar, node);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Get current function activation record. */
+run_proc_ar_t *run_get_current_proc_ar(run_t *run)
+{
+	list_node_t *node;
+
+	node = list_last(&run->thread_ar->proc_ar);
+	return list_node_data(node, run_proc_ar_t *);
+}
+
+/** Get current block activation record. */
+run_block_ar_t *run_get_current_block_ar(run_t *run)
+{
+	run_proc_ar_t *proc_ar;
+	list_node_t *node;
+
+	proc_ar = run_get_current_proc_ar(run);
+
+	node = list_last(&proc_ar->block_ar);
+	return list_node_data(node, run_block_ar_t *);
+}
+
+/** Get current CSI. */
+stree_csi_t *run_get_current_csi(run_t *run)
+{
+	run_proc_ar_t *proc_ar;
+
+	proc_ar = run_get_current_proc_ar(run);
+	return proc_ar->proc->outer_symbol->outer_csi;
+}
+
+/** Construct variable from a value item.
+ *
+ * XXX This should be in fact implemented using existing code as:
+ *
+ * (1) Create a variable of the desired type.
+ * (2) Initialize the variable with the provided value.
+ */
+void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var)
+{
+	rdata_int_t *int_v;
+	rdata_string_t *string_v;
+	rdata_ref_t *ref_v;
+	rdata_var_t *in_var;
+
+	assert(item->ic == ic_value);
+	in_var = item->u.value->var;
+
+	switch (in_var->vc) {
+	case vc_int:
+		*var = rdata_var_new(vc_int);
+		int_v = rdata_int_new();
+
+		(*var)->u.int_v = int_v;
+		int_v->value = item->u.value->var->u.int_v->value;
+		break;
+	case vc_string:
+		*var = rdata_var_new(vc_string);
+		string_v = rdata_string_new();
+
+		(*var)->u.string_v = string_v;
+		string_v->value = item->u.value->var->u.string_v->value;
+		break;
+	case vc_ref:
+		*var = rdata_var_new(vc_ref);
+		ref_v = rdata_ref_new();
+
+		(*var)->u.ref_v = ref_v;
+		ref_v->vref = item->u.value->var->u.ref_v->vref;
+		break;
+	default:
+		printf("Error: Unimplemented argument type.\n");
+		exit(1);
+
+	}
+}
+
+/** Construct a function AR. */
+void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
+    run_proc_ar_t **rproc_ar)
+{
+	run_proc_ar_t *proc_ar;
+	run_block_ar_t *block_ar;
+
+	(void) run;
+
+	/* Create function activation record. */
+	proc_ar = run_proc_ar_new();
+	proc_ar->obj = obj;
+	proc_ar->proc = proc;
+	list_init(&proc_ar->block_ar);
+
+	proc_ar->retval = NULL;
+
+	/* Create special block activation record to hold function arguments. */
+	block_ar = run_block_ar_new();
+	intmap_init(&block_ar->vars);
+	list_append(&proc_ar->block_ar, block_ar);
+
+	*rproc_ar = proc_ar;
+}
+
+/** Fill arguments in a procedure AR.
+ *
+ * When invoking a procedure this is used to store the argument values
+ * in the activation record.
+ */
+void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar, list_t *arg_vals)
+{
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+	list_t *args;
+	stree_proc_arg_t *varg;
+	stree_symbol_t *outer_symbol;
+
+	run_block_ar_t *block_ar;
+	list_node_t *block_ar_n;
+	list_node_t *rarg_n, *parg_n;
+	list_node_t *cn;
+	rdata_item_t *rarg;
+	stree_proc_arg_t *parg;
+	rdata_var_t *var;
+	rdata_var_t *ref_var;
+	rdata_ref_t *ref;
+	rdata_array_t *array;
+	int n_vargs, idx;
+
+	(void) run;
+
+	/* AR should have been created with run_proc_ar_create(). */
+	assert(proc_ar->proc != NULL);
+	outer_symbol = proc_ar->proc->outer_symbol;
+
+	/*
+	 * The procedure being activated should belong to a member function or
+	 * property getter/setter.
+	 */
+	switch (outer_symbol->sc) {
+	case sc_fun:
+		fun = symbol_to_fun(outer_symbol);
+		args = &fun->args;
+		varg = fun->varg;
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_symbol);
+		args = &prop->args;
+		varg = prop->varg;
+		break;
+	default:
+		assert(b_false);
+	}
+
+	/* Fetch first block activation record. */
+	block_ar_n = list_first(&proc_ar->block_ar);
+	assert(block_ar_n != NULL);
+	block_ar = list_node_data(block_ar_n, run_block_ar_t *);
+
+	/* Declare local variables to hold argument values. */
+	rarg_n = list_first(arg_vals);
+	parg_n = list_first(args);
+
+	while (parg_n != NULL) {
+		if (rarg_n == NULL) {
+			printf("Error: Too few arguments to '");
+			symbol_print_fqn(outer_symbol);
+			printf("'.\n");
+			exit(1);
+		}
+
+		rarg = list_node_data(rarg_n, rdata_item_t *);
+		parg = list_node_data(parg_n, stree_proc_arg_t *);
+
+		assert(rarg->ic == ic_value);
+
+		/* Construct a variable from the argument value. */
+		run_value_item_to_var(rarg, &var);
+
+		/* Declare variable using name of formal argument. */
+		intmap_set(&block_ar->vars, parg->name->sid, var);
+
+		rarg_n = list_next(arg_vals, rarg_n);
+		parg_n = list_next(args, parg_n);
+	}
+
+	if (varg != NULL) {
+		/* Function is variadic. Count number of variadic arguments. */
+		cn = rarg_n;
+		n_vargs = 0;
+		while (cn != NULL) {
+			n_vargs += 1;
+			cn = list_next(arg_vals, cn);
+		}
+
+		/* Prepare array to store variadic arguments. */
+		array = rdata_array_new(1);
+		array->extent[0] = n_vargs;
+		rdata_array_alloc_element(array);
+
+		/* Read variadic arguments. */
+
+		idx = 0;
+		while (rarg_n != NULL) {
+			rarg = list_node_data(rarg_n, rdata_item_t *);
+			assert(rarg->ic == ic_value);
+
+			rdata_var_write(array->element[idx], rarg->u.value);
+
+			rarg_n = list_next(arg_vals, rarg_n);
+			idx += 1;
+		}
+
+		var = rdata_var_new(vc_array);
+		var->u.array_v = array;
+
+		/* Create reference to the new array. */
+		ref_var = rdata_var_new(vc_ref);
+		ref = rdata_ref_new();
+		ref_var->u.ref_v = ref;
+		ref->vref = var;
+
+		/* Declare variable using name of formal argument. */
+		intmap_set(&block_ar->vars, varg->name->sid,
+		    ref_var);
+	}
+
+	/* Check for excess real parameters. */
+	if (rarg_n != NULL) {
+		printf("Error: Too many arguments to '");
+		symbol_print_fqn(outer_symbol);
+		printf("'.\n");
+		exit(1);
+	}
+}
+
+/** Fill setter argument in a procedure AR.
+ *
+ * When invoking a setter this is used to store its argument value in its
+ * procedure activation record.
+ */
+void run_proc_ar_set_setter_arg(run_t *run, run_proc_ar_t *proc_ar,
+    rdata_item_t *arg_val)
+{
+	stree_prop_t *prop;
+	run_block_ar_t *block_ar;
+	list_node_t *block_ar_n;
+	rdata_var_t *var;
+
+	(void) run;
+
+	/* AR should have been created with run_proc_ar_create(). */
+	assert(proc_ar->proc != NULL);
+
+	/* The procedure being activated should belong to a property setter. */
+	prop = symbol_to_prop(proc_ar->proc->outer_symbol);
+	assert(prop != NULL);
+	assert(proc_ar->proc == prop->setter);
+
+	/* Fetch first block activation record. */
+	block_ar_n = list_first(&proc_ar->block_ar);
+	assert(block_ar_n != NULL);
+	block_ar = list_node_data(block_ar_n, run_block_ar_t *);
+
+	assert(arg_val->ic == ic_value);
+
+	/* Construct a variable from the argument value. */
+	run_value_item_to_var(arg_val, &var);
+
+	/* Declare variable using name of formal argument. */
+	intmap_set(&block_ar->vars, prop->setter_arg->name->sid, var);
+}
+
+/** Print function activation backtrace. */
+void run_print_fun_bt(run_t *run)
+{
+	list_node_t *node;
+	run_proc_ar_t *proc_ar;
+
+	printf("Backtrace:\n");
+	node = list_last(&run->thread_ar->proc_ar);
+	while (node != NULL) {
+		printf(" * ");
+		proc_ar = list_node_data(node, run_proc_ar_t *);
+		symbol_print_fqn(proc_ar->proc->outer_symbol);
+		printf("\n");
+
+		node = list_prev(&run->thread_ar->proc_ar, node);
+	}
+}
+
+/** Convert item to value item.
+ *
+ * If @a item is a value, we just return a copy. If @a item is an address,
+ * we read from the address.
+ */
+void run_cvt_value_item(run_t *run, rdata_item_t *item, rdata_item_t **ritem)
+{
+	rdata_value_t *value;
+
+	/* 
+	 * This can happen when trying to use output of a function which
+	 * does not return a value.
+	 */
+	if (item == NULL) {
+		printf("Error: Sub-expression has no value.\n");
+		exit(1);
+	}
+
+	/* Address item. Perform read operation. */
+	if (item->ic == ic_address) {
+		run_address_read(run, item->u.address, ritem);
+		return;
+	}
+
+	/* It already is a value, we can share the @c var. */
+	value = rdata_value_new();
+	value->var = item->u.value->var;
+	*ritem = rdata_item_new(ic_value);
+	(*ritem)->u.value = value;
+}
+
+/** Get item var-class.
+ *
+ * Get var-class of @a item, regardless whether it is a value or address.
+ * (I.e. the var class of the value or variable at the given address).
+ */
+var_class_t run_item_get_vc(run_t *run, rdata_item_t *item)
+{
+	var_class_t vc;
+	rdata_var_t *tpos;
+
+	(void) run;
+
+	switch (item->ic) {
+	case ic_value:
+		vc = item->u.value->var->vc;
+		break;
+	case ic_address:
+		switch (item->u.address->ac) {
+		case ac_var:
+			vc = item->u.address->u.var_a->vref->vc;
+			break;
+		case ac_prop:
+			/* Prefetch the value of the property. */
+			tpos = run_aprop_get_tpos(run, item->u.address);
+			vc = tpos->vc;
+			break;
+		default:
+			assert(b_false);
+		}
+		break;
+	default:
+		assert(b_false);
+	}
+
+	return vc;
+}
+
+/** Get pointer to current var node in temporary copy in property address.
+ *
+ * A property address refers to a specific @c var node in a property.
+ * This function will fetch a copy of the property value (by running
+ * its getter) if there is not a temporary copy in the address yet.
+ * It returns a pointer to the relevant @c var node in the temporary
+ * copy.
+ *
+ * @param run	Runner object.
+ * @param addr	Address of class @c ac_prop.
+ * @param	Pointer to var node.
+ */
+static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *addr)
+{
+	rdata_item_t *ritem;
+
+	assert(addr->ac == ac_prop);
+
+	if (addr->u.prop_a->tvalue == NULL) {
+		/* Fetch value of the property. */
+		run_address_read(run, addr, &ritem);
+		assert(ritem->ic == ic_value);
+		addr->u.prop_a->tvalue = ritem->u.value;
+		addr->u.prop_a->tpos = addr->u.prop_a->tvalue->var;
+	}
+
+	return addr->u.prop_a->tpos;
+}
+
+/** Read data from an address.
+ *
+ * Return value stored in a variable at the specified address.
+ */
+void run_address_read(run_t *run, rdata_address_t *address,
+    rdata_item_t **ritem)
+{
+	(void) run;
+
+	switch (address->ac) {
+	case ac_var:
+		rdata_var_read(address->u.var_a->vref, ritem);
+		break;
+	case ac_prop:
+		run_aprop_read(run, address->u.prop_a, ritem);
+		break;
+	}
+
+	assert((*ritem)->ic == ic_value);
+}
+
+/** Write data to an address.
+ *
+ * Store @a value to the variable at @a address.
+ */
+void run_address_write(run_t *run, rdata_address_t *address,
+    rdata_value_t *value)
+{
+	(void) run;
+
+	switch (address->ac) {
+	case ac_var:
+		rdata_var_write(address->u.var_a->vref, value);
+		break;
+	case ac_prop:
+		run_aprop_write(run, address->u.prop_a, value);
+		break;
+	}
+}
+
+static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
+    rdata_item_t **ritem)
+{
+	rdata_deleg_t *deleg;
+	rdata_var_t *obj;
+	stree_symbol_t *prop_sym;
+	stree_prop_t *prop;
+
+	run_proc_ar_t *proc_ar;
+
+	rdata_var_t *cvar;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read from property.\n");
+#endif
+	/*
+	 * If @c tvalue is present, we need to use the relevant part from that
+	 * instead of re-reading the whole thing.
+	 */
+	if (addr_prop->tvalue != NULL) {
+		/* Copy the value */
+		rdata_var_copy(addr_prop->tpos, &cvar);
+		*ritem = rdata_item_new(ic_value);
+		(*ritem)->u.value = rdata_value_new();
+		(*ritem)->u.value->var = cvar;
+		return;
+	}
+
+	if (addr_prop->apc == apc_named)
+		deleg = addr_prop->u.named->prop_d;
+	else
+		deleg = addr_prop->u.indexed->object_d;
+
+	obj = deleg->obj;
+	prop_sym = deleg->sym;
+	prop = symbol_to_prop(prop_sym);
+	assert(prop != NULL);
+
+	if (prop->getter == NULL) {
+		printf("Error: Property is not readable.\n");
+		exit(1);
+	}
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, obj, prop->getter, &proc_ar);
+
+	/* Fill in arguments (indices). */
+	if (addr_prop->apc == apc_indexed) {
+		run_proc_ar_set_args(run, proc_ar,
+		    &addr_prop->u.indexed->args);
+	}
+
+	/* Run getter. */
+	run_proc(run, proc_ar, ritem);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Getter returns ");
+	rdata_item_print(*ritem);
+	printf(".\n");
+	printf("Done reading from property.\n");
+#endif
+}
+
+static void run_aprop_write(run_t *run, rdata_addr_prop_t *addr_prop,
+    rdata_value_t *value)
+{
+	rdata_deleg_t *deleg;
+	rdata_var_t *obj;
+	stree_symbol_t *prop_sym;
+	stree_prop_t *prop;
+
+	run_proc_ar_t *proc_ar;
+	rdata_item_t *vitem;
+	rdata_item_t *ritem;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Write to property.\n");
+#endif
+	/* If @c tvalue is present, we need to modify it and write it back. */
+	if (addr_prop->tvalue != NULL) {
+		printf("Unimplemented: Read-modify-write property access.\n");
+		exit(1);
+	}
+
+	if (addr_prop->apc == apc_named)
+		deleg = addr_prop->u.named->prop_d;
+	else
+		deleg = addr_prop->u.indexed->object_d;
+
+	obj = deleg->obj;
+	prop_sym = deleg->sym;
+	prop = symbol_to_prop(prop_sym);
+	assert(prop != NULL);
+
+	if (prop->setter == NULL) {
+		printf("Error: Property is not writable.\n");
+		exit(1);
+	}
+
+	vitem = rdata_item_new(ic_value);
+	vitem->u.value = value;
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, obj, prop->setter, &proc_ar);
+
+	/* Fill in arguments (indices). */
+	if (addr_prop->apc == apc_indexed) {
+		run_proc_ar_set_args(run, proc_ar,
+		    &addr_prop->u.indexed->args);
+	}
+
+	/* Fill in value argument for setter. */
+	run_proc_ar_set_setter_arg(run, proc_ar, vitem);
+
+	/* Run setter. */
+	run_proc(run, proc_ar, &ritem);
+
+	/* Setter should not return a value. */
+	assert(ritem == NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Done writing to property.\n");
+#endif
+}
+
+/** Return reference to a variable.
+ *
+ * Constructs a reference (value item) pointing to @a var.
+ */
+void run_reference(run_t *run, rdata_var_t *var, rdata_item_t **res)
+{
+	rdata_ref_t *ref;
+	rdata_var_t *ref_var;
+	rdata_value_t *ref_value;
+	rdata_item_t *ref_item;
+
+	(void) run;
+
+	/* Create reference to the variable. */
+	ref = rdata_ref_new();
+	ref_var = rdata_var_new(vc_ref);
+	ref->vref = var;
+	ref_var->u.ref_v = ref;
+
+	/* Construct value of the reference to return. */
+	ref_item = rdata_item_new(ic_value);
+	ref_value = rdata_value_new();
+	ref_item->u.value = ref_value;
+	ref_value->var = ref_var;
+
+	*res = ref_item;
+}
+
+/** Return address of reference target.
+ *
+ * Takes a reference (address or value) and returns the address (item) of
+ * the target of the reference.
+ */
+void run_dereference(run_t *run, rdata_item_t *ref, rdata_item_t **ritem)
+{
+	rdata_item_t *ref_val;
+	rdata_item_t *item;
+	rdata_address_t *address;
+	rdata_addr_var_t *addr_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("run_dereference()\n");
+#endif
+	run_cvt_value_item(run, ref, &ref_val);
+	assert(ref_val->u.value->var->vc == vc_ref);
+
+	item = rdata_item_new(ic_address);
+	address = rdata_address_new(ac_var);
+	addr_var = rdata_addr_var_new();
+	item->u.address = address;
+	address->u.var_a = addr_var;
+	addr_var->vref = ref_val->u.value->var->u.ref_v->vref;
+
+	if (addr_var->vref == NULL) {
+		printf("Error: Accessing null reference.\n");
+		run_raise_error(run);
+		*ritem = run_recovery_item(run);
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("vref set to %p\n", addr_var->vref);
+#endif
+	*ritem = item;
+}
+
+run_thread_ar_t *run_thread_ar_new(void)
+{
+	run_thread_ar_t *thread_ar;
+
+	thread_ar = calloc(1, sizeof(run_thread_ar_t));
+	if (thread_ar == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return thread_ar;
+}
+
+run_proc_ar_t *run_proc_ar_new(void)
+{
+	run_proc_ar_t *proc_ar;
+
+	proc_ar = calloc(1, sizeof(run_proc_ar_t));
+	if (proc_ar == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc_ar;
+}
+
+run_block_ar_t *run_block_ar_new(void)
+{
+	run_block_ar_t *block_ar;
+
+	block_ar = calloc(1, sizeof(run_block_ar_t));
+	if (block_ar == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return block_ar;
+}
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RUN_H_
+#define RUN_H_
+
+#include "mytypes.h"
+
+void run_init(run_t *run);
+void run_program(run_t *run, stree_program_t *prog);
+void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res);
+void run_stat(run_t *run, stree_stat_t *stat, rdata_item_t **res);
+
+void run_print_fun_bt(run_t *run);
+
+void run_raise_error(run_t *run);
+rdata_item_t *run_recovery_item(run_t *run);
+
+rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name);
+run_proc_ar_t *run_get_current_proc_ar(run_t *run);
+run_block_ar_t *run_get_current_block_ar(run_t *run);
+stree_csi_t *run_get_current_csi(run_t *run);
+
+void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var);
+void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar,
+    list_t *arg_vals);
+void run_proc_ar_set_setter_arg(run_t *run, run_proc_ar_t *proc_ar,
+    rdata_item_t *arg_val);
+void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
+    run_proc_ar_t **rproc_ar);
+
+var_class_t run_item_get_vc(run_t *run, rdata_item_t *item);
+void run_cvt_value_item(run_t *run, rdata_item_t *item, rdata_item_t **ritem);
+void run_address_read(run_t *run, rdata_address_t *address,
+    rdata_item_t **ritem);
+void run_address_write(run_t *run, rdata_address_t *address,
+    rdata_value_t *value);
+void run_reference(run_t *run, rdata_var_t *var, rdata_item_t **res);
+void run_dereference(run_t *run, rdata_item_t *ref, rdata_item_t **ritem);
+
+run_thread_ar_t *run_thread_ar_new(void);
+run_proc_ar_t *run_proc_ar_new(void);
+run_block_ar_t *run_block_ar_new(void);
+
+#endif
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Runner (executes the code). */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "debug.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "os/os.h"
+#include "rdata.h"
+#include "run.h"
+#include "run_texpr.h"
+#include "symbol.h"
+#include "stree.h"
+#include "strtab.h"
+#include "tdata.h"
+
+#include "run_expr.h"
+
+static void run_nameref(run_t *run, stree_nameref_t *nameref,
+    rdata_item_t **res);
+
+static void run_literal(run_t *run, stree_literal_t *literal,
+    rdata_item_t **res);
+static void run_lit_int(run_t *run, stree_lit_int_t *lit_int,
+    rdata_item_t **res);
+static void run_lit_ref(run_t *run, stree_lit_ref_t *lit_ref,
+    rdata_item_t **res);
+static void run_lit_string(run_t *run, stree_lit_string_t *lit_string,
+    rdata_item_t **res);
+
+static void run_self_ref(run_t *run, stree_self_ref_t *self_ref,
+    rdata_item_t **res);
+
+static void run_binop(run_t *run, stree_binop_t *binop, rdata_item_t **res);
+static void run_binop_int(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res);
+static void run_binop_string(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res);
+static void run_binop_ref(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res);
+
+static void run_unop(run_t *run, stree_unop_t *unop, rdata_item_t **res);
+static void run_new(run_t *run, stree_new_t *new_op, rdata_item_t **res);
+static void run_new_array(run_t *run, stree_new_t *new_op,
+    tdata_item_t *titem, rdata_item_t **res);
+static void run_new_object(run_t *run, stree_new_t *new_op,
+    tdata_item_t *titem, rdata_item_t **res);
+
+static void run_access(run_t *run, stree_access_t *access, rdata_item_t **res);
+static void run_access_item(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res);
+static void run_access_ref(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res);
+static void run_access_deleg(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res);
+static void run_access_object(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res);
+
+static void run_call(run_t *run, stree_call_t *call, rdata_item_t **res);
+static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res);
+static void run_index_array(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res);
+static void run_index_object(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res);
+static void run_index_string(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res);
+static void run_assign(run_t *run, stree_assign_t *assign, rdata_item_t **res);
+static void run_as(run_t *run, stree_as_t *as_op, rdata_item_t **res);
+
+/** Evaluate expression. */
+void run_expr(run_t *run, stree_expr_t *expr, rdata_item_t **res)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing expression.\n");
+#endif
+
+	switch (expr->ec) {
+	case ec_nameref:
+		run_nameref(run, expr->u.nameref, res);
+		break;
+	case ec_literal:
+		run_literal(run, expr->u.literal, res);
+		break;
+	case ec_self_ref:
+		run_self_ref(run, expr->u.self_ref, res);
+		break;
+	case ec_binop:
+		run_binop(run, expr->u.binop, res);
+		break;
+	case ec_unop:
+		run_unop(run, expr->u.unop, res);
+		break;
+	case ec_new:
+		run_new(run, expr->u.new_op, res);
+		break;
+	case ec_access:
+		run_access(run, expr->u.access, res);
+		break;
+	case ec_call:
+		run_call(run, expr->u.call, res);
+		break;
+	case ec_index:
+		run_index(run, expr->u.index, res);
+		break;
+	case ec_assign:
+		run_assign(run, expr->u.assign, res);
+		break;
+	case ec_as:
+		run_as(run, expr->u.as_op, res);
+		break;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Expression result: ");
+	rdata_item_print(*res);
+	printf(".\n");
+#endif
+}
+
+/** Evaluate name reference expression. */
+static void run_nameref(run_t *run, stree_nameref_t *nameref,
+    rdata_item_t **res)
+{
+	stree_symbol_t *sym;
+	rdata_item_t *item;
+	rdata_address_t *address;
+	rdata_addr_var_t *addr_var;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_deleg_t *deleg_v;
+
+	run_proc_ar_t *proc_ar;
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+	rdata_object_t *obj;
+	rdata_var_t *member_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run nameref.\n");
+#endif
+
+	/*
+	 * Look for a local variable.
+	 */
+	var = run_local_vars_lookup(run, nameref->name->sid);
+	if (var != NULL) {
+		/* Found a local variable. */
+		item = rdata_item_new(ic_address);
+		address = rdata_address_new(ac_var);
+		addr_var = rdata_addr_var_new();
+
+		item->u.address = address;
+		address->u.var_a = addr_var;
+		addr_var->vref = var;
+
+		*res = item;
+#ifdef DEBUG_RUN_TRACE
+		printf("Found local variable.\n");
+#endif
+		return;
+	}
+
+	/*
+	 * Look for a class-wide or global symbol.
+	 */
+
+	/* Determine currently active object or CSI. */
+	proc_ar = run_get_current_proc_ar(run);
+	if (proc_ar->obj != NULL) {
+		assert(proc_ar->obj->vc == vc_object);
+		obj = proc_ar->obj->u.object_v;
+		csi_sym = obj->class_sym;
+		csi = symbol_to_csi(csi_sym);
+		assert(csi != NULL);
+	} else {
+		csi = proc_ar->proc->outer_symbol->outer_csi;
+		obj = NULL;
+	}
+
+	sym = symbol_lookup_in_csi(run->program, csi, nameref->name);
+
+	/* Existence should have been verified in type checking phase. */
+	assert(sym != NULL);
+
+	switch (sym->sc) {
+	case sc_csi:
+#ifdef DEBUG_RUN_TRACE
+		printf("Referencing class.\n");
+#endif
+		item = rdata_item_new(ic_value);
+		value = rdata_value_new();
+		var = rdata_var_new(vc_deleg);
+		deleg_v = rdata_deleg_new();
+
+		item->u.value = value;
+		value->var = var;
+		var->u.deleg_v = deleg_v;
+
+		deleg_v->obj = NULL;
+		deleg_v->sym = sym;
+		*res = item;
+		break;
+	case sc_fun:
+		/* There should be no global functions. */
+		assert(csi != NULL);
+
+		if (sym->outer_csi != csi) {
+			/* Function is not in the current object. */
+			printf("Error: Cannot access non-static member "
+			    "function '");
+			symbol_print_fqn(sym);
+			printf("' from nested CSI '");
+			symbol_print_fqn(csi_sym);
+			printf("'.\n");
+			exit(1);
+		}
+
+		/* Construct delegate. */
+		item = rdata_item_new(ic_value);
+		value = rdata_value_new();
+		item->u.value = value;
+
+		var = rdata_var_new(vc_deleg);
+		deleg_v = rdata_deleg_new();
+		value->var = var;
+		var->u.deleg_v = deleg_v;
+
+		deleg_v->obj = proc_ar->obj;
+		deleg_v->sym = sym;
+
+		*res = item;
+		break;
+	case sc_var:
+#ifdef DEBUG_RUN_TRACE
+		printf("Referencing member variable.\n");
+#endif
+		/* There should be no global variables. */
+		assert(csi != NULL);
+
+		/* XXX Assume variable is not static for now. */
+		assert(obj != NULL);
+
+		if (sym->outer_csi != csi) {
+			/* Variable is not in the current object. */
+			printf("Error: Cannot access non-static member "
+			    "variable '");
+			symbol_print_fqn(sym);
+			printf("' from nested CSI '");
+			symbol_print_fqn(csi_sym);
+			printf("'.\n");
+			exit(1);
+		}
+
+		/* Find member variable in object. */
+		member_var = intmap_get(&obj->fields, nameref->name->sid);
+		assert(member_var != NULL);
+
+		/* Return address of the variable. */
+		item = rdata_item_new(ic_address);
+		address = rdata_address_new(ac_var);
+		addr_var = rdata_addr_var_new();
+
+		item->u.address = address;
+		address->u.var_a = addr_var;
+		addr_var->vref = member_var;
+
+		*res = item;
+		break;
+	default:
+		printf("Referencing symbol class %d unimplemented.\n", sym->sc);
+		*res = NULL;
+		break;
+	}
+}
+
+/** Evaluate literal. */
+static void run_literal(run_t *run, stree_literal_t *literal,
+    rdata_item_t **res)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Run literal.\n");
+#endif
+
+	switch (literal->ltc) {
+	case ltc_int:
+		run_lit_int(run, &literal->u.lit_int, res);
+		break;
+	case ltc_ref:
+		run_lit_ref(run, &literal->u.lit_ref, res);
+		break;
+	case ltc_string:
+		run_lit_string(run, &literal->u.lit_string, res);
+		break;
+	default:
+		assert(b_false);
+	}
+}
+
+/** Evaluate integer literal. */
+static void run_lit_int(run_t *run, stree_lit_int_t *lit_int,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_int_t *int_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run integer literal.\n");
+#endif
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_int);
+	int_v = rdata_int_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.int_v = int_v;
+	int_v->value = lit_int->value;
+
+	*res = item;
+}
+
+/** Evaluate reference literal (@c nil). */
+static void run_lit_ref(run_t *run, stree_lit_ref_t *lit_ref,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_ref_t *ref_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run reference literal (nil).\n");
+#endif
+	(void) run;
+	(void) lit_ref;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_ref);
+	ref_v = rdata_ref_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.ref_v = ref_v;
+	ref_v->vref = NULL;
+
+	*res = item;
+}
+
+/** Evaluate string literal. */
+static void run_lit_string(run_t *run, stree_lit_string_t *lit_string,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_string_t *string_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run integer literal.\n");
+#endif
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_string);
+	string_v = rdata_string_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.string_v = string_v;
+	string_v->value = lit_string->value;
+
+	*res = item;
+}
+
+/** Evaluate @c self reference. */
+static void run_self_ref(run_t *run, stree_self_ref_t *self_ref,
+    rdata_item_t **res)
+{
+	run_proc_ar_t *proc_ar;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run self reference.\n");
+#endif
+	(void) self_ref;
+	proc_ar = run_get_current_proc_ar(run);
+
+	/* Return reference to the currently active object. */
+	run_reference(run, proc_ar->obj, res);
+}
+
+/** Evaluate binary operation. */
+static void run_binop(run_t *run, stree_binop_t *binop, rdata_item_t **res)
+{
+	rdata_item_t *rarg1_i, *rarg2_i;
+	rdata_item_t *rarg1_vi, *rarg2_vi;
+	rdata_value_t *v1, *v2;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run binary operation.\n");
+#endif
+	run_expr(run, binop->arg1, &rarg1_i);
+	run_expr(run, binop->arg2, &rarg2_i);
+
+	switch (binop->bc) {
+	case bo_plus:
+	case bo_equal:
+	case bo_notequal:
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+		/* These are implemented so far. */
+		break;
+	default:
+		printf("Unimplemented: Binary operation type %d.\n",
+		    binop->bc);
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check binop argument results.\n");
+#endif
+
+	run_cvt_value_item(run, rarg1_i, &rarg1_vi);
+	run_cvt_value_item(run, rarg2_i, &rarg2_vi);
+
+	v1 = rarg1_vi->u.value;
+	v2 = rarg2_vi->u.value;
+
+	if (v1->var->vc != v2->var->vc) {
+		printf("Unimplemented: Binary operation arguments have "
+		    "different type.\n");
+		exit(1);
+	}
+
+	switch (v1->var->vc) {
+	case vc_int:
+		run_binop_int(run, binop, v1, v2, res);
+		break;
+	case vc_string:
+		run_binop_string(run, binop, v1, v2, res);
+		break;
+	case vc_ref:
+		run_binop_ref(run, binop, v1, v2, res);
+		break;
+	default:
+		printf("Unimplemented: Binary operation arguments of "
+		    "type %d.\n", v1->var->vc);
+		exit(1);
+	}
+}
+
+/** Evaluate binary operation on int arguments. */
+static void run_binop_int(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_int_t *int_v;
+
+	int i1, i2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_int);
+	int_v = rdata_int_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.int_v = int_v;
+
+	i1 = v1->var->u.int_v->value;
+	i2 = v2->var->u.int_v->value;
+
+	switch (binop->bc) {
+	case bo_plus:
+		int_v->value = i1 + i2;
+		break;
+
+	/* XXX We should have a real boolean type. */
+	case bo_equal:
+		int_v->value = (i1 == i2) ? 1 : 0;
+		break;
+	case bo_notequal:
+		int_v->value = (i1 != i2) ? 1 : 0;
+		break;
+	case bo_lt:
+		int_v->value = (i1 < i2) ? 1 : 0;
+		break;
+	case bo_gt:
+		int_v->value = (i1 > i2) ? 1 : 0;
+		break;
+	case bo_lt_equal:
+		int_v->value = (i1 <= i2) ? 1 : 0;
+		break;
+	case bo_gt_equal:
+		int_v->value = (i1 >= i2) ? 1 : 0;
+		break;
+	default:
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on string arguments. */
+static void run_binop_string(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_string_t *string_v;
+
+	char *s1, *s2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_string);
+	string_v = rdata_string_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.string_v = string_v;
+
+	s1 = v1->var->u.string_v->value;
+	s2 = v2->var->u.string_v->value;
+
+	switch (binop->bc) {
+	case bo_plus:
+		/* Concatenate strings. */
+		string_v->value = os_str_acat(s1, s2);
+		break;
+	default:
+		printf("Error: Invalid binary operation on string "
+		    "arguments (%d).\n", binop->bc);
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on ref arguments. */
+static void run_binop_ref(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_int_t *int_v;
+
+	rdata_var_t *ref1, *ref2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_int);
+	int_v = rdata_int_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.int_v = int_v;
+
+	ref1 = v1->var->u.ref_v->vref;
+	ref2 = v2->var->u.ref_v->vref;
+
+	switch (binop->bc) {
+	/* XXX We should have a real boolean type. */
+	case bo_equal:
+		int_v->value = (ref1 == ref2) ? 1 : 0;
+		break;
+	case bo_notequal:
+		int_v->value = (ref1 != ref2) ? 1 : 0;
+		break;
+	default:
+		printf("Error: Invalid binary operation on reference "
+		    "arguments (%d).\n", binop->bc);
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+
+/** Evaluate unary operation. */
+static void run_unop(run_t *run, stree_unop_t *unop, rdata_item_t **res)
+{
+	rdata_item_t *rarg;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run unary operation.\n");
+#endif
+	run_expr(run, unop->arg, &rarg);
+	*res = NULL;
+}
+
+/** Evaluate @c new operation. */
+static void run_new(run_t *run, stree_new_t *new_op, rdata_item_t **res)
+{
+	tdata_item_t *titem;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run 'new' operation.\n");
+#endif
+	/* Evaluate type expression */
+	run_texpr(run->program, run_get_current_csi(run), new_op->texpr,
+	    &titem);
+
+	switch (titem->tic) {
+	case tic_tarray:
+		run_new_array(run, new_op, titem, res);
+		break;
+	case tic_tobject:
+		run_new_object(run, new_op, titem, res);
+		break;
+	default:
+		printf("Error: Invalid argument to operator 'new', "
+		    "expected object.\n");
+		exit(1);
+	}
+}
+
+/** Create new array. */
+static void run_new_array(run_t *run, stree_new_t *new_op,
+    tdata_item_t *titem, rdata_item_t **res)
+{
+	tdata_array_t *tarray;
+	rdata_array_t *array;
+	rdata_var_t *array_var;
+	rdata_var_t *elem_var;
+
+	rdata_item_t *rexpr, *rexpr_vi;
+	rdata_var_t *rexpr_var;
+
+	stree_expr_t *expr;
+
+	list_node_t *node;
+	int length;
+	int i;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Create new array.\n");
+#endif
+	(void) run;
+	(void) new_op;
+
+	assert(titem->tic == tic_tarray);
+	tarray = titem->u.tarray;
+
+	/* Create the array. */
+	assert(titem->u.tarray->rank > 0);
+	array = rdata_array_new(titem->u.tarray->rank);
+
+	/* Compute extents. */
+	node = list_first(&tarray->extents);
+	if (node == NULL) {
+		printf("Error: Extents must be specified when constructing "
+		    "an array with 'new'.\n");
+		exit(1);
+	}
+
+	i = 0; length = 1;
+	while (node != NULL) {
+		expr = list_node_data(node, stree_expr_t *);
+
+		/* Evaluate extent argument. */
+		run_expr(run, expr, &rexpr);
+		run_cvt_value_item(run, rexpr, &rexpr_vi);
+		assert(rexpr_vi->ic == ic_value);
+		rexpr_var = rexpr_vi->u.value->var;
+
+		if (rexpr_var->vc != vc_int) {
+			printf("Error: Array extent must be an integer.\n");
+			exit(1);
+		}
+
+#ifdef DEBUG_RUN_TRACE
+		printf("Array extent: %d.\n", rexpr_var->u.int_v->value);
+#endif
+		array->extent[i] = rexpr_var->u.int_v->value;
+		length = length * array->extent[i];
+
+		node = list_next(&tarray->extents, node);
+		i += 1;
+	}
+
+	array->element = calloc(length, sizeof(rdata_var_t *));
+	if (array->element == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	/* Create member variables */
+	for (i = 0; i < length; ++i) {
+		/* XXX Depends on member variable type. */
+		elem_var = rdata_var_new(vc_int);
+		elem_var->u.int_v = rdata_int_new();
+		elem_var->u.int_v->value = 0;
+
+		array->element[i] = elem_var;
+	}
+
+	/* Create array variable. */
+	array_var = rdata_var_new(vc_array);
+	array_var->u.array_v = array;
+
+	/* Create reference to the new array. */
+	run_reference(run, array_var, res);
+}
+
+/** Create new object. */
+static void run_new_object(run_t *run, stree_new_t *new_op,
+    tdata_item_t *titem, rdata_item_t **res)
+{
+	rdata_object_t *obj;
+	rdata_var_t *obj_var;
+
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+	stree_csimbr_t *csimbr;
+
+	rdata_var_t *mbr_var;
+
+	list_node_t *node;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Create new object.\n");
+#endif
+	(void) run;
+	(void) new_op;
+
+	/* Lookup object CSI. */
+	assert(titem->tic == tic_tobject);
+	csi = titem->u.tobject->csi;
+	csi_sym = csi_to_symbol(csi);
+
+	/* Create the object. */
+	obj = rdata_object_new();
+	obj->class_sym = csi_sym;
+	intmap_init(&obj->fields);
+
+	obj_var = rdata_var_new(vc_object);
+	obj_var->u.object_v = obj;
+
+	/* Create object fields. */
+	node = list_first(&csi->members);
+	while (node != NULL) {
+		csimbr = list_node_data(node, stree_csimbr_t *);
+		if (csimbr->cc == csimbr_var) {
+			/* XXX Depends on member variable type. */
+			mbr_var = rdata_var_new(vc_int);
+			mbr_var->u.int_v = rdata_int_new();
+			mbr_var->u.int_v->value = 0;
+
+			intmap_set(&obj->fields, csimbr->u.var->name->sid,
+			    mbr_var);
+		}
+
+		node = list_next(&csi->members, node);
+	}
+
+	/* Create reference to the new object. */
+	run_reference(run, obj_var, res);
+}
+
+/** Evaluate member acccess. */
+static void run_access(run_t *run, stree_access_t *access, rdata_item_t **res)
+{
+	rdata_item_t *rarg;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run access operation.\n");
+#endif
+	run_expr(run, access->arg, &rarg);
+	if (rarg == NULL) {
+		printf("Error: Sub-expression has no value.\n");
+		exit(1);
+	}
+
+	run_access_item(run, access, rarg, res);
+}
+
+/** Evaluate member acccess (with base already evaluated). */
+static void run_access_item(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res)
+{
+	var_class_t vc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run access operation on pre-evaluated base.\n");
+#endif
+	vc = run_item_get_vc(run, arg);
+
+	switch (vc) {
+	case vc_ref:
+		run_access_ref(run, access, arg, res);
+		break;
+	case vc_deleg:
+		run_access_deleg(run, access, arg, res);
+		break;
+	case vc_object:
+		run_access_object(run, access, arg, res);
+		break;
+	default:
+		printf("Unimplemented: Using access operator ('.') "
+		    "with unsupported data type (value/%d).\n", vc);
+		exit(1);
+	}
+}
+
+/** Evaluate reference acccess. */
+static void run_access_ref(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res)
+{
+	rdata_item_t *darg;
+
+	/* Implicitly dereference. */
+	run_dereference(run, arg, &darg);
+
+	if (run->thread_ar->bo_mode != bm_none) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
+	/* Try again. */
+	run_access_item(run, access, darg, res);
+}
+
+/** Evaluate delegate-member acccess. */
+static void run_access_deleg(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res)
+{
+	rdata_item_t *arg_vi;
+	rdata_value_t *arg_val;
+	rdata_deleg_t *deleg_v;
+	stree_symbol_t *member;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run delegate access operation.\n");
+#endif
+	run_cvt_value_item(run, arg, &arg_vi);
+	arg_val = arg_vi->u.value;
+	assert(arg_val->var->vc == vc_deleg);
+
+	deleg_v = arg_val->var->u.deleg_v;
+	if (deleg_v->obj != NULL || deleg_v->sym->sc != sc_csi) {
+		printf("Error: Using '.' with delegate to different object "
+		    "than a CSI (%d).\n", deleg_v->sym->sc);
+		exit(1);
+	}
+
+	member = symbol_search_csi(run->program, deleg_v->sym->u.csi,
+	    access->member_name);
+
+	if (member == NULL) {
+		printf("Error: CSI '");
+		symbol_print_fqn(deleg_v->sym);
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	/*
+	 * Reuse existing item, value, var, deleg.
+	 * XXX This is maybe not a good idea because it complicates memory
+	 * management as there is not a single owner 
+	 */
+	deleg_v->sym = member;
+	*res = arg;
+}
+
+/** Evaluate object member acccess. */
+static void run_access_object(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res)
+{
+	stree_symbol_t *member;
+	rdata_var_t *object_var;
+	rdata_object_t *object;
+	rdata_item_t *ritem;
+	rdata_address_t *address;
+	rdata_addr_var_t *addr_var;
+	rdata_addr_prop_t *addr_prop;
+	rdata_aprop_named_t *aprop_named;
+	rdata_deleg_t *deleg_p;
+
+	rdata_value_t *value;
+	rdata_deleg_t *deleg_v;
+	rdata_var_t *var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run object access operation.\n");
+#endif
+	assert(arg->ic == ic_address);
+	assert(arg->u.address->ac == ac_var);
+	assert(arg->u.address->u.var_a->vref->vc == vc_object);
+
+	object_var = arg->u.address->u.var_a->vref;
+	object = object_var->u.object_v;
+
+	member = symbol_search_csi(run->program, object->class_sym->u.csi,
+	    access->member_name);
+
+	if (member == NULL) {
+		printf("Error: Object of class '");
+		symbol_print_fqn(object->class_sym);
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	switch (member->sc) {
+	case sc_csi:
+		printf("Error: Accessing object member which is nested CSI.\n");
+		exit(1);
+	case sc_fun:
+		/* Construct delegate. */
+		ritem = rdata_item_new(ic_value);
+		value = rdata_value_new();
+		ritem->u.value = value;
+
+		var = rdata_var_new(vc_deleg);
+		value->var = var;
+		deleg_v = rdata_deleg_new();
+		var->u.deleg_v = deleg_v;
+
+		deleg_v->obj = arg->u.address->u.var_a->vref;
+		deleg_v->sym = member;
+		break;
+	case sc_var:
+		/* Construct variable address item. */
+		ritem = rdata_item_new(ic_address);
+		address = rdata_address_new(ac_var);
+		addr_var = rdata_addr_var_new();
+		ritem->u.address = address;
+		address->u.var_a = addr_var;
+
+		addr_var->vref = intmap_get(&object->fields,
+		    access->member_name->sid);
+		assert(addr_var->vref != NULL);
+		break;
+	case sc_prop:
+		/* Construct named property address. */
+		ritem = rdata_item_new(ic_address);
+		address = rdata_address_new(ac_prop);
+		addr_prop = rdata_addr_prop_new(apc_named);
+		aprop_named = rdata_aprop_named_new();
+		ritem->u.address = address;
+		address->u.prop_a = addr_prop;
+		addr_prop->u.named = aprop_named;
+
+		deleg_p = rdata_deleg_new();
+		deleg_p->obj = object_var;
+		deleg_p->sym = member;
+		addr_prop->u.named->prop_d = deleg_p;
+		break;
+	}
+
+	*res = ritem;
+}
+
+/** Call a function. */
+static void run_call(run_t *run, stree_call_t *call, rdata_item_t **res)
+{
+	rdata_item_t *rfun;
+	rdata_deleg_t *deleg_v;
+	list_t arg_vals;
+	list_node_t *node;
+	stree_expr_t *arg;
+	rdata_item_t *rarg_i, *rarg_vi;
+
+	stree_fun_t *fun;
+	run_proc_ar_t *proc_ar;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run call operation.\n");
+#endif
+	run_expr(run, call->fun, &rfun);
+
+	if (run->thread_ar->bo_mode != bm_none) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
+	if (rfun->ic != ic_value || rfun->u.value->var->vc != vc_deleg) {
+		printf("Unimplemented: Call expression of this type.\n");
+		exit(1);
+	}
+
+	deleg_v = rfun->u.value->var->u.deleg_v;
+
+	if (deleg_v->sym->sc != sc_fun) {
+		printf("Error: Called symbol is not a function.\n");
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Call function '");
+	symbol_print_fqn(deleg_v->sym);
+	printf("'\n");
+#endif
+	/* Evaluate function arguments. */
+	list_init(&arg_vals);
+	node = list_first(&call->args);
+
+	while (node != NULL) {
+		arg = list_node_data(node, stree_expr_t *);
+		run_expr(run, arg, &rarg_i);
+		run_cvt_value_item(run, rarg_i, &rarg_vi);
+
+		list_append(&arg_vals, rarg_vi);
+		node = list_next(&call->args, node);
+	}
+
+	fun = symbol_to_fun(deleg_v->sym);
+	assert(fun != NULL);
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, deleg_v->obj, fun->proc, &proc_ar);
+
+	/* Fill in argument values. */
+	run_proc_ar_set_args(run, proc_ar, &arg_vals);
+
+	/* Run the function. */
+	run_proc(run, proc_ar, res);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Returned from function call.\n");
+#endif
+}
+
+/** Run index operation. */
+static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res)
+{
+	rdata_item_t *rbase;
+	rdata_item_t *base_i;
+	list_node_t *node;
+	stree_expr_t *arg;
+	rdata_item_t *rarg_i, *rarg_vi;
+	var_class_t vc;
+	list_t arg_vals;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run index operation.\n");
+#endif
+	run_expr(run, index->base, &rbase);
+
+	vc = run_item_get_vc(run, rbase);
+
+	/* Implicitly dereference. */
+	if (vc == vc_ref) {
+		run_dereference(run, rbase, &base_i);
+	} else {
+		base_i = rbase;
+	}
+
+	vc = run_item_get_vc(run, base_i);
+
+	/* Evaluate arguments (indices). */
+	node = list_first(&index->args);
+	list_init(&arg_vals);
+
+	while (node != NULL) {
+		arg = list_node_data(node, stree_expr_t *);
+		run_expr(run, arg, &rarg_i);
+		run_cvt_value_item(run, rarg_i, &rarg_vi);
+
+		list_append(&arg_vals, rarg_vi);
+
+		node = list_next(&index->args, node);
+	}
+
+	switch (vc) {
+	case vc_array:
+		run_index_array(run, index, base_i, &arg_vals, res);
+		break;
+	case vc_object:
+		run_index_object(run, index, base_i, &arg_vals, res);
+		break;
+	case vc_string:
+		run_index_string(run, index, base_i, &arg_vals, res);
+		break;
+	default:
+		printf("Error: Indexing object of bad type (%d).\n", vc);
+		exit(1);
+	}
+}
+
+/** Run index operation on array. */
+static void run_index_array(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res)
+{
+	list_node_t *node;
+	rdata_array_t *array;
+	rdata_item_t *arg;
+
+	int i;
+	int elem_index;
+	int arg_val;
+
+	rdata_item_t *ritem;
+	rdata_address_t *address;
+	rdata_addr_var_t *addr_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run array index operation.\n");
+#endif
+	(void) run;
+	(void) index;
+
+	assert(base->ic == ic_address);
+	assert(base->u.address->ac == ac_var);
+	assert(base->u.address->u.var_a->vref->vc == vc_array);
+	array = base->u.address->u.var_a->vref->u.array_v;
+
+	/*
+	 * Linear index of the desired element. Elements are stored in
+	 * lexicographic order with the last index changing the fastest.
+	 */
+	elem_index = 0;
+
+	node = list_first(args);
+	i = 0;
+
+	while (node != NULL) {
+		if (i >= array->rank) {
+			printf("Error: Too many indices for array of rank %d",
+			    array->rank);
+			exit(1);
+		}
+
+		arg = list_node_data(node, rdata_item_t *);
+		assert(arg->ic == ic_value);
+
+		if (arg->u.value->var->vc != vc_int) {
+			printf("Error: Array index is not an integer.\n");
+			exit(1);
+		}
+
+		arg_val = arg->u.value->var->u.int_v->value;
+
+		if (arg_val < 0 || arg_val >= array->extent[i]) {
+			printf("Error: Array index (value: %d) is out of range.\n",
+			    arg_val);
+			run_raise_error(run);
+			*res = run_recovery_item(run);
+			return;
+		}
+
+		elem_index = elem_index * array->extent[i] + arg_val;
+
+		node = list_next(args, node);
+		i += 1;
+	}
+
+	if (i < array->rank) {
+		printf("Error: Too few indices for array of rank %d",
+		    array->rank);
+		exit(1);
+	}
+
+	/* Construct variable address item. */
+	ritem = rdata_item_new(ic_address);
+	address = rdata_address_new(ac_var);
+	addr_var = rdata_addr_var_new();
+	ritem->u.address = address;
+	address->u.var_a = addr_var;
+
+	addr_var->vref = array->element[elem_index];
+
+	*res = ritem;
+}
+
+/** Index an object (via its indexer). */
+static void run_index_object(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res)
+{
+	rdata_item_t *ritem;
+	rdata_address_t *address;
+	rdata_addr_prop_t *addr_prop;
+	rdata_aprop_indexed_t *aprop_indexed;
+	rdata_var_t *obj_var;
+	stree_csi_t *obj_csi;
+	rdata_deleg_t *object_d;
+	stree_symbol_t *indexer_sym;
+	stree_ident_t *indexer_ident;
+
+	list_node_t *node;
+	rdata_item_t *arg;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run object index operation.\n");
+#endif
+	(void) index;
+
+	/* Construct property address item. */
+	ritem = rdata_item_new(ic_address);
+	address = rdata_address_new(ac_prop);
+	addr_prop = rdata_addr_prop_new(apc_indexed);
+	aprop_indexed = rdata_aprop_indexed_new();
+	ritem->u.address = address;
+	address->u.prop_a = addr_prop;
+	addr_prop->u.indexed = aprop_indexed;
+
+	if (base->ic != ic_address || base->u.address->ac != ac_var) {
+		/* XXX Several other cases can occur. */
+		printf("Unimplemented: Indexing object varclass via something "
+		    "which is not a simple variable reference.\n");
+		exit(1);
+	}
+
+	/* Find indexer symbol. */
+	obj_var = base->u.address->u.var_a->vref;
+	assert(obj_var->vc == vc_object);
+	indexer_ident = stree_ident_new();
+	indexer_ident->sid = strtab_get_sid(INDEXER_IDENT);
+	obj_csi = symbol_to_csi(obj_var->u.object_v->class_sym);
+	assert(obj_csi != NULL);
+	indexer_sym = symbol_search_csi(run->program, obj_csi, indexer_ident);
+
+	if (indexer_sym == NULL) {
+		printf("Error: Accessing object which does not have an "
+		    "indexer.\n");
+		exit(1);
+	}
+
+	/* Construct delegate. */
+	object_d = rdata_deleg_new();
+	object_d->obj = obj_var;
+	object_d->sym = indexer_sym;
+	aprop_indexed->object_d = object_d;
+
+	/* Copy list of argument values. */
+	list_init(&aprop_indexed->args);
+
+	node = list_first(args);
+	while (node != NULL) {
+		arg = list_node_data(node, rdata_item_t *);
+		list_append(&aprop_indexed->args, arg);
+		node = list_next(args, node);
+	}
+
+	*res = ritem;
+}
+
+/** Run index operation on string. */
+static void run_index_string(run_t *run, stree_index_t *index,
+    rdata_item_t *base, list_t *args, rdata_item_t **res)
+{
+	list_node_t *node;
+	rdata_string_t *string;
+	rdata_item_t *base_vi;
+	rdata_item_t *arg;
+
+	int i;
+	int elem_index;
+	int arg_val;
+	int rc;
+
+	rdata_value_t *value;
+	rdata_var_t *cvar;
+	rdata_item_t *ritem;
+	int cval;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run string index operation.\n");
+#endif
+	(void) run;
+	(void) index;
+
+	run_cvt_value_item(run, base, &base_vi);
+	assert(base_vi->u.value->var->vc == vc_string);
+	string = base->u.value->var->u.string_v;
+
+	/*
+	 * Linear index of the desired element. Elements are stored in
+	 * lexicographic order with the last index changing the fastest.
+	 */
+	node = list_first(args);
+	elem_index = 0;
+
+	i = 0;
+	while (node != NULL) {
+		if (i >= 1) {
+			printf("Error: Too many indices string.\n");
+			exit(1);
+		}
+
+		arg = list_node_data(node, rdata_item_t *);
+		assert(arg->ic == ic_value);
+
+		if (arg->u.value->var->vc != vc_int) {
+			printf("Error: String index is not an integer.\n");
+			exit(1);
+		}
+
+		arg_val = arg->u.value->var->u.int_v->value;
+		elem_index = arg_val;
+
+		node = list_next(args, node);
+		i += 1;
+	}
+
+	if (i < 1) {
+		printf("Error: Too few indices for string.\n");
+		exit(1);
+	}
+
+	rc = os_str_get_char(string->value, elem_index, &cval);
+	if (rc != EOK) {
+		printf("Error: String index (value: %d) is out of range.\n",
+		    arg_val);
+		exit(1);
+	}
+
+	/* Construct character value. */
+	ritem = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	ritem->u.value = value;
+
+	cvar = rdata_var_new(vc_int);
+	cvar->u.int_v = rdata_int_new();
+	cvar->u.int_v->value = cval;
+	value->var = cvar;
+
+	*res = ritem;
+}
+
+/** Execute assignment. */
+static void run_assign(run_t *run, stree_assign_t *assign, rdata_item_t **res)
+{
+	rdata_item_t *rdest_i, *rsrc_i;
+	rdata_item_t *rsrc_vi;
+	rdata_value_t *src_val;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run assign operation.\n");
+#endif
+	run_expr(run, assign->dest, &rdest_i);
+	run_expr(run, assign->src, &rsrc_i);
+
+	run_cvt_value_item(run, rsrc_i, &rsrc_vi);
+	assert(rsrc_vi->ic == ic_value);
+	src_val = rsrc_vi->u.value;
+
+	if (rdest_i->ic != ic_address) {
+		printf("Error: Address expression required on left side of "
+		    "assignment operator.\n");
+		exit(1);
+	}
+
+	run_address_write(run, rdest_i->u.address, rsrc_vi->u.value);
+
+	*res = NULL;
+}
+
+/** Execute @c as conversion. */
+static void run_as(run_t *run, stree_as_t *as_op, rdata_item_t **res)
+{
+	rdata_item_t *rarg_i;
+	rdata_item_t *rarg_vi;
+	rdata_item_t *rarg_di;
+	rdata_var_t *arg_vref;
+	tdata_item_t *dtype;
+	run_proc_ar_t *proc_ar;
+
+	stree_symbol_t *obj_csi_sym;
+	stree_csi_t *obj_csi;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run @c as conversion operation.\n");
+#endif
+	run_expr(run, as_op->arg, &rarg_i);
+
+	/*
+	 * This should always be a reference if the argument is indeed
+	 * a class instance.
+	 */
+	assert(run_item_get_vc(run, rarg_i) == vc_ref);
+	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	assert(rarg_vi->ic == ic_value);
+
+	if (rarg_vi->u.value->var->u.ref_v->vref == NULL) {
+		/* Nil reference is always okay. */
+		*res = rarg_vi;
+		return;
+	}
+
+	run_dereference(run, rarg_vi, &rarg_di);
+
+	/* Now we should have a variable address. */
+	assert(rarg_di->ic == ic_address);
+	assert(rarg_di->u.address->ac == ac_var);
+
+	arg_vref = rarg_di->u.address->u.var_a->vref;
+
+	proc_ar = run_get_current_proc_ar(run);
+	/* XXX Memoize to avoid recomputing. */
+	run_texpr(run->program, proc_ar->proc->outer_symbol->outer_csi,
+	    as_op->dtype, &dtype);
+
+	assert(arg_vref->vc == vc_object);
+	obj_csi_sym = arg_vref->u.object_v->class_sym;
+	obj_csi = symbol_to_csi(obj_csi_sym);
+	assert(obj_csi != NULL);
+
+	if (tdata_is_csi_derived_from_ti(obj_csi, dtype) != b_true) {
+		printf("Error: Run-time type conversion error. Object is "
+		    "of type '");
+		symbol_print_fqn(obj_csi_sym);
+		printf("' which is not derived from '");
+		tdata_item_print(dtype);
+		printf("'.\n");
+		exit(1);
+	}
+
+	*res = rarg_vi;
+}
+
+/** Return boolean value of an item.
+ *
+ * Tries to interpret @a item as a boolean value. If it is not a boolean
+ * value, this generates an error.
+ *
+ * XXX Currently int supplants the role of a true boolean type.
+ */
+bool_t run_item_boolean_value(run_t *run, rdata_item_t *item)
+{
+	rdata_item_t *vitem;
+	rdata_var_t *var;
+
+	(void) run;
+	run_cvt_value_item(run, item, &vitem);
+
+	assert(vitem->ic == ic_value);
+	var = vitem->u.value->var;
+
+	if (var->vc != vc_int) {
+		printf("Error: Boolean (int) expression expected.\n");
+		exit(1);
+	}
+
+	return (var->u.int_v->value != 0);
+}
Index: uspace/app/sbi/src/run_expr.h
===================================================================
--- uspace/app/sbi/src/run_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RUN_EXPR_H_
+#define RUN_EXPR_H_
+
+#include "mytypes.h"
+
+void run_expr(run_t *run, stree_expr_t *expr, rdata_item_t **res);
+
+bool_t run_item_boolean_value(run_t *run, rdata_item_t *item);
+
+
+#endif
Index: uspace/app/sbi/src/run_t.h
===================================================================
--- uspace/app/sbi/src/run_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RUN_T_H_
+#define RUN_T_H_
+
+#include "intmap_t.h"
+#include "list_t.h"
+
+/** Block activation record
+ *
+ * One block AR is created for each block that we enter. A variable declaration
+ * statement inserts the variable here. Upon exiting the block we pop from the
+ * stack, thus all the variables declared in that block are forgotten.
+ */
+typedef struct run_block_ar {
+	/** Variables in this block */
+	intmap_t vars; /* of rdata_var_t */
+} run_block_ar_t;
+
+
+/** Procedure activation record
+ *
+ * A procedure can be a member function, a named property or an indexed
+ * property. A procedure activation record is created whenever a procedure
+ * is invoked.
+ */
+typedef struct run_proc_ar {
+	/** Object on which the procedure is being invoked or @c NULL. */
+	struct rdata_var *obj;
+
+	/** Procedure being invoked */
+	struct stree_proc *proc;
+
+	/** Block activation records */
+	list_t block_ar; /* of run_block_ar_t */
+
+	/** Procedure return value or @c NULL if not set. */
+	struct rdata_item *retval;
+} run_proc_ar_t;
+
+/** Bailout mode
+ *
+ * Determines whether control is bailing out of a statement, function, etc.
+ */
+typedef enum {
+	/** Normal execution */
+	bm_none,
+
+	/** Break from statement */
+	bm_stat,
+
+	/** Return from procedure */
+	bm_proc,
+
+	/** Exception */
+	bm_exc,
+
+	/** Unrecoverable runtime error */
+	bm_error
+} run_bailout_mode_t;
+
+/** Thread activation record
+ *
+ * We can walk the list of function ARs to get a function call backtrace.
+ */
+typedef struct run_thread_ar {
+	/** Function activation records */
+	list_t proc_ar; /* of run_proc_ar_t */
+
+	/** Bailout mode */
+	run_bailout_mode_t bo_mode;
+
+	/** Exception payload */
+	struct rdata_value *exc_payload;
+
+	/** @c b_true if a run-time error occured. */
+	bool_t error;
+} run_thread_ar_t;
+
+/** Runner state object */
+typedef struct run {
+	/** Code of the program being executed */
+	struct stree_program *program;
+
+	/** Thread-private state */
+	run_thread_ar_t *thread_ar;
+} run_t;
+
+#endif
Index: uspace/app/sbi/src/run_texpr.c
===================================================================
--- uspace/app/sbi/src/run_texpr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run_texpr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Evaluates type expressions. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "list.h"
+#include "mytypes.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "run_texpr.h"
+
+static void run_taccess(stree_program_t *prog, stree_csi_t *ctx,
+    stree_taccess_t *taccess, tdata_item_t **res);
+static void run_tindex(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tindex_t *tindex, tdata_item_t **res);
+static void run_tliteral(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tliteral_t *tliteral, tdata_item_t **res);
+static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tnameref_t *tnameref, tdata_item_t **res);
+
+void run_texpr(stree_program_t *prog, stree_csi_t *ctx, stree_texpr_t *texpr,
+    tdata_item_t **res)
+{
+	switch (texpr->tc) {
+	case tc_taccess:
+		run_taccess(prog, ctx, texpr->u.taccess, res);
+		break;
+	case tc_tindex:
+		run_tindex(prog, ctx, texpr->u.tindex, res);
+		break;
+	case tc_tliteral:
+		run_tliteral(prog, ctx, texpr->u.tliteral, res);
+		break;
+	case tc_tnameref:
+		run_tnameref(prog, ctx, texpr->u.tnameref, res);
+		break;
+	case tc_tapply:
+		printf("Unimplemented: Evaluate type expression type %d.\n",
+		    texpr->tc);
+		exit(1);
+	}
+}
+
+static void run_taccess(stree_program_t *prog, stree_csi_t *ctx,
+    stree_taccess_t *taccess, tdata_item_t **res)
+{
+	stree_symbol_t *sym;
+	tdata_item_t *targ_i;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+	stree_csi_t *base_csi;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type access operation.\n");
+#endif
+	/* Evaluate base type. */
+	run_texpr(prog, ctx, taccess->arg, &targ_i);
+
+	if (targ_i->tic != tic_tobject) {
+		printf("Error: Using '.' with type which is not an object.\n");
+		exit(1);
+	}
+
+	/* Get base CSI. */
+	base_csi = targ_i->u.tobject->csi;
+
+	sym = symbol_lookup_in_csi(prog, base_csi, taccess->member_name);
+
+	/* Existence should have been verified in type checking phase. */
+	assert(sym != NULL);
+
+	if (sym->sc != sc_csi) {
+		printf("Error: Symbol '");
+		symbol_print_fqn(sym);
+		printf("' is not a CSI.\n");
+		exit(1);
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = sym->u.csi;
+
+	*res = titem;
+}
+
+static void run_tindex(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tindex_t *tindex, tdata_item_t **res)
+{
+	tdata_item_t *base_ti;
+	tdata_item_t *titem;
+	tdata_array_t *tarray;
+	stree_expr_t *arg_expr;
+	list_node_t *arg_node;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type index operation.\n");
+#endif
+	/* Evaluate base type. */
+	run_texpr(prog, ctx, tindex->base_type, &base_ti);
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tarray);
+	tarray = tdata_array_new();
+	titem->u.tarray = tarray;
+
+	tarray->base_ti = base_ti;
+	tarray->rank = tindex->n_args;
+
+	/* Copy extents. */
+	list_init(&tarray->extents);
+	arg_node = list_first(&tindex->args);
+
+	while (arg_node != NULL) {
+		arg_expr = list_node_data(arg_node, stree_expr_t *);
+		list_append(&tarray->extents, arg_expr);
+		arg_node = list_next(&tindex->args, arg_node);
+	}
+
+	*res = titem;
+}
+
+static void run_tliteral(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tliteral_t *tliteral, tdata_item_t **res)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+	tprimitive_class_t tpc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type literal.\n");
+#endif
+	(void) prog;
+	(void) ctx;
+	(void) tliteral;
+
+	switch (tliteral->tlc) {
+	case tlc_int: tpc = tpc_int; break;
+	case tlc_string: tpc = tpc_string; break;
+	case tlc_resource: tpc = tpc_resource; break;
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc);
+	titem->u.tprimitive = tprimitive;
+
+	*res = titem;
+}
+
+static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tnameref_t *tnameref, tdata_item_t **res)
+{
+	stree_symbol_t *sym;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type name reference.\n");
+#endif
+	sym = symbol_lookup_in_csi(prog, ctx, tnameref->name);
+
+	/* Existence should have been verified in type-checking phase. */
+	assert(sym);
+
+	if (sym->sc != sc_csi) {
+		printf("Error: Symbol '");
+		symbol_print_fqn(sym);
+		printf("' is not a CSI.\n");
+		exit(1);
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = sym->u.csi;
+
+	*res = titem;
+}
Index: uspace/app/sbi/src/run_texpr.h
===================================================================
--- uspace/app/sbi/src/run_texpr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/run_texpr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RUN_TEXPR_H_
+#define RUN_TEXPR_H_
+
+#include "mytypes.h"
+
+void run_texpr(stree_program_t *prog, stree_csi_t *ctx, stree_texpr_t *texpr,
+    tdata_item_t **res);
+
+#endif
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stree.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Stree (syntax tree) intermediate representation. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "list.h"
+#include "mytypes.h"
+
+#include "stree.h"
+
+stree_module_t *stree_module_new(void)
+{
+	stree_module_t *module;
+
+	module = calloc(1, sizeof(stree_module_t));
+	if (module == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	list_init(&module->members);
+	return module;
+}
+
+stree_modm_t *stree_modm_new(modm_class_t mc)
+{
+	stree_modm_t *modm;
+
+	modm = calloc(1, sizeof(stree_modm_t));
+	if (modm == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	modm->mc = mc;
+	return modm;
+}
+
+stree_csi_t *stree_csi_new(csi_class_t cc)
+{
+	stree_csi_t *csi;
+
+	csi = calloc(1, sizeof(stree_csi_t));
+	if (csi == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	csi->cc = cc;
+	csi->ancr_state = ws_unvisited;
+	csi->name = NULL;
+	csi->base_csi_ref = NULL;
+	list_init(&csi->members);
+	return csi;
+}
+
+stree_csimbr_t *stree_csimbr_new(csimbr_class_t cc)
+{
+	stree_csimbr_t *csimbr;
+
+	csimbr = calloc(1, sizeof(stree_csimbr_t));
+	if (csimbr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	csimbr->cc = cc;
+	return csimbr;
+}
+
+stree_fun_t *stree_fun_new(void)
+{
+	stree_fun_t *fun;
+
+	fun = calloc(1, sizeof(stree_fun_t));
+	if (fun == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return fun;
+}
+
+stree_var_t *stree_var_new(void)
+{
+	stree_var_t *var;
+
+	var = calloc(1, sizeof(stree_var_t));
+	if (var == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return var;
+}
+
+stree_prop_t *stree_prop_new(void)
+{
+	stree_prop_t *prop;
+
+	prop = calloc(1, sizeof(stree_prop_t));
+	if (prop == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return prop;
+}
+
+stree_symbol_attr_t *stree_symbol_attr_new(symbol_attr_class_t sac)
+{
+	stree_symbol_attr_t *symbol_attr;
+
+	symbol_attr = calloc(1, sizeof(stree_symbol_attr_t));
+	if (symbol_attr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	symbol_attr->sac = sac;
+	return symbol_attr;
+}
+
+stree_proc_t *stree_proc_new(void)
+{
+	stree_proc_t *proc;
+
+	proc = calloc(1, sizeof(stree_proc_t));
+	if (proc == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc;
+}
+
+stree_proc_arg_t *stree_proc_arg_new(void)
+{
+	stree_proc_arg_t *proc_arg;
+
+	proc_arg = calloc(1, sizeof(stree_proc_arg_t));
+	if (proc_arg == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc_arg;
+}
+
+stree_arg_attr_t *stree_arg_attr_new(arg_attr_class_t aac)
+{
+	stree_arg_attr_t *arg_attr;
+
+	arg_attr = calloc(1, sizeof(stree_arg_attr_t));
+	if (arg_attr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	arg_attr->aac = aac;
+	return arg_attr;
+}
+
+stree_stat_t *stree_stat_new(stat_class_t sc)
+{
+	stree_stat_t *stat;
+
+	stat = calloc(1, sizeof(stree_stat_t));
+	if (stat == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	stat->sc = sc;
+	return stat;
+}
+
+stree_vdecl_t *stree_vdecl_new(void)
+{
+	stree_vdecl_t *vdecl_s;
+
+	vdecl_s = calloc(1, sizeof(stree_vdecl_t));
+	if (vdecl_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return vdecl_s;
+}
+
+stree_if_t *stree_if_new(void)
+{
+	stree_if_t *if_s;
+
+	if_s = calloc(1, sizeof(stree_if_t));
+	if (if_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return if_s;
+}
+
+stree_while_t *stree_while_new(void)
+{
+	stree_while_t *while_s;
+
+	while_s = calloc(1, sizeof(stree_while_t));
+	if (while_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return while_s;
+}
+
+stree_for_t *stree_for_new(void)
+{
+	stree_for_t *for_s;
+
+	for_s = calloc(1, sizeof(stree_for_t));
+	if (for_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return for_s;
+}
+
+stree_raise_t *stree_raise_new(void)
+{
+	stree_raise_t *raise_s;
+
+	raise_s = calloc(1, sizeof(stree_raise_t));
+	if (raise_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return raise_s;
+}
+
+stree_return_t *stree_return_new(void)
+{
+	stree_return_t *return_s;
+
+	return_s = calloc(1, sizeof(stree_return_t));
+	if (return_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return return_s;
+}
+
+stree_wef_t *stree_wef_new(void)
+{
+	stree_wef_t *wef_s;
+
+	wef_s = calloc(1, sizeof(stree_wef_t));
+	if (wef_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return wef_s;
+}
+
+stree_exps_t *stree_exps_new(void)
+{
+	stree_exps_t *exp_s;
+
+	exp_s = calloc(1, sizeof(stree_exps_t));
+	if (exp_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return exp_s;
+}
+
+stree_except_t *stree_except_new(void)
+{
+	stree_except_t *except_c;
+
+	except_c = calloc(1, sizeof(stree_except_t));
+	if (except_c == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return except_c;
+}
+
+stree_block_t *stree_block_new(void)
+{
+	stree_block_t *block;
+
+	block = calloc(1, sizeof(stree_block_t));
+	if (block == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return block;
+}
+
+stree_expr_t *stree_expr_new(expr_class_t ec)
+{
+	stree_expr_t *expr;
+
+	expr = calloc(1, sizeof(stree_expr_t));
+	if (expr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	expr->ec = ec;
+	return expr;
+}
+
+stree_assign_t *stree_assign_new(assign_class_t ac)
+{
+	stree_assign_t *assign;
+
+	assign = calloc(1, sizeof(stree_assign_t));
+	if (assign == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	assign->ac = ac;
+	return assign;
+}
+
+stree_binop_t *stree_binop_new(binop_class_t bc)
+{
+	stree_binop_t *binop;
+
+	binop = calloc(1, sizeof(stree_binop_t));
+	if (binop == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	binop->bc = bc;
+	return binop;
+}
+
+stree_new_t *stree_new_new(void)
+{
+	stree_new_t *new_op;
+
+	new_op = calloc(1, sizeof(stree_new_t));
+	if (new_op == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return new_op;
+}
+
+stree_access_t *stree_access_new(void)
+{
+	stree_access_t *access;
+
+	access = calloc(1, sizeof(stree_access_t));
+	if (access == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return access;
+}
+
+stree_call_t *stree_call_new(void)
+{
+	stree_call_t *call;
+
+	call = calloc(1, sizeof(stree_call_t));
+	if (call == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return call;
+}
+
+stree_index_t *stree_index_new(void)
+{
+	stree_index_t *index;
+
+	index = calloc(1, sizeof(stree_index_t));
+	if (index == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return index;
+}
+
+stree_as_t *stree_as_new(void)
+{
+	stree_as_t *as_expr;
+
+	as_expr = calloc(1, sizeof(stree_as_t));
+	if (as_expr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return as_expr;
+}
+
+stree_nameref_t *stree_nameref_new(void)
+{
+	stree_nameref_t *nameref;
+
+	nameref = calloc(1, sizeof(stree_nameref_t));
+	if (nameref == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return nameref;
+}
+
+stree_ident_t *stree_ident_new(void)
+{
+	stree_ident_t *ident;
+
+	ident = calloc(1, sizeof(stree_ident_t));
+	if (ident == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return ident;
+}
+
+stree_literal_t *stree_literal_new(literal_class_t ltc)
+{
+	stree_literal_t *literal;
+
+	literal = calloc(1, sizeof(stree_literal_t));
+	if (literal == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	literal->ltc = ltc;
+	return literal;
+}
+
+stree_self_ref_t *stree_self_ref_new(void)
+{
+	stree_self_ref_t *self_ref;
+
+	self_ref = calloc(1, sizeof(stree_self_ref_t));
+	if (self_ref == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return self_ref;
+}
+
+stree_texpr_t *stree_texpr_new(texpr_class_t tc)
+{
+	stree_texpr_t *texpr;
+
+	texpr = calloc(1, sizeof(stree_texpr_t));
+	if (texpr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	texpr->tc = tc;
+	return texpr;
+}
+
+stree_taccess_t *stree_taccess_new(void)
+{
+	stree_taccess_t *taccess;
+
+	taccess = calloc(1, sizeof(stree_taccess_t));
+	if (taccess == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return taccess;
+}
+
+stree_tapply_t *stree_tapply_new(void)
+{
+	stree_tapply_t *tapply;
+
+	tapply = calloc(1, sizeof(stree_tapply_t));
+	if (tapply == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tapply;
+}
+
+stree_tindex_t *stree_tindex_new(void)
+{
+	stree_tindex_t *tindex;
+
+	tindex = calloc(1, sizeof(stree_tindex_t));
+	if (tindex == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tindex;
+}
+
+stree_tliteral_t *stree_tliteral_new(tliteral_class_t tlc)
+{
+	stree_tliteral_t *tliteral;
+
+	tliteral = calloc(1, sizeof(stree_tliteral_t));
+	if (tliteral == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	tliteral->tlc = tlc;
+	return tliteral;
+}
+
+stree_tnameref_t *stree_tnameref_new(void)
+{
+	stree_tnameref_t *tnameref;
+
+	tnameref = calloc(1, sizeof(stree_tnameref_t));
+	if (tnameref == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tnameref;
+}
+
+stree_symbol_t *stree_symbol_new(symbol_class_t sc)
+{
+	stree_symbol_t *symbol;
+
+	symbol = calloc(1, sizeof(stree_symbol_t));
+	if (symbol == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	symbol->sc = sc;
+	return symbol;
+}
+
+stree_program_t *stree_program_new(void)
+{
+	stree_program_t *program;
+
+	program = calloc(1, sizeof(stree_program_t));
+	if (program == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return program;
+}
+
+/** Determine if @a symbol has attribute of class @a sac. */
+bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac)
+{
+	list_node_t *node;
+	stree_symbol_attr_t *attr;
+
+	node = list_first(&symbol->attr);
+	while (node != NULL) {
+		attr = list_node_data(node, stree_symbol_attr_t *);
+		if (attr->sac == sac)
+			return b_true;
+
+		node = list_next(&symbol->attr, node);
+	}
+
+	return b_false;
+}
+
+/** Determine if argument @a arg has attribute of class @a aac. */
+bool_t stree_arg_has_attr(stree_proc_arg_t *arg, arg_attr_class_t aac)
+{
+	list_node_t *node;
+	stree_arg_attr_t *attr;
+
+	node = list_first(&arg->attr);
+	while (node != NULL) {
+		attr = list_node_data(node, stree_arg_attr_t *);
+		if (attr->aac == aac)
+			return b_true;
+
+		node = list_next(&arg->attr, node);
+	}
+
+	return b_false;
+}
+
+/** Determine wheter @a a is derived (transitively) from @a b.
+ *
+ * @param a	Derived CSI.
+ * @param b	Base CSI.
+ * @return	@c b_true if @a a is equal to or directly or indirectly
+ *		derived from @a b.
+ */
+bool_t stree_is_csi_derived_from_csi(stree_csi_t *a, stree_csi_t *b)
+{
+	stree_csi_t *csi;
+
+	csi = a;
+	while (csi != NULL) {
+		if (csi == b)
+			return b_true;
+
+		csi = csi->base_csi;
+	}
+
+	/* We went all the way to the root and did not find b. */
+	return b_false;
+}
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stree.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STREE_H_
+#define STREE_H_
+
+#include "mytypes.h"
+
+stree_module_t *stree_module_new(void);
+stree_modm_t *stree_modm_new(modm_class_t mc);
+stree_csi_t *stree_csi_new(csi_class_t cc);
+stree_csimbr_t *stree_csimbr_new(csimbr_class_t cc);
+stree_fun_t *stree_fun_new(void);
+stree_var_t *stree_var_new(void);
+stree_prop_t *stree_prop_new(void);
+
+stree_symbol_attr_t *stree_symbol_attr_new(symbol_attr_class_t sac);
+
+stree_proc_t *stree_proc_new(void);
+stree_proc_arg_t *stree_proc_arg_new(void);
+stree_arg_attr_t *stree_arg_attr_new(arg_attr_class_t aac);
+
+stree_stat_t *stree_stat_new(stat_class_t sc);
+stree_vdecl_t *stree_vdecl_new(void);
+stree_if_t *stree_if_new(void);
+stree_while_t *stree_while_new(void);
+stree_for_t *stree_for_new(void);
+stree_raise_t *stree_raise_new(void);
+stree_return_t *stree_return_new(void);
+stree_wef_t *stree_wef_new(void);
+stree_exps_t *stree_exps_new(void);
+
+stree_except_t *stree_except_new(void);
+stree_block_t *stree_block_new(void);
+
+stree_expr_t *stree_expr_new(expr_class_t ec);
+stree_assign_t *stree_assign_new(assign_class_t ac);
+stree_binop_t *stree_binop_new(binop_class_t bc);
+stree_new_t *stree_new_new(void);
+stree_access_t *stree_access_new(void);
+stree_call_t *stree_call_new(void);
+stree_index_t *stree_index_new(void);
+stree_as_t *stree_as_new(void);
+stree_nameref_t *stree_nameref_new(void);
+
+stree_ident_t *stree_ident_new(void);
+stree_literal_t *stree_literal_new(literal_class_t ltc);
+stree_self_ref_t *stree_self_ref_new(void);
+
+stree_texpr_t *stree_texpr_new(texpr_class_t tc);
+stree_taccess_t *stree_taccess_new(void);
+stree_tapply_t *stree_tapply_new(void);
+stree_tindex_t *stree_tindex_new(void);
+stree_tliteral_t *stree_tliteral_new(tliteral_class_t tlc);
+stree_tnameref_t *stree_tnameref_new(void);
+
+stree_symbol_t *stree_symbol_new(symbol_class_t sc);
+stree_program_t *stree_program_new(void);
+
+bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac);
+bool_t stree_arg_has_attr(stree_proc_arg_t *arg, arg_attr_class_t aac);
+bool_t stree_is_csi_derived_from_csi(stree_csi_t *a, stree_csi_t *b);
+
+#endif
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stree_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STREE_T_H_
+#define STREE_T_H_
+
+#include "list_t.h"
+#include "builtin_t.h"
+
+/*
+ * Arithmetic expressions
+ */
+
+struct stree_expr;
+
+/** Identifier */
+typedef struct {
+	int sid;
+} stree_ident_t;
+
+/** Name reference */
+typedef struct {
+	stree_ident_t *name;
+} stree_nameref_t;
+
+/** Reference to currently active object. */
+typedef struct {
+} stree_self_ref_t;
+
+typedef struct {
+	int value;
+} stree_lit_int_t;
+
+/** Reference literal (there is only one: @c nil). */
+typedef struct {
+} stree_lit_ref_t;
+
+typedef struct {
+	char *value;
+} stree_lit_string_t;
+
+typedef enum {
+	ltc_int,
+	ltc_ref,
+	ltc_string
+} literal_class_t;
+
+/** Literal */
+typedef struct {
+	literal_class_t ltc;
+	union {
+		stree_lit_int_t lit_int;
+		stree_lit_ref_t lit_ref;
+		stree_lit_string_t lit_string;
+	} u;
+} stree_literal_t;
+
+/** Binary operation class */
+typedef enum {
+	bo_equal,
+	bo_notequal,
+	bo_lt,
+	bo_gt,
+	bo_lt_equal,
+	bo_gt_equal,
+	bo_plus
+} binop_class_t;
+
+/** Unary operation class */
+typedef enum {
+	uo_plus
+} unop_class_t;
+
+/** Binary operation */
+typedef struct {
+	/** Binary operation class */
+	binop_class_t bc;
+
+	/** Arguments */
+	struct stree_expr *arg1, *arg2;
+} stree_binop_t;
+
+/** Unary operation */
+typedef struct {
+	/** Operation class */
+	unop_class_t oc;
+
+	/** Argument */
+	struct stree_expr *arg;
+} stree_unop_t;
+
+/** New operation */
+typedef struct {
+	/** Type of object to construct. */
+	struct stree_texpr *texpr;
+} stree_new_t;
+
+/** Member access operation */
+typedef struct {
+	/** Argument */
+	struct stree_expr *arg;
+	/** Name of member being accessed. */
+	stree_ident_t *member_name;
+} stree_access_t;
+
+/** Function call operation */
+typedef struct {
+	/** Function */
+	struct stree_expr *fun;
+
+	/** Arguments */
+	list_t args; /* of stree_expr_t */
+} stree_call_t;
+
+typedef enum {
+	ac_set,
+	ac_increase
+} assign_class_t;
+
+/** Assignment */
+typedef struct {
+	assign_class_t ac;
+	struct stree_expr *dest, *src;
+} stree_assign_t;
+
+/** Indexing operation */
+typedef struct {
+	/** Base */
+	struct stree_expr *base;
+
+	/** Arguments (indices) */
+	list_t args; /* of stree_expr_t */
+} stree_index_t;
+
+/** @c as conversion operation */
+typedef struct {
+	/** Expression to convert */
+	struct stree_expr *arg;
+	/** Destination type of conversion. */
+	struct stree_texpr *dtype;
+} stree_as_t;
+
+/** Arithmetic expression class */
+typedef enum {
+	ec_nameref,
+	ec_literal,
+	ec_self_ref,
+	ec_binop,
+	ec_unop,
+	ec_new,
+	ec_access,
+	ec_call,
+	ec_assign,
+	ec_index,
+	ec_as
+} expr_class_t;
+
+/** Arithmetic expression */
+typedef struct stree_expr {
+	expr_class_t ec;
+
+	struct tdata_item *titem;
+
+	union {
+		stree_nameref_t *nameref;
+		stree_literal_t *literal;
+		stree_self_ref_t *self_ref;
+		stree_binop_t *binop;
+		stree_unop_t *unop;
+		stree_new_t *new_op;
+		stree_access_t *access;
+		stree_call_t *call;
+		stree_index_t *index;
+		stree_assign_t *assign;
+		stree_as_t *as_op;
+	} u;
+} stree_expr_t;
+
+/*
+ * Type expressions
+ */
+
+struct stree_texpr;
+
+/** Type literal class */
+typedef enum {
+	tlc_int,
+	tlc_resource,
+	tlc_string
+} tliteral_class_t;
+
+/** Type literal */
+typedef struct {
+	tliteral_class_t tlc;
+} stree_tliteral_t;
+
+/** Type name reference */
+typedef struct {
+	stree_ident_t *name;
+} stree_tnameref_t;
+
+/** Type member access operation */
+typedef struct {
+	/** Argument */
+	struct stree_texpr *arg;
+	/** Name of member being accessed. */
+	stree_ident_t *member_name;
+} stree_taccess_t;
+
+/** Type application operation */
+typedef struct {
+	/** Arguments */
+	struct stree_texpr *gtype, *targ;
+} stree_tapply_t;
+
+/** Type index operation */
+typedef struct {
+	/** Base type */
+	struct stree_texpr *base_type;
+
+	/**
+	 * Number of arguments (rank). Needed when only rank is specified
+	 * and @c args are not used.
+	 */
+	int n_args;
+
+	/** Arguments (extents) */
+	list_t args; /* of stree_expr_t */
+} stree_tindex_t;
+
+/** Type expression class */
+typedef enum {
+	tc_tliteral,
+	tc_tnameref,
+	tc_taccess,
+	tc_tapply,
+	tc_tindex
+} texpr_class_t;
+
+/** Arithmetic expression */
+typedef struct stree_texpr {
+	texpr_class_t tc;
+
+	union {
+		stree_tliteral_t *tliteral;
+		stree_tnameref_t *tnameref;
+		stree_taccess_t *taccess;
+		stree_tapply_t *tapply;
+		stree_tindex_t *tindex;
+	} u;
+} stree_texpr_t;
+
+/*
+ * Statements, class members and module members.
+ */
+
+/** Statement block */
+typedef struct stree_block {
+	/** List of statements in the block */
+	list_t stats; /* of stree_stat_t */
+} stree_block_t;
+
+/** Variable declaration */
+typedef struct {
+	stree_ident_t *name;
+	stree_texpr_t *type;
+} stree_vdecl_t;
+
+/** @c except clause */
+typedef struct {
+	stree_ident_t *evar;
+	stree_texpr_t *etype;
+	stree_block_t *block;
+} stree_except_t;
+
+/** If statement */
+typedef struct {
+	stree_expr_t *cond;
+	stree_block_t *if_block;
+	stree_block_t *else_block;
+} stree_if_t;
+
+/** While statement */
+typedef struct {
+	stree_expr_t *cond;
+	stree_block_t *body;
+} stree_while_t;
+
+/** For statement */
+typedef struct {
+	stree_block_t *body;
+} stree_for_t;
+
+/** Raise statement */
+typedef struct {
+	stree_expr_t *expr;
+} stree_raise_t;
+
+/** Return statement */
+typedef struct {
+	stree_expr_t *expr;
+} stree_return_t;
+
+/** Expression statement */
+typedef struct {
+	stree_expr_t *expr;
+} stree_exps_t;
+
+/** With-try-except-finally statement (WEF) */
+typedef struct {
+	stree_block_t *with_block;
+	list_t except_clauses; /* of stree_except_t */
+	stree_block_t *finally_block;
+} stree_wef_t;
+
+/** Statement class */
+typedef enum {
+	st_vdecl,
+	st_if,
+	st_while,
+	st_for,
+	st_raise,
+	st_return,
+	st_exps,
+	st_wef
+} stat_class_t;
+
+/** Statement */
+typedef struct {
+	stat_class_t sc;
+
+	union {
+		stree_vdecl_t *vdecl_s;
+		stree_if_t *if_s;
+		stree_while_t *while_s;
+		stree_for_t *for_s;
+		stree_raise_t *raise_s;
+		stree_return_t *return_s;
+		stree_exps_t *exp_s;
+		stree_wef_t *wef_s;
+	} u;
+} stree_stat_t;
+
+/** Argument attribute class */
+typedef enum {
+	/** Packed argument (for variadic functions) */
+	aac_packed
+} arg_attr_class_t;
+
+/** Argument atribute */
+typedef struct {
+	arg_attr_class_t aac;
+} stree_arg_attr_t;
+
+/** Formal function parameter */
+typedef struct {
+	/* Argument name */
+	stree_ident_t *name;
+
+	/* Argument type */
+	stree_texpr_t *type;
+
+	/* Attributes */
+	list_t attr; /* of stree_arg_attr_t */
+} stree_proc_arg_t;
+
+/** Procedure
+ *
+ * Procedure is the common term for a getter, setter or function body.
+ * A procedure can be invoked. However, the arguments are specified by
+ * the containing symbol.
+ */
+typedef struct stree_proc {
+	/** Symbol (function or property) containing the procedure */
+	struct stree_symbol *outer_symbol;
+
+	/** Main block for regular procedures */
+	stree_block_t *body;
+
+	/** Builtin handler for builtin procedures */
+	builtin_proc_t bi_handler;
+} stree_proc_t;
+
+/** Member function declaration */
+typedef struct stree_fun {
+	/** Function name */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** Formal parameters */
+	list_t args; /* of stree_proc_arg_t */
+
+	/** Variadic argument or @c NULL if none. */
+	stree_proc_arg_t *varg;
+
+	/** Return type */
+	stree_texpr_t *rtype;
+
+	/** Function implementation */
+	stree_proc_t *proc;
+} stree_fun_t;
+
+/** Member variable declaration */
+typedef struct stree_var {
+	stree_ident_t *name;
+	struct stree_symbol *symbol;
+	stree_texpr_t *type;
+} stree_var_t;
+
+/** Member property declaration */
+typedef struct stree_prop {
+	stree_ident_t *name;
+	struct stree_symbol *symbol;
+	stree_texpr_t *type;
+
+	stree_proc_t *getter;
+
+	stree_proc_t *setter;
+	stree_proc_arg_t *setter_arg;
+
+	/** Formal parameters (for indexed properties) */
+	list_t args; /* of stree_proc_arg_t */
+
+	/** Variadic argument or @c NULL if none. */
+	stree_proc_arg_t *varg;
+} stree_prop_t;
+
+/**
+ * Fake identifiers used with symbols that do not really have one.
+ * (Mostly for error messages.)
+ */
+#define INDEXER_IDENT "$indexer"
+
+typedef enum {
+	csimbr_csi,
+	csimbr_fun,
+	csimbr_var,
+	csimbr_prop
+} csimbr_class_t;
+
+/** Class, struct or interface member */
+typedef struct {
+	csimbr_class_t cc;
+
+	union {
+		struct stree_csi *csi;
+		stree_fun_t *fun;
+		stree_var_t *var;
+		stree_prop_t *prop;
+	} u;
+} stree_csimbr_t;
+
+typedef enum {
+	csi_class,
+	csi_struct,
+	csi_interface
+} csi_class_t;
+
+/** Class, struct or interface declaration */
+typedef struct stree_csi {
+	/** Which of class, struct or interface */
+	csi_class_t cc;
+
+	/** Name of this CSI */
+	stree_ident_t *name;
+
+	/** Symbol for this CSI */
+	struct stree_symbol *symbol;
+
+	/** Type expression referencing base CSI. */
+	stree_texpr_t *base_csi_ref;
+
+	/** Base CSI. Only available when ancr_state == ws_visited. */
+	struct stree_csi *base_csi;
+
+	/** Node state for ancr walks. */
+	walk_state_t ancr_state;
+
+	/** List of CSI members */
+	list_t members; /* of stree_csimbr_t */
+} stree_csi_t;
+
+typedef enum {
+	/* Class, struct or interface declaration */
+	mc_csi
+} modm_class_t;
+
+/** Module member */
+typedef struct {
+	modm_class_t mc;
+	union {
+		stree_csi_t *csi;
+	} u;
+} stree_modm_t;
+
+/** Module */
+typedef struct stree_module {
+	/** List of module members */
+	list_t members; /* of stree_modm_t */
+} stree_module_t;
+
+/** Symbol attribute class */
+typedef enum {
+	/** Builtin symbol (interpreter hook) */
+	sac_builtin
+} symbol_attr_class_t;
+
+/** Symbol atribute */
+typedef struct {
+	symbol_attr_class_t sac;
+} stree_symbol_attr_t;
+
+
+typedef enum {
+	sc_csi,
+	sc_fun,
+	sc_var,
+	sc_prop
+} symbol_class_t;
+
+/** Symbol
+ *
+ * A symbol is a common superclass of different program elements that
+ * allow us to refer to them, print their fully qualified names, etc.
+ */
+typedef struct stree_symbol {
+	symbol_class_t sc;
+
+	union {
+		struct stree_csi *csi;
+		stree_fun_t *fun;
+		stree_var_t *var;
+		stree_prop_t *prop;
+	} u;
+
+	/** Containing CSI (for all symbols) */
+	stree_csi_t *outer_csi;
+
+	/** Containing block (for block-level symbols) */
+	stree_block_t *outer_block;
+
+	/** Symbol attributes. */
+	list_t attr; /* of stree_symbol_attr_t */
+} stree_symbol_t;
+
+/** Program */
+typedef struct stree_program {
+	/** The one and only module in the program */
+	stree_module_t *module;
+
+	/** Builtin symbols binding. */
+	struct builtin *builtin;
+} stree_program_t;
+
+#endif
Index: uspace/app/sbi/src/strtab.c
===================================================================
--- uspace/app/sbi/src/strtab.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/strtab.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file String table.
+ *
+ * Converts strings to more compact SID (string ID, integer) and back.
+ * The string table is not an object as there will never be a need for
+ * more than one.
+ */
+
+#include <stdlib.h>
+#include "mytypes.h"
+#include "os/os.h"
+#include "list.h"
+
+#include "strtab.h"
+
+static list_t str_list;
+
+void strtab_init(void)
+{
+	list_init(&str_list);
+}
+
+sid_t strtab_get_sid(const char *str)
+{
+	list_node_t *node;
+	sid_t sid;
+
+	sid = 0;
+	node = list_first(&str_list);
+
+	while (node != NULL) {
+		++sid;
+		if (os_str_cmp(str, list_node_data(node, char *)) == 0)
+			return sid;
+
+		node = list_next(&str_list, node);
+	}
+
+	++sid;
+	list_append(&str_list, os_str_dup(str));
+
+	return sid;
+}
+
+char *strtab_get_str(sid_t sid)
+{
+	list_node_t *node;
+	sid_t cnt;
+
+	node = list_first(&str_list);
+	cnt = 1;
+	while (node != NULL && cnt < sid) {
+		node = list_next(&str_list, node);
+		cnt += 1;
+	}
+
+	if (node == NULL) {
+		printf("Internal error: Invalid SID %d", sid);
+		abort();
+	}
+
+	return list_node_data(node, char *);
+}
Index: uspace/app/sbi/src/strtab.h
===================================================================
--- uspace/app/sbi/src/strtab.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/strtab.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STRTAB_H_
+#define STRTAB_H_
+
+#include "mytypes.h"
+
+void strtab_init(void);
+sid_t strtab_get_sid(const char *str);
+char *strtab_get_str(sid_t sid);
+
+#endif
Index: uspace/app/sbi/src/strtab_t.h
===================================================================
--- uspace/app/sbi/src/strtab_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/strtab_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STRTAB_T_H_
+#define STRTAB_T_H_
+
+/** String ID */
+typedef int sid_t;
+
+#endif
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stype.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Implements a walk on the program that computes and checks static
+ * types. 'Types' the program.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "debug.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "run_texpr.h"
+#include "stree.h"
+#include "strtab.h"
+#include "stype_expr.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "stype.h"
+
+static void stype_csi(stype_t *stype, stree_csi_t *csi);
+static void stype_fun(stype_t *stype, stree_fun_t *fun);
+static void stype_var(stype_t *stype, stree_var_t *var);
+static void stype_prop(stype_t *stype, stree_prop_t *prop);
+
+static void stype_block(stype_t *stype, stree_block_t *block);
+
+static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s);
+static void stype_if(stype_t *stype, stree_if_t *if_s);
+static void stype_while(stype_t *stype, stree_while_t *while_s);
+static void stype_for(stype_t *stype, stree_for_t *for_s);
+static void stype_raise(stype_t *stype, stree_raise_t *raise_s);
+static void stype_return(stype_t *stype, stree_return_t *return_s);
+static void stype_exps(stype_t *stype, stree_exps_t *exp_s, bool_t want_value);
+static void stype_wef(stype_t *stype, stree_wef_t *wef_s);
+
+static tdata_item_t *stype_boolean_titem(stype_t *stype);
+
+/** Type module */
+void stype_module(stype_t *stype, stree_module_t *module)
+{
+	list_node_t *mbr_n;
+	stree_modm_t *mbr;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type module.\n");
+#endif
+	stype->current_csi = NULL;
+	stype->proc_vr = NULL;
+
+	mbr_n = list_first(&module->members);
+	while (mbr_n != NULL) {
+		mbr = list_node_data(mbr_n, stree_modm_t *);
+		assert(mbr->mc == mc_csi);
+
+		stype_csi(stype, mbr->u.csi);
+
+		mbr_n = list_next(&module->members, mbr_n);
+	}
+}
+
+/** Type CSI */
+static void stype_csi(stype_t *stype, stree_csi_t *csi)
+{
+	list_node_t *csimbr_n;
+	stree_csimbr_t *csimbr;
+	stree_csi_t *prev_ctx;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type CSI '");
+	symbol_print_fqn(csi_to_symbol(csi));
+	printf("'.\n");
+#endif
+	prev_ctx = stype->current_csi;
+	stype->current_csi = csi;
+
+	csimbr_n = list_first(&csi->members);
+	while (csimbr_n != NULL) {
+		csimbr = list_node_data(csimbr_n, stree_csimbr_t *);
+
+		switch (csimbr->cc) {
+		case csimbr_csi: stype_csi(stype, csimbr->u.csi); break;
+		case csimbr_fun: stype_fun(stype, csimbr->u.fun); break;
+		case csimbr_var: stype_var(stype, csimbr->u.var); break;
+		case csimbr_prop: stype_prop(stype, csimbr->u.prop); break;
+		}
+
+		csimbr_n = list_next(&csi->members, csimbr_n);
+	}
+
+	stype->current_csi = prev_ctx;
+}
+
+/** Type function */
+static void stype_fun(stype_t *stype, stree_fun_t *fun)
+{
+	list_node_t *arg_n;
+	stree_proc_arg_t *arg;
+	stree_symbol_t *fun_sym;
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function '");
+	symbol_print_fqn(fun_to_symbol(fun));
+	printf("'.\n");
+#endif
+	fun_sym = fun_to_symbol(fun);
+
+	/*
+	 * Type formal arguments.
+	 * XXX Save the results.
+	 */
+	arg_n = list_first(&fun->args);
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_proc_arg_t *);
+
+		/* XXX Because of overloaded builtin WriteLine. */
+		if (arg->type == NULL) {
+			arg_n = list_next(&fun->args, arg_n);
+			continue;
+		}
+
+		run_texpr(stype->program, fun_sym->outer_csi, arg->type,
+		    &titem);
+
+		arg_n = list_next(&fun->args, arg_n);
+	}
+
+	/* Variadic argument */
+	if (fun->varg != NULL) {
+		/* Check type and verify it is an array. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->varg->type,
+		    &titem);
+
+		if (titem->tic != tic_tarray) {
+			printf("Error: Packed argument is not an array.\n");
+			stype_note_error(stype);
+		}
+	}
+
+	/*
+	 * Type function body.
+	 */
+
+	/* Builtin functions do not have a body. */
+	if (fun->proc->body == NULL)
+		return;
+
+	stype->proc_vr = stype_proc_vr_new();
+	stype->proc_vr->proc = fun->proc;
+	list_init(&stype->proc_vr->block_vr);
+
+	stype_block(stype, fun->proc->body);
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
+}
+
+/** Type member variable */
+static void stype_var(stype_t *stype, stree_var_t *var)
+{
+	(void) stype;
+	(void) var;
+}
+
+/** Type property */
+static void stype_prop(stype_t *stype, stree_prop_t *prop)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type property '");
+	symbol_print_fqn(prop_to_symbol(prop));
+	printf("'.\n");
+#endif
+	stype->proc_vr = stype_proc_vr_new();
+	list_init(&stype->proc_vr->block_vr);
+
+	if (prop->getter != NULL) {
+		stype->proc_vr->proc = prop->getter;
+		stype_block(stype, prop->getter->body);
+	}
+
+	if (prop->setter != NULL) {
+		stype->proc_vr->proc = prop->setter;
+		stype_block(stype, prop->setter->body);
+	}
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
+}
+
+/** Type statement block */
+static void stype_block(stype_t *stype, stree_block_t *block)
+{
+	stree_stat_t *stat;
+	list_node_t *stat_n;
+	stype_block_vr_t *block_vr;
+	list_node_t *bvr_n;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type block.\n");
+#endif
+
+	/* Create block visit record. */
+	block_vr = stype_block_vr_new();
+	intmap_init(&block_vr->vdecls);
+
+	/* Add block visit record to the stack. */
+	list_append(&stype->proc_vr->block_vr, block_vr);
+
+	stat_n = list_first(&block->stats);
+	while (stat_n != NULL) {
+		stat = list_node_data(stat_n, stree_stat_t *);
+		stype_stat(stype, stat, b_false);
+
+		stat_n = list_next(&block->stats, stat_n);
+	}
+
+	/* Remove block visit record from the stack, */
+	bvr_n = list_last(&stype->proc_vr->block_vr);
+	assert(list_node_data(bvr_n, stype_block_vr_t *) == block_vr);
+	list_remove(&stype->proc_vr->block_vr, bvr_n);
+}
+
+/** Type statement
+ *
+ * Types a statement. If @a want_value is @c b_true, then warning about
+ * ignored expression value will be supressed for this statement (but not
+ * for nested statemens). This is used in interactive mode.
+ *
+ * @param stype		Static typer object.
+ * @param stat		Statement to type.
+ * @param want_value	@c b_true to allow ignoring expression value.
+ */
+void stype_stat(stype_t *stype, stree_stat_t *stat, bool_t want_value)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type statement.\n");
+#endif
+	switch (stat->sc) {
+	case st_vdecl: stype_vdecl(stype, stat->u.vdecl_s); break;
+	case st_if: stype_if(stype, stat->u.if_s); break;
+	case st_while: stype_while(stype, stat->u.while_s); break;
+	case st_for: stype_for(stype, stat->u.for_s); break;
+	case st_raise: stype_raise(stype, stat->u.raise_s); break;
+	case st_return: stype_return(stype, stat->u.return_s); break;
+	case st_exps: stype_exps(stype, stat->u.exp_s, want_value); break;
+	case st_wef: stype_wef(stype, stat->u.wef_s); break;
+	}
+}
+
+/** Type local variable declaration */
+static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s)
+{
+	stype_block_vr_t *block_vr;
+	stree_vdecl_t *old_vdecl;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type variable declaration statement.\n");
+#endif
+	block_vr = stype_get_current_block_vr(stype);
+	old_vdecl = (stree_vdecl_t *) intmap_get(&block_vr->vdecls,
+	    vdecl_s->name->sid);
+
+	if (old_vdecl != NULL) {
+		printf("Error: Duplicate variable declaration '%s'.\n",
+		    strtab_get_str(vdecl_s->name->sid));
+		stype_note_error(stype);
+	}
+
+	intmap_set(&block_vr->vdecls, vdecl_s->name->sid, vdecl_s);
+
+}
+
+/** Type @c if statement */
+static void stype_if(stype_t *stype, stree_if_t *if_s)
+{
+	stree_expr_t *ccond;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'if' statement.\n");
+#endif
+	/* Convert condition to boolean type. */
+	stype_expr(stype, if_s->cond);
+	ccond = stype_convert(stype, if_s->cond, stype_boolean_titem(stype));
+
+	/* Patch code with augmented expression. */
+	if_s->cond = ccond;
+
+	/* Type the @c if block */
+	stype_block(stype, if_s->if_block);
+
+	/* Type the @c else block */
+	if (if_s->else_block != NULL)
+		stype_block(stype, if_s->else_block);
+}
+
+/** Type @c while statement */
+static void stype_while(stype_t *stype, stree_while_t *while_s)
+{
+	stree_expr_t *ccond;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'while' statement.\n");
+#endif
+	/* Convert condition to boolean type. */
+	stype_expr(stype, while_s->cond);
+	ccond = stype_convert(stype, while_s->cond,
+	    stype_boolean_titem(stype));
+
+	/* Patch code with augmented expression. */
+	while_s->cond = ccond;
+
+	/* Type the body of the loop */
+	stype_block(stype, while_s->body);
+}
+
+/** Type @c for statement */
+static void stype_for(stype_t *stype, stree_for_t *for_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'for' statement.\n");
+#endif
+	stype_block(stype, for_s->body);
+}
+
+/** Type @c raise statement */
+static void stype_raise(stype_t *stype, stree_raise_t *raise_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'raise' statement.\n");
+#endif
+	stype_expr(stype, raise_s->expr);
+}
+
+/** Type @c return statement */
+static void stype_return(stype_t *stype, stree_return_t *return_s)
+{
+	stree_symbol_t *outer_sym;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+
+	stree_expr_t *cexpr;
+	tdata_item_t *dtype;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'return' statement.\n");
+#endif
+	stype_expr(stype, return_s->expr);
+
+	/* Determine the type we need to return. */
+
+	outer_sym = stype->proc_vr->proc->outer_symbol;
+	switch (outer_sym->sc) {
+	case sc_fun:
+		fun = symbol_to_fun(outer_sym);
+		assert(fun != NULL);
+
+		/* XXX Memoize to avoid recomputing. */
+		run_texpr(stype->program, outer_sym->outer_csi, fun->rtype,
+		    &dtype);
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_sym);
+		assert(prop != NULL);
+
+		if (stype->proc_vr->proc != prop->getter) {
+			printf("Error: Return statement in "
+			    "setter.\n");
+			stype_note_error(stype);
+		}
+
+		/* XXX Memoize to avoid recomputing. */
+		run_texpr(stype->program, outer_sym->outer_csi, prop->type,
+		    &dtype);
+		break;
+	default:
+		assert(b_false);
+	}
+
+	/* Convert to the return type. */
+	cexpr = stype_convert(stype, return_s->expr, dtype);
+
+	/* Patch code with the augmented expression. */
+	return_s->expr = cexpr;
+}
+
+/** Type expression statement */
+static void stype_exps(stype_t *stype, stree_exps_t *exp_s, bool_t want_value)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type expression statement.\n");
+#endif
+	stype_expr(stype, exp_s->expr);
+
+	if (want_value == b_false && exp_s->expr->titem != NULL)
+		printf("Warning: Expression value ignored.\n");
+}
+
+/** Type With-Except-Finally statement */
+static void stype_wef(stype_t *stype, stree_wef_t *wef_s)
+{
+	list_node_t *ec_n;
+	stree_except_t *ec;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type WEF statement.\n");
+#endif
+	/* Type the @c with block. */
+	if (wef_s->with_block != NULL)
+		stype_block(stype, wef_s->with_block);
+
+	/* Type the @c except clauses. */
+	ec_n = list_first(&wef_s->except_clauses);
+	while (ec_n != NULL) {
+		ec = list_node_data(ec_n, stree_except_t *);
+		stype_block(stype, ec->block);
+
+		ec_n = list_next(&wef_s->except_clauses, ec_n);
+	}
+
+	/* Type the @c finally block. */
+	if (wef_s->finally_block != NULL)
+		stype_block(stype, wef_s->finally_block);
+}
+
+/** Convert expression of one type to another type.
+ *
+ * If the type of expression @a expr is not compatible with @a dtype
+ * (i.e. there does not exist an implicit conversion from @a expr->type to
+ * @a dtype), this function will produce an error (Cannot convert A to B).
+ *
+ * Otherwise it will either return the expression unmodified (if there is
+ * no action to take at run time) or it will return a new expression
+ * while clobbering the old one. Typically this would just attach the
+ * expression as a subtree of the conversion.
+ *
+ * Note: No conversion that would require modifying @a expr is implemented
+ * yet.
+ */
+stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+	(void) stype;
+	src = expr->titem;
+
+	if (dest == NULL) {
+		printf("Error: Conversion destination is not valid.\n");
+		stype_note_error(stype);
+		return expr;
+	}
+
+	if (src == NULL) {
+		printf("Error: Conversion source is not valid.\n");
+		stype_note_error(stype);
+		return expr;
+	}
+
+	if (dest == NULL || src == NULL)
+		return expr;
+
+	/*
+	 * Special case: Nil to object.
+	 */
+	if (src->tic == tic_tprimitive && src->u.tprimitive->tpc == tpc_nil) {
+		if (dest->tic == tic_tobject)
+			return expr;
+	}
+
+	if (src->tic != dest->tic)
+		goto failure;
+
+	switch (src->tic) {
+	case tic_tprimitive:
+		/* Check if both have the same tprimitive class. */
+		if (src->u.tprimitive->tpc != dest->u.tprimitive->tpc)
+			goto failure;
+		break;
+	case tic_tobject:
+		/* Check if @c src is derived from @c dest. */
+		if (stree_is_csi_derived_from_csi(src->u.tobject->csi,
+		    dest->u.tobject->csi) != b_true) {
+			goto failure;
+		}
+		break;
+	case tic_tarray:
+		/* Compare rank and base type. */
+		if (src->u.tarray->rank != dest->u.tarray->rank)
+			goto failure;
+
+		/* XXX Should we convert each element? */
+		if (tdata_item_equal(src->u.tarray->base_ti,
+		    dest->u.tarray->base_ti) != b_true)
+			goto failure;
+		break;
+	default:
+		printf("Error: Unimplemented: Converting '");
+		tdata_item_print(src);
+		printf("' to '");
+		tdata_item_print(dest);
+		printf("'.\n");
+		stype_note_error(stype);
+	}
+
+	return expr;
+
+failure:
+	printf("Error: Cannot convert ");
+	tdata_item_print(src);
+	printf(" to ");
+	tdata_item_print(dest);
+	printf(".\n");
+
+	stype_note_error(stype);
+	return expr;
+}
+
+/** Return a boolean type item */
+static tdata_item_t *stype_boolean_titem(stype_t *stype)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+
+	(void) stype;
+
+	/* XXX Use a true boolean type */
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc_int);
+	titem->u.tprimitive = tprimitive;
+
+	return titem;
+}
+
+/** Find a local variable in the current function. */
+stree_vdecl_t *stype_local_vars_lookup(stype_t *stype, sid_t name)
+{
+	stype_proc_vr_t *proc_vr;
+	stype_block_vr_t *block_vr;
+	stree_vdecl_t *vdecl;
+	list_node_t *node;
+
+	proc_vr = stype->proc_vr;
+	node = list_last(&proc_vr->block_vr);
+
+	/* Walk through all block visit records. */
+	while (node != NULL) {
+		block_vr = list_node_data(node, stype_block_vr_t *);
+		vdecl = intmap_get(&block_vr->vdecls, name);
+		if (vdecl != NULL)
+			return vdecl;
+
+		node = list_prev(&proc_vr->block_vr, node);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Find argument of the current procedure. */
+stree_proc_arg_t *stype_proc_args_lookup(stype_t *stype, sid_t name)
+{
+	stype_proc_vr_t *proc_vr;
+
+	stree_symbol_t *outer_sym;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+
+	list_t *args;
+	list_node_t *arg_node;
+	stree_proc_arg_t *varg;
+	stree_proc_arg_t *arg;
+	stree_proc_arg_t *setter_arg;
+
+	proc_vr = stype->proc_vr;
+	outer_sym = proc_vr->proc->outer_symbol;
+
+	setter_arg = NULL;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Look for argument named '%s'.\n", strtab_get_str(name));
+#endif
+
+	switch (outer_sym->sc) {
+	case sc_fun:
+		fun = symbol_to_fun(outer_sym);
+		assert(fun != NULL);
+		args = &fun->args;
+		varg = fun->varg;
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_sym);
+		assert(prop != NULL);
+		args = &prop->args;
+		varg = prop->varg;
+
+		/* If we are in a setter, look also at setter argument. */
+		if (prop->setter == proc_vr->proc)
+			setter_arg = prop->setter_arg;
+		break;
+	default:
+		assert(b_false);
+	}
+
+	arg_node = list_first(args);
+	while (arg_node != NULL) {
+		arg = list_node_data(arg_node, stree_proc_arg_t *);
+		if (arg->name->sid == name) {
+			/* Match */
+#ifdef DEBUG_TYPE_TRACE
+			printf("Found argument.\n");
+#endif
+			return arg;
+		}
+
+		arg_node = list_next(args, arg_node);
+	}
+
+	/* Variadic argument */
+	if (varg != NULL && varg->name->sid == name) {
+#ifdef DEBUG_TYPE_TRACE
+		printf("Found variadic argument.\n");
+#endif
+		return varg;
+}
+
+	/* Setter argument */
+	if (setter_arg != NULL && setter_arg->name->sid == name) {
+#ifdef DEBUG_TYPE_TRACE
+		printf("Found setter argument.\n");
+#endif
+		return setter_arg;
+
+	}
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Not found.\n");
+#endif
+	/* No match */
+	return NULL;
+}
+
+/** Note a static typing error that has been immediately recovered. */
+void stype_note_error(stype_t *stype)
+{
+	stype->error = b_true;
+}
+
+/** Construct a special type item for recovery. */
+tdata_item_t *stype_recovery_titem(stype_t *stype)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+
+	(void) stype;
+
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc_int);
+
+	titem->u.tprimitive = tprimitive;
+
+	return titem;
+}
+
+/** Get current block visit record. */
+stype_block_vr_t *stype_get_current_block_vr(stype_t *stype)
+{
+	list_node_t *node;
+
+	node = list_last(&stype->proc_vr->block_vr);
+	return list_node_data(node, stype_block_vr_t *);
+}
+
+stype_proc_vr_t *stype_proc_vr_new(void)
+{
+	stype_proc_vr_t *proc_vr;
+
+	proc_vr = calloc(1, sizeof(stype_proc_vr_t));
+	if (proc_vr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc_vr;
+}
+
+stype_block_vr_t *stype_block_vr_new(void)
+{
+	stype_block_vr_t *block_vr;
+
+	block_vr = calloc(1, sizeof(stype_block_vr_t));
+	if (block_vr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return block_vr;
+}
Index: uspace/app/sbi/src/stype.h
===================================================================
--- uspace/app/sbi/src/stype.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stype.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_H_
+#define STYPE_H_
+
+#include "mytypes.h"
+
+void stype_module(stype_t *stype, stree_module_t *module);
+void stype_stat(stype_t *stype, stree_stat_t *stat, bool_t want_value);
+
+void stype_note_error(stype_t *stype);
+tdata_item_t *stype_recovery_titem(stype_t *stype);
+
+stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+
+stree_vdecl_t *stype_local_vars_lookup(stype_t *stype, sid_t name);
+stree_proc_arg_t *stype_proc_args_lookup(stype_t *stype, sid_t name);
+stype_block_vr_t *stype_get_current_block_vr(stype_t *stype);
+
+stype_proc_vr_t *stype_proc_vr_new(void);
+stype_block_vr_t *stype_block_vr_new(void);
+
+#endif
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stype_expr.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,905 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Type expressions. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "debug.h"
+#include "list.h"
+#include "mytypes.h"
+#include "run_texpr.h"
+#include "stree.h"
+#include "strtab.h"
+#include "stype.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "stype_expr.h"
+
+static void stype_nameref(stype_t *stype, stree_nameref_t *nameref,
+    tdata_item_t **rtitem);
+static void stype_literal(stype_t *stype, stree_literal_t *literal,
+    tdata_item_t **rtitem);
+static void stype_self_ref(stype_t *stype, stree_self_ref_t *self_ref,
+    tdata_item_t **rtitem);
+
+static void stype_binop(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_tprimitive(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+static void stype_binop_tobject(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+
+static void stype_unop(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t **rtitem);
+static void stype_new(stype_t *stype, stree_new_t *new,
+    tdata_item_t **rtitem);
+
+static void stype_access(stype_t *stype, stree_access_t *access,
+    tdata_item_t **rtitem);
+static void stype_access_tprimitive(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tobject(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tarray(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tgeneric(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+
+static void stype_call(stype_t *stype, stree_call_t *call,
+    tdata_item_t **rtitem);
+
+static void stype_index(stype_t *stype, stree_index_t *index,
+    tdata_item_t **rtitem);
+static void stype_index_tprimitive(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tobject(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tarray(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tgeneric(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+
+static void stype_assign(stype_t *stype, stree_assign_t *assign,
+    tdata_item_t **rtitem);
+static void stype_as(stype_t *stype, stree_as_t *as_op, tdata_item_t **rtitem);
+
+
+/** Type expression. */
+void stype_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *et;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type expression.\n");
+#endif
+	/* Silence warning. */
+	et = NULL;
+
+	switch (expr->ec) {
+	case ec_nameref: stype_nameref(stype, expr->u.nameref, &et); break;
+	case ec_literal: stype_literal(stype, expr->u.literal, &et); break;
+	case ec_self_ref: stype_self_ref(stype, expr->u.self_ref, &et); break;
+	case ec_binop: stype_binop(stype, expr->u.binop, &et); break;
+	case ec_unop: stype_unop(stype, expr->u.unop, &et); break;
+	case ec_new: stype_new(stype, expr->u.new_op, &et); break;
+	case ec_access: stype_access(stype, expr->u.access, &et); break;
+	case ec_call: stype_call(stype, expr->u.call, &et); break;
+	case ec_index: stype_index(stype, expr->u.index, &et); break;
+	case ec_assign: stype_assign(stype, expr->u.assign, &et); break;
+	case ec_as: stype_as(stype, expr->u.as_op, &et); break;
+	}
+
+	expr->titem = et;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Expression type is '");
+	tdata_item_print(et);
+	printf("'.\n");
+#endif
+}
+
+/** Type name reference. */
+static void stype_nameref(stype_t *stype, stree_nameref_t *nameref,
+    tdata_item_t **rtitem)
+{
+	stree_symbol_t *sym;
+	stree_vdecl_t *vdecl;
+	stree_proc_arg_t *proc_arg;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+	stree_csi_t *csi;
+	stree_fun_t *fun;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of name reference '%s'.\n",
+	    strtab_get_str(nameref->name->sid));
+#endif
+	/*
+	 * Look for a local variable declaration.
+	 */
+
+	vdecl = stype_local_vars_lookup(stype, nameref->name->sid);
+	if (vdecl != NULL) {
+		/* Found a local variable declaration. */
+#ifdef DEBUG_RUN_TRACE
+		printf("Found local variable declaration.\n");
+#endif
+		run_texpr(stype->program, stype->current_csi, vdecl->type,
+		    &titem);
+		*rtitem = titem;
+		return;
+	}
+
+	/*
+	 * Look for a procedure argument.
+	 */
+
+	proc_arg = stype_proc_args_lookup(stype, nameref->name->sid);
+	if (proc_arg != NULL) {
+		/* Found a procedure argument. */
+#ifdef DEBUG_RUN_TRACE
+		printf("Found procedure argument.\n");
+#endif
+		run_texpr(stype->program, stype->current_csi, proc_arg->type,
+		    &titem);
+		*rtitem = titem;
+		return;
+	}
+
+	/*
+	 * Look for a class-wide or global symbol.
+	 */
+
+	sym = symbol_lookup_in_csi(stype->program, stype->current_csi,
+	    nameref->name);
+
+	if (sym == NULL) {
+		/* Not found. */
+		if (stype->current_csi != NULL) {
+			printf("Error: Symbol '%s' not found in '",
+			    strtab_get_str(nameref->name->sid));
+			symbol_print_fqn(csi_to_symbol(stype->current_csi));
+			printf("'.\n");
+		} else {
+			printf("Error: Symbol '%s' not found.\n",
+			    strtab_get_str(nameref->name->sid));
+		}
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	switch (sym->sc) {
+	case sc_var:
+		run_texpr(stype->program, stype->current_csi,
+		    sym->u.var->type, &titem);
+		break;
+	case sc_prop:
+		run_texpr(stype->program, stype->current_csi,
+		    sym->u.prop->type, &titem);
+		break;
+	case sc_csi:
+		csi = symbol_to_csi(sym);
+		assert(csi != NULL);
+
+		titem = tdata_item_new(tic_tobject);
+		tobject = tdata_object_new();
+		titem->u.tobject = tobject;
+
+		/* This is a static CSI reference. */
+		tobject->static_ref = b_true;
+		tobject->csi = csi;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(sym);
+		assert(fun != NULL);
+
+		titem = tdata_item_new(tic_tfun);
+		titem->u.tfun = tdata_fun_new();
+		titem->u.tfun->fun = fun;
+		break;
+	}
+
+	*rtitem = titem;
+}
+
+/** Type a literal. */
+static void stype_literal(stype_t *stype, stree_literal_t *literal,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+	tprimitive_class_t tpc;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of literal.\n");
+#endif
+	(void) stype;
+
+	switch (literal->ltc) {
+	case ltc_int: tpc = tpc_int; break;
+	case ltc_ref: tpc = tpc_nil; break;
+	case ltc_string: tpc = tpc_string; break;
+	}
+
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc);
+	titem->u.tprimitive = tprimitive;
+
+	*rtitem = titem;
+}
+
+/** Type a self reference. */
+static void stype_self_ref(stype_t *stype, stree_self_ref_t *self_ref,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of self reference.\n");
+#endif
+	(void) stype;
+	(void) self_ref;
+
+	*rtitem = NULL;
+}
+
+/** Type a binary operation. */
+static void stype_binop(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	bool_t equal;
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of binary operation.\n");
+#endif
+	stype_expr(stype, binop->arg1);
+	stype_expr(stype, binop->arg2);
+
+	/* XXX This should be checked properly. */
+	assert(binop->arg1->titem != NULL);
+	assert(binop->arg2->titem != NULL);
+
+	if (binop->arg1->titem == NULL) {
+		printf("Error First binary operand has no value.\n");
+		stype_note_error(stype);
+		if (binop->arg2->titem != NULL)
+			*rtitem = binop->arg2->titem;
+		else
+			*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if (binop->arg2->titem == NULL) {
+		printf("Error: Second binary operand has no value.\n");
+		stype_note_error(stype);
+		*rtitem = binop->arg1->titem;
+		return;
+	}
+
+	equal = tdata_item_equal(binop->arg1->titem, binop->arg2->titem);
+	if (equal != b_true) {
+		printf("Error: Binary operation arguments "
+		    "have different types ('");
+		tdata_item_print(binop->arg1->titem);
+		printf("' and '");
+		tdata_item_print(binop->arg2->titem);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = binop->arg1->titem;
+		return;
+	}
+
+	titem = binop->arg1->titem;
+
+	switch (titem->tic) {
+	case tic_tprimitive:
+		stype_binop_tprimitive(stype, binop, binop->arg1->titem,
+		    binop->arg2->titem, rtitem);
+		break;
+	case tic_tobject:
+		stype_binop_tobject(stype, binop, binop->arg1->titem,
+		    binop->arg2->titem, rtitem);
+		break;
+	default:
+		printf("Error: Binary operation on value which is not of a "
+		    "supported type (found '");
+		tdata_item_print(titem);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = titem;
+		break;
+	}
+
+}
+
+/** Type a binary operation arguments of primitive type. */
+static void stype_binop_tprimitive(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	assert(ta->tic == tic_tprimitive);
+	assert(tb->tic == tic_tprimitive);
+
+	switch (ta->u.tprimitive->tpc) {
+	case tpc_int:
+		rtpc = tpc_int;
+		break;
+	case tpc_nil:
+		printf("Unimplemented; Binary operation on nil.\n");
+		stype_note_error(stype);
+		rtpc = tpc_nil;
+		break;
+	case tpc_string:
+		if (binop->bc != bo_plus) {
+			printf("Unimplemented: Binary operation(%d) "
+			    "on strings.\n", binop->bc);
+			stype_note_error(stype);
+		}
+		rtpc = tpc_string;
+		break;
+	case tpc_resource:
+		printf("Error: Cannot apply operator to resource type.\n");
+		stype_note_error(stype);
+		rtpc = tpc_resource;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation arguments of an object type. */
+static void stype_binop_tobject(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	assert(ta->tic == tic_tobject || (ta->tic == tic_tprimitive &&
+	    ta->u.tprimitive->tpc == tpc_nil));
+	assert(tb->tic == tic_tobject || (tb->tic == tic_tprimitive &&
+	    tb->u.tprimitive->tpc == tpc_nil));
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparing objects -> boolean (XXX int for now) type */
+		res_ti = tdata_item_new(tic_tprimitive);
+		res_ti->u.tprimitive = tdata_primitive_new(tpc_int);
+		break;
+	default:
+		printf("Error: Binary operation (%d) on objects.\n",
+		    binop->bc);
+		res_ti = NULL;
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+
+/** Type a unary operation. */
+static void stype_unop(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of unary operation.\n");
+#endif
+	stype_expr(stype, unop->arg);
+
+	*rtitem = NULL;
+}
+
+/** Type a @c new operation. */
+static void stype_new(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of 'new' operation.\n");
+#endif
+	/*
+	 * Type of @c new expression is exactly the type supplied as parameter
+	 * to the @c new operator.
+	 */
+	run_texpr(stype->program, stype->current_csi, new_op->texpr, rtitem);
+}
+
+/** Type a field access operation */
+static void stype_access(stype_t *stype, stree_access_t *access,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *arg_ti;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of access operation.\n");
+#endif
+	stype_expr(stype, access->arg);
+	arg_ti = access->arg->titem;
+
+	if (arg_ti == NULL) {
+		printf("Error: Argument of access has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	switch (arg_ti->tic) {
+	case tic_tprimitive:
+		stype_access_tprimitive(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tobject:
+		stype_access_tobject(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tarray:
+		stype_access_tarray(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tgeneric:
+		stype_access_tgeneric(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tfun:
+		printf("Error: Using '.' operator on a function.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+}
+
+/** Type a primitive type access operation. */
+static void stype_access_tprimitive(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing primitive type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type an object access operation. */
+static void stype_access_tobject(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	stree_symbol_t *member_sym;
+	stree_var_t *var;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type a CSI access operation.\n");
+#endif
+	assert(arg_ti->tic == tic_tobject);
+	tobject = arg_ti->u.tobject;
+
+	/* Look for a member with the specified name. */
+	member_sym = symbol_search_csi(stype->program, tobject->csi,
+	    access->member_name);
+
+	if (member_sym == NULL) {
+		/* No such member found. */
+		printf("Error: CSI '");
+		symbol_print_fqn(csi_to_symbol(tobject->csi));
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	switch (member_sym->sc) {
+	case sc_csi:
+		printf("Error: Accessing object member which is nested "
+		    "CSI.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(member_sym);
+		assert(fun != NULL);
+		*rtitem = tdata_item_new(tic_tfun);
+		(*rtitem)->u.tfun = tdata_fun_new();
+		(*rtitem)->u.tfun->fun = fun;
+		break;
+	case sc_var:
+		var = symbol_to_var(member_sym);
+		assert(var != NULL);
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, member_sym->outer_csi,
+		    var->type, rtitem);
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(member_sym);
+		assert(prop != NULL);
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, member_sym->outer_csi,
+		    prop->type, rtitem);
+		break;
+	}
+}
+
+/** Type an array access operation. */
+static void stype_access_tarray(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing array type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type a generic access operation. */
+static void stype_access_tgeneric(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing generic type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type a call operation. */
+static void stype_call(stype_t *stype, stree_call_t *call,
+    tdata_item_t **rtitem)
+{
+	list_node_t *farg_n;
+	stree_proc_arg_t *farg;
+	tdata_item_t *farg_ti;
+	tdata_item_t *varg_ti;
+
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	stree_expr_t *carg;
+
+	tdata_item_t *fun_ti;
+	stree_fun_t *fun;
+	stree_symbol_t *fun_sym;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of call operation.\n");
+#endif
+	/* Type the function */
+	stype_expr(stype, call->fun);
+
+	fun_ti = call->fun->titem;
+	assert(fun_ti->tic == tic_tfun);
+	fun = fun_ti->u.tfun->fun;
+	fun_sym = fun_to_symbol(fun);
+
+	/* Type and check the arguments. */
+	farg_n = list_first(&fun->args);
+	arg_n = list_first(&call->args);
+	while (farg_n != NULL && arg_n != NULL) {
+		farg = list_node_data(farg_n, stree_proc_arg_t *);
+		arg = list_node_data(arg_n, stree_expr_t *);
+		stype_expr(stype, arg);
+
+		/* XXX Because of overloaded bultin WriteLine */
+		if (farg->type == NULL) {
+			/* Skip the check */
+			farg_n = list_next(&fun->args, farg_n);
+			arg_n = list_next(&call->args, arg_n);
+			continue;
+		}
+
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, farg->type,
+		    &farg_ti);
+
+		/* Convert expression to type of formal argument. */
+		carg = stype_convert(stype, arg, farg_ti);
+
+		/* Patch code with augmented expression. */
+		list_node_setdata(arg_n, carg);
+
+		farg_n = list_next(&fun->args, farg_n);
+		arg_n = list_next(&call->args, arg_n);
+	}
+
+	/* Type and check variadic arguments. */
+	if (fun->varg != NULL) {
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->varg->type,
+		    &farg_ti);
+
+		/* Get array element type */
+		assert(farg_ti->tic == tic_tarray);
+		varg_ti = farg_ti->u.tarray->base_ti;
+
+		while (arg_n != NULL) {
+			arg = list_node_data(arg_n, stree_expr_t *);
+			stype_expr(stype, arg);
+
+			/* Convert expression to type of formal argument. */
+			carg = stype_convert(stype, arg, varg_ti);
+
+			/* Patch code with augmented expression. */
+			list_node_setdata(arg_n, carg);
+
+			arg_n = list_next(&call->args, arg_n);
+		}
+	}
+
+	if (farg_n != NULL) {
+		printf("Error: Too few arguments to function '");
+		symbol_print_fqn(fun_to_symbol(fun));
+		printf("'.\n");
+		stype_note_error(stype);
+	}
+
+	if (arg_n != NULL) {
+		printf("Error: Too many arguments to function '");
+		symbol_print_fqn(fun_to_symbol(fun));
+		printf("'.\n");
+		stype_note_error(stype);
+	}
+
+	if (fun->rtype != NULL) {
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->rtype,
+		    rtitem);
+	} else {
+		*rtitem = NULL;
+	}
+}
+
+/** Type an indexing operation. */
+static void stype_index(stype_t *stype, stree_index_t *index,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *base_ti;
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of index operation.\n");
+#endif
+	stype_expr(stype, index->base);
+	base_ti = index->base->titem;
+
+	/* Type the arguments (indices). */
+	arg_n = list_first(&index->args);
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_expr_t *);
+		stype_expr(stype, arg);
+
+		arg_n = list_next(&index->args, arg_n);
+	}
+
+	switch (base_ti->tic) {
+	case tic_tprimitive:
+		stype_index_tprimitive(stype, index, base_ti, rtitem);
+		break;
+	case tic_tobject:
+		stype_index_tobject(stype, index, base_ti, rtitem);
+		break;
+	case tic_tarray:
+		stype_index_tarray(stype, index, base_ti, rtitem);
+		break;
+	case tic_tgeneric:
+		stype_index_tgeneric(stype, index, base_ti, rtitem);
+		break;
+	case tic_tfun:
+		printf("Error: Indexing a function.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+}
+
+/** Type a primitive indexing operation. */
+static void stype_index_tprimitive(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	tdata_primitive_t *tprimitive;
+	tdata_item_t *titem;
+
+	(void) stype;
+	(void) index;
+
+	assert(base_ti->tic == tic_tprimitive);
+	tprimitive = base_ti->u.tprimitive;
+
+	if (tprimitive->tpc == tpc_string) {
+		titem = tdata_item_new(tic_tprimitive);
+		titem->u.tprimitive = tdata_primitive_new(tpc_int);
+		*rtitem = titem;
+		return;
+	}
+
+	printf("Error: Indexing primitive type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type an object indexing operation. */
+static void stype_index_tobject(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	tdata_object_t *tobject;
+	stree_symbol_t *idx_sym;
+	stree_prop_t *idx;
+	stree_ident_t *idx_ident;
+
+	(void) index;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Indexing object type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+#endif
+
+	assert(base_ti->tic == tic_tobject);
+	tobject = base_ti->u.tobject;
+
+	/* Find indexer symbol. */
+	idx_ident = stree_ident_new();
+	idx_ident->sid = strtab_get_sid(INDEXER_IDENT);
+	idx_sym = symbol_search_csi(stype->program, tobject->csi, idx_ident);
+
+	if (idx_sym == NULL) {
+		printf("Error: Indexing object of type '");
+		tdata_item_print(base_ti);
+		printf("' which does not have an indexer.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	idx = symbol_to_prop(idx_sym);
+	assert(idx != NULL);
+
+	/* XXX Memoize to avoid recomputing every time. */
+	run_texpr(stype->program, idx_sym->outer_csi, idx->type, rtitem);
+}
+
+/** Type an array indexing operation. */
+static void stype_index_tarray(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	int arg_count;
+
+	(void) stype;
+	assert(base_ti->tic == tic_tarray);
+
+	/*
+	 * Check that type of all indices is @c int and that the number of
+	 * indices matches array rank.
+	 */
+	arg_count = 0;
+	arg_n = list_first(&index->args);
+	while (arg_n != NULL) {
+		++arg_count;
+
+		arg = list_node_data(arg_n, stree_expr_t *);
+		if (arg->titem->tic != tic_tprimitive ||
+		    arg->titem->u.tprimitive->tpc != tpc_int) {
+
+			printf("Error: Array index is not an integer.\n");
+			stype_note_error(stype);
+		}
+
+		arg_n = list_next(&index->args, arg_n);
+	}
+
+	if (arg_count != base_ti->u.tarray->rank) {
+		printf("Error: Using %d indices with array of rank %d.\n",
+		    arg_count, base_ti->u.tarray->rank);
+		stype_note_error(stype);
+	}
+
+	*rtitem = base_ti->u.tarray->base_ti;
+}
+
+/** Type a generic indexing operation. */
+static void stype_index_tgeneric(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) index;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Indexing generic type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type an assignment. */
+static void stype_assign(stype_t *stype, stree_assign_t *assign,
+    tdata_item_t **rtitem)
+{
+	stree_expr_t *csrc;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of assignment.\n");
+#endif
+	stype_expr(stype, assign->dest);
+	stype_expr(stype, assign->src);
+
+	csrc = stype_convert(stype, assign->src, assign->dest->titem);
+
+	/* Patch code with the augmented expression. */
+	assign->src = csrc;
+	*rtitem = NULL;
+}
+
+/** Type @c as conversion. */
+static void stype_as(stype_t *stype, stree_as_t *as_op, tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of @c as conversion.\n");
+#endif
+	stype_expr(stype, as_op->arg);
+	run_texpr(stype->program, stype->current_csi, as_op->dtype, &titem);
+
+	/* Check that target type is derived from argument type. */
+	if (tdata_is_ti_derived_from_ti(titem, as_op->arg->titem) != b_true) {
+		printf("Error: Target of 'as' operator '");
+		tdata_item_print(titem);
+		printf("' is not derived from '");
+		tdata_item_print(as_op->arg->titem);
+		printf("'.\n");
+		stype_note_error(stype);
+	}
+
+	*rtitem = titem;
+}
Index: uspace/app/sbi/src/stype_expr.h
===================================================================
--- uspace/app/sbi/src/stype_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stype_expr.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_EXPR_H_
+#define STYPE_EXPR_H_
+
+#include "mytypes.h"
+
+void stype_expr(stype_t *stype, stree_expr_t *expr);
+
+#endif
Index: uspace/app/sbi/src/stype_t.h
===================================================================
--- uspace/app/sbi/src/stype_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/stype_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_T_H_
+#define STYPE_T_H_
+
+/** Block visit record
+ *
+ * One block VR is created for each block that we enter. A variable declaration
+ * statement inserts the variable declaration here. Upon leaving the block we
+ * pop from the stack, thus all the variable declarations from that block
+ * are forgotten.
+ */
+typedef struct run_block_vr {
+	/** Variable declarations in this block */
+	intmap_t vdecls; /* of stree_vdecl_t */
+} stype_block_vr_t;
+
+/** Procedure visit record
+ *
+ * A procedure can be a member function or a property getter or setter. A
+ * procedure visit record is created whenever @c stype (the static typing
+ * pass) enters a procedure.
+ */
+typedef struct run_proc_vr {
+	/** Definition of function or property being invoked */
+	struct stree_proc *proc;
+
+	/** Block activation records */
+	list_t block_vr; /* of run_block_ar_t */
+} stype_proc_vr_t;
+
+/** Static typer state object */
+typedef struct stype {
+	/** Code of the program being typed */
+	struct stree_program *program;
+
+	/**
+	 * CSI context in which we are currently typing. We keep an implicit
+	 * stack of these (in instances of local variable
+	 * @c stype_csi::prev_ctx.)
+	 */
+	struct stree_csi *current_csi;
+
+	/** Procedure VR for the current procedure. */
+	stype_proc_vr_t *proc_vr;
+
+	/** @c b_true if an error occured. */
+	bool_t error;
+} stype_t;
+
+#endif
Index: uspace/app/sbi/src/symbol.c
===================================================================
--- uspace/app/sbi/src/symbol.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/symbol.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Symbols. */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "list.h"
+#include "mytypes.h"
+#include "strtab.h"
+#include "stree.h"
+
+#include "symbol.h"
+
+static stree_symbol_t *symbol_search_global(stree_program_t *prog,
+    stree_ident_t *name);
+static stree_symbol_t *symbol_find_epoint_rec(stree_program_t *prog,
+    stree_ident_t *name, stree_csi_t *csi);
+static stree_ident_t *symbol_get_ident(stree_symbol_t *symbol);
+
+/** Lookup symbol in CSI using a type expression. */
+stree_symbol_t *symbol_xlookup_in_csi(stree_program_t *prog,
+    stree_csi_t *scope, stree_texpr_t *texpr)
+{
+	stree_symbol_t *a, *b;
+	stree_csi_t *a_csi;
+
+	switch (texpr->tc) {
+	case tc_tnameref:
+		return symbol_lookup_in_csi(prog, scope, texpr->u.tnameref->name);
+	case tc_taccess:
+		a = symbol_xlookup_in_csi(prog, scope, texpr->u.taccess->arg);
+		a_csi = symbol_to_csi(a);
+		if (a_csi == NULL) {
+			printf("Error: Symbol is not CSI.\n");
+			exit(1);
+		}
+		b = symbol_search_csi(prog, a_csi, texpr->u.taccess->member_name);
+		if (b == NULL) {
+			printf("Error: CSI '%s' not found\n", strtab_get_str(texpr->u.taccess->member_name->sid));
+			exit(1);
+		}
+		return b;
+	case tc_tapply:
+		printf("Internal error: Generic types not implemented.\n");
+		exit(1);
+	default:
+		assert(b_false);
+	}
+}
+
+/** Lookup symbol reference in CSI.
+ *
+ * @param prog	Program to look in.
+ * @param scope CSI in @a prog which is the base for references.
+ * @param name	Identifier of the symbol.
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+stree_symbol_t *symbol_lookup_in_csi(stree_program_t *prog, stree_csi_t *scope,
+	stree_ident_t *name)
+{
+	stree_symbol_t *symbol;
+
+	/* This CSI node should have been processed. */
+	assert(scope == NULL || scope->ancr_state == ws_visited);
+
+	symbol = NULL;
+	while (scope != NULL && symbol == NULL) {
+		symbol = symbol_search_csi(prog, scope, name);
+		scope = csi_to_symbol(scope)->outer_csi;
+	}
+
+	if (symbol == NULL)
+		symbol = symbol_search_global(prog, name);
+
+	return symbol;
+}
+
+/** Look for symbol strictly in CSI.
+ *
+ * Look for symbol in definition of a CSI and its ancestors. (But not
+ * in lexically enclosing CSI.)
+ */
+stree_symbol_t *symbol_search_csi(stree_program_t *prog,
+    stree_csi_t *scope, stree_ident_t *name)
+{
+	list_node_t *node;
+	stree_csimbr_t *csimbr;
+	stree_symbol_t *symbol;
+	stree_ident_t *mbr_name;
+	stree_symbol_t *base_csi_sym;
+	stree_csi_t *base_csi;
+
+	(void) prog;
+
+	/* Look in new members in this class. */
+
+	node = list_first(&scope->members);
+	while (node != NULL) {
+		csimbr = list_node_data(node, stree_csimbr_t *);
+		switch (csimbr->cc) {
+		case csimbr_csi: mbr_name = csimbr->u.csi->name; break;
+		case csimbr_fun: mbr_name = csimbr->u.fun->name; break;
+		case csimbr_var: mbr_name = csimbr->u.var->name; break;
+		case csimbr_prop: mbr_name = csimbr->u.prop->name; break;
+		default: assert(b_false);
+		}
+
+		if (name->sid == mbr_name->sid) {
+			/* Match */
+			switch (csimbr->cc) {
+			case csimbr_csi:
+				symbol = csi_to_symbol(csimbr->u.csi);
+				break;
+			case csimbr_fun:
+				symbol = fun_to_symbol(csimbr->u.fun);
+				break;
+			case csimbr_var:
+				symbol = var_to_symbol(csimbr->u.var);
+				break;
+			case csimbr_prop:
+				symbol = prop_to_symbol(csimbr->u.prop);
+				break;
+			default:
+				assert(b_false);
+			}
+			return symbol;
+		}
+		node = list_next(&scope->members, node);
+	}
+
+	/* Try inherited members. */
+	if (scope->base_csi_ref != NULL) {
+		base_csi_sym = symbol_xlookup_in_csi(prog,
+		    csi_to_symbol(scope)->outer_csi, scope->base_csi_ref);
+		base_csi = symbol_to_csi(base_csi_sym);
+		assert(base_csi != NULL);
+
+		return symbol_search_csi(prog, base_csi, name);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+static stree_symbol_t *symbol_search_global(stree_program_t *prog,
+    stree_ident_t *name)
+{
+	list_node_t *node;
+	stree_modm_t *modm;
+	stree_symbol_t *symbol;
+
+	node = list_first(&prog->module->members);
+	while (node != NULL) {
+		modm = list_node_data(node, stree_modm_t *);
+		if (name->sid == modm->u.csi->name->sid) {
+			/* Match */
+			switch (modm->mc) {
+			case mc_csi:
+				symbol = csi_to_symbol(modm->u.csi);
+				break;
+			default:
+				assert(b_false);
+			}
+			return symbol;
+		}
+		node = list_next(&prog->module->members, node);
+	}
+
+	return NULL;
+}
+
+/** Find entry point. */
+stree_symbol_t *symbol_find_epoint(stree_program_t *prog, stree_ident_t *name)
+{
+	list_node_t *node;
+	stree_modm_t *modm;
+	stree_symbol_t *entry, *etmp;
+
+	entry = NULL;
+
+	node = list_first(&prog->module->members);
+	while (node != NULL) {
+		modm = list_node_data(node, stree_modm_t *);
+		if (modm->mc == mc_csi) {
+			etmp = symbol_find_epoint_rec(prog, name, modm->u.csi);
+			if (etmp != NULL) {
+				if (entry != NULL) {
+					printf("Error: Duplicate entry point.\n");
+					exit(1);
+				}
+				entry = etmp;
+			}
+		}
+	    	node = list_next(&prog->module->members, node);
+	}
+
+	return entry;
+}
+
+static stree_symbol_t *symbol_find_epoint_rec(stree_program_t *prog,
+    stree_ident_t *name, stree_csi_t *csi)
+{
+	list_node_t *node;
+	stree_csimbr_t *csimbr;
+	stree_symbol_t *entry, *etmp;
+
+	entry = NULL;
+
+	node = list_first(&csi->members);
+	while (node != NULL) {
+		csimbr = list_node_data(node, stree_csimbr_t *);
+
+		switch (csimbr->cc) {
+		case csimbr_csi:
+			etmp = symbol_find_epoint_rec(prog, name, csimbr->u.csi);
+			if (etmp != NULL) {
+				if (entry != NULL) {
+					printf("Error: Duplicate entry point.\n");
+					exit(1);
+				}
+				entry = etmp;
+			}
+			break;
+		case csimbr_fun:
+			if (csimbr->u.fun->name->sid == name->sid) {
+				if (entry != NULL) {
+					printf("Error: Duplicate entry point.\n");
+					exit(1);
+				}
+				entry = fun_to_symbol(csimbr->u.fun);
+			}
+		default:
+			break;
+		}
+
+	    	node = list_next(&csi->members, node);
+	}
+
+	return entry;
+}
+
+stree_csi_t *symbol_to_csi(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_csi)
+		return NULL;
+
+	return symbol->u.csi;
+}
+
+stree_symbol_t *csi_to_symbol(stree_csi_t *csi)
+{
+	assert(csi->symbol);
+	return csi->symbol;
+}
+
+stree_fun_t *symbol_to_fun(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_fun)
+		return NULL;
+
+	return symbol->u.fun;
+}
+
+stree_symbol_t *fun_to_symbol(stree_fun_t *fun)
+{
+	assert(fun->symbol);
+	return fun->symbol;
+}
+
+stree_var_t *symbol_to_var(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_var)
+		return NULL;
+
+	return symbol->u.var;
+}
+
+stree_symbol_t *var_to_symbol(stree_var_t *var)
+{
+	assert(var->symbol);
+	return var->symbol;
+}
+
+stree_prop_t *symbol_to_prop(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_prop)
+		return NULL;
+
+	return symbol->u.prop;
+}
+
+stree_symbol_t *prop_to_symbol(stree_prop_t *prop)
+{
+	assert(prop->symbol);
+	return prop->symbol;
+}
+
+/** Print fully qualified name of symbol. */
+void symbol_print_fqn(stree_symbol_t *symbol)
+{
+	stree_ident_t *name;
+	stree_symbol_t *outer_sym;
+
+	if (symbol->outer_csi != NULL) {
+		outer_sym = csi_to_symbol(symbol->outer_csi);
+		symbol_print_fqn(outer_sym);
+		printf(".");
+	}
+
+	name = symbol_get_ident(symbol);
+	printf("%s", strtab_get_str(name->sid));
+}
+
+static stree_ident_t *symbol_get_ident(stree_symbol_t *symbol)
+{
+	stree_ident_t *ident;
+
+	switch (symbol->sc) {
+	case sc_csi: ident = symbol->u.csi->name; break;
+	case sc_fun: ident = symbol->u.fun->name; break;
+	case sc_var: ident = symbol->u.var->name; break;
+	case sc_prop: ident = symbol->u.prop->name; break;
+	}
+
+	return ident;
+}
Index: uspace/app/sbi/src/symbol.h
===================================================================
--- uspace/app/sbi/src/symbol.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/symbol.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYMBOL_H_
+#define SYMBOL_H_
+
+#include "mytypes.h"
+
+stree_symbol_t *symbol_xlookup_in_csi(stree_program_t *prog,
+    stree_csi_t *scope, stree_texpr_t *texpr);
+stree_symbol_t *symbol_lookup_in_csi(stree_program_t *prog, stree_csi_t *scope,
+    stree_ident_t *name);
+stree_symbol_t *symbol_search_csi(stree_program_t *prog, stree_csi_t *scope,
+    stree_ident_t *name);
+stree_symbol_t *symbol_find_epoint(stree_program_t *prog, stree_ident_t *name);
+
+stree_csi_t *symbol_to_csi(stree_symbol_t *symbol);
+stree_symbol_t *csi_to_symbol(stree_csi_t *csi);
+stree_fun_t *symbol_to_fun(stree_symbol_t *symbol);
+stree_symbol_t *fun_to_symbol(stree_fun_t *fun);
+stree_var_t *symbol_to_var(stree_symbol_t *symbol);
+stree_symbol_t *var_to_symbol(stree_var_t *var);
+stree_prop_t *symbol_to_prop(stree_symbol_t *symbol);
+stree_symbol_t *prop_to_symbol(stree_prop_t *prop);
+
+void symbol_print_fqn(stree_symbol_t *symbol);
+
+#endif
Index: uspace/app/sbi/src/tdata.c
===================================================================
--- uspace/app/sbi/src/tdata.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/tdata.c	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Run-time data representation. */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "mytypes.h"
+#include "stree.h"
+#include "symbol.h"
+
+#include "tdata.h"
+
+static void tdata_tprimitive_print(tdata_primitive_t *tprimitive);
+static void tdata_tobject_print(tdata_object_t *tobject);
+static void tdata_tarray_print(tdata_array_t *tarray);
+static void tdata_tgeneric_print(tdata_generic_t *tgeneric);
+static void tdata_tfun_print(tdata_fun_t *tfun);
+
+/** Determine if CSI @a a is derived from CSI described by type item @a tb. */
+bool_t tdata_is_csi_derived_from_ti(stree_csi_t *a, tdata_item_t *tb)
+{
+	bool_t res;
+
+	switch (tb->tic) {
+	case tic_tobject:
+		res = stree_is_csi_derived_from_csi(a, tb->u.tobject->csi);
+		break;
+	default:
+		printf("Error: Base type is not a CSI.\n");
+		exit(1);
+	}
+
+	return res;
+}
+
+/**
+ * Determine if CSI described by type item @a a is derived from CSI described
+ * by type item @a tb.
+ */
+bool_t tdata_is_ti_derived_from_ti(tdata_item_t *ta, tdata_item_t *tb)
+{
+	bool_t res;
+
+	switch (ta->tic) {
+	case tic_tobject:
+		res = tdata_is_csi_derived_from_ti(ta->u.tobject->csi, tb);
+		break;
+	default:
+		printf("Error: Derived type is not a CSI.\n");
+		exit(1);
+	}
+
+	return res;
+}
+
+/** Determine if two type items are equal (i.e. describe the same type). */
+bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b)
+{
+	/*
+	 * Special case: Nil vs. object
+	 *
+	 * XXX Type of @c Nil should probably be @c object to avoid this
+	 * madness.
+	 */
+	if (a->tic == tic_tprimitive && a->u.tprimitive->tpc == tpc_nil) {
+		if (b->tic == tic_tobject)
+			return b_true;
+	} else if (b->tic == tic_tprimitive && b->u.tprimitive->tpc == tpc_nil) {
+		if (a->tic == tic_tobject)
+			return b_true;
+	}
+
+	if (a->tic != b->tic)
+		return b_false;
+
+	switch (a->tic) {
+	case tic_tprimitive:
+		/* Check if both have the same tprimitive class. */
+		return (a->u.tprimitive->tpc == b->u.tprimitive->tpc);
+	case tic_tobject:
+		/* Check if both use the same CSI definition. */
+		return (a->u.tobject->csi == b->u.tobject->csi);
+	case tic_tarray:
+		/* Compare rank and base type. */
+		if (a->u.tarray->rank != b->u.tarray->rank)
+			return b_false;
+
+		return tdata_item_equal(a->u.tarray->base_ti,
+		    b->u.tarray->base_ti);
+	default:
+		printf("Warning: Unimplemented: Compare types '");
+		tdata_item_print(a);
+		printf("' and '");
+		tdata_item_print(b);
+		printf("'.\n");
+		return b_true;
+	}
+}
+
+/** Print type item. */
+void tdata_item_print(tdata_item_t *titem)
+{
+	if (titem == NULL) {
+		printf("none");
+		return;
+	}
+
+	switch (titem->tic) {
+	case tic_tprimitive:
+		tdata_tprimitive_print(titem->u.tprimitive);
+		break;
+	case tic_tobject:
+		tdata_tobject_print(titem->u.tobject);
+		break;
+	case tic_tarray:
+		tdata_tarray_print(titem->u.tarray);
+		break;
+	case tic_tgeneric:
+		tdata_tgeneric_print(titem->u.tgeneric);
+		break;
+	case tic_tfun:
+		tdata_tfun_print(titem->u.tfun);
+		break;
+	}
+}
+
+static void tdata_tprimitive_print(tdata_primitive_t *tprimitive)
+{
+	switch (tprimitive->tpc) {
+	case tpc_int: printf("int"); break;
+	case tpc_nil: printf("nil"); break;
+	case tpc_string: printf("string"); break;
+	case tpc_resource: printf("resource"); break;
+	}
+}
+
+static void tdata_tobject_print(tdata_object_t *tobject)
+{
+	stree_symbol_t *csi_sym;
+
+	csi_sym = csi_to_symbol(tobject->csi);
+	assert(csi_sym != NULL);
+	symbol_print_fqn(csi_sym);
+}
+
+static void tdata_tarray_print(tdata_array_t *tarray)
+{
+	int i;
+
+	tdata_item_print(tarray->base_ti);
+
+	printf("[");
+	for (i = 0; i < tarray->rank - 1; ++i)
+		printf(",");
+	printf("]");
+}
+
+static void tdata_tgeneric_print(tdata_generic_t *tgeneric)
+{
+	(void) tgeneric;
+	printf("unimplemented(generic)");
+}
+
+static void tdata_tfun_print(tdata_fun_t *tfun)
+{
+	(void) tfun;
+	printf("unimplemented(fun)");
+}
+
+tdata_item_t *tdata_item_new(titem_class_t tic)
+{
+	tdata_item_t *titem;
+
+	titem = calloc(1, sizeof(tdata_item_t));
+	if (titem == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	titem->tic = tic;
+	return titem;
+}
+
+tdata_array_t *tdata_array_new(void)
+{
+	tdata_array_t *tarray;
+
+	tarray = calloc(1, sizeof(tdata_array_t));
+	if (tarray == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tarray;
+}
+
+tdata_object_t *tdata_object_new(void)
+{
+	tdata_object_t *tobject;
+
+	tobject = calloc(1, sizeof(tdata_object_t));
+	if (tobject == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tobject;
+}
+
+tdata_primitive_t *tdata_primitive_new(tprimitive_class_t tpc)
+{
+	tdata_primitive_t *tprimitive;
+
+	tprimitive = calloc(1, sizeof(tdata_primitive_t));
+	if (tprimitive == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	tprimitive->tpc = tpc;
+	return tprimitive;
+}
+
+tdata_fun_t *tdata_fun_new(void)
+{
+	tdata_fun_t *tfun;
+
+	tfun = calloc(1, sizeof(tdata_fun_t));
+	if (tfun == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tfun;
+}
Index: uspace/app/sbi/src/tdata.h
===================================================================
--- uspace/app/sbi/src/tdata.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/tdata.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TDATA_H_
+#define TDATA_H_
+
+#include "mytypes.h"
+
+tdata_item_t *tdata_item_new(titem_class_t tic);
+tdata_array_t *tdata_array_new(void);
+tdata_object_t *tdata_object_new(void);
+tdata_primitive_t *tdata_primitive_new(tprimitive_class_t tpc);
+tdata_fun_t *tdata_fun_new(void);
+
+bool_t tdata_is_csi_derived_from_ti(stree_csi_t *a, tdata_item_t *tb);
+bool_t tdata_is_ti_derived_from_ti(tdata_item_t *ta, tdata_item_t *tb);
+bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b);
+void tdata_item_print(tdata_item_t *titem);
+
+#endif
Index: uspace/app/sbi/src/tdata_t.h
===================================================================
--- uspace/app/sbi/src/tdata_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/app/sbi/src/tdata_t.h	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Static type system representation. */
+
+#ifndef TDATA_T_H_
+#define TDATA_T_H_
+
+/** Class of primitive type. */
+typedef enum {
+	/** Integer type */
+	tpc_int,
+	/** Special type for nil reference */
+	tpc_nil,
+	/** String type */
+	tpc_string,
+	/** Resource type */
+	tpc_resource
+} tprimitive_class_t;
+
+/** Primitive type. */
+typedef struct {
+	/** Class of primitive type */
+	tprimitive_class_t tpc;
+} tdata_primitive_t;
+
+/** Object type. */
+typedef struct {
+	/** @c true if expression is a static CSI reference */
+	bool_t static_ref;
+
+	/** CSI definition */
+	struct stree_csi *csi;
+} tdata_object_t;
+
+/** Array type. */
+typedef struct {
+	/** Base type item */
+	struct tdata_item *base_ti;
+
+	/** Rank */
+	int rank;
+
+	/** Extents */
+	list_t extents; /* of stree_expr_t */
+} tdata_array_t;
+
+/** Generic type. */
+typedef struct {
+} tdata_generic_t;
+
+/** Functional type. */
+typedef struct {
+	/**
+	 * Function definition. We'll leave expansion to the call operation.
+	 */
+	struct stree_fun *fun;
+} tdata_fun_t;
+
+typedef enum {
+	tic_tprimitive,
+	tic_tobject,
+	tic_tarray,
+	tic_tgeneric,
+	tic_tfun
+} titem_class_t;
+
+/** Type item, the result of evaluating a type expression. */
+typedef struct tdata_item {
+	titem_class_t tic;
+
+	union {
+		tdata_primitive_t *tprimitive;
+		tdata_object_t *tobject;
+		tdata_array_t *tarray;
+		tdata_generic_t *tgeneric;
+		tdata_fun_t *tfun;
+	} u;
+} tdata_item_t;
+
+#endif
Index: uspace/dist/src/sysel/demos/array.sy
===================================================================
--- uspace/dist/src/sysel/demos/array.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/array.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,46 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class ArrayDemo is
+	fun Main() is
+		var a : int[,];
+		var i : int;
+
+		a = new int[3, 2];
+
+		a[0, 0] = 1;
+		a[1, 0] = 2;
+		a[2, 0] = 3;
+
+		i = 0;
+		while i < 3 do
+			Builtin.WriteLine(a[i, 0]);
+			i = i + 1;
+		end
+	end
+end
Index: uspace/dist/src/sysel/demos/count.sy
===================================================================
--- uspace/dist/src/sysel/demos/count.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/count.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,44 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class CountDemo is
+	fun Count(a : int; b : int) is
+		var i : int;
+
+		i = a;
+		while i < b do
+			Builtin.WriteLine(i);
+			i = i + 1;
+		end
+
+	end
+
+	fun Main() is
+		Count(0, 10);
+	end
+end
Index: uspace/dist/src/sysel/demos/except.sy
===================================================================
--- uspace/dist/src/sysel/demos/except.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/except.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,53 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class ExceptionDemo is
+	fun foo() is
+	        Builtin.WriteLine("Entered foo().");
+		raise new BaseException();
+	end
+
+	fun Main() is
+		do
+			foo();
+			foo();
+		except e : DerivedException do
+			Builtin.WriteLine("Caught derived exception.");
+		except e : BaseException do
+			Builtin.WriteLine("Caught base exception.");
+		finally do
+			Builtin.WriteLine("Finally.");
+		end
+	end
+end
+
+class BaseException is
+end
+
+class DerivedException : BaseException is
+end
Index: uspace/dist/src/sysel/demos/hello.sy
===================================================================
--- uspace/dist/src/sysel/demos/hello.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/hello.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,33 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class HelloWorld is
+	fun Main() is
+		Builtin.WriteLine("Hello world!");
+	end
+end
Index: uspace/dist/src/sysel/demos/hexec.sy
===================================================================
--- uspace/dist/src/sysel/demos/hexec.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/hexec.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,34 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class HelenOSExecDemo is
+	fun Main() is
+		Task.Exec("/app/tester");
+		Task.Exec("/app/tester", "print1");
+	end
+end
Index: uspace/dist/src/sysel/demos/htxtfile.sy
===================================================================
--- uspace/dist/src/sysel/demos/htxtfile.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/htxtfile.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,54 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class TextFileDemo is
+	fun Main() is
+		var name : string;
+		var line : string;
+
+		var in_file : TextFile;
+		var out_file : TextFile;
+
+		name = "/readme";
+
+		in_file = new TextFile();
+		in_file.OpenRead(name);
+
+		out_file = new TextFile();
+		out_file.OpenWrite("/out.txt");
+
+		while in_file.EOF != 1 do
+			line = in_file.ReadLine();
+			Builtin.WriteLine(name + ": " + line);
+			out_file.WriteLine(name + ": " + line);
+		end
+
+		in_file.Close();
+		out_file.Close();
+	end
+end
Index: uspace/dist/src/sysel/demos/inherit.sy
===================================================================
--- uspace/dist/src/sysel/demos/inherit.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/inherit.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,69 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class A is
+	fun Foo() is
+		Builtin.WriteLine("A.Foo()");
+	end
+end
+
+class B : A is
+	fun Foo() is
+		Builtin.WriteLine("B.Foo()");
+	end
+end
+
+class C : A is
+end
+
+class InheritanceDemo is
+	fun Main() is
+		var a : A;
+		var c : C;
+
+		-- Construct and assign object.
+		a = new A();
+		a.Foo();
+
+		-- Implicit conversion to base type.
+		a = new B();
+		a.Foo();
+
+		a = new C();
+		a.Foo();
+
+		-- Test 'as' operator for conversion to derived type.
+		c = a as C;
+
+		-- Test grandfather class.
+		var d : Object;
+		d = a;
+		d = new B();
+		d = c;
+	end
+end
Index: uspace/dist/src/sysel/demos/list.sy
===================================================================
--- uspace/dist/src/sysel/demos/list.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/list.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,143 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+-- Doubly-linked list implementation.
+class List is
+	var head : ListNode;
+
+	-- Initialize list.
+	fun Init() is
+		head = new ListNode();
+		head.prev = head;
+		head.next = head;
+	end
+
+	-- Append new entry at the end of the list.
+	fun Append(data : int) is
+		var n : ListNode;
+		var ntl : ListNode;
+
+		ntl = head.prev;
+
+		n = new ListNode();
+		n.value = data;
+
+		n.prev = ntl;
+		n.next = head;
+		n.head = head;
+
+		ntl.next = n;
+		head.prev = n;
+	end
+
+	-- Return first node in the list or @c nil if there is none.
+	prop First : ListNode is
+		get is
+		    return get_first();
+		end
+	end
+
+	-- Return first node in the list or @c nil if there is none.
+	fun get_first() : ListNode is
+		if head.next == head then
+			return nil;
+		else
+			return head.next;
+		end
+	end
+end
+
+class ListNode is
+	var value : int;
+
+	var prev : ListNode;
+	var next : ListNode;
+	var head : ListNode;
+
+	-- Value stored in this node.
+	prop Value : int is
+		get is
+			return value;
+		end
+	end
+
+	-- Previous node in list.
+	prop Prev : ListNode is
+		get is
+			return get_prev();
+		end
+	end
+
+	-- Next node in list.
+	prop Next : ListNode is
+		get is
+			return get_next();
+		end
+	end
+
+	-- Get next node.
+	fun get_next() : ListNode is
+		if next != head then
+			return next;
+		else
+			return nil;
+		end
+	end
+
+	-- Get previous node.
+	fun get_prev() : ListNode is
+		if prev != head then
+			return next;
+		else
+			return nil;
+		end
+	end
+
+end
+
+class ListDemo is
+	fun Main() is
+		var list : List;
+
+		list = new List();
+		list.Init();
+
+		list.Append(5);
+		list.Append(6);
+		list.Append(7);
+		list.Append(8);
+
+		var n : ListNode;
+
+		n = list.First;
+		while n != nil do
+			Builtin.WriteLine(n.value);
+			n = n.Next;
+		end
+	end
+end
Index: uspace/dist/src/sysel/demos/property.sy
===================================================================
--- uspace/dist/src/sysel/demos/property.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/property.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,138 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class Foo is
+	var x : int;
+
+	-- Example of a named property
+	prop X : int is
+		get is
+			Builtin.WriteLine("Getting value of X which is");
+			Builtin.WriteLine(x);
+			return x;
+		end
+
+		set value is
+			Builtin.WriteLine("Setting value of X to");
+			Builtin.WriteLine(value);
+			x = value;
+		end
+	end
+
+	-- Backing store for indexed properties
+	var iprops : int[];
+
+	-- Example of an indexed property set (i.e. an indexer)
+	prop self[index : int] : int is
+		get is
+			Builtin.WriteLine("Getting property with index ");
+			Builtin.WriteLine(index);
+			Builtin.WriteLine("which is");
+			Builtin.WriteLine(iprops[index]);
+
+			return iprops[index];
+		end
+
+		set value is
+			Builtin.WriteLine("Setting property with index ");
+			Builtin.WriteLine(index);
+			Builtin.WriteLine("to");
+			Builtin.WriteLine(value);
+
+			iprops[index] = value;
+		end
+	end
+
+	--
+	-- Class-type property. This is used for demonstrating property
+	-- field access. This case is still quite easy. It does not require
+	-- read-modify-write. Since class is a reference type, access
+	-- operator will read the value and dereference it, thereby
+	-- getting somewhere else (so the value will not be modified and
+	-- need not be written back).
+	--
+
+	var bprop : Bar;
+
+	prop B : Bar is
+		get is
+			Builtin.WriteLine("Getting B");
+			return bprop;
+		end
+		set value is
+			Builtin.WriteLine("Setting B");
+			bprop = value;
+		end
+	end
+
+end
+
+class Bar is
+	var i : int;
+end
+
+class PropertyDemo is
+	fun Main() is
+		var a : Foo;
+		var i : int;
+
+		a = new Foo();
+
+		-- Get value of named property.
+		a.X = 1;
+
+		-- Set value of named property.
+		i = a.X;
+
+		Builtin.WriteLine("Main(): Got ");
+		Builtin.WriteLine(i);
+
+		a.iprops = new int[5];
+
+		-- Set value of indexed property.
+		a[1] = 2;
+
+		-- Get value of indexed property.
+		i = a[1];
+
+		Builtin.WriteLine("Main(): Got ");
+		Builtin.WriteLine(i);
+
+		-- Property field access
+		var b : Bar;
+
+		b = new Bar();
+
+		b.i = 42;
+		a.bprop = b;
+
+		Builtin.WriteLine(a.bprop.i);
+		a.bprop.i = 2;
+		Builtin.WriteLine(a.bprop.i);
+	end
+end
Index: uspace/dist/src/sysel/demos/string.sy
===================================================================
--- uspace/dist/src/sysel/demos/string.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/string.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,42 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class StringDemo is
+	fun Main() is
+		-- Concatenate some strings.
+		Builtin.WriteLine("One-" + "two-" + "three!");
+
+		-- Extract characters from a string.
+		var i : int;
+		i = 0;
+		while i < 5 do
+			Builtin.WriteLine("ABCDE"[i]);
+			i = i + 1;
+		end
+	end
+end
Index: uspace/dist/src/sysel/demos/varargs.sy
===================================================================
--- uspace/dist/src/sysel/demos/varargs.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
+++ uspace/dist/src/sysel/demos/varargs.sy	(revision 7d6fe4db89ff2f41ed1c55a6255f9752bde88aad)
@@ -0,0 +1,51 @@
+--
+-- Copyright (c) 2010 Jiri Svoboda
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+-- o The name of the author may not be used to endorse or promote products
+--   derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+-- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+
+class VariadicArgumentsDemo is
+	--- Variadic function example.
+	--
+	-- A variadic function is declared by marking its last argument
+	-- with the attribute 'packed'.
+	--
+	-- Note that we need to pass 'n' just because the array type
+	-- does not implement the Length property yet.
+	--
+	fun Print(n : int; args : string[], packed) is
+		var i : int;
+
+		i = 0;
+		while i < n do
+			Builtin.WriteLine(args[i]);
+			i = i + 1;
+		end
+	end
+
+	fun Main() is
+		Print(5, "One", "Two", "Three", "Four", "Five");
+	end
+end
