diff --git a/libwccl/ops/functions/position/firsttoken.cpp b/libwccl/ops/functions/position/firsttoken.cpp
index 8c900756afc3c6029c85b8a75c73d4b3bdb3bf63..b92b66d608574bf2488495d942219e5ca014f3e8 100644
--- a/libwccl/ops/functions/position/firsttoken.cpp
+++ b/libwccl/ops/functions/position/firsttoken.cpp
@@ -21,7 +21,9 @@ FirstToken::BaseRetValPtr FirstToken::apply_internal(
 	if(match->empty()) {
 		return detail::DefaultFunction<Position>()->apply(context);
 	}
-	return boost::make_shared<Position>(match->first_token(s));
+	int abs_pos = match->first_token(s);
+	int rel_pos = abs_pos - context.sentence_context().get_position();
+	return boost::make_shared<Position>(rel_pos);
 }
 
 std::string FirstToken::to_string(const Corpus2::Tagset &tagset) const
diff --git a/libwccl/ops/functions/position/lasttoken.cpp b/libwccl/ops/functions/position/lasttoken.cpp
index 6d4ca00193da63f17cd35f717054eb21d93ffbd0..6b4f43ecd83251faf7a4cdadd6792b5bec953e0d 100644
--- a/libwccl/ops/functions/position/lasttoken.cpp
+++ b/libwccl/ops/functions/position/lasttoken.cpp
@@ -14,13 +14,15 @@ LastToken::BaseRetValPtr LastToken::apply_internal(
 	if (!s) {
 		throw InvalidArgument(
 			"context",
-			"Supplied context does not have valid Corpus2::AnnotatedSentence.");
+			"Supplied context does not have a valid Corpus2::AnnotatedSentence.");
 	}
 	const Function<Match>::RetValPtr match = match_expr_->apply(context);
 	if(match->empty()) {
 		return detail::DefaultFunction<Position>()->apply(context);
 	}
-	return boost::make_shared<Position>(match->last_token(s));
+	int abs_pos = match->last_token(s);
+	int rel_pos = abs_pos - context.sentence_context().get_position();
+	return boost::make_shared<Position>(rel_pos);
 }
 
 std::string LastToken::to_string(const Corpus2::Tagset &tagset) const