Index: uspace/app/Makefile.common
===================================================================
--- uspace/app/Makefile.common	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ 	(revision )
@@ -1,92 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# 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.
-#
-
-## Common rules for building apps.
-#
-
-# Individual makefiles set:
-#
-#	USPACE_PREFIX	relative path to uspace/ directory
-#	LIBS		libraries to link with (with relative path)
-#	EXTRA_CFLAGS	additional flags to pass to C compiler
-#	JOB		job file name (like appname.job)
-#	OUTPUT		output binary name (like appname)
-#	SOURCES		list of source files
-#
-
-DEPEND = Makefile.depend
-DEPEND_PREV = $(DEPEND).prev
-
-LIBC_PREFIX = $(USPACE_PREFIX)/lib/libc
-LIBBLOCK_PREFIX = $(USPACE_PREFIX)/lib/libblock
-SOFTINT_PREFIX = $(USPACE_PREFIX)/lib/softint
-
-JOB = $(OUTPUT).job
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += $(EXTRA_CFLAGS)
-
-.PHONY: all build clean
-
-all: \
-    $(LIBC_PREFIX)/../../../version \
-    $(LIBC_PREFIX)/../../../Makefile.config \
-    $(LIBC_PREFIX)/../../../config.h \
-    $(LIBC_PREFIX)/../../../config.defs \
-    $(LIBS) \
-    \
-    $(OUTPUT) $(OUTPUT).disasm
-	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
-
-clean:
-	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
-	find . -name '*.o' -follow -exec rm \{\} \;
-
-build: 
-
--include $(DEPEND)
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-%.o: %.c $(DEPEND)
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
-ifeq ($(PRECHECK),y)
-	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
-endif
-
-$(DEPEND):
-	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
-	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,8 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
-EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I. -Icmds/ -Icmds/builtins -Icmds/modules
-
-OUTPUT = bdsh
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBCLUI_PREFIX)/libclui.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBCLUI_PREFIX) -I. -Icmds/ \
+	-Icmds/builtins -Icmds/modules
+BINARY = bdsh
 
 SOURCES = \
@@ -60,3 +60,3 @@
 	scli.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/bdsh/cmds/builtin_cmds.c
===================================================================
--- uspace/app/bdsh/cmds/builtin_cmds.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/builtin_cmds.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -34,5 +34,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include "errors.h"
 #include "cmds.h"
Index: uspace/app/bdsh/cmds/builtins/builtins.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/builtins.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/builtins/builtins.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -10,5 +10,5 @@
 #include "cd/cd_def.h"
 #include "exit/exit_def.h"
-	{NULL, NULL, NULL, NULL}
+	{NULL, NULL, NULL, NULL, NULL}
 };
 
Index: uspace/app/bdsh/cmds/builtins/cd/cd.c
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/builtins/cd/cd.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -32,5 +32,5 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <string.h>
+#include <str.h>
 #include <errno.h>
 
@@ -41,5 +41,5 @@
 #include "cd.h"
 
-static char * cmdname = "cd";
+static const char *cmdname = "cd";
 
 void help_cmd_cd(unsigned int level)
Index: uspace/app/bdsh/cmds/builtins/cd/cd_def.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/cd/cd_def.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/builtins/cd/cd_def.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -4,3 +4,4 @@
 	&cmd_cd,
 	&help_cmd_cd,
+	0
 },
Index: uspace/app/bdsh/cmds/builtins/exit/exit_def.h
===================================================================
--- uspace/app/bdsh/cmds/builtins/exit/exit_def.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/builtins/exit/exit_def.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -4,3 +4,4 @@
 	&cmd_exit,
 	&help_cmd_exit,
+	0
 },
Index: uspace/app/bdsh/cmds/cmds.h
===================================================================
--- uspace/app/bdsh/cmds/cmds.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/cmds.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -33,6 +33,6 @@
 /* Module structure */
 typedef struct {
-	char *name;         /* Name of the command */
-	char *desc;         /* Description of the command */
+	const char *name;   /* Name of the command */
+	const char *desc;   /* Description of the command */
 	mod_entry_t entry;  /* Command (exec) entry function */
 	mod_help_t help;    /* Command (help) entry function */
@@ -41,6 +41,6 @@
 /* Builtin structure, same as modules except different types of entry points */
 typedef struct {
-	char *name;
-	char *desc;
+	const char *name;
+	const char *desc;
 	builtin_entry_t entry;
 	builtin_help_t help;
@@ -57,5 +57,5 @@
 extern int is_module(const char *);
 extern int is_module_alias(const char *);
-extern char * alias_for_module(const char *);
+extern char *alias_for_module(const char *);
 extern int help_module(int, unsigned int);
 extern int run_module(int, char *[]);
@@ -65,5 +65,5 @@
 extern int is_builtin(const char *);
 extern int is_builtin_alias(const char *);
-extern char * alias_for_builtin(const char *);
+extern char *alias_for_builtin(const char *);
 extern int help_builtin(int, unsigned int);
 extern int run_builtin(int, char *[], cliuser_t *);
Index: uspace/app/bdsh/cmds/mod_cmds.c
===================================================================
--- uspace/app/bdsh/cmds/mod_cmds.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/mod_cmds.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -47,5 +47,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include "errors.h"
 #include "cmds.h"
Index: uspace/app/bdsh/cmds/modules/bdd/bdd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,5 +29,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include "config.h"
 #include "util.h"
@@ -73,5 +73,5 @@
 	size_t block_size;
 	int rc;
-	bn_t ba;
+	aoff64_t ba;
 	uint8_t b;
 
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -33,5 +33,5 @@
 #include <unistd.h>
 #include <getopt.h>
-#include <string.h>
+#include <str.h>
 #include <fcntl.h>
 
@@ -43,9 +43,9 @@
 #include "cmds.h"
 
-static char *cmdname = "cat";
+static const char *cmdname = "cat";
 #define CAT_VERSION "0.0.1"
 #define CAT_DEFAULT_BUFLEN 1024
 
-static char *cat_oops = "That option is not yet supported\n";
+static const char *cat_oops = "That option is not yet supported\n";
 
 static struct option const long_options[] = {
@@ -85,5 +85,5 @@
 {
 	int fd, bytes = 0, count = 0, reads = 0;
-	off_t total = 0;
+	off64_t total = 0;
 	char *buff = NULL;
 
Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -33,5 +33,5 @@
 #include <unistd.h>
 #include <getopt.h>
-#include <string.h>
+#include <str.h>
 #include <fcntl.h>
 #include "config.h"
@@ -74,5 +74,5 @@
 {
 	int fd1, fd2, bytes = 0;
-	off_t total = 0;
+	off64_t total = 0;
 	int64_t copied = 0;
 	char *buff = NULL;
Index: uspace/app/bdsh/cmds/modules/help/help.c
===================================================================
--- uspace/app/bdsh/cmds/modules/help/help.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/help/help.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 
 #include "config.h"
@@ -42,5 +42,5 @@
 #include "util.h"
 
-static char *cmdname = "help";
+static const char *cmdname = "help";
 extern const char *progname;
 
Index: uspace/app/bdsh/cmds/modules/kcon/kcon.c
===================================================================
--- uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,5 +40,5 @@
 #include "cmds.h"
 
-static char *cmdname = "kcon";
+static const char *cmdname = "kcon";
 
 /* Dispays help for kcon in various levels */
Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,5 +40,5 @@
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <string.h>
+#include <str.h>
 
 #include "errors.h"
@@ -49,5 +49,5 @@
 #include "cmds.h"
 
-static char *cmdname = "ls";
+static const char *cmdname = "ls";
 
 static void ls_scan_dir(const char *d, DIR *dirp)
Index: uspace/app/bdsh/cmds/modules/mkdir/mkdir.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/mkdir/mkdir.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #include <getopt.h>
 #include <stdarg.h>
-#include <string.h>
+#include <str.h>
 
 #include "config.h"
@@ -49,5 +49,5 @@
 #define MKDIR_VERSION "0.0.1"
 
-static char *cmdname = "mkdir";
+static const char *cmdname = "mkdir";
 
 static struct option const long_options[] = {
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #include <getopt.h>
 #include <stdarg.h>
-#include <string.h>
+#include <str.h>
 #include <ctype.h>
 
@@ -51,5 +51,5 @@
 #define BUFFER_SIZE 16384
 
-static char *cmdname = "mkfile";
+static const char *cmdname = "mkfile";
 
 static struct option const long_options[] = {
Index: uspace/app/bdsh/cmds/modules/module_aliases.h
===================================================================
--- uspace/app/bdsh/cmds/modules/module_aliases.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/module_aliases.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -12,5 +12,5 @@
  * the entry point being reached. */
 
-char *mod_aliases[] = {
+const char *mod_aliases[] = {
 	"ren", "mv",
 	"umount", "unmount",
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -58,5 +58,5 @@
 {
 	unsigned int argc;
-	char *mopts = "";
+	const char *mopts = "";
 	int rc;
 
Index: uspace/app/bdsh/cmds/modules/pwd/pwd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/pwd/pwd.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/pwd/pwd.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -39,5 +39,5 @@
 #include "pwd.h"
 
-static char * cmdname = "pwd";
+static const char *cmdname = "pwd";
 
 void help_cmd_pwd(unsigned int level)
Index: uspace/app/bdsh/cmds/modules/rm/rm.c
===================================================================
--- uspace/app/bdsh/cmds/modules/rm/rm.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/rm/rm.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -36,5 +36,5 @@
 #include <getopt.h>
 #include <mem.h>
-#include <string.h>
+#include <str.h>
 
 #include "config.h"
@@ -45,5 +45,5 @@
 #include "cmds.h"
 
-static char *cmdname = "rm";
+static const char *cmdname = "rm";
 #define RM_VERSION "0.0.1"
 
Index: uspace/app/bdsh/cmds/modules/sleep/sleep.c
===================================================================
--- uspace/app/bdsh/cmds/modules/sleep/sleep.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/sleep/sleep.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #include "cmds.h"
 
-static char *cmdname = "sleep";
+static const char *cmdname = "sleep";
 
 /* Dispays help for sleep in various levels */
Index: uspace/app/bdsh/cmds/modules/touch/touch.c
===================================================================
--- uspace/app/bdsh/cmds/modules/touch/touch.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/cmds/modules/touch/touch.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #include <dirent.h>
 #include <sys/types.h>
-#include <string.h>
+#include <str.h>
 
 #include "config.h"
@@ -47,5 +47,5 @@
 #include "cmds.h"
 
-static char *cmdname = "touch";
+static const char *cmdname = "touch";
 
 /* Dispays help for touch in various levels */
Index: uspace/app/bdsh/errors.c
===================================================================
--- uspace/app/bdsh/errors.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/errors.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -30,5 +30,5 @@
 
 #include <stdio.h>
-#include <string.h>
+#include <str.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -47,5 +47,5 @@
 /* Look up errno in cl_errors and return the corresponding string.
  * Return NULL if not found */
-static char *err2str(int err)
+static const char *err2str(int err)
 {
 
Index: uspace/app/bdsh/errstr.h
===================================================================
--- uspace/app/bdsh/errstr.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/errstr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -4,5 +4,5 @@
 /* Simple array to translate error codes to meaningful strings */
 
-static char *cl_errors[] = {
+static const char *cl_errors[] = {
 	"Success",
 	"Failure",
@@ -18,5 +18,5 @@
 };
 
-static char *err2str(int);
+static const char *err2str(int);
 
 #endif
Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/exec.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,6 +38,7 @@
 #include <stdlib.h>
 #include <unistd.h>
-#include <string.h>
+#include <str.h>
 #include <fcntl.h>
+#include <str_error.h>
 
 #include "config.h"
@@ -120,9 +121,10 @@
 	free(found);
 
-	tid = task_spawn((const char *)tmp, argv);
+	tid = task_spawn(tmp, (const char **) argv, &retval);
 	free(tmp);
 
 	if (tid == 0) {
-		cli_error(CL_EEXEC, "Cannot spawn `%s'.", cmd);
+		cli_error(CL_EEXEC, "%s: Cannot spawn `%s' (%s)", progname, cmd,
+		    str_error(retval));
 		return 1;
 	}
@@ -130,7 +132,8 @@
 	task_wait(tid, &texit, &retval);
 	if (texit != TASK_EXIT_NORMAL) {
-		printf("Command failed (unexpectedly terminated).\n");
+		printf("%s: Command failed (unexpectedly terminated)\n", progname);
 	} else if (retval != 0) {
-		printf("Command failed (return value %d).\n", retval);
+		printf("%s: Command failed (%s)\n",
+		    progname, str_error(retval));
 	}
 
Index: uspace/app/bdsh/exec.h
===================================================================
--- uspace/app/bdsh/exec.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/exec.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -5,3 +5,4 @@
 
 extern unsigned int try_exec(char *, char **);
+
 #endif
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/input.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -1,5 +1,4 @@
 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
  * All rights reserved.
- * Copyright (c) 2008, Jiri Svoboda - All Rights Reserved
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,5 +31,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <io/console.h>
 #include <io/keycode.h>
@@ -43,4 +42,5 @@
 #include <assert.h>
 #include <bool.h>
+#include <tinput.h>
 
 #include "config.h"
@@ -51,51 +51,8 @@
 #include "exec.h"
 
-#define HISTORY_LEN 10
+extern volatile unsigned int cli_quit;
 
 /** Text input field. */
-typedef struct {
-	/** Buffer holding text currently being edited */
-	wchar_t buffer[INPUT_MAX + 1];
-	/** Screen coordinates of the top-left corner of the text field */
-	int col0, row0;
-	/** Screen dimensions */
-	int con_cols, con_rows;
-	/** Number of characters in @c buffer */
-	int nc;
-	/** Caret position within buffer */
-	int pos;
-	/** Selection mark position within buffer */
-	int sel_start;
-
-	/** History (dynamically allocated strings) */
-	char *history[1 + HISTORY_LEN];
-	/** Number of entries in @c history, not counting [0] */
-	int hnum;
-	/** Current position in history */
-	int hpos;
-	/** Exit flag */
-	bool done;
-} tinput_t;
-
-/** Seek direction */
-typedef enum {
-	seek_backward = -1,
-	seek_forward = 1
-} seek_dir_t;
-
-static tinput_t tinput;
-
-static char *tinput_read(tinput_t *ti);
-static void tinput_insert_string(tinput_t *ti, const char *str);
-static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb);
-static bool tinput_sel_active(tinput_t *ti);
-static void tinput_sel_all(tinput_t *ti);
-static void tinput_sel_delete(tinput_t *ti);
-static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev);
-static void tinput_key_shift(tinput_t *ti, console_event_t *ev);
-static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev);
-static void tinput_key_unmod(tinput_t *ti, console_event_t *ev);
-static void tinput_pre_seek(tinput_t *ti, bool shift_held);
-static void tinput_post_seek(tinput_t *ti, bool shift_held);
+static tinput_t *tinput;
 
 /* Tokenizes input from console, sees if the first word is a built-in, if so
@@ -149,623 +106,8 @@
 }
 
-static void tinput_display_tail(tinput_t *ti, int start, int pad)
-{
-	static wchar_t dbuf[INPUT_MAX + 1];
-	int sa, sb;
-	int i, p;
-
-	tinput_sel_get_bounds(ti, &sa, &sb);
-
-	console_goto(fphone(stdout), (ti->col0 + start) % ti->con_cols,
-	    ti->row0 + (ti->col0 + start) / ti->con_cols);
-	console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
-
-	p = start;
-	if (p < sa) {
-		memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(wchar_t));
-		dbuf[sa - p] = '\0';
-		printf("%ls", dbuf);
-		p = sa;
-	}
-
-	if (p < sb) {
-		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_RED, 0);
-		memcpy(dbuf, ti->buffer + p,
-		    (sb - p) * sizeof(wchar_t));
-		dbuf[sb - p] = '\0';
-		printf("%ls", dbuf);
-		p = sb;
-	}
-
-	fflush(stdout);
-	console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
-
-	if (p < ti->nc) {
-		memcpy(dbuf, ti->buffer + p,
-		    (ti->nc - p) * sizeof(wchar_t));
-		dbuf[ti->nc - p] = '\0';
-		printf("%ls", dbuf);
-	}
-
-	for (i = 0; i < pad; ++i)
-		putchar(' ');
-	fflush(stdout);
-}
-
-static char *tinput_get_str(tinput_t *ti)
-{
-	return wstr_to_astr(ti->buffer);
-}
-
-static void tinput_position_caret(tinput_t *ti)
-{
-	console_goto(fphone(stdout), (ti->col0 + ti->pos) % ti->con_cols,
-	    ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
-}
-
-/** Update row0 in case the screen could have scrolled. */
-static void tinput_update_origin(tinput_t *ti)
-{
-	int width, rows;
-
-	width = ti->col0 + ti->nc;
-	rows = (width / ti->con_cols) + 1;
-
-	/* Update row0 if the screen scrolled. */
-	if (ti->row0 + rows > ti->con_rows)
-		ti->row0 = ti->con_rows - rows;	
-}
-
-static void tinput_insert_char(tinput_t *ti, wchar_t c)
-{
-	int i;
-	int new_width, new_height;
-
-	if (ti->nc == INPUT_MAX)
-		return;
-
-	new_width = ti->col0 + ti->nc + 1;
-	if (new_width % ti->con_cols == 0) {
-		/* Advancing to new line. */
-		new_height = (new_width / ti->con_cols) + 1;
-		if (new_height >= ti->con_rows)
-			return; /* Disallow text longer than 1 page for now. */
-	}
-
-	for (i = ti->nc; i > ti->pos; --i)
-		ti->buffer[i] = ti->buffer[i - 1];
-
-	ti->buffer[ti->pos] = c;
-	ti->pos += 1;
-	ti->nc += 1;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos - 1, 0);
-	tinput_update_origin(ti);
-	tinput_position_caret(ti);
-}
-
-static void tinput_insert_string(tinput_t *ti, const char *str)
-{
-	int i;
-	int new_width, new_height;
-	int ilen;
-	wchar_t c;
-	size_t off;
-
-	ilen = min((ssize_t) str_length(str), INPUT_MAX - ti->nc);
-	if (ilen == 0)
-		return;
-
-	new_width = ti->col0 + ti->nc + ilen;
-	new_height = (new_width / ti->con_cols) + 1;
-	if (new_height >= ti->con_rows)
-		return; /* Disallow text longer than 1 page for now. */
-
-	for (i = ti->nc - 1; i >= ti->pos; --i)
-		ti->buffer[i + ilen] = ti->buffer[i];
-
-	off = 0; i = 0;
-	while (i < ilen) {
-		c = str_decode(str, &off, STR_NO_LIMIT);
-		if (c == '\0')
-			break;
-
-		/* Filter out non-printable chars. */
-		if (c < 32)
-			c = 32;
-
-		ti->buffer[ti->pos + i] = c;
-		++i;
-	}
-
-	ti->pos += ilen;
-	ti->nc += ilen;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos - ilen, 0);
-	tinput_update_origin(ti);
-	tinput_position_caret(ti);
-}
-
-static void tinput_backspace(tinput_t *ti)
-{
-	int i;
-
-	if (tinput_sel_active(ti)) {
-		tinput_sel_delete(ti);
-		return;
-	}
-
-	if (ti->pos == 0)
-		return;
-
-	for (i = ti->pos; i < ti->nc; ++i)
-		ti->buffer[i - 1] = ti->buffer[i];
-	ti->pos -= 1;
-	ti->nc -= 1;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos, 1);
-	tinput_position_caret(ti);
-}
-
-static void tinput_delete(tinput_t *ti)
-{
-	if (tinput_sel_active(ti)) {
-		tinput_sel_delete(ti);
-		return;
-	}
-
-	if (ti->pos == ti->nc)
-		return;
-
-	ti->pos += 1;
-	ti->sel_start = ti->pos;
-
-	tinput_backspace(ti);
-}
-
-static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos < ti->nc)
-			ti->pos += 1;
-	} else {
-		if (ti->pos > 0)
-			ti->pos -= 1;
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos == ti->nc)
-			return;
-
-		while (1) {
-			ti->pos += 1;
-
-			if (ti->pos == ti->nc)
-				break;
-
-			if (ti->buffer[ti->pos - 1] == ' ' &&
-			    ti->buffer[ti->pos] != ' ')
-				break;
-		}
-	} else {
-		if (ti->pos == 0)
-			return;
-
-		while (1) {
-			ti->pos -= 1;
-
-			if (ti->pos == 0)
-				break;
-
-			if (ti->buffer[ti->pos - 1] == ' ' &&
-			    ti->buffer[ti->pos] != ' ')
-				break;
-		}
-
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos + ti->con_cols <= ti->nc)
-			ti->pos = ti->pos + ti->con_cols;
-	} else {
-		if (ti->pos - ti->con_cols >= 0)
-			ti->pos = ti->pos - ti->con_cols;
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_backward)
-		ti->pos = 0;
-	else
-		ti->pos = ti->nc;
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_pre_seek(tinput_t *ti, bool shift_held)
-{
-	if (tinput_sel_active(ti) && !shift_held) {
-		/* Unselect and redraw. */
-		ti->sel_start = ti->pos;
-		tinput_display_tail(ti, 0, 0);
-		tinput_position_caret(ti);
-	}
-}
-
-static void tinput_post_seek(tinput_t *ti, bool shift_held)
-{
-	if (shift_held) {
-		/* Selecting text. Need redraw. */
-		tinput_display_tail(ti, 0, 0);
-	} else {
-		/* Shift not held. Keep selection empty. */
-		ti->sel_start = ti->pos;
-	}
-	tinput_position_caret(ti);
-}
-
-static void tinput_history_insert(tinput_t *ti, char *str)
-{
-	int i;
-
-	if (ti->hnum < HISTORY_LEN) {
-		ti->hnum += 1;
-	} else {
-		if (ti->history[HISTORY_LEN] != NULL)
-			free(ti->history[HISTORY_LEN]);
-	}
-
-	for (i = ti->hnum; i > 1; --i)
-		ti->history[i] = ti->history[i - 1];
-
-	ti->history[1] = str_dup(str);
-
-	if (ti->history[0] != NULL) {
-		free(ti->history[0]);
-		ti->history[0] = NULL;
-	}
-}
-
-static void tinput_set_str(tinput_t *ti, char *str)
-{
-	str_to_wstr(ti->buffer, INPUT_MAX, str);
-	ti->nc = wstr_length(ti->buffer);
-	ti->pos = ti->nc;
-	ti->sel_start = ti->pos;
-}
-
-static void tinput_sel_get_bounds(tinput_t *ti, int *sa, int *sb)
-{
-	if (ti->sel_start < ti->pos) {
-		*sa = ti->sel_start;
-		*sb = ti->pos;
-	} else {
-		*sa = ti->pos;
-		*sb = ti->sel_start;
-	}
-}
-
-static bool tinput_sel_active(tinput_t *ti)
-{
-	return ti->sel_start != ti->pos;
-}
-
-static void tinput_sel_all(tinput_t *ti)
-{
-	ti->sel_start = 0;
-	ti->pos = ti->nc;
-	tinput_display_tail(ti, 0, 0);
-	tinput_position_caret(ti);
-}
-
-static void tinput_sel_delete(tinput_t *ti)
-{
-	int sa, sb;
-
-	tinput_sel_get_bounds(ti, &sa, &sb);
-	if (sa == sb)
-		return;
-
-	memmove(ti->buffer + sa, ti->buffer + sb,
-	    (ti->nc - sb) * sizeof(wchar_t));
-	ti->pos = ti->sel_start = sa;
-	ti->nc -= (sb - sa);
-	ti->buffer[ti->nc] = '\0';
-
-	tinput_display_tail(ti, sa, sb - sa);
-	tinput_position_caret(ti);
-}
-
-static void tinput_sel_copy_to_cb(tinput_t *ti)
-{
-	int sa, sb;
-	wchar_t tmp_c;
-	char *str;
-
-	tinput_sel_get_bounds(ti, &sa, &sb);
-
-	if (sb < ti->nc) {
-		tmp_c = ti->buffer[sb];
-		ti->buffer[sb] = '\0';
-	}
-
-	str = wstr_to_astr(ti->buffer + sa);
-
-	if (sb < ti->nc)
-		ti->buffer[sb] = tmp_c;
-
-	if (str == NULL)
-		goto error;
-
-	if (clipboard_put_str(str) != EOK)
-		goto error;
-
-	free(str);
-	return;
-error:
-	return;
-	/* TODO: Give the user some warning. */
-}
-
-static void tinput_paste_from_cb(tinput_t *ti)
+void get_input(cliuser_t *usr)
 {
 	char *str;
 	int rc;
-
-	rc = clipboard_get_str(&str);
-	if (rc != EOK || str == NULL)
-		return; /* TODO: Give the user some warning. */
-
-	tinput_insert_string(ti, str);
-	free(str);
-}
-
-static void tinput_history_seek(tinput_t *ti, int offs)
-{
-	int pad;
-
-	if (ti->hpos + offs < 0 || ti->hpos + offs > ti->hnum)
-		return;
-
-	if (ti->history[ti->hpos] != NULL) {
-		free(ti->history[ti->hpos]);
-		ti->history[ti->hpos] = NULL;
-	}
-
-	ti->history[ti->hpos] = tinput_get_str(ti);
-	ti->hpos += offs;
-
-	pad = ti->nc - str_length(ti->history[ti->hpos]);
-	if (pad < 0) pad = 0;
-
-	tinput_set_str(ti, ti->history[ti->hpos]);
-	tinput_display_tail(ti, 0, pad);
-	tinput_update_origin(ti);
-	tinput_position_caret(ti);
-}
-
-/** Initialize text input field.
- *
- * Must be called before using the field. It clears the history.
- */
-static void tinput_init(tinput_t *ti)
-{
-	ti->hnum = 0;
-	ti->hpos = 0;
-	ti->history[0] = NULL;
-}
-
-/** Read in one line of input. */
-static char *tinput_read(tinput_t *ti)
-{
-	console_event_t ev;
-	char *str;
-
-	fflush(stdout);
-
-	if (console_get_size(fphone(stdin), &ti->con_cols, &ti->con_rows) != EOK)
-		return NULL;
-	if (console_get_pos(fphone(stdin), &ti->col0, &ti->row0) != EOK)
-		return NULL;
-
-	ti->pos = ti->sel_start = 0;
-	ti->nc = 0;
-	ti->buffer[0] = '\0';
-	ti->done = false;
-
-	while (!ti->done) {
-		fflush(stdout);
-		if (!console_get_event(fphone(stdin), &ev))
-			return NULL;
-
-		if (ev.type != KEY_PRESS)
-			continue;
-
-		if ((ev.mods & KM_CTRL) != 0 &&
-		    (ev.mods & (KM_ALT | KM_SHIFT)) == 0) {
-			tinput_key_ctrl(ti, &ev);
-		}
-
-		if ((ev.mods & KM_SHIFT) != 0 &&
-		    (ev.mods & (KM_CTRL | KM_ALT)) == 0) {
-			tinput_key_shift(ti, &ev);
-		}
-
-		if ((ev.mods & KM_CTRL) != 0 &&
-		    (ev.mods & KM_SHIFT) != 0 &&
-		    (ev.mods & KM_ALT) == 0) {
-			tinput_key_ctrl_shift(ti, &ev);
-		}
-
-		if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
-			tinput_key_unmod(ti, &ev);
-		}
-
-		if (ev.c >= ' ') {
-			tinput_sel_delete(ti);
-			tinput_insert_char(ti, ev.c);
-		}
-	}
-
-	ti->pos = ti->nc;
-	tinput_position_caret(ti);
-	putchar('\n');
-
-	str = tinput_get_str(ti);
-	if (str_cmp(str, "") != 0)
-		tinput_history_insert(ti, str);
-
-	ti->hpos = 0;
-
-	return str;
-}
-
-static void tinput_key_ctrl(tinput_t *ti, console_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_word(ti, seek_backward, false);
-		break;
-	case KC_RIGHT:
-		tinput_seek_word(ti, seek_forward, false);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, false);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, false);
-		break;
-	case KC_X:
-		tinput_sel_copy_to_cb(ti);
-		tinput_sel_delete(ti);
-		break;
-	case KC_C:
-		tinput_sel_copy_to_cb(ti);
-		break;
-	case KC_V:
-		tinput_sel_delete(ti);
-		tinput_paste_from_cb(ti);
-		break;
-	case KC_A:
-		tinput_sel_all(ti);
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_ctrl_shift(tinput_t *ti, console_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_word(ti, seek_backward, true);
-		break;
-	case KC_RIGHT:
-		tinput_seek_word(ti, seek_forward, true);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, true);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, true);
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_shift(tinput_t *ti, console_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_cell(ti, seek_backward, true);
-		break;
-	case KC_RIGHT:
-		tinput_seek_cell(ti, seek_forward, true);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, true);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, true);
-		break;
-	case KC_HOME:
-		tinput_seek_max(ti, seek_backward, true);
-		break;
-	case KC_END:
-		tinput_seek_max(ti, seek_forward, true);
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_unmod(tinput_t *ti, console_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_ENTER:
-	case KC_NENTER:
-		ti->done = true;
-		break;
-	case KC_BACKSPACE:
-		tinput_backspace(ti);
-		break;
-	case KC_DELETE:
-		tinput_delete(ti);
-		break;
-	case KC_LEFT:
-		tinput_seek_cell(ti, seek_backward, false);
-		break;
-	case KC_RIGHT:
-		tinput_seek_cell(ti, seek_forward, false);
-		break;
-	case KC_HOME:
-		tinput_seek_max(ti, seek_backward, false);
-		break;
-	case KC_END:
-		tinput_seek_max(ti, seek_forward, false);
-		break;
-	case KC_UP:
-		tinput_history_seek(ti, +1);
-		break;
-	case KC_DOWN:
-		tinput_history_seek(ti, -1);
-		break;
-	default:
-		break;
-	}
-}
-
-void get_input(cliuser_t *usr)
-{
-	char *str;
 
 	fflush(stdout);
@@ -775,5 +117,16 @@
 	console_set_style(fphone(stdout), STYLE_NORMAL);
 
-	str = tinput_read(&tinput);
+	rc = tinput_read(tinput, &str);
+	if (rc == ENOENT) {
+		/* User requested exit */
+		cli_quit = 1;
+		putchar('\n');
+		return;
+	}
+
+	if (rc != EOK) {
+		/* Error in communication with console */
+		return;
+	}
 
 	/* Check for empty input. */
@@ -787,6 +140,12 @@
 }
 
-void input_init(void)
+int input_init(void)
 {
-	tinput_init(&tinput);
+	tinput = tinput_new();
+	if (tinput == NULL) {
+		printf("Failed to initialize input.\n");
+		return 1;
+	}
+
+	return 0;
 }
Index: uspace/app/bdsh/input.h
===================================================================
--- uspace/app/bdsh/input.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/input.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -8,5 +8,5 @@
 extern void get_input(cliuser_t *);
 extern int tok_input(cliuser_t *);
-extern void input_init(void);
+extern int input_init(void);
 
 #endif
Index: uspace/app/bdsh/scli.c
===================================================================
--- uspace/app/bdsh/scli.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/scli.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <unistd.h>
 #include "config.h"
@@ -65,5 +65,6 @@
 	usr->lasterr = 0;
 
-	input_init();
+	if (input_init() != 0)
+		return 1;
 
 	return (int) cli_set_prompt(usr);
@@ -99,7 +100,7 @@
 		}
 	}
-	goto finit;
 
-finit:
+	printf("Leaving %s.\n", progname);
+
 	cli_finit(&usr);
 	return ret;
Index: uspace/app/bdsh/scli.h
===================================================================
--- uspace/app/bdsh/scli.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/scli.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -6,5 +6,5 @@
 
 typedef struct {
-	char *name;
+	const char *name;
 	char *line;
 	char *cwd;
@@ -13,3 +13,5 @@
 } cliuser_t;
 
+extern const char *progname;
+
 #endif
Index: uspace/app/bdsh/util.c
===================================================================
--- uspace/app/bdsh/util.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/bdsh/util.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,5 +29,5 @@
 
 #include <stdio.h>
-#include <string.h>
+#include <str.h>
 #include <stdarg.h>
 #include <stdlib.h>
Index: uspace/app/edit/Makefile
===================================================================
--- uspace/app/edit/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/edit/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,7 +29,5 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = edit
+BINARY = edit
 
 SOURCES = \
@@ -37,3 +35,3 @@
 	sheet.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/edit/edit.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,5 +40,5 @@
 #include <vfs/vfs.h>
 #include <io/console.h>
-#include <io/color.h>
+#include <io/style.h>
 #include <io/keycode.h>
 #include <errno.h>
@@ -100,5 +100,6 @@
 static bool cursor_visible;
 
-static int scr_rows, scr_columns;
+static ipcarg_t scr_rows;
+static ipcarg_t scr_columns;
 
 #define ROW_BUF_SIZE 4096
@@ -475,8 +476,7 @@
 static void file_save_as(void)
 {
-	char *old_fname, *fname;
-	int rc;
-
-	old_fname = (doc.file_name != NULL) ? doc.file_name : "";
+	const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
+	char *fname;
+	
 	fname = filename_prompt("Save As", old_fname);
 	if (fname == NULL) {
@@ -485,5 +485,5 @@
 	}
 
-	rc = file_save(fname);
+	int rc = file_save(fname);
 	if (rc != EOK)
 		return;
@@ -506,8 +506,8 @@
 	asprintf(&str, "%s: %s", prompt, init_value);
 	status_display(str);
-	console_goto(con, 1 + str_length(str), scr_rows - 1);
+	console_set_pos(con, 1 + str_length(str), scr_rows - 1);
 	free(str);
 
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+	console_set_style(con, STYLE_INVERTED);
 
 	max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
@@ -553,5 +553,5 @@
 	str = wstr_to_astr(buffer);
 
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	return str;
@@ -672,5 +672,4 @@
 {
 	int sh_rows, rows;
-	int i, j;
 
 	sheet_get_num_rows(&doc.sh, &sh_rows);
@@ -679,11 +678,13 @@
 	/* Draw rows from the sheet. */
 
-	console_goto(con, 0, 0);
+	console_set_pos(con, 0, 0);
 	pane_row_range_display(0, rows);
 
 	/* Clear the remaining rows if file is short. */
-
+	
+	int i;
+	ipcarg_t j;
 	for (i = rows; i < pane.rows; ++i) {
-		console_goto(con, 0, i);
+		console_set_pos(con, 0, i);
 		for (j = 0; j < scr_columns; ++j)
 			putchar(' ');
@@ -718,5 +719,5 @@
 	wchar_t c;
 	size_t pos, size;
-	unsigned s_column;
+	int s_column;
 	coord_t csel_start, csel_end, ctmp;
 
@@ -737,5 +738,5 @@
 	/* Draw rows from the sheet. */
 
-	console_goto(con, 0, 0);
+	console_set_pos(con, 0, 0);
 	for (i = r0; i < r1; ++i) {
 		/* Starting point for row display */
@@ -757,22 +758,22 @@
 		    coord_cmp(&rbc, &csel_end) < 0) {
 			fflush(stdout);
-			console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+			console_set_style(con, STYLE_SELECTED);
 			fflush(stdout);
 		}
 
-		console_goto(con, 0, i);
+		console_set_pos(con, 0, i);
 		size = str_size(row_buf);
 		pos = 0;
 		s_column = pane.sh_column;
 		while (pos < size) {
-			if (csel_start.row == rbc.row && csel_start.column == s_column) {
+			if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
 				fflush(stdout);
-				console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+				console_set_style(con, STYLE_SELECTED);
 				fflush(stdout);
 			}
 	
-			if (csel_end.row == rbc.row && csel_end.column == s_column) {
+			if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
 				fflush(stdout);
-				console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+				console_set_style(con, STYLE_NORMAL);
 				fflush(stdout);
 			}
@@ -792,7 +793,7 @@
 		}
 
-		if (csel_end.row == rbc.row && csel_end.column == s_column) {
+		if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
 			fflush(stdout);
-			console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(con, STYLE_NORMAL);
 			fflush(stdout);
 		}
@@ -808,5 +809,5 @@
 			putchar(' ');
 		fflush(stdout);
-		console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+		console_set_style(con, STYLE_NORMAL);
 	}
 
@@ -819,19 +820,17 @@
 	spt_t caret_pt;
 	coord_t coord;
-	char *fname;
-	int n;
 
 	tag_get_pt(&pane.caret_pos, &caret_pt);
 	spt_get_coord(&caret_pt, &coord);
 
-	fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
-
-	console_goto(con, 0, scr_rows - 1);
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
-	n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
+	const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
+
+	console_set_pos(con, 0, scr_rows - 1);
+	console_set_style(con, STYLE_INVERTED);
+	int n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
 	    "Ctrl-E Save As", coord.row, coord.column, fname);
 	printf("%*s", scr_columns - 1 - n, "");
 	fflush(stdout);
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	pane.rflags |= REDRAW_CARET;
@@ -847,5 +846,5 @@
 
 	spt_get_coord(&caret_pt, &coord);
-	console_goto(con, coord.column - pane.sh_column,
+	console_set_pos(con, coord.column - pane.sh_column,
 	    coord.row - pane.sh_row);
 }
@@ -1152,9 +1151,9 @@
 static void status_display(char const *str)
 {
-	console_goto(con, 0, scr_rows - 1);
-	console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
+	console_set_pos(con, 0, scr_rows - 1);
+	console_set_style(con, STYLE_INVERTED);
 	printf(" %*s ", -(scr_columns - 3), str);
 	fflush(stdout);
-	console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+	console_set_style(con, STYLE_NORMAL);
 
 	pane.rflags |= REDRAW_CARET;
Index: uspace/app/edit/sheet.c
===================================================================
--- uspace/app/edit/sheet.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/edit/sheet.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -50,5 +50,5 @@
 
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <errno.h>
 #include <adt/list.h>
Index: uspace/app/getterm/Makefile
===================================================================
--- uspace/app/getterm/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/getterm/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -28,11 +28,7 @@
 #
 
-include ../../../version
-DEFS += -DRELEASE=$(RELEASE) "-DNAME=$(NAME)"
-
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = getterm
+DEFS = -DRELEASE=$(RELEASE) "-DNAME=$(NAME)"
+BINARY = getterm
 
 SOURCES = \
@@ -40,3 +36,3 @@
 	version.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/getterm/getterm.c
===================================================================
--- uspace/app/getterm/getterm.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/getterm/getterm.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,9 +40,12 @@
 #include <stdio.h>
 #include <task.h>
+#include <str_error.h>
 #include "version.h"
+
+#define APP_NAME  "getterm"
 
 static void usage(void)
 {
-	printf("Usage: getterm <terminal> <path>\n");
+	printf("Usage: %s <terminal> <path>\n", APP_NAME);
 }
 
@@ -69,15 +72,17 @@
 }
 
-static task_id_t spawn(char *fname)
+static task_id_t spawn(const char *fname)
 {
-	char *args[2];
+	const char *args[2];
 	
 	args[0] = fname;
 	args[1] = NULL;
 	
-	task_id_t id = task_spawn(fname, args);
+	int err;
+	task_id_t id = task_spawn(fname, args, &err);
 	
 	if (id == 0)
-		printf("Error spawning %s\n", fname);
+		printf("%s: Error spawning %s (%s)\n", APP_NAME, fname,
+		    str_error(err));
 	
 	return id;
Index: uspace/app/getterm/version.c
===================================================================
--- uspace/app/getterm/version.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/getterm/version.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,18 +40,18 @@
 #include "version.h"
 
-static char *release = STRING(RELEASE);
-static char *name = STRING(NAME);
-static char *arch = STRING(UARCH);
+static const char *release = STRING(RELEASE);
+static const char *name = STRING(NAME);
+static const char *arch = STRING(UARCH);
 
 #ifdef REVISION
-	static char *revision = ", revision " STRING(REVISION);
+	static const char *revision = ", revision " STRING(REVISION);
 #else
-	static char *revision = "";
+	static const char *revision = "";
 #endif
 
 #ifdef TIMESTAMP
-	static char *timestamp = "\nBuilt on " STRING(TIMESTAMP);
+	static const char *timestamp = "\nBuilt on " STRING(TIMESTAMP);
 #else
-	static char *timestamp = "";
+	static const char *timestamp = "";
 #endif
 
Index: uspace/app/init/Makefile
===================================================================
--- uspace/app/init/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/init/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,10 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = init
+BINARY = init
 
 SOURCES = \
 	init.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/init/init.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -46,9 +46,21 @@
 #include <malloc.h>
 #include <macros.h>
-#include <string.h>
+#include <str.h>
 #include <devmap.h>
+#include <str_error.h>
 #include "init.h"
 
+#define ROOT_DEVICE       "bd/initrd"
+#define ROOT_MOUNT_POINT  "/"
+
+#define DEVFS_FS_TYPE      "devfs"
 #define DEVFS_MOUNT_POINT  "/dev"
+
+#define SCRATCH_FS_TYPE      "tmpfs"
+#define SCRATCH_MOUNT_POINT  "/scratch"
+
+#define DATA_FS_TYPE      "fat"
+#define DATA_DEVICE       "bd/disk0"
+#define DATA_MOUNT_POINT  "/data"
 
 #define SRV_CONSOLE  "/srv/console"
@@ -57,71 +69,60 @@
 static void info_print(void)
 {
-	printf(NAME ": HelenOS init\n");
+	printf("%s: HelenOS init\n", NAME);
+}
+
+static bool mount_report(const char *desc, const char *mntpt,
+    const char *fstype, const char *dev, int rc)
+{
+	switch (rc) {
+	case EOK:
+		if (dev != NULL)
+			printf("%s: %s mounted on %s (%s at %s)\n", NAME, desc, mntpt,
+			    fstype, dev);
+		else
+			printf("%s: %s mounted on %s (%s)\n", NAME, desc, mntpt, fstype);
+		break;
+	case EBUSY:
+		printf("%s: %s already mounted on %s\n", NAME, desc, mntpt);
+		return false;
+	case ELIMIT:
+		printf("%s: %s limit exceeded\n", NAME, desc);
+		return false;
+	case ENOENT:
+		printf("%s: %s unknown type (%s)\n", NAME, desc, fstype);
+		return false;
+	default:
+		printf("%s: %s not mounted on %s (%s)\n", NAME, desc, mntpt,
+		    str_error(rc));
+		return false;
+	}
+	
+	return true;
 }
 
 static bool mount_root(const char *fstype)
 {
-	char *opts = "";
-	const char *root_dev = "bd/initrd";
+	const char *opts = "";
 	
 	if (str_cmp(fstype, "tmpfs") == 0)
 		opts = "restore";
 	
-	int rc = mount(fstype, "/", root_dev, opts, IPC_FLAG_BLOCKING);
-	
-	switch (rc) {
-	case EOK:
-		printf(NAME ": Root filesystem mounted, %s at %s\n",
-		    fstype, root_dev);
-		break;
-	case EBUSY:
-		printf(NAME ": Root filesystem already mounted\n");
-		return false;
-	case ELIMIT:
-		printf(NAME ": Unable to mount root filesystem\n");
-		return false;
-	case ENOENT:
-		printf(NAME ": Unknown filesystem type (%s)\n", fstype);
-		return false;
-	default:
-		printf(NAME ": Error mounting root filesystem (%d)\n", rc);
-		return false;
-	}
-	
-	return true;
+	int rc = mount(fstype, ROOT_MOUNT_POINT, ROOT_DEVICE, opts,
+	    IPC_FLAG_BLOCKING);
+	return mount_report("Root filesystem", ROOT_MOUNT_POINT, fstype,
+	    ROOT_DEVICE, rc);
 }
 
 static bool mount_devfs(void)
 {
-	int rc = mount("devfs", DEVFS_MOUNT_POINT, "", "", IPC_FLAG_BLOCKING);
-	
-	switch (rc) {
-	case EOK:
-		printf(NAME ": Device filesystem mounted\n");
-		break;
-	case EBUSY:
-		printf(NAME ": Device filesystem already mounted\n");
-
-		return false;
-	case ELIMIT:
-		printf(NAME ": Unable to mount device filesystem\n");
-
-		return false;
-	case ENOENT:
-		printf(NAME ": Unknown filesystem type (devfs)\n");
-
-		return false;
-	default:
-		printf(NAME ": Error mounting device filesystem (%d)\n", rc);
-
-		return false;
-	}
-	
-	return true;
-}
-
-static void spawn(char *fname)
-{
-	char *argv[2];
+	int rc = mount(DEVFS_FS_TYPE, DEVFS_MOUNT_POINT, "", "",
+	    IPC_FLAG_BLOCKING);
+	return mount_report("Device filesystem", DEVFS_MOUNT_POINT, DEVFS_FS_TYPE,
+	    NULL, rc);
+}
+
+static void spawn(const char *fname)
+{
+	const char *argv[2];
 	struct stat s;
 	
@@ -129,16 +130,18 @@
 		return;
 	
-	printf(NAME ": Spawning %s\n", fname);
+	printf("%s: Spawning %s\n", NAME, fname);
 	
 	argv[0] = fname;
 	argv[1] = NULL;
 	
-	if (!task_spawn(fname, argv))
-		printf(NAME ": Error spawning %s\n", fname);
-}
-
-static void srv_start(char *fname)
-{
-	char *argv[2];
+	int err;
+	if (!task_spawn(fname, argv, &err))
+		printf("%s: Error spawning %s (%s)\n", NAME, fname,
+		    str_error(err));
+}
+
+static void srv_start(const char *fname)
+{
+	const char *argv[2];
 	task_id_t id;
 	task_exit_t texit;
@@ -149,30 +152,32 @@
 		return;
 	
-	printf(NAME ": Starting %s\n", fname);
+	printf("%s: Starting %s\n", NAME, fname);
 	
 	argv[0] = fname;
 	argv[1] = NULL;
 	
-	id = task_spawn(fname, argv);
+	id = task_spawn(fname, argv, &retval);
 	if (!id) {
-		printf(NAME ": Error spawning %s\n", fname);
+		printf("%s: Error spawning %s (%s)\n", NAME, fname,
+		    str_error(retval));
 		return;
 	}
-
+	
 	rc = task_wait(id, &texit, &retval);
 	if (rc != EOK) {
-		printf(NAME ": Error waiting for %s\n", fname);
+		printf("%s: Error waiting for %s (%s(\n", NAME, fname,
+		    str_error(retval));
 		return;
 	}
-
+	
 	if ((texit != TASK_EXIT_NORMAL) || (retval != 0)) {
-		printf(NAME ": Server %s failed to start (returned %d)\n",
-			fname, retval);
-	}
-}
-
-static void console(char *dev)
-{
-	char *argv[3];
+		printf("%s: Server %s failed to start (%s)\n", NAME,
+			fname, str_error(retval));
+	}
+}
+
+static void console(const char *dev)
+{
+	const char *argv[3];
 	char hid_in[DEVMAP_NAME_MAXLEN];
 	int rc;
@@ -180,5 +185,5 @@
 	snprintf(hid_in, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
 	
-	printf(NAME ": Spawning %s with %s\n", SRV_CONSOLE, hid_in);
+	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, hid_in);
 	
 	/* Wait for the input device to be ready */
@@ -191,13 +196,15 @@
 		argv[2] = NULL;
 		
-		if (!task_spawn(SRV_CONSOLE, argv))
-			printf(NAME ": Error spawning %s with %s\n", SRV_CONSOLE, hid_in);
+		if (!task_spawn(SRV_CONSOLE, argv, &rc))
+			printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
+			    hid_in, str_error(rc));
 	} else
-		printf(NAME ": Error waiting on %s\n", hid_in);
-}
-
-static void getterm(char *dev, char *app)
-{
-	char *argv[4];
+		printf("%s: Error waiting on %s (%s)\n", NAME, hid_in,
+		    str_error(rc));
+}
+
+static void getterm(const char *dev, const char *app)
+{
+	const char *argv[4];
 	char term[DEVMAP_NAME_MAXLEN];
 	int rc;
@@ -205,5 +212,5 @@
 	snprintf(term, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
 	
-	printf(NAME ": Spawning %s with %s %s\n", APP_GETTERM, term, app);
+	printf("%s: Spawning %s %s %s\n", NAME, APP_GETTERM, term, app);
 	
 	/* Wait for the terminal device to be ready */
@@ -217,37 +224,24 @@
 		argv[3] = NULL;
 		
-		if (!task_spawn(APP_GETTERM, argv))
-			printf(NAME ": Error spawning %s with %s %s\n", APP_GETTERM,
-			    term, app);
+		if (!task_spawn(APP_GETTERM, argv, &rc))
+			printf("%s: Error spawning %s %s %s (%s)\n", NAME, APP_GETTERM,
+			    term, app, str_error(rc));
 	} else
-		printf(NAME ": Error waiting on %s\n", term);
-}
-
-static void mount_scratch(void)
-{
-	int rc;
-
-	printf("Trying to mount null/0 on /scratch... ");
-	fflush(stdout);
-
-	rc = mount("tmpfs", "/scratch", "null/0", "", 0);
-	if (rc == EOK)
-		printf("OK\n");
-	else
-		printf("Failed\n");
-}
-
-static void mount_data(void)
-{
-	int rc;
-
-	printf("Trying to mount bd/disk0 on /data... ");
-	fflush(stdout);
-
-	rc = mount("fat", "/data", "bd/disk0", "wtcache", 0);
-	if (rc == EOK)
-		printf("OK\n");
-	else
-		printf("Failed\n");
+		printf("%s: Error waiting on %s (%s)\n", NAME, term,
+		    str_error(rc));
+}
+
+static bool mount_scratch(void)
+{
+	int rc = mount(SCRATCH_FS_TYPE, SCRATCH_MOUNT_POINT, "", "", 0);
+	return mount_report("Scratch filesystem", SCRATCH_MOUNT_POINT,
+	    SCRATCH_FS_TYPE, NULL, rc);
+}
+
+static bool mount_data(void)
+{
+	int rc = mount(DATA_FS_TYPE, DATA_MOUNT_POINT, DATA_DEVICE, "wtcache", 0);
+	return mount_report("Data filesystem", DATA_MOUNT_POINT, DATA_FS_TYPE,
+	    DATA_DEVICE, rc);
 }
 
@@ -257,8 +251,8 @@
 	
 	if (!mount_root(STRING(RDFMT))) {
-		printf(NAME ": Exiting\n");
+		printf("%s: Exiting\n", NAME);
 		return -1;
 	}
-
+	
 	/* Make sure tmpfs is running. */
 	if (str_cmp(STRING(RDFMT), "tmpfs") != 0) {
@@ -270,8 +264,8 @@
 	
 	if (!mount_devfs()) {
-		printf(NAME ": Exiting\n");
+		printf("%s: Exiting\n", NAME);
 		return -2;
 	}
-
+	
 	mount_scratch();
 	
@@ -282,5 +276,5 @@
 	srv_start("/srv/adb_ms");
 	srv_start("/srv/char_ms");
-
+	
 	spawn("/srv/fb");
 	spawn("/srv/kbd");
@@ -288,5 +282,5 @@
 	
 	spawn("/srv/clip");
-
+	
 	/*
 	 * Start these synchronously so that mount_data() can be
@@ -299,5 +293,5 @@
 	(void) srv_start;
 #endif
-
+	
 #ifdef CONFIG_MOUNT_DATA
 	mount_data();
@@ -305,5 +299,5 @@
 	(void) mount_data;
 #endif
-
+	
 	getterm("term/vc0", "/app/bdsh");
 	getterm("term/vc1", "/app/bdsh");
@@ -314,8 +308,4 @@
 	getterm("term/vc6", "/app/klog");
 	getterm("term/vc7", "/srv/devman");
-
-	//usleep(1000000);
-	//spawn("/srv/dd");
-		
 	
 	return 0;
Index: uspace/app/klog/Makefile
===================================================================
--- uspace/app/klog/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/klog/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,10 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = klog
+BINARY = klog
 
 SOURCES = \
 	klog.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/klog/klog.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -64,5 +64,10 @@
 int main(int argc, char *argv[])
 {
-	size_t klog_pages = sysinfo_value("klog.pages");
+	size_t klog_pages;
+	if (sysinfo_get_value("klog.pages", &klog_pages) != EOK) {
+		printf("%s: Error getting klog address\n", NAME);
+		return -1;
+	}
+	
 	size_t klog_size = klog_pages * PAGE_SIZE;
 	klog_length = klog_size / sizeof(wchar_t);
@@ -70,5 +75,5 @@
 	klog = (wchar_t *) as_get_mappable_page(klog_size);
 	if (klog == NULL) {
-		printf(NAME ": Error allocating memory area\n");
+		printf("%s: Error allocating memory area\n", NAME);
 		return -1;
 	}
@@ -77,10 +82,10 @@
 	    klog_size, SERVICE_MEM_KLOG);
 	if (res != EOK) {
-		printf(NAME ": Error initializing memory area\n");
+		printf("%s: Error initializing memory area\n", NAME);
 		return -1;
 	}
 	
 	if (event_subscribe(EVENT_KLOG, 0) != EOK) {
-		printf(NAME ": Error registering klog notifications\n");
+		printf("%s: Error registering klog notifications\n", NAME);
 		return -1;
 	}
Index: uspace/app/mkfat/Makefile
===================================================================
--- uspace/app/mkfat/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/mkfat/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,11 +29,10 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
 EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
-
-OUTPUT = mkfat
+BINARY = mkfat
 
 SOURCES = \
 	mkfat.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/mkfat/fat.h
===================================================================
--- uspace/app/mkfat/fat.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/mkfat/fat.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -78,5 +78,5 @@
 			uint16_t	signature;
 		} __attribute__ ((packed));
-		struct fat32 {
+		struct {
 			/* FAT32 only */
 			/** Sectors per FAT. */
@@ -108,5 +108,5 @@
 			/** Signature. */
 			uint16_t	signature;
-		} __attribute__ ((packed));
+		} fat32 __attribute__ ((packed));
 	};
 } __attribute__ ((packed)) fat_bs_t;
Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/mkfat/mkfat.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -98,5 +98,5 @@
 	size_t block_size;
 	char *endptr;
-	bn_t dev_nblocks;
+	aoff64_t dev_nblocks;
 
 	cfg.total_sectors = 0;
@@ -160,5 +160,5 @@
 		printf(NAME ": Warning, failed to obtain block device size.\n");
 	} else {
-		printf(NAME ": Block device has %" PRIuBN " blocks.\n",
+		printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
 		    dev_nblocks);
 		cfg.total_sectors = dev_nblocks;
@@ -236,5 +236,5 @@
 static int fat_blocks_write(struct fat_params const *par, dev_handle_t handle)
 {
-	bn_t addr;
+	aoff64_t addr;
 	uint8_t *buffer;
 	int i;
Index: uspace/app/netecho/Makefile
===================================================================
--- uspace/app/netecho/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/netecho/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = netecho
+
+SOURCES = \
+	netecho.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/netecho/netecho.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup netecho
+ *  @{
+ */
+
+/** @file
+ *  Network echo application.
+ *  Answers received packets.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <arg_parse.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+#include <socket_parse.h>
+
+#include "print_error.h"
+
+/** Network echo module name.
+ */
+#define NAME	"Network Echo"
+
+/** Prints the application help.
+ */
+void echo_print_help(void);
+
+/** Module entry point.
+ *  Reads command line parameters and starts listenning.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+void echo_print_help(void){
+	printf(
+		"Network Echo aplication\n" \
+		"Usage: echo [options]\n" \
+		"Where options are:\n" \
+		"-b backlog | --backlog=size\n" \
+		"\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \
+		"\n" \
+		"-c count | --count=count\n" \
+		"\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
+		"\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should listen at. The default is 7.\n" \
+		"\n" \
+		"-r reply_string | --reply=reply_string\n" \
+		"\tThe constant reply string. The default is the original data received.\n" \
+		"\n" \
+		"-s receive_size | --size=receive_size\n" \
+		"\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
+		"\n" \
+		"-t socket_type | --type=socket_type\n" \
+		"\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 1024;
+	int verbose			= 0;
+	char * reply		= NULL;
+	sock_type_t type	= SOCK_DGRAM;
+	int count			= -1;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+	int backlog			= 3;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+	int socket_id;
+	int listening_id;
+	char * data;
+	size_t length;
+	int index;
+	size_t reply_length;
+	int value;
+
+	// parse the command line arguments
+	for(index = 1; index < argc; ++ index){
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				case 'b':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 0));
+					break;
+				case 'c':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 0));
+					break;
+				case 'f':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
+					break;
+				case 'h':
+					echo_print_help();
+					return EOK;
+					break;
+				case 'p':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					port = (uint16_t) value;
+					break;
+				case 'r':
+					ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 0));
+					break;
+				case 's':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "backlog=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 8));
+					}else if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 8));
+					}else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						echo_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "reply=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 8));
+					}else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
+						size = (value >= 0) ? (size_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						echo_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					echo_print_help();
+					return EINVAL;
+			}
+		}else{
+			echo_print_help();
+			return EINVAL;
+		}
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Receive size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+	// size plus the terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+
+	// set the reply size if set
+	reply_length = reply ? str_length(reply) : 0;
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Protocol family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// get a listening socket
+	listening_id = socket(family, type, 0);
+	if(listening_id < 0){
+		socket_print_error(stderr, listening_id, "Socket create: ", "\n");
+		return listening_id;
+	}
+
+	// if the stream socket is used
+	if(type == SOCK_STREAM){
+		// check the backlog
+		if(backlog <= 0){
+			fprintf(stderr, "Accepted sockets queue size too small (%d). Using 3 instead.\n", size);
+			backlog = 3;
+		}
+		// set the backlog
+		if(ERROR_OCCURRED(listen(listening_id, backlog))){
+			socket_print_error(stderr, ERROR_CODE, "Socket listen: ", "\n");
+			return ERROR_CODE;
+		}
+	}
+
+	// bind the listenning socket
+	if(ERROR_OCCURRED(bind(listening_id, address, addrlen))){
+		socket_print_error(stderr, ERROR_CODE, "Socket bind: ", "\n");
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("Socket %d listenning at %d\n", listening_id, port);
+	}
+
+	socket_id = listening_id;
+
+	// do count times
+	// or indefinitely if set to a negative value
+	while(count){
+
+		addrlen = max_length;
+		if(type == SOCK_STREAM){
+			// acceept a socket if the stream socket is used
+			socket_id = accept(listening_id, address, &addrlen);
+			if(socket_id <= 0){
+				socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
+			}else{
+				if(verbose){
+					printf("Socket %d accepted\n", socket_id);
+				}
+			}
+		}
+
+		// if the datagram socket is used or the stream socked was accepted
+		if(socket_id > 0){
+
+			// receive an echo request
+			value = recvfrom(socket_id, data, size, 0, address, &addrlen);
+			if(value < 0){
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+			}else{
+				length = (size_t) value;
+				if(verbose){
+					// print the header
+
+					// get the source port and prepare the address buffer
+					address_start = NULL;
+					switch(address->sa_family){
+						case AF_INET:
+							port = ntohs(address_in->sin_port);
+							address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+							break;
+						case AF_INET6:
+							port = ntohs(address_in6->sin6_port);
+							address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+							break;
+						default:
+							fprintf(stderr, "Address family %d (0x%X) is not supported.\n", address->sa_family);
+					}
+					// parse the source address
+					if(address_start){
+						if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
+							fprintf(stderr, "Received address error %d\n", ERROR_CODE);
+						}else{
+							data[length] = '\0';
+							printf("Socket %d received %d bytes from %s:%d\n%s\n", socket_id, length, address_string, port, data);
+						}
+					}
+				}
+
+				// answer the request either with the static reply or the original data
+				if(ERROR_OCCURRED(sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen))){
+					socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				}
+
+			}
+
+			// close the accepted stream socket
+			if(type == SOCK_STREAM){
+				if(ERROR_OCCURRED(closesocket(socket_id))){
+					socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n");
+				}
+			}
+
+		}
+
+		// decrease the count if positive
+		if(count > 0){
+			-- count;
+			if(verbose){
+				printf("Waiting for next %d packet(s)\n", count);
+			}
+		}
+	}
+
+	if(verbose){
+		printf("Closing the socket\n");
+	}
+
+	// close the listenning socket
+	if(ERROR_OCCURRED(closesocket(listening_id))){
+		socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n");
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("Exiting\n");
+	}
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/netecho/print_error.c
===================================================================
--- uspace/app/netecho/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/netecho/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup net_app
+ *  @{
+ */
+
+/** @file
+ *  Generic application error printing functions implementation.
+ */
+
+#include <stdio.h>
+
+#include <icmp_codes.h>
+#include <socket_errno.h>
+
+#include "print_error.h"
+
+void icmp_print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(output){
+		if(prefix){
+			fprintf(output, "%s", prefix);
+		}
+		switch(error_code){
+			case ICMP_DEST_UNREACH:
+				fprintf(output, "ICMP Destination Unreachable (%d) error", error_code);
+				break;
+			case ICMP_SOURCE_QUENCH:
+				fprintf(output, "ICMP Source Quench (%d) error", error_code);
+				break;
+			case ICMP_REDIRECT:
+				fprintf(output, "ICMP Redirect (%d) error", error_code);
+				break;
+			case ICMP_ALTERNATE_ADDR:
+				fprintf(output, "ICMP Alternate Host Address (%d) error", error_code);
+				break;
+			case ICMP_ROUTER_ADV:
+				fprintf(output, "ICMP Router Advertisement (%d) error", error_code);
+				break;
+			case ICMP_ROUTER_SOL:
+				fprintf(output, "ICMP Router Solicitation (%d) error", error_code);
+				break;
+			case ICMP_TIME_EXCEEDED:
+				fprintf(output, "ICMP Time Exceeded (%d) error", error_code);
+				break;
+			case ICMP_PARAMETERPROB:
+				fprintf(output, "ICMP Paramenter Problem (%d) error", error_code);
+				break;
+			case ICMP_CONVERSION_ERROR:
+				fprintf(output, "ICMP Datagram Conversion Error (%d) error", error_code);
+				break;
+			case ICMP_REDIRECT_MOBILE:
+				fprintf(output, "ICMP Mobile Host Redirect (%d) error", error_code);
+				break;
+			case ICMP_SKIP:
+				fprintf(output, "ICMP SKIP (%d) error", error_code);
+				break;
+			case ICMP_PHOTURIS:
+				fprintf(output, "ICMP Photuris (%d) error", error_code);
+				break;
+			default:
+				fprintf(output, "Other (%d) error", error_code);
+		}
+		if(suffix){
+			fprintf(output, "%s", suffix);
+		}
+	}
+}
+
+void print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(IS_ICMP_ERROR(error_code)){
+		icmp_print_error(output, error_code, prefix, suffix);
+	}else if(IS_SOCKET_ERROR(error_code)){
+		socket_print_error(output, error_code, prefix, suffix);
+	}
+}
+
+void socket_print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(output){
+		if(prefix){
+			fprintf(output, "%s", prefix);
+		}
+		switch(error_code){
+			case ENOTSOCK:
+				fprintf(output, "Not a socket (%d) error", error_code);
+				break;
+			case EPROTONOSUPPORT:
+				fprintf(output, "Protocol not supported (%d) error", error_code);
+				break;
+			case ESOCKTNOSUPPORT:
+				fprintf(output, "Socket type not supported (%d) error", error_code);
+				break;
+			case EPFNOSUPPORT:
+				fprintf(output, "Protocol family not supported (%d) error", error_code);
+				break;
+			case EAFNOSUPPORT:
+				fprintf(output, "Address family not supported (%d) error", error_code);
+				break;
+			case EADDRINUSE:
+				fprintf(output, "Address already in use (%d) error", error_code);
+				break;
+			case ENOTCONN:
+				fprintf(output, "Socket not connected (%d) error", error_code);
+				break;
+			case NO_DATA:
+				fprintf(output, "No data (%d) error", error_code);
+				break;
+			case EINPROGRESS:
+				fprintf(output, "Another operation in progress (%d) error", error_code);
+				break;
+			case EDESTADDRREQ:
+				fprintf(output, "Destination address required (%d) error", error_code);
+			case TRY_AGAIN:
+				fprintf(output, "Try again (%d) error", error_code);
+			default:
+				fprintf(output, "Other (%d) error", error_code);
+		}
+		if(suffix){
+			fprintf(output, "%s", suffix);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/app/netecho/print_error.h
===================================================================
--- uspace/app/netecho/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/netecho/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup net_app
+ *  @{
+ */
+
+/** @file
+ *  Generic application error printing functions.
+ */
+
+#ifndef __NET_APP_PRINT__
+#define __NET_APP_PRINT__
+
+/** Returns whether the error code may be an ICMP error code.
+ *  @param[in] error_code The error code.
+ *  @returns A value indicating whether the error code may be an ICMP error code.
+ */
+#define IS_ICMP_ERROR(error_code)		((error_code) > 0)
+
+/** Returns whether the error code may be socket error code.
+ *  @param[in] error_code The error code.
+ *  @returns A value indicating whether the error code may be a socket error code.
+ */
+#define IS_SOCKET_ERROR(error_code)	((error_code) < 0)
+
+/** Prints the specific ICMP error description.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The ICMP error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void icmp_print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+/** Prints the error description.
+ *  Supports ICMP and socket error codes.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+/** Prints the specific socket error description.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The socket error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void socket_print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nettest1/Makefile
===================================================================
--- uspace/app/nettest1/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = nettest1
+
+SOURCES = \
+	nettest1.c \
+	nettest.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest1/nettest.c
===================================================================
--- uspace/app/nettest1/nettest.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/nettest.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test support functions implementation.
+ */
+
+#include <stdio.h>
+
+#include <socket.h>
+#include <net_err.h>
+
+#include "nettest.h"
+#include "print_error.h"
+
+int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type){
+	int index;
+
+	if(verbose){
+		printf("Create\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		socket_ids[index] = socket(family, type, 0);
+		if(socket_ids[index] < 0){
+			printf("Socket %d (%d) error:\n", index, socket_ids[index]);
+			socket_print_error(stderr, socket_ids[index], "Socket create: ", "\n");
+			return socket_ids[index];
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_close(int verbose, int * socket_ids, int sockets){
+	ERROR_DECLARE;
+
+	int index;
+
+	if(verbose){
+		printf("\tClose\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		if(ERROR_OCCURRED(closesocket(socket_ids[index]))){
+			printf("Socket %d (%d) error:\n", index, socket_ids[index]);
+			socket_print_error(stderr, ERROR_CODE, "Socket close: ", "\n");
+			return ERROR_CODE;
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen){
+	ERROR_DECLARE;
+
+	int index;
+
+	if(verbose){
+		printf("\tConnect\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		if(ERROR_OCCURRED(connect(socket_ids[index], address, addrlen))){
+			socket_print_error(stderr, ERROR_CODE, "Socket connect: ", "\n");
+			return ERROR_CODE;
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages){
+	ERROR_DECLARE;
+
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tSendto\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, addrlen))){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				return ERROR_CODE;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
+	int value;
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tRecvfrom\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
+			if(value < 0){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+				return value;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
+	ERROR_DECLARE;
+
+	int value;
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tSendto and recvfrom\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, * addrlen))){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				return ERROR_CODE;
+			}
+			value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
+			if(value < 0){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+				return value;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+void print_mark(int index){
+	if((index + 1) % 10){
+		printf("*");
+	}else{
+		printf("|");
+	}
+	fflush(stdout);
+}
+
+/** @}
+ */
Index: uspace/app/nettest1/nettest.h
===================================================================
--- uspace/app/nettest1/nettest.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/nettest.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test support functions.
+ */
+
+#ifndef __NET_TEST__
+#define __NET_TEST__
+
+#include <socket.h>
+
+/** Prints a mark.
+ *  If the index is a multiple of ten, a different mark is printed.
+ *  @param[in] index The index of the mark to be printed.
+ */
+extern void print_mark(int index);
+
+/** Creates new sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[out] socket_ids A field to store the socket identifiers.
+ *  @param[in] sockets The number of sockets to create. Should be at most the size of the field.
+ *  @param[in] family The socket address family.
+ *  @param[in] type The socket type.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the socket() function.
+ */
+extern int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type);
+
+/** Closes sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the closesocket() function.
+ */
+extern int sockets_close(int verbose, int * socket_ids, int sockets);
+
+/** Connects sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The destination host address to connect to.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the connect() function.
+ */
+extern int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen);
+
+/** Sends data via sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The destination host address to send data to.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @param[in] data The data to be sent.
+ *  @param[in] size The data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be sent.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the sendto() function.
+ */
+extern int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages);
+
+/** Receives data via sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The source host address of received datagrams.
+ *  @param[in,out] addrlen The maximum length of the source address in bytes. The actual size of the source address is set instead.
+ *  @param[out] data The received data.
+ *  @param[in] size The maximum data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be received.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the recvfrom() function.
+ */
+extern int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
+
+/** Sends and receives data via sockets.
+ *  Each datagram is sent and a reply read consequently.
+ *  The next datagram is sent after the reply is received.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in,out] address The destination host address to send data to. The source host address of received datagrams is set instead.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @param[in,out] data The data to be sent. The received data are set instead.
+ *  @param[in] size The data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be received.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the recvfrom() function.
+ */
+extern int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nettest1/nettest1.c
===================================================================
--- uspace/app/nettest1/nettest1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/nettest1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test 1 application - sockets.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+#include <arg_parse.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+#include <socket_parse.h>
+
+#include "nettest.h"
+#include "print_error.h"
+
+/** Echo module name.
+ */
+#define NAME	"Nettest1"
+
+/** Packet data pattern.
+ */
+#define NETTEST1_TEXT	"Networking test 1 - sockets"
+
+/** Module entry point.
+ *  Starts testing.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+/** Prints the application help.
+ */
+void nettest1_print_help(void);
+
+/** Refreshes the data.
+ *  Fills the data block with the NETTEST1_TEXT pattern.
+ *  @param[out] data The data block.
+ *  @param[in] size The data block size in bytes.
+ */
+void nettest1_refresh_data(char * data, size_t size);
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 27;
+	int verbose			= 0;
+	sock_type_t type	= SOCK_DGRAM;
+	int sockets			= 10;
+	int messages		= 10;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+//	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+
+	int * socket_ids;
+	char * data;
+	int value;
+	int index;
+	struct timeval time_before;
+	struct timeval time_after;
+
+	// parse the command line arguments
+	// stop before the last argument if it does not start with the minus sign ('-')
+	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
+		// options should start with the minus sign ('-')
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				// short options with only one letter
+				case 'f':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
+					break;
+				case 'h':
+					nettest1_print_help();
+					return EOK;
+					break;
+				case 'm':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 0));
+					break;
+				case 'n':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 0));
+					break;
+				case 'p':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					port = (uint16_t) value;
+					break;
+				case 's':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						nettest1_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 8));
+					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 8));
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						nettest1_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					nettest1_print_help();
+					return EINVAL;
+			}
+		}else{
+			nettest1_print_help();
+			return EINVAL;
+		}
+	}
+
+	// if not before the last argument containing the address
+	if(index >= argc){
+		printf("Command line error: missing address\n");
+		nettest1_print_help();
+		return EINVAL;
+	}
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Address family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// parse the last argument which should contain the address
+	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
+		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+
+	// prepare the buffer
+	// size plus the terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate data buffer.\n");
+		return ENOMEM;
+	}
+	nettest1_refresh_data(data, size);
+
+	// check the socket count
+	if(sockets <= 0){
+		fprintf(stderr, "Socket count too small (%d). Using 2 instead.\n", sockets);
+		sockets = 2;
+	}
+
+	// prepare the socket buffer
+	// count plus the terminating null (\0)
+	socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
+	if(! socket_ids){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+	socket_ids[sockets] = NULL;
+
+	if(verbose){
+		printf("Starting tests\n");
+	}
+
+	if(verbose){
+		printf("1 socket, 1 message\n");
+	}
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, 1, address, addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("1 socket, %d messages\n", messages);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, 1, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("%d sockets, 1 message\n", sockets);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("%d sockets, %d messages\n", sockets, messages);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("Tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	if(verbose){
+		printf("Exiting\n");
+	}
+
+	return EOK;
+}
+
+void nettest1_print_help(void){
+	printf(
+		"Network Networking test 1 aplication - sockets\n" \
+		"Usage: echo [options] numeric_address\n" \
+		"Where options are:\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-m count | --messages=count\n" \
+		"\tThe number of messages to send and receive per socket. The default is 10.\n" \
+		"\n" \
+		"-n sockets | --sockets=count\n" \
+		"\tThe number of sockets to use. The default is 10.\n" \
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should send messages to. The default is 7.\n" \
+		"\n" \
+		"-s packet_size | --size=packet_size\n" \
+		"\tThe packet data size the application sends. The default is 28 bytes.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+void nettest1_refresh_data(char * data, size_t size){
+	size_t length;
+
+	// fill the data
+	length = 0;
+	while(size > length + sizeof(NETTEST1_TEXT) - 1){
+		memcpy(data + length, NETTEST1_TEXT, sizeof(NETTEST1_TEXT) - 1);
+		length += sizeof(NETTEST1_TEXT) - 1;
+	}
+	memcpy(data + length, NETTEST1_TEXT, size - length);
+	data[size] = '\0';
+}
+
+/** @}
+ */
Index: uspace/app/nettest1/print_error.c
===================================================================
--- uspace/app/nettest1/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/nettest1/print_error.h
===================================================================
--- uspace/app/nettest1/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest1/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
Index: uspace/app/nettest2/Makefile
===================================================================
--- uspace/app/nettest2/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = nettest2
+
+SOURCES = \
+	nettest2.c \
+	nettest.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest2/nettest.c
===================================================================
--- uspace/app/nettest2/nettest.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/nettest.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../nettest1/nettest.c
Index: uspace/app/nettest2/nettest.h
===================================================================
--- uspace/app/nettest2/nettest.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/nettest.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../nettest1/nettest.h
Index: uspace/app/nettest2/nettest2.c
===================================================================
--- uspace/app/nettest2/nettest2.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/nettest2.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test 2 application - transfer.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+#include <arg_parse.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+#include <socket_parse.h>
+
+#include "nettest.h"
+#include "print_error.h"
+
+/** Echo module name.
+ */
+#define NAME	"Nettest2"
+
+/** Packet data pattern.
+ */
+#define NETTEST2_TEXT	"Networking test 2 - transfer"
+
+/** Module entry point.
+ *  Starts testing.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+/** Prints the application help.
+ */
+void nettest2_print_help(void);
+
+/** Refreshes the data.
+ *  Fills the data block with the NETTEST1_TEXT pattern.
+ *  @param[out] data The data block.
+ *  @param[in] size The data block size in bytes.
+ */
+void nettest2_refresh_data(char * data, size_t size);
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 28;
+	int verbose			= 0;
+	sock_type_t type	= SOCK_DGRAM;
+	int sockets			= 10;
+	int messages		= 10;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+//	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+
+	int * socket_ids;
+	char * data;
+	int value;
+	int index;
+	struct timeval time_before;
+	struct timeval time_after;
+
+	// parse the command line arguments
+	// stop before the last argument if it does not start with the minus sign ('-')
+	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
+		// options should start with the minus sign ('-')
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				// short options with only one letter
+				case 'f':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family));
+					break;
+				case 'h':
+					nettest2_print_help();
+					return EOK;
+					break;
+				case 'm':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 0));
+					break;
+				case 'n':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 0));
+					break;
+				case 'p':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					port = (uint16_t) value;
+					break;
+				case 's':
+					ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						nettest2_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &messages, 8));
+					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &sockets, 8));
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						nettest2_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					nettest2_print_help();
+					return EINVAL;
+			}
+		}else{
+			nettest2_print_help();
+			return EINVAL;
+		}
+	}
+
+	// if not before the last argument containing the address
+	if(index >= argc){
+		printf("Command line error: missing address\n");
+		nettest2_print_help();
+		return EINVAL;
+	}
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Address family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// parse the last argument which should contain the address
+	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
+		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+
+	// prepare the buffer
+	// size plus terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate data buffer.\n");
+		return ENOMEM;
+	}
+	nettest2_refresh_data(data, size);
+
+	// check the socket count
+	if(sockets <= 0){
+		fprintf(stderr, "Socket count too small (%d). Using 2 instead.\n", sockets);
+		sockets = 2;
+	}
+
+	// prepare the socket buffer
+	// count plus the terminating null (\0)
+	socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
+	if(! socket_ids){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+	socket_ids[sockets] = NULL;
+
+	if(verbose){
+		printf("Starting tests\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+
+	if(verbose){
+		printf("\n");
+	}
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("sendto + recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("sendto, recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+
+	if(verbose){
+		printf("\nExiting\n");
+	}
+
+	return EOK;
+}
+
+void nettest2_print_help(void){
+	printf(
+		"Network Networking test 2 aplication - UDP transfer\n" \
+		"Usage: echo [options] numeric_address\n" \
+		"Where options are:\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-m count | --messages=count\n" \
+		"\tThe number of messages to send and receive per socket. The default is 10.\n" \
+		"\n" \
+		"-n sockets | --sockets=count\n" \
+		"\tThe number of sockets to use. The default is 10.\n" \
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should send messages to. The default is 7.\n" \
+		"\n" \
+		"-s packet_size | --size=packet_size\n" \
+		"\tThe packet data size the application sends. The default is 29 bytes.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+void nettest2_refresh_data(char * data, size_t size){
+	size_t length;
+
+	// fill the data
+	length = 0;
+	while(size > length + sizeof(NETTEST2_TEXT) - 1){
+		memcpy(data + length, NETTEST2_TEXT, sizeof(NETTEST2_TEXT) - 1);
+		length += sizeof(NETTEST2_TEXT) - 1;
+	}
+	memcpy(data + length, NETTEST2_TEXT, size - length);
+	data[size] = '\0';
+}
+
+/** @}
+ */
Index: uspace/app/nettest2/print_error.c
===================================================================
--- uspace/app/nettest2/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/nettest2/print_error.h
===================================================================
--- uspace/app/nettest2/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/nettest2/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
Index: uspace/app/ping/Makefile
===================================================================
--- uspace/app/ping/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/ping/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = ping
+
+SOURCES = \
+	ping.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/ping/ping.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup ping
+ * @{
+ */
+
+/** @file
+ * Packet Internet Network Grouper.
+ */
+
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+#include <ipc/ipc.h>
+#include <ipc/services.h>
+#include <str_error.h>
+#include <arg_parse.h>
+
+#include <icmp_api.h>
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <ip_codes.h>
+#include <socket_errno.h>
+#include <socket_parse.h>
+
+#include "print_error.h"
+
+#define NAME  "ping"
+
+#define CL_OK           0
+#define CL_USAGE        -1
+#define CL_MISSING      -2
+#define CL_INVALID      -3
+#define CL_UNSUPPORTED  -4
+#define CL_ERROR        -5
+
+/** Ping configuration
+ *
+ */
+typedef struct {
+	bool verbose;               /**< Verbose printouts. */
+	size_t size;                /**< Outgoing packet size. */
+	unsigned int count;         /**< Number of packets to send. */
+	suseconds_t timeout;        /**< Reply wait timeout. */
+	int af;                     /**< Address family. */
+	ip_tos_t tos;               /**< Type of service. */
+	ip_ttl_t ttl;               /**< Time-to-live. */
+	bool fragments;             /**< Fragmentation. */
+	
+	char *dest_addr;            /**< Destination address. */
+	struct sockaddr_in dest;    /**< IPv4 destionation. */
+	struct sockaddr_in6 dest6;  /**< IPv6 destionation. */
+	
+	struct sockaddr *dest_raw;  /**< Raw destination address. */
+	socklen_t dest_len;         /**< Raw destination address length. */
+	
+	/** Converted address string. */
+	char dest_str[INET6_ADDRSTRLEN];
+} ping_config_t;
+
+
+static void usage(void)
+{
+	printf(
+	    "Usage: ping [-c count] [-s size] [-W timeout] [-f family] [-t ttl]\n" \
+	    "            [-Q tos] [--dont_fragment] destination\n" \
+	    "\n" \
+	    "Options:\n" \
+	    "\t-c count\n" \
+	    "\t--count=count\n" \
+	    "\t\tNumber of outgoing packets (default: 4)\n" \
+	    "\n" \
+	    "\t-s size\n" \
+	    "\t--size=bytes\n" \
+	    "\t\tOutgoing packet size (default: 56 bytes)\n" \
+	    "\n" \
+	    "\t-W timeout\n" \
+	    "\t--timeout=ms\n" \
+	    "\t\tReply wait timeout (default: 3000 ms)\n" \
+	    "\n" \
+	    "\t-f family\n" \
+	    "\t--family=family\n" \
+	    "\t\tDestination address family, AF_INET or AF_INET6 (default: AF_INET)\n" \
+	    "\n" \
+	    "\t-t ttl\n" \
+	    "\t--ttl=ttl\n" \
+	    "\t\tOutgoing packet time-to-live (default: 0)\n" \
+	    "\n" \
+	    "\t-Q tos\n" \
+	    "\t--tos=tos\n" \
+	    "\t\tOutgoing packet type of service (default: 0)\n" \
+	    "\n" \
+	    "\t--dont_fragment\n" \
+	    "\t\tDisable packet fragmentation (default: enabled)\n" \
+	    "\n" \
+	    "\t-v\n" \
+	    "\t--verbose\n" \
+	    "\t\tVerbose operation\n" \
+	    "\n" \
+	    "\t-h\n" \
+	    "\t--help\n" \
+	    "\t\tPrint this usage information\n"
+	);
+}
+
+static int args_parse(int argc, char *argv[], ping_config_t *config)
+{
+	if (argc < 2)
+		return CL_USAGE;
+	
+	int i;
+	int ret;
+	
+	for (i = 1; i < argc; i++) {
+		
+		/* Not an option */
+		if (argv[i][0] != '-')
+			break;
+		
+		/* Options terminator */
+		if (str_cmp(argv[i], "--") == 0) {
+			i++;
+			break;
+		}
+		
+		int off;
+		
+		/* Usage */
+		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1)
+			return CL_USAGE;
+		
+		/* Verbose */
+		if ((off = arg_parse_short_long(argv[i], "-v", "--verbose")) != -1) {
+			config->verbose = true;
+			continue;
+		}
+		
+		/* Don't fragment */
+		if (str_cmp(argv[i], "--dont_fragment") == 0) {
+			config->fragments = false;
+			continue;
+		}
+		
+		/* Count */
+		if ((off = arg_parse_short_long(argv[i], "-c", "--count=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->count = (unsigned int) tmp;
+			continue;
+		}
+		
+		/* Outgoing packet size */
+		if ((off = arg_parse_short_long(argv[i], "-s", "--size=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->size = (size_t) tmp;
+			continue;
+		}
+		
+		/* Reply wait timeout */
+		if ((off = arg_parse_short_long(argv[i], "-W", "--timeout=")) != -1) {
+			int tmp;
+			ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->timeout = (suseconds_t) tmp;
+			continue;
+		}
+		
+		/* Address family */
+		if ((off = arg_parse_short_long(argv[i], "-f", "--family=")) != -1) {
+			ret = arg_parse_name_int(argc, argv, &i, &config->af, off,
+			    socket_parse_address_family);
+			
+			if (ret != EOK)
+				return i;
+			
+			continue;
+		}
+		
+		/* Type of service */
+		if ((off = arg_parse_short_long(argv[i], "-Q", "--tos=")) != -1) {
+			int tmp;
+			ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
+			    socket_parse_address_family);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->tos = (ip_tos_t) tmp;
+			continue;
+		}
+		
+		/* Time to live */
+		if ((off = arg_parse_short_long(argv[i], "-t", "--ttl=")) != -1) {
+			int tmp;
+			ret = arg_parse_name_int(argc, argv, &i, &tmp, off,
+			    socket_parse_address_family);
+			
+			if ((ret != EOK) || (tmp < 0))
+				return i;
+			
+			config->ttl = (ip_ttl_t) tmp;
+			continue;
+		}
+	}
+	
+	if (i >= argc)
+		return CL_MISSING;
+	
+	config->dest_addr = argv[i];
+	
+	/* Resolve destionation address */
+	switch (config->af) {
+	case AF_INET:
+		config->dest_raw = (struct sockaddr *) &config->dest;
+		config->dest_len = sizeof(config->dest);
+		config->dest.sin_family = config->af;
+		ret = inet_pton(config->af, config->dest_addr,
+		    (uint8_t *) &config->dest.sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		config->dest_raw = (struct sockaddr *) &config->dest6;
+		config->dest_len = sizeof(config->dest6);
+		config->dest6.sin6_family = config->af;
+		ret = inet_pton(config->af, config->dest_addr,
+		    (uint8_t *) &config->dest6.sin6_addr.s6_addr);
+		break;
+	default:
+		return CL_UNSUPPORTED;
+	}
+	
+	if (ret != EOK)
+		return CL_INVALID;
+	
+	/* Convert destination address back to string */
+	switch (config->af) {
+	case AF_INET:
+		ret = inet_ntop(config->af,
+		    (uint8_t *) &config->dest.sin_addr.s_addr,
+		    config->dest_str, sizeof(config->dest_str));
+		break;
+	case AF_INET6:
+		ret = inet_ntop(config->af,
+		    (uint8_t *) &config->dest6.sin6_addr.s6_addr,
+		    config->dest_str, sizeof(config->dest_str));
+		break;
+	default:
+		return CL_UNSUPPORTED;
+	}
+	
+	if (ret != EOK)
+		return CL_ERROR;
+	
+	return CL_OK;
+}
+
+int main(int argc, char *argv[])
+{
+	ping_config_t config;
+	
+	/* Default configuration */
+	config.verbose = false;
+	config.size = 56;
+	config.count = 4;
+	config.timeout = 3000;
+	config.af = AF_INET;
+	config.tos = 0;
+	config.ttl = 0;
+	config.fragments = true;
+	
+	int ret = args_parse(argc, argv, &config);
+	
+	switch (ret) {
+	case CL_OK:
+		break;
+	case CL_USAGE:
+		usage();
+		return 0;
+	case CL_MISSING:
+		fprintf(stderr, "%s: Destination address missing\n", NAME);
+		return 1;
+	case CL_INVALID:
+		fprintf(stderr, "%s: Destination address '%s' invalid or malformed\n",
+		    NAME, config.dest_addr);
+		return 2;
+	case CL_UNSUPPORTED:
+		fprintf(stderr, "%s: Destination address '%s' unsupported\n",
+		    NAME, config.dest_addr);
+		return 3;
+	case CL_ERROR:
+		fprintf(stderr, "%s: Destination address '%s' error\n",
+		    NAME, config.dest_addr);
+		return 4;
+	default:
+		fprintf(stderr, "%s: Unknown or invalid option '%s'\n", NAME,
+		    argv[ret]);
+		return 5;
+	}
+	
+	printf("PING %s (%s) %u(%u) bytes of data\n", config.dest_addr,
+	    config.dest_str, config.size, config.size);
+	
+	int icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
+	if (icmp_phone < 0) {
+		fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
+		    str_error(icmp_phone));
+		return icmp_phone;
+	}
+	
+	unsigned int seq;
+	for (seq = 0; seq < config.count; seq++) {
+		struct timeval t0;
+		ret = gettimeofday(&t0, NULL);
+		if (ret != EOK) {
+			fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
+			    str_error(ret));
+			
+			ipc_hangup(icmp_phone);
+			return ret;
+		}
+		
+		/* Ping! */
+		int result = icmp_echo_msg(icmp_phone, config.size, config.timeout,
+		    config.ttl, config.tos, !config.fragments, config.dest_raw,
+		    config.dest_len);
+		
+		struct timeval t1;
+		ret = gettimeofday(&t1, NULL);
+		if (ret != EOK) {
+			fprintf(stderr, "%s: gettimeofday failed (%s)\n", NAME,
+			    str_error(ret));
+			
+			ipc_hangup(icmp_phone);
+			return ret;
+		}
+		
+		suseconds_t elapsed = tv_sub(&t1, &t0);
+		
+		switch (result) {
+		case ICMP_ECHO:
+			printf("%u bytes from ? (?): icmp_seq=%u ttl=? time=%u.%04u\n",
+				config.size, seq, elapsed / 1000, elapsed % 1000);
+			break;
+		case ETIMEOUT:
+			printf("%u bytes from ? (?): icmp_seq=%u Timed out\n",
+				config.size, seq);
+			break;
+		default:
+			print_error(stdout, result, NULL, "\n");
+		}
+	}
+	
+	ipc_hangup(icmp_phone);
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/ping/print_error.c
===================================================================
--- uspace/app/ping/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/ping/print_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/ping/print_error.h
===================================================================
--- uspace/app/ping/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/ping/print_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
Index: uspace/app/redir/Makefile
===================================================================
--- uspace/app/redir/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/redir/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,10 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = redir
+BINARY = redir
 
 SOURCES = \
 	redir.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/redir/redir.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -39,11 +39,15 @@
 #include <fcntl.h>
 #include <unistd.h>
-#include <string.h>
+#include <str.h>
 #include <stdio.h>
 #include <task.h>
+#include <str_error.h>
+
+#define NAME  "redir"
 
 static void usage(void)
 {
-	printf("Usage: redir [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n");
+	printf("Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
+	    NAME);
 }
 
@@ -72,5 +76,5 @@
 static task_id_t spawn(int argc, char *argv[])
 {
-	char **args = (char *) calloc(argc + 1, sizeof(char *));
+	const char **args = (const char **) calloc(argc + 1, sizeof(char *));
 	if (!args) {
 		printf("No memory available\n");
@@ -84,10 +88,12 @@
 	args[argc] = NULL;
 	
-	task_id_t id = task_spawn(argv[0], args);
+	int err;
+	task_id_t id = task_spawn(argv[0], args, &err);
 	
 	free(args);
 	
 	if (id == 0)
-		printf("Error spawning %s\n", argv[0]);
+		printf("%s: Error spawning %s (%s)\n", NAME, argv[0],
+		    str_error(err));
 	
 	return id;
Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,67 @@
+#
+# 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 = $(LIBCLUI_PREFIX)/libclui.a
+EXTRA_CFLAGS = -D__HELENOS__ -I$(LIBCLUI_PREFIX)
+
+BINARY = sbi
+
+SOURCES = \
+	src/builtin/bi_boxed.c \
+	src/builtin/bi_error.c \
+	src/builtin/bi_fun.c \
+	src/builtin/bi_textfile.c \
+	src/builtin/bi_string.c \
+	src/os/helenos.c \
+	src/ancr.c \
+	src/bigint.c \
+	src/builtin.c \
+	src/cspan.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/program.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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/ancr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,222 @@
+/*
+ * 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 *);
+
+		switch (modm->mc) {
+		case mc_csi:
+			ancr_csi_dfs(prog, modm->u.csi);
+			break;
+		case mc_enum:
+			break;
+		}
+
+		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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/ancr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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/bigint.c
===================================================================
--- uspace/app/sbi/src/bigint.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/bigint.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,668 @@
+/*
+ * 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 Big integers.
+ *
+ * Sysel type @c int should accomodate large numbers. This implementation
+ * is limited by the available memory and range of the @c size_t type used
+ * to index digits.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "debug.h"
+#include "mytypes.h"
+
+#include "bigint.h"
+
+static void bigint_sign_comb(bool_t srf_a, bigint_t *a, bool_t srf_b,
+    bigint_t *b, bigint_t *dest);
+static void bigint_add_abs(bigint_t *a, bigint_t *b, bigint_t *dest);
+static void bigint_sub_abs(bigint_t *a, bigint_t *b, bigint_t *dest);
+static void bigint_shift_mul_dig(bigint_t *a, bigint_word_t b, size_t shift,
+    bigint_t *dest);
+
+static void bigint_alloc(bigint_t *bigint, size_t length);
+static void bigint_refine_len(bigint_t *bigint);
+
+/** Initialize bigint with value from small integer.
+ *
+ * Initializes a bigint structure with the provided small value.
+ *
+ * @param value		Initial value (small int).
+ */
+void bigint_init(bigint_t *bigint, int value)
+{
+	size_t length;
+	size_t idx;
+	int t;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Initialize bigint with int value %d.\n", value);
+#endif
+
+	if (value < 0) {
+		bigint->negative = b_true;
+		value = -value;
+	} else {
+		bigint->negative = b_false;
+	}
+
+	/* Determine length. */
+	length = 0;
+	t = value;
+	while (t > 0) {
+		length += 1;
+		t = t / BIGINT_BASE;
+	}
+
+	/* Allocate digit array. */
+	bigint_alloc(bigint, length);
+
+	/* Compute digits. */
+	t = value;
+	for (idx = 0; idx < length; ++idx) {
+		bigint->digit[idx] = t % BIGINT_BASE;
+		t = t / BIGINT_BASE;
+	}
+}
+
+/** Shallow copy of integer.
+ *
+ * @param src		Source.
+ * @param dest		Destination.
+ */
+void bigint_shallow_copy(bigint_t *src, bigint_t *dest)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Shallow copy of bigint.\n");
+#endif
+	dest->negative = src->negative;
+	dest->digit = src->digit;
+	dest->length = src->length;
+}
+/** Clone big integer.
+ *
+ * @param src		Source.
+ * @param dest		Destination.
+ */
+void bigint_clone(bigint_t *src, bigint_t *dest)
+{
+	size_t idx;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Clone bigint.\n");
+#endif
+	/* Copy sign. */
+	dest->negative = src->negative;
+
+	/* Allocate dest digit array. */
+	bigint_alloc(dest, src->length);
+
+	/* Copy digits. */
+	for (idx = 0; idx < dest->length; ++idx)
+		dest->digit[idx] = src->digit[idx];
+}
+
+/** Compute big integer with reversed sign.
+ *
+ * @param src		Source.
+ * @param dest		Destination.
+ */
+void bigint_reverse_sign(bigint_t *src, bigint_t *dest)
+{
+	size_t idx;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Reverse-sign copy of bigint.\n");
+#endif
+	/* Copy reversed sign. */
+	dest->negative = !src->negative;
+
+	/* Allocate dest digit array. */
+	bigint_alloc(dest, src->length);
+
+	/* Copy digits. */
+	for (idx = 0; idx < dest->length; ++idx)
+		dest->digit[idx] = src->digit[idx];
+}
+
+/** Destroy big integer.
+ *
+ * Any bigint that is initialized via bigint_init() or any other bigint
+ * function that constructs a new bigint value should be destroyed with
+ * this function to free memory associated with the bigint. It should
+ * also be used to destroy a bigint before it is reused.
+ *
+ * @param bigint	The bigint to destroy.
+ */
+void bigint_destroy(bigint_t *bigint)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Destroy bigint.\n");
+#endif
+	bigint->negative = b_false;
+
+	bigint->length = 0;
+
+	free(bigint->digit);
+	bigint->digit = NULL;
+}
+
+/** Get value of big integer.
+ *
+ * Allows to obtain the value of big integer, provided that it fits
+ * into a small integer.
+ *
+ * @param bigint	Bigint to obtain value from.
+ * @param dval		Place to store value.
+ * @return		EOK on success, ELIMIT if bigint is too big to fit
+ *			to @a dval.
+ */
+int bigint_get_value_int(bigint_t *bigint, int *dval)
+{
+	bigint_t vval, diff;
+	size_t idx;
+	int val;
+	bool_t zf;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Get int value of bigint.\n");
+#endif
+	val = 0;
+	for (idx = 0; idx < bigint->length; ++idx) {
+		val = val * BIGINT_BASE + bigint->digit[idx];
+	}
+
+	if (bigint->negative)
+		val = - val;
+
+	/* If the value did not fit @c val now contains garbage. Verify. */
+	bigint_init(&vval, val);
+
+	bigint_sub(bigint, &vval, &diff);
+	zf = bigint_is_zero(&diff);
+
+	bigint_destroy(&vval);
+	bigint_destroy(&diff);
+
+	/* If the difference is not zero, the verification failed. */
+	if (zf != b_true)
+		return EINVAL;
+
+	*dval = val;
+	return EOK;
+}
+
+/** Determine if bigint is zero.
+ *
+ * @param bigint	Big integer.
+ * @return		b_true if @a bigint is zero, b_false otherwise.
+ */
+bool_t bigint_is_zero(bigint_t *bigint)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Determine if bigint is zero.\n");
+#endif
+	return (bigint->length == 0);
+}
+
+/** Determine if bigint is negative.
+ *
+ * @param bigint	Big integer.
+ * @return		b_true if @a bigint is negative, b_false otherwise.
+ */
+bool_t bigint_is_negative(bigint_t *bigint)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Determine if bigint is negative\n");
+#endif
+	/* Verify that we did not accidentaly introduce a negative zero. */
+	assert(bigint->negative == b_false || bigint->length > 0);
+
+	return bigint->negative;
+}
+
+/** Divide bigint by (unsigned) digit.
+ *
+ * @param a		Bigint dividend.
+ * @param b		Divisor digit.
+ * @param quot		Output bigint quotient.
+ * @param rem		Output remainder digit.
+ */
+void bigint_div_digit(bigint_t *a, bigint_word_t b, bigint_t *quot,
+    bigint_word_t *rem)
+{
+	size_t lbound;
+	size_t idx;
+	bigint_dword_t da, db;
+	bigint_dword_t q, r;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Divide bigint by digit.\n");
+#endif
+	lbound = a->length;
+	bigint_alloc(quot, lbound);
+
+	quot->negative = a->negative;
+
+	r = 0;
+	idx = lbound;
+	while (idx > 0) {
+		--idx;
+
+		da = a->digit[idx] + r * BIGINT_BASE;
+		db = b;
+
+		q = da / db;
+		r = da % db;
+
+		quot->digit[idx] = q;
+	}
+
+	bigint_refine_len(quot);
+	*rem = r;
+}
+
+/** Add two big integers.
+ *
+ * The big integers @a a and @a b are added and the result is stored in
+ * @a dest.
+ *
+ * @param a		First addend.
+ * @param b		Second addend.
+ * @param dest		Destination bigint.
+ */
+void bigint_add(bigint_t *a, bigint_t *b, bigint_t *dest)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Add bigints.\n");
+#endif
+	bigint_sign_comb(b_false, a, b_false, b, dest);
+}
+
+/** Subtract two big integers.
+ *
+ * The big integers @a a and @a b are subtracted and the result is stored in
+ * @a dest.
+ *
+ * @param a		Minuend.
+ * @param b		Subtrahend.
+ * @param dest		Destination bigint.
+ */
+void bigint_sub(bigint_t *a, bigint_t *b, bigint_t *dest)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Subtract bigints.\n");
+#endif
+	bigint_sign_comb(b_false, a, b_true, b, dest);
+}
+
+/** Multiply two big integers.
+ *
+ * The big integers @a a and @a b are multiplied and the result is stored in
+ * @a dest.
+ *
+ * @param a		First factor.
+ * @param b		Second factor.
+ * @param dest		Destination bigint.
+ */
+void bigint_mul(bigint_t *a, bigint_t *b, bigint_t *dest)
+{
+	size_t idx;
+	bigint_t dprod;
+	bigint_t sum;
+	bigint_t tmp;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Multiply bigints.\n");
+#endif
+	bigint_init(&sum, 0);
+	for (idx = 0; idx < b->length; ++idx) {
+		bigint_shift_mul_dig(a, b->digit[idx], idx, &dprod);
+		bigint_add(&dprod, &sum, &tmp);
+		bigint_destroy(&dprod);
+
+		bigint_destroy(&sum);
+		bigint_shallow_copy(&tmp, &sum);
+	}
+
+	if (b->negative)
+		sum.negative = !sum.negative;
+
+	bigint_shallow_copy(&sum, dest);
+}
+
+/** Print bigint to standard output. */
+void bigint_print(bigint_t *bigint)
+{
+	bigint_t val, tmp;
+	bigint_word_t rem;
+	size_t ndigits;
+	int *digits;
+	size_t idx;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Print bigint.\n");
+#endif
+	assert(BIGINT_BASE >= 10);
+
+	if (bigint_is_zero(bigint)) {
+		putchar('0');
+		return;
+	}
+
+	if (bigint->negative)
+		putchar('-');
+
+	/* Compute number of digits. */
+	ndigits = 0;
+	bigint_clone(bigint, &val);
+	while (bigint_is_zero(&val) != b_true) {
+		bigint_div_digit(&val, 10, &tmp, &rem);
+		bigint_destroy(&val);
+		bigint_shallow_copy(&tmp, &val);
+
+		ndigits += 1;
+	}
+	bigint_destroy(&val);
+
+	/* Store digits to array. */
+
+	digits = malloc(ndigits * sizeof(int));
+	if (digits == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	idx = 0;
+	bigint_clone(bigint, &val);
+	while (bigint_is_zero(&val) != b_true) {
+		bigint_div_digit(&val, 10, &tmp, &rem);
+		bigint_destroy(&val);
+		bigint_shallow_copy(&tmp, &val);
+
+		digits[idx++] = (int) rem;
+	}
+	bigint_destroy(&val);
+
+	for (idx = 0; idx < ndigits; ++idx)
+		printf("%u", digits[ndigits - 1 - idx]);
+
+	free(digits);
+}
+
+/** Compute sign combination of two big integers.
+ *
+ * Of the big integers @a a and @a b each is optionally sign-reversed and then
+ * they are added and the result is stored in @a dest.
+ *
+ * @param srf_a		First sign reversal flag.
+ * @param a		First bigint.
+ * @param srf_b		Second sign reversal flag.
+ * @param b		Second bigint.
+ * @param dest		Destination bigint.
+ */
+static void bigint_sign_comb(bool_t srf_a, bigint_t *a, bool_t srf_b,
+    bigint_t *b, bigint_t *dest)
+{
+	bool_t neg_a, neg_b;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Signed combination of two bigints.\n");
+#endif
+	/* Compute resulting signs of combination elements. */
+	neg_a = (srf_a != a->negative);
+	neg_b = (srf_b != b->negative);
+
+	if (neg_a == neg_b) {
+		bigint_add_abs(a, b, dest);
+		dest->negative = neg_a;
+	} else {
+		bigint_sub_abs(a, b, dest);
+		dest->negative = (neg_a != dest->negative);
+	}
+}
+
+/** Add absolute values of two big integers.
+ *
+ * The absolute values of big integers @a a and @a b are added and the result
+ * is stored in @a dest.
+ *
+ * @param a		First addend.
+ * @param b		Second addend.
+ * @param dest		Destination bigint.
+ */
+static void bigint_add_abs(bigint_t *a, bigint_t *b, bigint_t *dest)
+{
+	size_t lbound;
+	size_t idx;
+	bigint_dword_t da, db;
+	bigint_dword_t tmp;
+	bigint_word_t res, carry;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Add absolute values of bigints.\n");
+#endif
+	/* max(a->length, b->length) + 1 */
+	lbound = (a->length > b->length ? a->length : b->length) + 1;
+	dest->negative = b_false;
+
+	bigint_alloc(dest, lbound);
+	carry = 0;
+
+	for (idx = 0; idx < lbound; ++idx) {
+		da = idx < a->length ? a->digit[idx] : 0;
+		db = idx < b->length ? b->digit[idx] : 0;
+
+		tmp = da + db + (bigint_word_t) carry;
+
+		carry = (bigint_word_t) (tmp / BIGINT_BASE);
+		res = (bigint_word_t) (tmp % BIGINT_BASE);
+
+		dest->digit[idx] = res;
+	}
+
+	/* If our lbound is correct, carry must be zero. */
+	assert(carry == 0);
+
+	bigint_refine_len(dest);
+}
+
+/** Subtract absolute values of two big integers.
+ *
+ * The absolute values of big integers @a a and @a b are subtracted and the
+ * result is stored in @a dest.
+ *
+ * @param a		Minuend.
+ * @param b		Subtrahend.
+ * @param dest		Destination bigint.
+ */
+static void bigint_sub_abs(bigint_t *a, bigint_t *b, bigint_t *dest)
+{
+	size_t lbound;
+	size_t idx;
+	bigint_dword_t da, db;
+	bigint_dword_t tmp;
+	bigint_word_t res, borrow;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Subtract absolute values of bigints.\n");
+#endif
+	/* max(a->length, b->length) */
+	lbound = a->length > b->length ? a->length : b->length;
+
+	bigint_alloc(dest, lbound);
+	borrow = 0;
+
+	for (idx = 0; idx < lbound; ++idx) {
+		da = idx < a->length ? a->digit[idx] : 0;
+		db = idx < b->length ? b->digit[idx] : 0;
+
+		if (da > db + borrow) {
+			tmp = da - db - borrow;
+			borrow = 0;
+		} else {
+			tmp = da + BIGINT_BASE - db - borrow;
+			borrow = 1;
+		}
+
+		res = (bigint_word_t) tmp;
+		dest->digit[idx] = res;
+	}
+
+	if (borrow != 0) {
+		/* We subtracted the greater number from the smaller. */
+		dest->negative = b_true;
+
+		/*
+		 * Now we must complement the number to get the correct
+		 * absolute value. We do this by subtracting from 10..0
+		 * (0 repeated lbound-times).
+		 */
+		borrow = 0;
+
+		for (idx = 0; idx < lbound; ++idx) {
+			da = 0;
+			db = dest->digit[idx];
+
+			if (da > db + borrow) {
+				tmp = da - db - borrow;
+				borrow = 0;
+			} else {
+				tmp = da + BIGINT_BASE - db - borrow;
+				borrow = 1;
+			}
+
+			res = (bigint_word_t) tmp;
+			dest->digit[idx] = res;
+		}
+
+		/* The last step is the '1'. */
+		assert(borrow == 1);
+	} else {
+		dest->negative = b_false;
+	}
+
+	bigint_refine_len(dest);
+}
+
+/** Multiply big integer by digit.
+ *
+ * @param a		Bigint factor.
+ * @param b		Digit factor.
+ * @param dest		Destination bigint.
+ */
+static void bigint_shift_mul_dig(bigint_t *a, bigint_word_t b, size_t shift,
+    bigint_t *dest)
+{
+	size_t lbound;
+	size_t idx;
+
+	bigint_dword_t da, db;
+	bigint_dword_t tmp;
+	bigint_word_t res, carry;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Multiply bigint by digit.\n");
+#endif
+	/* Compute length bound and allocate. */
+	lbound = a->length + shift + 1;
+	bigint_alloc(dest, lbound);
+
+	/* Copy sign. */
+	dest->negative = a->negative;
+
+	for (idx = 0; idx < shift; ++idx)
+		dest->digit[idx] = 0;
+
+	carry = 0;
+	for (idx = 0; idx < lbound - shift; ++idx) {
+		da = idx < a->length ? a->digit[idx] : 0;
+		db = b;
+
+		tmp = (da * db) + (bigint_word_t) carry;
+
+		carry = (bigint_word_t) (tmp / BIGINT_BASE);
+		res = (bigint_word_t) (tmp % BIGINT_BASE);
+
+		dest->digit[shift + idx] = res;
+	}
+
+	/* If our lbound is correct, carry must be zero. */
+	assert(carry == 0);
+
+	bigint_refine_len(dest);
+}
+
+
+/** Allocate bigint of the given length.
+ *
+ * @param bigint	Bigint whose digit array should be allocated.
+ * @param length	Length of array (also set as bigint length).
+ */
+static void bigint_alloc(bigint_t *bigint, size_t length)
+{
+	size_t a_length;
+
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Allocate bigint digit array.\n");
+#endif
+	/* malloc() sometimes cannot allocate blocks of zero size. */
+	if (length == 0)
+		a_length = 1;
+	else
+		a_length = length;
+
+	bigint->digit = malloc(a_length * sizeof(bigint_word_t));
+	if (bigint->digit == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	bigint->length = length;
+}
+
+/** Adjust length field of bigint to be exact.
+ *
+ * When bigint is allocated with bigint_alloc() its length can be
+ * imprecise (higher than actually number of non-zero digits).
+ * Then this function is used to lower @c length to the exact value.
+ */
+static void bigint_refine_len(bigint_t *bigint)
+{
+#ifdef DEBUG_BIGINT_TRACE
+	printf("Refine bigint length.\n");
+#endif
+	while (bigint->length > 0 && bigint->digit[bigint->length - 1] == 0)
+		bigint->length -= 1;
+
+	if (bigint->length == 0)
+		bigint->negative = b_false;
+}
Index: uspace/app/sbi/src/bigint.h
===================================================================
--- uspace/app/sbi/src/bigint.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/bigint.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 BIGINT_H_
+#define BIGINT_H_
+
+#include "mytypes.h"
+
+void bigint_init(bigint_t *bigint, int value);
+void bigint_shallow_copy(bigint_t *src, bigint_t *dest);
+void bigint_clone(bigint_t *src, bigint_t *dest);
+void bigint_reverse_sign(bigint_t *src, bigint_t *dest);
+void bigint_destroy(bigint_t *bigint);
+
+int bigint_get_value_int(bigint_t *bigint, int *dval);
+bool_t bigint_is_zero(bigint_t *bigint);
+bool_t bigint_is_negative(bigint_t *bigint);
+
+void bigint_div_digit(bigint_t *a, bigint_word_t b, bigint_t *quot,
+    bigint_word_t *rem);
+
+void bigint_add(bigint_t *a, bigint_t *b, bigint_t *dest);
+void bigint_sub(bigint_t *a, bigint_t *b, bigint_t *dest);
+void bigint_mul(bigint_t *a, bigint_t *b, bigint_t *dest);
+void bigint_print(bigint_t *bigint);
+
+#endif
Index: uspace/app/sbi/src/bigint_t.h
===================================================================
--- uspace/app/sbi/src/bigint_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/bigint_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,55 @@
+/*
+ * 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 BIGINT_T_H_
+#define BIGINT_T_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+typedef uint8_t bigint_word_t;
+typedef uint16_t bigint_dword_t;
+
+#define BIGINT_BASE ((bigint_dword_t) 256UL)
+
+/** Big integer.
+ *
+ * Used to implement Sysel @c int type.
+ */
+typedef struct bigint {
+	/** Number of non-zero digits in the @c digit array. */
+	size_t length;
+
+	/** Sign. */
+	bool_t negative;
+
+	/** Digits starting from the least significant. */
+	bigint_word_t *digit;
+} bigint_t;
+
+#endif
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,366 @@
+/*
+ * 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 "builtin/bi_boxed.h"
+#include "builtin/bi_error.h"
+#include "builtin/bi_fun.h"
+#include "builtin/bi_textfile.h"
+#include "builtin/bi_string.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_error_declare(bi);
+	bi_fun_declare(bi);
+	bi_textfile_declare(bi);
+	bi_string_declare(bi);
+}
+
+/** Bind internal interpreter references to symbols in the program.
+ *
+ * This is performed in separate phase for several reasons. First,
+ * symbol lookups do not work until ancestry is processed. Second,
+ * this gives a chance to process the library first and thus bind
+ * to symbols defined there.
+ */
+void builtin_bind(builtin_t *bi)
+{
+	bi_boxed_bind(bi);
+	bi_error_bind(bi);
+	bi_fun_bind(bi);
+	bi_textfile_bind(bi);
+	bi_string_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_fun_sig_t *sig;
+	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;
+	sig = stree_fun_sig_new();
+	fun->sig = sig;
+
+	list_init(&fun->sig->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->sig->args, proc_arg);
+}
Index: uspace/app/sbi/src/builtin.h
===================================================================
--- uspace/app/sbi/src/builtin.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 BUILTIN_H_
+#define BUILTIN_H_
+
+#include "mytypes.h"
+
+void builtin_declare(stree_program_t *program);
+void builtin_bind(builtin_t *bi);
+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_boxed.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_boxed.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_boxed.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,48 @@
+/*
+ * 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 Boxed primitive types binding. */
+
+#include "../builtin.h"
+#include "../mytypes.h"
+
+#include "bi_boxed.h"
+
+/** No declaration function. Boxed types are declared in the library. */
+
+/** Bind boxed types.
+ *
+ * @param bi	Builtin object
+ */
+void bi_boxed_bind(builtin_t *bi)
+{
+	bi->boxed_bool = builtin_find_lvl0(bi, "Bool");
+	bi->boxed_char = builtin_find_lvl0(bi, "Char");
+	bi->boxed_int = builtin_find_lvl0(bi, "Int");
+	bi->boxed_string = builtin_find_lvl0(bi, "String");
+}
Index: uspace/app/sbi/src/builtin/bi_boxed.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_boxed.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_boxed.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 BI_BOXED_H_
+#define BI_BOXED_H_
+
+#include "../mytypes.h"
+
+void bi_boxed_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_error.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_error.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,79 @@
+/*
+ * 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 Error classes (used with exception handling). */
+
+#include <assert.h>
+#include "../builtin.h"
+#include "../mytypes.h"
+#include "../symbol.h"
+
+#include "bi_error.h"
+
+/** Declare error class hierarchy.
+ *
+ * @param bi	Builtin object
+ */
+void bi_error_declare(builtin_t *bi)
+{
+	/*
+	 * Declare class Error and its subclasses.
+	 * Here, class Error supplants a package or namespace.
+	 */
+
+	builtin_code_snippet(bi,
+		"class Error is\n"
+			/* Common ancestor of all error classes */
+			"class Base is\n"
+			"end\n"
+			/* Accessing nil reference */
+			"class NilReference : Base is\n"
+			"end\n"
+			/* Array index out of bounds */
+			"class OutOfBounds : Base is\n"
+			"end\n"
+		"end\n");}
+
+/** Bind error class hierarchy.
+ *
+ * @param bi	Builtin object
+ */
+void bi_error_bind(builtin_t *bi)
+{
+	stree_symbol_t *sym;
+
+	/* Declare class Error and its subclasses. */
+
+	sym = builtin_find_lvl1(bi, "Error", "OutOfBounds");
+	bi->error_outofbounds = symbol_to_csi(sym);
+	assert(bi->error_outofbounds != NULL);
+
+	sym = builtin_find_lvl1(bi, "Error", "NilReference");
+	bi->error_nilreference = symbol_to_csi(sym);
+	assert(bi->error_nilreference != NULL);
+}
Index: uspace/app/sbi/src/builtin/bi_error.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_error.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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_ERROR_H_
+#define BI_ERROR_H_
+
+#include "../mytypes.h"
+
+void bi_error_declare(builtin_t *bi);
+void bi_error_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_fun.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_fun.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,219 @@
+/*
+ * 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 "../bigint.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_write(run_t *run);
+static void bi_fun_builtin_writeline(run_t *run);
+static void bi_fun_task_exec(run_t *run);
+
+/** Declare builtin functions.
+ *
+ * @param bi	Builtin object
+ */
+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->targ);
+	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.Write(). */
+
+	fun_sym = builtin_declare_fun(csi, "Write");
+	builtin_fun_add_arg(fun_sym, "arg");
+
+	/* 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.
+ *
+ * @param bi	Builtin object
+ */
+void bi_fun_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Builtin", "Write", bi_fun_builtin_write);
+	builtin_fun_bind(bi, "Builtin", "WriteLine", bi_fun_builtin_writeline);
+	builtin_fun_bind(bi, "Task", "Exec", bi_fun_task_exec);
+}
+
+/** Write to the console.
+ *
+ * @param run	Runner object
+ */
+static void bi_fun_builtin_write(run_t *run)
+{
+	rdata_var_t *var;
+	int char_val;
+	int rc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Builtin.Write()\n");
+#endif
+	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
+	assert(var);
+
+	switch (var->vc) {
+	case vc_bool:
+		printf("%s", var->u.bool_v->value ? "true" : "false");
+		break;
+	case vc_char:
+		rc = bigint_get_value_int(&var->u.char_v->value, &char_val);
+		if (rc == EOK)
+			printf("%lc", char_val);
+		else
+			printf("???");
+		break;
+	case vc_int:
+		bigint_print(&var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("%s", var->u.string_v->value);
+		break;
+	default:
+		printf("Unimplemented: Write() with unsupported type.\n");
+		exit(1);
+	}
+}
+
+/** Write a line of output.
+ *
+ * @param run	Runner object
+ */
+static void bi_fun_builtin_writeline(run_t *run)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Builtin.WriteLine()\n");
+#endif
+	bi_fun_builtin_write(run);
+	putchar('\n');
+}
+
+/** Start an executable and wait for it to finish.
+ *
+ * @param run	Runner object
+ */
+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;
+	const 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((char * const *)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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_fun.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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_string.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_string.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_string.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,181 @@
+/*
+ * 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 builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../bigint.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_string.h"
+
+static void bi_string_length(run_t *run);
+static void bi_string_slice(run_t *run);
+
+/** Declare String builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_string_declare(builtin_t *bi)
+{
+	(void) bi;
+}
+
+/** Bind String builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_string_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "String", "get_length", bi_string_length);
+	builtin_fun_bind(bi, "String", "Slice", bi_string_slice);
+}
+
+/** Return length of the string.
+ *
+ * @param run	Runner object
+ */
+static void bi_string_length(run_t *run)
+{
+        rdata_var_t *self_value_var;
+        const char *str;
+        size_t str_l;
+
+	rdata_int_t *rint;
+	rdata_var_t *rvar;
+	rdata_value_t *rval;
+	rdata_item_t *ritem;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract self.Value */
+	self_value_var = builtin_get_self_mbr_var(run, "Value");
+	assert(self_value_var->vc == vc_string);
+	str = self_value_var->u.string_v->value;
+	str_l = os_str_length(str);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Get length of string '%s'.\n", str);
+#endif
+
+	/* Construct return value. */
+	rint = rdata_int_new();
+	bigint_init(&rint->value, (int) str_l);
+
+	rvar = rdata_var_new(vc_int);
+	rvar->u.int_v = rint;
+	rval = rdata_value_new();
+	rval->var = rvar;
+
+	ritem = rdata_item_new(ic_value);
+	ritem->u.value = rval;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = ritem;
+}
+
+/** Return slice (substring) of the string.
+ *
+ * @param run	Runner object
+ */
+static void bi_string_slice(run_t *run)
+{
+        rdata_var_t *self_value_var;
+        const char *str;
+        size_t str_l;
+
+	rdata_var_t *start_var;
+	int start;
+
+	rdata_var_t *length_var;
+	int length;
+
+	int rc;
+
+	rdata_string_t *rstring;
+	rdata_var_t *rvar;
+	rdata_value_t *rval;
+	rdata_item_t *ritem;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract self.Value */
+	self_value_var = builtin_get_self_mbr_var(run, "Value");
+	assert(self_value_var->vc == vc_string);
+	str = self_value_var->u.string_v->value;
+	str_l = os_str_length(str);
+
+	/* Get argument @a start. */
+	start_var = run_local_vars_lookup(run, strtab_get_sid("start"));
+	assert(start_var);
+	assert(start_var->vc == vc_int);
+
+	rc = bigint_get_value_int(&start_var->u.int_v->value, &start);
+	if (rc != EOK || start < 0 || (size_t) start > str_l) {
+		printf("Error: Parameter 'start' to Slice() out of range.\n");
+		exit(1);
+	}
+
+	/* Get argument @a length. */
+	length_var = run_local_vars_lookup(run, strtab_get_sid("length"));
+	assert(length_var);
+	assert(length_var->vc == vc_int);
+
+	rc = bigint_get_value_int(&length_var->u.int_v->value, &length);
+	if (rc != EOK || length < 0 || (size_t) (start + length) > str_l) {
+		printf("Error: Parameter 'length' to Slice() out of range.\n");
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Construct Slice(%d, %d) from string '%s'.\n",
+	    start, length, str);
+#endif
+	/* Construct return value. */
+	rstring = rdata_string_new();
+	rstring->value = os_str_aslice(str, start, length);
+
+	rvar = rdata_var_new(vc_string);
+	rvar->u.string_v = rstring;
+	rval = rdata_value_new();
+	rval->var = rvar;
+
+	ritem = rdata_item_new(ic_value);
+	ritem->u.value = rval;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = ritem;
+}
Index: uspace/app/sbi/src/builtin/bi_string.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_string.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_string.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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_STRING_H_
+#define BI_STRING_H_
+
+#include "../mytypes.h"
+
+void bi_string_declare(builtin_t *bi);
+void bi_string_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_textfile.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_textfile.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,383 @@
+/*
+ * 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 "../bigint.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.
+ *
+ * @param bi	Builtin object
+ */
+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 : bool is\n"
+				"get is\n"
+					"return is_eof();\n"
+				"end\n"
+			"end\n"
+			"\n"
+			"fun is_eof() : bool, builtin;\n"
+		"end\n");
+
+}
+
+/** Bind TextFile builtin.
+ *
+ * @param bi	Builtin object
+ */
+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.
+ *
+ * @param run	Runner object
+ */
+static void bi_textfile_openread(run_t *run)
+{
+	rdata_var_t *fname_var;
+	const 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.
+ *
+ * @param run	Runner object
+ */
+static void bi_textfile_openwrite(run_t *run)
+{
+	rdata_var_t *fname_var;
+	const 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.
+ *
+ * @param run	Runner object
+ */
+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.
+ *
+ * @param run	Runner object
+ */
+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.
+ *
+ * @param run	Runner object
+ */
+static void bi_textfile_writeline(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+	rdata_var_t *line_var;
+	const 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.
+ *
+ * @param run	Runner object
+ */
+static void bi_textfile_is_eof(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+
+	bool_t eof_flag;
+	rdata_bool_t *eof_bool;
+	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) ? b_true : b_false;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read EOF flag '%s'.\n", eof_flag ? "true" : "false");
+#endif
+	/* Construct return value. */
+	eof_bool = rdata_bool_new();
+	eof_bool->value = eof_flag;
+
+	eof_var = rdata_var_new(vc_bool);
+	eof_var->u.bool_v = eof_bool;
+	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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin/bi_textfile.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/builtin_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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.
+ */
+
+#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;
+
+	/** Boxed variants of primitive types */
+	struct stree_symbol *boxed_bool;
+	struct stree_symbol *boxed_char;
+	struct stree_symbol *boxed_int;
+	struct stree_symbol *boxed_string;
+
+	/** Error class for nil reference access */
+	struct stree_csi *error_nilreference;
+
+	/** Error class for out-of-bounds array access */
+	struct stree_csi *error_outofbounds;
+} 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/compat.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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/cspan.c
===================================================================
--- uspace/app/sbi/src/cspan.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/cspan.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,104 @@
+/*
+ * 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 Coordinate span
+ *
+ * Captures the origin (input object, starting and ending line number and
+ * columnt number) of a code fragment.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mytypes.h"
+
+#include "cspan.h"
+
+/** Allocate new coordinate span.
+ *
+ * @param	input	Input object.
+ * @param	line	Starting line number.
+ * @param	col0	Starting column number.
+ * @param	line	Ending number (inclusive).
+ * @param	col1	Ending column number (inclusive).
+ *
+ * @return	New coordinate span.
+ */
+cspan_t *cspan_new(input_t *input, int line0, int col0, int line1, int col1)
+{
+	cspan_t *cspan;
+
+	cspan = calloc(1, sizeof(cspan_t));
+	if (cspan == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	cspan->input = input;
+	cspan->line0 = line0;
+	cspan->col0 = col0;
+	cspan->line1 = line1;
+	cspan->col1 = col1;
+
+	return cspan;
+}
+
+/** Create a merged coordinate span.
+ *
+ * Creates the smalles cspan covering cpans @a a and @a b. Both spans
+ * must be from the same input object and @a a must start earlier
+ * than @a b terminates.
+ *
+ * @param	a	First coordinate span
+ * @param	b	Second coordinate span
+ * @return	New coordinate span.
+ */
+cspan_t *cspan_merge(cspan_t *a, cspan_t *b)
+{
+	assert(a != NULL);
+	assert(b != NULL);
+	assert(a->input == b->input);
+
+	return cspan_new(a->input, a->line0, a->col0, b->line1, b->col1);
+}
+
+/** Print coordinate span.
+ *
+ * @param cspan		Coordinate span
+ */
+void cspan_print(cspan_t *cspan)
+{
+	printf("%s:", cspan->input->name);
+
+	if (cspan->line0 != cspan->line1) {
+		printf("%d:%d-%d:%d", cspan->line0, cspan->col0, cspan->line1,
+		    cspan->col1);
+	} else {
+		printf("%d:%d-%d", cspan->line0, cspan->col0, cspan->col1);
+	}
+}
Index: uspace/app/sbi/src/cspan.h
===================================================================
--- uspace/app/sbi/src/cspan.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/cspan.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 CSPAN_H_
+#define CSPAN_H_
+
+#include "mytypes.h"
+
+cspan_t *cspan_new(input_t *input, int line0, int col0, int line1, int col1);
+cspan_t *cspan_merge(cspan_t *a, cspan_t *b);
+void cspan_print(cspan_t *cspan);
+
+#endif
Index: uspace/app/sbi/src/cspan_t.h
===================================================================
--- uspace/app/sbi/src/cspan_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/cspan_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,48 @@
+/*
+ * 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 CSPAN_T_H_
+#define CSPAN_T_H_
+
+/** Coordinate span
+ *
+ * A coordinate span records the coordinates of a source code fragment.
+ * It can span multiple lines, but not multiple input objects.
+ */
+typedef struct cspan {
+	/** Input object where the span comes from */
+	struct input *input;
+
+	/* Starting line and column */
+	int line0, col0;
+
+	/* Ending line and column, inclusive. */
+	int line1, col1;
+} cspan_t;
+
+#endif
Index: uspace/app/sbi/src/debug.h
===================================================================
--- uspace/app/sbi/src/debug.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/debug.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 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
+
+/** Uncomment this to get verbose debugging messages for bigint computation. */
+//#define DEBUG_BIGINT_TRACE
+
+#endif
Index: uspace/app/sbi/src/imode.c
===================================================================
--- uspace/app/sbi/src/imode.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/imode.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,193 @@
+/*
+ * 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 "os/os.h"
+#include "ancr.h"
+#include "assert.h"
+#include "builtin.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "program.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);
+
+	/* Process the library. */
+	if (program_lib_process(program) != EOK)
+		exit(1);
+
+	/* Resolve ancestry. */
+	ancr_module_process(program, program->module);
+
+	/* Bind internal interpreter references to symbols. */
+	builtin_bind(program->builtin);
+
+	/* 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");
+	fun->sig = stree_fun_sig_new();
+
+	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);
+
+	printf("SBI interactive mode. ");
+	os_input_disp_help();
+
+	quit_im = b_false;
+	while (quit_im != b_true) {
+		parse.error = b_false;
+		stype.error = b_false;
+		run.thread_ar->exc_payload = NULL;
+		run.thread_ar->bo_mode = bm_none;
+
+		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);
+
+		/* Check for unhandled exceptions. */
+		run_exc_check_unhandled(&run);
+
+		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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/imode.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/input.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,238 @@
+/*
+ * 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, const 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, const 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, const 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->name = os_str_dup(fname);
+	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->name = "<user-input>";
+	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->name = "<builtin>";
+	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 object.
+ * @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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/input.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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, const 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/input_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 INPUT_T_H_
+#define INPUT_T_H_
+
+#include <stdio.h>
+
+/** Input state object */
+typedef struct input {
+	/** Input name (for error output) */
+	const char *name;
+
+	/** 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/intmap.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/intmap.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/intmap_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/lex.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,749 @@
+/*
+ * 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 "bigint.h"
+#include "cspan.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_char(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_and,	"and" },
+	{ lc_as,	"as" },
+	{ lc_bool,	"bool" },
+	{ lc_break,	"break" },
+	{ lc_builtin,	"builtin" },
+	{ lc_char,	"char" },
+	{ lc_class,	"class" },
+	{ lc_deleg,	"deleg" },
+	{ lc_do,	"do" },
+	{ lc_elif,	"elif" },
+	{ lc_else,	"else" },
+	{ lc_end,	"end" },
+	{ lc_enum,	"enum" },
+	{ lc_except,	"except" },
+	{ lc_false,	"false" },
+	{ 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_not,	"not" },
+	{ lc_nil,	"nil" },
+	{ lc_or,	"or" },
+	{ 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_true,	"true" },
+	{ 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_minus,	"-" },
+	{ lc_mult,	"*" },
+	{ 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("('%s')", strtab_get_str(lem->u.ident.sid));
+		break;
+	case lc_lit_int:
+		printf("(");
+		bigint_print(&lem->u.lit_int.value);
+		printf(")");
+		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)
+{
+	cspan_print(lem->cspan);
+}
+
+/** 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->prev_valid = b_false;
+	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.
+ * @return		Pointer to current lem. Owned by @a lex and only valid
+ *			until next call to lex_xxx().
+ */
+lem_t *lex_get_current(lex_t *lex)
+{
+	lex_touch(lex);
+	return &lex->current;
+}
+
+/** Get previous lem if valid.
+ *
+ * The returned pointer is invalidated by next call to lex_next()
+ *
+ * @param lex		Lexer object.
+ * @return		Pointer to previous lem. Owned by @a lex and only valid
+ *			until next call to lex_xxx().
+ */
+lem_t *lex_peek_prev(lex_t *lex)
+{
+	if (lex->current_valid == b_false) {
+		/*
+		 * This means the head is advanced but next lem was not read.
+		 * Thus the previous lem is still in @a current.
+		 */
+		return &lex->current;
+	}
+
+	if (lex->prev_valid != b_true) {
+		/* Looks like we are still at the first lem. */
+		return NULL;
+	}
+
+	/*
+	 * Current lem has been read in. Thus the previous lem was moved to
+	 * @a previous.
+	 */
+	return &lex->prev;
+}
+
+/** 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;
+
+	/* Copy previous lem */
+	lex->prev = lex->current;
+	lex->prev_valid = b_true;
+
+	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, *lsp;
+	int line0, col0;
+
+	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.
+	 */
+	line0 = input_get_line_no(lex->input);
+	col0 = 1 + lex->col_adj + (lex->ibp - lex->inbuf);
+
+	lex->current.cspan = cspan_new(lex->input, line0, col0, line0, col0);
+
+	lsp = lex->ibp;
+	bp = lex->ibp;
+
+	if (bp[0] == '\0') {
+		/* End of input */
+		lex->current.lclass = lc_eof;
+		goto finish;
+	}
+
+	if (is_wstart(bp[0])) {
+		lex_word(lex);
+		goto finish;
+	}
+
+	if (bp[0] == '\'') {
+		lex_char(lex);
+		goto finish;
+	}
+
+	if (is_digit(bp[0])) {
+		lex_number(lex);
+		goto finish;
+	}
+
+	if (bp[0] == '"') {
+		lex_string(lex);
+		goto finish;
+	}
+
+	if (bp[0] == '-' && bp[1] == '-') {
+		lex_skip_comment(lex);
+
+		/* Compute ending column number */
+		lex->current.cspan->col1 = col0 + (lex->ibp - lsp) - 1;
+
+		/* Try again */
+		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 '-':
+		lex->current.lclass = lc_minus; ++bp; break;
+
+	case '*':
+		lex->current.lclass = lc_mult; ++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;
+
+finish:
+	/* Compute ending column number */
+	lex->current.cspan->col1 = col0 + (lex->ibp - lsp) - 1;
+	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 character literal.
+ *
+ * Reads in a character literal and stores it in the current lem in @a lex.
+ *
+ * @param lex		Lexer object.
+ */
+static void lex_char(lex_t *lex)
+{
+	char *bp;
+	int idx;
+	size_t len;
+	int char_val;
+
+	bp = lex->ibp + 1;
+	idx = 0;
+
+	while (bp[idx] != '\'') {
+		if (idx >= SLBUF_SIZE) {
+			printf("Error: Character literal too long.\n");
+			exit(1);
+		}
+
+		if (bp[idx] == '\0') {
+			printf("Error: Unterminated character literal.\n");
+			exit(1);
+		}
+
+		strlit_buf[idx] = bp[idx];
+		++idx;
+	}
+
+	lex->ibp = bp + idx + 1;
+
+	strlit_buf[idx] = '\0';
+	len = os_str_length(strlit_buf);
+	if (len != 1) {
+		printf("Character literal should contain one character, "
+		    "but contains %u characters instead.\n", (unsigned) len);
+		exit(1);
+	}
+
+	os_str_get_char(strlit_buf, 0, &char_val);
+	lex->current.lclass = lc_lit_char;
+	bigint_init(&lex->current.u.lit_char.value, char_val);
+}
+
+/** 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;
+	bigint_t value;
+	bigint_t dgval;
+	bigint_t base;
+	bigint_t tprod;
+
+	bp = lex->ibp;
+
+	bigint_init(&value, 0);
+	bigint_init(&base, 10);
+
+	while (is_digit(*bp)) {
+		bigint_mul(&value, &base, &tprod);
+		bigint_init(&dgval, digit_value(*bp));
+
+		bigint_destroy(&value);
+		bigint_add(&tprod, &dgval, &value);
+		bigint_destroy(&tprod);
+		bigint_destroy(&dgval);
+
+		++bp;
+	}
+
+	bigint_destroy(&base);
+
+	lex->ibp = bp;
+
+	lex->current.lclass = lc_lit_int;
+	bigint_shallow_copy(&value, &lex->current.u.lit_int.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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/lex.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 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);
+lem_t *lex_peek_prev(lex_t *lex);
+
+#endif
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/lex_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,188 @@
+/*
+ * 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_
+
+#include "bigint_t.h"
+
+/** Lexical element class */
+typedef enum {
+	lc_invalid,
+	lc_eof,
+
+	lc_ident,
+	lc_lit_char,
+	lc_lit_int,
+	lc_lit_string,
+
+	/* Keywords */
+	lc_and,
+	lc_as,
+	lc_break,
+	lc_bool,
+	lc_builtin,
+	lc_char,
+	lc_class,
+	lc_deleg,
+	lc_do,
+	lc_elif,
+	lc_else,
+	lc_end,
+	lc_enum,
+	lc_except,
+	lc_false,
+	lc_finally,
+	lc_for,
+	lc_fun,
+	lc_new,
+	lc_get,
+	lc_if,
+	lc_in,
+	lc_int,
+	lc_interface,
+	lc_is,
+	lc_nil,
+	lc_not,
+	lc_or,
+	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_true,
+	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_minus,
+	lc_mult,
+	lc_increase,
+
+	/* Punctuators */
+	lc_comma,
+	lc_colon,
+	lc_scolon,
+
+	lc__limit
+} lclass_t;
+
+typedef struct {
+	/* String ID */
+	int sid;
+} lem_ident_t;
+
+typedef struct {
+	/* Character value */
+	bigint_t value;
+} lem_lit_char_t;
+
+typedef struct {
+	/* Integer value */
+	bigint_t 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_char_t lit_char;
+		lem_lit_int_t lit_int;
+		lem_lit_string_t lit_string;
+	} u;
+
+	/** Coordinates of this lexical element */
+	struct cspan *cspan;
+} 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 previous lem in @c prev */
+	bool_t prev_valid;
+
+	/** Previous lem (only valid if @c current_valid is true) */
+	lem_t prev;
+
+	/** @c b_true if we have the current 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/list.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/list.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/list_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/main.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,137 @@
+/*
+ * 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 "os/os.h"
+#include "builtin.h"
+#include "imode.h"
+#include "mytypes.h"
+#include "program.h"
+#include "strtab.h"
+#include "stree.h"
+#include "stype.h"
+#include "input.h"
+#include "lex.h"
+#include "parse.h"
+#include "run.h"
+
+static void syntax_print(void);
+
+/** Main entry point.
+ *
+ * @return	Zero on success, non-zero on error.
+ */
+int main(int argc, char *argv[])
+{
+	stree_program_t *program;
+	stype_t stype;
+	run_t run;
+	int rc;
+
+	/* Store executable file path under which we have been invoked. */
+	os_store_ef_path(*argv);
+
+	argv += 1;
+	argc -= 1;
+
+	if (argc == 0) {
+		/* Enter interactive mode */
+		strtab_init();
+		imode_run();
+		return 0;
+	}
+
+	if (os_str_cmp(*argv, "-h") == 0) {
+		syntax_print();
+		return 0;
+	}
+
+	strtab_init();
+	program = stree_program_new();
+	program->module = stree_module_new();
+
+	/* Declare builtin symbols. */
+	builtin_declare(program);
+
+	/* Process source files in the library. */
+	if (program_lib_process(program) != EOK)
+		return 1;
+
+	/* Resolve ancestry. */
+	ancr_module_process(program, program->module);
+
+	/* Bind internal interpreter references to symbols. */
+	builtin_bind(program->builtin);
+
+	/* Process all source files specified in command-line arguments. */
+	while (argc > 0) {
+		rc = program_file_process(program, *argv);
+		if (rc != EOK)
+			return 1;
+
+		argv += 1;
+		argc -= 1;
+	}
+
+	/* Resolve ancestry. */
+	ancr_module_process(program, program->module);
+
+	/* Type program. */
+	stype.program = program;
+	stype.error = b_false;
+	stype_module(&stype, program->module);
+
+	/* Check for typing errors. */
+	if (stype.error)
+		return 1;
+
+	/* Run program. */
+	run_init(&run);
+	run_program(&run, program);
+
+	/* Check for run-time errors. */
+	if (run.thread_ar->error)
+		return 1;
+
+	return 0;
+}
+
+/** Print command-line syntax help. */
+static void syntax_print(void)
+{
+	printf("Syntax: sbi <source_file.sy>\n");
+}
Index: uspace/app/sbi/src/mytypes.h
===================================================================
--- uspace/app/sbi/src/mytypes.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/mytypes.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,64 @@
+/*
+ * 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 "bigint_t.h"
+#include "builtin_t.h"
+#include "cspan_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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/os/helenos.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,255 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <task.h>
+#include <tinput.h>
+#include <str_error.h>
+
+#include "os.h"
+
+/** Path to executable file via which we have been invoked. */
+static char *ef_path;
+
+/*
+ * Using HelenOS-specific string API.
+ */
+
+static tinput_t *tinput = NULL;
+
+/** Concatenate two strings.
+ *
+ * @param a	First string
+ * @param b	Second string
+ * @return	New string, concatenation of @a a and @a b.
+ */
+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;
+}
+
+/** Return slice (substring) of a string.
+ *
+ * Copies the specified range of characters from @a str and returns it
+ * as a newly allocated string. @a start + @a length must be less than
+ * or equal to the length of @a str.
+ *
+ * @param str		String
+ * @param start		Index of first character (starting from zero).
+ * @param length	Number of characters to copy.
+ *
+ * @return		Newly allocated string holding the slice.
+ */
+char *os_str_aslice(const char *str, size_t start, size_t length)
+{
+	char *slice;
+	size_t offset;
+	size_t i;
+	size_t size;
+	wchar_t c;
+
+	assert(start + length <= str_length(str));
+
+	offset = 0;
+	for (i = 0; i < start; ++i) {
+		c = str_decode(str, &offset, STR_NO_LIMIT);
+		assert(c != '\0');
+		assert(c != U_SPECIAL);
+		(void) c;
+	}
+
+	size = str_lsize(str, length);
+	slice = str_ndup(str + offset, size);
+
+	return slice;
+}
+
+/** Compare two strings.
+ *
+ * @param a	First string
+ * @param b	Second string
+ * @return	Zero if equal, nonzero if not equal
+ */
+int os_str_cmp(const char *a, const char *b)
+{
+	return str_cmp(a, b);
+}
+
+/** Return number of characters in string.
+ *
+ * @param str	String
+ * @return	Number of characters in @a str.
+ */
+size_t os_str_length(const char *str)
+{
+	return str_length(str);
+}
+
+/** Duplicate string.
+ *
+ * @param str	String
+ * @return	New string, duplicate of @a str.
+ */
+char *os_str_dup(const char *str)
+{
+	return str_dup(str);
+}
+
+/** Get character from string at the given index.
+ *
+ * @param str		String
+ * @param index		Character index (starting from zero).
+ * @param out_char	Place to store character.
+ * @return		EOK on success, EINVAL if index is out of bounds,
+ *			EIO on decoding error.
+ */
+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;
+}
+
+/** Display survival help message. */
+void os_input_disp_help(void)
+{
+	printf("Press Ctrl-Q to quit.\n");
+}
+
+/** Read one line of input from the user.
+ *
+ * @param ptr	Place to store pointer to new string.
+ */
+int os_input_line(char **ptr)
+{
+	char *line;
+	int rc;
+
+	if (tinput == NULL) {
+		tinput = tinput_new();
+		if (tinput == NULL)
+			return EIO;
+	}
+
+	rc = tinput_read(tinput, &line);
+	if (rc == ENOENT) {
+		/* User-requested abort */
+		*ptr = os_str_dup("");
+		return EOK;
+	}
+
+	if (rc != EOK) {
+		/* Error in communication with console */
+		return EIO;
+	}
+
+	/* XXX Input module needs trailing newline to keep going. */
+	*ptr = os_str_acat(line, "\n");
+	free(line);
+
+	return EOK;
+}
+
+/** Simple command execution.
+ *
+ * @param cmd	Command and arguments (NULL-terminated list of strings.)
+ *		Command is present just one, not duplicated.
+ */
+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, &retval);
+	if (tid == 0) {
+		printf("Error: Failed spawning '%s' (%s).\n", cmd[0],
+		    str_error(retval));
+		exit(1);
+	}
+
+	/* XXX Handle exit status and return value. */
+	task_wait(tid, &texit, &retval);
+
+	return EOK;
+}
+
+/** Store the executable file path via which we were executed.
+ *
+ * @param path	Executable path via which we were executed.
+ */
+void os_store_ef_path(char *path)
+{
+	ef_path = path;
+}
+
+/** Return path to the Sysel library
+ *
+ * @return New string. Caller should deallocate it using @c free().
+ */
+char *os_get_lib_path(void)
+{
+	return os_str_dup("/src/sysel/lib");
+}
Index: uspace/app/sbi/src/os/os.h
===================================================================
--- uspace/app/sbi/src/os/os.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/os/os.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 OS_H_
+#define OS_H_
+
+char *os_str_acat(const char *a, const char *b);
+char *os_str_aslice(const char *str, size_t start, size_t length);
+int os_str_cmp(const char *a, const char *b);
+char *os_str_dup(const char *str);
+size_t os_str_length(const char *str);
+int os_str_get_char(const char *str, int index, int *out_char);
+void os_input_disp_help(void);
+int os_input_line(char **ptr);
+int os_exec(char * const cmd[]);
+
+void os_store_ef_path(char *path);
+char *os_get_lib_path(void);
+
+#endif
Index: uspace/app/sbi/src/os/posix.c
===================================================================
--- uspace/app/sbi/src/os/posix.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/os/posix.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,239 @@
+/*
+ * 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 <assert.h>
+#include <libgen.h>
+#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"
+
+/** Path to executable file via which we have been invoked. */
+static char *ef_path;
+
+/*
+ * The string functions are in fact standard C, but would not work under
+ * HelenOS.
+ * 
+ * XXX String functions used here only work with 8-bit text encoding.
+ */
+
+/** Concatenate two strings.
+ *
+ * @param a	First string
+ * @param b	Second string
+ * @return	New string, concatenation of @a a and @a b.
+ */
+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;
+}
+
+/** Return slice (substring) of a string.
+ *
+ * Copies the specified range of characters from @a str and returns it
+ * as a newly allocated string. @a start + @a length must be less than
+ * or equal to the length of @a str.
+ *
+ * @param str		String
+ * @param start		Index of first character (starting from zero).
+ * @param length	Number of characters to copy.
+ *
+ * @return		Newly allocated string holding the slice.
+ */
+char *os_str_aslice(const char *str, size_t start, size_t length)
+{
+	char *slice;
+
+	assert(start + length <= strlen(str));
+	slice = malloc(length + 1);
+	if (slice == NULL) {
+		printf("Memory allocation error.\n");
+		exit(1);
+	}
+
+	strncpy(slice, str + start, length);
+	slice[length] = '\0';
+
+	return slice;
+}
+
+/** Compare two strings.
+ *
+ * @param a	First string
+ * @param b	Second string
+ * @return	Zero if equal, nonzero if not equal
+ */
+int os_str_cmp(const char *a, const char *b)
+{
+	return strcmp(a, b);
+}
+
+/** Return number of characters in string.
+ *
+ * @param str	String
+ * @return	Number of characters in @a str.
+ */
+size_t os_str_length(const char *str)
+{
+	return strlen(str);
+}
+
+/** Duplicate string.
+ *
+ * @param str	String
+ * @return	New string, duplicate of @a str.
+ */
+char *os_str_dup(const char *str)
+{
+	return strdup(str);
+}
+
+/** Get character from string at the given index.
+ *
+ * @param str		String
+ * @param index		Character index (starting from zero).
+ * @param out_char	Place to store character.
+ * @return		EOK on success, EINVAL if index is out of bounds,
+ *			EIO on decoding error.
+ */
+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];
+
+/** Display survival help message. */
+void os_input_disp_help(void)
+{
+	printf("Send ^C (SIGINT) to quit.\n");
+}
+
+/** Read one line of input from the user.
+ *
+ * @param ptr	Place to store pointer to new string.
+ */
+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.
+ *
+ * @param cmd	Command and arguments (NULL-terminated list of strings.)
+ *		Command is present just one, not duplicated.
+ */
+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;
+}
+
+/** Store the executable file path via which we were executed.
+ *
+ * @param path	Executable path via which we were executed.
+ */
+void os_store_ef_path(char *path)
+{
+	ef_path = path;
+}
+
+/** Return path to the Sysel library
+ *
+ * @return New string. Caller should deallocate it using @c free().
+ */
+char *os_get_lib_path(void)
+{
+	return os_str_acat(dirname(ef_path), "/lib");
+}
Index: uspace/app/sbi/src/p_expr.c
===================================================================
--- uspace/app/sbi/src/p_expr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/p_expr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,865 @@
+/*
+ * 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 "bigint.h"
+#include "cspan.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_disjunctive(parse_t *parse);
+static stree_expr_t *parse_conjunctive(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_multip(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_paren(parse_t *parse);
+static stree_expr_t *parse_primitive(parse_t *parse);
+static stree_expr_t *parse_nameref(parse_t *parse);
+static stree_expr_t *parse_lit_bool(parse_t *parse);
+static stree_expr_t *parse_lit_char(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_disjunctive(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_disjunctive(parse);
+
+	assign->dest = a;
+	assign->src = b;
+
+	tmp = stree_expr_new(ec_assign);
+	tmp->u.assign = assign;
+	tmp->cspan = cspan_merge(a->cspan, b->cspan);
+
+	assign->expr = tmp;
+
+	return tmp;
+}
+
+/** Parse disjunctive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_disjunctive(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	cspan_t *cs;
+
+	a = parse_conjunctive(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_or) {
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_conjunctive(parse);
+
+		binop = stree_binop_new(bo_or);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
+}
+
+/** Parse conjunctive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_conjunctive(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	cspan_t *cs;
+
+	a = parse_comparative(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_and) {
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_comparative(parse);
+
+		binop = stree_binop_new(bo_and);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
+}
+
+/** 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;
+	cspan_t *cs;
+
+	a = parse_additive(parse);
+	cs = a->cspan;
+
+	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;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	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;
+	binop_class_t bc;
+	cspan_t *cs;
+
+	a = parse_multip(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_plus || lcur_lc(parse) == lc_minus) {
+		if (parse_is_error(parse))
+			break;
+
+		switch (lcur_lc(parse)) {
+		case lc_plus: bc = bo_plus; break;
+		case lc_minus: bc = bo_minus; break;
+		default: assert(b_false);
+		}
+
+		lskip(parse);
+		b = parse_multip(parse);
+
+		binop = stree_binop_new(bc);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
+}
+
+/** Parse multiplicative expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_multip(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	binop_class_t bc;
+	cspan_t *cs;
+
+	a = parse_prefix(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_mult) {
+		if (parse_is_error(parse))
+			break;
+
+		switch (lcur_lc(parse)) {
+		case lc_mult: bc = bo_mult; break;
+		default: assert(b_false);
+		}
+
+		lskip(parse);
+		b = parse_prefix(parse);
+
+		binop = stree_binop_new(bc);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
+}
+
+/** Parse prefix expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_prefix(parse_t *parse)
+{
+	stree_expr_t *a;
+	stree_expr_t *tmp;
+	stree_unop_t *unop;
+	unop_class_t uc;
+	cspan_t *cs0;
+
+	switch (lcur_lc(parse)) {
+	case lc_plus:
+	case lc_minus:
+	case lc_not:
+		if (parse_is_error(parse))
+			return parse_recovery_expr(parse);
+
+		switch (lcur_lc(parse)) {
+		case lc_plus: uc = uo_plus; break;
+		case lc_minus: uc = uo_minus; break;
+		case lc_not: uc = uo_not; break;
+		default: assert(b_false);
+		}
+
+		cs0 = lcur_span(parse);
+		lskip(parse);
+		a = parse_postfix(parse);
+
+		unop = stree_unop_new(uc);
+		unop->arg = a;
+
+		tmp = stree_expr_new(ec_unop);
+		tmp->u.unop = unop;
+		tmp->cspan = cspan_merge(cs0, a->cspan);
+		unop->expr = tmp;
+		a = tmp;
+		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;
+	stree_expr_t *arg;
+	cspan_t *cs0, *cs1;
+
+	cs0 = lcur_span(parse);
+	lmatch(parse, lc_new);
+	texpr = parse_texpr(parse);
+
+	/* XXX Take span from texpr */
+	cs1 = lprev_span(parse);
+
+	new_op = stree_new_new();
+	new_op->texpr = texpr;
+	expr = stree_expr_new(ec_new);
+	expr->u.new_op = new_op;
+
+	list_init(&new_op->ctor_args);
+
+	/* Parenthesized arguments should be present except for arrays. */
+	if (texpr->tc != tc_tindex) {
+		lmatch(parse, lc_lparen);
+
+		/* Parse constructor arguments */
+
+		if (lcur_lc(parse) != lc_rparen) {
+			while (!parse_is_error(parse)) {
+				arg = parse_expr(parse);
+				list_append(&new_op->ctor_args, arg);
+
+				if (lcur_lc(parse) == lc_rparen)
+					break;
+				lmatch(parse, lc_comma);
+			}
+		}
+
+		lmatch(parse, lc_rparen);
+		cs1 = cspan_merge(cs0, lprev_span(parse));
+	}
+
+	expr->cspan = cspan_merge(cs0, cs1);
+	new_op->expr = expr;
+
+	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_paren(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;
+	cspan_t *cs1;
+
+	lmatch(parse, lc_period);
+	ident = parse_ident(parse);
+
+	/* XXX Take span from ident */
+	cs1 = lprev_span(parse);
+
+	access = stree_access_new();
+	access->arg = a;
+	access->member_name = ident;
+
+	expr = stree_expr_new(ec_access);
+	expr->u.access = access;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+
+	access->expr = expr;
+
+	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;
+	cspan_t *cs1;
+
+	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);
+	cs1 = lprev_span(parse);
+
+	expr = stree_expr_new(ec_call);
+	expr->u.call = call;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+	call->expr = expr;
+
+	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;
+	cspan_t *cs1;
+
+	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);
+	cs1 = lprev_span(parse);
+
+	expr = stree_expr_new(ec_index);
+	expr->u.index = index;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+	index->expr = expr;
+
+	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;
+	cspan_t *cs1;
+
+	lmatch(parse, lc_as);
+	texpr = parse_texpr(parse);
+
+	/* XXX Take span from texpr */
+	cs1 = lprev_span(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;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+
+	as_op->expr = expr;
+
+	return expr;
+}
+
+/** Parse possibly partenthesized expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_paren(parse_t *parse)
+{
+	stree_expr_t *expr;
+	cspan_t *cs0, *cs1;
+
+	if (lcur_lc(parse) == lc_lparen) {
+		cs0 = lcur_span(parse);
+		lskip(parse);
+		expr = parse_expr(parse);
+		lmatch(parse, lc_rparen);
+		cs1 = lprev_span(parse);
+
+		expr->cspan = cspan_merge(cs0, cs1);
+	} else {
+		expr = parse_primitive(parse);
+	}
+
+	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_false:
+	case lc_true:
+		expr = parse_lit_bool(parse);
+		break;
+	case lc_lit_char:
+		expr = parse_lit_char(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;
+	expr->cspan = lprev_span(parse);
+	nameref->expr = expr;
+
+	return expr;
+}
+
+/** Parse boolean literal.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_lit_bool(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+	bool_t value;
+
+	switch (lcur_lc(parse)) {
+	case lc_false: value = b_false; break;
+	case lc_true: value = b_true; break;
+	default: assert(b_false);
+	}
+
+	lskip(parse);
+
+	literal = stree_literal_new(ltc_bool);
+	literal->u.lit_bool.value = value;
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
+
+	return expr;
+}
+
+/** Parse character literal.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_lit_char(parse_t *parse)
+{
+	stree_literal_t *literal;
+	stree_expr_t *expr;
+
+	lcheck(parse, lc_lit_char);
+
+	literal = stree_literal_new(ltc_char);
+	bigint_clone(&lcur(parse)->u.lit_char.value,
+	    &literal->u.lit_char.value);
+
+	lskip(parse);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
+
+	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);
+	bigint_clone(&lcur(parse)->u.lit_int.value,
+	    &literal->u.lit_int.value);
+
+	lskip(parse);
+
+	expr = stree_expr_new(ec_literal);
+	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
+
+	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;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
+
+	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;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
+
+	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;
+	expr->cspan = lprev_span(parse);
+	self_ref->expr = expr;
+
+	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;
+	literal->expr = expr;
+
+	return expr;
+}
Index: uspace/app/sbi/src/p_expr.h
===================================================================
--- uspace/app/sbi/src/p_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/p_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/p_type.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,366 @@
+/*
+ * 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 "cspan.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_tparen(parse_t *parse);
+static stree_texpr_t *parse_tprimitive(parse_t *parse);
+static stree_texpr_t *parse_tliteral(parse_t *parse);
+static stree_texpr_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 *gtype;
+	stree_texpr_t *aexpr;
+	stree_texpr_t *targ;
+	stree_tapply_t *tapply;
+
+	gtype = parse_tpostfix(parse);
+	if (lcur_lc(parse) != lc_slash)
+		return gtype;
+
+	tapply = stree_tapply_new();
+	tapply->gtype = gtype;
+	list_init(&tapply->targs);
+
+	targ = NULL;
+
+	while (lcur_lc(parse) == lc_slash) {
+
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		targ = parse_tpostfix(parse);
+
+		list_append(&tapply->targs, targ);
+	}
+
+	aexpr = stree_texpr_new(tc_tapply);
+	aexpr->u.tapply = tapply;
+	tapply->texpr = aexpr;
+
+	if (targ != NULL)
+		aexpr->cspan = cspan_merge(gtype->cspan, targ->cspan);
+	else
+		aexpr->cspan = gtype->cspan;
+
+	return aexpr;
+}
+
+/** 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_tparen(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;
+	taccess->texpr = texpr;
+	texpr->cspan = cspan_merge(a->cspan, ident->cspan);
+
+	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;
+	cspan_t *cs1;
+
+	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);
+	cs1 = lprev_span(parse);
+
+	texpr = stree_texpr_new(tc_tindex);
+	texpr->u.tindex = tindex;
+	tindex->texpr = texpr;
+	texpr->cspan = cspan_merge(a->cspan, cs1);
+
+	return texpr;
+}
+
+/** Parse possibly partenthesized type expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tparen(parse_t *parse)
+{
+	stree_texpr_t *texpr;
+	cspan_t *cs0, *cs1;
+
+	if (lcur_lc(parse) == lc_lparen) {
+		cs0 = lcur_span(parse);
+		lskip(parse);
+		texpr = parse_texpr(parse);
+		lmatch(parse, lc_rparen);
+		cs1 = lprev_span(parse);
+		texpr->cspan = cspan_merge(cs0, cs1);
+	} else {
+		texpr = parse_tprimitive(parse);
+	}
+
+	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 = parse_tnameref(parse);
+		break;
+	case lc_bool:
+	case lc_char:
+	case lc_int:
+	case lc_string:
+	case lc_resource:
+		texpr = 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_texpr_t *parse_tliteral(parse_t *parse)
+{
+	stree_tliteral_t *tliteral;
+	tliteral_class_t tlc;
+	stree_texpr_t *texpr;
+
+	switch (lcur_lc(parse)) {
+	case lc_bool:
+		tlc = tlc_bool;
+		break;
+	case lc_char:
+		tlc = tlc_char;
+		break;
+	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);
+	texpr = stree_texpr_new(tc_tliteral);
+	texpr->u.tliteral = tliteral;
+	tliteral->texpr = texpr;
+	texpr->cspan = lprev_span(parse);
+
+	return texpr;
+}
+
+/** Parse type identifier.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tnameref(parse_t *parse)
+{
+	stree_tnameref_t *tnameref;
+	stree_texpr_t *texpr;
+
+	tnameref = stree_tnameref_new();
+	tnameref->name = parse_ident(parse);
+
+	texpr = stree_texpr_new(tc_tnameref);
+	texpr->u.tnameref = tnameref;
+	tnameref->texpr = texpr;
+	texpr->cspan = tnameref->name->cspan;
+
+	return texpr;
+}
+
+/** 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;
+	tliteral->texpr = texpr;
+
+	return texpr;
+}
Index: uspace/app/sbi/src/p_type.h
===================================================================
--- uspace/app/sbi/src/p_type.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/p_type.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/parse.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1432 @@
+/*
+ * 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 and CSI 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_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi);
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum);
+
+static stree_deleg_t *parse_deleg(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);
+static stree_fun_sig_t *parse_fun_sig(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_break_t *parse_break(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);
+
+/** Initialize parser object.
+ *
+ * Set up parser @a parse to use lexer @a lex for input and to store
+ * output (i.e. new declarations) to program @a prog. @a prog is not
+ * necessarily empty, the declarations being parsed are simply added
+ * to it.
+ *
+ * @param parse		Parser object.
+ * @param prog		Destination program stree.
+ * @param lex		Input lexer.
+ */
+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.
+ *
+ * Parse a program module.
+ *
+ * The input is read using the lexer associated with @a parse. The resulting
+ * declarations are added to existing declarations in the program associated
+ * with @a parse.
+ *
+ * If any parse 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.
+ */
+void parse_module(parse_t *parse)
+{
+	stree_csi_t *csi;
+	stree_enum_t *enum_d;
+	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;
+		case lc_enum:
+			enum_d = parse_enum(parse, NULL);
+			modm = stree_modm_new(mc_enum);
+			modm->u.enum_d = enum_d;
+
+			list_append(&parse->cur_mod->members, modm);
+			break;
+		default:
+			lunexpected_error(parse);
+			lex_next(parse->lex);
+			break;
+		}
+
+	}
+}
+
+/** Parse class, struct or interface declaration.
+ *
+ * @param parse		Parser object.
+ * @param dclass	What to parse: @c lc_class, @c lc_struct or @c lc_csi.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+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;
+	stree_ident_t *targ_name;
+	stree_targ_t *targ;
+
+	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);
+
+	list_init(&csi->targ);
+
+	while (lcur_lc(parse) == lc_slash) {
+		lskip(parse);
+		targ_name = parse_ident(parse);
+
+		targ = stree_targ_new();
+		targ->name = targ_name;
+
+		list_append(&csi->targ, targ);
+	}
+
+	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);
+		if (csimbr == NULL)
+			break;
+
+		list_append(&csi->members, csimbr);
+	}
+
+	lmatch(parse, lc_end);
+
+	return csi;
+}
+
+/** Parse class, struct or interface member.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration.
+ * @return		New syntax tree node. In case of parse error,
+ *			@c NULL may (but need not) be returned.
+ */
+static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_csimbr_t *csimbr;
+
+	stree_csi_t *csi;
+	stree_ctor_t *ctor;
+	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
+	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_new:
+		ctor = parse_ctor(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_ctor);
+		csimbr->u.ctor = ctor;
+		break;
+	case lc_deleg:
+		deleg = parse_deleg(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_deleg);
+		csimbr->u.deleg = deleg;
+		break;
+	case lc_enum:
+		enum_d = parse_enum(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_enum);
+		csimbr->u.enum_d = enum_d;
+		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);
+		csimbr = NULL;
+		break;
+	}
+
+	return csimbr;
+}
+
+/** Parse constructor.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_ctor_t *ctor;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
+
+	ctor = stree_ctor_new();
+	symbol = stree_symbol_new(sc_ctor);
+
+	symbol->u.ctor = ctor;
+	symbol->outer_csi = outer_csi;
+	ctor->symbol = symbol;
+
+	lmatch(parse, lc_new);
+
+	/* Fake identifier. */
+	ctor->name = stree_ident_new();
+	ctor->name->sid = strtab_get_sid(CTOR_IDENT);
+	ctor->name->cspan = lprev_span(parse);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing constructor of CSI '");
+	symbol_print_fqn(csi_to_symbol(outer_csi));
+	printf("'.\n");
+#endif
+	ctor->sig = parse_fun_sig(parse);
+	if (ctor->sig->rtype != NULL) {
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has a return type.\n");
+		parse_note_error(parse);
+	}
+
+	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);
+	}
+
+	ctor->proc = stree_proc_new();
+	ctor->proc->outer_symbol = symbol;
+
+	if (lcur_lc(parse) == lc_scolon) {
+		lskip(parse);
+
+		/* This constructor has no body. */
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has no body.\n");
+		parse_note_error(parse);
+
+		ctor->proc->body = NULL;
+	} else {
+		lmatch(parse, lc_is);
+		ctor->proc->body = parse_block(parse);
+		lmatch(parse, lc_end);
+	}
+
+	return ctor;
+}
+
+/** Parse @c enum declaration.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_enum_t *enum_d;
+	stree_symbol_t *symbol;
+	stree_embr_t *embr;
+
+	enum_d = stree_enum_new();
+	symbol = stree_symbol_new(sc_enum);
+
+	symbol->u.enum_d = enum_d;
+	symbol->outer_csi = outer_csi;
+	enum_d->symbol = symbol;
+
+	lmatch(parse, lc_enum);
+	enum_d->name = parse_ident(parse);
+	list_init(&enum_d->members);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse enum '%s'.\n", strtab_get_str(enum_d->name->sid));
+#endif
+	lmatch(parse, lc_is);
+
+	/* Parse enum members. */
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
+		embr = parse_embr(parse, enum_d);
+		if (embr == NULL)
+			break;
+
+		list_append(&enum_d->members, embr);
+	}
+
+	if (list_is_empty(&enum_d->members)) {
+		printf("Error: Enum type '%s' has no members.\n",
+		    strtab_get_str(enum_d->name->sid));
+		parse_note_error(parse);
+	}
+
+	lmatch(parse, lc_end);
+
+	return enum_d;
+}
+
+/** Parse enum member.
+ *
+ * @param parse		Parser object.
+ * @param outer_enum	Enum containing this declaration.
+ * @return		New syntax tree node. In case of parse error,
+ *			@c NULL may (but need not) be returned.
+ */
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum)
+{
+	stree_embr_t *embr;
+
+	embr = stree_embr_new();
+	embr->outer_enum = outer_enum;
+	embr->name = parse_ident(parse);
+
+	lmatch(parse, lc_scolon);
+
+	return embr;
+}
+
+/** Parse delegate.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_deleg_t *parse_deleg(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_deleg_t *deleg;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
+
+	deleg = stree_deleg_new();
+	symbol = stree_symbol_new(sc_deleg);
+
+	symbol->u.deleg = deleg;
+	symbol->outer_csi = outer_csi;
+	deleg->symbol = symbol;
+
+	lmatch(parse, lc_deleg);
+	deleg->name = parse_ident(parse);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing delegate '%s'.\n", strtab_get_str(deleg->name->sid));
+#endif
+
+	deleg->sig = parse_fun_sig(parse);
+
+	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);
+	}
+
+	lmatch(parse, lc_scolon);
+
+	return deleg;
+}
+
+/** Parse member function.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_fun_t *fun;
+	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);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
+#endif
+	fun->sig = parse_fun_sig(parse);
+
+	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.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse procedure argument.\n");
+#endif
+ 	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);
+	}
+
+	return arg;
+}
+
+/** Parse argument attribute.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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 function signature.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_fun_sig_t *parse_fun_sig(parse_t *parse)
+{
+	stree_fun_sig_t *sig;
+	stree_proc_arg_t *arg;
+
+	sig = stree_fun_sig_new();
+
+	lmatch(parse, lc_lparen);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing function signature.\n");
+#endif
+
+	list_init(&sig->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)) {
+				sig->varg = arg;
+				break;
+			} else {
+				list_append(&sig->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);
+		sig->rtype = parse_texpr(parse);
+	} else {
+		sig->rtype = NULL;
+	}
+
+	return sig;
+}
+
+/** Parse statement block.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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_break_t *break_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_break:
+		break_s = parse_break(parse);
+		stat = stree_stat_new(st_break);
+		stat->u.break_s = break_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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_if_t *parse_if(parse_t *parse)
+{
+	stree_if_t *if_s;
+	stree_if_clause_t *if_c;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'if' statement.\n");
+#endif
+	if_s = stree_if_new();
+	list_init(&if_s->if_clauses);
+
+	/* Parse @c if clause. */
+	lmatch(parse, lc_if);
+
+	if_c = stree_if_clause_new();
+	if_c->cond = parse_expr(parse);
+	lmatch(parse, lc_then);
+	if_c->block = parse_block(parse);
+
+	list_append(&if_s->if_clauses, if_c);
+
+	/* Parse @c elif clauses. */
+	while (lcur_lc(parse) == lc_elif) {
+		lskip(parse);
+		if_c = stree_if_clause_new();
+		if_c->cond = parse_expr(parse);
+		lmatch(parse, lc_then);
+		if_c->block = parse_block(parse);
+
+		list_append(&if_s->if_clauses, if_c);
+	}
+
+	/* Parse @c else clause. */
+	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.
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ */
+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 break statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_break_t *parse_break(parse_t *parse)
+{
+	stree_break_t *break_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'break' statement.\n");
+#endif
+	break_s = stree_break_new();
+
+	lmatch(parse, lc_break);
+	lmatch(parse, lc_scolon);
+
+	return break_s;
+}
+
+/** Parse @c return statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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);
+
+	if (lcur_lc(parse) != lc_scolon)
+		return_s->expr = parse_expr(parse);
+
+	lmatch(parse, lc_scolon);
+
+	return return_s;
+}
+
+/* Parse @c with-except-finally statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+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;
+	ident->cspan = lcur_span(parse);
+	lskip(parse);
+
+	return ident;
+}
+
+/** Signal a parse error, start bailing out from parser. 
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * @param parse		Parser object.
+ * @return		Pointer to current lem. Only valid until the lexing
+ *			position is advanced.
+ */
+lem_t *lcur(parse_t *parse)
+{
+#ifdef DEBUG_LPARSE_TRACE
+	printf("lcur()\n");
+#endif
+	return lex_get_current(parse->lex);
+}
+
+/** Return current lem lclass.
+ *
+ * @param parse		Parser object
+ * @return		Lclass of the current lem
+ */
+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;
+}
+
+/** Return coordinate span of current lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of current lem or @c NULL if a
+ *			parse error is active
+ */
+cspan_t *lcur_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lcur(parse);
+	return lem->cspan;
+}
+
+/** Return coordinate span of previous lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of previous lem or @c NULL if
+ * 			parse error is active or previous lem is not
+ *			available.
+ */
+cspan_t *lprev_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lex_peek_prev(parse->lex);
+	if (lem == NULL)
+		return NULL;
+
+	return lem->cspan;
+}
+
+/** Skip to next lem.
+ *
+ * @param parse		Parser object.
+ */
+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.
+ *
+ * If a lem of different lclass is found, a parse error is raised and
+ * a message is printed.
+ *
+ * @param parse		Parser object.
+ * @param lc		Expected lclass.
+ */
+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.
+ *
+ * If a lem of different lclass is found, a parse error is raised and
+ * a message is printed.
+ *
+ * @param parse		Parser object.
+ * @param lc		Expected lclass.
+ */
+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);
+}
+
+/** Raise and display generic parsing error.
+ *
+ * @param parse		Parser object.
+ */
+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);
+}
+
+/** Determine whether @a lclass is in follow(block).
+ *
+ * Tests whether @a lclass belongs to the follow(block) set, i.e. if it is
+ * lclass of a lem that can follow a block in the program.
+ *
+ * @param lclass	Lclass.
+ */
+bool_t terminates_block(lclass_t lclass)
+{
+	switch (lclass) {
+	case lc_elif:
+	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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/parse.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 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);
+cspan_t *lcur_span(parse_t *parse);
+cspan_t *lprev_span(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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/parse_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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/program.c
===================================================================
--- uspace/app/sbi/src/program.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/program.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,150 @@
+/*
+ * 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 "os/os.h"
+#include "mytypes.h"
+#include "stype.h"
+#include "input.h"
+#include "lex.h"
+#include "parse.h"
+
+#include "program.h"
+
+#define MAX_NAME_SIZE 64
+static char name_buf[MAX_NAME_SIZE + 1];
+
+/** Process one specified source file.
+ *
+ * @param program 	The program to which the parsed code is added.
+ * @param fname		Name of file to read from.
+ * @return		EOK on success, EIO if file is not found,
+ *			EINVAL if file has syntax errors.
+ */
+int program_file_process(stree_program_t *program, const char *fname)
+{
+	input_t *input;
+	lex_t lex;
+	parse_t parse;
+	int rc;
+
+	rc = input_new_file(&input, fname);
+	if (rc != EOK) {
+		printf("Failed opening source file '%s'.\n", fname);
+		return EIO;
+	}
+
+	/* Parse input file. */
+	lex_init(&lex, input);
+	parse_init(&parse, program, &lex);
+	parse_module(&parse);
+
+	/* Check for parse errors. */
+	if (parse.error)
+		return EINVAL;
+
+	return EOK;
+}
+
+/** Process sources of the library. 
+ *
+ * Processes all source files in the library. The list of library source files
+ * is read from '<libdir>/libflist'. Each line of the file contains one file
+ * name relative to <libdir>.
+ */
+int program_lib_process(stree_program_t *program)
+{
+	int rc;
+	char *path, *fname;
+	char *tmp;
+	char *cp;
+
+	FILE *f;
+
+	path = os_get_lib_path();
+	fname = os_str_acat(path, "/libflist");
+
+	f = fopen(fname, "rt");
+	if (f == NULL) {
+		printf("Failed opening library list file '%s'.\n", fname);
+		free(path);
+		free(fname);
+		return EIO;
+	}
+
+	free(fname);
+
+	while (b_true) {
+		if (fgets(name_buf, MAX_NAME_SIZE + 1, f) == NULL)
+			break;
+
+		/*
+		 * Remove trailing newline, if present.
+		 */
+		cp = name_buf;
+		while (*cp != '\0' && *cp != '\n')
+			++cp;
+
+		if (*cp == '\n')
+			*cp = '\0';
+
+		tmp = os_str_acat(path, "/");
+		fname = os_str_acat(tmp, name_buf);
+		free(tmp);
+
+		rc = program_file_process(program, fname);
+		if (rc != EOK) {
+			free(fname);
+			free(path);
+			fclose(f);
+			return rc;
+		}
+
+		free(fname);
+	}
+
+	if (ferror(f)) {
+		printf("Error reading from library list file.\n");
+		free(path);
+		fclose(f);
+		return EIO;
+	}
+
+	free(path);
+	fclose(f);
+
+	return rc;
+}
Index: uspace/app/sbi/src/program.h
===================================================================
--- uspace/app/sbi/src/program.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/program.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 PROGRAM_H_
+#define PROGRAM_H_
+
+#include "mytypes.h"
+
+int program_file_process(stree_program_t *program, const char *fname);
+int program_lib_process(stree_program_t *program);
+
+#endif
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/rdata.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,826 @@
+/*
+ * 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.
+ *
+ * At run time SBI represents all data as a graph of interconnected @c var
+ * nodes (variable nodes). Any piece of memory addressable by the program
+ * (i.e. all variables) are stored in var nodes. However, var nodes are also
+ * used internally to implement value items. (I.e. values in value items
+ * have exactly the same structure as program variables).
+ *
+ * Unlike byte- or word-oriented memory on a real machine, var nodes provide
+ * structured and typed storage. (This typing is dynamic, however and has
+ * nothing to do with the static type system).
+ *
+ * There are several types of var nodes, one for each primitive type,
+ * reference, delegate, array, and object. A reference var node contains
+ * a pointer to another var node. Delegate var node points to some stree
+ * declaration. Array and object var nodes refer to a collection of child
+ * nodes (fields, elements).
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "bigint.h"
+#include "mytypes.h"
+#include "stree.h"
+#include "symbol.h"
+#include "strtab.h"
+
+#include "rdata.h"
+
+static void rdata_bool_copy(rdata_bool_t *src, rdata_bool_t **dest);
+static void rdata_char_copy(rdata_char_t *src, rdata_char_t **dest);
+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_enum_copy(rdata_enum_t *src, rdata_enum_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 void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_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);
+
+/** Allocate new data item.
+ *
+ * @param ic	Item class.
+ * @return	New item.
+ */
+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;
+}
+
+/** Allocate new address.
+ *
+ * @return	New address.
+ */
+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;
+}
+
+/** Allocate new named property address.
+ *
+ * @return	New named property address.
+ */
+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;
+}
+
+/** Allocate new indexed property address.
+ *
+ * @return	New indexed property address.
+ */
+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;
+}
+
+/** Allocate new property address.
+ *
+ * @param apc	Property address class.
+ * @return	New property address.
+ */
+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;
+}
+
+/** Allocate new address.
+ *
+ * @param ac	Address class.
+ * @return	New address.
+ */
+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;
+}
+
+/** Allocate new value.
+ *
+ * @return	New value.
+ */
+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;
+}
+
+/** Allocate new var node.
+ *
+ * @param vc	Var node class (varclass).
+ * @return	New var node.
+ */
+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;
+}
+
+/** Allocate new reference.
+ *
+ * @return	New reference.
+ */
+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;
+}
+
+/** Allocate new delegate.
+ *
+ * @return	New delegate.
+ */
+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;
+}
+
+/** Allocate new enum value.
+ *
+ * @return	New enum value.
+ */
+rdata_enum_t *rdata_enum_new(void)
+{
+	rdata_enum_t *enum_v;
+
+	enum_v = calloc(1, sizeof(rdata_enum_t));
+	if (enum_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return enum_v;
+}
+
+/** Allocate new array.
+ *
+ * @return	New array.
+ */
+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;
+}
+
+/** Allocate new object.
+ *
+ * @return	New object.
+ */
+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;
+}
+
+/** Allocate new boolean.
+ *
+ * @return	New boolean.
+ */
+rdata_bool_t *rdata_bool_new(void)
+{
+	rdata_bool_t *bool_v;
+
+	bool_v = calloc(1, sizeof(rdata_bool_t));
+	if (bool_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return bool_v;
+}
+
+/** Allocate new character.
+ *
+ * @return	New character.
+ */
+rdata_char_t *rdata_char_new(void)
+{
+	rdata_char_t *char_v;
+
+	char_v = calloc(1, sizeof(rdata_char_t));
+	if (char_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return char_v;
+}
+
+/** Allocate new integer.
+ *
+ * @return	New integer.
+ */
+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;
+}
+
+/** Allocate new string.
+ *
+ * @return	New string.
+ */
+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;
+}
+
+/** Allocate new resource.
+ *
+ * @return	New resource.
+ */
+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;
+}
+
+/** Allocate new symbol reference.
+ *
+ * @return	New symbol reference.
+ */
+rdata_symbol_t *rdata_symbol_new(void)
+{
+	rdata_symbol_t *symbol_v;
+
+	symbol_v = calloc(1, sizeof(rdata_symbol_t));
+	if (symbol_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return symbol_v;
+}
+
+/** Allocate array elements.
+ *
+ * Allocates var nodes for elements of @a array.
+ *
+ * @param array		Array.
+ */
+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.
+ *
+ * @param array		Array.
+ */
+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.
+ *
+ * Creates a new var node that is an exact copy of an existing var node.
+ * This can be thought of as a shallow copy.
+ *
+ * @param src		Source var node.
+ * @param dest		Place to store pointer to new var node.
+ */
+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_bool:
+		rdata_bool_copy(src->u.bool_v, &nvar->u.bool_v);
+		break;
+	case vc_char:
+		rdata_char_copy(src->u.char_v, &nvar->u.char_v);
+		break;
+	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_enum:
+		rdata_enum_copy(src->u.enum_v, &nvar->u.enum_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;
+	case vc_symbol:
+		rdata_symbol_copy(src->u.symbol_v, &nvar->u.symbol_v);
+		break;
+	}
+
+	*dest = nvar;
+}
+
+/** Copy boolean.
+ *
+ * @param src		Source boolean.
+ * @param dest		Place to store pointer to new boolean.
+ */
+static void rdata_bool_copy(rdata_bool_t *src, rdata_bool_t **dest)
+{
+	*dest = rdata_bool_new();
+	(*dest)->value = src->value;
+}
+
+/** Copy character.
+ *
+ * @param src		Source character.
+ * @param dest		Place to store pointer to new character.
+ */
+static void rdata_char_copy(rdata_char_t *src, rdata_char_t **dest)
+{
+	*dest = rdata_char_new();
+	bigint_clone(&src->value, &(*dest)->value);
+}
+
+/** Copy integer.
+ *
+ * @param src		Source integer.
+ * @param dest		Place to store pointer to new integer.
+ */
+static void rdata_int_copy(rdata_int_t *src, rdata_int_t **dest)
+{
+	*dest = rdata_int_new();
+	bigint_clone(&src->value, &(*dest)->value);
+}
+
+/** Copy string.
+ *
+ * @param src		Source string.
+ * @param dest		Place to store pointer to new string.
+ */
+static void rdata_string_copy(rdata_string_t *src, rdata_string_t **dest)
+{
+	*dest = rdata_string_new();
+	(*dest)->value = src->value;
+}
+
+/** Copy reference.
+ *
+ * @param src		Source reference.
+ * @param dest		Place to store pointer to new reference.
+ */
+static void rdata_ref_copy(rdata_ref_t *src, rdata_ref_t **dest)
+{
+	*dest = rdata_ref_new();
+	(*dest)->vref = src->vref;
+}
+
+/** Copy delegate.
+ *
+ * @param src		Source delegate.
+ * @param dest		Place to store pointer to new delegate.
+ */
+static void rdata_deleg_copy(rdata_deleg_t *src, rdata_deleg_t **dest)
+{
+	*dest = rdata_deleg_new();
+	(*dest)->obj = src->obj;
+	(*dest)->sym = src->sym;
+}
+
+/** Copy enum value.
+ *
+ * @param src		Source enum value.
+ * @param dest		Place to store pointer to new enum value.
+ */
+static void rdata_enum_copy(rdata_enum_t *src, rdata_enum_t **dest)
+{
+	*dest = rdata_enum_new();
+	(*dest)->value = src->value;
+}
+
+/** Copy array.
+ *
+ * @param src		Source array.
+ * @param dest		Place to store pointer to new array.
+ */
+static void rdata_array_copy(rdata_array_t *src, rdata_array_t **dest)
+{
+	(void) src; (void) dest;
+	printf("Unimplemented: Copy array.\n");
+	exit(1);
+}
+
+/** Copy object.
+ *
+ * @param src		Source object.
+ * @param dest		Place to store pointer to new object.
+ */
+static void rdata_object_copy(rdata_object_t *src, rdata_object_t **dest)
+{
+	(void) src; (void) dest;
+	printf("Unimplemented: Copy object.\n");
+	exit(1);
+}
+
+/** Copy resource.
+ *
+ * @param src		Source resource.
+ * @param dest		Place to store pointer to new resource.
+ */
+static void rdata_resource_copy(rdata_resource_t *src, rdata_resource_t **dest)
+{
+	*dest = rdata_resource_new();
+	(*dest)->data = src->data;
+}
+
+/** Copy symbol.
+ *
+ * @param src		Source symbol.
+ * @param dest		Place to store pointer to new symbol.
+ */
+static void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_t **dest)
+{
+	*dest = rdata_symbol_new();
+	(*dest)->sym = src->sym;
+}
+
+/** Read data from a variable.
+ *
+ * This copies data from the variable to a value item. Ideally any read access
+ * to a program variable should go through this function. (Keep in mind
+ * that although values are composed of var nodes internally, but are not
+ * variables per se. Therefore this function is not used to read from values)
+ *
+ * @param var		Variable to read from (var node where it is stored).
+ * @param ritem		Place to store pointer to new value item read from
+ *			the variable.
+ */
+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.
+ *
+ * This copies data to the variable from a value. Ideally any write access
+ * to a program variable should go through this function. (Keep in mind
+ * that even though values are composed of var nodes internally, but are not
+ * variables per se. Therefore this function is not used to write to values)
+ *
+ * @param var		Variable to write to (var node where it is stored).
+ * @param value		The value to write.
+ */
+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_bool: var->u.bool_v = nvar->u.bool_v; break;
+	case vc_char: var->u.char_v = nvar->u.char_v; break;
+	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_enum: var->u.enum_v = nvar->u.enum_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;
+	case vc_symbol: var->u.symbol_v = nvar->u.symbol_v; break;
+	}
+
+	/* XXX We should free some stuff around here. */
+}
+
+/** Print data item in human-readable form.
+ *
+ * @param item		Item to print.
+ */
+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;
+	}
+}
+
+/** Print address in human-readable form.
+ *
+ * Actually this displays contents of the var node that is being addressed.
+ *
+ * XXX Maybe we should really rather print the address and not the data
+ * it is pointing to?
+ *
+ * @param item		Address to print.
+ */
+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;
+	}
+}
+
+/** Print value in human-readable form.
+ *
+ * @param value		Value to print.
+ */
+void rdata_value_print(rdata_value_t *value)
+{
+	rdata_var_print(value->var);
+}
+
+/** Print contents of var node in human-readable form.
+ *
+ * @param item		Var node to print.
+ */
+static void rdata_var_print(rdata_var_t *var)
+{
+	int val;
+
+	switch (var->vc) {
+	case vc_bool:
+		printf("bool(%s)", var->u.bool_v->value ? "true" : "false");
+		break;
+	case vc_char:
+		printf("char(");
+		if (bigint_get_value_int(&var->u.char_v->value, &val) == EOK)
+			printf("'%c'", val);
+		else
+			printf("???:x%x\n", (unsigned) val);
+		printf(")");
+		break;
+	case vc_int:
+		printf("int(");
+		bigint_print(&var->u.int_v->value);
+		printf(")");
+		break;
+	case vc_string:
+		printf("string(\"%s\")", var->u.string_v->value);
+		break;
+	case vc_ref:
+		if (var->u.ref_v->vref != NULL) {
+			printf("ref(");
+			rdata_var_print(var->u.ref_v->vref);
+			printf(")");
+		} else {
+			printf("nil");
+		}
+		break;
+	case vc_deleg:
+		printf("deleg(");
+		if (var->u.deleg_v->sym != NULL) {
+			if (var->u.deleg_v->obj != NULL) {
+				rdata_var_print(var->u.deleg_v->obj);
+				printf(",");
+			}
+			symbol_print_fqn(var->u.deleg_v->sym);
+		} else {
+			printf("nil");
+		}
+		printf(")");
+		break;
+	case vc_enum:
+		symbol_print_fqn(
+		    enum_to_symbol(var->u.enum_v->value->outer_enum));
+		printf(".%s",
+		    strtab_get_str(var->u.enum_v->value->name->sid));
+		break;
+	case vc_array:
+		printf("array");
+		break;
+	case vc_object:
+		printf("object");
+		break;
+	case vc_resource:
+		printf("resource(%p)", var->u.resource_v->data);
+		break;
+	case vc_symbol:
+		printf("symbol(");
+		if (var->u.symbol_v->sym != NULL) {
+			symbol_print_fqn(var->u.symbol_v->sym);
+		} else {
+			printf("nil");
+		}
+		printf(")");
+		break;
+	}
+}
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/rdata.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,64 @@
+/*
+ * 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_enum_t *rdata_enum_new(void);
+rdata_array_t *rdata_array_new(int rank);
+rdata_object_t *rdata_object_new(void);
+rdata_bool_t *rdata_bool_new(void);
+rdata_char_t *rdata_char_new(void);
+rdata_int_t *rdata_int_new(void);
+rdata_string_t *rdata_string_new(void);
+rdata_resource_t *rdata_resource_new(void);
+rdata_symbol_t *rdata_symbol_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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/rdata_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,300 @@
+/*
+ * 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"
+
+/** Boolean variable. */
+typedef struct {
+	bool_t value;
+} rdata_bool_t;
+
+/** Character variable.
+ *
+ * Sysel character type should be able to store arbitrarily (or at least
+ * very) large character sets.
+ */
+typedef struct {
+	bigint_t value;
+} rdata_char_t;
+
+/** Integer variable.
+ *
+ * Sysel int type should be able to store arbitrarily (or at least
+ * very) large numbers.
+ */
+typedef struct {
+	bigint_t value;
+} rdata_int_t;
+
+/** String variable */
+typedef struct {
+	const 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;
+
+/** Enumerated type value. */
+typedef struct {
+	/** Enum member declaration */
+	struct stree_embr *value;
+} rdata_enum_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;
+
+/** Symbol reference variable
+ *
+ * A symbol reference points to a program symbol.
+ */
+typedef struct {
+	/** Program symbol. */
+	struct stree_symbol *sym;
+} rdata_symbol_t;
+
+typedef enum var_class {
+	/** Boolean */
+	vc_bool,
+
+	/** Character **/
+	vc_char,
+
+	/** Integer */
+	vc_int,
+
+	/** String */
+	vc_string,
+
+	/** Reference */
+	vc_ref,
+
+	/** Delegate */
+	vc_deleg,
+
+	/** Enumerated type value */
+	vc_enum,
+
+	/** Array */
+	vc_array,
+
+	/** Object */
+	vc_object,
+
+	/** Interpreter builtin resource */
+	vc_resource,
+
+	/** Symbol reference */
+	vc_symbol
+} 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_bool_t *bool_v;
+		rdata_char_t *char_v;
+		rdata_int_t *int_v;
+		rdata_string_t *string_v;
+		rdata_ref_t *ref_v;
+		rdata_deleg_t *deleg_v;
+		rdata_enum_t *enum_v;
+		rdata_array_t *array_v;
+		rdata_object_t *object_v;
+		rdata_resource_t *resource_v;
+		rdata_symbol_t *symbol_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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1755 @@
+/*
+ * 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 "bigint.h"
+#include "builtin.h"
+#include "cspan.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_break(run_t *run, stree_break_t *break_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 stree_csi_t *run_exc_payload_get_csi(run_t *run);
+
+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);
+
+static void run_var_new_tprimitive(run_t *run, tdata_primitive_t *tprimitive,
+    rdata_var_t **rvar);
+static void run_var_new_null_ref(run_t *run, rdata_var_t **rvar);
+static void run_var_new_deleg(run_t *run, rdata_var_t **rvar);
+static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
+    rdata_var_t **rvar);
+
+/** Initialize runner instance.
+ *
+ * @param run		Runner object
+ */
+void run_init(run_t *run)
+{
+	(void) run;
+}
+
+/** Run program.
+ *
+ * Associates the program @a prog with the runner object and executes
+ * it. If a run-time error occurs during the execution (e.g. an unhandled
+ * exception), @a run->error will be set to @c b_true when this function
+ * returns.
+ *
+ * @param run		Runner object
+ * @param prog		Program to run
+ */
+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);
+
+	run_exc_check_unhandled(run);
+}
+
+/** Run procedure.
+ *
+ * Inserts the provided procedure AR @a proc_ar on the execution stack
+ * (in the thread AR) and executes the procedure. The return value
+ * of the procedure is stored to *(@a res). @c NULL is stored if the
+ * procedure returns no value.
+ *
+ * If the procedure execution bails out due to an exception, this
+ * can be determined by looking at @c bo_mode in thread AR. Also,
+ * in this case @c NULL is stored into *(@a res).
+ *
+ * @param run		Runner object
+ * @param proc_ar	Procedure activation record
+ * @param res		Place to store procedure return value
+ */
+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:
+		/* Break bailout was not caught. */
+		assert(b_false);
+	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.
+ *
+ * @param run		Runner object
+ * @param block		Block to run
+ */
+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_break:
+		run_break(run, stat->u.break_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;
+	}
+}
+
+/** 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.
+ *
+ * @param run	Runner object
+ * @param vdecl	Variable declaration statement to run
+ */
+static void run_vdecl(run_t *run, stree_vdecl_t *vdecl)
+{
+	run_block_ar_t *block_ar;
+	rdata_var_t *var, *old_var;
+	tdata_item_t *var_ti;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing variable declaration statement.\n");
+#endif
+	/* Compute variable type. XXX Memoize. */
+	run_texpr(run->program, run_get_current_csi(run), vdecl->type,
+	    &var_ti);
+
+	/* Create variable and initialize with default value. */
+	run_var_new(run, var_ti, &var);
+
+	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.
+ *
+ * @param run	Runner object
+ * @param if_s	If statement to run
+ */
+static void run_if(run_t *run, stree_if_t *if_s)
+{
+	rdata_item_t *rcond;
+	list_node_t *ifc_node;
+	stree_if_clause_t *ifc;
+	bool_t clause_fired;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing if statement.\n");
+#endif
+	clause_fired = b_false;
+	ifc_node = list_first(&if_s->if_clauses);
+
+	/* Walk through all if/elif clauses and see if they fire. */
+
+	while (ifc_node != NULL) {
+		/* Get if/elif clause */
+		ifc = list_node_data(ifc_node, stree_if_clause_t *);
+
+		run_expr(run, ifc->cond, &rcond);
+		if (run_is_bo(run))
+			return;
+
+		if (run_item_boolean_value(run, rcond) == b_true) {
+#ifdef DEBUG_RUN_TRACE
+			printf("Taking non-default path.\n");
+#endif
+			run_block(run, ifc->block);
+			clause_fired = b_true;
+			break;
+		}
+
+		ifc_node = list_next(&if_s->if_clauses, ifc_node);
+	}
+
+	/* If no if/elif clause fired, invoke the else clause. */
+	if (clause_fired == b_false && if_s->else_block != NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking default path.\n");
+#endif
+		run_block(run, if_s->else_block);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("If statement terminated.\n");
+#endif
+}
+
+/** Run @c while statement.
+ *
+ * @param run		Runner object
+ * @param while_s	While statement to run
+ */
+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);
+	if (run_is_bo(run))
+		return;
+
+	while (run_item_boolean_value(run, rcond) == b_true) {
+		run_block(run, while_s->body);
+		run_expr(run, while_s->cond, &rcond);
+		if (run_is_bo(run))
+			break;
+	}
+
+	if (run->thread_ar->bo_mode == bm_stat) {
+		/* Bailout due to break statement */
+		run->thread_ar->bo_mode = bm_none;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("While statement terminated.\n");
+#endif
+}
+
+/** Run @c raise statement.
+ *
+ * @param run		Runner object
+ * @param raise_s	Raise statement to run
+ */
+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);
+	if (run_is_bo(run))
+		return;
+
+	run_cvt_value_item(run, rexpr, &rexpr_vi);
+
+	/* Store expression cspan in thread AR. */
+	run->thread_ar->exc_cspan = raise_s->expr->cspan;
+
+	/* 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 break statement.
+ *
+ * Forces control to return from the active breakable statement by setting
+ * bailout mode to @c bm_stat.
+ *
+ * @param run		Runner object
+ * @param break_s	Break statement to run
+ */
+static void run_break(run_t *run, stree_break_t *break_s)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing 'break' statement.\n");
+#endif
+	(void) break_s;
+
+	/* Force control to ascend and leave the procedure. */
+	if (run->thread_ar->bo_mode == bm_none)
+		run->thread_ar->bo_mode = bm_stat;
+}
+
+/** Run @c return statement.
+ *
+ * Sets the return value in procedure AR and forces control to return
+ * from the function by setting bailout mode to @c bm_proc.
+ *
+ * @param run		Runner object
+ * @param return_s	Return statement to run
+ */
+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
+	if (return_s->expr != NULL) {
+		run_expr(run, return_s->expr, &rexpr);
+		if (run_is_bo(run))
+			return;
+
+		run_cvt_value_item(run, rexpr, &rexpr_vi);
+
+		/* Store expression result in procedure 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.
+ *
+ * Note: 'With' clause is not implemented.
+ *
+ * @param run		Runner object
+ * @param wef_s		With-except-finally statement to run
+ */
+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.
+ *
+ * @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)
+{
+	stree_csi_t *exc_csi;
+	tdata_item_t *etype;
+
+	/* Get CSI of active exception. */
+	exc_csi = run_exc_payload_get_csi(run);
+
+	/* Evaluate type expression in except clause. */
+	run_texpr(run->program, run_get_current_csi(run), except_c->etype,
+	    &etype);
+
+	/* Determine if active exc. is derived from type in exc. clause. */
+	/* XXX This is wrong, it does not work with generics. */
+	return tdata_is_csi_derived_from_ti(exc_csi, etype);
+}
+
+/** Return CSI of the active exception.
+ *
+ * @param run		Runner object
+ * @return		CSI of the active exception
+ */
+static stree_csi_t *run_exc_payload_get_csi(run_t *run)
+{
+	rdata_value_t *payload;
+	rdata_var_t *payload_v;
+	rdata_object_t *payload_o;
+
+	payload = run->thread_ar->exc_payload;
+	assert(payload != NULL);
+
+	if (payload->var->vc != vc_ref) {
+		/* XXX Prevent this via static type checking. */
+		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) {
+		/* XXX Prevent this via static type checking. */
+		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);
+
+	return payload_o->class_sym->u.csi;
+}
+
+
+/** Check for unhandled exception.
+ *
+ * Checks whether there is an active exception. If so, it prints an
+ * error message and raises a run-time error.
+ *
+ * @param run		Runner object
+ */
+void run_exc_check_unhandled(run_t *run)
+{
+	stree_csi_t *exc_csi;
+
+	if (run->thread_ar->bo_mode != bm_none) {
+		assert(run->thread_ar->bo_mode == bm_exc);
+
+		exc_csi = run_exc_payload_get_csi(run);
+
+		if (run->thread_ar->exc_cspan != NULL) {
+			cspan_print(run->thread_ar->exc_cspan);
+			putchar(' ');
+		}
+
+		printf("Error: Unhandled exception '");
+		symbol_print_fqn(csi_to_symbol(exc_csi));
+		printf("'.\n");
+
+		run_raise_error(run);
+	}
+}
+
+/** Raise an irrecoverable run-time error, start bailing out.
+ *
+ * Raises an error that cannot be handled by the user program.
+ *
+ * @param run		Runner object
+ */
+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.
+ *
+ * @param run		Runner object
+ */
+rdata_item_t *run_recovery_item(run_t *run)
+{
+	(void) run;
+	return NULL;
+}
+
+/** Find a local variable in the currently active function.
+ *
+ * @param run		Runner object
+ * @param name		Name SID of the local variable
+ * @return		Pointer to var node or @c NULL if not found
+ */
+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 procedure activation record.
+ *
+ * @param run		Runner object
+ * @return		Active procedure AR
+ */
+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.
+ *
+ * @param run		Runner object
+ * @return		Active block AR
+ */
+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.
+ *
+ * @param run		Runner object
+ * @return		Active 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.
+ *
+ * @param item		Value item (initial value for variable).
+ * @param var		Place to store new var node.
+ */
+void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var)
+{
+	rdata_bool_t *bool_v;
+	rdata_char_t *char_v;
+	rdata_deleg_t *deleg_v;
+	rdata_enum_t *enum_v;
+	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_bool:
+		*var = rdata_var_new(vc_bool);
+		bool_v = rdata_bool_new();
+
+		(*var)->u.bool_v = bool_v;
+		bool_v->value = item->u.value->var->u.bool_v->value;
+		break;
+	case vc_char:
+		*var = rdata_var_new(vc_char);
+		char_v = rdata_char_new();
+
+		(*var)->u.char_v = char_v;
+		bigint_clone(&item->u.value->var->u.char_v->value,
+		    &char_v->value);
+		break;
+	case vc_deleg:
+		*var = rdata_var_new(vc_deleg);
+		deleg_v = rdata_deleg_new();
+
+		(*var)->u.deleg_v = deleg_v;
+		deleg_v->obj = item->u.value->var->u.deleg_v->obj;
+		deleg_v->sym = item->u.value->var->u.deleg_v->sym;
+		break;
+	case vc_enum:
+		*var = rdata_var_new(vc_enum);
+		enum_v = rdata_enum_new();
+
+		(*var)->u.enum_v = enum_v;
+		enum_v->value = item->u.value->var->u.enum_v->value;
+		break;
+	case vc_int:
+		*var = rdata_var_new(vc_int);
+		int_v = rdata_int_new();
+
+		(*var)->u.int_v = int_v;
+		bigint_clone(&item->u.value->var->u.int_v->value,
+		    &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 procedure AR.
+ *
+ * @param run		Runner object
+ * @param obj		Object whose procedure is being activated
+ * @param proc		Procedure that is being activated
+ * @param rproc_ar	Place to store pointer to new activation record
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Existing procedure activation record where to store
+ *			the values
+ * @param arg_vals	List of value items (rdata_item_t *) -- real
+ *			argument values
+ */
+void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar, list_t *arg_vals)
+{
+	stree_ctor_t *ctor;
+	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;
+
+	/* Make compiler happy. */
+	args = NULL;
+	varg = NULL;
+
+	/*
+	 * The procedure being activated should belong to a member function or
+	 * property getter/setter.
+	 */
+	switch (outer_symbol->sc) {
+	case sc_ctor:
+		ctor = symbol_to_ctor(outer_symbol);
+		args = &ctor->sig->args;
+		varg = ctor->sig->varg;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(outer_symbol);
+		args = &fun->sig->args;
+		varg = fun->sig->varg;
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_symbol);
+		args = &prop->args;
+		varg = prop->varg;
+		break;
+	case sc_csi:
+	case sc_deleg:
+	case sc_enum:
+	case sc_var:
+		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.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Existing procedure activation record where to store
+ *			the setter argument
+ * @param arg_val	Value items (rdata_item_t *) -- real argument value
+ */
+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.
+ *
+ * Prints a backtrace of activated functions for debugging purposes.
+ *
+ * @param run		Runner object
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param item		Input item (value or address)
+ * @param ritem		Place to store pointer to new value item
+ */
+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).
+ *
+ * @param run		Runner object
+ * @param item		Value or address item
+ * @return		Varclass of @a item
+ */
+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
+ * @return	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.
+ *
+ * Read value from the specified address.
+ *
+ * @param run		Runner object
+ * @param address	Address to read
+ * @param ritem		Place to store pointer to the value that was read
+ */
+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 value @a value at address @a address.
+ *
+ * @param run		Runner object
+ * @param address	Address to write
+ * @param value		Value to store at the 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;
+	}
+}
+
+/** Read data from a property address.
+ *
+ * This involves invoking the property getter procedure.
+ *
+ * @param run		Runner object.
+ * @param addr_prop	Property address to read.
+ * @param ritem		Place to store pointer to the value that was read.
+ */
+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
+}
+
+/** Write data to a property address.
+ *
+ * This involves invoking the property setter procedure.
+ *
+ * @param run		Runner object
+ * @param addr_prop	Property address to write
+ * @param value		Value to store at the address
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param var		Variable node that is being referenced
+ * @param res		Place to store pointer to new reference.
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param ref		Reference
+ * @param cspan		Cspan to put into exception if reference is nil
+ *			or @c NULL if no cspan is provided.
+ * @param rtitem	Place to store pointer to the resulting address.
+ */
+void run_dereference(run_t *run, rdata_item_t *ref, cspan_t *cspan,
+    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) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Error: Accessing null reference.\n");
+#endif
+		/* Raise Error.NilReference */
+		run_raise_exc(run, run->program->builtin->error_nilreference,
+		    cspan);
+		*ritem = run_recovery_item(run);
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("vref set to %p\n", addr_var->vref);
+#endif
+	*ritem = item;
+}
+
+/** Raise an exception of the given class.
+ *
+ * Used when the interpreter generates an exception due to a run-time
+ * error (not for the @c raise statement).
+ *
+ * @param run		Runner object
+ * @param csi		Exception class
+ * @param cspan		Cspan of code that caused exception (for debugging)
+ */
+void run_raise_exc(run_t *run, stree_csi_t *csi, cspan_t *cspan)
+{
+	rdata_item_t *exc_vi;
+
+	/* Store exception cspan in thread AR. */
+	run->thread_ar->exc_cspan = cspan;
+
+	/* Create exception object. */
+	run_new_csi_inst(run, csi, &exc_vi);
+	assert(exc_vi->ic == ic_value);
+
+	/* Store exception object in thread AR. */
+	run->thread_ar->exc_payload = exc_vi->u.value;
+
+	/* Start exception bailout. */
+	run->thread_ar->bo_mode = bm_exc;
+}
+
+/** Determine if we are bailing out.
+ *
+ * @param run		Runner object
+ * @return		@c b_true if we are bailing out, @c b_false otherwise
+ */
+bool_t run_is_bo(run_t *run)
+{
+	return run->thread_ar->bo_mode != bm_none;
+}
+
+/** Construct a new variable of the given type.
+ *
+ * The variable is allocated and initialized with a default value
+ * based on type item @a ti. For reference types the default value
+ * is a null reference. At this point this does not work for generic
+ * types (we need RTTI).
+ *
+ * @param run		Runner object
+ * @param ti		Type of variable to create (type item)
+ * @param rvar		Place to store pointer to new variable
+ */
+void run_var_new(run_t *run, tdata_item_t *ti, rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+
+	switch (ti->tic) {
+	case tic_tprimitive:
+		run_var_new_tprimitive(run, ti->u.tprimitive, rvar);
+		break;
+	case tic_tobject:
+	case tic_tarray:
+		run_var_new_null_ref(run, rvar);
+		break;
+	case tic_tdeleg:
+		run_var_new_deleg(run, rvar);
+		break;
+	case tic_tebase:
+		/*
+		 * One cannot declare variable of ebase type. It is just
+		 * type of expressions referring to enum types.
+		 */
+		assert(b_false);
+	case tic_tenum:
+		run_var_new_enum(run, ti->u.tenum, rvar);
+		break;
+	case tic_tfun:
+		run_var_new_deleg(run, rvar);
+		break;
+	case tic_tvref:
+		/* 
+		 * XXX Need to obtain run-time value of type argument to
+		 * initialize variable properly.
+		 */
+		var = rdata_var_new(vc_int);
+		var->u.int_v = rdata_int_new();
+		bigint_init(&var->u.int_v->value, 0);
+		*rvar = var;
+		break;
+	case tic_ignore:
+		assert(b_false);
+	}
+}
+
+/** Construct a new variable of primitive type.
+ *
+ * The variable is allocated and initialized with a default value
+ * based on primitive type item @a tprimitive.
+ *
+ * @param run		Runner object
+ * @param ti		Primitive type of variable to create
+ * @param rvar		Place to store pointer to new variable
+ */
+static void run_var_new_tprimitive(run_t *run, tdata_primitive_t *tprimitive,
+    rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+
+	(void) run;
+
+	/* Make compiler happy. */
+	var = NULL;
+
+	switch (tprimitive->tpc) {
+	case tpc_bool:
+		var = rdata_var_new(vc_bool);
+		var->u.bool_v = rdata_bool_new();
+		var->u.bool_v->value = b_false;
+		break;
+	case tpc_char:
+		var = rdata_var_new(vc_char);
+		var->u.char_v = rdata_char_new();
+		bigint_init(&var->u.char_v->value, 0);
+		break;
+	case tpc_int:
+		var = rdata_var_new(vc_int);
+		var->u.int_v = rdata_int_new();
+		bigint_init(&var->u.int_v->value, 0);
+		break;
+	case tpc_nil:
+		assert(b_false);
+	case tpc_string:
+		var = rdata_var_new(vc_string);
+		var->u.string_v = rdata_string_new();
+		var->u.string_v->value = "";
+		break;
+	case tpc_resource:
+		var = rdata_var_new(vc_resource);
+		var->u.resource_v = rdata_resource_new();
+		var->u.resource_v->data = NULL;
+		break;
+	}
+
+	*rvar = var;
+}
+
+/** Construct a new variable containing null reference.
+ *
+ * @param run		Runner object
+ * @param rvar		Place to store pointer to new variable
+ */
+static void run_var_new_null_ref(run_t *run, rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+
+	(void) run;
+
+	/* Return null reference. */
+	var = rdata_var_new(vc_ref);
+	var->u.ref_v = rdata_ref_new();
+
+	*rvar = var;
+}
+
+/** Construct a new variable containing invalid delegate.
+ *
+ * @param run		Runner object
+ * @param rvar		Place to store pointer to new variable
+ */
+static void run_var_new_deleg(run_t *run, rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+
+	(void) run;
+
+	/* Return null reference. */
+	var = rdata_var_new(vc_deleg);
+	var->u.deleg_v = rdata_deleg_new();
+
+	*rvar = var;
+}
+
+/** Construct a new variable containing default value of an enum type.
+ *
+ * @param run		Runner object
+ * @param rvar		Place to store pointer to new variable
+ */
+static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
+    rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+	list_node_t *embr_n;
+	stree_embr_t *embr;
+
+	(void) run;
+
+	/* Get first member of enum which will serve as default value. */
+	embr_n = list_first(&tenum->enum_d->members);
+	assert(embr_n != NULL);
+
+	embr = list_node_data(embr_n, stree_embr_t *);
+
+	/* Return null reference. */
+	var = rdata_var_new(vc_enum);
+	var->u.enum_v = rdata_enum_new();
+	var->u.enum_v->value = embr;
+
+	*rvar = var;
+}
+
+/** Construct a new thread activation record.
+ *
+ * @param run	Runner object
+ * @return	New thread AR.
+ */
+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;
+}
+
+/** Construct a new procedure activation record.
+ *
+ * @param run	Runner object
+ * @return	New procedure 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;
+}
+
+/** Construct a new block activation record.
+ *
+ * @param run	Runner object
+ * @return	New block 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 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_exc_check_unhandled(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, cspan_t *cspan,
+    rdata_item_t **ritem);
+
+void run_raise_exc(run_t *run, stree_csi_t *csi, cspan_t *cspan);
+bool_t run_is_bo(run_t *run);
+
+void run_var_new(run_t *run, tdata_item_t *ti, rdata_var_t **rvar);
+
+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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run_expr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,2501 @@
+/*
+ * 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 expressions. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bigint.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_bool(run_t *run, stree_lit_bool_t *lit_bool,
+    rdata_item_t **res);
+static void run_lit_char(run_t *run, stree_lit_char_t *lit_char,
+    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_bool(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res);
+static void run_binop_char(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, 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_binop_enum(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_unop_bool(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    rdata_item_t **res);
+static void run_unop_int(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    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_object_ctor(run_t *run, rdata_var_t *obj, list_t *arg_vals);
+
+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_access_symbol(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_call_args(run_t *run, list_t *args, list_t *arg_vals);
+
+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);
+static void run_box(run_t *run, stree_box_t *box, rdata_item_t **res);
+
+/** Evaluate expression.
+ *
+ * Run the expression @a expr and store pointer to the result in *(@a res).
+ * If the expression has on value (assignment) then @c NULL is returned.
+ * @c NULL is also returned if an error or exception occurs.
+ *
+ * @param run		Runner object
+ * @param expr		Expression to run
+ * @param res		Place to store result
+ */
+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;
+	case ec_box:
+		run_box(run, expr->u.box, res);
+		break;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Expression result: ");
+	rdata_item_print(*res);
+	printf(".\n");
+#endif
+}
+
+/** Evaluate name reference expression.
+ *
+ * @param run		Runner object
+ * @param nameref	Name reference
+ * @param res		Place to store result
+ */
+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;
+	rdata_symbol_t *symbol_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 CSI.\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_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_enum:
+#ifdef DEBUG_RUN_TRACE
+		printf("Referencing enum.\n");
+#endif
+		item = rdata_item_new(ic_value);
+		value = rdata_value_new();
+		var = rdata_var_new(vc_symbol);
+		symbol_v = rdata_symbol_new();
+
+		item->u.value = value;
+		value->var = var;
+		var->u.symbol_v = symbol_v;
+
+		symbol_v->sym = sym;
+		*res = item;
+		break;
+	case sc_deleg:
+		/* XXX TODO */
+		printf("Unimplemented: Delegate name reference.\n");
+		abort();
+		break;
+	case sc_fun:
+		/* There should be no global functions. */
+		assert(csi != NULL);
+
+		if (symbol_search_csi(run->program, csi, nameref->name)
+		    == NULL) {
+			/* 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 (symbol_search_csi(run->program, csi, nameref->name)
+		    == NULL) {
+			/* 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;
+	case sc_prop:
+		/* XXX TODO */
+		printf("Unimplemented: Property name reference.\n");
+		abort();
+		break;
+	}
+}
+
+/** Evaluate literal.
+ *
+ * @param run		Runner object
+ * @param literal	Literal
+ * @param res		Place to store result
+ */
+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_bool:
+		run_lit_bool(run, &literal->u.lit_bool, res);
+		break;
+	case ltc_char:
+		run_lit_char(run, &literal->u.lit_char, res);
+		break;
+	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;
+	}
+}
+
+/** Evaluate Boolean literal.
+ *
+ * @param run		Runner object
+ * @param lit_bool	Boolean literal
+ * @param res		Place to store result
+ */
+static void run_lit_bool(run_t *run, stree_lit_bool_t *lit_bool,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_bool_t *bool_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run Boolean literal.\n");
+#endif
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+	bool_v->value = lit_bool->value;
+
+	*res = item;
+}
+
+/** Evaluate character literal. */
+static void run_lit_char(run_t *run, stree_lit_char_t *lit_char,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_char_t *char_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run character literal.\n");
+#endif
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_char);
+	char_v = rdata_char_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.char_v = char_v;
+	bigint_clone(&lit_char->value, &char_v->value);
+
+	*res = item;
+}
+
+/** Evaluate integer literal.
+ *
+ * @param run		Runner object
+ * @param lit_int	Integer literal
+ * @param res		Place to store result
+ */
+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;
+	bigint_clone(&lit_int->value, &int_v->value);
+
+	*res = item;
+}
+
+/** Evaluate reference literal (@c nil).
+ *
+ * @param run		Runner object
+ * @param lit_ref	Reference literal
+ * @param res		Place to store result
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param lit_string	String literal
+ * @param res		Place to store result
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param self_ref	Self reference
+ * @param res		Place to store result
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param res		Place to store result
+ */
+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);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	run_expr(run, binop->arg2, &rarg2_i);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+#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_bool:
+		run_binop_bool(run, binop, v1, v2, res);
+		break;
+	case vc_char:
+		run_binop_char(run, binop, v1, v2, res);
+		break;
+	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;
+	case vc_enum:
+		run_binop_enum(run, binop, v1, v2, res);
+		break;
+	case vc_deleg:
+	case vc_array:
+	case vc_object:
+	case vc_resource:
+	case vc_symbol:
+		assert(b_false);
+	}
+}
+
+/** Evaluate binary operation on bool arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+ */
+static void run_binop_bool(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_bool_t *bool_v;
+
+	bool_t b1, b2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	b1 = v1->var->u.bool_v->value;
+	b2 = v2->var->u.bool_v->value;
+
+	switch (binop->bc) {
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		assert(b_false);
+
+	case bo_equal:
+		bool_v->value = (b1 == b2);
+		break;
+	case bo_notequal:
+		bool_v->value = (b1 != b2);
+		break;
+	case bo_lt:
+		bool_v->value = (b1 == b_false) && (b2 == b_true);
+		break;
+	case bo_gt:
+		bool_v->value = (b1 == b_true) && (b2 == b_false);
+		break;
+	case bo_lt_equal:
+		bool_v->value = (b1 == b_false) || (b2 == b_true);
+		break;
+	case bo_gt_equal:
+		bool_v->value = (b1 == b_true) || (b2 == b_false);
+		break;
+
+	case bo_and:
+		bool_v->value = (b1 == b_true) && (b2 == b_true);
+		break;
+	case bo_or:
+		bool_v->value = (b1 == b_true) || (b2 == b_true);
+		break;
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on char arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+*/
+static void run_binop_char(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_bool_t *bool_v;
+
+	bigint_t *c1, *c2;
+	bigint_t diff;
+	bool_t zf, nf;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+
+	item->u.value = value;
+
+	c1 = &v1->var->u.char_v->value;
+	c2 = &v2->var->u.char_v->value;
+
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+	var->u.bool_v = bool_v;
+	value->var = var;
+
+	bigint_sub(c1, c2, &diff);
+	zf = bigint_is_zero(&diff);
+	nf = bigint_is_negative(&diff);
+
+	switch (binop->bc) {
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		assert(b_false);
+
+	case bo_equal:
+		bool_v->value = zf;
+		break;
+	case bo_notequal:
+		bool_v->value = !zf;
+		break;
+	case bo_lt:
+		bool_v->value = (!zf && nf);
+		break;
+	case bo_gt:
+		bool_v->value = (!zf && !nf);
+		break;
+	case bo_lt_equal:
+		bool_v->value = (zf || nf);
+		break;
+	case bo_gt_equal:
+		bool_v->value = !nf;
+		break;
+
+	case bo_and:
+	case bo_or:
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on int arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+*/
+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;
+	rdata_bool_t *bool_v;
+
+	bigint_t *i1, *i2;
+	bigint_t diff;
+	bool_t done;
+	bool_t zf, nf;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+
+	item->u.value = value;
+
+	i1 = &v1->var->u.int_v->value;
+	i2 = &v2->var->u.int_v->value;
+
+	done = b_true;
+
+	switch (binop->bc) {
+	case bo_plus:
+		int_v = rdata_int_new();
+		bigint_add(i1, i2, &int_v->value);
+		break;
+	case bo_minus:
+		int_v = rdata_int_new();
+		bigint_sub(i1, i2, &int_v->value);
+		break;
+	case bo_mult:
+		int_v = rdata_int_new();
+		bigint_mul(i1, i2, &int_v->value);
+		break;
+	default:
+		done = b_false;
+		break;
+	}
+
+	if (done) {
+		var = rdata_var_new(vc_int);
+		var->u.int_v = int_v;
+		value->var = var;
+		*res = item;
+		return;
+	}
+
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+	var->u.bool_v = bool_v;
+	value->var = var;
+
+	/* Relational operation. */
+
+	bigint_sub(i1, i2, &diff);
+	zf = bigint_is_zero(&diff);
+	nf = bigint_is_negative(&diff);
+
+	switch (binop->bc) {
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		assert(b_false);
+
+	case bo_equal:
+		bool_v->value = zf;
+		break;
+	case bo_notequal:
+		bool_v->value = !zf;
+		break;
+	case bo_lt:
+		bool_v->value = (!zf && nf);
+		break;
+	case bo_gt:
+		bool_v->value = (!zf && !nf);
+		break;
+	case bo_lt_equal:
+		bool_v->value = (zf || nf);
+		break;
+	case bo_gt_equal:
+		bool_v->value = !nf;
+		break;
+	case bo_and:
+	case bo_or:
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on string arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+ */
+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;
+	rdata_bool_t *bool_v;
+	bool_t done;
+	bool_t zf;
+
+	const char *s1, *s2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+
+	item->u.value = value;
+
+	s1 = v1->var->u.string_v->value;
+	s2 = v2->var->u.string_v->value;
+
+	done = b_true;
+
+	switch (binop->bc) {
+	case bo_plus:
+		/* Concatenate strings. */
+		string_v = rdata_string_new();
+		string_v->value = os_str_acat(s1, s2);
+		break;
+	default:
+		done = b_false;
+		break;
+	}
+
+	if (done) {
+		var = rdata_var_new(vc_string);
+		var->u.string_v = string_v;
+		value->var = var;
+		*res = item;
+		return;
+	}
+
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+	var->u.bool_v = bool_v;
+	value->var = var;
+
+	/* Relational operation. */
+
+	zf = os_str_cmp(s1, s2) == 0;
+
+	switch (binop->bc) {
+	case bo_equal:
+		bool_v->value = zf;
+		break;
+	case bo_notequal:
+		bool_v->value = !zf;
+		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.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+ */
+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_bool_t *bool_v;
+
+	rdata_var_t *ref1, *ref2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	ref1 = v1->var->u.ref_v->vref;
+	ref2 = v2->var->u.ref_v->vref;
+
+	switch (binop->bc) {
+	case bo_equal:
+		bool_v->value = (ref1 == ref2);
+		break;
+	case bo_notequal:
+		bool_v->value = (ref1 != ref2);
+		break;
+	default:
+		printf("Error: Invalid binary operation on reference "
+		    "arguments (%d).\n", binop->bc);
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate binary operation on enum arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+ */
+static void run_binop_enum(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_bool_t *bool_v;
+
+	rdata_var_t *ref1, *ref2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	ref1 = v1->var->u.ref_v->vref;
+	ref2 = v2->var->u.ref_v->vref;
+
+	switch (binop->bc) {
+	case bo_equal:
+		bool_v->value = (ref1 == ref2);
+		break;
+	case bo_notequal:
+		bool_v->value = (ref1 != ref2);
+		break;
+	default:
+		/* Should have been caught by static typing. */
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate unary operation.
+ *
+ * @param run		Runner object
+ * @param unop		Unary operation
+ * @param res		Place to store result
+ */
+static void run_unop(run_t *run, stree_unop_t *unop, rdata_item_t **res)
+{
+	rdata_item_t *rarg_i;
+	rdata_item_t *rarg_vi;
+	rdata_value_t *val;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run unary operation.\n");
+#endif
+	run_expr(run, unop->arg, &rarg_i);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check unop argument result.\n");
+#endif
+	run_cvt_value_item(run, rarg_i, &rarg_vi);
+
+	val = rarg_vi->u.value;
+
+	switch (val->var->vc) {
+	case vc_bool:
+		run_unop_bool(run, unop, val, res);
+		break;
+	case vc_int:
+		run_unop_int(run, unop, val, res);
+		break;
+	default:
+		printf("Unimplemented: Unrary operation argument of "
+		    "type %d.\n", val->var->vc);
+		run_raise_error(run);
+		*res = NULL;
+		break;
+	}
+}
+
+/** Evaluate unary operation on bool argument.
+ *
+ * @param run		Runner object
+ * @param unop		Unary operation
+ * @param val		Value of argument
+ * @param res		Place to store result
+ */
+static void run_unop_bool(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_bool_t *bool_v;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	switch (unop->uc) {
+	case uo_plus:
+	case uo_minus:
+		assert(b_false);
+
+	case uo_not:
+		bool_v->value = !val->var->u.bool_v->value;
+		break;
+	}
+
+	*res = item;
+}
+
+/** Evaluate unary operation on int argument.
+ *
+ * @param run		Runner object
+ * @param unop		Unary operation
+ * @param val		Value of argument
+ * @param res		Place to store result
+ */
+static void run_unop_int(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_int_t *int_v;
+
+	(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;
+
+	switch (unop->uc) {
+	case uo_plus:
+	        bigint_clone(&val->var->u.int_v->value, &int_v->value);
+		break;
+	case uo_minus:
+		bigint_reverse_sign(&val->var->u.int_v->value,
+		    &int_v->value);
+		break;
+	case uo_not:
+		assert(b_false);
+	}
+
+	*res = item;
+}
+
+/** Evaluate @c new operation.
+ *
+ * Evaluates operation per the @c new operator that creates a new
+ * instance of some type.
+ *
+ * @param run		Runner object
+ * @param unop		Unary operation
+ * @param res		Place to store result
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param new_op	New operation
+ * @param titem		Type of new var node (tic_tarray)
+ * @param res		Place to store result
+ */
+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;
+	int rc;
+	int iextent;
+
+#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);
+		if (run_is_bo(run)) {
+			*res = NULL;
+			return;
+		}
+
+		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: ");
+		bigint_print(&rexpr_var->u.int_v->value);
+		printf(".\n");
+#endif
+		rc = bigint_get_value_int(&rexpr_var->u.int_v->value,
+		    &iextent);
+		if (rc != EOK) {
+			printf("Memory allocation failed (big int used).\n");
+			exit(1);
+		}
+
+		array->extent[i] = iextent;
+		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) {
+		/* Create and initialize element. */
+		run_var_new(run, tarray->base_ti, &elem_var);
+
+		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.
+ *
+ * @param run		Runner object
+ * @param new_op	New operation
+ * @param titem		Type of new var node (tic_tobject)
+ * @param res		Place to store result
+ */
+static void run_new_object(run_t *run, stree_new_t *new_op,
+    tdata_item_t *titem, rdata_item_t **res)
+{
+	stree_csi_t *csi;
+	rdata_item_t *obj_i;
+	list_t arg_vals;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Create new object.\n");
+#endif
+	/* Lookup object CSI. */
+	assert(titem->tic == tic_tobject);
+	csi = titem->u.tobject->csi;
+
+	/* Evaluate constructor arguments. */
+	run_call_args(run, &new_op->ctor_args, &arg_vals);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	/* Create CSI instance. */
+	run_new_csi_inst(run, csi, res);
+
+	/* Run the constructor. */
+	run_dereference(run, *res, NULL, &obj_i);
+	assert(obj_i->ic == ic_address);
+	assert(obj_i->u.address->ac == ac_var);
+	run_object_ctor(run, obj_i->u.address->u.var_a->vref, &arg_vals);
+}
+
+/** Evaluate member acccess.
+ *
+ * Evaluate operation per the member access ('.') operator.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param res		Place to store result
+ */
+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 (run_is_bo(run)) {
+		*res = NULL;
+		return;
+    	}
+
+	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).
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+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;
+	case vc_symbol:
+		run_access_symbol(run, access, arg, res);
+		break;
+
+	case vc_bool:
+	case vc_char:
+	case vc_enum:
+	case vc_int:
+	case vc_string:
+	case vc_array:
+	case vc_resource:
+		printf("Unimplemented: Using access operator ('.') "
+		    "with unsupported data type (value/%d).\n", vc);
+		exit(1);
+	}
+}
+
+/** Evaluate reference acccess.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+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, access->arg->cspan, &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.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+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);
+
+	/* Member existence should be ensured by static type checking. */
+	assert(member != NULL);
+
+#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.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+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
+
+	/* Make compiler happy. */
+	ritem = NULL;
+
+	switch (member->sc) {
+	case sc_csi:
+		printf("Error: Accessing object member which is nested CSI.\n");
+		exit(1);
+	case sc_deleg:
+		printf("Error: Accessing object member which is a delegate.\n");
+		exit(1);
+	case sc_enum:
+		printf("Error: Accessing object member which is an enum.\n");
+		exit(1);
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_fun:
+		/* Construct anonymous 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;
+}
+
+/** Evaluate symbol member acccess.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+static void run_access_symbol(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_symbol_t *symbol_v;
+	stree_embr_t *embr;
+
+	rdata_item_t *ritem;
+	rdata_value_t *rvalue;
+	rdata_var_t *rvar;
+	rdata_enum_t *enum_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run symbol access operation.\n");
+#endif
+	run_cvt_value_item(run, arg, &arg_vi);
+	arg_val = arg_vi->u.value;
+	assert(arg_val->var->vc == vc_symbol);
+
+	symbol_v = arg_val->var->u.symbol_v;
+
+	/* XXX Port CSI symbol reference to using vc_symbol */
+	assert(symbol_v->sym->sc == sc_enum);
+
+	embr = stree_enum_find_mbr(symbol_v->sym->u.enum_d,
+	    access->member_name);
+
+	/* Member existence should be ensured by static type checking. */
+	assert(embr != NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found enum member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+	ritem = rdata_item_new(ic_value);
+	rvalue = rdata_value_new();
+	rvar = rdata_var_new(vc_enum);
+	enum_v = rdata_enum_new();
+
+	ritem->u.value = rvalue;
+	rvalue->var = rvar;
+	rvar->u.enum_v = enum_v;
+	enum_v->value = embr;
+
+	*res = ritem;
+}
+
+/** Call a function.
+ *
+ * Call a function and return the result in @a res.
+ *
+ * @param run		Runner object
+ * @param call		Call operation
+ * @param res		Place to store result
+ */
+static void run_call(run_t *run, stree_call_t *call, rdata_item_t **res)
+{
+	rdata_item_t *rdeleg, *rdeleg_vi;
+	rdata_deleg_t *deleg_v;
+	list_t arg_vals;
+
+	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, &rdeleg);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	if (run->thread_ar->bo_mode != bm_none) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
+	run_cvt_value_item(run, rdeleg, &rdeleg_vi);
+	assert(rdeleg_vi->ic == ic_value);
+
+	if (rdeleg_vi->u.value->var->vc != vc_deleg) {
+		printf("Unimplemented: Call expression of this type (");
+		rdata_item_print(rdeleg_vi);
+		printf(").\n");
+		exit(1);
+	}
+
+	deleg_v = rdeleg_vi->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. */
+	run_call_args(run, &call->args, &arg_vals);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	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);
+
+	if (!run_is_bo(run) && fun->sig->rtype != NULL && *res == NULL) {
+		printf("Error: Function '");
+		symbol_print_fqn(deleg_v->sym);
+		printf("' did not return a value.\n");
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Returned from function call.\n");
+#endif
+}
+
+/** Evaluate call arguments.
+ *
+ * Evaluate arguments to function or constructor.
+ *
+ * @param run		Runner object
+ * @param args		Real arguments (list of stree_expr_t)
+ * @param arg_vals	Address of uninitialized list to store argument values
+ *			(list of rdata_item_t).
+ */
+static void run_call_args(run_t *run, list_t *args, list_t *arg_vals)
+{
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	rdata_item_t *rarg_i, *rarg_vi;
+
+	/* Evaluate function arguments. */
+	list_init(arg_vals);
+	arg_n = list_first(args);
+
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_expr_t *);
+		run_expr(run, arg, &rarg_i);
+		if (run_is_bo(run))
+			return;
+
+		run_cvt_value_item(run, rarg_i, &rarg_vi);
+
+		list_append(arg_vals, rarg_vi);
+		arg_n = list_next(args, arg_n);
+	}
+}
+
+/** Run index operation.
+ *
+ * Evaluate operation per the indexing ('[', ']') operator.
+ *
+ * @param run		Runner object
+ * @param index		Index operation
+ * @param res		Place to store result
+ */
+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);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	vc = run_item_get_vc(run, rbase);
+
+	/* Implicitly dereference. */
+	if (vc == vc_ref) {
+		run_dereference(run, rbase, index->base->cspan, &base_i);
+		if (run_is_bo(run)) {
+			*res = NULL;
+			return;
+		}
+	} 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);
+		if (run_is_bo(run)) {
+			*res = NULL;
+			return;
+		}
+
+		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.
+ *
+ * @param run		Runner object
+ * @param index		Index operation
+ * @param base		Evaluated base expression
+ * @param args		Evaluated indices (list of rdata_item_t)
+ * @param res		Place to store result
+ */
+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;
+	int rc;
+
+	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;
+
+	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);
+		}
+
+		rc = bigint_get_value_int(
+		    &arg->u.value->var->u.int_v->value,
+		    &arg_val);
+
+		if (rc != EOK || arg_val < 0 || arg_val >= array->extent[i]) {
+#ifdef DEBUG_RUN_TRACE
+			printf("Error: Array index (value: %d) is out of range.\n",
+			    arg_val);
+#endif
+			/* Raise Error.OutOfBounds */
+			run_raise_exc(run,
+			    run->program->builtin->error_outofbounds,
+			    index->expr->cspan);
+			/* XXX It should be cspan of the argument. */
+			*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).
+ *
+ * @param run		Runner object
+ * @param index		Index operation
+ * @param base		Evaluated base expression
+ * @param args		Evaluated indices (list of rdata_item_t)
+ * @param res		Place to store result
+ */
+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.
+ *
+ * @param run		Runner object
+ * @param index		Index operation
+ * @param base		Evaluated base expression
+ * @param args		Evaluated indices (list of rdata_item_t)
+ * @param res		Place to store result
+ */
+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 rc1, rc2;
+
+	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;
+
+	run_cvt_value_item(run, base, &base_vi);
+	assert(base_vi->u.value->var->vc == vc_string);
+	string = base_vi->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);
+		}
+
+		rc1 = bigint_get_value_int(
+		    &arg->u.value->var->u.int_v->value,
+		    &arg_val);
+
+		elem_index = arg_val;
+
+		node = list_next(args, node);
+		i += 1;
+	}
+
+	if (i < 1) {
+		printf("Error: Too few indices for string.\n");
+		exit(1);
+	}
+
+	if (rc1 == EOK)
+		rc2 = os_str_get_char(string->value, elem_index, &cval);
+
+	if (rc1 != EOK || rc2 != EOK) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Error: String index (value: %d) is out of range.\n",
+		    arg_val);
+#endif
+		/* Raise Error.OutOfBounds */
+		run_raise_exc(run, run->program->builtin->error_outofbounds,
+		    index->expr->cspan);
+		*res = run_recovery_item(run);
+		return;
+	}
+
+	/* Construct character value. */
+	ritem = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	ritem->u.value = value;
+
+	cvar = rdata_var_new(vc_char);
+	cvar->u.char_v = rdata_char_new();
+	bigint_init(&cvar->u.char_v->value, cval);
+	value->var = cvar;
+
+	*res = ritem;
+}
+
+/** Run assignment.
+ *
+ * Executes an assignment. @c NULL is always stored to @a res because
+ * an assignment does not have a value.
+ *
+ * @param run		Runner object
+ * @param assign	Assignment expression
+ * @param res		Place to store result
+*/
+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);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	run_expr(run, assign->src, &rsrc_i);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	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.
+ *
+ * @param run		Runner object
+ * @param as_op		@c as conversion expression
+ * @param res		Place to store result
+ */
+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);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	/*
+	 * 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, NULL, &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;
+}
+
+/** Execute boxing operation.
+ *
+ * XXX We can scrap this special operation once we have constructors.
+ *
+ * @param run		Runner object
+ * @param box		Boxing operation
+ * @param res		Place to store result
+ */
+static void run_box(run_t *run, stree_box_t *box, rdata_item_t **res)
+{
+	rdata_item_t *rarg_i;
+	rdata_item_t *rarg_vi;
+
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+	builtin_t *bi;
+	rdata_var_t *var;
+	rdata_object_t *object;
+
+	sid_t mbr_name_sid;
+	rdata_var_t *mbr_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run boxing operation.\n");
+#endif
+	run_expr(run, box->arg, &rarg_i);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	assert(rarg_vi->ic == ic_value);
+
+	bi = run->program->builtin;
+
+	/* Just to keep the compiler happy. */
+	csi_sym = NULL;
+
+	switch (rarg_vi->u.value->var->vc) {
+	case vc_bool: csi_sym = bi->boxed_bool; break;
+	case vc_char: csi_sym = bi->boxed_char; break;
+	case vc_int: csi_sym = bi->boxed_int; break;
+	case vc_string: csi_sym = bi->boxed_string; break;
+
+	case vc_ref:
+	case vc_deleg:
+	case vc_enum:
+	case vc_array:
+	case vc_object:
+	case vc_resource:
+	case vc_symbol:
+		assert(b_false);
+	}
+
+	csi = symbol_to_csi(csi_sym);
+	assert(csi != NULL);
+
+	/* Construct object of the relevant boxed type. */
+	run_new_csi_inst(run, csi, res);
+
+	/* Set the 'Value' field */
+
+	assert((*res)->ic == ic_value);
+	assert((*res)->u.value->var->vc == vc_ref);
+	var = (*res)->u.value->var->u.ref_v->vref;
+	assert(var->vc == vc_object);
+	object = var->u.object_v;
+
+	mbr_name_sid = strtab_get_sid("Value");
+	mbr_var = intmap_get(&object->fields, mbr_name_sid);
+	assert(mbr_var != NULL);
+
+	rdata_var_write(mbr_var, rarg_vi->u.value);
+}
+
+/** Create new CSI instance.
+ *
+ * Create a new object, instance of @a csi.
+ * XXX This does not work with generics as @a csi cannot specify a generic
+ * type.
+ *
+ * Initialize the fields with default values of their types, but do not
+ * run any constructor.
+ *
+ * @param run		Runner object
+ * @param as_op		@c as conversion expression
+ * @param res		Place to store result
+ */
+void run_new_csi_inst(run_t *run, stree_csi_t *csi, rdata_item_t **res)
+{
+	rdata_object_t *obj;
+	rdata_var_t *obj_var;
+
+	stree_symbol_t *csi_sym;
+	stree_csimbr_t *csimbr;
+
+	rdata_var_t *mbr_var;
+	list_node_t *node;
+	tdata_item_t *field_ti;
+
+	csi_sym = csi_to_symbol(csi);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Create new instance of CSI '");
+	symbol_print_fqn(csi_sym);
+	printf("'.\n");
+#endif
+
+	/* 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. */
+	while (csi != NULL) {
+		node = list_first(&csi->members);
+		while (node != NULL) {
+			csimbr = list_node_data(node, stree_csimbr_t *);
+			if (csimbr->cc == csimbr_var) {
+				/* Compute field type. XXX Memoize. */
+				run_texpr(run->program, csi,
+				    csimbr->u.var->type,
+				    &field_ti);
+
+				/* Create and initialize field. */
+				run_var_new(run, field_ti, &mbr_var);
+
+				/* Add to field map. */
+				intmap_set(&obj->fields,
+				    csimbr->u.var->name->sid,
+				    mbr_var);
+			}
+
+			node = list_next(&csi->members, node);
+		}
+
+		/* Continue with base CSI */
+		csi = csi->base_csi;
+	}
+
+	/* Create reference to the new object. */
+	run_reference(run, obj_var, res);
+}
+
+/** Run constructor on an object.
+ *
+ * @param run		Runner object
+ * @param obj		Object to run constructor on
+ * @param arg_vals	Argument values (list of rdata_item_t)
+ */
+static void run_object_ctor(run_t *run, rdata_var_t *obj, list_t *arg_vals)
+{
+	stree_ident_t *ctor_ident;
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+	stree_symbol_t *ctor_sym;
+	stree_ctor_t *ctor;
+	run_proc_ar_t *proc_ar;
+	rdata_item_t *res;
+
+	csi_sym = obj->u.object_v->class_sym;
+	csi = symbol_to_csi(csi_sym);
+	assert(csi != NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run object constructor from CSI '");
+	symbol_print_fqn(csi_sym);
+	printf("'.\n");
+#endif
+	ctor_ident = stree_ident_new();
+	ctor_ident->sid = strtab_get_sid(CTOR_IDENT);
+
+	/* Find constructor. */
+	ctor_sym = symbol_search_csi_no_base(run->program, csi, ctor_ident);
+	if (ctor_sym == NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("No constructor found.\n");
+#endif
+		return;
+	}
+
+	ctor = symbol_to_ctor(ctor_sym);
+	assert(ctor != NULL);
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, obj, ctor->proc, &proc_ar);
+
+	/* Fill in argument values. */
+	run_proc_ar_set_args(run, proc_ar, arg_vals);
+
+	/* Run the procedure. */
+	run_proc(run, proc_ar, &res);
+
+	/* Constructor does not return a value. */
+	assert(res == NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Returned from constructor..\n");
+#endif
+}
+
+/** Return boolean value of an item.
+ *
+ * Try to interpret @a item as a boolean value. If it is not a boolean
+ * value, generate an error.
+ *
+ * @param run		Runner object
+ * @param item		Input item
+ * @return		Resulting boolean value
+ */
+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;
+
+	assert(var->vc == vc_bool);
+	return var->u.bool_v->value;
+}
Index: uspace/app/sbi/src/run_expr.h
===================================================================
--- uspace/app/sbi/src/run_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 RUN_EXPR_H_
+#define RUN_EXPR_H_
+
+#include "mytypes.h"
+
+void run_expr(run_t *run, stree_expr_t *expr, rdata_item_t **res);
+
+void run_new_csi_inst(run_t *run, stree_csi_t *csi, 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,118 @@
+/*
+ * 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 cspan */
+	struct cspan *exc_cspan;
+
+	/** 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run_texpr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,484 @@
+/*
+ * 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 Evaluate type expressions. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "cspan.h"
+#include "debug.h"
+#include "list.h"
+#include "mytypes.h"
+#include "stree.h"
+#include "strtab.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);
+static void run_tapply(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tapply_t *tapply, tdata_item_t **res);
+
+/** Evaluate type expression.
+ *
+ * Evaluate type expression (this produces a type item). If a type error
+ * occurs, the resulting type item is of class @c tic_ignore.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param texpr		Type expression to evaluate
+ * @param res		Place to store type result
+ */
+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:
+		run_tapply(prog, ctx, texpr->u.tapply, res);
+		break;
+	}
+}
+
+/** Evaluate type access expression.
+ *
+ * Evaluate operation per the type access ('.') operator.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param taccess	Type access expression to evaluate
+ * @param res		Place to store type result
+ */
+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;
+	tdata_deleg_t *tdeleg;
+	stree_csi_t *base_csi;
+	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
+	tdata_enum_t *tenum;
+
+#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_ignore) {
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	if (targ_i->tic != tic_tobject) {
+		cspan_print(taccess->texpr->cspan);
+		printf(" Error: Using '.' with type which is not an "
+		    "object.\n");
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	/* Get base CSI. */
+	base_csi = targ_i->u.tobject->csi;
+
+	sym = symbol_lookup_in_csi(prog, base_csi, taccess->member_name);
+	if (sym == NULL) {
+		cspan_print(taccess->member_name->cspan);
+		printf(" Error: CSI '");
+		symbol_print_fqn(csi_to_symbol(base_csi));
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(taccess->member_name->sid));
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	switch (sym->sc) {
+	case sc_csi:
+		/* 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;
+		list_init(&tobject->targs);
+		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_deleg:
+		/* Fetch stored delegate type. */
+		deleg = symbol_to_deleg(sym);
+		assert(deleg != NULL);
+		if (deleg->titem == NULL) {
+			/*
+			 * Prepare a partial delegate which will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tdeleg);
+			tdeleg = tdata_deleg_new();
+			titem->u.tdeleg = tdeleg;
+			tdeleg->deleg = deleg;
+			tdeleg->tsig = NULL;
+
+			deleg->titem = titem;
+		} else {
+			titem = deleg->titem;
+		}
+		break;
+	case sc_enum:
+		/* Fetch stored enum type. */
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+		if (enum_d->titem == NULL) {
+			/*
+			 * Prepare a partial enum whic will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tenum);
+			tenum = tdata_enum_new();
+			titem->u.tenum = tenum;
+			tenum->enum_d = enum_d;
+		} else {
+			titem = enum_d->titem;
+		}
+		break;
+	case sc_fun:
+	case sc_var:
+	case sc_prop:
+		cspan_print(taccess->member_name->cspan);
+		printf(" Error: Symbol '");
+		symbol_print_fqn(sym);
+		printf("' is not a type.\n");
+		titem = tdata_item_new(tic_ignore);
+		break;
+	}
+
+	*res = titem;
+}
+
+/** Evaluate type indexing expression.
+ *
+ * Evaluate operation per the type indexing ('[', ']') operator.
+ * A type indexing operation may have extents specified or only rank
+ * specified.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param tindex	Type indexing expression to evaluate
+ * @param res		Place to store type result
+ */
+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);
+
+	if (base_ti->tic == tic_ignore) {
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	/* 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;
+}
+
+/** Evaluate type literal expression.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param tliteral	Type literal
+ * @param res		Place to store type result
+ */
+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_bool: tpc = tpc_bool; break;
+	case tlc_char: tpc = tpc_char; break;
+	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;
+	stree_targ_t *targ;
+	tdata_vref_t *tvref;
+	stree_deleg_t *deleg;
+	tdata_deleg_t *tdeleg;
+	stree_enum_t *enum_d;
+	tdata_enum_t *tenum;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type name reference.\n");
+	printf("'%s'\n", strtab_get_str(tnameref->name->sid));
+#endif
+	/* In interactive mode we are not in a class */
+	if (ctx != NULL) {
+		/* Look for type argument */
+		targ = stree_csi_find_targ(ctx, tnameref->name);
+
+		if (targ != NULL) {
+			/* Found type argument */
+#ifdef DEBUG_RUN_TRACE
+			printf("Found type argument '%s'.\n",
+			    strtab_get_str(tnameref->name->sid));
+#endif
+			titem = tdata_item_new(tic_tvref);
+			tvref = tdata_vref_new();
+			titem->u.tvref = tvref;
+			tvref->targ = targ;
+
+			*res = titem;
+			return;
+		}
+	}
+
+	/* Look for symbol */
+	sym = symbol_lookup_in_csi(prog, ctx, tnameref->name);
+	if (sym == NULL) {
+		cspan_print(tnameref->texpr->cspan);
+		printf(" Error: Symbol '%s' not found.\n",
+		    strtab_get_str(tnameref->name->sid));
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	switch (sym->sc) {
+	case sc_csi:
+		/* 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;
+		list_init(&tobject->targs);
+		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_deleg:
+		/* Fetch stored delegate type. */
+		deleg = symbol_to_deleg(sym);
+		assert(deleg != NULL);
+		if (deleg->titem == NULL) {
+			/*
+			 * Prepare a partial delegate which will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tdeleg);
+			tdeleg = tdata_deleg_new();
+			titem->u.tdeleg = tdeleg;
+			tdeleg->deleg = deleg;
+			tdeleg->tsig = NULL;
+
+			deleg->titem = titem;
+		} else {
+			titem = deleg->titem;
+		}
+		break;
+	case sc_enum:
+		/* Fetch stored enum type. */
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+		if (enum_d->titem == NULL) {
+			/*
+			 * Prepare a partial enum whic will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tenum);
+			tenum = tdata_enum_new();
+			titem->u.tenum = tenum;
+			tenum->enum_d = enum_d;
+		} else {
+			titem = enum_d->titem;
+		}
+		break;
+	case sc_fun:
+	case sc_var:
+	case sc_prop:
+		cspan_print(tnameref->texpr->cspan);
+		printf(" Error: Symbol '");
+		symbol_print_fqn(sym);
+		printf("' is not a type.\n");
+		titem = tdata_item_new(tic_ignore);
+		break;
+	}
+
+	*res = titem;
+}
+
+/** Evaluate type application expression.
+ *
+ * In a type application expression type arguments are applied to a generic
+ * CSI.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param tapply	Type application expression
+ * @param res		Place to store type result
+ */
+static void run_tapply(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tapply_t *tapply, tdata_item_t **res)
+{
+	tdata_item_t *base_ti;
+	tdata_item_t *arg_ti;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+
+	list_node_t *arg_n;
+	stree_texpr_t *arg;
+
+	list_node_t *farg_n;
+	stree_targ_t *farg;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type apply operation.\n");
+#endif
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	/* Evaluate base (generic) type. */
+	run_texpr(prog, ctx, tapply->gtype, &base_ti);
+
+	if (base_ti->tic != tic_tobject) {
+		cspan_print(tapply->gtype->cspan);
+		printf(" Error: Base type of generic application is not "
+		    "a CSI.\n");
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	tobject->static_ref = b_false;
+	tobject->csi = base_ti->u.tobject->csi;
+	list_init(&tobject->targs);
+
+	/* Evaluate type arguments. */
+	farg_n = list_first(&tobject->csi->targ);
+	arg_n = list_first(&tapply->targs);
+	while (farg_n != NULL && arg_n != NULL) {
+		farg = list_node_data(farg_n, stree_targ_t *);
+		arg = list_node_data(arg_n, stree_texpr_t *);
+
+		run_texpr(prog, ctx, arg, &arg_ti);
+
+		if (arg_ti->tic == tic_ignore) {
+			*res = tdata_item_new(tic_ignore);
+			return;
+		}
+
+		list_append(&tobject->targs, arg_ti);
+
+		farg_n = list_next(&tobject->csi->targ, farg_n);
+		arg_n = list_next(&tapply->targs, arg_n);
+	}
+
+	if (farg_n != NULL || arg_n != NULL) {
+		cspan_print(tapply->texpr->cspan);
+		printf(" Error: Incorrect number of type arguments.\n");
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	*res = titem;
+}
Index: uspace/app/sbi/src/run_texpr.h
===================================================================
--- uspace/app/sbi/src/run_texpr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/run_texpr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stree.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1094 @@
+/*
+ * 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"
+
+/** Allocate new module.
+ *
+ * @return	New module
+ */
+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;
+}
+
+/** Allocate new module member.
+ *
+ * @param mc	Module member class
+ * @return	New module member
+ */
+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;
+}
+
+/** Allocate new CSI.
+ *
+ * @param cc	CSI class
+ * @return	New CSI
+ */
+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;
+}
+
+/** Allocate new CSI member.
+ *
+ * @param cc	CSI member class
+ * @return	New CSI member
+ */
+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;
+}
+
+/** Allocate new constructor.
+ *
+ * @return	New constructor
+ */
+stree_ctor_t *stree_ctor_new(void)
+{
+	stree_ctor_t *ctor;
+
+	ctor = calloc(1, sizeof(stree_ctor_t));
+	if (ctor == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return ctor;
+}
+
+/** Allocate new member delegate.
+ *
+ * @return	New member delegate
+ */
+stree_deleg_t *stree_deleg_new(void)
+{
+	stree_deleg_t *deleg;
+
+	deleg = calloc(1, sizeof(stree_deleg_t));
+	if (deleg == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return deleg;
+}
+
+/** Allocate new enum.
+ *
+ * @return	New enum
+ */
+stree_enum_t *stree_enum_new(void)
+{
+	stree_enum_t *enum_d;
+
+	enum_d = calloc(1, sizeof(stree_enum_t));
+	if (enum_d == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return enum_d;
+}
+
+/** Allocate new enum member.
+ *
+ * @return	New enum member
+ */
+stree_embr_t *stree_embr_new(void)
+{
+	stree_embr_t *embr;
+
+	embr = calloc(1, sizeof(stree_embr_t));
+	if (embr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return embr;
+}
+
+/** Allocate new member function.
+ *
+ * @return	New member function
+ */
+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;
+}
+
+/** Allocate new member variable.
+ *
+ * @return	New member variable
+ */
+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;
+}
+
+/** Allocate new property.
+ *
+ * @return	New property
+ */
+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;
+}
+
+/** Allocate new type argument.
+ *
+ * @return	New type argument
+ */
+stree_targ_t *stree_targ_new(void)
+{
+	stree_targ_t *targ;
+
+	targ = calloc(1, sizeof(stree_targ_t));
+	if (targ == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return targ;
+}
+
+/** Allocate new symbol attribute.
+ *
+ * @param sac	Symbol attribute class
+ * @return	New symbol attribute
+ */
+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;
+}
+
+/** Allocate new procedure.
+ *
+ * @return	New procedure
+ */
+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;
+}
+
+/** Allocate new procedure argument.
+ *
+ * @return	New procedure argument
+ */
+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;
+}
+
+/** Allocate new function signature.
+ *
+ * @return	New procedure argument
+ */
+stree_fun_sig_t *stree_fun_sig_new(void)
+{
+	stree_fun_sig_t *fun_sig;
+
+	fun_sig = calloc(1, sizeof(stree_fun_sig_t));
+	if (fun_sig == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return fun_sig;
+}
+
+/** Allocate new procedure argument attribute.
+ *
+ * @param	Argument attribute class
+ * @return	New procedure argument attribute
+ */
+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;
+}
+
+/** Allocate new statement.
+ *
+ * @param sc	Statement class
+ * @return	New statement
+ */
+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;
+}
+
+/** Allocate new local variable declaration.
+ *
+ * @return	New local variable declaration
+ */
+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;
+}
+
+/** Allocate new @c if statement.
+ *
+ * @return	New @c if statement
+ */
+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;
+}
+
+/** Allocate new @c while statement.
+ *
+ * @return	New @c while statement
+ */
+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;
+}
+
+/** Allocate new @c for statement.
+ *
+ * @return	New @c for statement
+ */
+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;
+}
+
+/** Allocate new @c raise statement.
+ *
+ * @return	New @c raise statement
+ */
+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;
+}
+
+/** Allocate new @c break statement.
+ *
+ * @return	New @c break statement
+ */
+stree_break_t *stree_break_new(void)
+{
+	stree_break_t *break_s;
+
+	break_s = calloc(1, sizeof(stree_break_t));
+	if (break_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return break_s;
+}
+
+/** Allocate new @c return statement.
+ *
+ * @return	New @c return statement
+ */
+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;
+}
+
+/** Allocate new with-except-finally statement.
+ *
+ * @return	New with-except-finally statement.
+ */
+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;
+}
+
+/** Allocate new expression statement.
+ *
+ * @return	New expression statement
+ */
+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;
+}
+
+/** Allocate new @c except clause.
+ *
+ * @return	New @c except clause
+ */
+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;
+}
+
+/** Allocate new @c if/elif clause.
+ *
+ * @return	New @c if/elif clause
+ */
+stree_if_clause_t *stree_if_clause_new(void)
+{
+	stree_if_clause_t *if_clause;
+
+	if_clause = calloc(1, sizeof(stree_if_clause_t));
+	if (if_clause == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return if_clause;
+}
+
+/** Allocate new statement block.
+ *
+ * @return	New statement block
+ */
+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;
+}
+
+/** Allocate new expression.
+ *
+ * @param ec	Expression class
+ * @return	New expression
+ */
+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;
+}
+
+/** Allocate new assignment.
+ *
+ * @param ac	Assignment class
+ * @return	New assignment
+ */
+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;
+}
+
+/** Allocate new binary operation.
+ *
+ * @return	New binary operation
+ */
+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;
+}
+
+/** Allocate new unary operation.
+ *
+ * @param uc	Unary operation class
+ * @return	New unary operation
+ */
+stree_unop_t *stree_unop_new(unop_class_t uc)
+{
+	stree_unop_t *unop;
+
+	unop = calloc(1, sizeof(stree_unop_t));
+	if (unop == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	unop->uc = uc;
+	return unop;
+}
+
+/** Allocate new @c new operation.
+ *
+ * @return	New @c new operation
+ */
+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;
+}
+
+/** Allocate new .
+ *
+ * @return	New 
+ */
+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;
+}
+
+/** Allocate new function call operation.
+ *
+ * @return	New function call operation
+ */
+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;
+}
+
+/** Allocate new indexing operation.
+ *
+ * @return	New indexing operation
+ */
+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;
+}
+
+/** Allocate new as conversion.
+ *
+ * @return	New as conversion
+ */
+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;
+}
+
+/** Allocate new boxing operation.
+ *
+ * @return	New boxing operation
+ */
+stree_box_t *stree_box_new(void)
+{
+	stree_box_t *box_expr;
+
+	box_expr = calloc(1, sizeof(stree_box_t));
+	if (box_expr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return box_expr;
+}
+
+/** Allocate new name reference operation.
+ *
+ * @return	New name reference operation
+ */
+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;
+}
+
+/** Allocate new identifier.
+ *
+ * @return	New identifier
+ */
+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;
+}
+
+/** Allocate new literal.
+ *
+ * @param ltc	Literal class
+ * @return	New literal
+ */
+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;
+}
+
+/** Allocate new @c self reference.
+ *
+ * @return	New @c self reference
+ */
+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;
+}
+
+/** Allocate new type expression
+ *
+ * @return	New type expression
+ */
+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;
+}
+
+/** Allocate new type access operation.
+ *
+ * @return	New type access operation
+ */
+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;
+}
+
+/** Allocate new type application operation.
+ *
+ * @return	New type application operation
+ */
+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;
+}
+
+/** Allocate new type indexing operation.
+ *
+ * @return	New type indexing operation
+ */
+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;
+}
+
+/** Allocate new type literal.
+ *
+ * @return	New type literal
+ */
+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;
+}
+
+/** Allocate new type name reference.
+ *
+ * @return	New type name reference
+ */
+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;
+}
+
+/** Allocate new symbol.
+ *
+ * @return	New symbol
+ */
+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;
+}
+
+/** Allocate new program.
+ *
+ * @return	New program
+ */
+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.
+ *
+ * @param symbol	Symbol
+ * @param sac		Symbol attribute class
+ * @return		@c b_true if yes, @c b_false if no
+ */
+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.
+ *
+ * @param arg		Formal procedure argument
+ * @param aac		Argument attribute class
+ * @return		@c b_true if yes, @c b_false if no.
+ */
+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.
+ *
+ * XXX This does not work right with generics.
+ *
+ * @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;
+}
+
+/** Search for CSI type argument of the given name.
+ *
+ * @param csi		CSI to look in
+ * @param ident		Identifier of the type argument
+ * @return		Type argument declaration or @c NULL if not found
+ */
+stree_targ_t *stree_csi_find_targ(stree_csi_t *csi, stree_ident_t *ident)
+{
+	list_node_t *targ_n;
+	stree_targ_t *targ;
+
+	targ_n = list_first(&csi->targ);
+	while (targ_n != NULL) {
+		targ = list_node_data(targ_n, stree_targ_t *);
+		if (targ->name->sid == ident->sid)
+			return targ;
+
+		targ_n = list_next(&csi->targ, targ_n);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Search for enum member of the given name.
+ *
+ * @param enum_d	Enum to look in
+ * @param ident		Identifier of the enum member
+ * @return		Enum member declaration or @c NULL if not found
+ */
+stree_embr_t *stree_enum_find_mbr(stree_enum_t *enum_d, stree_ident_t *ident)
+{
+	list_node_t *embr_n;
+	stree_embr_t *embr;
+
+	embr_n = list_first(&enum_d->members);
+	while (embr_n != NULL) {
+		embr = list_node_data(embr_n, stree_embr_t *);
+		if (embr->name->sid == ident->sid)
+			return embr;
+
+		embr_n = list_next(&enum_d->members, embr_n);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Get CSI member name.
+ *
+ * @param csimbr	CSI member
+ * @return		Member name
+ */
+stree_ident_t *stree_csimbr_get_name(stree_csimbr_t *csimbr)
+{
+	stree_ident_t *mbr_name;
+
+	/* Keep compiler happy. */
+	mbr_name = NULL;
+
+	switch (csimbr->cc) {
+	case csimbr_csi: mbr_name = csimbr->u.csi->name; break;
+	case csimbr_ctor: mbr_name = csimbr->u.ctor->name; break;
+	case csimbr_deleg: mbr_name = csimbr->u.deleg->name; break;
+	case csimbr_enum: mbr_name = csimbr->u.enum_d->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;
+	}
+
+	return mbr_name;
+}
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stree.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,102 @@
+/*
+ * 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_ctor_t *stree_ctor_new(void);
+stree_deleg_t *stree_deleg_new(void);
+stree_enum_t *stree_enum_new(void);
+stree_embr_t *stree_embr_new(void);
+stree_fun_t *stree_fun_new(void);
+stree_var_t *stree_var_new(void);
+stree_prop_t *stree_prop_new(void);
+stree_targ_t *stree_targ_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_fun_sig_t *stree_fun_sig_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_break_t *stree_break_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_if_clause_t *stree_if_clause_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_unop_t *stree_unop_new(unop_class_t uc);
+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_box_t *stree_box_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);
+stree_targ_t *stree_csi_find_targ(stree_csi_t *csi, stree_ident_t *ident);
+stree_embr_t *stree_enum_find_mbr(stree_enum_t *enum_d, stree_ident_t *ident);
+stree_ident_t *stree_csimbr_get_name(stree_csimbr_t *csimbr);
+
+#endif
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stree_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,800 @@
+/*
+ * 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 "bigint_t.h"
+#include "list_t.h"
+#include "builtin_t.h"
+
+/*
+ * Arithmetic expressions
+ */
+
+struct stree_expr;
+
+/** Identifier */
+typedef struct {
+	int sid;
+	struct cspan *cspan;
+} stree_ident_t;
+
+/** Name reference */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	stree_ident_t *name;
+} stree_nameref_t;
+
+/** Boolean literal */
+typedef struct {
+	bool_t value;
+} stree_lit_bool_t;
+
+/** Character literal */
+typedef struct {
+	bigint_t value;
+} stree_lit_char_t;
+
+/** Integer literal */
+typedef struct {
+	bigint_t value;
+} stree_lit_int_t;
+
+/** Reference literal (there is only one: @c nil). */
+typedef struct {
+} stree_lit_ref_t;
+
+/** String literal */
+typedef struct {
+	char *value;
+} stree_lit_string_t;
+
+typedef enum {
+	ltc_bool,
+	ltc_char,
+	ltc_int,
+	ltc_ref,
+	ltc_string
+} literal_class_t;
+
+/** Literal */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	literal_class_t ltc;
+	union {
+		stree_lit_bool_t lit_bool;
+		stree_lit_char_t lit_char;
+		stree_lit_int_t lit_int;
+		stree_lit_ref_t lit_ref;
+		stree_lit_string_t lit_string;
+	} u;
+} stree_literal_t;
+
+/** Reference to currently active object. */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+} stree_self_ref_t;
+
+/** Binary operation class */
+typedef enum {
+	bo_equal,
+	bo_notequal,
+	bo_lt,
+	bo_gt,
+	bo_lt_equal,
+	bo_gt_equal,
+	bo_plus,
+	bo_minus,
+	bo_mult,
+	bo_and,
+	bo_or
+} binop_class_t;
+
+/** Unary operation class */
+typedef enum {
+	uo_plus,
+	uo_minus,
+	uo_not
+} unop_class_t;
+
+/** Binary operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Binary operation class */
+	binop_class_t bc;
+
+	/** Arguments */
+	struct stree_expr *arg1, *arg2;
+} stree_binop_t;
+
+/** Unary operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Operation class */
+	unop_class_t uc;
+
+	/** Argument */
+	struct stree_expr *arg;
+} stree_unop_t;
+
+/** New operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Type of object to construct. */
+	struct stree_texpr *texpr;
+
+	/** Constructor arguments */
+	list_t ctor_args; /* of stree_expr_t */
+} stree_new_t;
+
+/** Member access operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Argument */
+	struct stree_expr *arg;
+	/** Name of member being accessed. */
+	stree_ident_t *member_name;
+} stree_access_t;
+
+/** Function call operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** 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 {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	assign_class_t ac;
+	struct stree_expr *dest, *src;
+} stree_assign_t;
+
+/** Indexing operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Base */
+	struct stree_expr *base;
+
+	/** Arguments (indices) */
+	list_t args; /* of stree_expr_t */
+} stree_index_t;
+
+/** @c as conversion operation */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/** Expression to convert */
+	struct stree_expr *arg;
+
+	/** Destination type of conversion. */
+	struct stree_texpr *dtype;
+} stree_as_t;
+
+/** Boxing of primitive type (pseudo)
+ *
+ * This pseudo-node is used internally to box a value of primitive type.
+ * It is implicitly inserted by stype_convert(). It does not correspond
+ * to a an explicit program construct.
+ */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
+	/* Primitive type expression */
+	struct stree_expr *arg;
+} stree_box_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,
+	ec_box
+} expr_class_t;
+
+/** Arithmetic expression */
+typedef struct stree_expr {
+	expr_class_t ec;
+
+	/** Type of this expression or @c NULL if not typed yet */
+	struct tdata_item *titem;
+
+	/** Coordinate span */
+	struct cspan *cspan;
+
+	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;
+		stree_box_t *box;
+	} u;
+} stree_expr_t;
+
+/*
+ * Type expressions
+ */
+
+struct stree_texpr;
+
+/** Type literal class */
+typedef enum {
+	tlc_bool,
+	tlc_char,
+	tlc_int,
+	tlc_resource,
+	tlc_string
+} tliteral_class_t;
+
+/** Type literal */
+typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
+	tliteral_class_t tlc;
+} stree_tliteral_t;
+
+/** Type name reference */
+typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
+	stree_ident_t *name;
+} stree_tnameref_t;
+
+/** Type member access operation */
+typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
+	/** Argument */
+	struct stree_texpr *arg;
+
+	/** Name of member being accessed. */
+	stree_ident_t *member_name;
+} stree_taccess_t;
+
+/** Type application operation */
+typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
+	/* Base type */
+	struct stree_texpr *gtype;
+
+	/** (Formal) type arguments */
+	list_t targs; /* of stree_texpr_t */
+} stree_tapply_t;
+
+/** Type index operation */
+typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
+	/** 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;
+
+	/** Coordinate span */
+	struct cspan *cspan;
+
+	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;
+
+/** @c if or @c elif clause */
+typedef struct {
+	stree_expr_t *cond;
+	stree_block_t *block;
+} stree_if_clause_t;
+
+/** If statement */
+typedef struct {
+	/** If and elif clauses */
+	list_t if_clauses; /* of stree_if_clause_t */
+
+	/** Else 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;
+
+/** Break statement */
+typedef struct {
+} stree_break_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_break,
+	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_break_t *break_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;
+
+/** Function signature.
+ *
+ * Foormal parameters and return type. This is common to function and delegate
+ * delcarations.
+ */
+typedef struct {
+	/** 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;
+} stree_fun_sig_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;
+
+/** Constructor declaration */
+typedef struct stree_ctor {
+	/** Constructor 'name'. Points to the @c new keyword. */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** Signature (arguments, return type is always none) */
+	stree_fun_sig_t *sig;
+
+	/** Constructor implementation */
+	stree_proc_t *proc;
+
+	/** Type item describing the constructor */
+	struct tdata_item *titem;
+} stree_ctor_t;
+
+/** Delegate declaration */
+typedef struct stree_deleg {
+	/** Delegate name */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** Signature (arguments and return type) */
+	stree_fun_sig_t *sig;
+
+	/** Type item describing the delegate */
+	struct tdata_item *titem;
+} stree_deleg_t;
+
+/** Enum member */
+typedef struct stree_embr {
+	/** Enum containing this declaration */
+	struct stree_enum *outer_enum;
+
+	/** Enum member name */
+	stree_ident_t *name;
+} stree_embr_t;
+
+/** Enum declaration */
+typedef struct stree_enum {
+	/** Enum name */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** List of enum members */
+	list_t members; /* of stree_embr_t */
+
+	/** Type item describing the enum */
+	struct tdata_item *titem;
+} stree_enum_t;
+
+/** Member function declaration */
+typedef struct stree_fun {
+	/** Function name */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** Signature (arguments and return type) */
+	stree_fun_sig_t *sig;
+
+	/** Function implementation */
+	stree_proc_t *proc;
+
+	/** Type item describing the function */
+	struct tdata_item *titem;
+} 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.
+ */
+#define CTOR_IDENT "$ctor"
+#define INDEXER_IDENT "$indexer"
+
+typedef enum {
+	csimbr_csi,
+	csimbr_ctor,
+	csimbr_deleg,
+	csimbr_enum,
+	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_ctor_t *ctor;
+		stree_deleg_t *deleg;
+		stree_enum_t *enum_d;
+		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;
+
+/** CSI formal type argument */
+typedef struct stree_targ {
+	stree_ident_t *name;
+	struct stree_symbol *symbol;
+} stree_targ_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;
+
+	/** List of type arguments */
+	list_t targ; /* of stree_targ_t */
+
+	/** 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,
+	/* Enum declaration */
+	mc_enum
+} modm_class_t;
+
+/** Module member */
+typedef struct {
+	modm_class_t mc;
+	union {
+		stree_csi_t *csi;
+		stree_enum_t *enum_d;
+	} 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 {
+	/** CSI (class, struct or interface) */
+	sc_csi,
+	/** Constructor */
+	sc_ctor,
+	/** Member delegate */
+	sc_deleg,
+	/** Enum */
+	sc_enum,
+	/** Member function */
+	sc_fun,
+	/** Member variable */
+	sc_var,
+	/** Member property */
+	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_ctor_t *ctor;
+		stree_deleg_t *deleg;
+		stree_enum_t *enum_d;
+		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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/strtab.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,112 @@
+/*
+ * 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 point is that this deduplicates the strings. Using SID might actually
+ * not be such a big win.)
+ *
+ * The string table is a singleton as there will never be a need for
+ * more than one.
+ *
+ * Current implementation uses a linked list and thus it is slow.
+ */
+
+#include <stdlib.h>
+#include "mytypes.h"
+#include "os/os.h"
+#include "list.h"
+
+#include "strtab.h"
+
+static list_t str_list;
+
+/** Initialize string table. */
+void strtab_init(void)
+{
+	list_init(&str_list);
+}
+
+/** Get SID of a string.
+ *
+ * Return SID of @a str. If @a str is not in the string table yet,
+ * it is added and thus a new SID is assigned.
+ *
+ * @param str	String
+ * @return	SID of @a str.
+ */
+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;
+}
+
+/** Get string with the given SID.
+ *
+ * Returns string that has SID @a sid. If no such string exists, this
+ * causes a fatal error in the interpreter.
+ *
+ * @param sid	SID of the string.
+ * @return	Pointer to the string.
+ */
+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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/strtab.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/strtab_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stype.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1758 @@
+/*
+ * 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.
+ *
+ * If a type error is encountered, stype_note_error() is called to set
+ * the typing error flag.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "cspan.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_ctor(stype_t *stype, stree_ctor_t *ctor);
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor);
+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_fun_sig(stype_t *stype, stree_csi_t *outer_csi,
+    stree_fun_sig_t *sig, tdata_fun_sig_t **rtsig);
+static void stype_fun_body(stype_t *stype, stree_fun_t *fun);
+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_break(stype_t *stype, stree_break_t *break_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 stree_expr_t *stype_convert_tprimitive(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest);
+static stree_expr_t *stype_convert_tprim_tobj(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest);
+static stree_expr_t *stype_convert_tobject(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+static stree_expr_t *stype_convert_tarray(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+static stree_expr_t *stype_convert_tdeleg(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+static stree_expr_t *stype_convert_tfun_tdeleg(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest);
+static stree_expr_t *stype_convert_tvref(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+
+static bool_t stype_fun_sig_equal(stype_t *stype, tdata_fun_sig_t *asig,
+    tdata_fun_sig_t *sdig);
+
+/** Type module.
+ *
+ * If the module contains a type error, @a stype->error will be set
+ * when this function returns.
+ *
+ * @param stype		Static typing object
+ * @param module	Module to type
+ */
+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 *);
+
+		switch (mbr->mc) {
+		case mc_csi:
+			stype_csi(stype, mbr->u.csi);
+			break;
+		case mc_enum:
+			stype_enum(stype, mbr->u.enum_d);
+			break;
+		}
+
+		mbr_n = list_next(&module->members, mbr_n);
+	}
+}
+
+/** Type CSI.
+ *
+ * @param stype		Static typing object
+ * @param csi		CSI to type
+ */
+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_ctor: stype_ctor(stype, csimbr->u.ctor); break;
+		case csimbr_deleg: stype_deleg(stype, csimbr->u.deleg); break;
+		case csimbr_enum: stype_enum(stype, csimbr->u.enum_d); 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 a constructor.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+static void stype_ctor(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("'.\n");
+#endif
+	if (ctor->titem == NULL)
+		stype_ctor_header(stype, ctor);
+
+	stype_ctor_body(stype, ctor);
+}
+
+/** Type constructor header.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+void stype_ctor_header(stype_t *stype, stree_ctor_t *ctor)
+{
+	stree_symbol_t *ctor_sym;
+	tdata_item_t *ctor_ti;
+	tdata_fun_t *tfun;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' header.\n");
+#endif
+	if (ctor->titem != NULL)
+		return; /* Constructor header has already been typed. */
+
+	ctor_sym = ctor_to_symbol(ctor);
+
+	/* Type function signature. */
+	stype_fun_sig(stype, ctor_sym->outer_csi, ctor->sig, &tsig);
+
+	ctor_ti = tdata_item_new(tic_tfun);
+	tfun = tdata_fun_new();
+	ctor_ti->u.tfun = tfun;
+	tfun->tsig = tsig;
+
+	ctor->titem = ctor_ti;
+}
+
+/** Type constructor body.
+ *
+ * @param stype		Static typing object
+ * @param ctor		Constructor
+ */
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' body.\n");
+#endif
+	assert(stype->proc_vr == NULL);
+
+	stype->proc_vr = stype_proc_vr_new();
+	stype->proc_vr->proc = ctor->proc;
+	list_init(&stype->proc_vr->block_vr);
+
+	stype_block(stype, ctor->proc->body);
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
+}
+
+/** Type delegate.
+ *
+ * @param stype		Static typing object.
+ * @param deleg		Delegate to type.
+ */
+void stype_deleg(stype_t *stype, stree_deleg_t *deleg)
+{
+	stree_symbol_t *deleg_sym;
+	tdata_item_t *deleg_ti;
+	tdata_deleg_t *tdeleg;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type delegate '");
+	symbol_print_fqn(deleg_to_symbol(deleg));
+	printf("'.\n");
+#endif
+	if (deleg->titem == NULL) {
+		deleg_ti = tdata_item_new(tic_tdeleg);
+		deleg->titem = deleg_ti;
+		tdeleg = tdata_deleg_new();
+		deleg_ti->u.tdeleg = tdeleg;
+	} else {
+		deleg_ti = deleg->titem;
+		assert(deleg_ti->u.tdeleg != NULL);
+		tdeleg = deleg_ti->u.tdeleg;
+	}
+
+	if (tdeleg->tsig != NULL)
+		return; /* Delegate has already been typed. */
+
+	deleg_sym = deleg_to_symbol(deleg);
+
+	/* Type function signature. Store result in deleg->titem. */
+	stype_fun_sig(stype, deleg_sym->outer_csi, deleg->sig, &tsig);
+
+	tdeleg->deleg = deleg;
+	tdeleg->tsig = tsig;
+}
+
+/** Type enum.
+ *
+ * @param stype		Static typing object
+ * @param enum_d	Enum to type
+ */
+void stype_enum(stype_t *stype, stree_enum_t *enum_d)
+{
+	tdata_item_t *titem;
+	tdata_enum_t *tenum;
+
+	(void) stype;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type enum '");
+	symbol_print_fqn(enum_to_symbol(enum_d));
+	printf("'.\n");
+#endif
+	if (enum_d->titem == NULL) {
+		titem = tdata_item_new(tic_tenum);
+		tenum = tdata_enum_new();
+		titem->u.tenum = tenum;
+		tenum->enum_d = enum_d;
+
+		enum_d->titem = titem;
+	} else {
+		titem = enum_d->titem;
+	}
+}
+
+/** Type function.
+ *
+ * We split typing of function header and body because at the point we
+ * are typing the body of some function we may encounter function calls.
+ * To type a function call we first need to type the header of the function
+ * being called.
+ *
+ * @param stype		Static typing object.
+ * @param fun		Function to type.
+ */
+static void stype_fun(stype_t *stype, stree_fun_t *fun)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function '");
+	symbol_print_fqn(fun_to_symbol(fun));
+	printf("'.\n");
+#endif
+	if (fun->titem == NULL)
+		stype_fun_header(stype, fun);
+
+	stype_fun_body(stype, fun);
+}
+
+/** Type function header.
+ *
+ * Types the header of @a fun (but not its body).
+ *
+ * @param stype		Static typing object
+ * @param fun		Funtction
+ */
+void stype_fun_header(stype_t *stype, stree_fun_t *fun)
+{
+	stree_symbol_t *fun_sym;
+	tdata_item_t *fun_ti;
+	tdata_fun_t *tfun;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function '");
+	symbol_print_fqn(fun_to_symbol(fun));
+	printf("' header.\n");
+#endif
+	if (fun->titem != NULL)
+		return; /* Function header has already been typed. */
+
+	fun_sym = fun_to_symbol(fun);
+
+	/* Type function signature. */
+	stype_fun_sig(stype, fun_sym->outer_csi, fun->sig, &tsig);
+
+	fun_ti = tdata_item_new(tic_tfun);
+	tfun = tdata_fun_new();
+	fun_ti->u.tfun = tfun;
+	tfun->tsig = tsig;
+
+	fun->titem = fun_ti;
+}
+
+/** Type function signature.
+ *
+ * Types the function signature @a sig.
+ *
+ * @param stype		Static typing object
+ * @param outer_csi	CSI within which the signature is defined.
+ * @param sig		Function signature
+ */
+static void stype_fun_sig(stype_t *stype, stree_csi_t *outer_csi,
+    stree_fun_sig_t *sig, tdata_fun_sig_t **rtsig)
+{
+	list_node_t *arg_n;
+	stree_proc_arg_t *arg;
+	tdata_item_t *titem;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function signature.\n");
+#endif
+	tsig = tdata_fun_sig_new();
+
+	list_init(&tsig->arg_ti);
+
+	/*
+	 * Type formal arguments.
+	 */
+	arg_n = list_first(&sig->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) {
+			list_append(&tsig->arg_ti, NULL);
+			arg_n = list_next(&sig->args, arg_n);
+			continue;
+		}
+
+		run_texpr(stype->program, outer_csi, arg->type, &titem);
+		list_append(&tsig->arg_ti, titem);
+
+		arg_n = list_next(&sig->args, arg_n);
+	}
+
+	/* Variadic argument */
+	if (sig->varg != NULL) {
+		/* Check type and verify it is an array. */
+		run_texpr(stype->program, outer_csi, sig->varg->type, &titem);
+		tsig->varg_ti = titem;
+
+		if (titem->tic != tic_tarray && titem->tic != tic_ignore) {
+			printf("Error: Packed argument is not an array.\n");
+			stype_note_error(stype);
+		}
+	}
+
+	/* Return type */
+	if (sig->rtype != NULL) {
+		run_texpr(stype->program, outer_csi, sig->rtype, &titem);
+		tsig->rtype = titem;
+	}
+
+	*rtsig = tsig;
+}
+
+/** Type function body.
+ *
+ * Types the body of function @a fun (if it has one).
+ *
+ * @param stype		Static typing object
+ * @param fun		Funtction
+ */
+static void stype_fun_body(stype_t *stype, stree_fun_t *fun)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function '");
+	symbol_print_fqn(fun_to_symbol(fun));
+	printf("' body.\n");
+#endif
+	assert(stype->proc_vr == NULL);
+
+	/* 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.
+ *
+ * @param stype		Static typing object
+ * @param var		Member variable
+ */
+static void stype_var(stype_t *stype, stree_var_t *var)
+{
+	tdata_item_t *titem;
+
+	(void) stype;
+	(void) var;
+
+	run_texpr(stype->program, stype->current_csi, var->type,
+	    &titem);
+	if (titem->tic == tic_ignore) {
+		/* An error occured. */
+		stype_note_error(stype);
+		return;
+	}
+}
+
+/** Type property.
+ *
+ * @param stype		Static typing object
+ * @param prop		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.
+ *
+ * @param stype		Static typing object
+ * @param block		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 typing 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_break: stype_break(stype, stat->u.break_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 statement.
+ *
+ * @param stype		Static typing object
+ * @param vdecl_s	Variable delcaration statement
+ */
+static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s)
+{
+	stype_block_vr_t *block_vr;
+	stree_vdecl_t *old_vdecl;
+	tdata_item_t *titem;
+
+#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);
+	}
+
+	run_texpr(stype->program, stype->current_csi, vdecl_s->type,
+	    &titem);
+	if (titem->tic == tic_ignore) {
+		/* An error occured. */
+		stype_note_error(stype);
+		return;
+	}
+
+	intmap_set(&block_vr->vdecls, vdecl_s->name->sid, vdecl_s);
+}
+
+/** Type @c if statement.
+ *
+ * @param stype		Static typing object
+ * @param if_s		@c if statement
+ */
+static void stype_if(stype_t *stype, stree_if_t *if_s)
+{
+	stree_expr_t *ccond;
+	list_node_t *ifc_node;
+	stree_if_clause_t *ifc;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'if' statement.\n");
+#endif
+	ifc_node = list_first(&if_s->if_clauses);
+
+	/* Walk through all if/elif clauses. */
+
+	while (ifc_node != NULL) {
+		/* Get if/elif clause */
+		ifc = list_node_data(ifc_node, stree_if_clause_t *);
+
+		/* Convert condition to boolean type. */
+		stype_expr(stype, ifc->cond);
+		ccond = stype_convert(stype, ifc->cond,
+		    stype_boolean_titem(stype));
+
+		/* Patch code with augmented expression. */
+		ifc->cond = ccond;
+
+		/* Type the @c if/elif block */
+		stype_block(stype, ifc->block);
+
+		ifc_node = list_next(&if_s->if_clauses, ifc_node);
+	}
+
+	/* Type the @c else block */
+	if (if_s->else_block != NULL)
+		stype_block(stype, if_s->else_block);
+}
+
+/** Type @c while statement
+ *
+ * @param stype		Static typing object
+ * @param while_s	@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;
+
+	/* While is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
+	/* Type the body of the loop */
+	stype_block(stype, while_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
+}
+
+/** Type @c for statement.
+ *
+ * @param stype		Static typing object
+ * @param for_s		@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
+	/* For is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
+	stype_block(stype, for_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
+}
+
+/** Type @c raise statement.
+ *
+ * @param stype		Static typing object
+ * @param raise_s	@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 break statement */
+static void stype_break(stype_t *stype, stree_break_t *break_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'break' statement.\n");
+#endif
+	(void) break_s;
+
+	/* Check whether there is an active statement to break from. */
+	if (stype->proc_vr->bstat_cnt == 0) {
+		printf("Error: Break statement outside of while or for.\n");
+		stype_note_error(stype);
+	}
+}
+
+/** 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
+	if (return_s->expr != NULL)
+		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. */
+		if (fun->sig->rtype != NULL) {
+			run_texpr(stype->program, outer_sym->outer_csi,
+			    fun->sig->rtype, &dtype);
+
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "function returning value.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			dtype = NULL;
+
+			if (return_s->expr != NULL) {
+				printf("Error: Return with a value in "
+				    "value-less function.\n");
+				stype_note_error(stype);
+			}
+		}
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_sym);
+		assert(prop != NULL);
+
+		if (stype->proc_vr->proc == prop->getter) {
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "getter.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			if (return_s->expr == NULL) {
+				printf("Error: Return with a value 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);
+	}
+
+	if (dtype != NULL && return_s->expr != NULL) {
+		/* 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.
+ *
+ * @param stype		Static typing object
+ * @param exp_s		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.
+ *
+ * @param stype		Static typing object
+ * @param wef_s		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.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+	src = expr->titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert '");
+	tdata_item_print(src);
+	printf("' to '");
+	tdata_item_print(dest);
+	printf("'.\n");
+#endif
+
+	if (dest == NULL) {
+		printf("Error: Conversion destination is not valid.\n");
+		stype_note_error(stype);
+		return expr;
+	}
+
+	if (src == NULL) {
+		cspan_print(expr->cspan);
+		printf(" Error: Conversion source is not valid.\n");
+		stype_note_error(stype);
+		return expr;
+	}
+
+	if (dest->tic == tic_ignore || src->tic == tic_ignore)
+		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 == tic_tprimitive && dest->tic == tic_tobject) {
+		return stype_convert_tprim_tobj(stype, expr, dest);
+	}
+
+	if (src->tic == tic_tfun && dest->tic == tic_tdeleg) {
+		return stype_convert_tfun_tdeleg(stype, expr, dest);
+	}
+
+	if (src->tic == tic_tebase) {
+		stype_convert_failure(stype, expr, dest);
+		printf("Invalid use of reference to enum type in "
+		    "expression.\n");
+		return expr;
+	}
+
+	if (src->tic != dest->tic) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	switch (src->tic) {
+	case tic_tprimitive:
+		expr = stype_convert_tprimitive(stype, expr, dest);
+		break;
+	case tic_tobject:
+		expr = stype_convert_tobject(stype, expr, dest);
+		break;
+	case tic_tarray:
+		expr = stype_convert_tarray(stype, expr, dest);
+		break;
+	case tic_tdeleg:
+		expr = stype_convert_tdeleg(stype, expr, dest);
+		break;
+	case tic_tebase:
+		/* Conversion destination should never be enum-base */
+		assert(b_false);
+	case tic_tenum:
+		expr = stype_convert_tenum(stype, expr, dest);
+		break;
+	case tic_tfun:
+		assert(b_false);
+	case tic_tvref:
+		expr = stype_convert_tvref(stype, expr, dest);
+		break;
+	case tic_ignore:
+		assert(b_false);
+	}
+
+	return expr;
+}
+
+/** Convert expression of primitive type to primitive type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tprimitive(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert primitive type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tprimitive);
+	assert(dest->tic == tic_tprimitive);
+
+	/* Check if both have the same tprimitive class. */
+	if (src->u.tprimitive->tpc != dest->u.tprimitive->tpc)
+		stype_convert_failure(stype, expr, dest);
+
+	return expr;
+}
+
+/** Convert expression of primitive type to object type.
+ *
+ * This function implements autoboxing. It modifies the code by inserting
+ * the boxing operation.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tprim_tobj(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	builtin_t *bi;
+	stree_symbol_t *csi_sym;
+	stree_symbol_t *bp_sym;
+	stree_box_t *box;
+	stree_expr_t *bexpr;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert primitive type to object.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tprimitive);
+	assert(dest->tic == tic_tobject);
+
+	bi = stype->program->builtin;
+	csi_sym = csi_to_symbol(dest->u.tobject->csi);
+
+	switch (src->u.tprimitive->tpc) {
+	case tpc_bool: bp_sym = bi->boxed_bool; break;
+	case tpc_char: bp_sym = bi->boxed_char; break;
+	case tpc_int: bp_sym = bi->boxed_int; break;
+	case tpc_nil: assert(b_false);
+	case tpc_string: bp_sym = bi->boxed_string; break;
+	case tpc_resource:
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	/* Target type must be boxed @a src or Object */
+	if (csi_sym != bp_sym && csi_sym != bi->gf_class)
+		stype_convert_failure(stype, expr, dest);
+
+	/* Patch the code to box the primitive value */
+	box = stree_box_new();
+	box->arg = expr;
+	bexpr = stree_expr_new(ec_box);
+	bexpr->u.box = box;
+	bexpr->titem = dest;
+
+	/* No action needed to optionally convert boxed type to Object */
+
+	return bexpr;
+}
+
+/** Convert expression of object type to object type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tobject(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_item_t *cur;
+	stree_csi_t *cur_csi;
+	tdata_tvv_t *tvv;
+	tdata_item_t *b_ti, *bs_ti;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert object type.\n");
+#endif
+	list_node_t *ca_n, *da_n;
+	tdata_item_t *carg, *darg;
+
+	src = expr->titem;
+	assert(src->tic == tic_tobject);
+	assert(dest->tic == tic_tobject);
+
+	cur = src;
+
+	while (cur->u.tobject->csi != dest->u.tobject->csi) {
+
+		cur_csi = cur->u.tobject->csi;
+		stype_titem_to_tvv(stype, cur, &tvv);
+
+		if (cur_csi->base_csi_ref != NULL) {
+			run_texpr(stype->program, cur_csi, cur_csi->base_csi_ref, &b_ti);
+			if (b_ti->tic == tic_ignore) {
+				/* An error occured. */
+				stype_note_error(stype);
+				return expr;
+			}
+
+			tdata_item_subst(b_ti, tvv, &bs_ti);
+			cur = bs_ti;
+			assert(cur->tic == tic_tobject);
+
+		} else if (cur_csi->base_csi != NULL) {
+			/* No explicit reference. Use grandfather class. */
+			cur = tdata_item_new(tic_tobject);
+			cur->u.tobject = tdata_object_new();
+			cur->u.tobject->csi = cur_csi->base_csi;
+			cur->u.tobject->static_ref = b_false;
+
+			list_init(&cur->u.tobject->targs);
+		} else {
+			/* No match */
+			stype_convert_failure(stype, expr, dest);
+			return expr;
+		}
+	}
+
+	/* Verify that type arguments match */
+	ca_n = list_first(&cur->u.tobject->targs);
+	da_n = list_first(&dest->u.tobject->targs);
+
+	while (ca_n != NULL && da_n != NULL) {
+		carg = list_node_data(ca_n, tdata_item_t *);
+		darg = list_node_data(da_n, tdata_item_t *);
+
+		if (tdata_item_equal(carg, darg) != b_true) {
+			/* Diferent argument type */
+			stype_convert_failure(stype, expr, dest);
+			printf("Different argument type '");
+			tdata_item_print(carg);
+			printf("' vs. '");
+			tdata_item_print(darg);
+			printf("'.\n");
+			return expr;
+		}
+
+		ca_n = list_next(&cur->u.tobject->targs, ca_n);
+		da_n = list_next(&dest->u.tobject->targs, da_n);
+	}
+
+	if (ca_n != NULL || da_n != NULL) {
+		/* Diferent number of arguments */
+		stype_convert_failure(stype, expr, dest);
+		printf("Different number of arguments.\n");
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Convert expression of array type to array type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tarray(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert array type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tarray);
+	assert(dest->tic == tic_tarray);
+
+	/* Compare rank and base type. */
+	if (src->u.tarray->rank != dest->u.tarray->rank) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	/* XXX Should we convert each element? */
+	if (tdata_item_equal(src->u.tarray->base_ti,
+	    dest->u.tarray->base_ti) != b_true) {
+		stype_convert_failure(stype, expr, dest);
+	}
+
+	return expr;
+}
+
+/** Convert expression of delegate type to delegate type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tdeleg(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_deleg_t *sdeleg, *ddeleg;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert delegate type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tdeleg);
+	assert(dest->tic == tic_tdeleg);
+
+	sdeleg = src->u.tdeleg;
+	ddeleg = dest->u.tdeleg;
+
+	/*
+	 * XXX We need to redesign handling of generic types to handle
+	 * delegates in generic CSIs properly.
+	 */
+
+	/* Destination should never be anonymous delegate. */
+	assert(ddeleg->deleg != NULL);
+
+	/* Both must be the same delegate. */
+	if (sdeleg->deleg != ddeleg->deleg) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Convert expression of enum type to enum type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_enum_t *senum, *denum;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert enum type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tenum);
+	assert(dest->tic == tic_tenum);
+
+	senum = src->u.tenum;
+	denum = dest->u.tenum;
+
+	/*
+	 * XXX How should enum types interact with generics?
+	 */
+
+	/* Both must be of the same enum type (with the same declaration). */
+	if (senum->enum_d != denum->enum_d) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Convert expression of function type to delegate type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tfun_tdeleg(stype_t *stype,
+    stree_expr_t *expr, tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_fun_t *sfun;
+	tdata_deleg_t *ddeleg;
+	tdata_fun_sig_t *ssig, *dsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert delegate type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tfun);
+	assert(dest->tic == tic_tdeleg);
+
+	sfun = src->u.tfun;
+	ddeleg = dest->u.tdeleg;
+
+	ssig = sfun->tsig;
+	assert(ssig != NULL);
+	dsig = stype_deleg_get_sig(stype, ddeleg);
+	assert(dsig != NULL);
+
+	/* Signature type must match. */
+
+	if (!stype_fun_sig_equal(stype, ssig, dsig)) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	/*
+	 * XXX We should also compare attributes. Either the
+	 * tdeleg should be extended or we should get them
+	 * from stree_deleg.
+	 */
+
+	return expr;
+}
+
+
+/** Convert expression of variable type to variable type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tvref(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert variable type.\n");
+#endif
+	src = expr->titem;
+
+	/* Currently only allow if both types are the same. */
+	if (src->u.tvref->targ != dest->u.tvref->targ) {
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Display conversion error message and note error.
+ *
+ * @param stype		Static typing object
+ * @param expr		Original expression
+ * @param dest		Destination type
+ */
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	cspan_print(expr->cspan);
+	printf(" Error: Cannot convert ");
+	tdata_item_print(expr->titem);
+	printf(" to ");
+	tdata_item_print(dest);
+	printf(".\n");
+
+	stype_note_error(stype);
+}
+
+/** Box value.
+ *
+ * This function implements implicit boxing. It modifies the code by inserting
+ * the boxing operation.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @return		Modified expression.
+ */
+stree_expr_t *stype_box_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *src;
+	builtin_t *bi;
+	stree_symbol_t *bp_sym;
+	stree_box_t *box;
+	stree_expr_t *bexpr;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Boxing.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tprimitive);
+
+	bi = stype->program->builtin;
+
+	/* Make compiler happy. */
+	bp_sym = NULL;
+
+	switch (src->u.tprimitive->tpc) {
+	case tpc_bool: bp_sym = bi->boxed_bool; break;
+	case tpc_char: bp_sym = bi->boxed_char; break;
+	case tpc_int: bp_sym = bi->boxed_int; break;
+	case tpc_nil: assert(b_false);
+	case tpc_string: bp_sym = bi->boxed_string; break;
+	case tpc_resource:
+		cspan_print(expr->cspan);
+		printf(" Error: Cannot use ");
+		tdata_item_print(expr->titem);
+		printf(" as an object.\n");
+
+		stype_note_error(stype);
+		return expr;
+	}
+
+	/* Patch the code to box the primitive value */
+	box = stree_box_new();
+	box->arg = expr;
+	bexpr = stree_expr_new(ec_box);
+	bexpr->u.box = box;
+	bexpr->titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	bexpr->titem->u.tobject = tobject;
+
+	tobject->csi = symbol_to_csi(bp_sym);
+	assert(tobject->csi != NULL);
+
+	return bexpr;
+}
+
+
+
+/** Determine if two type signatures are equal.
+ *
+ * XXX This does not compare the attributes, which are missing from
+ * @c tdata_fun_sig_t.
+ *
+ * @param stype		Static typing object
+ * @param asig		First function signature type
+ * @param bsig		Second function signature type
+ */
+static bool_t stype_fun_sig_equal(stype_t *stype, tdata_fun_sig_t *asig,
+    tdata_fun_sig_t *bsig)
+{
+	list_node_t *aarg_n, *barg_n;
+	tdata_item_t *aarg_ti, *barg_ti;
+
+	(void) stype;
+
+	/* Compare types of arguments */
+	aarg_n = list_first(&asig->arg_ti);
+	barg_n = list_first(&bsig->arg_ti);
+
+	while (aarg_n != NULL && barg_n != NULL) {
+		aarg_ti = list_node_data(aarg_n, tdata_item_t *);
+		barg_ti = list_node_data(barg_n, tdata_item_t *);
+
+		if (!tdata_item_equal(aarg_ti, barg_ti))
+			return b_false;
+
+		aarg_n = list_next(&asig->arg_ti, aarg_n);
+		barg_n = list_next(&bsig->arg_ti, barg_n);
+	}
+
+	if (aarg_n != NULL || barg_n != NULL)
+		return b_false;
+
+	/* Compare variadic argument */
+
+	if (asig->varg_ti != NULL || bsig->varg_ti != NULL) {
+		if (asig->varg_ti == NULL ||
+		    bsig->varg_ti == NULL) {
+			return b_false;
+		}
+
+		if (!tdata_item_equal(asig->varg_ti, bsig->varg_ti)) {
+			return b_false;
+		}
+	}
+
+	/* Compare return type */
+	if (!tdata_item_equal(asig->rtype, bsig->rtype))
+		return b_false;
+
+	return b_true;
+}
+
+/** Get function signature from delegate.
+ *
+ * Function signature can be missing if the delegate type is incomplete.
+ * This is used to break circular dependency when typing delegates.
+ * If this happens, we type the delegate, which gives us the signature.
+ */
+tdata_fun_sig_t *stype_deleg_get_sig(stype_t *stype, tdata_deleg_t *tdeleg)
+{
+	if (tdeleg->tsig == NULL)
+		stype_deleg(stype, tdeleg->deleg);
+
+	/* Now we should have a signature. */
+	assert(tdeleg->tsig != NULL);
+	return tdeleg->tsig;
+}
+
+/** Convert tic_tobject type item to TVV,
+ *
+ * We split generic type application into two steps. In the first step
+ * we match argument names of @a ti->csi to argument values in @a ti
+ * to produce a TVV (name to value map for type arguments). That is the
+ * purpose of this function.
+ *
+ * In the second step we substitute variables in another type item
+ * with their values using the TVV. This is performed by tdata_item_subst().
+ *
+ * @param stype		Static typing object.
+ * @param ti		Type item of class tic_tobject.
+ * @param rtvv		Place to store pointer to new TVV.
+ */
+void stype_titem_to_tvv(stype_t *stype, tdata_item_t *ti, tdata_tvv_t **rtvv)
+{
+	tdata_tvv_t *tvv;
+	stree_csi_t *csi;
+
+	list_node_t *formal_n;
+	list_node_t *real_n;
+
+	stree_targ_t *formal_arg;
+	tdata_item_t *real_arg;
+
+	assert(ti->tic == tic_tobject);
+
+	tvv = tdata_tvv_new();
+	intmap_init(&tvv->tvv);
+
+	csi = ti->u.tobject->csi;
+	formal_n = list_first(&csi->targ);
+	real_n = list_first(&ti->u.tobject->targs);
+
+	while (formal_n != NULL && real_n != NULL) {
+		formal_arg = list_node_data(formal_n, stree_targ_t *);
+		real_arg = list_node_data(real_n, tdata_item_t *);
+
+		/* Store argument value into valuation. */
+		tdata_tvv_set_val(tvv, formal_arg->name->sid, real_arg);
+
+		formal_n = list_next(&csi->targ, formal_n);
+		real_n = list_next(&ti->u.tobject->targs, real_n);
+	}
+
+	if (formal_n != NULL || real_n != NULL) {
+		printf("Error: Incorrect number of type arguments.\n");
+		stype_note_error(stype);
+
+		/* Fill missing arguments with recovery type items. */
+		while (formal_n != NULL) {
+			formal_arg = list_node_data(formal_n, stree_targ_t *);
+			/* Store recovery value into valuation. */
+			tdata_tvv_set_val(tvv, formal_arg->name->sid,
+			    stype_recovery_titem(stype));
+
+			formal_n = list_next(&csi->targ, formal_n);
+		}
+	}
+
+	*rtvv = tvv;
+}
+
+/** Return a boolean type item.
+ *
+ * @param stype		Static typing object
+ * @return		New boolean type item.
+ */
+tdata_item_t *stype_boolean_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_bool);
+	titem->u.tprimitive = tprimitive;
+
+	return titem;
+}
+
+/** Find a local variable in the current function.
+ *
+ * @param stype		Static typing object
+ * @param name		Name of variable (SID).
+ * @return		Pointer to variable declaration or @c NULL if not
+ *			found.
+ */
+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.
+ *
+ * @param stype		Static typing object
+ * @param name		Name of argument (SID).
+ * @return		Pointer to argument declaration or @c NULL if not
+ *			found.
+ */
+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_ctor_t *ctor;
+	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
+
+	/* Make compiler happy. */
+	args = NULL;
+	varg = NULL;
+
+	switch (outer_sym->sc) {
+	case sc_ctor:
+		ctor = symbol_to_ctor(outer_sym);
+		assert(ctor != NULL);
+		args = &ctor->sig->args;
+		varg = ctor->sig->varg;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(outer_sym);
+		assert(fun != NULL);
+		args = &fun->sig->args;
+		varg = fun->sig->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;
+	case sc_csi:
+	case sc_deleg:
+	case sc_enum:
+	case sc_var:
+		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.
+ *
+ * @param stype		Static typing object
+ */
+void stype_note_error(stype_t *stype)
+{
+	stype->error = b_true;
+}
+
+/** Construct a special type item for recovery.
+ *
+ * The recovery item is propagated towards the expression root and causes
+ * any further typing errors in the expression to be supressed.
+ *
+ * @param stype		Static typing object
+ */
+tdata_item_t *stype_recovery_titem(stype_t *stype)
+{
+	tdata_item_t *titem;
+
+	(void) stype;
+
+	titem = tdata_item_new(tic_ignore);
+	return titem;
+}
+
+/** Get current block visit record.
+ *
+ * @param stype		Static typing object
+ */
+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 *);
+}
+
+/** Allocate new procedure visit record.
+ *
+ * @return	New procedure VR
+ */
+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;
+}
+
+/** Allocate new block visit record.
+ *
+ * @return	New block 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stype.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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.
+ */
+
+#ifndef STYPE_H_
+#define STYPE_H_
+
+#include "mytypes.h"
+
+void stype_module(stype_t *stype, stree_module_t *module);
+void stype_ctor_header(stype_t *stype, stree_ctor_t *ctor);
+void stype_deleg(stype_t *stype, stree_deleg_t *deleg);
+void stype_enum(stype_t *stype, stree_enum_t *enum_d);
+void stype_fun_header(stype_t *stype, stree_fun_t *fun);
+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_expr_t *stype_box_expr(stype_t *stype, stree_expr_t *expr);
+
+tdata_fun_sig_t *stype_deleg_get_sig(stype_t *stype, tdata_deleg_t *tdeleg);
+
+void stype_titem_to_tvv(stype_t *stype, tdata_item_t *ti, tdata_tvv_t **rtvv);
+
+tdata_item_t *stype_boolean_titem(stype_t *stype);
+
+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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stype_expr.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,1728 @@
+/*
+ * 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 Typing of expressions.
+ *
+ * This module types (data) expressions -- not to be confused with evaluating
+ * type expressions! Thus the type of each (sub-)expression is determined
+ * and stored in its @c titem field.
+ *
+ * It can also happen that, due to implicit conversions, the expression
+ * needs to be patched to insert these conversions.
+ *
+ * If a type error occurs within an expression, @c stype->error is set
+ * and the type of the expression will be @c tic_ignore. This type item
+ * is propagated upwards and causes further typing errors to be ignored
+ * (this prevents a type error avalanche). Type checking is thus resumed
+ * at the next expression.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "cspan.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_bool(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_char(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_int(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_nil(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_string(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_resource(stype_t *stype, stree_binop_t *binop,
+    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_binop_tenum(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+static void stype_binop_tvref(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_unop_tprimitive(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t *ta, tdata_item_t **rtitem);
+static void stype_new(stype_t *stype, stree_new_t *new,
+    tdata_item_t **rtitem);
+static void stype_new_object_args(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t *obj_ti);
+
+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_tebase(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_call_args(stype_t *stype, cspan_t *cspan, list_t *farg_tis,
+    tdata_item_t *fvarg_ti, list_t *args);
+
+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_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);
+static void stype_box(stype_t *stype, stree_box_t *box, tdata_item_t **rtitem);
+
+
+/** Type expression
+ *
+ * The type is stored in @a expr->titem. If the express contains a type error,
+ * @a stype->error will be set when this function returns.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ */
+void stype_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *et;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(expr->cspan);
+	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;
+	case ec_box: stype_box(stype, expr->u.box, &et); break;
+	}
+
+	expr->titem = et;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(expr->cspan);
+	printf(" Expression type is '");
+	tdata_item_print(et);
+	printf("'.\n");
+#endif
+}
+
+/** Type name reference.
+ *
+ * @param stype		Static typing object
+ * @param nameref	Name reference
+ * @param rtitem	Place to store result type
+ */
+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_deleg_t *deleg;
+	stree_enum_t *enum_d;
+	tdata_ebase_t *tebase;
+	stree_fun_t *fun;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(nameref->expr->cspan);
+	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) {
+			cspan_print(nameref->expr->cspan);
+			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 {
+			cspan_print(nameref->expr->cspan);
+			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_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_deleg:
+		deleg = symbol_to_deleg(sym);
+		assert(deleg != NULL);
+		/* Type delegate if it has not been typed yet. */
+		stype_deleg(stype, deleg);
+		titem = deleg->titem;
+		break;
+	case sc_enum:
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+
+		titem = tdata_item_new(tic_tebase);
+		tebase = tdata_ebase_new();
+		titem->u.tebase = tebase;
+
+		/* This is an enum base reference. */
+		tebase->enum_d = enum_d;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(sym);
+		assert(fun != NULL);
+		/* Type function header if it has not been typed yet. */
+		stype_fun_header(stype, fun);
+		titem = fun->titem;
+		break;
+	}
+
+	*rtitem = titem;
+}
+
+/** Type a literal.
+ *
+ * @param stype		Static typing object
+ * @param literal	Literal
+ * @param rtitem	Place to store result type
+ */
+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
+	cspan_print(literal->expr->cspan);
+	printf(" Evaluate type of literal.\n");
+#endif
+	(void) stype;
+
+	switch (literal->ltc) {
+	case ltc_bool: tpc = tpc_bool; break;
+	case ltc_char: tpc = tpc_char; break;
+	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 @c self reference.
+ *
+ * @param stype		Static typing object
+ * @param self_ref	@c self reference
+ * @param rtitem	Place to store result type
+ */
+static void stype_self_ref(stype_t *stype, stree_self_ref_t *self_ref,
+    tdata_item_t **rtitem)
+{
+	stree_csi_t *cur_csi;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(self_ref->expr->cspan);
+	printf(" Evaluate type of self reference.\n");
+#endif
+	(void) stype;
+	(void) self_ref;
+
+	cur_csi = stype->proc_vr->proc->outer_symbol->outer_csi;
+
+	/* No global symbols should have procedures. */
+	assert(cur_csi != NULL);
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = cur_csi;
+	list_init(&tobject->targs);
+
+	*rtitem = titem;
+}
+
+/** Type a binary operation.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	bool_t equal;
+	tdata_item_t *titem1, *titem2;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(binop->expr->cspan);
+	printf(" Evaluate type of binary operation.\n");
+#endif
+	stype_expr(stype, binop->arg1);
+	stype_expr(stype, binop->arg2);
+
+	titem1 = binop->arg1->titem;
+	titem2 = binop->arg2->titem;
+
+	if (titem1 == NULL) {
+		cspan_print(binop->arg1->cspan);
+		printf(" Error: Binary operand has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if (titem2 == NULL) {
+		cspan_print(binop->arg2->cspan);
+		printf(" Error: Binary operand has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if (titem1->tic == tic_ignore || titem2->tic == tic_ignore) {
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	equal = tdata_item_equal(titem1, titem2);
+	if (equal != b_true) {
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation arguments "
+		    "have different types ('");
+		tdata_item_print(titem1);
+		printf("' and '");
+		tdata_item_print(titem2);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	switch (titem1->tic) {
+	case tic_tprimitive:
+		stype_binop_tprimitive(stype, binop, titem1, titem2, rtitem);
+		break;
+	case tic_tobject:
+		stype_binop_tobject(stype, binop, titem1, titem2, rtitem);
+		break;
+	case tic_tenum:
+		stype_binop_tenum(stype, binop, titem1, titem2, rtitem);
+		break;
+	case tic_tvref:
+		stype_binop_tvref(stype, binop, titem1, titem2, rtitem);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation on value which is not of a "
+		    "supported type (found '");
+		tdata_item_print(titem1);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+
+}
+
+/** Type a binary operation with arguments of primitive type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result 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)
+{
+	assert(ta->tic == tic_tprimitive);
+	assert(tb->tic == tic_tprimitive);
+
+	switch (ta->u.tprimitive->tpc) {
+	case tpc_bool:
+		stype_binop_bool(stype, binop, rtitem);
+		break;
+	case tpc_char:
+		stype_binop_char(stype, binop, rtitem);
+		break;
+	case tpc_int:
+		stype_binop_int(stype, binop, rtitem);
+		break;
+	case tpc_nil:
+		stype_binop_nil(stype, binop, rtitem);
+		break;
+	case tpc_string:
+		stype_binop_string(stype, binop, rtitem);
+		break;
+	case tpc_resource:
+		stype_binop_resource(stype, binop, rtitem);
+		break;
+	}
+}
+
+/** Type a binary operation with @c bool arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_bool(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+		/* Comparison -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		/* Arithmetic -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on booleans.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	case bo_and:
+	case bo_or:
+		/* Boolean -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with @c char arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_char(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+		/* Comparison -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+	case bo_and:
+	case bo_or:
+		/* Arithmetic, boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on characters.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		rtpc = tpc_char;
+		break;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with @c int arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_int(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+		/* Comparison -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		/* Arithmetic -> int type */
+		rtpc = tpc_int;
+		break;
+	case bo_and:
+	case bo_or:
+		/* Boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on integers.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		rtpc = tpc_char;
+		break;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with @c nil arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_nil(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	(void) binop;
+
+	cspan_print(binop->expr->cspan);
+	printf(" Unimplemented: Binary operation on nil.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type a binary operation with @c string arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_string(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	case bo_plus:
+		/* Concatenation -> string type */
+		rtpc = tpc_string;
+		break;
+
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+
+	case bo_minus:
+	case bo_mult:
+	case bo_and:
+	case bo_or:
+		/* Ordering, arithmetic, boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on strings.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		rtpc = tpc_char;
+		break;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with resource arguments.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_resource(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) binop;
+
+	cspan_print(binop->expr->cspan);
+	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 with arguments of an object type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result 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 type */
+		res_ti = stype_boolean_titem(stype);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on objects.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with arguments of an enum type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_tenum(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	assert(ta->tic == tic_tenum);
+	assert(tb->tic == tic_tenum);
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		res_ti = stype_boolean_titem(stype);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on values of enum "
+		    "type.\n", binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with arguments of a variable type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_tvref(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	assert(ta->tic == tic_tvref || (ta->tic == tic_tprimitive &&
+	    ta->u.tprimitive->tpc == tpc_nil));
+	assert(tb->tic == tic_tvref || (tb->tic == tic_tprimitive &&
+	    tb->u.tprimitive->tpc == tpc_nil));
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		res_ti = stype_boolean_titem(stype);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on variable types.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+/** Type a unary operation.
+ *
+ * @param stype		Static typing object
+ * @param unop		Unary operation
+ * @param rtitem	Place to store result type
+*/
+static void stype_unop(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(unop->expr->cspan);
+	printf(" Evaluate type of unary operation.\n");
+#endif
+	stype_expr(stype, unop->arg);
+
+	titem = unop->arg->titem;
+
+	if (titem->tic == tic_ignore) {
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	switch (titem->tic) {
+	case tic_tprimitive:
+		stype_unop_tprimitive(stype, unop, titem, rtitem);
+		break;
+	default:
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Unary operation on value which is not of a "
+		    "supported type (found '");
+		tdata_item_print(titem);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+}
+
+/** Type a binary operation arguments of primitive type.
+ *
+ * @param stype		Static typing object
+ * @param unop		Binary operation
+ * @param ta		Type of argument
+ * @param rtitem	Place to store result type
+ */
+static void stype_unop_tprimitive(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t *ta, tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) stype;
+	(void) unop;
+
+	assert(ta->tic == tic_tprimitive);
+
+	switch (ta->u.tprimitive->tpc) {
+	case tpc_bool:
+		rtpc = tpc_bool;
+		break;
+	case tpc_int:
+		rtpc = tpc_int;
+		break;
+	default:
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Unary operator applied on unsupported "
+		    "primitive type %d.\n", ta->u.tprimitive->tpc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a @c new operation.
+ *
+ * @param stype		Static typing object
+ * @param new_op	@c new operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_new(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(new_op->expr->cspan);
+	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);
+
+	if ((*rtitem)->tic == tic_ignore) {
+		/* An error occured when evaluating the type expression. */
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if ((*rtitem)->tic == tic_tobject)
+		stype_new_object_args(stype, new_op, *rtitem);
+}
+
+/** Type a new object operation arguments.
+ *
+ * @param stype		Static typing object
+ * @param new_op	@c new operation
+ */
+static void stype_new_object_args(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t *obj_ti)
+{
+	stree_csi_t *csi;
+	stree_ctor_t *ctor;
+	stree_symbol_t *ctor_sym;
+	stree_ident_t *ctor_ident;
+	tdata_fun_sig_t *tsig;
+
+	assert(obj_ti->tic == tic_tobject);
+	csi = obj_ti->u.tobject->csi;
+	ctor_ident = stree_ident_new();
+	ctor_ident->sid = strtab_get_sid(CTOR_IDENT);
+
+	/* Find constructor. */
+	ctor_sym = symbol_search_csi_no_base(stype->program, csi,
+	    ctor_ident);
+
+	if (ctor_sym == NULL && !list_is_empty(&new_op->ctor_args)) {
+		cspan_print(new_op->expr->cspan);
+		printf(" Error: Passing arguments to 'new' but no "
+		    "constructor found.\n");
+		stype_note_error(stype);
+		return;
+	}
+
+	if (ctor_sym == NULL)
+		return;
+
+	ctor = symbol_to_ctor(ctor_sym);
+	assert(ctor != NULL);
+
+	/* Type constructor header if it has not been typed yet. */
+	stype_ctor_header(stype, ctor);
+	if (ctor->titem->tic == tic_ignore)
+		return;
+
+	assert(ctor->titem->tic == tic_tfun);
+	tsig = ctor->titem->u.tfun->tsig;
+
+	stype_call_args(stype, new_op->expr->cspan, &tsig->arg_ti,
+	    tsig->varg_ti, &new_op->ctor_args);
+}
+
+/** Type a member access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_access(stype_t *stype, stree_access_t *access,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *arg_ti;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(access->expr->cspan);
+	printf(" Evaluate type of access operation.\n");
+#endif
+	stype_expr(stype, access->arg);
+	arg_ti = access->arg->titem;
+
+	if (arg_ti == NULL) {
+		cspan_print(access->arg->cspan);
+		printf(" Error: Argument of access operation 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_tdeleg:
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on a delegate.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tebase:
+		stype_access_tebase(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tenum:
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on expression of enum "
+		    "type.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tfun:
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on a function.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tvref:
+		/* Cannot allow this without some constraint. */
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on generic data.\n");
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_ignore:
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+}
+
+/** Type a primitive type access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param arg_ti	Base type
+ * @param rtitem	Place to store result type
+ */
+static void stype_access_tprimitive(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) arg_ti;
+
+	/* Box the value. */
+	access->arg = stype_box_expr(stype, access->arg);
+	if (access->arg->titem->tic == tic_ignore) {
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	/* Access the boxed object. */
+	stype_access_tobject(stype, access, access->arg->titem, rtitem);
+}
+
+/** Type an object access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param arg_ti	Base type
+ * @param rtitem	Place to store result type
+*/
+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_enum_t *enum_d;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+	tdata_object_t *tobject;
+	tdata_item_t *mtitem;
+	tdata_tvv_t *tvv;
+
+#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. */
+		cspan_print(access->member_name->cspan);
+		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));
+		stype_note_error(stype);
+		*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:
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Accessing object member which is nested "
+		    "CSI.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_deleg:
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Accessing object member which is a "
+		    "delegate.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	case sc_enum:
+		enum_d = symbol_to_enum(member_sym);
+		assert(enum_d != NULL);
+		/* Type enum if it has not been typed yet. */
+		stype_enum(stype, enum_d);
+		mtitem = enum_d->titem;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(member_sym);
+		assert(fun != NULL);
+		/* Type function header now */
+		stype_fun_header(stype, fun);
+		mtitem = fun->titem;
+		break;
+	case sc_var:
+		var = symbol_to_var(member_sym);
+		assert(var != NULL);
+		run_texpr(stype->program, member_sym->outer_csi,
+		    var->type, &mtitem);
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(member_sym);
+		assert(prop != NULL);
+		run_texpr(stype->program, member_sym->outer_csi,
+		    prop->type, &mtitem);
+		break;
+	}
+
+	/*
+	 * Substitute type arguments in member titem.
+	 *
+	 * Since the CSI can be generic the actual type of the member
+	 * is obtained by substituting our type arguments into the
+	 * (generic) type of the member.
+	 */
+
+	stype_titem_to_tvv(stype, arg_ti, &tvv);
+	tdata_item_subst(mtitem, tvv, rtitem);
+}
+
+/** Type an array access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param arg_ti	Base type
+ * @param rtitem	Place to store result type
+ */
+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;
+
+	cspan_print(access->arg->cspan);
+	printf(" Error: Unimplemented: Accessing array type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	stype_note_error(stype);
+	*rtitem = stype_recovery_titem(stype);
+}
+
+/** Type an enum access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param arg_ti	Base type
+ * @param rtitem	Place to store result type
+*/
+static void stype_access_tebase(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	tdata_ebase_t *tebase;
+	tdata_enum_t *tenum;
+	tdata_item_t *mtitem;
+	stree_embr_t *embr;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type an ebase access operation.\n");
+#endif
+	assert(arg_ti->tic == tic_tebase);
+	tebase = arg_ti->u.tebase;
+
+	/* Look for a member with the specified name. */
+	embr = stree_enum_find_mbr(tebase->enum_d, access->member_name);
+
+	if (embr == NULL) {
+		/* No such member found. */
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Enum type '");
+		symbol_print_fqn(enum_to_symbol(tebase->enum_d));
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	mtitem = tdata_item_new(tic_tenum);
+	tenum = tdata_enum_new();
+	mtitem->u.tenum = tenum;
+	tenum->enum_d = tebase->enum_d;
+
+	*rtitem = mtitem;
+}
+
+
+/** Type a call operation.
+ *
+ * @param stype		Static typing object
+ * @param call		Call operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_call(stype_t *stype, stree_call_t *call,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *fun_ti;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(call->expr->cspan);
+	printf(" Evaluate type of call operation.\n");
+#endif
+	/* Type the function */
+	stype_expr(stype, call->fun);
+
+	/* Check type item class */
+	fun_ti = call->fun->titem;
+	switch (fun_ti->tic) {
+	case tic_tdeleg:
+		tsig = stype_deleg_get_sig(stype, fun_ti->u.tdeleg);
+		assert(tsig != NULL);
+		break;
+	case tic_tfun:
+		tsig = fun_ti->u.tfun->tsig;
+		break;
+	case tic_ignore:
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	default:
+		cspan_print(call->fun->cspan);
+		printf(" Error: Calling something which is not a function ");
+		printf("(found '");
+		tdata_item_print(fun_ti);
+		printf("').\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	/* Type call arguments. */
+	stype_call_args(stype, call->expr->cspan, &tsig->arg_ti, tsig->varg_ti,
+	    &call->args);
+
+	if (tsig->rtype != NULL) {
+		/* XXX Might be better to clone here. */
+		*rtitem = tsig->rtype;
+	} else {
+		*rtitem = NULL;
+	}
+}
+
+/** Type call arguments.
+ *
+ * Type arguments in call to a function or constructor.
+ *
+ * @param stype		Static typing object
+ * @param cpsan		Cspan to print in case of error.
+ * @param farg_tis	Formal argument types (list of tdata_item_t)
+ * @param args		Real arguments (list of stree_expr_t)
+ */
+static void stype_call_args(stype_t *stype, cspan_t *cspan, list_t *farg_tis,
+    tdata_item_t *fvarg_ti, list_t *args)
+{
+	list_node_t *fargt_n;
+	tdata_item_t *farg_ti;
+	tdata_item_t *varg_ti;
+
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	stree_expr_t *carg;
+
+	int cnt;
+
+	/* Type and check regular arguments. */
+	fargt_n = list_first(farg_tis);
+	arg_n = list_first(args);
+
+	cnt = 0;
+	while (fargt_n != NULL && arg_n != NULL) {
+		farg_ti = list_node_data(fargt_n, tdata_item_t *);
+		arg = list_node_data(arg_n, stree_expr_t *);
+		stype_expr(stype, arg);
+
+		/* XXX Because of overloaded bultin WriteLine */
+		if (farg_ti == NULL) {
+			/* Skip the check */
+			fargt_n = list_next(farg_tis, fargt_n);
+			arg_n = list_next(args, arg_n);
+			continue;
+		}
+
+		/* 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);
+
+		fargt_n = list_next(farg_tis, fargt_n);
+		arg_n = list_next(args, arg_n);
+	}
+
+	/* Type and check variadic arguments. */
+	if (fvarg_ti != NULL) {
+		/* Obtain type of packed argument. */
+		farg_ti = fvarg_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(args, arg_n);
+		}
+	}
+
+	if (fargt_n != NULL) {
+		cspan_print(cspan);
+		printf(" Error: Too few arguments.\n");
+		stype_note_error(stype);
+	}
+
+	if (arg_n != NULL) {
+		cspan_print(cspan);
+		printf(" Error: Too many arguments.\n");
+		stype_note_error(stype);
+	}
+}
+
+/** Type an indexing operation.
+ *
+ * @param stype		Static typing object
+ * @param index		Indexing operation
+ * @param rtitem	Place to store result type
+ */
+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
+	cspan_print(index->expr->cspan);
+	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_tdeleg:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing a delegate.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tebase:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing an enum declaration.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tenum:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing an enum value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tfun:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing a function.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tvref:
+		/* Cannot allow this without some constraint. */
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing generic data.\n");
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_ignore:
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	}
+}
+
+/** Type a primitive indexing operation.
+ *
+ * @param stype		Static typing object
+ * @param index		Indexing operation
+ * @param base_ti	Base type (primitive being indexed)
+ * @param rtitem	Place to store result type
+ */
+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_char);
+		*rtitem = titem;
+		return;
+	}
+
+	cspan_print(index->base->cspan);
+	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.
+ *
+ * @param stype		Static typing object
+ * @param index		Indexing operation
+ * @param base_ti	Base type (object being indexed)
+ * @param rtitem	Place to store result type
+ */
+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;
+	tdata_item_t *mtitem;
+	tdata_tvv_t *tvv;
+
+	(void) index;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(index->expr->cspan);
+	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) {
+		cspan_print(index->base->cspan);
+		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, &mtitem);
+
+	/*
+	 * Substitute type arguments in member titem.
+	 *
+	 * Since the CSI can be generic the actual type of the member
+	 * is obtained by substituting our type arguments into the
+	 * (generic) type of the member.
+	 */
+
+	stype_titem_to_tvv(stype, base_ti, &tvv);
+	tdata_item_subst(mtitem, tvv, rtitem);
+}
+
+/** Type an array indexing operation.
+ *
+ * @param stype		Static typing object
+ * @param index		Indexing operation
+ * @param base_ti	Base type (array being indexed)
+ * @param rtitem	Place to store result type
+ */
+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) {
+
+			cspan_print(arg->cspan);
+			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) {
+		cspan_print(index->expr->cspan);
+		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 an assignment.
+ *
+ * @param stype		Static typing object
+ * @param assign	Assignment operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_assign(stype_t *stype, stree_assign_t *assign,
+    tdata_item_t **rtitem)
+{
+	stree_expr_t *csrc;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(assign->expr->cspan);
+	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.
+ *
+ * @param stype		Static typing object
+ * @param as_op		@c as conversion operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_as(stype_t *stype, stree_as_t *as_op, tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(as_op->expr->cspan);
+	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) {
+		cspan_print(as_op->dtype->cspan);
+		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;
+}
+
+/** Type boxing operation.
+ *
+ * While there is no boxing operation on the first typing pass, we do want
+ * to allow potential re-evaluation (with same results).
+ *
+ * @param stype		Static typing object
+ * @param box		Boxing operation
+ * @param rtitem	Place to store result type
+ */
+static void stype_box(stype_t *stype, stree_box_t *box, tdata_item_t **rtitem)
+{
+	tdata_item_t *ptitem, *btitem;
+	tdata_object_t *tobject;
+	stree_symbol_t *csi_sym;
+	builtin_t *bi;
+
+#ifdef DEBUG_TYPE_TRACE
+	cspan_print(box->expr->cspan);
+	printf(" Evaluate type of boxing operation.\n");
+#endif
+	bi = stype->program->builtin;
+
+	stype_expr(stype, box->arg);
+	ptitem = box->arg->titem;
+
+        /* Make compiler happy. */
+	csi_sym = NULL;
+
+	assert(ptitem->tic == tic_tprimitive);
+	switch (ptitem->u.tprimitive->tpc) {
+	case tpc_bool: csi_sym = bi->boxed_bool; break;
+	case tpc_char: csi_sym = bi->boxed_char; break;
+	case tpc_int: csi_sym = bi->boxed_int; break;
+	case tpc_nil: assert(b_false);
+	case tpc_string: csi_sym = bi->boxed_string; break;
+	case tpc_resource: assert(b_false);
+	}
+
+	btitem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+
+	btitem->u.tobject = tobject;
+	tobject->static_ref = b_false;
+	tobject->csi = symbol_to_csi(csi_sym);
+	assert(tobject->csi != NULL);
+	list_init(&tobject->targs);
+
+	*rtitem = btitem;
+}
Index: uspace/app/sbi/src/stype_expr.h
===================================================================
--- uspace/app/sbi/src/stype_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stype_expr.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/stype_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,80 @@
+/*
+ * 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 */
+
+	/** Number of active breakable statements (for break checking). */
+	int bstat_cnt;
+} 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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/symbol.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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.
+ */
+
+/** @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_symbol_t *csimbr_to_symbol(stree_csimbr_t *csimbr);
+static stree_ident_t *symbol_get_ident(stree_symbol_t *symbol);
+
+/** Lookup symbol in CSI using a type expression.
+ *
+ * XXX This should be removed in favor of full type expression evaluation
+ * (run_texpr). This cannot work properly with generics.
+ *
+ * @param prog		Program
+ * @param scope		CSI used as base for relative references
+ * @param texpr		Type expression
+ *
+ * @return		Symbol referenced by type expression or @c NULL
+ *			if not found
+ */
+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:
+		return symbol_xlookup_in_csi(prog, scope,
+		    texpr->u.tapply->gtype);
+	default:
+		assert(b_false);
+	}
+}
+
+/** Lookup symbol reference in CSI.
+ *
+ * XXX These functions should take just an sid, not a full identifier.
+ * Sometimes we search for a name which has no associated cspan.
+ *
+ * @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.)
+ *
+ * @param prog	Program to look in
+ * @param scope CSI in which to look
+ * @param name	Identifier of the symbol
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+stree_symbol_t *symbol_search_csi(stree_program_t *prog,
+    stree_csi_t *scope, stree_ident_t *name)
+{
+	stree_symbol_t *base_csi_sym;
+	stree_csi_t *base_csi;
+	stree_symbol_t *symbol;
+
+	/* Look in new members in this class. */
+	symbol = symbol_search_csi_no_base(prog, scope, name);
+	if (symbol != NULL)
+		return symbol;
+
+	/* 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;
+}
+
+/** Look for symbol strictly in CSI.
+ *
+ * Look for symbol in definition of a CSI and its ancestors. (But not
+ * in lexically enclosing CSI or in base CSI.)
+ *
+ * @param prog	Program to look in
+ * @param scope CSI in which to look
+ * @param name	Identifier of the symbol
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+stree_symbol_t *symbol_search_csi_no_base(stree_program_t *prog,
+    stree_csi_t *scope, stree_ident_t *name)
+{
+	list_node_t *node;
+	stree_csimbr_t *csimbr;
+	stree_ident_t *mbr_name;
+
+	(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 *);
+		mbr_name = stree_csimbr_get_name(csimbr);
+
+		if (name->sid == mbr_name->sid) {
+			/* Match */
+			return csimbr_to_symbol(csimbr);
+		}
+
+		node = list_next(&scope->members, node);
+	}
+	/* No match */
+	return NULL;
+}
+
+/** Look for symbol in global scope.
+ *
+ * @param prog	Program to look in
+ * @param name	Identifier of the symbol
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+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;
+	stree_ident_t *mbr_name;
+
+	node = list_first(&prog->module->members);
+	while (node != NULL) {
+		modm = list_node_data(node, stree_modm_t *);
+
+		switch (modm->mc) {
+		case mc_csi: mbr_name = modm->u.csi->name; break;
+		case mc_enum: mbr_name = modm->u.enum_d->name; break;
+		}
+
+		if (name->sid == mbr_name->sid) {
+			/* Match */
+			switch (modm->mc) {
+			case mc_csi:
+				symbol = csi_to_symbol(modm->u.csi);
+				break;
+			case mc_enum:
+				symbol = enum_to_symbol(modm->u.enum_d);
+				break;
+			}
+			return symbol;
+		}
+		node = list_next(&prog->module->members, node);
+	}
+
+	return NULL;
+}
+
+/** Find entry point.
+ *
+ * Perform a walk of all CSIs and look for a function with the name @a name.
+ *
+ * @param prog	Program to look in
+ * @param name	Name of entry point
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+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;
+}
+
+/** Find entry point under CSI.
+ *
+ * Internal part of symbol_find_epoint() that recursively walks CSIs.
+ *
+ * @param prog	Program to look in
+ * @param name	Name of entry point
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+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;
+}
+
+/*
+ * The notion of symbol is designed as a common base class for several
+ * types of declarations with global and CSI scope. Here we simulate
+ * conversion from this base class (symbol) to derived classes (CSI,
+ * fun, ..) and vice versa.
+ */
+
+/** Convert symbol to delegate (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Delegate or @c NULL if symbol is not a delegate
+ */
+stree_deleg_t *symbol_to_deleg(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_deleg)
+		return NULL;
+
+	return symbol->u.deleg;
+}
+
+/** Convert delegate to symbol (derived to base).
+ *
+ * @param deleg		Delegate
+ * @return		Symbol
+ */
+stree_symbol_t *deleg_to_symbol(stree_deleg_t *deleg)
+{
+	assert(deleg->symbol);
+	return deleg->symbol;
+}
+
+/** Convert symbol to enum (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Enum or @c NULL if symbol is not a enum
+ */
+stree_enum_t *symbol_to_enum(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_enum)
+		return NULL;
+
+	return symbol->u.enum_d;
+}
+
+/** Convert enum to symbol (derived to base).
+ *
+ * @param deleg		Enum
+ * @return		Symbol
+ */
+stree_symbol_t *enum_to_symbol(stree_enum_t *enum_d)
+{
+	assert(enum_d->symbol);
+	return enum_d->symbol;
+}
+
+/** Convert symbol to CSI (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		CSI or @c NULL if symbol is not a CSI
+ */
+stree_csi_t *symbol_to_csi(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_csi)
+		return NULL;
+
+	return symbol->u.csi;
+}
+
+/** Convert CSI to symbol (derived to base).
+ *
+ * @param csi		CSI
+ * @return		Symbol
+ */
+stree_symbol_t *csi_to_symbol(stree_csi_t *csi)
+{
+	assert(csi->symbol);
+	return csi->symbol;
+}
+
+/** Convert symbol to constructor (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Constructor or @c NULL if symbol is not a constructor
+ */
+stree_ctor_t *symbol_to_ctor(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_ctor)
+		return NULL;
+
+	return symbol->u.ctor;
+}
+
+/** Convert constructor to symbol (derived to base).
+ *
+ * @param ctor		Constructor
+ * @return		Symbol
+ */
+stree_symbol_t *ctor_to_symbol(stree_ctor_t *ctor)
+{
+	assert(ctor->symbol);
+	return ctor->symbol;
+}
+
+
+/** Convert symbol to function (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Function or @c NULL if symbol is not a function
+ */
+stree_fun_t *symbol_to_fun(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_fun)
+		return NULL;
+
+	return symbol->u.fun;
+}
+
+/** Convert function to symbol (derived to base).
+ *
+ * @param fun		Function
+ * @return		Symbol
+ */
+stree_symbol_t *fun_to_symbol(stree_fun_t *fun)
+{
+	assert(fun->symbol);
+	return fun->symbol;
+}
+
+/** Convert symbol to member variable (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Variable or @c NULL if symbol is not a member variable
+ */
+stree_var_t *symbol_to_var(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_var)
+		return NULL;
+
+	return symbol->u.var;
+}
+
+/** Convert variable to symbol (derived to base).
+ *
+ * @param fun		Variable
+ * @return		Symbol
+ */
+stree_symbol_t *var_to_symbol(stree_var_t *var)
+{
+	assert(var->symbol);
+	return var->symbol;
+}
+
+/** Convert symbol to property (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Property or @c NULL if symbol is not a property
+ */
+stree_prop_t *symbol_to_prop(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_prop)
+		return NULL;
+
+	return symbol->u.prop;
+}
+
+/** Get symbol from CSI member.
+ *
+ * A symbol corresponds to any CSI member. Return it.
+ *
+ * @param csimbr	CSI member
+ * @return		Symbol
+ */
+static stree_symbol_t *csimbr_to_symbol(stree_csimbr_t *csimbr)
+{
+	stree_symbol_t *symbol;
+
+	/* Keep compiler happy. */
+	symbol = NULL;
+
+	/* Match */
+	switch (csimbr->cc) {
+	case csimbr_csi:
+		symbol = csi_to_symbol(csimbr->u.csi);
+		break;
+	case csimbr_ctor:
+		symbol = ctor_to_symbol(csimbr->u.ctor);
+		break;
+	case csimbr_deleg:
+		symbol = deleg_to_symbol(csimbr->u.deleg);
+		break;
+	case csimbr_enum:
+		symbol = enum_to_symbol(csimbr->u.enum_d);
+		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;
+	}
+
+	return symbol;
+}
+
+
+/** Convert property to symbol (derived to base).
+ *
+ * @param fun		Property
+ * @return		Symbol
+ */
+stree_symbol_t *prop_to_symbol(stree_prop_t *prop)
+{
+	assert(prop->symbol);
+	return prop->symbol;
+}
+
+/** Print fully qualified name of symbol.
+ *
+ * @param symbol	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));
+}
+
+/** Return symbol identifier.
+ *
+ * @param symbol	Symbol
+ * @return 		Symbol identifier
+ */
+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_ctor: ident = symbol->u.ctor->name; break;
+	case sc_deleg: ident = symbol->u.deleg->name; break;
+	case sc_enum: ident = symbol->u.enum_d->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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/symbol.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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.
+ */
+
+#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_search_csi_no_base(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_deleg_t *symbol_to_deleg(stree_symbol_t *symbol);
+stree_symbol_t *deleg_to_symbol(stree_deleg_t *deleg);
+stree_csi_t *symbol_to_csi(stree_symbol_t *symbol);
+stree_symbol_t *csi_to_symbol(stree_csi_t *csi);
+stree_ctor_t *symbol_to_ctor(stree_symbol_t *symbol);
+stree_symbol_t *ctor_to_symbol(stree_ctor_t *ctor);
+stree_enum_t *symbol_to_enum(stree_symbol_t *symbol);
+stree_symbol_t *enum_to_symbol(stree_enum_t *enum_d);
+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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/tdata.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,841 @@
+/*
+ * 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 "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "stree.h"
+#include "strtab.h"
+#include "symbol.h"
+
+#include "tdata.h"
+
+static void tdata_item_subst_tprimitive(tdata_primitive_t *torig,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tobject(tdata_object_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res);
+static void tdata_item_subst_tarray(tdata_array_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res);
+static void tdata_item_subst_tdeleg(tdata_deleg_t *torig,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tebase(tdata_ebase_t *tebase,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tenum(tdata_enum_t *tenum,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tfun(tdata_fun_t *torig,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tvref(tdata_vref_t *tvref, tdata_tvv_t *tvv,
+    tdata_item_t **res);
+
+static void tdata_item_subst_fun_sig(tdata_fun_sig_t *torig, tdata_tvv_t *tvv,
+    tdata_fun_sig_t **res);
+
+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_tdeleg_print(tdata_deleg_t *tdeleg);
+static void tdata_tebase_print(tdata_ebase_t *tebase);
+static void tdata_tenum_print(tdata_enum_t *tenum);
+static void tdata_tfun_print(tdata_fun_t *tfun);
+static void tdata_tvref_print(tdata_vref_t *tvref);
+
+/** Determine if CSI @a a is derived from CSI described by type item @a tb.
+ *
+ * XXX This won't work with generics.
+ *
+ * @param a	Potential derived CSI.
+ * @param tb	Type of potentail base CSI.
+ */
+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.
+ *
+ * XXX This is somewhat complementary to stype_convert(). It is used for
+ * the explicit @c as conversion. It should only work for objects and only
+ * allow conversion from base to derived types. We might want to scrap this
+ * for a version specific to @c as. The current code does not work with
+ * generics.
+ *
+ * @param a	Potential derived CSI.
+ * @param tb	Type of potentail base CSI.
+ */
+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).
+ *
+ * Needed to check compatibility of type arguments in which a parametrized
+ * type is not monotonous.
+ *
+ * @param a	Type item
+ * @param b	Type item
+ * @return	@c b_true if equal, @c b_false if not.
+ */
+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);
+	case tic_tenum:
+		/* Check if both use the same enum definition. */
+		return (a->u.tenum->enum_d == b->u.tenum->enum_d);
+	case tic_tvref:
+		/* Check if both refer to the same type argument. */
+		return (a->u.tvref->targ == b->u.tvref->targ);
+	default:
+		printf("Warning: Unimplemented: Compare types '");
+		tdata_item_print(a);
+		printf("' and '");
+		tdata_item_print(b);
+		printf("'.\n");
+		return b_true;
+	}
+}
+
+/** Substitute type variables in a type item.
+ *
+ * This is the second part of generic type application. In the first part
+ * obtained a TVV using stype_titem_to_tvv() and in this second part we
+ * actually substitute type variables in a type item for their values.
+ * @a tvv must contain all variables referenced in @a ti.
+ *
+ * @param ti	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+void tdata_item_subst(tdata_item_t *ti, tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	switch (ti->tic) {
+	case tic_tprimitive:
+		tdata_item_subst_tprimitive(ti->u.tprimitive, tvv, res);
+		break;
+	case tic_tobject:
+		tdata_item_subst_tobject(ti->u.tobject, tvv, res);
+		break;
+	case tic_tarray:
+		tdata_item_subst_tarray(ti->u.tarray, tvv, res);
+		break;
+	case tic_tdeleg:
+		tdata_item_subst_tdeleg(ti->u.tdeleg, tvv, res);
+		break;
+	case tic_tebase:
+		tdata_item_subst_tebase(ti->u.tebase, tvv, res);
+		break;
+	case tic_tenum:
+		tdata_item_subst_tenum(ti->u.tenum, tvv, res);
+		break;
+	case tic_tfun:
+		tdata_item_subst_tfun(ti->u.tfun, tvv, res);
+		break;
+	case tic_tvref:
+		tdata_item_subst_tvref(ti->u.tvref, tvv, res);
+		break;
+	case tic_ignore:
+		*res = tdata_item_new(tic_ignore);
+	}
+}
+
+/** Substitute type variables in a primitive type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tprimitive(tdata_primitive_t *torig,
+    tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	tdata_primitive_t *tnew;
+
+	(void) tvv;
+
+	/* Plain copy */
+	tnew = tdata_primitive_new(torig->tpc);
+	*res = tdata_item_new(tic_tprimitive);
+	(*res)->u.tprimitive = tnew;
+}
+
+/** Substitute type variables in an object type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tobject(tdata_object_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res)
+{
+	tdata_object_t *tnew;
+	list_node_t *targ_n;
+	tdata_item_t *targ;
+	tdata_item_t *new_targ;
+
+	/* Copy static ref flag and base CSI. */
+	tnew = tdata_object_new();
+	tnew->static_ref = torig->static_ref;
+	tnew->csi = torig->csi;
+	list_init(&tnew->targs);
+
+	/* Substitute arguments */
+	targ_n = list_first(&torig->targs);
+	while (targ_n != NULL) {
+		targ = list_node_data(targ_n, tdata_item_t *);
+		tdata_item_subst(targ, tvv, &new_targ);
+		list_append(&tnew->targs, new_targ);
+
+		targ_n = list_next(&torig->targs, targ_n);
+	}
+
+	*res = tdata_item_new(tic_tobject);
+	(*res)->u.tobject = tnew;
+}
+
+/** Substitute type variables in an array type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tarray(tdata_array_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res)
+{
+	tdata_array_t *tnew;
+	list_node_t *ext_n;
+	stree_expr_t *extent;
+
+	tnew = tdata_array_new();
+
+	/* Substitute base type */
+	tdata_item_subst(torig->base_ti, tvv, &tnew->base_ti);
+
+	/* Copy rank and extents */
+	tnew->rank = torig->rank;
+	list_init(&tnew->extents);
+
+	ext_n = list_first(&torig->extents);
+	while (ext_n != NULL) {
+		extent = list_node_data(ext_n, stree_expr_t *);
+		list_append(&tnew->extents, extent);
+
+		ext_n = list_next(&tnew->extents, ext_n);
+	}
+
+	*res = tdata_item_new(tic_tarray);
+	(*res)->u.tarray = tnew;
+}
+
+/** Substitute type variables in a delegate type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tdeleg(tdata_deleg_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res)
+{
+	tdata_deleg_t *tnew;
+
+	tnew = tdata_deleg_new();
+	tnew->deleg = torig->deleg;
+	tdata_item_subst_fun_sig(torig->tsig, tvv, &tnew->tsig);
+
+	*res = tdata_item_new(tic_tdeleg);
+	(*res)->u.tdeleg = tnew;
+}
+
+/** Substitute type variables in a enum-base type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tebase(tdata_ebase_t *tebase,
+    tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	tdata_ebase_t *tnew;
+
+	(void) tvv;
+
+	/* Plain copy */
+	tnew = tdata_ebase_new();
+	*res = tdata_item_new(tic_tebase);
+	(*res)->u.tebase = tebase;
+}
+
+/** Substitute type variables in a enum type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tenum(tdata_enum_t *tenum,
+    tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	tdata_enum_t *tnew;
+
+	(void) tvv;
+
+	/* Plain copy */
+	tnew = tdata_enum_new();
+	*res = tdata_item_new(tic_tenum);
+	(*res)->u.tenum = tenum;
+}
+
+/** Substitute type variables in a functional type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tfun(tdata_fun_t *torig, tdata_tvv_t *tvv,
+    tdata_item_t **res)
+{
+	tdata_fun_t *tnew;
+
+	tnew = tdata_fun_new();
+	tdata_item_subst_fun_sig(torig->tsig, tvv, &tnew->tsig);
+
+	*res = tdata_item_new(tic_tfun);
+	(*res)->u.tfun = tnew;
+}
+
+/** Substitute type variables in a type-variable reference item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tvref(tdata_vref_t *tvref, tdata_tvv_t *tvv,
+    tdata_item_t **res)
+{
+	tdata_item_t *ti_new;
+
+	ti_new = tdata_tvv_get_val(tvv, tvref->targ->name->sid);
+	assert(ti_new != NULL);
+
+	/* XXX Might be better to clone here. */
+	*res = ti_new;
+}
+
+/** Substitute type variables in a function signature type fragment.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_fun_sig(tdata_fun_sig_t *torig, tdata_tvv_t *tvv,
+    tdata_fun_sig_t **res)
+{
+	tdata_fun_sig_t *tnew;
+	list_node_t *arg_n;
+	tdata_item_t *arg_ti;
+	tdata_item_t *narg_ti;
+
+	tnew = tdata_fun_sig_new();
+
+	/* Substitute type of each argument */
+	list_init(&tnew->arg_ti);
+	arg_n = list_first(&torig->arg_ti);
+	while (arg_n != NULL) {
+		arg_ti = list_node_data(arg_n, tdata_item_t *);
+
+		/* XXX Because of overloaded Builtin.WriteLine */
+		if (arg_ti == NULL)
+			narg_ti = NULL;
+		else
+			tdata_item_subst(arg_ti, tvv, &narg_ti);
+
+		list_append(&tnew->arg_ti, narg_ti);
+
+		arg_n = list_next(&torig->arg_ti, arg_n);
+	}
+
+	/* Substitute type of variadic argument */
+	if (torig->varg_ti != NULL)
+		tdata_item_subst(torig->varg_ti, tvv, &tnew->varg_ti);
+
+	/* Substitute return type */
+	if (torig->rtype != NULL)
+		tdata_item_subst(torig->rtype, tvv, &tnew->rtype);
+
+	*res = tnew;
+}
+
+
+/** Print type item.
+ *
+ * @param titem	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_tdeleg:
+		tdata_tdeleg_print(titem->u.tdeleg);
+		break;
+	case tic_tebase:
+		tdata_tebase_print(titem->u.tebase);
+		break;
+	case tic_tenum:
+		tdata_tenum_print(titem->u.tenum);
+		break;
+	case tic_tfun:
+		tdata_tfun_print(titem->u.tfun);
+		break;
+	case tic_tvref:
+		tdata_tvref_print(titem->u.tvref);
+		break;
+	case tic_ignore:
+		printf("ignore");
+		break;
+	}
+}
+
+/** Print primitive type item.
+ *
+ * @param tprimitive	Primitive type item
+ */
+static void tdata_tprimitive_print(tdata_primitive_t *tprimitive)
+{
+	switch (tprimitive->tpc) {
+	case tpc_bool: printf("bool"); break;
+	case tpc_char: printf("char"); break;
+	case tpc_int: printf("int"); break;
+	case tpc_nil: printf("nil"); break;
+	case tpc_string: printf("string"); break;
+	case tpc_resource: printf("resource"); break;
+	}
+}
+
+/** Print object type item.
+ *
+ * @param tobject	Object type item
+ */
+static void tdata_tobject_print(tdata_object_t *tobject)
+{
+	stree_symbol_t *csi_sym;
+	list_node_t *arg_n;
+	tdata_item_t *arg;
+
+	csi_sym = csi_to_symbol(tobject->csi);
+	assert(csi_sym != NULL);
+	symbol_print_fqn(csi_sym);
+
+	arg_n = list_first(&tobject->targs);
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, tdata_item_t *);
+		putchar('/');
+		tdata_item_print(arg);
+		arg_n = list_next(&tobject->targs, arg_n);
+	}
+}
+
+/** Print array type item.
+ *
+ * @param tarray	Array type item
+ */
+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("]");
+}
+
+/** Print delegate type item.
+ *
+ * @param tdeleg	Delegate type item
+ */
+static void tdata_tdeleg_print(tdata_deleg_t *tdeleg)
+{
+	stree_symbol_t *deleg_sym;
+
+	deleg_sym = deleg_to_symbol(tdeleg->deleg);
+	symbol_print_fqn(deleg_sym);
+}
+
+/** Print enum-base type item.
+ *
+ * @param tebase		Enum-base type item
+ */
+static void tdata_tebase_print(tdata_ebase_t *tebase)
+{
+	stree_symbol_t *enum_sym;
+
+	enum_sym = enum_to_symbol(tebase->enum_d);
+
+	printf("typeref(");
+	symbol_print_fqn(enum_sym);
+	printf(")");
+}
+
+/** Print enum type item.
+ *
+ * @param tenum		Enum type item
+ */
+static void tdata_tenum_print(tdata_enum_t *tenum)
+{
+	stree_symbol_t *enum_sym;
+
+	enum_sym = enum_to_symbol(tenum->enum_d);
+	symbol_print_fqn(enum_sym);
+}
+
+/** Print function type item.
+ *
+ * @param tfun		Function type item
+ */
+static void tdata_tfun_print(tdata_fun_t *tfun)
+{
+	list_node_t *arg_n;
+	tdata_item_t *arg_ti;
+	bool_t first;
+
+	printf("fun(");
+
+	arg_n = list_first(&tfun->tsig->arg_ti);
+	first = b_true;
+	while (arg_n != NULL) {
+		if (first == b_false)
+			printf("; ");
+		else
+			first = b_false;
+
+		arg_ti = list_node_data(arg_n, tdata_item_t *);
+		tdata_item_print(arg_ti);
+
+		arg_n = list_next(&tfun->tsig->arg_ti, arg_n);
+	}
+
+	printf(") : ");
+	tdata_item_print(tfun->tsig->rtype);
+}
+
+/** Print type variable reference type item.
+ *
+ * @param tvref		Type variable reference type item
+ */
+static void tdata_tvref_print(tdata_vref_t *tvref)
+{
+	printf("%s", strtab_get_str(tvref->targ->name->sid));
+}
+
+/** Allocate new type item.
+ *
+ * @param tic	Type item class
+ * @return	New type item
+ */
+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;
+}
+
+/** Allocate new array type item.
+ *
+ * @return	New array type item
+ */
+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;
+}
+
+/** Allocate new object type item.
+ *
+ * @return	New object type item
+ */
+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;
+}
+
+/** Allocate new primitive type item.
+ *
+ * @return	New primitive type item
+ */
+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;
+}
+
+/** Allocate new delegate type item.
+ *
+ * @return	New function type item
+ */
+tdata_deleg_t *tdata_deleg_new(void)
+{
+	tdata_deleg_t *tdeleg;
+
+	tdeleg = calloc(1, sizeof(tdata_deleg_t));
+	if (tdeleg == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tdeleg;
+}
+
+/** Allocate new enum-base type item.
+ *
+ * @return	New enum type item
+ */
+tdata_ebase_t *tdata_ebase_new(void)
+{
+	tdata_ebase_t *tebase;
+
+	tebase = calloc(1, sizeof(tdata_ebase_t));
+	if (tebase == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tebase;
+}
+
+/** Allocate new enum type item.
+ *
+ * @return	New enum type item
+ */
+tdata_enum_t *tdata_enum_new(void)
+{
+	tdata_enum_t *tenum;
+
+	tenum = calloc(1, sizeof(tdata_enum_t));
+	if (tenum == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tenum;
+}
+
+/** Allocate new functional type item.
+ *
+ * @return	New function type item
+ */
+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;
+}
+
+/** Allocate new type variable reference type item.
+ *
+ * @return	New type variable reference type item
+ */
+tdata_vref_t *tdata_vref_new(void)
+{
+	tdata_vref_t *tvref;
+
+	tvref = calloc(1, sizeof(tdata_vref_t));
+	if (tvref == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tvref;
+}
+
+/** Allocate new function signature type fragment.
+ *
+ * @return	New function signature type fragment
+ */
+tdata_fun_sig_t *tdata_fun_sig_new(void)
+{
+	tdata_fun_sig_t *tfun_sig;
+
+	tfun_sig = calloc(1, sizeof(tdata_fun_sig_t));
+	if (tfun_sig == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tfun_sig;
+}
+
+/** Create a new type variable valuation.
+ *
+ * @retrun	New type variable valuation
+ */
+tdata_tvv_t *tdata_tvv_new(void)
+{
+	tdata_tvv_t *tvv;
+
+	tvv = calloc(1, sizeof(tdata_tvv_t));
+	if (tvv == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tvv;
+}
+
+/** Get type variable value.
+ *
+ * Looks up value of the variable with name SID @a name in type
+ * variable valuation @a tvv.
+ *
+ * @param tvv		Type variable valuation
+ * @param name		Name of the variable (SID)
+ * @return		Value of the type variable (type item) or @c NULL
+ *			if not defined in @a tvv
+ */
+tdata_item_t *tdata_tvv_get_val(tdata_tvv_t *tvv, sid_t name)
+{
+	return (tdata_item_t *)intmap_get(&tvv->tvv, name);
+}
+
+/** Set type variable value.
+ *
+ * Sets the value of variable with name SID @a name in type variable
+ * valuation @a tvv to the value @a tvalue.
+ *
+ * @param tvv		Type variable valuation
+ * @param name		Name of the variable (SID)
+ * @param tvalue	Value to set (type item) or @c NULL to unset
+ */
+void tdata_tvv_set_val(tdata_tvv_t *tvv, sid_t name, tdata_item_t *tvalue)
+{
+	intmap_set(&tvv->tvv, name, tvalue);
+}
Index: uspace/app/sbi/src/tdata.h
===================================================================
--- uspace/app/sbi/src/tdata.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/tdata.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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 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_deleg_t *tdata_deleg_new(void);
+tdata_ebase_t *tdata_ebase_new(void);
+tdata_enum_t *tdata_enum_new(void);
+tdata_fun_t *tdata_fun_new(void);
+tdata_vref_t *tdata_vref_new(void);
+
+tdata_fun_sig_t *tdata_fun_sig_new(void);
+
+tdata_tvv_t *tdata_tvv_new(void);
+tdata_item_t *tdata_tvv_get_val(tdata_tvv_t *tvv, sid_t name);
+void tdata_tvv_set_val(tdata_tvv_t *tvv, sid_t name, tdata_item_t *tvalue);
+
+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_subst(tdata_item_t *ti, tdata_tvv_t *tvv, tdata_item_t **res);
+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 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/sbi/src/tdata_t.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,181 @@
+/*
+ * 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_
+
+#include "intmap_t.h"
+
+/** Class of primitive type. */
+typedef enum {
+	/** Boolean type */
+	tpc_bool,
+	/** Character type */
+	tpc_char,
+	/** 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;
+
+	/** (Real) type arguments */
+	list_t targs; /* of tdata_item_t */
+} 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;
+
+/** Function signature type.
+ *
+ * This is a part of functional type or delegate type.
+ */
+typedef struct {
+	/** Types of fixed arguments. */
+	list_t arg_ti; /* of tdata_item_t */
+
+	/** Type of variadic argument */
+	struct tdata_item *varg_ti;
+
+	/** Return type */
+	struct tdata_item *rtype;
+} tdata_fun_sig_t;
+
+/** Delegate type. */
+typedef struct {
+	/** Delegate definition or @c NULL if anonymous delegate */
+	struct stree_deleg *deleg;
+
+	/** Delegate signature type */
+	tdata_fun_sig_t *tsig;
+} tdata_deleg_t;
+
+/** Enum-base type.
+ *
+ * Type for expression which reference an enum declaration. In run time
+ * enum type reference is represented by @c rdata_deleg_t. (Which is used
+ * for any symbol references).
+ */
+typedef struct {
+	/** Enum definition */
+	struct stree_enum *enum_d;
+} tdata_ebase_t;
+
+/** Enum type. */
+typedef struct {
+	/** Enum definition */
+	struct stree_enum *enum_d;
+} tdata_enum_t;
+
+/** Functional type. */
+typedef struct {
+	/** Delegate definition or @c NULL if anonymous delegate */
+	struct stree_deleg *deleg;
+
+	/** Function signature type */
+	tdata_fun_sig_t *tsig;
+} tdata_fun_t;
+
+/** Type variable reference. */
+typedef struct {
+	/** Definition of type argument this variable is referencing. */
+	struct stree_targ *targ;
+} tdata_vref_t;
+
+typedef enum {
+	/** Primitive type item */
+	tic_tprimitive,
+	/** Object type item */
+	tic_tobject,
+	/** Array type item */
+	tic_tarray,
+	/** Delegate type item */
+	tic_tdeleg,
+	/** Enum-base type item */
+	tic_tebase,
+	/** Enum type item */
+	tic_tenum,
+	/** Function type item */
+	tic_tfun,
+	/** Type variable item */
+	tic_tvref,
+	/** Special error-recovery type item */
+	tic_ignore
+} 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_deleg_t *tdeleg;
+		tdata_ebase_t *tebase;
+		tdata_enum_t *tenum;
+		tdata_fun_t *tfun;
+		tdata_vref_t *tvref;
+	} u;
+} tdata_item_t;
+
+/** Type variable valuation (mapping of type argument names to values). */
+typedef struct {
+	/** Maps name SID to type item */
+	intmap_t tvv; /* of tdata_item_t */
+} tdata_tvv_t;
+
+#endif
Index: uspace/app/shutters/Makefile
===================================================================
--- uspace/app/shutters/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/shutters/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,10 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = shutters
+BINARY = shutters
 
 SOURCES = \
 	shutters.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/shutters/shutters.c
===================================================================
--- uspace/app/shutters/shutters.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/shutters/shutters.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -53,5 +53,5 @@
 #include <sys/stat.h>
 
-#include <string.h>
+#include <str.h>
 
 #define NAME 		"shutters"
Index: uspace/app/stats/Makefile
===================================================================
--- uspace/app/stats/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/stats/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = ../..
+BINARY = stats
+
+SOURCES = \
+	stats.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/stats/stats.c
===================================================================
--- uspace/app/stats/stats.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/stats/stats.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * 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.
+ */
+
+/** @addtogroup stats
+ * @brief Print system statistics.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stats.h>
+#include <sys/time.h>
+#include <inttypes.h>
+#include <malloc.h>
+
+#define NAME  "sysstat"
+
+#define DAY     86400
+#define HOUR    3600
+#define MINUTE  60
+
+int main(int argc, char *argv[])
+{
+	struct timeval time;
+	if (gettimeofday(&time, NULL) != 0) {
+		fprintf(stderr, "%s: Cannot get time of day\n", NAME);
+		return -1;
+	}
+	
+	uint64_t sec = time.tv_sec;
+	printf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64, (sec % DAY) / HOUR,
+	    (sec % HOUR) / MINUTE, sec % MINUTE);
+	
+	sysarg_t uptime = stats_get_uptime();
+	printf(", up %u days, %u hours, %u minutes, %u seconds", uptime / DAY,
+	    (uptime % DAY) / HOUR, (uptime % HOUR) / MINUTE, uptime % MINUTE);
+	
+	size_t count;
+	load_t *load = stats_get_load(&count);
+	if (load != NULL) {
+		printf(", load average: ");
+		
+		size_t i;
+		for (i = 0; i < count; i++) {
+			if (i > 0)
+				printf(" ");
+			
+			stats_print_load_fragment(load[i], 2);
+		}
+		
+		free(load);
+	}
+	
+	printf("\n");
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/taskdump/Makefile
===================================================================
--- uspace/app/taskdump/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/taskdump/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -28,12 +28,11 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
 EXTRA_CFLAGS = -Iinclude
-
-OUTPUT = taskdump
+BINARY = taskdump
 
 SOURCES = \
+	elf_core.c \
 	taskdump.c \
 	symtab.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/taskdump/elf_core.c
===================================================================
--- uspace/app/taskdump/elf_core.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/taskdump/elf_core.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup taskdump
+ * @{
+ */
+/** @file Write ELF core files.
+ *
+ * Creates ELF core files. Core files do not seem to be specified by some
+ * standard (the System V ABI explicitely states that it does not specify
+ * them).
+ *
+ * Looking at core files produced by Linux, these don't have section headers,
+ * only program headers, although objdump shows them as having sections.
+ * Basically at the beginning there should be a note segment (which we
+ * do not write) and one loadable segment per memory area (which we do write).
+ *
+ * The note segment probably contains register state, etc. -- we don't
+ * deal with these yet. Nevertheless you can use these core files with
+ * objdump or gdb.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mem.h>
+#include <stdint.h>
+#include <as.h>
+#include <udebug.h>
+#include <macros.h>
+
+#include <elf.h>
+#include "include/elf_core.h"
+
+static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size);
+static int write_all(int fd, void *data, size_t len);
+static int write_mem_area(int fd, as_area_info_t *area, int phoneid);
+
+#define BUFFER_SIZE 0x1000
+static uint8_t buffer[BUFFER_SIZE];
+
+/** Save ELF core file.
+ *
+ * @param file_name	Name of file to save to.
+ * @param ainfo		Array of @a n memory area info structures.
+ * @param n		Number of memory areas.
+ * @param phoneid	Debugging phone.
+ *
+ * @return		EOK on sucess, ENOENT if file cannot be created,
+ *			ENOMEM on out of memory, EIO on write error.
+ */
+int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid)
+{
+	elf_header_t elf_hdr;
+	off64_t foff;
+	size_t n_ph;
+	elf_word flags;
+	elf_segment_header_t *p_hdr;
+
+	int fd;
+	int rc;
+	unsigned int i;
+
+	n_ph = n;
+
+	p_hdr = malloc(sizeof(elf_segment_header_t) * n);
+	if (p_hdr == NULL) {
+		printf("Failed allocating memory.\n");
+		return ENOMEM;
+	}
+
+	fd = open(file_name, O_CREAT | O_WRONLY, 0644);
+	if (fd < 0) {
+		printf("Failed opening file.\n");
+		free(p_hdr);
+		return ENOENT;
+	}
+
+	/*
+	 * File layout:
+	 *
+	 * 	ELF header
+	 *	program headers
+	 * repeat:
+	 *	(pad for alignment)
+	 *	segment data
+	 * end repeat
+	 */
+
+	memset(&elf_hdr, 0, sizeof(elf_hdr));
+	elf_hdr.e_ident[EI_MAG0] = ELFMAG0;
+	elf_hdr.e_ident[EI_MAG1] = ELFMAG1;
+	elf_hdr.e_ident[EI_MAG2] = ELFMAG2;
+	elf_hdr.e_ident[EI_MAG3] = ELFMAG3;
+	elf_hdr.e_ident[EI_CLASS] = ELF_CLASS;
+	elf_hdr.e_ident[EI_DATA] = ELF_DATA_ENCODING;
+	elf_hdr.e_ident[EI_VERSION] = EV_CURRENT;
+
+	elf_hdr.e_type = ET_CORE;
+	elf_hdr.e_machine = ELF_MACHINE;
+	elf_hdr.e_version = EV_CURRENT;
+	elf_hdr.e_entry = 0;
+	elf_hdr.e_phoff = sizeof(elf_header_t);
+	elf_hdr.e_shoff = 0;
+	elf_hdr.e_flags = 0;
+	elf_hdr.e_ehsize = sizeof(elf_hdr);
+	elf_hdr.e_phentsize = sizeof(elf_segment_header_t);
+	elf_hdr.e_phnum = n_ph;
+	elf_hdr.e_shentsize = 0;
+	elf_hdr.e_shnum = 0;
+	elf_hdr.e_shstrndx = 0;
+
+	/* foff is used for allocation of file space for segment data. */
+	foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
+
+	for (i = 1; i <= n; ++i) {
+		foff = align_foff_up(foff, ainfo[i - 1].start_addr, PAGE_SIZE);
+
+		flags = 0;
+		if (ainfo[i - 1].flags & AS_AREA_READ)
+			flags |= PF_R;
+		if (ainfo[i - 1].flags & AS_AREA_WRITE)
+			flags |= PF_W;
+		if (ainfo[i - 1].flags & AS_AREA_EXEC)
+			flags |= PF_X;
+
+		memset(&p_hdr[i - 1], 0, sizeof(p_hdr[i - 1]));
+		p_hdr[i - 1].p_type = PT_LOAD;
+		p_hdr[i - 1].p_offset = foff;
+		p_hdr[i - 1].p_vaddr = ainfo[i - 1].start_addr;
+		p_hdr[i - 1].p_paddr = 0;
+		p_hdr[i - 1].p_filesz = ainfo[i - 1].size;
+		p_hdr[i - 1].p_memsz = ainfo[i - 1].size;
+		p_hdr[i - 1].p_flags = flags;
+		p_hdr[i - 1].p_align = PAGE_SIZE;
+
+		foff += ainfo[i - 1].size;
+	}
+
+	rc = write_all(fd, &elf_hdr, sizeof(elf_hdr));
+	if (rc != EOK) {
+		printf("Failed writing ELF header.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	for (i = 0; i < n_ph; ++i) {
+		rc = write_all(fd, &p_hdr[i], sizeof(p_hdr[i]));
+		if (rc != EOK) {
+			printf("Failed writing program header.\n");
+			free(p_hdr);
+			return EIO;
+		}
+	}
+
+	for (i = 0; i < n_ph; ++i) {
+		if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off64_t) -1) {
+			printf("Failed writing memory data.\n");
+			free(p_hdr);
+			return EIO;
+		}
+		if (write_mem_area(fd, &ainfo[i], phoneid) != EOK) {
+			printf("Failed writing memory data.\n");
+			free(p_hdr);
+			return EIO;
+		}
+	}
+
+	free(p_hdr);
+
+	return EOK;
+}
+
+/** Align file offset up to be congruent with vaddr modulo page size. */
+static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size)
+{
+	off64_t rva = vaddr % page_size;
+	off64_t rfo = foff % page_size;
+	
+	if (rva >= rfo)
+		return (foff + (rva - rfo));
+	
+	return (foff + (page_size + (rva - rfo)));
+}
+
+/** Write memory area from application to core file.
+ *
+ * @param fd		File to write to.
+ * @param area		Memory area info structure.
+ * @param phoneid	Debugging phone.
+ *
+ * @return		EOK on success, EIO on failure.
+ */
+static int write_mem_area(int fd, as_area_info_t *area, int phoneid)
+{
+	size_t to_copy;
+	size_t total;
+	uintptr_t addr;
+	int rc;
+
+	addr = area->start_addr;
+	total = 0;
+
+	while (total < area->size) {
+		to_copy = min(area->size - total, BUFFER_SIZE);
+		rc = udebug_mem_read(phoneid, buffer, addr, to_copy);
+		if (rc < 0) {
+			printf("Failed reading task memory.\n");
+			return EIO;
+		}
+
+		rc = write_all(fd, buffer, to_copy);
+		if (rc != EOK) {
+			printf("Failed writing memory contents.\n");
+			return EIO;
+		}
+
+		addr += to_copy;
+		total += to_copy;
+	}
+
+	return EOK;
+}
+
+/** Write until the buffer is written in its entirety.
+ *
+ * This function fails if it cannot write exactly @a len bytes to the file.
+ *
+ * @param fd		The file to write to.
+ * @param buf		Data, @a len bytes long.
+ * @param len		Number of bytes to write.
+ *
+ * @return		EOK on error, return value from write() if writing
+ *			failed.
+ */
+static int write_all(int fd, void *data, size_t len)
+{
+	int cnt = 0;
+
+	do {
+		data += cnt;
+		len -= cnt;
+		cnt = write(fd, data, len);
+	} while (cnt > 0 && (len - cnt) > 0);
+
+	if (cnt < 0)
+		return cnt;
+
+	if (len - cnt > 0)
+		return EIO;
+
+	return EOK;
+}
+
+
+/** @}
+ */
Index: uspace/app/taskdump/include/elf.h
===================================================================
--- uspace/app/taskdump/include/elf.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/taskdump/include/elf.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -148,4 +148,9 @@
 #define SHF_MASKPROC		0xf0000000
 
+/** Macros for decomposing elf_symbol.st_info into binging and type */
+#define ELF_ST_BIND(i)		((i) >> 4)
+#define ELF_ST_TYPE(i)		((i) & 0x0f)
+#define ELF_ST_INFO(b, t)	(((b) << 4) + ((t) & 0x0f))
+
 /**
  * Symbol binding
Index: uspace/app/taskdump/include/elf_core.h
===================================================================
--- uspace/app/taskdump/include/elf_core.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/taskdump/include/elf_core.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -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.
+ */
+
+/** @addtogroup debug
+ * @{
+ */
+/** @file
+ */
+
+#ifndef ELF_CORE_H_
+#define ELF_CORE_H_
+
+int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/taskdump/symtab.c
===================================================================
--- uspace/app/taskdump/symtab.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/taskdump/symtab.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -49,5 +49,5 @@
 static int section_hdr_load(int fd, const elf_header_t *ehdr, int idx,
     elf_section_header_t *shdr);
-static int chunk_load(int fd, off_t start, off_t size, void **ptr);
+static int chunk_load(int fd, off64_t start, size_t size, void **ptr);
 static int read_all(int fd, void *buf, size_t len);
 
@@ -65,5 +65,6 @@
 	elf_header_t elf_hdr;
 	elf_section_header_t sec_hdr;
-	off_t shstrt_start, shstrt_size;
+	off64_t shstrt_start;
+	size_t shstrt_size;
 	char *shstrt, *sec_name;
 	void *data;
@@ -206,7 +207,12 @@
 	size_t i;
 	char *sname;
+	unsigned stype;
 
 	for (i = 0; i < st->sym_size / sizeof(elf_symbol_t); ++i) {
 		if (st->sym[i].st_name == 0)
+			continue;
+
+		stype = ELF_ST_TYPE(st->sym[i].st_info);
+		if (stype != STT_OBJECT && stype != STT_FUNC)
 			continue;
 
@@ -240,4 +246,5 @@
 	uintptr_t saddr, best_addr;
 	char *sname, *best_name;
+	unsigned stype;
 
 	best_name = NULL;
@@ -248,6 +255,16 @@
 			continue;
 
+		stype = ELF_ST_TYPE(st->sym[i].st_info);
+		if (stype != STT_OBJECT && stype != STT_FUNC &&
+		    stype != STT_NOTYPE) {
+			continue;
+		}
+
 		saddr = st->sym[i].st_value;
 		sname = st->strtab + st->sym[i].st_name;
+
+		/* An ugly hack to filter out some special ARM symbols. */
+		if (sname[0] == '$')
+			continue;
 
 		if (best_name == NULL || (saddr <= addr && saddr > best_addr)) {
@@ -291,5 +308,5 @@
 	rc = lseek(fd, elf_hdr->e_shoff + idx * sizeof(elf_section_header_t),
 	    SEEK_SET);
-	if (rc == (off_t) -1)
+	if (rc == (off64_t) -1)
 		return EIO;
 
@@ -312,10 +329,10 @@
  * @return		EOK on success or EIO on failure.
  */
-static int chunk_load(int fd, off_t start, off_t size, void **ptr)
+static int chunk_load(int fd, off64_t start, size_t size, void **ptr)
 {
 	int rc;
 
 	rc = lseek(fd, start, SEEK_SET);
-	if (rc == (off_t) -1) {
+	if (rc == (off64_t) -1) {
 		printf("failed seeking chunk\n");
 		*ptr = NULL;
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/taskdump/taskdump.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -40,5 +40,5 @@
 #include <udebug.h>
 #include <task.h>
-#include <kernel/mm/as.h>
+#include <as.h>
 #include <sys/types.h>
 #include <sys/typefmt.h>
@@ -49,14 +49,13 @@
 
 #include <symtab.h>
+#include <elf_core.h>
 #include <stacktrace.h>
 
 #define LINE_BYTES 16
-
-#define DBUF_SIZE 4096
-static uint8_t data_buf[DBUF_SIZE];
 
 static int phoneid;
 static task_id_t task_id;
-static bool dump_memory;
+static bool write_core_file;
+static char *core_file_name;
 static char *app_name;
 static symtab_t *app_symtab;
@@ -68,6 +67,4 @@
 static int thread_dump(uintptr_t thash);
 static int areas_dump(void);
-static int area_dump(as_area_info_t *area);
-static void hex_dump(uintptr_t addr, void *buffer, size_t size);
 static int td_read_uintptr(void *arg, uintptr_t addr, uintptr_t *value);
 
@@ -80,13 +77,6 @@
 	int rc;
 
-	/*
-	 * FIXME: The stdio module cannot currently detect whether we are
-	 * writing to a console or file. This workaround make file output
-	 * faster.
-	 */
-	setvbuf(stdout, NULL, _IOFBF, 32768);
-
 	printf("Task Dump Utility\n");
-	dump_memory = false;
+	write_core_file = false;
 
 	if (parse_args(argc, argv) < 0)
@@ -172,6 +162,9 @@
 					return -1;
 				}
-			} else if (arg[1] == 'm' && arg[2] == '\0') {
-				dump_memory = true;
+			} else if (arg[1] == 'c' && arg[2] == '\0') {
+				write_core_file = true;
+
+				--argc; ++argv;
+				core_file_name = *argv;
 			} else {
 				printf("Uknown option '%s'\n", arg[0]);
@@ -203,6 +196,6 @@
 static void print_syntax(void)
 {
-	printf("Syntax: taskdump [-m] -t <task_id>\n");
-	printf("\t-m\tDump memory area contents.\n");
+	printf("Syntax: taskdump [-c <core_file>] -t <task_id>\n");
+	printf("\t-c <core_file_id>\tName of core file to write.\n");
 	printf("\t-t <task_id>\tWhich task to dump.\n");
 }
@@ -297,13 +290,16 @@
 		    (ainfo_buf[i].flags & AS_AREA_CACHEABLE) ? 'C' : '-',
 		    ainfo_buf[i].start_addr, ainfo_buf[i].size);
-
-		if (dump_memory) {
-			putchar('\n');
-			area_dump(&ainfo_buf[i]);
-			putchar('\n');
+	}
+
+	putchar('\n');
+
+	if (write_core_file) {
+		printf("Writing core file '%s'\n", core_file_name);
+		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, phoneid);
+		if (rc != EOK) {
+			printf("Failed writing core file.\n");
+			return EIO;
 		}
 	}
-
-	putchar('\n');
 
 	free(ainfo_buf);
@@ -353,63 +349,4 @@
 
 	return EOK;
-}
-
-static int area_dump(as_area_info_t *area)
-{
-	size_t to_copy;
-	size_t total;
-	uintptr_t addr;
-	int rc;
-
-	addr = area->start_addr;
-	total = 0;
-
-	while (total < area->size) {
-		to_copy = min(area->size - total, DBUF_SIZE);
-		rc = udebug_mem_read(phoneid, data_buf, addr, to_copy);
-		if (rc < 0) {
-			printf("udebug_mem_read() failed.\n");
-			return rc;
-		}
-
-		hex_dump(addr, data_buf, to_copy);
-
-		addr += to_copy;
-		total += to_copy;
-	}
-
-	return EOK;
-}
-
-static void hex_dump(uintptr_t addr, void *buffer, size_t size)
-{
-	uint8_t *data = (uint8_t *) buffer;
-	uint8_t b;
-	size_t pos, i;
-
-	assert(addr % LINE_BYTES == 0);
-	assert(size % LINE_BYTES == 0);
-
-	pos = 0;
-
-	while (pos < size) {
-		printf("%08lx:", addr + pos);
-		for (i = 0; i < LINE_BYTES; ++i) {
-			if (i % 4 == 0) putchar(' ');
-			printf(" %02x", data[pos + i]);
-		}
-		putchar('\t');
-
-		for (i = 0; i < LINE_BYTES; ++i) {
-			b = data[pos + i];
-			if (b >= 32 && b < 127) {
-				putchar(b);
-			} else {
-				putchar(' ');
-			}
-		}
-		putchar('\n');
-		pos += LINE_BYTES;
-	}
 }
 
Index: uspace/app/tasks/Makefile
===================================================================
--- uspace/app/tasks/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/tasks/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = ../..
+BINARY = tasks
+
+SOURCES = \
+	tasks.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tasks/tasks.c
===================================================================
--- uspace/app/tasks/tasks.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/tasks/tasks.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * 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.
+ */
+
+/** @addtogroup tasks
+ * @brief Task lister.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <task.h>
+#include <thread.h>
+#include <stats.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <inttypes.h>
+#include <bool.h>
+#include <str.h>
+#include <arg_parse.h>
+
+#define NAME  "tasks"
+
+#define TASK_COUNT    10
+#define THREAD_COUNT  50
+
+#define PRINT_LOAD1(x)  ((x) >> 11)
+#define PRINT_LOAD2(x)  (((x) & 0x7ff) / 2)
+
+static void list_tasks(void)
+{
+	size_t count;
+	stats_task_t *stats_tasks = stats_get_tasks(&count);
+	
+	if (stats_tasks == NULL) {
+		fprintf(stderr, "%s: Unable to get tasks\n", NAME);
+		return;
+	}
+	
+	printf("      ID  Threads      Mem       uCycles       kCycles   Name\n");
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		uint64_t virtmem, ucycles, kcycles;
+		char vmsuffix, usuffix, ksuffix;
+		
+		order_suffix(stats_tasks[i].virtmem, &virtmem, &vmsuffix);
+		order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
+		order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
+		
+		printf("%8" PRIu64 "%8u %8" PRIu64"%c %12"
+		    PRIu64 "%c %12" PRIu64 "%c %s\n", stats_tasks[i].task_id,
+		    stats_tasks[i].threads, virtmem, vmsuffix, ucycles, usuffix,
+		    kcycles, ksuffix, stats_tasks[i].name);
+	}
+	
+	free(stats_tasks);
+}
+
+static void list_threads(task_id_t task_id, bool all)
+{
+	size_t count;
+	stats_thread_t *stats_threads = stats_get_threads(&count);
+	
+	if (stats_threads == NULL) {
+		fprintf(stderr, "%s: Unable to get threads\n", NAME);
+		return;
+	}
+	
+	printf("    ID    State  CPU   Prio    [k]uCycles    [k]kcycles   Cycle fault\n");
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if ((all) || (stats_threads[i].task_id == task_id)) {
+			uint64_t ucycles, kcycles;
+			char usuffix, ksuffix;
+			
+			order_suffix(stats_threads[i].ucycles, &ucycles, &usuffix);
+			order_suffix(stats_threads[i].kcycles, &kcycles, &ksuffix);
+			
+			if (stats_threads[i].on_cpu) {
+				printf("%8" PRIu64 " %-8s %4u %6d %12"
+				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
+				    thread_get_state(stats_threads[i].state),
+				    stats_threads[i].cpu, stats_threads[i].priority,
+				    ucycles, usuffix, kcycles, ksuffix);
+			} else {
+				printf("%8" PRIu64 " %-8s ---- %6d %12"
+				    PRIu64"%c %12" PRIu64"%c\n", stats_threads[i].thread_id,
+				    thread_get_state(stats_threads[i].state),
+				    stats_threads[i].priority,
+				    ucycles, usuffix, kcycles, ksuffix);
+			}
+		}
+	}
+	
+	free(stats_threads);
+}
+
+static void print_load(void)
+{
+	size_t count;
+	load_t *load = stats_get_load(&count);
+	
+	if (load == NULL) {
+		fprintf(stderr, "%s: Unable to get load\n", NAME);
+		return;
+	}
+	
+	printf("%s: Load average: ", NAME);
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (i > 0)
+			printf(" ");
+		
+		stats_print_load_fragment(load[i], 2);
+	}
+	
+	printf("\n");
+	
+	free(load);
+}
+
+static void list_cpus(void)
+{
+	size_t count;
+	stats_cpu_t *cpus = stats_get_cpus(&count);
+	
+	if (cpus == NULL) {
+		fprintf(stderr, "%s: Unable to get CPU statistics\n", NAME);
+		return;
+	}
+	
+	printf("%s: %u CPU(s) detected\n", NAME, count);
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (cpus[i].active) {
+			printf("cpu%u: %" PRIu16 " MHz, busy ticks: "
+			    "%" PRIu64 ", idle ticks: %" PRIu64 "\n",
+			    cpus[i].id, cpus[i].frequency_mhz, cpus[i].busy_ticks,
+			    cpus[i].idle_ticks);
+		} else {
+			printf("cpu%u: inactive\n", cpus[i].id);
+		}
+	}
+	
+	free(cpus);
+}
+
+static void usage()
+{
+	printf(
+	    "Usage: tasks [-t task_id] [-a] [-l] [-c]\n" \
+	    "\n" \
+	    "Options:\n" \
+	    "\t-t task_id\n" \
+	    "\t--task=task_id\n" \
+	    "\t\tList threads of the given task\n" \
+	    "\n" \
+	    "\t-a\n" \
+	    "\t--all\n" \
+	    "\t\tList all threads\n" \
+	    "\n" \
+	    "\t-l\n" \
+	    "\t--load\n" \
+	    "\t\tPrint system load\n" \
+	    "\n" \
+	    "\t-c\n" \
+	    "\t--cpu\n" \
+	    "\t\tList CPUs\n" \
+	    "\n" \
+	    "\t-h\n" \
+	    "\t--help\n" \
+	    "\t\tPrint this usage information\n"
+	    "\n" \
+	    "Without any options all tasks are listed\n"
+	);
+}
+
+int main(int argc, char *argv[])
+{
+	bool toggle_tasks = true;
+	bool toggle_threads = false;
+	bool toggle_all = false;
+	bool toggle_load = false;
+	bool toggle_cpus = false;
+	
+	task_id_t task_id = 0;
+	
+	int i;
+	for (i = 1; i < argc; i++) {
+		int off;
+		
+		/* Usage */
+		if ((off = arg_parse_short_long(argv[i], "-h", "--help")) != -1) {
+			usage();
+			return 0;
+		}
+		
+		/* All threads */
+		if ((off = arg_parse_short_long(argv[i], "-a", "--all")) != -1) {
+			toggle_tasks = false;
+			toggle_threads = true;
+			toggle_all = true;
+			continue;
+		}
+		
+		/* Load */
+		if ((off = arg_parse_short_long(argv[i], "-l", "--load")) != -1) {
+			toggle_tasks = false;
+			toggle_load = true;
+			continue;
+		}
+		
+		/* CPUs */
+		if ((off = arg_parse_short_long(argv[i], "-c", "--cpus")) != -1) {
+			toggle_tasks = false;
+			toggle_cpus = true;
+			continue;
+		}
+		
+		/* Threads */
+		if ((off = arg_parse_short_long(argv[i], "-t", "--task=")) != -1) {
+			// TODO: Support for 64b range
+			int tmp;
+			int ret = arg_parse_int(argc, argv, &i, &tmp, off);
+			if (ret != EOK) {
+				printf("%s: Malformed task_id '%s'\n", NAME, argv[i]);
+				return -1;
+			}
+			
+			task_id = tmp;
+			
+			toggle_tasks = false;
+			toggle_threads = true;
+			continue;
+		}
+	}
+	
+	if (toggle_tasks)
+		list_tasks();
+	
+	if (toggle_threads)
+		list_threads(task_id, toggle_all);
+	
+	if (toggle_load)
+		print_load();
+	
+	if (toggle_cpus)
+		list_cpus();
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/test_serial/Makefile
===================================================================
--- uspace/app/test_serial/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/test_serial/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,10 +29,8 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = test_serial
+BINARY = test_serial
 
 SOURCES = \
 	test_serial.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/test_serial/test_serial.c
===================================================================
--- uspace/app/test_serial/test_serial.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/test_serial/test_serial.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -45,5 +45,5 @@
 #include <devman.h>
 #include <device/char.h>
-#include <string.h>
+#include <str.h>
 #include <ipc/serial_ctl.h>
 
@@ -136,6 +136,6 @@
 	}
 	
-	char *the_end = "\n---------\nTHE END\n---------\n";
-	write_dev(phone, the_end, str_size(the_end));
+	const char *the_end = "\n---------\nTHE END\n---------\n";
+	write_dev(phone, (void *)the_end, str_size(the_end));
 	
 	// restore original communication settings
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,7 +29,5 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = tester
+BINARY = tester
 
 SOURCES = \
@@ -53,3 +51,3 @@
 	mm/malloc1.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tester/console/console1.c
===================================================================
--- uspace/app/tester/console/console1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/console/console1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -36,5 +36,5 @@
 #include "../tester.h"
 
-const char *color_name[] = {
+static const char *color_name[] = {
 	[COLOR_BLACK] = "black",
 	[COLOR_BLUE] = "blue",
@@ -47,5 +47,5 @@
 };
 
-char *test_console1(void)
+const char *test_console1(void)
 {
 	if (!test_quiet) {
@@ -53,11 +53,17 @@
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_NORMAL);
-		printf("normal ");
+		printf(" normal ");
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_EMPHASIS);
-		printf("emphasized");
+		printf(" emphasized ");
+		fflush(stdout);
+		console_set_style(fphone(stdout), STYLE_INVERTED);
+		printf(" inverted ");
+		fflush(stdout);
+		console_set_style(fphone(stdout), STYLE_SELECTED);
+		printf(" selected ");
 		fflush(stdout);
 		console_set_style(fphone(stdout), STYLE_NORMAL);
-		printf(".\n");
+		printf("\n");
 		
 		unsigned int i;
@@ -73,5 +79,5 @@
 			}
 			fflush(stdout);
-			console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(fphone(stdout), STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -86,5 +92,5 @@
 			}
 			fflush(stdout);
-			console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+			console_set_style(fphone(stdout), STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -94,5 +100,5 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i << 16);
+			console_set_rgb_color(fphone(stdout), (255 - i) << 16, i << 16);
 			putchar('X');
 		}
@@ -103,5 +109,5 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i << 8);
+			console_set_rgb_color(fphone(stdout), (255 - i) << 8, i << 8);
 			putchar('X');
 		}
@@ -112,9 +118,9 @@
 		for (i = 0; i < 255; i += 16) {
 			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 0xffffff, i);
+			console_set_rgb_color(fphone(stdout), 255 - i, i);
 			putchar('X');
 		}
 		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_set_style(fphone(stdout), STYLE_NORMAL);
 		putchar('\n');
 	}
Index: uspace/app/tester/fault/fault1.c
===================================================================
--- uspace/app/tester/fault/fault1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/fault/fault1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -30,5 +30,5 @@
 #include "../tester.h"
 
-char *test_fault1(void)
+const char *test_fault1(void)
 {
 	((int *)(0))[1] = 0;
Index: uspace/app/tester/fault/fault2.c
===================================================================
--- uspace/app/tester/fault/fault2.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/fault/fault2.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -30,10 +30,12 @@
 #include "../tester.h"
 
-char *test_fault2(void)
+typedef int __attribute__((may_alias)) aliasing_int;
+
+const char *test_fault2(void)
 {
 	volatile long long var;
 	volatile int var1;
 	
-	var1 = *((int *) (((char *) (&var)) + 1));
+	var1 = *((aliasing_int *) (((char *) (&var)) + 1));
 	
 	return "Survived unaligned read";
Index: uspace/app/tester/fault/fault3.c
===================================================================
--- uspace/app/tester/fault/fault3.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/fault/fault3.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -30,5 +30,5 @@
 #include <stdlib.h>
 
-char *test_fault3(void)
+const char *test_fault3(void)
 {
 	abort();
Index: uspace/app/tester/fault/fault3.def
===================================================================
--- uspace/app/tester/fault/fault3.def	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/fault/fault3.def	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -3,4 +3,4 @@
 	"Abort",
 	&test_fault3,
-	true
+	false
 },
Index: uspace/app/tester/ipc/connect.c
===================================================================
--- uspace/app/tester/ipc/connect.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/ipc/connect.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -39,5 +39,5 @@
 }
 
-char *test_connect(void)
+const char *test_connect(void)
 {
 	TPRINTF("Connecting to %u...", IPC_TEST_SERVICE);
Index: uspace/app/tester/ipc/ping_pong.c
===================================================================
--- uspace/app/tester/ipc/ping_pong.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/ipc/ping_pong.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #define COUNT_GRANULARITY  100
 
-char *test_ping_pong(void)
+const char *test_ping_pong(void)
 {
 	TPRINTF("Pinging ns server for %d seconds...", DURATION_SECS);
Index: uspace/app/tester/ipc/register.c
===================================================================
--- uspace/app/tester/ipc/register.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/ipc/register.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -74,5 +74,5 @@
 }
 
-char *test_register(void)
+const char *test_register(void)
 {
 	async_set_client_connection(client_connection);
Index: uspace/app/tester/loop/loop1.c
===================================================================
--- uspace/app/tester/loop/loop1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/loop/loop1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include "../tester.h"
 
-char *test_loop1(void)
+const char *test_loop1(void)
 {
 	TPRINTF("Looping...");
Index: uspace/app/tester/mm/malloc1.c
===================================================================
--- uspace/app/tester/mm/malloc1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/mm/malloc1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -73,5 +73,5 @@
 
 typedef struct {
-	char *name;
+	const char *name;
 	sp_term_cond_s cond;
 	sp_action_prob_s prob;
@@ -90,5 +90,5 @@
 
 typedef struct {
-	char *name;
+	const char *name;
 	ph_alloc_size_s alloc;
 	subphase_s *subphases;
@@ -628,5 +628,5 @@
 }
 
-char *test_malloc1(void)
+const char *test_malloc1(void)
 {
 	init_mem();
Index: uspace/app/tester/print/print1.c
===================================================================
--- uspace/app/tester/print/print1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/print/print1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include "../tester.h"
 
-char *test_print1(void)
+const char *test_print1(void)
 {
 	TPRINTF("Testing printf(\"%%*.*s\", 5, 3, \"text\"):\n");
Index: uspace/app/tester/print/print2.c
===================================================================
--- uspace/app/tester/print/print2.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/print/print2.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include "../tester.h"
 
-char *test_print2(void)
+const char *test_print2(void)
 {
 	TPRINTF("Testing printf(\"%%c %%3.2c %%-3.2c %%2.3c %%-2.3c\", 'a', 'b', 'c', 'd', 'e'):\n");
Index: uspace/app/tester/print/print3.c
===================================================================
--- uspace/app/tester/print/print3.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/print/print3.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -34,5 +34,5 @@
 #define BUFFER_SIZE  32
 
-char *test_print3(void)
+const char *test_print3(void)
 {
 	char buffer[BUFFER_SIZE];
Index: uspace/app/tester/print/print4.c
===================================================================
--- uspace/app/tester/print/print4.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/print/print4.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -31,5 +31,5 @@
 #include "../tester.h"
 
-char *test_print4(void)
+const char *test_print4(void)
 {
 	TPRINTF("ASCII printable characters (32 - 127) using printf(\"%%c\") and printf(\"%%lc\"):\n");
Index: uspace/app/tester/stdio/stdio1.c
===================================================================
--- uspace/app/tester/stdio/stdio1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/stdio/stdio1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -36,8 +36,8 @@
 static char buf[BUF_SIZE + 1];
 
-char *test_stdio1(void)
+const char *test_stdio1(void)
 {
 	FILE *file;
-	char *file_name = "/readme";
+	const char *file_name = "/readme";
 	
 	TPRINTF("Open file \"%s\"...", file_name);
Index: uspace/app/tester/stdio/stdio2.c
===================================================================
--- uspace/app/tester/stdio/stdio2.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/stdio/stdio2.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -32,8 +32,8 @@
 #include "../tester.h"
 
-char *test_stdio2(void)
+const char *test_stdio2(void)
 {
 	FILE *file;
-	char *file_name = "/test";
+	const char *file_name = "/test";
 	
 	TPRINTF("Open file \"%s\" for writing...", file_name);
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/tester.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 #include <unistd.h>
 #include <stdio.h>
-#include <string.h>
+#include <str.h>
 #include "tester.h"
 
@@ -69,5 +69,5 @@
 {
 	/* Execute the test */
-	char *ret = test->entry();
+	const char *ret = test->entry();
 	
 	if (ret == NULL) {
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/tester.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -54,30 +54,30 @@
 	}
 
-typedef char *(*test_entry_t)(void);
+typedef const char *(*test_entry_t)(void);
 
 typedef struct {
-	char *name;
-	char *desc;
+	const char *name;
+	const char *desc;
 	test_entry_t entry;
 	bool safe;
 } test_t;
 
-extern char *test_thread1(void);
-extern char *test_print1(void);
-extern char *test_print2(void);
-extern char *test_print3(void);
-extern char *test_print4(void);
-extern char *test_console1(void);
-extern char *test_stdio1(void);
-extern char *test_stdio2(void);
-extern char *test_fault1(void);
-extern char *test_fault2(void);
-extern char *test_fault3(void);
-extern char *test_vfs1(void);
-extern char *test_ping_pong(void);
-extern char *test_register(void);
-extern char *test_connect(void);
-extern char *test_loop1(void);
-extern char *test_malloc1(void);
+extern const char *test_thread1(void);
+extern const char *test_print1(void);
+extern const char *test_print2(void);
+extern const char *test_print3(void);
+extern const char *test_print4(void);
+extern const char *test_console1(void);
+extern const char *test_stdio1(void);
+extern const char *test_stdio2(void);
+extern const char *test_fault1(void);
+extern const char *test_fault2(void);
+extern const char *test_fault3(void);
+extern const char *test_vfs1(void);
+extern const char *test_ping_pong(void);
+extern const char *test_register(void);
+extern const char *test_connect(void);
+extern const char *test_loop1(void);
+extern const char *test_malloc1(void);
 
 extern test_t tests[];
Index: uspace/app/tester/thread/thread1.c
===================================================================
--- uspace/app/tester/thread/thread1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/thread/thread1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -50,8 +50,8 @@
 }
 
-char *test_thread1(void)
+const char *test_thread1(void)
 {
 	unsigned int i;
-	int total = 0;
+	atomic_count_t total = 0;
 	
 	atomic_set(&finish, 1);
Index: uspace/app/tester/vfs/vfs1.c
===================================================================
--- uspace/app/tester/vfs/vfs1.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tester/vfs/vfs1.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -30,5 +30,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <vfs/vfs.h>
 #include <unistd.h>
@@ -54,5 +54,5 @@
 static char text[] = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
 
-static char *read_root(void)
+static const char *read_root(void)
 {
 	TPRINTF("Opening the root directory...");
@@ -73,5 +73,5 @@
 }
 
-char *test_vfs1(void)
+const char *test_vfs1(void)
 {
 	if (mkdir(MOUNT_POINT, 0) != 0)
@@ -121,5 +121,5 @@
 	close(fd0);
 	
-	char *rv = read_root();
+	const char *rv = read_root();
 	if (rv != NULL)
 		return rv;
Index: uspace/app/tetris/Makefile
===================================================================
--- uspace/app/tetris/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,7 +29,5 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = tetris
+BINARY = tetris
 
 SOURCES = \
@@ -40,3 +38,3 @@
 	screen.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tetris/input.c
===================================================================
--- uspace/app/tetris/input.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/input.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -52,5 +52,5 @@
 #include <errno.h>
 #include <unistd.h>
-#include <string.h>
+#include <str.h>
 
 #include "input.h"
Index: uspace/app/tetris/scores.c
===================================================================
--- uspace/app/tetris/scores.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/scores.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -52,5 +52,5 @@
 #include <errno.h>
 #include <stdio.h>
-#include <string.h>
+#include <str.h>
 #include <io/console.h>
 #include <io/keycode.h>
Index: uspace/app/tetris/scores.h
===================================================================
--- uspace/app/tetris/scores.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/scores.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -48,5 +48,5 @@
 
 #include <sys/time.h>
-#include <string.h>
+#include <str.h>
 
 #define MAXLOGNAME   16
Index: uspace/app/tetris/screen.c
===================================================================
--- uspace/app/tetris/screen.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/screen.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -49,11 +49,13 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <unistd.h>
 #include <vfs/vfs.h>
 #include <async.h>
+#include <bool.h>
+#include <io/console.h>
+#include <io/style.h>
 #include "screen.h"
 #include "tetris.h"
-#include <io/console.h>
 
 #define STOP  (B_COLS - 3)
@@ -63,5 +65,5 @@
 static int isset;               /* true => terminal is in game mode */
 
-static int use_color;		/* true => use colors */
+static bool use_color;          /* true => use colors */
 
 static const struct shape *lastshape;
@@ -72,5 +74,5 @@
  * simply literal strings);
  */
-static inline void putstr(char *s)
+static inline void putstr(const char *s)
 {
 	while (*s)
@@ -81,5 +83,5 @@
 {
 	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0xf0f0f0,
+	console_set_rgb_color(fphone(stdout), 0xffffff,
 	    use_color ? color : 0x000000);
 }
@@ -88,5 +90,5 @@
 {
 	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0, 0xf0f0f0);
+	console_set_style(fphone(stdout), STYLE_NORMAL);
 }
 
@@ -118,8 +120,8 @@
 }
 
-void moveto(int r, int c)
+void moveto(ipcarg_t r, ipcarg_t c)
 {
 	fflush(stdout);
-	console_goto(fphone(stdout), c, r);
+	console_set_pos(fphone(stdout), c, r);
 }
 
@@ -131,13 +133,12 @@
 }
 
-static int get_display_color_sup(void)
-{
-	int rc;
-	int ccap;
-
-	rc = console_get_color_cap(fphone(stdout), &ccap);
+static bool get_display_color_sup(void)
+{
+	ipcarg_t ccap;
+	int rc = console_get_color_cap(fphone(stdout), &ccap);
+	
 	if (rc != 0)
-		return 0;
-
+		return false;
+	
 	return (ccap >= CONSOLE_CCAP_RGB);
 }
@@ -181,5 +182,5 @@
 }
 
-void stop(char *why)
+void stop(const char *why)
 {
 	if (isset)
@@ -308,5 +309,5 @@
  * (We need its length in case we have to overwrite with blanks.)
  */
-void scr_msg(char *s, int set)
+void scr_msg(char *s, bool set)
 {
 	int l = str_size(s);
Index: uspace/app/tetris/screen.h
===================================================================
--- uspace/app/tetris/screen.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/screen.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -48,14 +48,16 @@
 
 #include <sys/types.h>
+#include <ipc/ipc.h>
 #include <async.h>
+#include <bool.h>
 
 typedef struct {
-	int ws_row;
-	int ws_col;
+	ipcarg_t ws_row;
+	ipcarg_t ws_col;
 } winsize_t;
 
 extern winsize_t winsize;
 
-extern void moveto(int r, int c);
+extern void moveto(ipcarg_t r, ipcarg_t c);
 extern void clear_screen(void);
 
@@ -65,5 +67,5 @@
 extern void scr_end(void);
 extern void scr_init(void);
-extern void scr_msg(char *, int);
+extern void scr_msg(char *, bool);
 extern void scr_set(void);
 extern void scr_update(void);
Index: uspace/app/tetris/tetris.c
===================================================================
--- uspace/app/tetris/tetris.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/tetris.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -53,5 +53,5 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <str.h>
 #include <unistd.h>
 #include <getopt.h>
Index: uspace/app/tetris/tetris.h
===================================================================
--- uspace/app/tetris/tetris.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/tetris/tetris.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -186,5 +186,5 @@
 extern int fits_in(const struct shape *, int);
 extern void place(const struct shape *, int, int);
-extern void stop(char *);
+extern void stop(const char *);
 
 /** @}
Index: uspace/app/top/Makefile
===================================================================
--- uspace/app/top/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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 = ../..
+BINARY = top
+
+SOURCES = \
+	top.c \
+	screen.c \
+	input.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/top/input.c
===================================================================
--- uspace/app/top/input.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/input.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,200 @@
+/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
+/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.c	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup top
+ * @{
+ */
+/** @file
+ */
+
+/*
+ * Top input.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <str.h>
+
+#include "input.h"
+
+#include <async.h>
+#include <vfs/vfs.h>
+#include <io/console.h>
+#include <ipc/console.h>
+
+#define USEC_COUNT 1000000
+
+/* return true iff the given timeval is positive */
+#define	TV_POS(tv) \
+	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
+
+/* subtract timeval `sub' from `res' */
+#define	TV_SUB(res, sub) \
+	(res)->tv_sec -= (sub)->tv_sec; \
+	(res)->tv_usec -= (sub)->tv_usec; \
+	if ((res)->tv_usec < 0) { \
+		(res)->tv_usec += 1000000; \
+		(res)->tv_sec--; \
+	}
+
+/* We will use a hack here - if lastchar is non-zero, it is
+ * the last character read. We will somehow simulate the select
+ * semantics.
+ */
+static aid_t getchar_inprog = 0;
+static char lastchar = '\0';
+
+/*
+ * Do a `read wait': select for reading from stdin, with timeout *tvp.
+ * On return, modify *tvp to reflect the amount of time spent waiting.
+ * It will be positive only if input appeared before the time ran out;
+ * otherwise it will be zero or perhaps negative.
+ *
+ * If tvp is nil, wait forever, but return if select is interrupted.
+ *
+ * Return 0 => no input, 1 => can read() from stdin
+ *
+ */
+int rwait(struct timeval *tvp)
+{
+	struct timeval starttv, endtv, *s;
+	static ipc_call_t charcall;
+	ipcarg_t rc;
+	
+	/*
+	 * Someday, select() will do this for us.
+	 * Just in case that day is now, and no one has
+	 * changed this, we use a temporary.
+	 */
+	if (tvp) {
+		(void) gettimeofday(&starttv, NULL);
+		endtv = *tvp;
+		s = &endtv;
+	} else
+		s = NULL;
+	
+	if (!lastchar) {
+again:
+		if (!getchar_inprog) {
+			getchar_inprog = async_send_0(fphone(stdin),
+			    CONSOLE_GET_EVENT, &charcall);
+		}
+		
+		if (!s)
+			async_wait_for(getchar_inprog, &rc);
+		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
+			tvp->tv_sec = 0;
+			tvp->tv_usec = 0;
+			return (0);
+		}
+		
+		getchar_inprog = 0;
+		if (rc) {
+			printf("End of file, bug?\n");
+			exit(1);
+		}
+		
+		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
+			goto again;
+		
+		lastchar = IPC_GET_ARG4(charcall);
+	}
+	
+	if (tvp) {
+		/* since there is input, we may not have timed out */
+		(void) gettimeofday(&endtv, NULL);
+		TV_SUB(&endtv, &starttv);
+		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
+	}
+	
+	return 1;
+}
+
+/*
+ * `sleep' for the current turn time (using select).
+ * Eat any input that might be available.
+ */
+void tsleep(unsigned int sec)
+{
+	struct timeval tv;
+	
+	tv.tv_sec = 0;
+	tv.tv_usec = sec * USEC_COUNT;
+	while (TV_POS(&tv))
+		if (rwait(&tv)) {
+			lastchar = '\0';
+		} else
+			break;
+}
+
+/*
+ * getchar with timeout.
+ */
+int tgetchar(unsigned int sec)
+{
+	static struct timeval timeleft;
+	char c;
+	
+	/*
+	 * Reset timeleft to USEC_COUNT whenever it is not positive.
+	 * In any case, wait to see if there is any input.  If so,
+	 * take it, and update timeleft so that the next call to
+	 * tgetchar() will not wait as long.  If there is no input,
+	 * make timeleft zero or negative, and return -1.
+	 *
+	 * Most of the hard work is done by rwait().
+	 */
+	if (!TV_POS(&timeleft)) {
+		timeleft.tv_sec = 0;
+		timeleft.tv_usec = sec * USEC_COUNT;
+	}
+	
+	if (!rwait(&timeleft))
+		return -1;
+	
+	c = lastchar;
+	lastchar = '\0';
+	return ((int) (unsigned char) c);
+}
+
+/** @}
+ */
Index: uspace/app/top/input.h
===================================================================
--- uspace/app/top/input.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/input.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,56 @@
+/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
+/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)input.h	8.1 (Berkeley) 5/31/93
+ */
+
+/** @addtogroup top
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TOP_INPUT_
+#define TOP_INPUT_
+
+#include <sys/time.h>
+
+extern int rwait(struct timeval *);
+extern int tgetchar(unsigned int sec);
+extern void tsleep(unsigned int sec);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/screen.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * 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.
+ */
+
+/** @addtogroup top
+ * @brief Top utility.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <ipc/ipc.h>
+#include <io/console.h>
+#include <io/style.h>
+#include <vfs/vfs.h>
+#include <stdarg.h>
+#include <stats.h>
+#include <inttypes.h>
+#include "screen.h"
+#include "top.h"
+
+static ipcarg_t warn_col = 0;
+static ipcarg_t warn_row = 0;
+
+static void screen_style_normal(void)
+{
+	fflush(stdout);
+	console_set_style(fphone(stdout), STYLE_NORMAL);
+}
+
+static void screen_style_inverted(void)
+{
+	fflush(stdout);
+	console_set_style(fphone(stdout), STYLE_INVERTED);
+}
+
+static void screen_moveto(ipcarg_t col, ipcarg_t row)
+{
+	fflush(stdout);
+	console_set_pos(fphone(stdout), col, row);
+}
+
+static void screen_get_pos(ipcarg_t *col, ipcarg_t *row)
+{
+	fflush(stdout);
+	console_get_pos(fphone(stdout), col, row);
+}
+
+static void screen_get_size(ipcarg_t *col, ipcarg_t *row)
+{
+	fflush(stdout);
+	console_get_size(fphone(stdout), col, row);
+}
+
+static void screen_restart(bool clear)
+{
+	screen_style_normal();
+	
+	if (clear) {
+		fflush(stdout);
+		console_clear(fphone(stdout));
+	}
+	
+	screen_moveto(0, 0);
+}
+
+static void screen_newline(void)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t c;
+	ipcarg_t r;
+	screen_get_pos(&c, &r);
+	
+	ipcarg_t i;
+	for (i = c + 1; i < cols; i++)
+		puts(" ");
+	
+	if (r + 1 < rows)
+		puts("\n");
+}
+
+void screen_init(void)
+{
+	fflush(stdout);
+	console_cursor_visibility(fphone(stdout), false);
+	
+	screen_restart(true);
+}
+
+void screen_done(void)
+{
+	screen_restart(true);
+	
+	fflush(stdout);
+	console_cursor_visibility(fphone(stdout), true);
+}
+
+static void print_float(fixed_float ffloat, unsigned int precision)
+{
+	printf("%2" PRIu64 ".", ffloat.upper / ffloat.lower);
+	
+	unsigned int i;
+	uint64_t rest = (ffloat.upper % ffloat.lower) * 10;
+	for (i = 0; i < precision; i++) {
+		printf("%" PRIu64, rest / ffloat.lower);
+		rest = (rest % ffloat.lower) * 10;
+	}
+}
+
+static inline void print_global_head(data_t *data)
+{
+	printf("top - %02lu:%02lu:%02lu up %u days, %02u:%02u:%02u, load average:",
+	    data->hours, data->minutes, data->seconds,
+	    data->udays, data->uhours, data->uminutes, data->useconds);
+	
+	size_t i;
+	for (i = 0; i < data->load_count; i++) {
+		puts(" ");
+		stats_print_load_fragment(data->load[i], 2);
+	}
+	
+	screen_newline();
+}
+
+static inline void print_task_summary(data_t *data)
+{
+	printf("tasks: %u total", data->tasks_count);
+	screen_newline();
+}
+
+static inline void print_thread_summary(data_t *data)
+{
+	size_t total = 0;
+	size_t running = 0;
+	size_t ready = 0;
+	size_t sleeping = 0;
+	size_t lingering = 0;
+	size_t other = 0;
+	size_t invalid = 0;
+	
+	size_t i;
+	for (i = 0; i < data->threads_count; i++) {
+		total++;
+		
+		switch (data->threads[i].state) {
+		case Running:
+			running++;
+			break;
+		case Ready:
+			ready++;
+			break;
+		case Sleeping:
+			sleeping++;
+			break;
+		case Lingering:
+			lingering++;
+			break;
+		case Entering:
+		case Exiting:
+			other++;
+			break;
+		default:
+			invalid++;
+		}
+	}
+	
+	printf("threads: %u total, %u running, %u ready, %u sleeping, %u lingering, "
+	    "%u other, %u invalid",
+	    total, running, ready, sleeping, lingering, other, invalid);
+	screen_newline();
+}
+
+static inline void print_cpu_info(data_t *data)
+{
+	size_t i;
+	for (i = 0; i < data->cpus_count; i++) {
+		if (data->cpus[i].active) {
+			printf("cpu%u (%4" PRIu16 " MHz): busy ticks: "
+			    "%" PRIu64 ", idle ticks: %" PRIu64,
+			    data->cpus[i].id, data->cpus[i].frequency_mhz,
+			    data->cpus[i].busy_ticks, data->cpus[i].idle_ticks);
+			puts(", idle: ");
+			print_float(data->cpus_perc[i].idle, 2);
+			puts("%, busy: ");
+			print_float(data->cpus_perc[i].busy, 2);
+			puts("%");
+		} else
+			printf("cpu%u inactive", data->cpus[i].id);
+		
+		screen_newline();
+	}
+}
+
+static inline void print_physmem_info(data_t *data)
+{
+	uint64_t total;
+	uint64_t unavail;
+	uint64_t used;
+	uint64_t free;
+	char total_suffix;
+	char unavail_suffix;
+	char used_suffix;
+	char free_suffix;
+	
+	order_suffix(data->physmem->total, &total, &total_suffix);
+	order_suffix(data->physmem->unavail, &unavail, &unavail_suffix);
+	order_suffix(data->physmem->used, &used, &used_suffix);
+	order_suffix(data->physmem->free, &free, &free_suffix);
+	
+	printf("memory: %" PRIu64 "%c total, %" PRIu64 "%c unavail, %"
+	    PRIu64 "%c used, %" PRIu64 "%c free", total, total_suffix,
+	    unavail, unavail_suffix, used, used_suffix, free, free_suffix);
+	screen_newline();
+}
+
+static inline void print_task_head(void)
+{
+	screen_style_inverted();
+	printf("      ID  Threads      Mem      %%Mem %%uCycles %%kCycles  Name");
+	screen_newline();
+	screen_style_normal();
+}
+
+static inline void print_tasks(data_t *data)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t col;
+	ipcarg_t row;
+	screen_get_pos(&col, &row);
+	
+	size_t i;
+	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
+		uint64_t virtmem;
+		char virtmem_suffix;
+		order_suffix(data->tasks[i].virtmem, &virtmem, &virtmem_suffix);
+		
+		printf("%8" PRIu64 " %8u %8" PRIu64 "%c ", data->tasks[i].task_id,
+		    data->tasks[i].threads, virtmem, virtmem_suffix);
+		puts("   ");
+		print_float(data->tasks_perc[i].virtmem, 2);
+		puts("%   ");
+		print_float(data->tasks_perc[i].ucycles, 2);
+		puts("%   ");
+		print_float(data->tasks_perc[i].kcycles, 2);
+		printf("%% %s", data->tasks[i].name);
+		
+		screen_newline();
+	}
+	
+	while (row < rows) {
+		screen_newline();
+		row++;
+	}
+}
+
+static inline void print_ipc_head(void)
+{
+	screen_style_inverted();
+	printf("      ID Calls sent Calls recv Answs sent Answs recv  IRQn recv       Forw Name");
+	screen_newline();
+	screen_style_normal();
+}
+
+static inline void print_ipc(data_t *data)
+{
+	ipcarg_t cols;
+	ipcarg_t rows;
+	screen_get_size(&cols, &rows);
+	
+	ipcarg_t col;
+	ipcarg_t row;
+	screen_get_pos(&col, &row);
+	
+	size_t i;
+	for (i = 0; (i < data->tasks_count) && (row < rows); i++, row++) {
+		printf("%8" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64
+		     " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %s",
+		     data->tasks[i].task_id, data->tasks[i].ipc_info.call_sent,
+		     data->tasks[i].ipc_info.call_recieved,
+		     data->tasks[i].ipc_info.answer_sent,
+		     data->tasks[i].ipc_info.answer_recieved,
+		     data->tasks[i].ipc_info.irq_notif_recieved,
+		     data->tasks[i].ipc_info.forwarded, data->tasks[i].name);
+		
+		screen_newline();
+	}
+	
+	while (row < rows) {
+		screen_newline();
+		row++;
+	}
+}
+
+void print_data(data_t *data)
+{
+	screen_restart(false);
+	print_global_head(data);
+	print_task_summary(data);
+	print_thread_summary(data);
+	print_cpu_info(data);
+	print_physmem_info(data);
+	
+	/* Empty row for warnings */
+	screen_get_pos(&warn_col, &warn_row);
+	screen_newline();
+	
+	if (operation_type == OP_IPC) {
+		print_ipc_head();
+		print_ipc(data);
+	} else {
+		print_task_head();
+		print_tasks(data);
+	}
+	
+	fflush(stdout);
+}
+
+void print_warning(const char *fmt, ...)
+{
+	screen_moveto(warn_col, warn_row);
+	
+	va_list args;
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+	
+	screen_newline();
+	fflush(stdout);
+}
+
+/** @}
+ */
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/screen.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * 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.
+ */
+
+/** @addtogroup top
+ * @{
+ */
+
+#ifndef TOP_SCREEN_H_
+#define TOP_SCREEN_H_
+
+#include "top.h"
+
+extern void screen_init(void);
+extern void screen_done(void);
+extern void print_data(data_t *);
+extern void print_warning(const char *, ...);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/top.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * 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.
+ */
+
+/** @addtogroup top
+ * @brief Top utility.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <task.h>
+#include <thread.h>
+#include <sys/time.h>
+#include <arch/barrier.h>
+#include <errno.h>
+#include "screen.h"
+#include "input.h"
+#include "top.h"
+
+#define NAME  "top"
+
+#define UPDATE_INTERVAL  1
+
+#define DAY     86400
+#define HOUR    3600
+#define MINUTE  60
+
+int operation_type;
+
+static const char *read_data(data_t *target)
+{
+	/* Initialize data */
+	target->load = NULL;
+	target->cpus = NULL;
+	target->cpus_perc = NULL;
+	target->tasks = NULL;
+	target->tasks_perc = NULL;
+	target->threads = NULL;
+	target->physmem = NULL;
+	
+	/* Get current time */
+	struct timeval time;
+	if (gettimeofday(&time, NULL) != EOK)
+		return "Cannot get time of day";
+	
+	target->hours = (time.tv_sec % DAY) / HOUR;
+	target->minutes = (time.tv_sec % HOUR) / MINUTE;
+	target->seconds = time.tv_sec % MINUTE;
+	
+	/* Get uptime */
+	sysarg_t uptime = stats_get_uptime();
+	target->udays = uptime / DAY;
+	target->uhours = (uptime % DAY) / HOUR;
+	target->uminutes = (uptime % HOUR) / MINUTE;
+	target->useconds = uptime % MINUTE;
+	
+	/* Get load */
+	target->load = stats_get_load(&(target->load_count));
+	if (target->load == NULL)
+		return "Cannot get system load";
+	
+	/* Get CPUs */
+	target->cpus = stats_get_cpus(&(target->cpus_count));
+	if (target->cpus == NULL)
+		return "Cannot get CPUs";
+	
+	target->cpus_perc =
+	    (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
+	if (target->cpus_perc == NULL)
+		return "Not enough memory for CPU utilization";
+	
+	/* Get tasks */
+	target->tasks = stats_get_tasks(&(target->tasks_count));
+	if (target->tasks == NULL)
+		return "Cannot get tasks";
+	
+	target->tasks_perc =
+	    (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
+	if (target->tasks_perc == NULL)
+		return "Not enough memory for task utilization";
+	
+	/* Get threads */
+	target->threads = stats_get_threads(&(target->threads_count));
+	if (target->threads == NULL)
+		return "Cannot get threads";
+	
+	/* Get physical memory */
+	target->physmem = stats_get_physmem();
+	if (target->physmem == NULL)
+		return "Cannot get physical memory";
+	
+	return NULL;
+}
+
+/** Computes percentage differencies from old_data to new_data
+ *
+ * @param old_data Pointer to old data strucutre.
+ * @param new_data Pointer to actual data where percetages are stored.
+ *
+ */
+static const char *compute_percentages(data_t *old_data, data_t *new_data)
+{
+	/* Allocate memory */
+	
+	uint64_t *ucycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (ucycles_diff == NULL)
+		return "Not enough memory for user utilization";
+	
+	uint64_t *kcycles_diff = calloc(new_data->tasks_count, sizeof(uint64_t));
+	if (kcycles_diff == NULL) {
+		free(ucycles_diff);
+		return "Not enough memory for kernel utilization";
+	}
+	
+	/* For each CPU: Compute total ticks and divide it between
+	   user and kernel */
+	
+	size_t i;
+	for (i = 0; i < new_data->cpus_count; i++) {
+		uint64_t idle =
+		    new_data->cpus[i].idle_ticks - old_data->cpus[i].idle_ticks;
+		uint64_t busy =
+		    new_data->cpus[i].busy_ticks - old_data->cpus[i].busy_ticks;
+		uint64_t sum = idle + busy;
+		
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
+		FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
+	}
+	
+	/* For all tasks compute sum and differencies of all cycles */
+	
+	uint64_t virtmem_total = 1;  /* Must NOT be zero */
+	uint64_t ucycles_total = 1;  /* Must NOT be zero */
+	uint64_t kcycles_total = 1;  /* Must NOT be zero */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		/* Match task with the previous instance */
+		
+		bool found = false;
+		size_t j;
+		for (j = 0; j < old_data->tasks_count; j++) {
+			if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
+				found = true;
+				break;
+			}
+		}
+		
+		if (!found) {
+			/* This is newly borned task, ignore it */
+			ucycles_diff[i] = 0;
+			kcycles_diff[i] = 0;
+			continue;
+		}
+		
+		ucycles_diff[i] =
+		    new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
+		kcycles_diff[i] =
+		    new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
+		
+		virtmem_total += new_data->tasks[i].virtmem;
+		ucycles_total += ucycles_diff[i];
+		kcycles_total += kcycles_diff[i];
+	}
+	
+	/* For each task: Compute percential change */
+	
+	for (i = 0; i < new_data->tasks_count; i++) {
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
+		    new_data->tasks[i].virtmem * 100, virtmem_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
+		    ucycles_diff[i] * 100, ucycles_total);
+		FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
+		    kcycles_diff[i] * 100, kcycles_total);
+	}
+	
+	/* Cleanup */
+	
+	free(ucycles_diff);
+	free(kcycles_diff);
+	
+	return NULL;
+}
+
+static void free_data(data_t *target)
+{
+	if (target->load != NULL)
+		free(target->load);
+	
+	if (target->cpus != NULL)
+		free(target->cpus);
+	
+	if (target->cpus_perc != NULL)
+		free(target->cpus_perc);
+	
+	if (target->tasks != NULL)
+		free(target->tasks);
+	
+	if (target->tasks_perc != NULL)
+		free(target->tasks_perc);
+	
+	if (target->threads != NULL)
+		free(target->threads);
+	
+	if (target->physmem != NULL)
+		free(target->physmem);
+}
+
+int main(int argc, char *argv[])
+{
+	data_t data;
+	data_t data_prev;
+	const char *ret = NULL;
+	
+	screen_init();
+	printf("Reading initial data...\n");
+	
+	if ((ret = read_data(&data_prev)) != NULL)
+		goto out;
+	
+	/* Compute some rubbish to have initialised values */
+	if ((ret = compute_percentages(&data_prev, &data_prev)) != NULL)
+		goto out;
+	
+	/* And paint screen until death */
+	operation_type = OP_TASKS;
+	while (true) {
+		int c = tgetchar(UPDATE_INTERVAL);
+		if (c < 0) {
+			if ((ret = read_data(&data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			if ((ret = compute_percentages(&data_prev, &data)) != NULL) {
+				free_data(&data);
+				goto out;
+			}
+			
+			print_data(&data);
+			free_data(&data_prev);
+			data_prev = data;
+			
+			continue;
+		}
+		
+		switch (c) {
+			case 'q':
+				goto out;
+			case 'i':
+				print_warning("Showing IPC statistics");
+				operation_type = OP_IPC;
+				break;
+			case 't':
+				print_warning("Showing task statistics");
+				operation_type = OP_TASKS;
+				break;
+			default:
+				print_warning("Unknown command: %c", c);
+				break;
+		}
+	}
+	
+out:
+	screen_done();
+	free_data(&data_prev);
+	
+	if (ret != NULL) {
+		fprintf(stderr, "%s: %s\n", NAME, ret);
+		return 1;
+	}
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/top/top.h
===================================================================
--- uspace/app/top/top.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
+++ uspace/app/top/top.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Stanislav Kozina
+ * Copyright (c) 2010 Martin Decky
+ * 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.
+ */
+
+/** @addtogroup top
+ * @{
+ */
+
+#ifndef TOP_TOP_H_
+#define TOP_TOP_H_
+
+#include <task.h>
+#include <stats.h>
+#include <time.h>
+
+#define FRACTION_TO_FLOAT(float, a, b) { \
+	(float).upper = (a); \
+	(float).lower = (b); \
+}
+
+#define OP_TASKS  1
+#define OP_IPC    2
+
+extern int operation_type;
+
+typedef struct {
+	uint64_t upper;
+	uint64_t lower;
+} fixed_float;
+
+typedef struct {
+	fixed_float idle;
+	fixed_float busy;
+} perc_cpu_t;
+
+typedef struct {
+	fixed_float ucycles;
+	fixed_float kcycles;
+	fixed_float virtmem;
+} perc_task_t;
+
+typedef struct {
+	time_t hours;
+	time_t minutes;
+	time_t seconds;
+	
+	sysarg_t udays;
+	sysarg_t uhours;
+	sysarg_t uminutes;
+	sysarg_t useconds;
+	
+	size_t load_count;
+	load_t *load;
+	
+	size_t cpus_count;
+	stats_cpu_t *cpus;
+	perc_cpu_t *cpus_perc;
+	
+	size_t tasks_count;
+	stats_task_t *tasks;
+	perc_task_t *tasks_perc;
+	
+	size_t threads_count;
+	stats_thread_t *threads;
+	
+	stats_physmem_t *physmem;
+} data_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/app/trace/Makefile
===================================================================
--- uspace/app/trace/Makefile	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/Makefile	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -29,7 +29,5 @@
 
 USPACE_PREFIX = ../..
-LIBS = $(LIBC_PREFIX)/libc.a
-
-OUTPUT = trace
+BINARY = trace
 
 SOURCES = \
@@ -41,3 +39,3 @@
 	errors.c
 
-include ../Makefile.common
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/trace/errors.h
===================================================================
--- uspace/app/trace/errors.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/errors.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -37,6 +37,6 @@
 
 typedef struct {
-	char *name;	/**< Error value name (Exx) */
-	char *desc;	/**< Error description */
+	const char *name;  /**< Error value name (Exx) */
+	const char *desc;  /**< Error description */
 } err_desc_t;
 
Index: uspace/app/trace/ipc_desc.h
===================================================================
--- uspace/app/trace/ipc_desc.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/ipc_desc.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -38,5 +38,5 @@
 typedef struct {
 	int number;
-	char *name;
+	const char *name;
 } ipc_m_desc_t;
 
Index: uspace/app/trace/proto.c
===================================================================
--- uspace/app/trace/proto.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/proto.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -157,5 +157,5 @@
 }
 
-static void proto_struct_init(proto_t *proto, char *name)
+static void proto_struct_init(proto_t *proto, const char *name)
 {
 	proto->name = name;
@@ -164,5 +164,5 @@
 }
 
-proto_t *proto_new(char *name)
+proto_t *proto_new(const char *name)
 {
 	proto_t *p;
@@ -206,10 +206,10 @@
 }
 
-static void oper_struct_init(oper_t *oper, char *name)
+static void oper_struct_init(oper_t *oper, const char *name)
 {
 	oper->name = name;
 }
 
-oper_t *oper_new(char *name, int argc, val_type_t *arg_types,
+oper_t *oper_new(const char *name, int argc, val_type_t *arg_types,
     val_type_t rv_type, int respc, val_type_t *resp_types)
 {
Index: uspace/app/trace/proto.h
===================================================================
--- uspace/app/trace/proto.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/proto.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -43,5 +43,5 @@
 
 typedef struct {
-	char *name;
+	const char *name;
 
 	int argc;
@@ -56,5 +56,5 @@
 typedef struct {
 	/** Protocol name */
-	char *name;
+	const char *name;
 
 	/** Maps method number to operation */
@@ -70,10 +70,10 @@
 void proto_register(int srv, proto_t *proto);
 proto_t *proto_get_by_srv(int srv);
-proto_t *proto_new(char *name);
+proto_t *proto_new(const char *name);
 void proto_delete(proto_t *proto);
 void proto_add_oper(proto_t *proto, int method, oper_t *oper);
 oper_t *proto_get_oper(proto_t *proto, int method);
 
-oper_t *oper_new(char *name, int argc, val_type_t *arg_types,
+oper_t *oper_new(const char *name, int argc, val_type_t *arg_types,
     val_type_t rv_type, int respc, val_type_t *resp_types);
 
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/syscalls.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -76,6 +76,9 @@
 	[SYS_INTERRUPT_ENABLE] = { "interrupt_enable",	2,	V_ERRNO },
 
-    [SYS_SYSINFO_VALID] = { "sysinfo_valid",		2,	V_HASH },
-    [SYS_SYSINFO_VALUE] = { "sysinfo_value",		2,	V_HASH },
+    [SYS_SYSINFO_GET_TAG] = { "sysinfo_get_tag",		2,	V_INTEGER },
+    [SYS_SYSINFO_GET_VALUE] = { "sysinfo_get_value",		3,	V_ERRNO },
+    [SYS_SYSINFO_GET_DATA_SIZE] = { "sysinfo_get_data_size",	3,	V_ERRNO },
+    [SYS_SYSINFO_GET_DATA] = { "sysinfo_get_data",		4,	V_ERRNO },
+
     [SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0,	V_ERRNO },
     [SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox",	1,	V_ERRNO }
Index: uspace/app/trace/syscalls.h
===================================================================
--- uspace/app/trace/syscalls.h	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/syscalls.h	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -39,5 +39,5 @@
 
 typedef struct {
-	char *name;
+	const char *name;
 	int n_args;
 	val_type_t rv_type;
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision cf8cc3692ffb17058d5881b6bfdde3a4a5d050fd)
+++ uspace/app/trace/trace.c	(revision 5159ae9cfe175971e2b16fd2a8cf120ffefe7cf2)
@@ -43,5 +43,5 @@
 #include <task.h>
 #include <mem.h>
-#include <string.h>
+#include <str.h>
 #include <bool.h>
 #include <loader/loader.h>
@@ -585,5 +585,5 @@
 }
 
-static loader_t *preload_task(const char *path, char *const argv[],
+static loader_t *preload_task(const char *path, char **argv,
     task_id_t *task_id)
 {
@@ -591,5 +591,5 @@
 	int rc;
 
-	/* Spawn a program loader */	
+	/* Spawn a program loader */
 	ldr = loader_connect();
 	if (ldr == NULL)
@@ -607,5 +607,5 @@
 
 	/* Send arguments */
-	rc = loader_set_args(ldr, argv);
+	rc = loader_set_args(ldr, (const char **) argv);
 	if (rc != EOK)
 		goto error;
@@ -870,25 +870,31 @@
 }
 
-static display_mask_t parse_display_mask(char *text)
+static display_mask_t parse_display_mask(const char *text)
 {
 	display_mask_t dm;
-	char *c;
-
-	c = text;
-
+	const char *c = text;
+	
 	while (*c) {
 		switch (*c) {
-		case 't': dm = dm | DM_THREAD; break;
-		case 's': dm = dm | DM_SYSCALL; break;
-		case 'i': dm = dm | DM_IPC; break;
-		case 'p': dm = dm | DM_SYSTEM | DM_USER; break;
+		case 't':
+			dm = dm | DM_THREAD;
+			break;
+		case 's':
+			dm = dm | DM_SYSCALL;
+			break;
+		case 'i':
+			dm = dm | DM_IPC;
+			break;
+		case 'p':
+			dm = dm | DM_SYSTEM | DM_USER;
+			break;
 		default:
 			printf("Unexpected event type '%c'.\n", *c);
 			exit(1);
 		}
-
+		
 		++c;
 	}
-
+	
 	return dm;
 }
@@ -896,13 +902,13 @@
 static int parse_args(int argc, char *argv[])
 {
-	char *arg;
 	char *err_p;
 
 	task_id = 0;
 
-	--argc; ++argv;
+	--argc;
+	++argv;
 
 	while (argc > 0) {
-		arg = *argv;
+		char *arg = *argv;
 		if (arg[0] == '+') {
 			display_mask = parse_display_mask(&arg[1]);
@@ -910,5 +916,6 @@
 			if (arg[1] == 't') {
 				/* Trace an already running task */
-				--argc; ++argv;
+				--argc;
+				++argv;
 				task_id = strtol(*argv, &err_p, 10);
 				task_ldr = NULL;
@@ -927,10 +934,12 @@
 			break;
 		}
-
-		--argc; ++argv;
+		
+		--argc;
+		++argv;
 	}
 
 	if (task_id != 0) {
-		if (argc == 0) return 0;
+		if (argc == 0)
+			return 0;
 		printf("Extra arguments\n");
 		print_syntax();
@@ -946,8 +955,9 @@
 	/* Preload the specified program file. */
 	printf("Spawning '%s' with arguments:\n", *argv);
-	{
-		char **cp = argv;
-		while (*cp) printf("'%s'\n", *cp++);
-	}
+	
+	char **cp = argv;
+	while (*cp)
+		printf("'%s'\n", *cp++);
+	
 	task_ldr = preload_task(*argv, argv, &task_id);
 	task_wait_for = true;
