diff --git a/libwccl/CMakeLists.txt b/libwccl/CMakeLists.txt
index 8bbf14623039956534e0c130c0c9b1c4a24eeded..5ed26c712a614d56ed3d13ad962a7d64019c1adf 100644
--- a/libwccl/CMakeLists.txt
+++ b/libwccl/CMakeLists.txt
@@ -16,6 +16,7 @@ SET(libwccl_STAT_SRC
 	sentencecontext.cpp
 	values/bool.cpp
 	values/position.cpp
+	values/positionref.cpp
 	values/value.cpp
 	variables.cpp
 )
diff --git a/libwccl/sentencecontext.cpp b/libwccl/sentencecontext.cpp
index 591d89c5bb376c5aabd9ea458313aca2422bcfe5..68f9c6dad53fa4761f78109a76524161c50b590d 100644
--- a/libwccl/sentencecontext.cpp
+++ b/libwccl/sentencecontext.cpp
@@ -19,4 +19,25 @@ SentenceContext* SentenceContext::clone() const
 	return new SentenceContext(duplicate());
 }
 
+int SentenceContext::get_abs_position(const Position &position) const
+{
+	return translate_special_position(position.get_value());
+}
+
+int SentenceContext::get_abs_position(const PositionRef &position) const
+{
+	int p = translate_special_position(position.get_base()->get_value());
+	return p + position.get_offset();
+}
+
+int SentenceContext::get_rel_position(const Position &position) const
+{
+	return get_abs_position(position) - position_;
+}
+
+int SentenceContext::get_rel_position(const PositionRef &position) const
+{
+	return get_abs_position(position) - position_;
+}
+
 } /* end ns Wccl */
diff --git a/libwccl/sentencecontext.h b/libwccl/sentencecontext.h
index 1994db44f49401615bc439513b5eff11188941fd..3604c54a27a0de6a3cd92b17b8ae29b8e046b21e 100644
--- a/libwccl/sentencecontext.h
+++ b/libwccl/sentencecontext.h
@@ -2,6 +2,7 @@
 #define LIBWCCL_SENTENCECONTEXT_H
 
 #include <libcorpus2/sentence.h>
+#include <libwccl/values/positionref.h>
 #include <boost/shared_ptr.hpp>
 
 namespace Wccl {
@@ -18,7 +19,7 @@ class SentenceContext
 {
 public:
 	/// Constructor, wraps the Sentence and sets position to 0
-	SentenceContext(const boost::shared_ptr<Corpus2::Sentence>& s);
+	explicit SentenceContext(const boost::shared_ptr<Corpus2::Sentence>& s);
 
 	/// Returns a copy of this with a cloned underlyiong sentence
 	SentenceContext duplicate() const;
@@ -47,8 +48,13 @@ public:
 	}
 
 	/// Checks if the current position is valid (within the sentence bounds)
-	bool is_inside() const {
-		return position_ >= 0 && position_ < size();
+	bool is_current_inside() const {
+		return is_inside(position_);
+	}
+
+	/// Checks if the the given absolute position is valid (in sentence bounds)
+	bool is_inside(int abs_pos) const {
+		return abs_pos >= 0 && abs_pos < size();
 	}
 
 	/// Position setter
@@ -57,7 +63,7 @@ public:
 	}
 
 	/// Position advance shorthand
-	void position() {
+	void advance() {
 		++position_;
 	}
 
@@ -69,7 +75,7 @@ public:
 	/// Token access convenience function - const.
 	/// Will return NULL if the passed position is not valid in this Sentence
 	const Corpus2::Token* at(int position) const {
-		if (is_inside()) {
+		if (is_current_inside()) {
 			return get_sentence()[position];
 		} else {
 			return NULL;
@@ -79,7 +85,7 @@ public:
 	/// Token access convenience function.
 	/// Will return NULL if the passed position is not valid in this Sentence
 	Corpus2::Token* at(int position) {
-		if (is_inside()) {
+		if (is_current_inside()) {
 			return get_sentence()[position];
 		} else {
 			return NULL;
@@ -96,7 +102,28 @@ public:
 		return at(position_);
 	}
 
+	int get_abs_position(const Position& position) const;
+
+	int get_abs_position(const PositionRef& position) const;
+
+	int get_rel_position(const Position& position) const;
+
+	int get_rel_position(const PositionRef& position) const;
+
+	int translate_special_position(int pos) const {
+		switch (pos) {
+		case Position::Begin:
+			return 0;
+		case Position::End:
+			return sentence_->size() - 1;
+		case Position::Nowhere:
+			return Position::Nowhere;
+		default:
+			return position_ + pos;
+		}
+	}
 private:
+
 	/// The wrapped sentence
 	boost::shared_ptr<Corpus2::Sentence> sentence_;
 
diff --git a/libwccl/values/position.cpp b/libwccl/values/position.cpp
index d422ccb4b0bbe81ce27d5e82593e8948b46ed4c5..329c65a8770132125d3b4be1335ded35ad6bee35 100644
--- a/libwccl/values/position.cpp
+++ b/libwccl/values/position.cpp
@@ -6,7 +6,16 @@ const char* Position::type_name = "Position";
 
 std::string Position::to_raw_string() const
 {
-	return boost::lexical_cast<std::string>(val_);
+	switch (val_) {
+	case Nowhere:
+		return "nowhere";
+	case Begin:
+		return "begin";
+	case End:
+		return "end";
+	default:
+		return boost::lexical_cast<std::string>(val_);
+	}
 }
 
 } /* end ns Wccl */
diff --git a/libwccl/values/position.h b/libwccl/values/position.h
index ee7b05941c3e31adde3607c1cdb2e64c1e330d13..0b2148b436e01e4018b955a101d6dc5cb8cb3376 100644
--- a/libwccl/values/position.h
+++ b/libwccl/values/position.h
@@ -3,6 +3,7 @@
 
 #include <libwccl/values/value.h>
 #include <cstdlib>
+#include <boost/integer_traits.hpp>
 
 namespace Wccl {
 
@@ -16,6 +17,10 @@ public:
 	{
 	}
 
+	static const int Nowhere = boost::integer_traits<int>::const_min;
+	static const int Begin = boost::integer_traits<int>::const_min + 1;
+	static const int End = boost::integer_traits<int>::const_max;
+
 	int get_value() const {
 		return val_;
 	}
diff --git a/libwccl/values/positionref.cpp b/libwccl/values/positionref.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b790885ed3e8215d0cbbc366dc3c79830059a9c
--- /dev/null
+++ b/libwccl/values/positionref.cpp
@@ -0,0 +1,19 @@
+#include <libwccl/values/positionref.h>
+#include <sstream>
+
+namespace Wccl {
+
+const char* PositionRef::type_name = "PositionRef";
+
+std::string PositionRef::to_raw_string() const
+{
+	std::stringstream ss;
+	ss << base_->get_value();
+	if (offset_ >=0) {
+		ss << "+";
+	}
+	ss << offset_;
+	return ss.str();
+}
+
+} /* end ns Wccl */
diff --git a/libwccl/values/positionref.h b/libwccl/values/positionref.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcb8667025e9bf558462c6a45a10adec8c821484
--- /dev/null
+++ b/libwccl/values/positionref.h
@@ -0,0 +1,48 @@
+#ifndef LIBWCCL_VALUES_POSITIONREF_H
+#define LIBWCCL_VALUES_POSITIONREF_H
+
+#include <libwccl/values/position.h>
+#include <boost/make_shared.hpp>
+
+namespace Wccl {
+
+class PositionRef : public Value
+{
+public:
+	WCCL_VALUE_PREAMBLE
+
+	explicit PositionRef(const boost::shared_ptr<Position>& base,
+			int offset = 0)
+		: base_(base), offset_(offset)
+	{
+		assert(base_);
+	}
+
+	explicit PositionRef(int base, int offset = 0)
+		: base_(boost::make_shared<Position>(base)), offset_(offset)
+	{
+	}
+
+	std::string to_raw_string() const;
+
+	const boost::shared_ptr<Position>& get_base() const {
+		return base_;
+	}
+
+	int get_offset() const {
+		return offset_;
+	}
+
+	void set_offset(int offset) {
+		offset_ = offset;
+	}
+
+private:
+	boost::shared_ptr<Position> base_;
+
+	int offset_;
+};
+
+} /* end ns Wccl */
+
+#endif // LIBWCCL_VALUES_POSITIONREF_H
diff --git a/libwccl/variables.h b/libwccl/variables.h
index 8cc21277272cc43813eef5c7791d0fe6e0c278ee..ea77194746658e8dc06fadd7782bcb2e2399a9f4 100644
--- a/libwccl/variables.h
+++ b/libwccl/variables.h
@@ -4,6 +4,7 @@
 #include <libwccl/values/bool.h>
 #include <libwccl/exception.h>
 #include <libwccl/values/position.h>
+#include <libwccl/values/positionref.h>
 #include <iostream>
 #include <map>
 #include <string>
@@ -82,11 +83,12 @@ public:
 class Variables : detail::Vmap<Value>
 	, detail::Vmap<Bool>
 	, detail::Vmap<Position>
+	, detail::Vmap<PositionRef>
 {
 public:
 	/// Valid value types, should match the inheritance.
 	/// the type Value must be first, order of other items is not important
-	typedef boost::mpl::list<Value, Bool, Position> types;
+	typedef boost::mpl::list<Value, Bool, Position, PositionRef> types;
 
 	/// Constructor, creates an empty instance.
 	Variables();
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5d575c52ec1ba0d9f178691ed3ec447b18583e57..e56b4db7f09580c88cfcda1df87b93d1236aeff1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -7,6 +7,7 @@ add_definitions(-DLIBWCCL_TEST_DATA_DIR="${PROJECT_SOURCE_DIR}/")
 add_executable(tests
 	main.cpp
 	variables.cpp
+	position.cpp
 	context.cpp
 )
 
diff --git a/tests/context.cpp b/tests/context.cpp
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c15a817405cae7189d5ae17452ed47c8f86f156 100644
--- a/tests/context.cpp
+++ b/tests/context.cpp
@@ -0,0 +1,226 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+
+#include <libwccl/variables.h>
+#include <libwccl/sentencecontext.h>
+
+#include <iostream>
+
+using namespace Wccl;
+
+BOOST_AUTO_TEST_SUITE(context_position)
+
+BOOST_AUTO_TEST_CASE(contex_init)
+{
+	SentenceContext sc(boost::make_shared<Corpus2::Sentence>());
+	BOOST_CHECK_EQUAL(sc.size(), 0);
+	BOOST_CHECK_EQUAL(sc.get_position(), 0);
+}
+
+struct Fpos
+{
+	Fpos()
+		: sc(boost::make_shared<Corpus2::Sentence>())
+	{
+		using namespace Corpus2;
+		using namespace PwrNlp::Whitespace;
+		sc.get_sentence().append(
+				new Token(UnicodeString::fromUTF8("t1"), Space));
+		sc.get_sentence().append(
+				new Token(UnicodeString::fromUTF8("t2"), Space));
+		sc.get_sentence().append(
+				new Token(UnicodeString::fromUTF8("t3"), Space));
+	}
+
+	SentenceContext sc;
+};
+
+BOOST_FIXTURE_TEST_CASE(scadvance, Fpos)
+{
+	BOOST_CHECK(sc.is_current_inside());
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_position(), 1);
+	BOOST_CHECK(sc.is_current_inside());
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_position(), 2);
+	BOOST_CHECK(sc.is_current_inside());
+	sc.advance();
+	BOOST_CHECK(!sc.is_current_inside());
+	sc.goto_start();
+	BOOST_CHECK(sc.is_current_inside());
+	BOOST_CHECK_EQUAL(sc.get_position(), 0);
+}
+
+BOOST_FIXTURE_TEST_CASE(pos0, Fpos)
+{
+	Position p(0);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(pos1, Fpos)
+{
+	Position p(1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(posneg1, Fpos)
+{
+	Position p(-1);
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(pos_begin, Fpos)
+{
+	Position p(Position::Begin);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -2);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -3);
+}
+
+BOOST_FIXTURE_TEST_CASE(pos_end, Fpos)
+{
+	Position p(Position::End);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 2);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+}
+
+BOOST_FIXTURE_TEST_CASE(pos_no, Fpos)
+{
+	Position p(Position::Nowhere);
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+
+BOOST_FIXTURE_TEST_CASE(posref0, Fpos)
+{
+	PositionRef p(0, 1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(posref1m1, Fpos)
+{
+	PositionRef p(1, -1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(posref1_1, Fpos)
+{
+	PositionRef p(-1, 1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 0);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 2);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_FIXTURE_TEST_CASE(posref_begin, Fpos)
+{
+	PositionRef p(Position::Begin, 1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -2);
+}
+
+BOOST_FIXTURE_TEST_CASE(posref_end, Fpos)
+{
+	PositionRef p(Position::End, -1);
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), 0);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -1);
+	sc.advance();
+	BOOST_CHECK_EQUAL(sc.get_abs_position(p), 1);
+	BOOST_CHECK_EQUAL(sc.get_rel_position(p), -2);
+}
+
+BOOST_FIXTURE_TEST_CASE(posref_no, Fpos)
+{
+	PositionRef p(Position::Nowhere, 1);
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+	sc.advance();
+	BOOST_CHECK(!sc.is_inside(sc.get_abs_position(p)));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/tests/position.cpp b/tests/position.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391