add INJA_NOEXCEPTION
diff --git a/README.md b/README.md
index 48e86c6..543f355 100644
--- a/README.md
+++ b/README.md
@@ -321,6 +321,11 @@
 render("Hello{# Todo #}!", data); // "Hello!"
 ```
 
+### Exceptions
+
+Inja uses exceptions to handle ill-formed template input. However, exceptions can be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `INJA_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls.
+
+
 ## Supported compilers
 
 Inja uses `string_view` from C++17, but includes the [polyfill](https://github.com/martinmoene/string-view-lite) from martinmoene. This way, the minimum version is C++11. Currently, the following compilers are tested:
diff --git a/include/inja/inja.hpp b/include/inja/inja.hpp
index fff245b..86b8a0a 100644
--- a/include/inja/inja.hpp
+++ b/include/inja/inja.hpp
@@ -5,6 +5,13 @@
 
 #include <nlohmann/json.hpp>
 
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(INJA_NOEXCEPTION)
+    #define INJA_THROW(exception) throw exception
+#else
+    #include <cstdlib>
+    #define INJA_THROW(exception) std::abort()
+#endif
+
 #include "environment.hpp"
 #include "exceptions.hpp"
 #include "parser.hpp"
diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp
index d676d75..6266c4a 100644
--- a/include/inja/parser.hpp
+++ b/include/inja/parser.hpp
@@ -51,7 +51,7 @@
   std::stack<ForStatementNode*> for_statement_stack;
 
   void throw_parser_error(const std::string &message) {
-    throw ParserError(message, lexer.current_position());
+    INJA_THROW(ParserError(message, lexer.current_position()));
   }
 
   void get_next_token() {
diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp
index 8b3a270..7bc518f 100644
--- a/include/inja/renderer.hpp
+++ b/include/inja/renderer.hpp
@@ -91,7 +91,7 @@
 
   void throw_renderer_error(const std::string &message, const AstNode& node) {
     SourceLocation loc = get_source_location(current_template->content, node.pos);
-    throw RenderError(message, loc);
+    INJA_THROW(RenderError(message, loc));
   }
 
   template<size_t N, bool throw_not_found=true>
diff --git a/include/inja/utils.hpp b/include/inja/utils.hpp
index ee58ccc..fb1736c 100644
--- a/include/inja/utils.hpp
+++ b/include/inja/utils.hpp
@@ -18,7 +18,7 @@
   try {
     file.open(path);
   } catch (const std::ios_base::failure & /*e*/) {
-    throw FileError("failed accessing file at '" + path + "'");
+    INJA_THROW(FileError("failed accessing file at '" + path + "'"));
   }
 }
 
diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp
index 516aa95..42dea1c 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -5,6 +5,13 @@
 
 #include <nlohmann/json.hpp>
 
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(INJA_NOEXCEPTION)
+    #define INJA_THROW(exception) throw exception
+#else
+    #include <cstdlib>
+    #define INJA_THROW(exception) std::abort()
+#endif
+
 // #include "environment.hpp"
 // Copyright (c) 2019 Pantor. All rights reserved.
 
@@ -1838,7 +1845,7 @@
   try {
     file.open(path);
   } catch (const std::ios_base::failure & /*e*/) {
-    throw FileError("failed accessing file at '" + path + "'");
+    INJA_THROW(FileError("failed accessing file at '" + path + "'"));
   }
 }
 
@@ -2780,7 +2787,7 @@
   std::stack<ForStatementNode*> for_statement_stack;
 
   void throw_parser_error(const std::string &message) {
-    throw ParserError(message, lexer.current_position());
+    INJA_THROW(ParserError(message, lexer.current_position()));
   }
 
   void get_next_token() {
@@ -3409,7 +3416,7 @@
 
   void throw_renderer_error(const std::string &message, const AstNode& node) {
     SourceLocation loc = get_source_location(current_template->content, node.pos);
-    throw RenderError(message, loc);
+    INJA_THROW(RenderError(message, loc));
   }
 
   template<size_t N, bool throw_not_found=true>
diff --git a/test/test-files.cpp b/test/test-files.cpp
index a999d90..74d099a 100644
--- a/test/test-files.cpp
+++ b/test/test-files.cpp
@@ -1,9 +1,5 @@
 // Copyright (c) 2020 Pantor. All rights reserved.
 
-#include "doctest/doctest.h"
-#include "inja/inja.hpp"
-
-
 TEST_CASE("loading") {
   inja::Environment env;
   json data;
diff --git a/test/test-functions.cpp b/test/test-functions.cpp
index 60c8b79..4870205 100644
--- a/test/test-functions.cpp
+++ b/test/test-functions.cpp
@@ -1,9 +1,5 @@
 // Copyright (c) 2020 Pantor. All rights reserved.
 
-#include "doctest/doctest.h"
-#include "inja/inja.hpp"
-
-
 TEST_CASE("functions") {
   inja::Environment env;
 
diff --git a/test/test-renderer.cpp b/test/test-renderer.cpp
index 8d5b447..fe38738 100644
--- a/test/test-renderer.cpp
+++ b/test/test-renderer.cpp
@@ -1,9 +1,5 @@
 // Copyright (c) 2020 Pantor. All rights reserved.
 
-#include "doctest/doctest.h"
-#include "inja/inja.hpp"
-
-
 TEST_CASE("types") {
   inja::Environment env;
   json data;
diff --git a/test/test-units.cpp b/test/test-units.cpp
index f84197a..95862f2 100644
--- a/test/test-units.cpp
+++ b/test/test-units.cpp
@@ -1,9 +1,5 @@
 // Copyright (c) 2020 Pantor. All rights reserved.
 
-#include "doctest/doctest.h"
-#include "inja/inja.hpp"
-
-
 TEST_CASE("source location") {
   std::string content = R""""(Lorem Ipsum
   Dolor