Index: makefile
===================================================================
--- makefile	(version 2026.08.10)
+++ makefile
@@ -206,7 +206,7 @@
 
 	commonflags := -c -pipe -x c++ -std=c++17 --pedantic -Wfatal-errors
 
-	cflags = $(commonflags) -Werror -Wall -Wextra -Wmissing-noreturn -Wno-switch -Wno-empty-body -Wno-parentheses -Wzero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-return-type -Wno-misleading-indentation -Wno-psabi -Wno-implicit-fallthrough -Wno-suggest-attribute=noreturn -o $(notdir $@)
+	cflags = $(commonflags) -Werror -Wall -Wextra -Wmissing-noreturn -Wno-switch -Wno-empty-body -Wno-parentheses -Wzero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-overloaded-virtual -Wno-return-type -Wno-misleading-indentation -Wno-psabi -Wno-implicit-fallthrough -Wno-suggest-attribute=noreturn -o $(notdir $@)
 	lflags = -o $(notdir $@)
 
 	ccheckflags := $(commonflags) -fsyntax-only
@@ -1199,8 +1199,8 @@
 lib := $(addprefix $(runtime), $(addsuffix run.lib, $(addprefix cpp, $(targets)) $(addprefix ob, $(targets))))
 std := $(addprefix $(cpplibrary), cassert.cpp cctype.cpp cmath.cpp csetjmp.cpp cstdio.cpp cstdlib.cpp cstring.cpp ctime.cpp debugging.cpp exception.cpp)
 hdr := $(addprefix $(cpplibrary), algorithm any array assert.h atomic barrier bit bitset cassert cctype cerrno cfenv cfloat charconv chrono cinttypes climits clocale cmath codecvt compare complex complex.h concepts condition_variable coroutine csetjmp csignal cstdarg cstddef cstdint cstdio cstdlib cstring ctime ctype.h cuchar cwchar cwctype debugging deque errno.h exception execution expected fenv.h filesystem flat_map flat_set float.h format forward_list fstream functional future generator initializer_list inttypes.h iomanip ios iosfwd iostream iso646.h istream iterator latch limits limits.h list locale locale.h map math.h mdspan memory memory_resource mutex new numbers numeric optional ostream print queue random ranges ratio rcu regex scoped_allocator semaphore set setjmp.h shared_mutex signal.h source_location span spanstream sstream stack stacktrace stdalign.h stdarg.h stdatomic.h stdbool.h stddef.h stdexcept stdfloat stdint.h stdio.h stdlib.h stop_token streambuf string string.h string_view strstream syncstream system_error text_encoding tgmath.h thread time.h tuple type_traits typeindex typeinfo uchar.h unordered_map unordered_set utility valarray variant vector version wchar.h wctype.h)
-api := $(addprefix $(apilibrary), darwin.hpp dlfcn.h linux.hpp pthread.h SDL.h tos.h windows.h)
-def := $(addprefix $(deflibrary), assembly darwinlib elf linuxlib macho pe tos wasm wasmlib winlib)
+api := $(addprefix $(apilibrary), darwin.hpp dlfcn.h efi.h linux.hpp pthread.h SDL.h tos.h windows.h)
+def := $(addprefix $(deflibrary), assembly darwinlib efi elf linuxlib macho pe tos wasm wasmlib winlib)
 obl := $(addprefix $(oblibrary), obl.arguments.mod obl.hashes.mod obl.basictypes.mod obl.booleans.mod obl.characters.mod obl.devices.mod obl.environment.mod obl.exceptions.mod obl.files.mod obl.iostreams.mod obl.streams.mod obl.iterators.mod obl.arrays.mod obl.coroutines.mod obl.dynamicarrays.mod obl.generators.mod obl.lists.mod obl.pairs.mod obl.hashmaps.mod obl.functions.mod obl.in.mod obl.math.mod obl.out.mod obl.random.mod obl.sets.mod obl.strings.mod obl.trees.mod)
 ext := $(addprefix $(oblibrary), api.darwin.mod api.linux.mod api.pthread.mod api.sdl.mod api.tos.mod api.windows.mod)
 oak := $(addprefix $(oblibrary), coroutines.mod in.mod math.mod mathc.mod mathl.mod mathlc.mod out.mod strings.mod xyplane.mod)
@@ -1695,24 +1695,18 @@
 man1dir := $(mandir)/man1
 docdir := $(prefix)/share/doc/ecs
 
-install: uninstall
-	@mkdir -p $(DESTDIR)$(ecsdir)
-	@mkdir -p $(DESTDIR)$(ecsdir)/$(tools)
-	@cp $(filter $(toolsp)%, $(wildcard $(bin))) $(DESTDIR)$(ecsdir)/$(tools)
-	@mkdir -p $(DESTDIR)$(ecsdir)/$(runtime)
-	@cp $(wildcard $(obf) $(run) $(lib) $(cod)) $(DESTDIR)$(ecsdir)/$(runtime)
-	@mkdir -p $(DESTDIR)$(ecsdir)/$(cpplibrary)
-	@cp $(hdr) $(DESTDIR)$(ecsdir)/$(cpplibrary)
-	@mkdir -p $(DESTDIR)$(ecsdir)/$(oblibrary)
-	@cp $(wildcard $(sym)) $(DESTDIR)$(ecsdir)/$(oblibrary)
-	@mkdir -p $(DESTDIR)$(ecsdir)/$(utilities)
-	@cp $(utilities)ecsd $(DESTDIR)$(ecsdir)/$(utilities)
-	@mkdir -p $(DESTDIR)$(bindir)
-	@ln -s $(patsubst $(DESTDIR)$(prefix)/%,../%,$(DESTDIR)$(ecsdir))/$(utilities)ecsd $(DESTDIR)$(bindir)/ecsd
-	@mkdir -p $(DESTDIR)$(man1dir)
-	@cp $(documentation)ecsd.1 $(DESTDIR)$(man1dir)/ecsd.1
-	@mkdir -p $(DESTDIR)$(docdir)
-	@cp $(wildcard $(pdf)) $(DESTDIR)$(docdir)
+install: uninstall $(utilities)ecsd$(prg)
+	@test -z "$(filter $(toolsp)%, $(wildcard $(bin)))" || install -D -t $(DESTDIR)$(ecsdir)/$(tools) $(filter $(toolsp)%, $(wildcard $(bin)))
+	@test -z "$(wildcard $(obf) $(run) $(lib) $(cod))" || install -D -t $(DESTDIR)$(ecsdir)/$(runtime) $(wildcard $(obf) $(run) $(lib) $(cod))
+	@install -D -t $(DESTDIR)$(ecsdir)/$(cpplibrary) $(hdr)
+	@install -D -t $(DESTDIR)$(ecsdir)/$(apilibrary) $(api)
+	@install -D -t $(DESTDIR)$(ecsdir)/$(deflibrary) $(def)
+	@test -z "$(wildcard $(sym))" || install -D -t $(DESTDIR)$(ecsdir)/$(oblibrary) $(wildcard $(sym))
+	@install -D -t $(DESTDIR)$(ecsdir)/$(utilities) $(utilities)ecsd$(prg)
+	@install -d $(DESTDIR)$(bindir)
+	@ln -s $(abspath $(DESTDIR)$(ecsdir)/$(utilities)ecsd$(prg)) $(DESTDIR)$(bindir)/ecsd
+	@install -D -t $(DESTDIR)$(man1dir) $(documentation)ecsd.1
+	@test -z "$(wildcard $(pdf))" || install -D -t  $(DESTDIR)$(docdir) $(wildcard $(pdf))
 
 uninstall:
 	@rm -f -r $(DESTDIR)$(ecsdir)
Index: tools/falinterpreter.cpp
===================================================================
--- tools/falinterpreter.cpp	(version 2026.08.10)
+++ tools/falinterpreter.cpp
@@ -47,12 +47,12 @@
 	void Interpret (const Element&);
 
 	void Push (const Value&);
-	Value Pop (const Element&);
-	Integer PopInteger (const Element&);
-	Value& PopVariable (const Element&);
-	const Function& PopFunction (const Element&);
+	Value Pop (const Position&);
+	Integer PopInteger (const Position&);
+	Value& PopVariable (const Position&);
+	const Function& PopFunction (const Position&);
 
-	void EmitError [[noreturn]] (const Element&, const char*) const;
+	void EmitError [[noreturn]] (const Position&, const char*) const;
 };
 
 struct Context::Value
@@ -98,7 +98,7 @@
 
 Integer Context::Interpret (const Program& program)
 {
-	source = &program.source; Push (0); Interpret (program.main); return PopInteger (program.main.back ());
+	source = &program.source; Push (0); Interpret (program.main); return PopInteger (program.end);
 }
 
 void Context::Interpret (const Function& function)
@@ -110,38 +110,38 @@
 {
 	switch (element.symbol)
 	{
-	case Lexer::Assign: {auto& variable = PopVariable (element); variable = Pop (element); break;}
-	case Lexer::Call: Interpret (PopFunction (element)); break;
-	case Lexer::If: {auto& function = PopFunction (element); if (PopInteger (element)) Interpret (function); break;}
-	case Lexer::While: {auto &function = PopFunction (element), &condition = PopFunction (element); while (Interpret (condition), PopInteger (element)) Interpret (function); break;}
-	case Lexer::Write: environment.Fputs (std::to_string (PopInteger (element)), environment.stdout_); break;
-	case Lexer::Put: environment.Putchar (PopInteger (element)); break;
+	case Lexer::Assign: {auto& variable = PopVariable (element.position); variable = Pop (element.position); break;}
+	case Lexer::Call: Interpret (PopFunction (element.position)); break;
+	case Lexer::If: {auto& function = PopFunction (element.position); if (PopInteger (element.position)) Interpret (function); break;}
+	case Lexer::While: {auto &function = PopFunction (element.position), &condition = PopFunction (element.position); while (Interpret (condition), PopInteger (element.position)) Interpret (function); break;}
+	case Lexer::Write: environment.Fputs (std::to_string (PopInteger (element.position)), environment.stdout_); break;
+	case Lexer::Put: environment.Putchar (PopInteger (element.position)); break;
 	case Lexer::Get: Push (environment.Getchar ()); break;
 	case Lexer::Flush: environment.Fflush (environment.stdout_); break;
-	case Lexer::Dereference: Push (PopVariable (element)); break;
+	case Lexer::Dereference: Push (PopVariable (element.position)); break;
 	case Lexer::BeginFunction: Push (element.function); break;
-	case Lexer::Negate: Push (-PopInteger (element)); break;
-	case Lexer::Add: {const auto value = PopInteger (element); Push (PopInteger (element) + value); break;}
-	case Lexer::Subtract: {const auto value = PopInteger (element); Push (PopInteger (element) - value); break;}
-	case Lexer::Multiply: {const auto value = PopInteger (element); Push (PopInteger (element) * value); break;}
-	case Lexer::Divide: {const auto value = PopInteger (element); Push (PopInteger (element) / value); break;}
-	case Lexer::Not: Push (!PopInteger (element)); break;
-	case Lexer::And: {const auto value = PopInteger (element); Push (PopInteger (element) && value); break;}
-	case Lexer::Or: {const auto value = PopInteger (element); Push (PopInteger (element) || value); break;}
-	case Lexer::Equal: {const auto value = Pop (element); Push (Pop (element) == value); break;}
-	case Lexer::Greater: {const auto value = PopInteger (element); Push (PopInteger (element) > value); break;}
+	case Lexer::Negate: Push (-PopInteger (element.position)); break;
+	case Lexer::Add: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) + value); break;}
+	case Lexer::Subtract: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) - value); break;}
+	case Lexer::Multiply: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) * value); break;}
+	case Lexer::Divide: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) / value); break;}
+	case Lexer::Not: Push (!PopInteger (element.position)); break;
+	case Lexer::And: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) && value); break;}
+	case Lexer::Or: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) || value); break;}
+	case Lexer::Equal: {const auto value = Pop (element.position); Push (Pop (element.position) == value); break;}
+	case Lexer::Greater: {const auto value = PopInteger (element.position); Push (PopInteger (element.position) > value); break;}
 	case Lexer::Duplicate: Push (stack.back ()); break;
-	case Lexer::Delete: Pop (element); break;
-	case Lexer::Swap: {const auto object1 = Pop (element), object2 = Pop (element); Push (object1); Push (object2); break;}
-	case Lexer::Rotate: {const auto object1 = Pop (element), object2 = Pop (element), object3 (Pop (element)); Push (object2); Push (object1); Push (object3); break;}
-	case Lexer::Select: {const auto selection = PopInteger (element); if (selection >= Integer (stack.size ())) EmitError (element, "invalid selection"); Push (stack[stack.size () - selection - 1]); break;}
+	case Lexer::Delete: Pop (element.position); break;
+	case Lexer::Swap: {const auto object1 = Pop (element.position), object2 = Pop (element.position); Push (object1); Push (object2); break;}
+	case Lexer::Rotate: {const auto object1 = Pop (element.position), object2 = Pop (element.position), object3 (Pop (element.position)); Push (object2); Push (object1); Push (object3); break;}
+	case Lexer::Select: {const auto selection = PopInteger (element.position); if (selection >= Integer (stack.size ())) EmitError (element.position, "invalid selection"); Push (stack[stack.size () - selection - 1]); break;}
 	case Lexer::Integer: Push (element.integer); break;
 	case Lexer::Character: Push (Integer (element.character)); break;
 	case Lexer::Variable: Push (&variables[element.character - 'a']); break;
 	case Lexer::String: environment.Fputs (element.string, environment.stdout_); break;
-	case Lexer::ExternalVariable: EmitError (element, "extern variables not supported");
-	case Lexer::ExternalFunction: EmitError (element, "extern functions not supported");
-	case Lexer::Assembly: EmitError (element, "inline assembly not supported");
+	case Lexer::ExternalVariable: EmitError (element.position, "extern variables not supported");
+	case Lexer::ExternalFunction: EmitError (element.position, "extern functions not supported");
+	case Lexer::Assembly: EmitError (element.position, "inline assembly not supported");
 	default: assert (Lexer::Unreachable);
 	}
 }
@@ -151,30 +151,30 @@
 	stack.push_back (value);
 }
 
-Context::Value Context::Pop (const Element& element)
+Context::Value Context::Pop (const Position& position)
 {
-	if (stack.empty ()) EmitError (element, "stack empty");
+	if (stack.empty ()) EmitError (position, "stack empty");
 	const auto value = stack.back (); stack.pop_back (); return value;
 }
 
-Integer Context::PopInteger (const Element& element)
+Integer Context::PopInteger (const Position& position)
 {
-	const auto value = Pop (element); if (value.type != Value::Integer) EmitError (element, "stack top not an integer"); return value.integer;
+	const auto value = Pop (position); if (value.type != Value::Integer) EmitError (position, "stack top not an integer"); return value.integer;
 }
 
-Context::Value& Context::PopVariable (const Element& element)
+Context::Value& Context::PopVariable (const Position& position)
 {
-	const auto value = Pop (element); if (value.type != Value::Variable) EmitError (element, "stack top not a variable"); return *value.variable;
+	const auto value = Pop (position); if (value.type != Value::Variable) EmitError (position, "stack top not a variable"); return *value.variable;
 }
 
-const Function& Context::PopFunction (const Element& element)
+const Function& Context::PopFunction (const Position& position)
 {
-	const auto value = Pop (element); if (value.type != Value::Function) EmitError (element, "stack top not a function"); return *value.function;
+	const auto value = Pop (position); if (value.type != Value::Function) EmitError (position, "stack top not a function"); return *value.function;
 }
 
-void Context::EmitError (const Element& element, const char*const message) const
+void Context::EmitError (const Position& position, const char*const message) const
 {
-	interpreter.diagnostics.Emit (Diagnostics::Error, *source, element.position, message); throw Error {};
+	interpreter.diagnostics.Emit (Diagnostics::Error, *source, position, message); throw Error {};
 }
 
 Context::Value::Value (const FALSE::Integer i) :
Index: tools/falparser.cpp
===================================================================
--- tools/falparser.cpp	(version 2026.08.10)
+++ tools/falparser.cpp
@@ -52,4 +52,5 @@
 		}
 
 	if (!stack.empty ()) EmitError (program, current.position, "function not closed");
+	program.end = current.position;
 }
Index: tools/false.hpp
===================================================================
--- tools/false.hpp	(version 2026.08.10)
+++ tools/false.hpp
@@ -41,6 +41,7 @@
 {
 	Source source;
 	Function main;
+	Position end;
 
 	explicit Program (const Source&);
 };
