Index: uspace/app/bithenge/Makefile
===================================================================
--- uspace/app/bithenge/Makefile	(revision 5a7c0e69a8cde81b5273b8c4db8c48fa734f8665)
+++ uspace/app/bithenge/Makefile	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
@@ -35,4 +35,5 @@
 	helenos/block.c \
 	blob.c \
+	expression.c \
 	file.c \
 	print.c \
Index: uspace/app/bithenge/Makefile.linux
===================================================================
--- uspace/app/bithenge/Makefile.linux	(revision 5a7c0e69a8cde81b5273b8c4db8c48fa734f8665)
+++ uspace/app/bithenge/Makefile.linux	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
@@ -36,4 +36,5 @@
 SOURCES = \
 	blob.c \
+	expression.c \
 	file.c \
 	print.c \
Index: uspace/app/bithenge/expression.c
===================================================================
--- uspace/app/bithenge/expression.c	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
+++ uspace/app/bithenge/expression.c	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Expressions.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "blob.h"
+#include "expression.h"
+#include "transform.h"
+#include "tree.h"
+
+/** Initialize a new expression.
+ * @param[out] self Expression to initialize.
+ * @param[in] ops Operations provided by the expression.
+ * @return EOK or an error code from errno.h. */
+int bithenge_init_expression(bithenge_expression_t *self,
+    const bithenge_expression_ops_t *ops)
+{
+	assert(ops);
+	assert(ops->evaluate);
+	assert(ops->destroy);
+	self->ops = ops;
+	self->refs = 1;
+	return EOK;
+}
+
+typedef struct {
+	bithenge_expression_t base;
+	int index;
+} param_expression_t;
+
+static inline param_expression_t *expression_as_param(
+    bithenge_expression_t *base)
+{
+	return (param_expression_t *)base;
+}
+
+static inline bithenge_expression_t *param_as_expression(
+    param_expression_t *self)
+{
+	return &self->base;
+}
+
+static int param_expression_evaluate(bithenge_expression_t *base,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	param_expression_t *self = expression_as_param(base);
+	return bithenge_scope_get_param(scope, self->index, out);
+}
+
+static void param_expression_destroy(bithenge_expression_t *base)
+{
+	param_expression_t *self = expression_as_param(base);
+	free(self);
+}
+
+static const bithenge_expression_ops_t param_expression_ops = {
+	.evaluate = param_expression_evaluate,
+	.destroy = param_expression_destroy,
+};
+
+/** Create an expression that returns a parameter.
+ * @param[out] out Holds the created expression.
+ * @param index The index of the parameter to get.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_param_expression(bithenge_expression_t **out, int index)
+{
+	int rc;
+	param_expression_t *self = malloc(sizeof(*self));
+	if (!self)
+		return ENOMEM;
+
+	rc = bithenge_init_expression(param_as_expression(self),
+	    &param_expression_ops);
+	if (rc != EOK) {
+		free(self);
+		return rc;
+	}
+
+	self->index = index;
+	*out = param_as_expression(self);
+	return EOK;
+}
+
+typedef struct {
+	bithenge_expression_t base;
+	bithenge_node_t *node;
+} const_expression_t;
+
+static inline const_expression_t *expression_as_const(
+    bithenge_expression_t *base)
+{
+	return (const_expression_t *)base;
+}
+
+static inline bithenge_expression_t *const_as_expression(
+    const_expression_t *self)
+{
+	return &self->base;
+}
+
+static int const_expression_evaluate(bithenge_expression_t *base,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	const_expression_t *self = expression_as_const(base);
+	bithenge_node_inc_ref(self->node);
+	*out = self->node;
+	return EOK;
+}
+
+static void const_expression_destroy(bithenge_expression_t *base)
+{
+	const_expression_t *self = expression_as_const(base);
+	bithenge_node_dec_ref(self->node);
+	free(self);
+}
+
+static const bithenge_expression_ops_t const_expression_ops = {
+	.evaluate = const_expression_evaluate,
+	.destroy = const_expression_destroy,
+};
+
+/** Create an expression that returns a constant. Takes a reference to @a node.
+ * @param[out] out Holds the created expression.
+ * @param node The constant.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_const_expression(bithenge_expression_t **out,
+    bithenge_node_t *node)
+{
+	int rc;
+	const_expression_t *self = malloc(sizeof(*self));
+	if (!self)
+		return ENOMEM;
+
+	rc = bithenge_init_expression(const_as_expression(self),
+	    &const_expression_ops);
+	if (rc != EOK) {
+		free(self);
+		return rc;
+	}
+
+	self->node = node;
+	*out = const_as_expression(self);
+	return EOK;
+}
+
+typedef struct {
+	bithenge_transform_t base;
+	bithenge_transform_t *transform;
+	bithenge_expression_t **params;
+} param_wrapper_t;
+
+static inline bithenge_transform_t *param_wrapper_as_transform(
+    param_wrapper_t *self)
+{
+	return &self->base;
+}
+
+static inline param_wrapper_t *transform_as_param_wrapper(
+    bithenge_transform_t *base)
+{
+	return (param_wrapper_t *)base;
+}
+
+static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
+    *inner, bithenge_scope_t *outer)
+{
+	int rc;
+	int num_params = bithenge_transform_num_params(self->transform);
+	rc = bithenge_scope_alloc_params(inner, num_params);
+	if (rc != EOK)
+		return rc;
+	for (int i = 0; i < num_params; i++) {
+		bithenge_node_t *node;
+		rc = bithenge_expression_evaluate(self->params[i], outer,
+		    &node);
+		if (rc != EOK)
+			return rc;
+		rc = bithenge_scope_set_param(inner, i, node);
+		if (rc != EOK)
+			return rc;
+	}
+	return EOK;
+}
+
+static int param_wrapper_apply(bithenge_transform_t *base,
+    bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	bithenge_scope_t inner;
+	bithenge_scope_init(&inner);
+	int rc = param_wrapper_fill_scope(self, &inner, outer);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_transform_apply(self->transform, &inner, in, out);
+	in = NULL;
+
+error:
+	bithenge_node_dec_ref(in);
+	bithenge_scope_destroy(&inner);
+	return rc;
+}
+
+
+static int param_wrapper_prefix_length(bithenge_transform_t *base,
+    bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	bithenge_scope_t inner;
+	bithenge_scope_init(&inner);
+	int rc = param_wrapper_fill_scope(self, &inner, outer);
+	if (rc != EOK)
+		goto error;
+
+	rc = bithenge_transform_prefix_length(self->transform, &inner, in,
+	    out);
+	in = NULL;
+
+error:
+	bithenge_blob_dec_ref(in);
+	bithenge_scope_destroy(&inner);
+	return rc;
+}
+static void param_wrapper_destroy(bithenge_transform_t *base)
+{
+	param_wrapper_t *self = transform_as_param_wrapper(base);
+	int num_params = bithenge_transform_num_params(self->transform);
+	bithenge_transform_dec_ref(self->transform);
+	for (int i = 0; i < num_params; i++)
+		bithenge_expression_dec_ref(self->params[i]);
+	free(self->params);
+	free(self);
+}
+
+static const bithenge_transform_ops_t param_wrapper_ops = {
+	.apply = param_wrapper_apply,
+	.prefix_length = param_wrapper_prefix_length,
+	.destroy = param_wrapper_destroy,
+	.num_params = 0, /* This transform should not be used inside another
+			    param_wrapper or explicitly in a script, so this
+			    number doesn't matter. */
+};
+
+/** Create a transform that calculates parameters for another transform. Takes
+ * ownership of @a transform, @a params, and each element of @a params. The
+ * number of parameters must be correct.
+ * @param[out] out Holds the new transform.
+ * @param transform The transform for which parameters are calculated.
+ * @param params The expressions used to calculate the parameters.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_param_wrapper(bithenge_transform_t **out,
+    bithenge_transform_t *transform, bithenge_expression_t **params)
+{
+	int rc;
+	int num_params = bithenge_transform_num_params(transform);
+	param_wrapper_t *self = malloc(sizeof(*self));
+	if (!self) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = bithenge_init_transform(param_wrapper_as_transform(self),
+	    &param_wrapper_ops);
+	if (rc != EOK)
+		goto error;
+
+	self->transform = transform;
+	self->params = params;
+	*out = param_wrapper_as_transform(self);
+	return EOK;
+
+error:
+	free(self);
+	for (int i = 0; i < num_params; i++)
+		bithenge_expression_dec_ref(params[i]);
+	free(params);
+	bithenge_transform_dec_ref(transform);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/app/bithenge/expression.h
===================================================================
--- uspace/app/bithenge/expression.h	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
+++ uspace/app/bithenge/expression.h	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012 Sean Bartell
+ * 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 bithenge
+ * @{
+ */
+/**
+ * @file
+ * Expressions.
+ */
+
+#ifndef BITHENGE_EXPRESSION_H_
+#define BITHENGE_EXPRESSION_H_
+
+#include "transform.h"
+#include "tree.h"
+
+/** An expression that calculates a value given a scope. */
+typedef struct {
+	/** @privatesection */
+	const struct bithenge_expression_ops *ops;
+	unsigned int refs;
+} bithenge_expression_t;
+
+/** Operations provided by an expression. */
+typedef struct bithenge_expression_ops {
+	/** @copydoc bithenge_expression_t::bithenge_expression_evaluate */
+	int (*evaluate)(bithenge_expression_t *self, bithenge_scope_t *scope,
+	    bithenge_node_t **out);
+	/** Destroy the expression.
+	 * @param self The expression. */
+	void (*destroy)(bithenge_expression_t *self);
+} bithenge_expression_ops_t;
+
+/** Increment an expression's reference count.
+ * @param self The expression to reference. */
+static inline void bithenge_expression_inc_ref(bithenge_expression_t *self)
+{
+	assert(self);
+	self->refs++;
+}
+
+/** Decrement an expression's reference count and free it if appropriate.
+ * @param self The expression to dereference, or NULL. */
+static inline void bithenge_expression_dec_ref(bithenge_expression_t *self)
+{
+	if (!self)
+		return;
+	assert(self->ops);
+	if (--self->refs == 0)
+		self->ops->destroy(self);
+}
+
+/** Evaluate an expression. Takes ownership of nothing.
+ * @memberof bithenge_expression_t
+ * @param self The expression.
+ * @param scope The scope.
+ * @param[out] out Where the output tree will be stored.
+ * @return EOK on success or an error code from errno.h. */
+static inline int bithenge_expression_evaluate(bithenge_expression_t *self,
+    bithenge_scope_t *scope, bithenge_node_t **out)
+{
+	assert(self);
+	assert(self->ops);
+	return self->ops->evaluate(self, scope, out);
+}
+
+int bithenge_init_expression(bithenge_expression_t *,
+    const bithenge_expression_ops_t *);
+int bithenge_param_expression(bithenge_expression_t **, int);
+int bithenge_const_expression(bithenge_expression_t **, bithenge_node_t *);
+int bithenge_param_wrapper(bithenge_transform_t **, bithenge_transform_t *,
+    bithenge_expression_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/bithenge/transform.h
===================================================================
--- uspace/app/bithenge/transform.h	(revision 5a7c0e69a8cde81b5273b8c4db8c48fa734f8665)
+++ uspace/app/bithenge/transform.h	(revision 6e34bd064f1f4400be75c04c79e90a5d097c2927)
@@ -101,4 +101,6 @@
 		return ENOMEM;
 	scope->num_params = num_params;
+	for (int i = 0; i < num_params; i++)
+		scope->params[i] = NULL;
 	return EOK;
 }
