diff --git a/src/SConscript b/src/SConscript
index 0c4f81ed3bcce5408e681ec92a7f0a9e677141f3..2af08ae19b237f4d9f22d08c115c74c470775914 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -21,7 +21,8 @@ parsers_headers = [
 
 backends_headers = [
     'backends/regex.h',
-    'backends/contextfree.h'
+    'backends/contextfree.h',
+    'backends/missing.h'
 ]
 
 parsers = ['parsers/%s.c'%s for s in
@@ -55,7 +56,7 @@ parsers = ['parsers/%s.c'%s for s in
             'value']]
 
 backends = ['backends/%s.c' % s for s in
-            ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']]
+            ['missing', 'packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']]
 
 misc_hammer_parts = [
     'allocator.c',
diff --git a/src/backends/missing.c b/src/backends/missing.c
new file mode 100644
index 0000000000000000000000000000000000000000..f159bf192329088fac3b5987d498d63f728fb9e6
--- /dev/null
+++ b/src/backends/missing.c
@@ -0,0 +1,25 @@
+#include "missing.h"
+
+/* Placeholder backend that always fails */
+
+int h_missing_compile(HAllocator* mm__, HParser* parser, const void* params) {
+  /* Always fail */
+
+  return -1;
+}
+
+HParseResult *h_missing_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream) {
+  /* Always fail */
+
+  return NULL;
+}
+
+void h_missing_free(HParser *parser) {
+  /* No-op */
+}
+
+HParserBackendVTable h__missing_backend_vtable = {
+  .compile = h_missing_compile,
+  .parse = h_missing_parse,
+  .free = h_missing_free,
+};
diff --git a/src/backends/missing.h b/src/backends/missing.h
new file mode 100644
index 0000000000000000000000000000000000000000..4efe5f350331a1dcc75dcd894bf1075e8f62bbd8
--- /dev/null
+++ b/src/backends/missing.h
@@ -0,0 +1,7 @@
+#ifndef HAMMER_BACKENDS_MISSING__H
+#define HAMMER_BACKENDS_MISSING__H
+
+#include "../hammer.h"
+#include "../internal.h"
+
+#endif /* !defined(HAMMER_BACKENDS_MISSING__H) */
diff --git a/src/hammer.c b/src/hammer.c
index 70ebc8a4943d8e1b3a25e036a745c2296bf8ddfd..44ff2e668a03eab03e5ca58240de409d39cc8b67 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -26,11 +26,12 @@
 #include "parsers/parser_internal.h"
 
 static HParserBackendVTable *backends[PB_MAX + 1] = {
-  &h__packrat_backend_vtable,
-  &h__regex_backend_vtable,
-  &h__llk_backend_vtable,
-  &h__lalr_backend_vtable,
-  &h__glr_backend_vtable,
+  &h__missing_backend_vtable, /* For PB_INVALID */
+  &h__packrat_backend_vtable, /* For PB_PACKRAT */
+  &h__regex_backend_vtable, /* For PB_REGULAR */
+  &h__llk_backend_vtable, /* For PB_LLk */
+  &h__lalr_backend_vtable, /* For PB_LALR */
+  &h__glr_backend_vtable /* For PB_GLR */
 };
 
 
@@ -41,7 +42,18 @@ typedef struct {
   const HParser *p2;
 } HTwoParsers;
 
+/* Backend-related inquiries */
 
+int h_is_backend_available(HParserBackend backend) {
+  if (backend >= PB_MIN && backend <= PB_MAX) {
+    return (backends[backend] != &h__missing_backend_vtable) ? 1 : 0;
+  } else return 0;
+}
+
+HParserBackend h_get_default_backend(void) {
+  /* Call the inline version in internal.h */
+  return h_get_default_backend__int();
+}
 
 #define DEFAULT_ENDIANNESS (BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN)
 
@@ -93,7 +105,10 @@ int h_compile(HParser* parser, HParserBackend backend, const void* params) {
 }
 
 int h_compile__m(HAllocator* mm__, HParser* parser, HParserBackend backend, const void* params) {
-  backends[parser->backend]->free(parser);
+  if (parser->backend >= PB_MIN && parser->backend <= PB_MAX &&
+      backends[parser->backend]->free != NULL) {
+    backends[parser->backend]->free(parser);
+  }
   int ret = backends[backend]->compile(mm__, parser, params);
   if (!ret)
     parser->backend = backend;
diff --git a/src/hammer.h b/src/hammer.h
index ad44fee910fcf42445e57e47ec8c1fe2d18d3724..a9ace572e8fcbc8588a111b8bc470bc72e34062b 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -41,7 +41,12 @@ typedef struct HParseState_ HParseState;
 
 typedef enum HParserBackend_ {
   PB_MIN = 0,
-  PB_PACKRAT = PB_MIN, // PB_MIN is always the default.
+  /*
+   * Have a backend that always fails to pass around "no such backend"
+   * indications
+   */
+  PB_INVALID = PB_MIN,
+  PB_PACKRAT,
   PB_REGULAR,
   PB_LLk,
   PB_LALR,
@@ -260,6 +265,17 @@ typedef struct HBenchmarkResults_ {
 #endif // SWIG
 // }}}
 
+/**
+ * Ask if this backend is available
+ */
+
+int h_is_backend_available(HParserBackend backend);
+
+/**
+ * Ask what the default backend is (currently always PB_PACKRAT)
+ */
+
+HParserBackend h_get_default_backend(void);
 
 /**
  * Top-level function to call a parser that has been built over some
diff --git a/src/internal.h b/src/internal.h
index 0e92e99e6facf5d04c6b13ca8de51272ba630a1d..51898bf0611ac607f898479ba952b546187be47a 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -318,6 +318,7 @@ struct HBitWriter_ {
 
 
 // Backends {{{
+extern HParserBackendVTable h__missing_backend_vtable;
 extern HParserBackendVTable h__packrat_backend_vtable;
 extern HParserBackendVTable h__llk_backend_vtable;
 extern HParserBackendVTable h__lalr_backend_vtable;
@@ -334,12 +335,25 @@ static inline size_t h_input_stream_pos(HInputStream* state) {
 HParseResult* h_do_parse(const HParser* parser, HParseState *state);
 void put_cached(HParseState *ps, const HParser *p, HParseResult *cached);
 
+/*
+ * Inline this for benefit of h_new_parser() below, then make
+ * the API h_get_default_backend() call it.
+ */
+static inline HParserBackend h_get_default_backend__int(void) {
+  return PB_PACKRAT;
+}
+
 static inline
 HParser *h_new_parser(HAllocator *mm__, const HParserVtable *vt, void *env) {
   HParser *p = h_new(HParser, 1);
   memset(p, 0, sizeof(HParser));
   p->vtable = vt;
   p->env = env;
+  /*
+   * Current limitation: if we specify backends solely by HParserBackend, we
+   * can't set a default backend that requires any parameters to h_compile()
+   */
+  p->backend = h_get_default_backend__int();
   return p;
 }