]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Added sclpl binary target and rscons based rakefile
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 19 Aug 2014 00:46:41 +0000 (20:46 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 19 Aug 2014 00:46:41 +0000 (20:46 -0400)
12 files changed:
Gemfile [new file with mode: 0644]
Gemfile.lock [new file with mode: 0644]
Rakefile [new file with mode: 0644]
source/libsof/libsof.c
source/libsof/libsof.os [new file with mode: 0644]
source/sclpl/ast.c [new file with mode: 0644]
source/sclpl/ast.h [new file with mode: 0644]
source/sclpl/grammar.c [new file with mode: 0644]
source/sclpl/grammar.y [new file with mode: 0644]
source/sclpl/main.c [new file with mode: 0644]
source/sclpl/mpc.c [new file with mode: 0644]
source/sclpl/mpc.h [new file with mode: 0644]

diff --git a/Gemfile b/Gemfile
new file mode 100644 (file)
index 0000000..c8d6a78
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source 'http://rubygems.org'
+gem 'rscons'
+gem 'rake'
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644 (file)
index 0000000..b932f82
--- /dev/null
@@ -0,0 +1,14 @@
+GEM
+  remote: http://rubygems.org/
+  specs:
+    json (1.8.1)
+    rake (10.3.2)
+    rscons (1.6.0)
+      json (~> 1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  rake
+  rscons
diff --git a/Rakefile b/Rakefile
new file mode 100644 (file)
index 0000000..d81d9c4
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,84 @@
+#------------------------------------------------------------------------------
+# Bundler Setup
+#------------------------------------------------------------------------------
+require "bundler"
+begin
+  Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+  raise LoadError.new("Unable to Bundler.setup(): You probably need to run `bundle install`: #{e.message}")
+end
+require 'rscons'
+
+#------------------------------------------------------------------------------
+# Clang Toolchain Targets
+#------------------------------------------------------------------------------
+CLANG_BUILD_DIR = 'build/llvm'
+CLANG_BIN_DIR = 'build/llvm/bin'
+CLANG_BIN_NAME = 'clang'
+CLANG_SRC_DIR = 'source/vendor/llvm-3.4.2'
+CLANG_CMAKE_GENERATOR = ENV['CMAKE_GENERATOR'] || "Unix Makefiles"
+CLANG_CMAKE_OPTS = [ '-DCMAKE_BUILD_TYPE=Release' ]
+CLANG_MAKE_CMD = 'make'
+
+file "#{CLANG_BUILD_DIR}/Makefile" => FileList["#{CLANG_SRC_DIR}/cmake/**/*"] do
+    FileUtils.mkdir_p(CLANG_BUILD_DIR)
+    FileUtils.cd(CLANG_BUILD_DIR) do
+        sh "cmake #{CLANG_CMAKE_OPTS.join} -G\"#{CLANG_CMAKE_GENERATOR}\" ../../#{CLANG_SRC_DIR}"
+    end
+end
+
+file "#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}" => ["#{CLANG_BUILD_DIR}/Makefile"] + FileList["#{CLANG_SRC_DIR}/tools/clang/**/*.c"] do
+    FileUtils.cd(CLANG_BUILD_DIR) do
+        sh "#{CLANG_MAKE_CMD} clang"
+    end
+end
+
+task :clang => ["#{CLANG_BIN_DIR}/#{CLANG_BIN_NAME}"] do
+    ENV['PATH'].unshift(CLANG_BIN_DIR)
+end
+
+#------------------------------------------------------------------------------
+# Envrionment Definitions
+#------------------------------------------------------------------------------
+class Environment < Rscons::Environment
+  @@environments = []
+  def initialize(args,&block)
+    super(args,&block)
+    @@environments << self
+  end
+
+  def self.process_all()
+    @@environments.each {|e| e.process }
+  end
+end
+
+# Process all environments so we actually build the targets
+at_exit { Environment.process_all }
+
+# Define the compiler environment
+BaseEnv = Environment.new(echo: :command) do |env|
+  env.build_dir('source/','build/obj/source')
+  env['CC'] = 'clang'
+  env['CXX'] = 'clang'
+  env['LD'] = 'clang'
+  env["CFLAGS"] += ['-Wall', '-Wextra' ]#, '-Werror']
+end
+
+task(:build) { BaseEnv.Program('build/bin/sclpl', FileList['source/sclpl/*.c']) }
+
+#------------------------------------------------------------------------------
+# Cleanup Target
+#------------------------------------------------------------------------------
+desc "Clean all rscons generated files and directories"
+task(:clean) { Rscons.clean }
+
+desc "Clean object files generated for vendor libraries as well as rscons"
+task :clean_all => [:clean] do
+  if Dir.exist? CLANG_BUILD_DIR
+    FileUtils.cd(CLANG_BUILD_DIR) { sh "#{CLANG_MAKE_CMD} clean" }
+  end
+end
+
+desc "Clobber the build driectory and all it's contents"
+task(:clobber) { FileUtils.rm_rf('build/') }
+
index 775b8185087c7fb30aaee9e2005cd73f3f1a3b87..d6d3ab004f47423cd14d0a82ca3f9c1a89683884 100644 (file)
@@ -206,7 +206,7 @@ size_t libsof_add_symbol(sof_file_t* obj, const char* name, uint32_t value, uint
 size_t libsof_add_st_entry(sof_file_t* obj, uint32_t name, uint32_t value, uint32_t size, uint32_t info)
 {
     sof_st_entry_t new_sym = { name, value, size, info };
-    return libsof_add_to_segment( (void**)&(obj->symbols), &(obj->header->sym_tbl_sz), &new_sym, sizeof(sof_st_entry_t) );
+    return libsof_add_to_segment( (void**)&(obj->symbols), (size_t*)&(obj->header->sym_tbl_sz), &new_sym, sizeof(sof_st_entry_t) );
 }
 
 sof_st_entry_t const* libsof_get_st_entry(sof_file_t* obj, size_t offset)
@@ -216,7 +216,7 @@ sof_st_entry_t const* libsof_get_st_entry(sof_file_t* obj, size_t offset)
 
 size_t libsof_add_string(sof_file_t* obj, char const* name)
 {
-    return libsof_add_to_segment( (void**)&(obj->strings), &(obj->header->sym_str_tbl_sz), name, strlen(name) + 1 );
+    return libsof_add_to_segment( (void**)&(obj->strings), (size_t*)&(obj->header->sym_str_tbl_sz), name, strlen(name) + 1 );
 }
 
 char const* libsof_get_string(sof_file_t* obj, size_t offset)
@@ -226,7 +226,7 @@ char const* libsof_get_string(sof_file_t* obj, size_t offset)
 
 size_t libsof_add_data(sof_file_t* obj, uint8_t const* data, size_t length)
 {
-    return libsof_add_to_segment( (void**)&(obj->data), &(obj->header->data_sz), data, length );
+    return libsof_add_to_segment( (void**)&(obj->data), (size_t*)&(obj->header->data_sz), data, length );
 }
 
 uint8_t const* libsof_get_data(sof_file_t* obj, size_t offset)
@@ -236,7 +236,7 @@ uint8_t const* libsof_get_data(sof_file_t* obj, size_t offset)
 
 size_t libsof_add_code(sof_file_t* obj, uint32_t const* code, size_t length)
 {
-    return libsof_add_to_segment( (void**)&(obj->code), &(obj->header->code_sz), code, length * sizeof(uint32_t) );
+    return libsof_add_to_segment( (void**)&(obj->code), (size_t*)&(obj->header->code_sz), code, length * sizeof(uint32_t) );
 }
 
 uint32_t const* libsof_get_code(sof_file_t* obj, size_t offset)
diff --git a/source/libsof/libsof.os b/source/libsof/libsof.os
new file mode 100644 (file)
index 0000000..b7fc8bd
Binary files /dev/null and b/source/libsof/libsof.os differ
diff --git a/source/sclpl/ast.c b/source/sclpl/ast.c
new file mode 100644 (file)
index 0000000..e45739f
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+  @file ast.c
+  @brief See header for details
+  $Revision$
+  $HeadURL$
+*/
+#include "ast.h"
+
+void ast_free(void* p_obj)
+{
+    (void)p_obj;
+}
+
+ast_t* ast_new(ast_type_t type, void* value)
+{
+    (void)type;
+    (void)value;
+    return NULL;
+}
+
+void ast_set_pos(ast_t* p_ast, const char* file, size_t line, size_t col)
+{
+    (void)p_ast;
+    (void)file;
+    (void)line;
+    (void)col;
+}
+
+const pos_t* ast_get_pos(ast_t* p_ast)
+{
+    (void)p_ast;
+    return NULL;
+}
+
+void ast_set_type(ast_t* p_ast, ast_type_t type)
+{
+    (void)p_ast;
+    (void)type;
+}
+
+ast_type_t ast_get_type(ast_t* p_ast)
+{
+    (void)p_ast;
+    return UNKNOWN;
+}
+
+void ast_set_value(ast_t* p_ast, void* value)
+{
+    (void)p_ast;
+    (void)value;
+}
+
+const void* ast_get_value(ast_t* p_ast)
+{
+    (void)p_ast;
+    return NULL;
+}
+
+void ast_set_children(ast_t* p_ast, child_t* p_children)
+{
+    (void)p_ast;
+    (void)p_children;
+}
+
+const child_t* ast_get_children(ast_t* p_ast)
+{
+    (void)p_ast;
+    return NULL;
+}
+
+ast_t* ast_map(const ast_t* p_ast, ast_map_fn_t p_fn)
+{
+    (void)p_ast;
+    (void)p_fn;
+    return NULL;
+}
diff --git a/source/sclpl/ast.h b/source/sclpl/ast.h
new file mode 100644 (file)
index 0000000..366b7ab
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+  @file ast.h
+  @brief TODO: Describe this file
+  $Revision$
+  $HeadURL$
+  */
+#ifndef AST_H
+#define AST_H
+
+#include <stddef.h>
+#include <string.h>
+
+typedef enum {
+    BOOLEAN,
+    INTEGER,
+    CHARACTER,
+    STRING,
+    UNKNOWN
+} ast_type_t;
+
+typedef struct {
+    char* file;
+    size_t line;
+    size_t column;
+} pos_t;
+
+struct ast_t;
+
+typedef struct child_t {
+    struct ast_t* ast;
+    struct child_t* next;
+} child_t;
+
+typedef struct ast_t {
+    pos_t* pos;
+    ast_type_t type;
+    void* value;
+    child_t* children;
+} ast_t;
+
+typedef ast_t* (*ast_map_fn_t)(const ast_t* p_ast);
+
+void ast_free(void* p_obj);
+
+ast_t* ast_new(ast_type_t type, void* value);
+
+void ast_set_pos(ast_t* p_ast, const char* file, size_t line, size_t col);
+
+const pos_t* ast_get_pos(ast_t* p_ast);
+
+void ast_set_type(ast_t* p_ast, ast_type_t type);
+
+ast_type_t ast_get_type(ast_t* p_ast);
+
+void ast_set_value(ast_t* p_ast, void* value);
+
+const void* ast_get_value(ast_t* p_ast);
+
+void ast_set_children(ast_t* p_ast, child_t* p_children);
+
+const child_t* ast_get_children(ast_t* p_ast);
+
+ast_t* ast_map(const ast_t* p_ast, ast_map_fn_t p_fn);
+
+#endif /* AST_H */
diff --git a/source/sclpl/grammar.c b/source/sclpl/grammar.c
new file mode 100644 (file)
index 0000000..e5f5506
--- /dev/null
@@ -0,0 +1,36 @@
+const char Grammar[] = 
+""
+"replexpr : <ws> <expr> /[^\\n]*\\n/ ;"
+""
+"expr : '(' <ws> \"quote\" <ws> <expr> <ws> ')'"
+"     | '(' <ws> \"quasiquote\" <ws> <expr> <ws> ')'"
+"     | '(' <ws> \"unquote\" <ws> <expr> <ws> ')'"
+"     | '(' <ws> \"if\" <ws> <expr> <ws> <expr> <ws> (<expr> <ws>)?')'"
+"     | '(' <ws> \"fn\" <ws> '(' (<ws> <var> <ws>)* ')' (<ws> <expr> <ws>)+ ')'"
+"     | '(' <ws> \"def\" <ws> <var> <ws> <expr> <ws> ')'"
+"     | '(' <ws> <expr> (<ws> <expr> <ws>)* ')'"
+"     | /['`,]/ <expr>"
+"     | <atom>"
+"     ;"
+""
+"atom : <num> | <ch> | <str> | <bool> | <var> ;"
+""
+"num : \"0b\" /[0-1]+/"
+"    | \"0o\" /[0-7]+/"
+"    | \"0d\" /[0-9]+/"
+"    | \"0x\" /[0-9a-fA-F]+/"
+"    | /[-+]?[0-9]+(\\.[0-9]+)?/"
+"    ;"
+""
+"ch : '\\\\' (\"space\"|\"newline\"|\"return\"|\"tab\"|\"vtab\")"
+"   | '\\\\' /./"
+"   ;"
+""
+"str : '\"' /[^\"]*/ '\"' ;"
+""
+"bool : \"True\" | \"False\" ;"
+""
+"var : /[^() \\t\\r\\n#`'\"]+/ ;"
+""
+"ws : '#' /[^\\n]*\\n/ | /[ \\t\\r\\n]*/ ;"
+;
diff --git a/source/sclpl/grammar.y b/source/sclpl/grammar.y
new file mode 100644 (file)
index 0000000..3358a2a
--- /dev/null
@@ -0,0 +1,34 @@
+
+replexpr : <ws> <expr> /[^\n]*\n/ ;
+
+expr : '(' <ws> "quote" <ws> <expr> <ws> ')'
+     | '(' <ws> "quasiquote" <ws> <expr> <ws> ')'
+     | '(' <ws> "unquote" <ws> <expr> <ws> ')'
+     | '(' <ws> "if" <ws> <expr> <ws> <expr> <ws> (<expr> <ws>)?')'
+     | '(' <ws> "fn" <ws> '(' (<ws> <var> <ws>)* ')' (<ws> <expr> <ws>)+ ')'
+     | '(' <ws> "def" <ws> <var> <ws> <expr> <ws> ')'
+     | '(' <ws> <expr> (<ws> <expr> <ws>)* ')'
+     | /['`,]/ <expr>
+     | <atom>
+     ;
+
+atom : <num> | <ch> | <str> | <bool> | <var> ;
+
+num : "0b" /[0-1]+/
+    | "0o" /[0-7]+/
+    | "0d" /[0-9]+/
+    | "0x" /[0-9a-fA-F]+/
+    | /[-+]?[0-9]+(\.[0-9]+)?/
+    ;
+
+ch : '\\' ("space"|"newline"|"return"|"tab"|"vtab")
+   | '\\' /./
+   ;
+
+str : '"' /[^"]*/ '"' ;
+
+bool : "True" | "False" ;
+
+var : /[^() \t\r\n#`'"]+/ ;
+
+ws : '#' /[^\n]*\n/ | /[ \t\r\n]*/ ;
diff --git a/source/sclpl/main.c b/source/sclpl/main.c
new file mode 100644 (file)
index 0000000..dc85100
--- /dev/null
@@ -0,0 +1,40 @@
+#include "mpc.h"
+#include <stdio.h>
+
+/* SCLPL Parser
+ *****************************************************************************/
+/* Grammar is auto generated into 'source/grammar.c' */
+extern const char Grammar[];
+
+mpc_ast_t* format_expr_ast(mpc_ast_t* expr) {
+    return expr;
+}
+
+int main(int argc, char **argv) {
+    mpc_parser_t* ReplExpr = mpc_new("replexpr");
+    mpc_parser_t* Expr = mpc_new("expr");
+    mpc_parser_t* Atom = mpc_new("atom");
+    mpc_parser_t* Num = mpc_new("num");
+    mpc_parser_t* Char = mpc_new("ch");
+    mpc_parser_t* String = mpc_new("str");
+    mpc_parser_t* Bool = mpc_new("bool");
+    mpc_parser_t* Var = mpc_new("var");
+    mpc_parser_t* WS = mpc_new("ws");
+    mpca_lang(MPCA_LANG_WHITESPACE_SENSITIVE, Grammar,
+        ReplExpr, Expr, Atom, Num, Char, String, Bool, Var, WS, NULL);
+    while(!feof(stdin)) {
+        mpc_result_t r;
+        printf(":> ");
+        if (mpc_parse_pipe("<stdin>", stdin, ReplExpr, &r)) {
+            mpc_ast_t* expr = (mpc_ast_t*)(((mpc_ast_t*)r.output)->children[1]);
+            mpc_ast_print(format_expr_ast(expr));
+            mpc_ast_delete(r.output);
+        } else {
+            mpc_err_print(r.error);
+            mpc_err_delete(r.error);
+            while('\n' != fgetc(stdin)){}
+        }
+    }
+    mpc_cleanup(9, ReplExpr, Expr, Atom, Num, Char, String, Bool, Var, WS);
+    return 0;
+}
diff --git a/source/sclpl/mpc.c b/source/sclpl/mpc.c
new file mode 100644 (file)
index 0000000..5b0c5c4
--- /dev/null
@@ -0,0 +1,3219 @@
+#include "mpc.h"\r
+\r
+/*\r
+** State Type\r
+*/\r
+\r
+static mpc_state_t mpc_state_invalid(void) {\r
+  mpc_state_t s;\r
+  s.pos = -1;\r
+  s.row = -1;\r
+  s.col = -1;\r
+  return s;\r
+}\r
+\r
+static mpc_state_t mpc_state_new(void) {\r
+  mpc_state_t s;\r
+  s.pos = 0;\r
+  s.row = 0;\r
+  s.col = 0;\r
+  return s;\r
+}\r
+\r
+static mpc_state_t *mpc_state_copy(mpc_state_t s) {\r
+  mpc_state_t *r = malloc(sizeof(mpc_state_t));\r
+  memcpy(r, &s, sizeof(mpc_state_t));\r
+  return r;\r
+}\r
+\r
+/*\r
+** Error Type\r
+*/\r
+\r
+static mpc_err_t *mpc_err_new(const char *filename, mpc_state_t s, const char *expected, char recieved) {\r
+  mpc_err_t *x = malloc(sizeof(mpc_err_t));\r
+  x->filename = malloc(strlen(filename) + 1);\r
+  strcpy(x->filename, filename);\r
+  x->state = s;\r
+  x->expected_num = 1;\r
+  x->expected = malloc(sizeof(char*));\r
+  x->expected[0] = malloc(strlen(expected) + 1);\r
+  strcpy(x->expected[0], expected);\r
+  x->failure = NULL;\r
+  x->recieved = recieved;\r
+  return x;\r
+}\r
+\r
+static mpc_err_t *mpc_err_fail(const char *filename, mpc_state_t s, const char *failure) {\r
+  mpc_err_t *x = malloc(sizeof(mpc_err_t));\r
+  x->filename = malloc(strlen(filename) + 1);\r
+  strcpy(x->filename, filename);\r
+  x->state = s;\r
+  x->expected_num = 0;\r
+  x->expected = NULL;\r
+  x->failure = malloc(strlen(failure) + 1);\r
+  strcpy(x->failure, failure);\r
+  x->recieved = ' ';\r
+  return x;\r
+}\r
+\r
+void mpc_err_delete(mpc_err_t *x) {\r
+\r
+  int i;\r
+  for (i = 0; i < x->expected_num; i++) {\r
+    free(x->expected[i]);\r
+  }\r
+  \r
+  free(x->expected);\r
+  free(x->filename);\r
+  free(x->failure);\r
+  free(x);\r
+}\r
+\r
+static int mpc_err_contains_expected(mpc_err_t *x, char *expected) {\r
+  \r
+  int i;\r
+  for (i = 0; i < x->expected_num; i++) {\r
+    if (strcmp(x->expected[i], expected) == 0) { return 1; }\r
+  }\r
+  \r
+  return 0;\r
+}\r
+\r
+static void mpc_err_add_expected(mpc_err_t *x, char *expected) {\r
+  \r
+  x->expected_num++;\r
+  x->expected = realloc(x->expected, sizeof(char*) * x->expected_num);\r
+  x->expected[x->expected_num-1] = malloc(strlen(expected) + 1);\r
+  strcpy(x->expected[x->expected_num-1], expected);\r
+  \r
+}\r
+\r
+static void mpc_err_clear_expected(mpc_err_t *x, char *expected) {\r
+  \r
+  int i;\r
+  for (i = 0; i < x->expected_num; i++) {\r
+    free(x->expected[i]);\r
+  }\r
+  x->expected_num = 1;\r
+  x->expected = realloc(x->expected, sizeof(char*) * x->expected_num);\r
+  x->expected[0] = malloc(strlen(expected) + 1);\r
+  strcpy(x->expected[0], expected);\r
+  \r
+}\r
+\r
+void mpc_err_print(mpc_err_t *x) {\r
+  mpc_err_print_to(x, stdout);\r
+}\r
+\r
+void mpc_err_print_to(mpc_err_t *x, FILE *f) {\r
+  char *str = mpc_err_string(x);\r
+  fprintf(f, "%s", str);\r
+  free(str);\r
+}\r
+\r
+void mpc_err_string_cat(char *buffer, int *pos, int *max, char *fmt, ...) {\r
+  /* TODO: Error Checking on Length */\r
+  int left = ((*max) - (*pos));\r
+  va_list va;\r
+  va_start(va, fmt);\r
+  if (left < 0) { left = 0;}\r
+  (*pos) += vsprintf(buffer + (*pos), fmt, va);\r
+  va_end(va);\r
+}\r
+\r
+static char char_unescape_buffer[3];\r
+\r
+static char *mpc_err_char_unescape(char c) {\r
+  \r
+  char_unescape_buffer[0] = '\'';\r
+  char_unescape_buffer[1] = ' ';\r
+  char_unescape_buffer[2] = '\'';\r
+  \r
+  switch (c) {\r
+    \r
+    case '\a': return "bell";\r
+    case '\b': return "backspace";\r
+    case '\f': return "formfeed";\r
+    case '\r': return "carriage return";\r
+    case '\v': return "vertical tab";\r
+    case '\0': return "end of input";\r
+    case '\n': return "newline";\r
+    case '\t': return "tab";\r
+    case ' ' : return "space";\r
+    default:\r
+      char_unescape_buffer[1] = c;\r
+      return char_unescape_buffer;\r
+  }\r
+  \r
+}\r
+\r
+char *mpc_err_string(mpc_err_t *x) {\r
+  \r
+  char *buffer = calloc(1, 1024);\r
+  int max = 1023;\r
+  int pos = 0; \r
+  int i;\r
+  \r
+  if (x->failure) {\r
+    mpc_err_string_cat(buffer, &pos, &max,\r
+    "%s: error: %s\n", \r
+      x->filename, x->failure);\r
+    return buffer;\r
+  }\r
+  \r
+  mpc_err_string_cat(buffer, &pos, &max, \r
+    "%s:%i:%i: error: expected ", x->filename, x->state.row+1, x->state.col+1);\r
+  \r
+  if (x->expected_num == 0) { mpc_err_string_cat(buffer, &pos, &max, "ERROR: NOTHING EXPECTED"); }\r
+  if (x->expected_num == 1) { mpc_err_string_cat(buffer, &pos, &max, "%s", x->expected[0]); }\r
+  if (x->expected_num >= 2) {\r
+  \r
+    for (i = 0; i < x->expected_num-2; i++) {\r
+      mpc_err_string_cat(buffer, &pos, &max, "%s, ", x->expected[i]);\r
+    } \r
+    \r
+    mpc_err_string_cat(buffer, &pos, &max, "%s or %s", \r
+      x->expected[x->expected_num-2], \r
+      x->expected[x->expected_num-1]);\r
+  }\r
+  \r
+  mpc_err_string_cat(buffer, &pos, &max, " at ");\r
+  mpc_err_string_cat(buffer, &pos, &max, mpc_err_char_unescape(x->recieved));\r
+  mpc_err_string_cat(buffer, &pos, &max, "\n");\r
+  \r
+  return realloc(buffer, strlen(buffer) + 1);\r
+}\r
+\r
+static mpc_err_t *mpc_err_or(mpc_err_t** x, int n) {\r
+  \r
+  int i, j;\r
+  mpc_err_t *e = malloc(sizeof(mpc_err_t));\r
+  e->state = mpc_state_invalid();\r
+  e->expected_num = 0;\r
+  e->expected = NULL;\r
+  e->failure = NULL;\r
+  e->filename = malloc(strlen(x[0]->filename)+1);\r
+  strcpy(e->filename, x[0]->filename);\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    if (x[i]->state.pos > e->state.pos) { e->state = x[i]->state; }\r
+  }\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    \r
+    if (x[i]->state.pos < e->state.pos) { continue; }\r
+    \r
+    if (x[i]->failure) {\r
+      e->failure = malloc(strlen(x[i]->failure)+1);\r
+      strcpy(e->failure, x[i]->failure);\r
+      break;\r
+    }\r
+    \r
+    e->recieved = x[i]->recieved;\r
+    \r
+    for (j = 0; j < x[i]->expected_num; j++) {\r
+      if (!mpc_err_contains_expected(e, x[i]->expected[j])) { mpc_err_add_expected(e, x[i]->expected[j]); }\r
+    }\r
+  }\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    mpc_err_delete(x[i]);\r
+  }\r
+  \r
+  return e;\r
+}\r
+\r
+static mpc_err_t *mpc_err_repeat(mpc_err_t *x, const char *prefix) {\r
+\r
+  int i;\r
+  char *expect = malloc(strlen(prefix) + 1);\r
+  strcpy(expect, prefix);\r
+  \r
+  if (x->expected_num == 1) {\r
+    expect = realloc(expect, strlen(expect) + strlen(x->expected[0]) + 1);\r
+    strcat(expect, x->expected[0]);\r
+  }\r
+  \r
+  if (x->expected_num > 1) {\r
+  \r
+    for (i = 0; i < x->expected_num-2; i++) {\r
+      expect = realloc(expect, strlen(expect) + strlen(x->expected[i]) + strlen(", ") + 1);\r
+      strcat(expect, x->expected[i]);\r
+      strcat(expect, ", ");\r
+    }\r
+    \r
+    expect = realloc(expect, strlen(expect) + strlen(x->expected[x->expected_num-2]) + strlen(" or ") + 1);\r
+    strcat(expect, x->expected[x->expected_num-2]);\r
+    strcat(expect, " or ");\r
+    expect = realloc(expect, strlen(expect) + strlen(x->expected[x->expected_num-1]) + 1);\r
+    strcat(expect, x->expected[x->expected_num-1]);\r
+\r
+  }\r
+  \r
+  mpc_err_clear_expected(x, expect);\r
+  free(expect);\r
+  \r
+  return x;\r
+\r
+}\r
+\r
+static mpc_err_t *mpc_err_many1(mpc_err_t *x) {\r
+  return mpc_err_repeat(x, "one or more of ");\r
+}\r
+\r
+static mpc_err_t *mpc_err_count(mpc_err_t *x, int n) {\r
+  mpc_err_t *y;\r
+  int digits = n/10 + 1;\r
+  char *prefix = malloc(digits + strlen(" of ") + 1);\r
+  sprintf(prefix, "%i of ", n);\r
+  y = mpc_err_repeat(x, prefix);\r
+  free(prefix);\r
+  return y;\r
+}\r
+\r
+/*\r
+** Input Type\r
+*/\r
+\r
+/*\r
+** In mpc the input type has three modes of \r
+** operation: String, File and Pipe.\r
+**\r
+** String is easy. The whole contents are \r
+** loaded into a buffer and scanned through.\r
+** The cursor can jump around at will making \r
+** backtracking easy.\r
+**\r
+** The second is a File which is also somewhat\r
+** easy. The contents are never loaded into \r
+** memory but backtracking can still be achieved\r
+** by seeking in the file at different positions.\r
+**\r
+** The final mode is Pipe. This is the difficult\r
+** one. As we assume pipes cannot be seeked - and \r
+** only support a single character lookahead at \r
+** any point, when the input is marked for a \r
+** potential backtracking we start buffering any \r
+** input.\r
+**\r
+** This means that if we are requested to seek\r
+** back we can simply start reading from the\r
+** buffer instead of the input.\r
+**\r
+** Of course using `mpc_predictive` will disable\r
+** backtracking and make LL(1) grammars easy\r
+** to parse for all input methods.\r
+**\r
+*/\r
+\r
+enum {\r
+  MPC_INPUT_STRING = 0,\r
+  MPC_INPUT_FILE   = 1,\r
+  MPC_INPUT_PIPE   = 2\r
+};\r
+\r
+typedef struct {\r
+\r
+  int type;\r
+  char *filename;  \r
+  mpc_state_t state;\r
+  \r
+  char *string;\r
+  char *buffer;\r
+  FILE *file;\r
+  \r
+  int backtrack;\r
+  int marks_num;\r
+  mpc_state_t* marks;\r
+  char* lasts;\r
+  \r
+  char last;\r
+  \r
+} mpc_input_t;\r
+\r
+static mpc_input_t *mpc_input_new_string(const char *filename, const char *string) {\r
+\r
+  mpc_input_t *i = malloc(sizeof(mpc_input_t));\r
+  \r
+  i->filename = malloc(strlen(filename) + 1);\r
+  strcpy(i->filename, filename);\r
+  i->type = MPC_INPUT_STRING;\r
+  \r
+  i->state = mpc_state_new();\r
+  \r
+  i->string = malloc(strlen(string) + 1);\r
+  strcpy(i->string, string);\r
+  i->buffer = NULL;\r
+  i->file = NULL;\r
+  \r
+  i->backtrack = 1;\r
+  i->marks_num = 0;\r
+  i->marks = NULL;\r
+  i->lasts = NULL;\r
+\r
+  i->last = '\0';\r
+  \r
+  return i;\r
+}\r
+\r
+static mpc_input_t *mpc_input_new_pipe(const char *filename, FILE *pipe) {\r
+\r
+  mpc_input_t *i = malloc(sizeof(mpc_input_t));\r
+  \r
+  i->filename = malloc(strlen(filename) + 1);\r
+  strcpy(i->filename, filename);\r
+  \r
+  i->type = MPC_INPUT_PIPE;\r
+  i->state = mpc_state_new();\r
+  \r
+  i->string = NULL;\r
+  i->buffer = NULL;\r
+  i->file = pipe;\r
+  \r
+  i->backtrack = 1;\r
+  i->marks_num = 0;\r
+  i->marks = NULL;\r
+  i->lasts = NULL;\r
+  \r
+  i->last = '\0';\r
+  \r
+  return i;\r
+  \r
+}\r
+\r
+static mpc_input_t *mpc_input_new_file(const char *filename, FILE *file) {\r
+  \r
+  mpc_input_t *i = malloc(sizeof(mpc_input_t));\r
+  \r
+  i->filename = malloc(strlen(filename) + 1);\r
+  strcpy(i->filename, filename);\r
+  i->type = MPC_INPUT_FILE;\r
+  i->state = mpc_state_new();\r
+  \r
+  i->string = NULL;\r
+  i->buffer = NULL;\r
+  i->file = file;\r
+  \r
+  i->backtrack = 1;\r
+  i->marks_num = 0;\r
+  i->marks = NULL;\r
+  i->lasts = NULL;\r
+  \r
+  i->last = '\0';\r
+  \r
+  return i;\r
+}\r
+\r
+static void mpc_input_delete(mpc_input_t *i) {\r
+  \r
+  free(i->filename);\r
+  \r
+  if (i->type == MPC_INPUT_STRING) { free(i->string); }\r
+  if (i->type == MPC_INPUT_PIPE) { free(i->buffer); }\r
+  \r
+  free(i->marks);\r
+  free(i->lasts);\r
+  free(i);\r
+}\r
+\r
+static void mpc_input_backtrack_disable(mpc_input_t *i) { i->backtrack--; }\r
+static void mpc_input_backtrack_enable(mpc_input_t *i) { i->backtrack++; }\r
+\r
+static void mpc_input_mark(mpc_input_t *i) {\r
+  \r
+  if (i->backtrack < 1) { return; }\r
+  \r
+  i->marks_num++;\r
+  i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_num);\r
+  i->lasts = realloc(i->lasts, sizeof(char) * i->marks_num);\r
+  i->marks[i->marks_num-1] = i->state;\r
+  i->lasts[i->marks_num-1] = i->last;\r
+  \r
+  if (i->type == MPC_INPUT_PIPE && i->marks_num == 1) {\r
+    i->buffer = calloc(1, 1);\r
+  }\r
+  \r
+}\r
+\r
+static void mpc_input_unmark(mpc_input_t *i) {\r
+  \r
+  if (i->backtrack < 1) { return; }\r
+  \r
+  i->marks_num--;\r
+  i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_num);\r
+  i->lasts = realloc(i->lasts, sizeof(char) * i->marks_num);\r
+  \r
+  if (i->type == MPC_INPUT_PIPE && i->marks_num == 0) {\r
+    free(i->buffer);\r
+    i->buffer = NULL;\r
+  }\r
+  \r
+}\r
+\r
+static void mpc_input_rewind(mpc_input_t *i) {\r
+  \r
+  if (i->backtrack < 1) { return; }\r
+  \r
+  i->state = i->marks[i->marks_num-1];\r
+  i->last  = i->lasts[i->marks_num-1];\r
+  \r
+  if (i->type == MPC_INPUT_FILE) {\r
+    fseek(i->file, i->state.pos, SEEK_SET);\r
+  }\r
+  \r
+  mpc_input_unmark(i);\r
+}\r
+\r
+static int mpc_input_buffer_in_range(mpc_input_t *i) {\r
+  return i->state.pos < (strlen(i->buffer) + i->marks[0].pos);\r
+}\r
+\r
+static char mpc_input_buffer_get(mpc_input_t *i) {\r
+  return i->buffer[i->state.pos - i->marks[0].pos];\r
+}\r
+\r
+static int mpc_input_terminated(mpc_input_t *i) {\r
+  if (i->type == MPC_INPUT_STRING && i->state.pos == strlen(i->string)) { return 1; }\r
+  if (i->type == MPC_INPUT_FILE && feof(i->file)) { return 1; }\r
+  if (i->type == MPC_INPUT_PIPE && feof(i->file)) { return 1; }\r
+  return 0;\r
+}\r
+\r
+static char mpc_input_getc(mpc_input_t *i) {\r
+  \r
+  char c = '\0';\r
+  \r
+  switch (i->type) {\r
+    \r
+    case MPC_INPUT_STRING: return i->string[i->state.pos];\r
+    case MPC_INPUT_FILE: c = fgetc(i->file); return c;\r
+    case MPC_INPUT_PIPE:\r
+    \r
+      if (!i->buffer) { c = getc(i->file); return c; }\r
+      \r
+      if (i->buffer && mpc_input_buffer_in_range(i)) {\r
+        c = mpc_input_buffer_get(i);\r
+        return c;\r
+      } else {\r
+        c = getc(i->file);\r
+        return c;\r
+      }\r
+    \r
+    default: return c;\r
+  }\r
+}\r
+\r
+static char mpc_input_peekc(mpc_input_t *i) {\r
+  \r
+  char c = '\0';\r
+  \r
+  switch (i->type) {\r
+    case MPC_INPUT_STRING: return i->string[i->state.pos];\r
+    case MPC_INPUT_FILE: \r
+      \r
+      c = fgetc(i->file);\r
+      if (feof(i->file)) { return '\0'; }\r
+      \r
+      fseek(i->file, -1, SEEK_CUR);\r
+      return c;\r
+    \r
+    case MPC_INPUT_PIPE:\r
+      \r
+      if (!i->buffer) {\r
+        c = getc(i->file);\r
+        if (feof(i->file)) { return '\0'; }\r
+        ungetc(c, i->file);\r
+        return c;\r
+      }\r
+      \r
+      if (i->buffer && mpc_input_buffer_in_range(i)) {\r
+        return mpc_input_buffer_get(i);\r
+      } else {\r
+        c = getc(i->file);\r
+        if (feof(i->file)) { return '\0'; }\r
+        ungetc(c, i->file);\r
+        return c;\r
+      }\r
+    \r
+    default: return c;\r
+  }\r
+  \r
+}\r
+\r
+static int mpc_input_failure(mpc_input_t *i, char c) {\r
+\r
+  switch (i->type) {\r
+    case MPC_INPUT_STRING: break;\r
+    case MPC_INPUT_FILE: fseek(i->file, -1, SEEK_CUR); break;\r
+    case MPC_INPUT_PIPE:\r
+      \r
+      if (!i->buffer) { ungetc(c, i->file); break; }\r
+      \r
+      if (i->buffer && mpc_input_buffer_in_range(i)) {\r
+        break;\r
+      } else {\r
+        ungetc(c, i->file); \r
+      }\r
+      \r
+  }\r
+  \r
+  return 0;\r
+}\r
+\r
+static int mpc_input_success(mpc_input_t *i, char c, char **o) {\r
+  \r
+  if (i->type == MPC_INPUT_PIPE &&\r
+      i->buffer &&\r
+      !mpc_input_buffer_in_range(i)) {\r
+    \r
+    i->buffer = realloc(i->buffer, strlen(i->buffer) + 2);\r
+    i->buffer[strlen(i->buffer) + 1] = '\0';\r
+    i->buffer[strlen(i->buffer) + 0] = c;\r
+  }\r
+  \r
+  i->last = c;\r
+  i->state.pos++;\r
+  i->state.col++;\r
+  \r
+  if (c == '\n') {\r
+    i->state.col = 0;\r
+    i->state.row++;\r
+  }\r
+  \r
+  if (o) {\r
+    (*o) = malloc(2);\r
+    (*o)[0] = c;\r
+    (*o)[1] = '\0';\r
+  }\r
+  \r
+  return 1;\r
+}\r
+\r
+static int mpc_input_any(mpc_input_t *i, char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return mpc_input_success(i, x, o);\r
+}\r
+\r
+static int mpc_input_char(mpc_input_t *i, char c, char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return x == c ? mpc_input_success(i, x, o) : mpc_input_failure(i, x);\r
+}\r
+\r
+static int mpc_input_range(mpc_input_t *i, char c, char d, char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return x >= c && x <= d ? mpc_input_success(i, x, o) : mpc_input_failure(i, x);  \r
+}\r
+\r
+static int mpc_input_oneof(mpc_input_t *i, const char *c, char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return strchr(c, x) != 0 ? mpc_input_success(i, x, o) : mpc_input_failure(i, x);  \r
+}\r
+\r
+static int mpc_input_noneof(mpc_input_t *i, const char *c, char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return strchr(c, x) == 0 ? mpc_input_success(i, x, o) : mpc_input_failure(i, x);  \r
+}\r
+\r
+static int mpc_input_satisfy(mpc_input_t *i, int(*cond)(char), char **o) {\r
+  char x = mpc_input_getc(i);\r
+  if (mpc_input_terminated(i)) { return 0; }\r
+  return cond(x) ? mpc_input_success(i, x, o) : mpc_input_failure(i, x);  \r
+}\r
+\r
+static int mpc_input_string(mpc_input_t *i, const char *c, char **o) {\r
+  \r
+  char *co = NULL;\r
+  const char *x = c;\r
+\r
+  mpc_input_mark(i);\r
+  while (*x) {\r
+    if (mpc_input_char(i, *x, &co)) {\r
+      free(co);\r
+    } else {\r
+      mpc_input_rewind(i);\r
+      return 0;\r
+    }\r
+    x++;\r
+  }\r
+  mpc_input_unmark(i);\r
+  \r
+  *o = malloc(strlen(c) + 1);\r
+  strcpy(*o, c);\r
+  return 1;\r
+}\r
+\r
+static int mpc_input_anchor(mpc_input_t* i, int(*f)(char,char)) {\r
+  return f(i->last, mpc_input_peekc(i));\r
+}\r
+\r
+/*\r
+** Parser Type\r
+*/\r
+\r
+enum {\r
+  MPC_TYPE_UNDEFINED = 0,\r
+  MPC_TYPE_PASS      = 1,\r
+  MPC_TYPE_FAIL      = 2,\r
+  MPC_TYPE_LIFT      = 3,\r
+  MPC_TYPE_LIFT_VAL  = 4,\r
+  MPC_TYPE_EXPECT    = 5,\r
+  MPC_TYPE_ANCHOR    = 6,\r
+  MPC_TYPE_STATE     = 7,\r
+  \r
+  MPC_TYPE_ANY       = 8,\r
+  MPC_TYPE_SINGLE    = 9,\r
+  MPC_TYPE_ONEOF     = 10,\r
+  MPC_TYPE_NONEOF    = 11,\r
+  MPC_TYPE_RANGE     = 12,\r
+  MPC_TYPE_SATISFY   = 13,\r
+  MPC_TYPE_STRING    = 14,\r
+  \r
+  MPC_TYPE_APPLY     = 15,\r
+  MPC_TYPE_APPLY_TO  = 16,\r
+  MPC_TYPE_PREDICT   = 17,\r
+  MPC_TYPE_NOT       = 18,\r
+  MPC_TYPE_MAYBE     = 19,\r
+  MPC_TYPE_MANY      = 20,\r
+  MPC_TYPE_MANY1     = 21,\r
+  MPC_TYPE_COUNT     = 22,\r
+  \r
+  MPC_TYPE_OR        = 23,\r
+  MPC_TYPE_AND       = 24\r
+};\r
+\r
+typedef struct { char *m; } mpc_pdata_fail_t;\r
+typedef struct { mpc_ctor_t lf; void *x; } mpc_pdata_lift_t;\r
+typedef struct { mpc_parser_t *x; char *m; } mpc_pdata_expect_t;\r
+typedef struct { int(*f)(char,char); } mpc_pdata_anchor_t;\r
+typedef struct { char x; } mpc_pdata_single_t;\r
+typedef struct { char x; char y; } mpc_pdata_range_t;\r
+typedef struct { int(*f)(char); } mpc_pdata_satisfy_t;\r
+typedef struct { char *x; } mpc_pdata_string_t;\r
+typedef struct { mpc_parser_t *x; mpc_apply_t f; } mpc_pdata_apply_t;\r
+typedef struct { mpc_parser_t *x; mpc_apply_to_t f; void *d; } mpc_pdata_apply_to_t;\r
+typedef struct { mpc_parser_t *x; } mpc_pdata_predict_t;\r
+typedef struct { mpc_parser_t *x; mpc_dtor_t dx; mpc_ctor_t lf; } mpc_pdata_not_t;\r
+typedef struct { int n; mpc_fold_t f; mpc_parser_t *x; mpc_dtor_t dx; } mpc_pdata_repeat_t;\r
+typedef struct { int n; mpc_parser_t **xs; } mpc_pdata_or_t;\r
+typedef struct { int n; mpc_fold_t f; mpc_parser_t **xs; mpc_dtor_t *dxs;  } mpc_pdata_and_t;\r
+\r
+typedef union {\r
+  mpc_pdata_fail_t fail;\r
+  mpc_pdata_lift_t lift;\r
+  mpc_pdata_expect_t expect;\r
+  mpc_pdata_anchor_t anchor;\r
+  mpc_pdata_single_t single;\r
+  mpc_pdata_range_t range;\r
+  mpc_pdata_satisfy_t satisfy;\r
+  mpc_pdata_string_t string;\r
+  mpc_pdata_apply_t apply;\r
+  mpc_pdata_apply_to_t apply_to;\r
+  mpc_pdata_predict_t predict;\r
+  mpc_pdata_not_t not;\r
+  mpc_pdata_repeat_t repeat;\r
+  mpc_pdata_and_t and;\r
+  mpc_pdata_or_t or;\r
+} mpc_pdata_t;\r
+\r
+struct mpc_parser_t {\r
+  char retained;\r
+  char *name;\r
+  char type;\r
+  mpc_pdata_t data;\r
+};\r
+\r
+/*\r
+** Stack Type\r
+*/\r
+\r
+typedef struct {\r
+\r
+  int parsers_num;\r
+  int parsers_slots;\r
+  mpc_parser_t **parsers;\r
+  int *states;\r
+\r
+  int results_num;\r
+  int results_slots;\r
+  mpc_result_t *results;\r
+  int *returns;\r
+  \r
+  mpc_err_t *err;\r
+  \r
+} mpc_stack_t;\r
+\r
+static mpc_stack_t *mpc_stack_new(const char *filename) {\r
+  mpc_stack_t *s = malloc(sizeof(mpc_stack_t));\r
+  \r
+  s->parsers_num = 0;\r
+  s->parsers_slots = 0;\r
+  s->parsers = NULL;\r
+  s->states = NULL;\r
+  \r
+  s->results_num = 0;\r
+  s->results_slots = 0;\r
+  s->results = NULL;\r
+  s->returns = NULL;\r
+  \r
+  s->err = mpc_err_fail(filename, mpc_state_invalid(), "Unknown Error");\r
+  \r
+  return s;\r
+}\r
+\r
+static void mpc_stack_err(mpc_stack_t *s, mpc_err_t* e) {\r
+  mpc_err_t *errs[2];\r
+  errs[0] = s->err;\r
+  errs[1] = e;\r
+  s->err = mpc_err_or(errs, 2);\r
+}\r
+\r
+static int mpc_stack_terminate(mpc_stack_t *s, mpc_result_t *r) {\r
+  int success = s->returns[0];\r
+  \r
+  if (success) {\r
+    r->output = s->results[0].output;\r
+    mpc_err_delete(s->err);\r
+  } else {\r
+    mpc_stack_err(s, s->results[0].error);\r
+    r->error = s->err;\r
+  }\r
+  \r
+  free(s->parsers);\r
+  free(s->states);\r
+  free(s->results);\r
+  free(s->returns);\r
+  free(s);\r
+  \r
+  return success;\r
+}\r
+\r
+/* Stack Parser Stuff */\r
+\r
+static void mpc_stack_set_state(mpc_stack_t *s, int x) {\r
+  s->states[s->parsers_num-1] = x;\r
+}\r
+\r
+static void mpc_stack_parsers_reserve_more(mpc_stack_t *s) {\r
+  if (s->parsers_num > s->parsers_slots) {\r
+    s->parsers_slots = ceil((s->parsers_slots+1) * 1.5);\r
+    s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots);\r
+    s->states = realloc(s->states, sizeof(int) * s->parsers_slots);\r
+  }\r
+}\r
+\r
+static void mpc_stack_parsers_reserve_less(mpc_stack_t *s) {\r
+  if (s->parsers_slots > pow(s->parsers_num+1, 1.5)) {\r
+    s->parsers_slots = floor((s->parsers_slots-1) * (1.0/1.5));\r
+    s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots);\r
+    s->states = realloc(s->states, sizeof(int) * s->parsers_slots);\r
+  }\r
+}\r
+\r
+static void mpc_stack_pushp(mpc_stack_t *s, mpc_parser_t *p) {\r
+  s->parsers_num++;\r
+  mpc_stack_parsers_reserve_more(s);\r
+  s->parsers[s->parsers_num-1] = p;\r
+  s->states[s->parsers_num-1] = 0;\r
+}\r
+\r
+static void mpc_stack_popp(mpc_stack_t *s, mpc_parser_t **p, int *st) {\r
+  *p = s->parsers[s->parsers_num-1];\r
+  *st = s->states[s->parsers_num-1];\r
+  s->parsers_num--;\r
+  mpc_stack_parsers_reserve_less(s);\r
+}\r
+\r
+static void mpc_stack_peepp(mpc_stack_t *s, mpc_parser_t **p, int *st) {\r
+  *p = s->parsers[s->parsers_num-1];\r
+  *st = s->states[s->parsers_num-1];\r
+}\r
+\r
+static int mpc_stack_empty(mpc_stack_t *s) {\r
+  return s->parsers_num == 0;\r
+}\r
+\r
+/* Stack Result Stuff */\r
+\r
+static mpc_result_t mpc_result_err(mpc_err_t *e) {\r
+  mpc_result_t r;\r
+  r.error = e;\r
+  return r;\r
+}\r
+\r
+static mpc_result_t mpc_result_out(mpc_val_t *x) {\r
+  mpc_result_t r;\r
+  r.output = x;\r
+  return r;\r
+}\r
+\r
+static void mpc_stack_results_reserve_more(mpc_stack_t *s) {\r
+  if (s->results_num > s->results_slots) {\r
+    s->results_slots = ceil((s->results_slots + 1) * 1.5);\r
+    s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots);\r
+    s->returns = realloc(s->returns, sizeof(int) * s->results_slots);\r
+  }\r
+}\r
+\r
+static void mpc_stack_results_reserve_less(mpc_stack_t *s) {\r
+  if ( s->results_slots > pow(s->results_num+1, 1.5)) {\r
+    s->results_slots = floor((s->results_slots-1) * (1.0/1.5));\r
+    s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots);\r
+    s->returns = realloc(s->returns, sizeof(int) * s->results_slots);\r
+  }\r
+}\r
+\r
+static void mpc_stack_pushr(mpc_stack_t *s, mpc_result_t x, int r) {\r
+  s->results_num++;\r
+  mpc_stack_results_reserve_more(s);\r
+  s->results[s->results_num-1] = x;\r
+  s->returns[s->results_num-1] = r;\r
+}\r
+\r
+static int mpc_stack_popr(mpc_stack_t *s, mpc_result_t *x) {\r
+  int r;\r
+  *x = s->results[s->results_num-1];\r
+  r = s->returns[s->results_num-1];\r
+  s->results_num--;\r
+  mpc_stack_results_reserve_less(s);\r
+  return r;\r
+}\r
+\r
+static int mpc_stack_peekr(mpc_stack_t *s, mpc_result_t *x) {\r
+  *x = s->results[s->results_num-1];\r
+  return s->returns[s->results_num-1];\r
+}\r
+\r
+static void mpc_stack_popr_err(mpc_stack_t *s, int n) {\r
+  mpc_result_t x;\r
+  while (n) {\r
+    mpc_stack_popr(s, &x);\r
+    mpc_stack_err(s, x.error);\r
+    n--;\r
+  }\r
+}\r
+\r
+static void mpc_stack_popr_out(mpc_stack_t *s, int n, mpc_dtor_t *ds) {\r
+  mpc_result_t x;\r
+  while (n) {\r
+    mpc_stack_popr(s, &x);\r
+    ds[n-1](x.output);\r
+    n--;\r
+  }\r
+}\r
+\r
+static void mpc_stack_popr_out_single(mpc_stack_t *s, int n, mpc_dtor_t dx) {\r
+  mpc_result_t x;\r
+  while (n) {\r
+    mpc_stack_popr(s, &x);\r
+    dx(x.output);\r
+    n--;\r
+  }\r
+}\r
+\r
+static void mpc_stack_popr_n(mpc_stack_t *s, int n) {\r
+  mpc_result_t x;\r
+  while (n) {\r
+    mpc_stack_popr(s, &x);\r
+    n--;\r
+  }\r
+}\r
+\r
+static mpc_val_t *mpc_stack_merger_out(mpc_stack_t *s, int n, mpc_fold_t f) {\r
+  mpc_val_t *x = f(n, (mpc_val_t**)(&s->results[s->results_num-n]));\r
+  mpc_stack_popr_n(s, n);\r
+  return x;\r
+}\r
+\r
+static mpc_err_t *mpc_stack_merger_err(mpc_stack_t *s, int n) {\r
+  mpc_err_t *x = mpc_err_or((mpc_err_t**)(&s->results[s->results_num-n]), n);\r
+  mpc_stack_popr_n(s, n);\r
+  return x;\r
+}\r
+\r
+/*\r
+** This is rather pleasant. The core parsing routine\r
+** is written in about 200 lines of C.\r
+**\r
+** I also love the way in which each parsing type\r
+** concisely matches some construct or pattern.\r
+**\r
+** Particularly nice are the `or` and `and`\r
+** types which have a broken but mirrored structure\r
+** with return value and error reflected.\r
+**\r
+** When this function was written in recursive form\r
+** it looked pretty nice. But I've since switched\r
+** it around to an awkward while loop. It was an\r
+** unfortunate change for code simplicity but it\r
+** is noble in the name of performance (and \r
+** not smashing the stack).\r
+**\r
+** But it is now a pretty ugly beast...\r
+*/\r
+\r
+#define MPC_CONTINUE(st, x) mpc_stack_set_state(stk, st); mpc_stack_pushp(stk, x); continue\r
+#define MPC_SUCCESS(x) mpc_stack_popp(stk, &p, &st); mpc_stack_pushr(stk, mpc_result_out(x), 1); continue\r
+#define MPC_FAILURE(x) mpc_stack_popp(stk, &p, &st); mpc_stack_pushr(stk, mpc_result_err(x), 0); continue\r
+#define MPC_PRIMATIVE(x, f) if (f) { MPC_SUCCESS(x); } else { MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Incorrect Input")); }\r
+\r
+int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) {\r
+  \r
+  /* Stack */\r
+  int st = 0;\r
+  mpc_parser_t *p = NULL;\r
+  mpc_stack_t *stk = mpc_stack_new(i->filename);\r
+  \r
+  /* Variables */\r
+  char *s;\r
+  mpc_result_t r;\r
+\r
+  /* Go! */\r
+  mpc_stack_pushp(stk, init);\r
+  \r
+  while (!mpc_stack_empty(stk)) {\r
+    \r
+    mpc_stack_peepp(stk, &p, &st);\r
+    \r
+    switch (p->type) {\r
+      \r
+      /* Basic Parsers */\r
+\r
+      case MPC_TYPE_ANY:       MPC_PRIMATIVE(s, mpc_input_any(i, &s));\r
+      case MPC_TYPE_SINGLE:    MPC_PRIMATIVE(s, mpc_input_char(i, p->data.single.x, &s));\r
+      case MPC_TYPE_RANGE:     MPC_PRIMATIVE(s, mpc_input_range(i, p->data.range.x, p->data.range.y, &s));\r
+      case MPC_TYPE_ONEOF:     MPC_PRIMATIVE(s, mpc_input_oneof(i, p->data.string.x, &s));\r
+      case MPC_TYPE_NONEOF:    MPC_PRIMATIVE(s, mpc_input_noneof(i, p->data.string.x, &s));\r
+      case MPC_TYPE_SATISFY:   MPC_PRIMATIVE(s, mpc_input_satisfy(i, p->data.satisfy.f, &s));\r
+      case MPC_TYPE_STRING:    MPC_PRIMATIVE(s, mpc_input_string(i, p->data.string.x, &s));\r
+      \r
+      /* Other parsers */\r
+      \r
+      case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Parser Undefined!"));      \r
+      case MPC_TYPE_PASS:      MPC_SUCCESS(NULL);\r
+      case MPC_TYPE_FAIL:      MPC_FAILURE(mpc_err_fail(i->filename, i->state, p->data.fail.m));\r
+      case MPC_TYPE_LIFT:      MPC_SUCCESS(p->data.lift.lf());\r
+      case MPC_TYPE_LIFT_VAL:  MPC_SUCCESS(p->data.lift.x);\r
+      case MPC_TYPE_STATE:     MPC_SUCCESS(mpc_state_copy(i->state));\r
+      \r
+      case MPC_TYPE_ANCHOR:\r
+        if (mpc_input_anchor(i, p->data.anchor.f)) {\r
+          MPC_SUCCESS(NULL);\r
+        } else {\r
+          MPC_FAILURE(mpc_err_new(i->filename, i->state, "anchor", mpc_input_peekc(i)));\r
+        }\r
+      \r
+      /* Application Parsers */\r
+      \r
+      case MPC_TYPE_EXPECT:\r
+        if (st == 0) { MPC_CONTINUE(1, p->data.expect.x); }\r
+        if (st == 1) {\r
+          if (mpc_stack_popr(stk, &r)) {\r
+            MPC_SUCCESS(r.output);\r
+          } else {\r
+            mpc_err_delete(r.error); \r
+            MPC_FAILURE(mpc_err_new(i->filename, i->state, p->data.expect.m, mpc_input_peekc(i)));\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_APPLY:\r
+        if (st == 0) { MPC_CONTINUE(1, p->data.apply.x); }\r
+        if (st == 1) {\r
+          if (mpc_stack_popr(stk, &r)) {\r
+            MPC_SUCCESS(p->data.apply.f(r.output));\r
+          } else {\r
+            MPC_FAILURE(r.error);\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_APPLY_TO:\r
+        if (st == 0) { MPC_CONTINUE(1, p->data.apply_to.x); }\r
+        if (st == 1) {\r
+          if (mpc_stack_popr(stk, &r)) {\r
+            MPC_SUCCESS(p->data.apply_to.f(r.output, p->data.apply_to.d));\r
+          } else {\r
+            MPC_FAILURE(r.error);\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_PREDICT:\r
+        if (st == 0) { mpc_input_backtrack_disable(i); MPC_CONTINUE(1, p->data.predict.x); }\r
+        if (st == 1) {\r
+          mpc_input_backtrack_enable(i);\r
+          mpc_stack_popp(stk, &p, &st);\r
+          continue;\r
+        }\r
+      \r
+      /* Optional Parsers */\r
+      \r
+      /* TODO: Update Not Error Message */\r
+      \r
+      case MPC_TYPE_NOT:\r
+        if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(1, p->data.not.x); }\r
+        if (st == 1) {\r
+          if (mpc_stack_popr(stk, &r)) {\r
+            mpc_input_rewind(i);\r
+            p->data.not.dx(r.output);\r
+            MPC_FAILURE(mpc_err_new(i->filename, i->state, "opposite", mpc_input_peekc(i)));\r
+          } else {\r
+            mpc_input_unmark(i);\r
+            mpc_stack_err(stk, r.error);\r
+            MPC_SUCCESS(p->data.not.lf());\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_MAYBE:\r
+        if (st == 0) { MPC_CONTINUE(1, p->data.not.x); }\r
+        if (st == 1) {\r
+          if (mpc_stack_popr(stk, &r)) {\r
+            MPC_SUCCESS(r.output);\r
+          } else {\r
+            mpc_stack_err(stk, r.error);\r
+            MPC_SUCCESS(p->data.not.lf());\r
+          }\r
+        }\r
+      \r
+      /* Repeat Parsers */\r
+      \r
+      case MPC_TYPE_MANY:\r
+        if (st == 0) { MPC_CONTINUE(st+1, p->data.repeat.x); }\r
+        if (st >  0) {\r
+          if (mpc_stack_peekr(stk, &r)) {\r
+            MPC_CONTINUE(st+1, p->data.repeat.x);\r
+          } else {\r
+            mpc_stack_popr(stk, &r);\r
+            mpc_stack_err(stk, r.error);\r
+            MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f));\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_MANY1:\r
+        if (st == 0) { MPC_CONTINUE(st+1, p->data.repeat.x); }\r
+        if (st >  0) {\r
+          if (mpc_stack_peekr(stk, &r)) {\r
+            MPC_CONTINUE(st+1, p->data.repeat.x);\r
+          } else {\r
+            if (st == 1) {\r
+              mpc_stack_popr(stk, &r);\r
+              MPC_FAILURE(mpc_err_many1(r.error));\r
+            } else {\r
+              mpc_stack_popr(stk, &r);\r
+              mpc_stack_err(stk, r.error);\r
+              MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f));\r
+            }\r
+          }\r
+        }\r
+      \r
+      case MPC_TYPE_COUNT:\r
+        if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(st+1, p->data.repeat.x); }\r
+        if (st >  0) {\r
+          if (mpc_stack_peekr(stk, &r)) {\r
+            MPC_CONTINUE(st+1, p->data.repeat.x);\r
+          } else {\r
+            if (st != (p->data.repeat.n+1)) {\r
+              mpc_stack_popr(stk, &r);\r
+              mpc_stack_popr_out_single(stk, st-1, p->data.repeat.dx);\r
+              mpc_input_rewind(i);\r
+              MPC_FAILURE(mpc_err_count(r.error, p->data.repeat.n));\r
+            } else {\r
+              mpc_stack_popr(stk, &r);\r
+              mpc_stack_err(stk, r.error);\r
+              mpc_input_unmark(i);\r
+              MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f));\r
+            }\r
+          }\r
+        }\r
+        \r
+      /* Combinatory Parsers */\r
+      \r
+      case MPC_TYPE_OR:\r
+        \r
+        if (p->data.or.n == 0) { MPC_SUCCESS(NULL); }\r
+        \r
+        if (st == 0) { MPC_CONTINUE(st+1, p->data.or.xs[st]); }\r
+        if (st <= p->data.or.n) {\r
+          if (mpc_stack_peekr(stk, &r)) {\r
+            mpc_stack_popr(stk, &r);\r
+            mpc_stack_popr_err(stk, st-1);\r
+            MPC_SUCCESS(r.output);\r
+          }\r
+          if (st <  p->data.or.n) { MPC_CONTINUE(st+1, p->data.or.xs[st]); }\r
+          if (st == p->data.or.n) { MPC_FAILURE(mpc_stack_merger_err(stk, p->data.or.n)); }\r
+        }\r
+      \r
+      case MPC_TYPE_AND:\r
+        \r
+        if (p->data.or.n == 0) { MPC_SUCCESS(p->data.and.f(0, NULL)); }\r
+        \r
+        if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(st+1, p->data.and.xs[st]); }\r
+        if (st <= p->data.and.n) {\r
+          if (!mpc_stack_peekr(stk, &r)) {\r
+            mpc_input_rewind(i);\r
+            mpc_stack_popr(stk, &r);\r
+            mpc_stack_popr_out(stk, st-1, p->data.and.dxs);\r
+            MPC_FAILURE(r.error);\r
+          }\r
+          if (st <  p->data.and.n) { MPC_CONTINUE(st+1, p->data.and.xs[st]); }\r
+          if (st == p->data.and.n) { mpc_input_unmark(i); MPC_SUCCESS(mpc_stack_merger_out(stk, p->data.and.n, p->data.and.f)); }\r
+        }\r
+      \r
+      /* End */\r
+      \r
+      default:\r
+        \r
+        MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Unknown Parser Type Id!"));\r
+    }\r
+  }\r
+  \r
+  return mpc_stack_terminate(stk, final);\r
+  \r
+}\r
+\r
+#undef MPC_CONTINUE\r
+#undef MPC_SUCCESS\r
+#undef MPC_FAILURE\r
+#undef MPC_PRIMATIVE\r
+\r
+int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r) {\r
+  int x;\r
+  mpc_input_t *i = mpc_input_new_string(filename, string);\r
+  x = mpc_parse_input(i, p, r);\r
+  mpc_input_delete(i);\r
+  return x;\r
+}\r
+\r
+int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result_t *r) {\r
+  int x;\r
+  mpc_input_t *i = mpc_input_new_file(filename, file);\r
+  x = mpc_parse_input(i, p, r);\r
+  mpc_input_delete(i);\r
+  return x;\r
+}\r
+\r
+int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result_t *r) {\r
+  int x;\r
+  mpc_input_t *i = mpc_input_new_pipe(filename, pipe);\r
+  x = mpc_parse_input(i, p, r);\r
+  mpc_input_delete(i);\r
+  return x;\r
+}\r
+\r
+int mpc_parse_contents(const char *filename, mpc_parser_t *p, mpc_result_t *r) {\r
+  \r
+  FILE *f = fopen(filename, "rb");\r
+  int res;\r
+  \r
+  if (f == NULL) {\r
+    r->output = NULL;\r
+    r->error = mpc_err_fail(filename, mpc_state_new(), "Unable to open file!");\r
+    return 0;\r
+  }\r
+  \r
+  res = mpc_parse_file(filename, f, p, r);\r
+  fclose(f);\r
+  return res;\r
+}\r
+\r
+/*\r
+** Building a Parser\r
+*/\r
+\r
+static void mpc_undefine_unretained(mpc_parser_t *p, int force);\r
+\r
+static void mpc_undefine_or(mpc_parser_t *p) {\r
+  \r
+  int i;\r
+  for (i = 0; i < p->data.or.n; i++) {\r
+    mpc_undefine_unretained(p->data.or.xs[i], 0);\r
+  }\r
+  free(p->data.or.xs);\r
+  \r
+}\r
+\r
+static void mpc_undefine_and(mpc_parser_t *p) {\r
+  \r
+  int i;\r
+  for (i = 0; i < p->data.and.n; i++) {\r
+    mpc_undefine_unretained(p->data.and.xs[i], 0);\r
+  }\r
+  free(p->data.and.xs);\r
+  free(p->data.and.dxs);\r
+  \r
+}\r
+\r
+static void mpc_undefine_unretained(mpc_parser_t *p, int force) {\r
+  \r
+  if (p->retained && !force) { return; }\r
+  \r
+  switch (p->type) {\r
+    \r
+    case MPC_TYPE_FAIL: free(p->data.fail.m); break;\r
+    \r
+    case MPC_TYPE_ONEOF: \r
+    case MPC_TYPE_NONEOF:\r
+    case MPC_TYPE_STRING:\r
+      free(p->data.string.x); \r
+      break;\r
+    \r
+    case MPC_TYPE_APPLY:    mpc_undefine_unretained(p->data.apply.x, 0);    break;\r
+    case MPC_TYPE_APPLY_TO: mpc_undefine_unretained(p->data.apply_to.x, 0); break;\r
+    case MPC_TYPE_PREDICT:  mpc_undefine_unretained(p->data.predict.x, 0);  break;\r
+    \r
+    case MPC_TYPE_MAYBE:\r
+    case MPC_TYPE_NOT:\r
+      mpc_undefine_unretained(p->data.not.x, 0);\r
+      break;\r
+    \r
+    case MPC_TYPE_EXPECT:\r
+      mpc_undefine_unretained(p->data.expect.x, 0);\r
+      free(p->data.expect.m);\r
+      break;\r
+      \r
+    case MPC_TYPE_MANY:\r
+    case MPC_TYPE_MANY1:\r
+    case MPC_TYPE_COUNT:\r
+      mpc_undefine_unretained(p->data.repeat.x, 0);\r
+      break;\r
+    \r
+    case MPC_TYPE_OR:  mpc_undefine_or(p);  break;\r
+    case MPC_TYPE_AND: mpc_undefine_and(p); break;\r
+    \r
+    default: break;\r
+  }\r
+  \r
+  if (!force) {\r
+    free(p->name);\r
+    free(p);\r
+  }\r
+  \r
+}\r
+\r
+void mpc_delete(mpc_parser_t *p) {\r
+  if (p->retained) {\r
+\r
+    if (p->type != MPC_TYPE_UNDEFINED) {\r
+      mpc_undefine_unretained(p, 0);\r
+    } \r
+    \r
+    free(p->name);\r
+    free(p);\r
+  \r
+  } else {\r
+    mpc_undefine_unretained(p, 0);  \r
+  }\r
+}\r
+\r
+static void mpc_soft_delete(mpc_val_t *x) {\r
+  mpc_undefine_unretained(x, 0);\r
+}\r
+\r
+static mpc_parser_t *mpc_undefined(void) {\r
+  mpc_parser_t *p = calloc(1, sizeof(mpc_parser_t));\r
+  p->retained = 0;\r
+  p->type = MPC_TYPE_UNDEFINED;\r
+  p->name = NULL;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_new(const char *name) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->retained = 1;\r
+  p->name = realloc(p->name, strlen(name) + 1);\r
+  strcpy(p->name, name);\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_undefine(mpc_parser_t *p) {\r
+  mpc_undefine_unretained(p, 1);\r
+  p->type = MPC_TYPE_UNDEFINED;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_define(mpc_parser_t *p, mpc_parser_t *a) {\r
+  \r
+  if (p->retained) {\r
+    p->type = a->type;\r
+    p->data = a->data;\r
+  } else {\r
+    mpc_parser_t *a2 = mpc_failf("Attempt to assign to Unretained Parser!");\r
+    p->type = a2->type;\r
+    p->data = a2->data;\r
+    free(a2);\r
+  }\r
+  \r
+  free(a);\r
+  return p;  \r
+}\r
+\r
+void mpc_cleanup(int n, ...) {\r
+  int i;\r
+  mpc_parser_t **list = malloc(sizeof(mpc_parser_t*) * n);\r
+  \r
+  va_list va;\r
+  va_start(va, n);\r
+  for (i = 0; i < n; i++) { list[i] = va_arg(va, mpc_parser_t*); }\r
+  for (i = 0; i < n; i++) { mpc_undefine(list[i]); }\r
+  for (i = 0; i < n; i++) { mpc_delete(list[i]); }  \r
+  va_end(va);  \r
+\r
+  free(list);\r
+}\r
+\r
+mpc_parser_t *mpc_pass(void) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_PASS;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_fail(const char *m) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_FAIL;\r
+  p->data.fail.m = malloc(strlen(m) + 1);\r
+  strcpy(p->data.fail.m, m);\r
+  return p;\r
+}\r
+\r
+/*\r
+** As `snprintf` is not ANSI standard this \r
+** function `mpc_failf` should be considered\r
+** unsafe.\r
+**\r
+** You have a few options if this is going to be\r
+** trouble.\r
+**\r
+** - Ensure the format string does not exceed\r
+**   the buffer length using precision specifiers\r
+**   such as `%.512s`.\r
+**\r
+** - Patch this function in your code base to \r
+**   use `snprintf` or whatever variant your\r
+**   system supports.\r
+**\r
+** - Avoid it altogether.\r
+**\r
+*/\r
+\r
+mpc_parser_t *mpc_failf(const char *fmt, ...) {\r
+  \r
+  va_list va;\r
+  char *buffer;\r
+\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_FAIL;\r
+  \r
+  va_start(va, fmt);\r
+  buffer = malloc(2048);\r
+  vsprintf(buffer, fmt, va);\r
+  va_end(va);\r
+  \r
+  buffer = realloc(buffer, strlen(buffer) + 1);\r
+  p->data.fail.m = buffer;\r
+  return p;\r
+\r
+}\r
+\r
+mpc_parser_t *mpc_lift_val(mpc_val_t *x) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_LIFT_VAL;\r
+  p->data.lift.x = x;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_lift(mpc_ctor_t lf) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_LIFT;\r
+  p->data.lift.lf = lf;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_anchor(int(*f)(char,char)) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_ANCHOR;\r
+  p->data.anchor.f = f;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_state(void) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_STATE;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *expected) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_EXPECT;\r
+  p->data.expect.x = a;\r
+  p->data.expect.m = malloc(strlen(expected) + 1);\r
+  strcpy(p->data.expect.m, expected);\r
+  return p;\r
+}\r
+\r
+/*\r
+** As `snprintf` is not ANSI standard this \r
+** function `mpc_expectf` should be considered\r
+** unsafe.\r
+**\r
+** You have a few options if this is going to be\r
+** trouble.\r
+**\r
+** - Ensure the format string does not exceed\r
+**   the buffer length using precision specifiers\r
+**   such as `%.512s`.\r
+**\r
+** - Patch this function in your code base to \r
+**   use `snprintf` or whatever variant your\r
+**   system supports.\r
+**\r
+** - Avoid it altogether.\r
+**\r
+*/\r
+\r
+mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...) {\r
+  va_list va;\r
+  char *buffer;\r
+\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_EXPECT;\r
+  \r
+  va_start(va, fmt);\r
+  buffer = malloc(2048);\r
+  vsprintf(buffer, fmt, va);\r
+  va_end(va);\r
+  \r
+  buffer = realloc(buffer, strlen(buffer) + 1);\r
+  p->data.expect.x = a;\r
+  p->data.expect.m = buffer;\r
+  return p;\r
+}\r
+\r
+/*\r
+** Basic Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_any(void) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_ANY;\r
+  return mpc_expect(p, "any character");\r
+}\r
+\r
+mpc_parser_t *mpc_char(char c) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_SINGLE;\r
+  p->data.single.x = c;\r
+  return mpc_expectf(p, "'%c'", c);\r
+}\r
+\r
+mpc_parser_t *mpc_range(char s, char e) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_RANGE;\r
+  p->data.range.x = s;\r
+  p->data.range.y = e;\r
+  return mpc_expectf(p, "character between '%c' and '%c'", s, e);\r
+}\r
+\r
+mpc_parser_t *mpc_oneof(const char *s) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_ONEOF;\r
+  p->data.string.x = malloc(strlen(s) + 1);\r
+  strcpy(p->data.string.x, s);\r
+  return mpc_expectf(p, "one of '%s'", s);\r
+}\r
+\r
+mpc_parser_t *mpc_noneof(const char *s) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_NONEOF;\r
+  p->data.string.x = malloc(strlen(s) + 1);\r
+  strcpy(p->data.string.x, s);\r
+  return mpc_expectf(p, "one of '%s'", s);\r
+\r
+}\r
+\r
+mpc_parser_t *mpc_satisfy(int(*f)(char)) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_SATISFY;\r
+  p->data.satisfy.f = f;\r
+  return mpc_expectf(p, "character satisfying function %p", f);\r
+}\r
+\r
+mpc_parser_t *mpc_string(const char *s) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_STRING;\r
+  p->data.string.x = malloc(strlen(s) + 1);\r
+  strcpy(p->data.string.x, s);\r
+  return mpc_expectf(p, "\"%s\"", s);\r
+}\r
+\r
+/*\r
+** Core Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_APPLY;\r
+  p->data.apply.x = a;\r
+  p->data.apply.f = f;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_APPLY_TO;\r
+  p->data.apply_to.x = a;\r
+  p->data.apply_to.f = f;\r
+  p->data.apply_to.d = x;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_predictive(mpc_parser_t *a) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_PREDICT;\r
+  p->data.predict.x = a;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_NOT;\r
+  p->data.not.x = a;\r
+  p->data.not.dx = da;\r
+  p->data.not.lf = lf;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da) {\r
+  return mpc_not_lift(a, da, mpcf_ctor_null);\r
+}\r
+\r
+mpc_parser_t *mpc_maybe_lift(mpc_parser_t *a, mpc_ctor_t lf) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_MAYBE;\r
+  p->data.not.x = a;\r
+  p->data.not.lf = lf;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_maybe(mpc_parser_t *a) {\r
+  return mpc_maybe_lift(a, mpcf_ctor_null);\r
+}\r
+\r
+mpc_parser_t *mpc_many(mpc_fold_t f, mpc_parser_t *a) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_MANY;\r
+  p->data.repeat.x = a;\r
+  p->data.repeat.f = f;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_many1(mpc_fold_t f, mpc_parser_t *a) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_MANY1;\r
+  p->data.repeat.x = a;\r
+  p->data.repeat.f = f;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_count(int n, mpc_fold_t f, mpc_parser_t *a, mpc_dtor_t da) {\r
+  mpc_parser_t *p = mpc_undefined();\r
+  p->type = MPC_TYPE_COUNT;\r
+  p->data.repeat.n = n;\r
+  p->data.repeat.f = f;\r
+  p->data.repeat.x = a;\r
+  p->data.repeat.dx = da;\r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_or(int n, ...) {\r
+\r
+  int i;\r
+  va_list va;\r
+\r
+  mpc_parser_t *p = mpc_undefined();\r
+  \r
+  p->type = MPC_TYPE_OR;\r
+  p->data.or.n = n;\r
+  p->data.or.xs = malloc(sizeof(mpc_parser_t*) * n);\r
+  \r
+  va_start(va, n);  \r
+  for (i = 0; i < n; i++) {\r
+    p->data.or.xs[i] = va_arg(va, mpc_parser_t*);\r
+  }\r
+  va_end(va);\r
+  \r
+  return p;\r
+}\r
+\r
+mpc_parser_t *mpc_and(int n, mpc_fold_t f, ...) {\r
+\r
+  int i;\r
+  va_list va;\r
+\r
+  mpc_parser_t *p = mpc_undefined();\r
+  \r
+  p->type = MPC_TYPE_AND;\r
+  p->data.and.n = n;\r
+  p->data.and.f = f;\r
+  p->data.and.xs = malloc(sizeof(mpc_parser_t*) * n);\r
+  p->data.and.dxs = malloc(sizeof(mpc_dtor_t) * (n-1));\r
+\r
+  va_start(va, f);  \r
+  for (i = 0; i < n; i++) {\r
+    p->data.and.xs[i] = va_arg(va, mpc_parser_t*);\r
+  }\r
+  for (i = 0; i < (n-1); i++) {\r
+    p->data.and.dxs[i] = va_arg(va, mpc_dtor_t);\r
+  }  \r
+  va_end(va);\r
+  \r
+  return p;\r
+}\r
+\r
+/*\r
+** Common Parsers\r
+*/\r
+\r
+static int mpc_soi_anchor(char prev, char next) { return (prev == '\0'); }\r
+static int mpc_eoi_anchor(char prev, char next) { return (next == '\0'); }\r
+\r
+mpc_parser_t *mpc_soi(void) { return mpc_expect(mpc_anchor(mpc_soi_anchor), "start of input"); }\r
+mpc_parser_t *mpc_eoi(void) { return mpc_expect(mpc_anchor(mpc_eoi_anchor), "end of input"); }\r
+\r
+static int mpc_boundary_anchor(char prev, char next) {\r
+  char* word = "abcdefghijklmnopqrstuvwxyz"\r
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\r
+               "0123456789_";\r
+  if ( strchr(word, next) &&  prev == '\0') { return 1; }\r
+  if ( strchr(word, prev) &&  next == '\0') { return 1; }\r
+  if ( strchr(word, next) && !strchr(word, prev)) { return 1; }\r
+  if (!strchr(word, next) &&  strchr(word, prev)) { return 1; }\r
+  return 0;\r
+}\r
+\r
+mpc_parser_t *mpc_boundary(void) { return mpc_expect(mpc_anchor(mpc_boundary_anchor), "boundary"); }\r
+\r
+mpc_parser_t *mpc_whitespace(void) { return mpc_expect(mpc_oneof(" \f\n\r\t\v"), "whitespace"); }\r
+mpc_parser_t *mpc_whitespaces(void) { return mpc_expect(mpc_many(mpcf_strfold, mpc_whitespace()), "spaces"); }\r
+mpc_parser_t *mpc_blank(void) { return mpc_expect(mpc_apply(mpc_whitespaces(), mpcf_free), "whitespace"); }\r
+\r
+mpc_parser_t *mpc_newline(void) { return mpc_expect(mpc_char('\n'), "newline"); }\r
+mpc_parser_t *mpc_tab(void) { return mpc_expect(mpc_char('\t'), "tab"); }\r
+mpc_parser_t *mpc_escape(void) { return mpc_and(2, mpcf_strfold, mpc_char('\\'), mpc_any(), free); }\r
+\r
+mpc_parser_t *mpc_digit(void) { return mpc_expect(mpc_oneof("0123456789"), "digit"); }\r
+mpc_parser_t *mpc_hexdigit(void) { return mpc_expect(mpc_oneof("0123456789ABCDEFabcdef"), "hex digit"); }\r
+mpc_parser_t *mpc_octdigit(void) { return mpc_expect(mpc_oneof("01234567"), "oct digit"); }\r
+mpc_parser_t *mpc_digits(void) { return mpc_expect(mpc_many1(mpcf_strfold, mpc_digit()), "digits"); }\r
+mpc_parser_t *mpc_hexdigits(void) { return mpc_expect(mpc_many1(mpcf_strfold, mpc_hexdigit()), "hex digits"); }\r
+mpc_parser_t *mpc_octdigits(void) { return mpc_expect(mpc_many1(mpcf_strfold, mpc_octdigit()), "oct digits"); }\r
+\r
+mpc_parser_t *mpc_lower(void) { return mpc_expect(mpc_oneof("abcdefghijklmnopqrstuvwxyz"), "lowercase letter"); }\r
+mpc_parser_t *mpc_upper(void) { return mpc_expect(mpc_oneof("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), "uppercase letter"); }\r
+mpc_parser_t *mpc_alpha(void) { return mpc_expect(mpc_oneof("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), "letter"); }\r
+mpc_parser_t *mpc_underscore(void) { return mpc_expect(mpc_char('_'), "underscore"); }\r
+mpc_parser_t *mpc_alphanum(void) { return mpc_expect(mpc_or(3, mpc_alpha(), mpc_digit(), mpc_underscore()), "alphanumeric"); }\r
+\r
+mpc_parser_t *mpc_int(void) { return mpc_expect(mpc_apply(mpc_digits(), mpcf_int), "integer"); }\r
+mpc_parser_t *mpc_hex(void) { return mpc_expect(mpc_apply(mpc_hexdigits(), mpcf_hex), "hexadecimal"); }\r
+mpc_parser_t *mpc_oct(void) { return mpc_expect(mpc_apply(mpc_octdigits(), mpcf_oct), "octadecimal"); }\r
+mpc_parser_t *mpc_number(void) { return mpc_expect(mpc_or(3, mpc_int(), mpc_hex(), mpc_oct()), "number"); }\r
+\r
+mpc_parser_t *mpc_real(void) {\r
+\r
+  /* [+-]?\d+(\.\d+)?([eE][+-]?[0-9]+)? */\r
+  \r
+  mpc_parser_t *p0, *p1, *p2, *p30, *p31, *p32, *p3;\r
+  \r
+  p0 = mpc_maybe_lift(mpc_oneof("+-"), mpcf_ctor_str);\r
+  p1 = mpc_digits();\r
+  p2 = mpc_maybe_lift(mpc_and(2, mpcf_strfold, mpc_char('.'), mpc_digits(), free), mpcf_ctor_str);\r
+  p30 = mpc_oneof("eE");\r
+  p31 = mpc_maybe_lift(mpc_oneof("+-"), mpcf_ctor_str);\r
+  p32 = mpc_digits();\r
+  p3 = mpc_maybe_lift(mpc_and(3, mpcf_strfold, p30, p31, p32, free, free), mpcf_ctor_str);\r
+  \r
+  return mpc_expect(mpc_and(4, mpcf_strfold, p0, p1, p2, p3, free, free, free), "real");\r
+\r
+}\r
+\r
+mpc_parser_t *mpc_float(void) {\r
+  return mpc_expect(mpc_apply(mpc_real(), mpcf_float), "float");\r
+}\r
+\r
+mpc_parser_t *mpc_char_lit(void) {\r
+  return mpc_expect(mpc_between(mpc_or(2, mpc_escape(), mpc_any()), free, "'", "'"), "char");\r
+}\r
+\r
+mpc_parser_t *mpc_string_lit(void) {\r
+  mpc_parser_t *strchar = mpc_or(2, mpc_escape(), mpc_noneof("\""));\r
+  return mpc_expect(mpc_between(mpc_many(mpcf_strfold, strchar), free, "\"", "\""), "string");\r
+}\r
+\r
+mpc_parser_t *mpc_regex_lit(void) {  \r
+  mpc_parser_t *regexchar = mpc_or(2, mpc_escape(), mpc_noneof("/"));\r
+  return mpc_expect(mpc_between(mpc_many(mpcf_strfold, regexchar), free, "/", "/"), "regex");\r
+}\r
+\r
+mpc_parser_t *mpc_ident(void) {\r
+  mpc_parser_t *p0, *p1; \r
+  p0 = mpc_or(2, mpc_alpha(), mpc_underscore());\r
+  p1 = mpc_many(mpcf_strfold, mpc_alphanum()); \r
+  return mpc_and(2, mpcf_strfold, p0, p1, free);\r
+}\r
+\r
+/*\r
+** Useful Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_startwith(mpc_parser_t *a) { return mpc_and(2, mpcf_snd, mpc_soi(), a, mpcf_dtor_null); }\r
+mpc_parser_t *mpc_endwith(mpc_parser_t *a, mpc_dtor_t da) { return mpc_and(2, mpcf_fst, a, mpc_eoi(), da); }\r
+mpc_parser_t *mpc_whole(mpc_parser_t *a, mpc_dtor_t da) { return mpc_and(3, mpcf_snd, mpc_soi(), a, mpc_eoi(), mpcf_dtor_null, da); }\r
+\r
+mpc_parser_t *mpc_stripl(mpc_parser_t *a) { return mpc_and(2, mpcf_snd, mpc_blank(), a, mpcf_dtor_null); }\r
+mpc_parser_t *mpc_stripr(mpc_parser_t *a) { return mpc_and(2, mpcf_fst, a, mpc_blank(), mpcf_dtor_null); }\r
+mpc_parser_t *mpc_strip(mpc_parser_t *a) { return mpc_and(3, mpcf_snd, mpc_blank(), a, mpc_blank(), mpcf_dtor_null, mpcf_dtor_null); }\r
+mpc_parser_t *mpc_tok(mpc_parser_t *a) { return mpc_and(2, mpcf_fst, a, mpc_blank(), mpcf_dtor_null); }\r
+mpc_parser_t *mpc_sym(const char *s) { return mpc_tok(mpc_string(s)); }\r
+\r
+mpc_parser_t *mpc_total(mpc_parser_t *a, mpc_dtor_t da) { return mpc_whole(mpc_strip(a), da); }\r
+\r
+mpc_parser_t *mpc_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c) {\r
+  return mpc_and(3, mpcf_snd_free,\r
+    mpc_string(o), a, mpc_string(c),\r
+    free, ad);\r
+}\r
+\r
+mpc_parser_t *mpc_parens(mpc_parser_t *a, mpc_dtor_t ad)   { return mpc_between(a, ad, "(", ")"); }\r
+mpc_parser_t *mpc_braces(mpc_parser_t *a, mpc_dtor_t ad)   { return mpc_between(a, ad, "<", ">"); }\r
+mpc_parser_t *mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad) { return mpc_between(a, ad, "{", "}"); }\r
+mpc_parser_t *mpc_squares(mpc_parser_t *a, mpc_dtor_t ad)  { return mpc_between(a, ad, "[", "]"); }\r
+\r
+mpc_parser_t *mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c) {\r
+  return mpc_and(3, mpcf_snd_free,\r
+    mpc_sym(o), mpc_tok(a), mpc_sym(c),\r
+    free, ad);\r
+}\r
+\r
+mpc_parser_t *mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad)   { return mpc_tok_between(a, ad, "(", ")"); }\r
+mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad)   { return mpc_tok_between(a, ad, "<", ">"); }\r
+mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad) { return mpc_tok_between(a, ad, "{", "}"); }\r
+mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad)  { return mpc_tok_between(a, ad, "[", "]"); }\r
+\r
+/*\r
+** Regular Expression Parsers\r
+*/\r
+\r
+/*\r
+** So here is a cute bootstrapping.\r
+**\r
+** I'm using the previously defined\r
+** mpc constructs and functions to\r
+** parse the user regex string and\r
+** construct a parser from it.\r
+**\r
+** As it turns out lots of the standard\r
+** mpc functions look a lot like `fold`\r
+** functions and so can be used indirectly\r
+** by many of the parsing functions to build\r
+** a parser directly - as we are parsing.\r
+**\r
+** This is certainly something that\r
+** would be less elegant/interesting \r
+** in a two-phase parser which first\r
+** builds an AST and then traverses it\r
+** to generate the object.\r
+**\r
+** This whole thing acts as a great\r
+** case study for how trivial it can be\r
+** to write a great parser in a few\r
+** lines of code using mpc.\r
+*/\r
+\r
+/*\r
+**\r
+**  ### Regular Expression Grammar\r
+**\r
+**      <regex> : <term> | (<term> "|" <regex>)\r
+**     \r
+**      <term> : <factor>*\r
+**\r
+**      <factor> : <base>\r
+**               | <base> "*"\r
+**               | <base> "+"\r
+**               | <base> "?"\r
+**               | <base> "{" <digits> "}"\r
+**           \r
+**      <base> : <char>\r
+**             | "\" <char>\r
+**             | "(" <regex> ")"\r
+**             | "[" <range> "]"\r
+*/\r
+\r
+static mpc_val_t *mpcf_re_or(int n, mpc_val_t **xs) {\r
+  if (xs[1] == NULL) { return xs[0]; }\r
+  else { return mpc_or(2, xs[0], xs[1]); }\r
+}\r
+\r
+static mpc_val_t *mpcf_re_and(int n, mpc_val_t **xs) {\r
+  int i;\r
+  mpc_parser_t *p = mpc_lift(mpcf_ctor_str);\r
+  for (i = 0; i < n; i++) {\r
+    p = mpc_and(2, mpcf_strfold, p, xs[i], free);\r
+  }\r
+  return p;\r
+}\r
+\r
+static mpc_val_t *mpcf_re_repeat(int n, mpc_val_t **xs) {\r
+  \r
+  int num;\r
+  if (xs[1] == NULL) { return xs[0]; }\r
+  if (strcmp(xs[1], "*") == 0) { free(xs[1]); return mpc_many(mpcf_strfold, xs[0]); }\r
+  if (strcmp(xs[1], "+") == 0) { free(xs[1]); return mpc_many1(mpcf_strfold, xs[0]); }\r
+  if (strcmp(xs[1], "?") == 0) { free(xs[1]); return mpc_maybe_lift(xs[0], mpcf_ctor_str); }\r
+  num = *(int*)xs[1];\r
+  free(xs[1]);\r
+  \r
+  return mpc_count(num, mpcf_strfold, xs[0], free);\r
+}\r
+\r
+static mpc_parser_t *mpc_re_escape_char(char c) {\r
+  switch (c) {\r
+    case 'a': return mpc_char('\a');\r
+    case 'f': return mpc_char('\f');\r
+    case 'n': return mpc_char('\n');\r
+    case 'r': return mpc_char('\r');\r
+    case 't': return mpc_char('\t');\r
+    case 'v': return mpc_char('\v');\r
+    case 'b': return mpc_and(2, mpcf_snd, mpc_boundary(), mpc_lift(mpcf_ctor_str), free);\r
+    case 'B': return mpc_not_lift(mpc_boundary(), free, mpcf_ctor_str);\r
+    case 'A': return mpc_and(2, mpcf_snd, mpc_soi(), mpc_lift(mpcf_ctor_str), free);\r
+    case 'Z': return mpc_and(2, mpcf_snd, mpc_eoi(), mpc_lift(mpcf_ctor_str), free);\r
+    case 'd': return mpc_digit();\r
+    case 'D': return mpc_not_lift(mpc_digit(), free, mpcf_ctor_str);\r
+    case 's': return mpc_whitespace();\r
+    case 'S': return mpc_not_lift(mpc_whitespace(), free, mpcf_ctor_str);\r
+    case 'w': return mpc_alphanum();\r
+    case 'W': return mpc_not_lift(mpc_alphanum(), free, mpcf_ctor_str);\r
+    default: return NULL;\r
+  }\r
+}\r
+\r
+static mpc_val_t *mpcf_re_escape(mpc_val_t *x) {\r
+  \r
+  char *s = x;\r
+  mpc_parser_t *p;\r
+  \r
+  /* Regex Special Characters */\r
+  if (s[0] == '.') { free(s); return mpc_any(); }\r
+  if (s[0] == '^') { free(s); return mpc_and(2, mpcf_snd, mpc_soi(), mpc_lift(mpcf_ctor_str), free); }\r
+  if (s[0] == '$') { free(s); return mpc_and(2, mpcf_snd, mpc_eoi(), mpc_lift(mpcf_ctor_str), free); }\r
+  \r
+  /* Regex Escape */\r
+  if (s[0] == '\\') {\r
+    p = mpc_re_escape_char(s[1]);\r
+    p = (p == NULL) ? mpc_char(s[1]) : p;\r
+    free(s);\r
+    return p;\r
+  }\r
+  \r
+  /* Regex Standard */\r
+  p = mpc_char(s[0]);\r
+  free(s);\r
+  return p;\r
+}\r
+\r
+static char *mpc_re_range_escape_char(char c) {\r
+  switch (c) {\r
+    case '-': return "-";\r
+    case 'a': return "\a";\r
+    case 'f': return "\f";\r
+    case 'n': return "\n";\r
+    case 'r': return "\r";\r
+    case 't': return "\t";\r
+    case 'v': return "\v";\r
+    case 'b': return "\b";\r
+    case 'd': return "0123456789";\r
+    case 's': return " \f\n\r\t\v";\r
+    case 'w': return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";\r
+    default: return NULL;\r
+  }\r
+}\r
+\r
+static mpc_val_t *mpcf_re_range(mpc_val_t *x) {\r
+  \r
+  mpc_parser_t *out;\r
+  char *range = calloc(1,1);\r
+  char *tmp = NULL;\r
+  char *s = x;\r
+  char start, end;\r
+  int i, j;\r
+  int comp = 0;\r
+  \r
+  if (s[0] == '\0') { free(x); return mpc_fail("Invalid Regex Range Expression"); } \r
+  if (s[0] == '^' && \r
+      s[1] == '\0') { free(x); return mpc_fail("Invalid Regex Range Expression"); }\r
+  \r
+  if (s[0] == '^') { comp = 1;}\r
+  \r
+  for (i = comp; i < strlen(s); i++){\r
+    \r
+    /* Regex Range Escape */\r
+    if (s[i] == '\\') {\r
+      tmp = mpc_re_range_escape_char(s[i+1]);\r
+      if (tmp != NULL) {\r
+        range = realloc(range, strlen(range) + strlen(tmp) + 1);\r
+        strcat(range, tmp);\r
+      } else {\r
+        range = realloc(range, strlen(range) + 1 + 1);\r
+        range[strlen(range) + 1] = '\0';\r
+        range[strlen(range) + 0] = s[i+1];      \r
+      }\r
+      i++;\r
+    }\r
+    \r
+    /* Regex Range...Range */\r
+    else if (s[i] == '-') {\r
+      if (s[i+1] == '\0' || i == 0) {\r
+          range = realloc(range, strlen(range) + strlen("-") + 1);\r
+          strcat(range, "-");\r
+      } else {\r
+        start = s[i-1]+1;\r
+        end = s[i+1]-1;\r
+        for (j = start; j <= end; j++) {\r
+          range = realloc(range, strlen(range) + 1 + 1);\r
+          range[strlen(range) + 1] = '\0';\r
+          range[strlen(range) + 0] = j;\r
+        }        \r
+      }\r
+    }\r
+    \r
+    /* Regex Range Normal */\r
+    else {\r
+      range = realloc(range, strlen(range) + 1 + 1);\r
+      range[strlen(range) + 1] = '\0';\r
+      range[strlen(range) + 0] = s[i];\r
+    }\r
+  \r
+  }\r
+  \r
+  out = comp ? mpc_noneof(range) : mpc_oneof(range);\r
+  \r
+  free(x);\r
+  free(range);\r
+  \r
+  return out;\r
+}\r
+\r
+mpc_parser_t *mpc_re(const char *re) {\r
+  \r
+  char *err_msg;\r
+  mpc_parser_t *err_out;\r
+  mpc_result_t r;\r
+  mpc_parser_t *Regex, *Term, *Factor, *Base, *Range, *RegexEnclose; \r
+  \r
+  Regex  = mpc_new("regex");\r
+  Term   = mpc_new("term");\r
+  Factor = mpc_new("factor");\r
+  Base   = mpc_new("base");\r
+  Range  = mpc_new("range");\r
+  \r
+  mpc_define(Regex, mpc_and(2, mpcf_re_or,\r
+    Term, \r
+    mpc_maybe(mpc_and(2, mpcf_snd_free, mpc_char('|'), Regex, free)),\r
+    (mpc_dtor_t)mpc_delete\r
+  ));\r
+  \r
+  mpc_define(Term, mpc_many(mpcf_re_and, Factor));\r
+  \r
+  mpc_define(Factor, mpc_and(2, mpcf_re_repeat,\r
+    Base,\r
+    mpc_or(5,\r
+      mpc_char('*'), mpc_char('+'), mpc_char('?'),\r
+      mpc_brackets(mpc_int(), free),\r
+      mpc_pass()),\r
+    (mpc_dtor_t)mpc_delete\r
+  ));\r
+  \r
+  mpc_define(Base, mpc_or(4,\r
+    mpc_parens(Regex, (mpc_dtor_t)mpc_delete),\r
+    mpc_squares(Range, (mpc_dtor_t)mpc_delete),\r
+    mpc_apply(mpc_escape(), mpcf_re_escape),\r
+    mpc_apply(mpc_noneof(")|"), mpcf_re_escape)\r
+  ));\r
+  \r
+  mpc_define(Range, mpc_apply(\r
+    mpc_many(mpcf_strfold, mpc_or(2, mpc_escape(), mpc_noneof("]"))),\r
+    mpcf_re_range\r
+  ));\r
+  \r
+  RegexEnclose = mpc_whole(mpc_predictive(Regex), (mpc_dtor_t)mpc_delete);\r
+  \r
+  if(!mpc_parse("<mpc_re_compiler>", re, RegexEnclose, &r)) {\r
+    err_msg = mpc_err_string(r.error);\r
+    err_out = mpc_failf("Invalid Regex: %s", err_msg);\r
+    mpc_err_delete(r.error);  \r
+    free(err_msg);\r
+    r.output = err_out;\r
+  }\r
+  \r
+  mpc_delete(RegexEnclose);\r
+  mpc_cleanup(5, Regex, Term, Factor, Base, Range);\r
+  \r
+  return r.output;\r
+  \r
+}\r
+\r
+/*\r
+** Common Fold Functions\r
+*/\r
+\r
+void mpcf_dtor_null(mpc_val_t *x) { return; }\r
+\r
+mpc_val_t *mpcf_ctor_null(void) { return NULL; }\r
+mpc_val_t *mpcf_ctor_str(void) { return calloc(1, 1); }\r
+mpc_val_t *mpcf_free(mpc_val_t *x) { free(x); return NULL; }\r
+\r
+mpc_val_t *mpcf_int(mpc_val_t *x) {\r
+  int *y = malloc(sizeof(int));\r
+  *y = strtol(x, NULL, 10);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_hex(mpc_val_t *x) {\r
+  int *y = malloc(sizeof(int));\r
+  *y = strtol(x, NULL, 16);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_oct(mpc_val_t *x) {\r
+  int *y = malloc(sizeof(int));\r
+  *y = strtol(x, NULL, 8);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_float(mpc_val_t *x) {\r
+  float* y = malloc(sizeof(float));\r
+  *y = strtod(x, NULL);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+static char mpc_escape_input_c[]  = {\r
+  '\a', '\b', '\f', '\n', '\r',\r
+  '\t', '\v', '\\', '\'', '\"', '\0'};\r
+    \r
+static char *mpc_escape_output_c[] = {\r
+  "\\a", "\\b", "\\f", "\\n", "\\r", "\\t", \r
+  "\\v", "\\\\", "\\'", "\\\"", "\\0", NULL};\r
+\r
+static char mpc_escape_input_raw_re[] = { '/' };\r
+static char *mpc_escape_output_raw_re[] = { "\\/", NULL };\r
+\r
+static char mpc_escape_input_raw_cstr[] = { '"' };\r
+static char *mpc_escape_output_raw_cstr[] = { "\\\"", NULL };\r
+\r
+static char mpc_escape_input_raw_cchar[] = { '\'' };\r
+static char *mpc_escape_output_raw_cchar[] = { "\\'", NULL };\r
+\r
+static mpc_val_t *mpcf_escape_new(mpc_val_t *x, char *input, char **output) {\r
+  \r
+  int i;\r
+  int found;\r
+  char *s = x;\r
+  char *y = calloc(1, 1);\r
+  char buff[2];\r
+  \r
+  while (*s) {\r
+    \r
+    i = 0;\r
+    found = 0;\r
+\r
+    while (output[i]) {\r
+      if (*s == input[i]) {\r
+        y = realloc(y, strlen(y) + strlen(output[i]) + 1);\r
+        strcat(y, output[i]);\r
+        found = 1;\r
+        break;\r
+      }\r
+      i++;\r
+    }\r
+    \r
+    if (!found) {\r
+      y = realloc(y, strlen(y) + 2);\r
+      buff[0] = *s; buff[1] = '\0';\r
+      strcat(y, buff);\r
+    }\r
+    \r
+    s++;\r
+  }\r
+  \r
+  \r
+  return y;\r
+}\r
+\r
+static mpc_val_t *mpcf_unescape_new(mpc_val_t *x, char *input, char **output) {\r
+  \r
+  int i;\r
+  int found = 0;\r
+  char *s = x;\r
+  char *y = calloc(1, 1);\r
+  char buff[2];\r
+\r
+  while (*s) {\r
+    \r
+    i = 0;\r
+    found = 0;\r
+    \r
+    while (output[i]) {\r
+      if ((*(s+0)) == output[i][0] &&\r
+          (*(s+1)) == output[i][1]) {\r
+        y = realloc(y, strlen(y) + 2);\r
+        buff[0] = input[i]; buff[1] = '\0';\r
+        strcat(y, buff);\r
+        found = 1;\r
+        s++;\r
+        break;\r
+      }\r
+      i++;\r
+    }\r
+      \r
+    if (!found) {\r
+      y = realloc(y, strlen(y) + 2);\r
+      buff[0] = *s; buff[1] = '\0';\r
+      strcat(y, buff);\r
+    }\r
+    \r
+    if (*s == '\0') { break; }\r
+    else { s++; }\r
+  }\r
+  \r
+  return y;\r
+  \r
+}\r
+\r
+mpc_val_t *mpcf_escape(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_escape_new(x, mpc_escape_input_c, mpc_escape_output_c);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_unescape(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_unescape_new(x, mpc_escape_input_c, mpc_escape_output_c);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_unescape_regex(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_unescape_new(x, mpc_escape_input_raw_re, mpc_escape_output_raw_re);\r
+  free(x);\r
+  return y;  \r
+}\r
+\r
+mpc_val_t *mpcf_escape_string_raw(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_escape_new(x, mpc_escape_input_raw_cstr, mpc_escape_output_raw_cstr);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_unescape_new(x, mpc_escape_input_raw_cstr, mpc_escape_output_raw_cstr);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_escape_char_raw(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_escape_new(x, mpc_escape_input_raw_cchar, mpc_escape_output_raw_cchar);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x) {\r
+  mpc_val_t *y = mpcf_unescape_new(x, mpc_escape_input_raw_cchar, mpc_escape_output_raw_cchar);\r
+  free(x);\r
+  return y;\r
+}\r
+\r
+mpc_val_t *mpcf_null(int n, mpc_val_t** xs) { return NULL; }\r
+mpc_val_t *mpcf_fst(int n, mpc_val_t **xs) { return xs[0]; }\r
+mpc_val_t *mpcf_snd(int n, mpc_val_t **xs) { return xs[1]; }\r
+mpc_val_t *mpcf_trd(int n, mpc_val_t **xs) { return xs[2]; }\r
+\r
+static mpc_val_t *mpcf_nth_free(int n, mpc_val_t **xs, int x) {\r
+  int i;\r
+  for (i = 0; i < n; i++) {\r
+    if (i != x) { free(xs[i]); }\r
+  }\r
+  return xs[x];\r
+}\r
\r
+mpc_val_t *mpcf_fst_free(int n, mpc_val_t **xs) { return mpcf_nth_free(n, xs, 0); }\r
+mpc_val_t *mpcf_snd_free(int n, mpc_val_t **xs) { return mpcf_nth_free(n, xs, 1); }\r
+mpc_val_t *mpcf_trd_free(int n, mpc_val_t **xs) { return mpcf_nth_free(n, xs, 2); }\r
+\r
+mpc_val_t *mpcf_strfold(int n, mpc_val_t **xs) {\r
+  char *x = calloc(1, 1);\r
+  int i;\r
+  for (i = 0; i < n; i++) {\r
+    x = realloc(x, strlen(x) + strlen(xs[i]) + 1);\r
+    strcat(x, xs[i]);\r
+    free(xs[i]);\r
+  }\r
+  return x;\r
+}\r
+\r
+mpc_val_t *mpcf_maths(int n, mpc_val_t **xs) {\r
+  \r
+  int **vs = (int**)xs;\r
+    \r
+  if (strcmp(xs[1], "*") == 0) { *vs[0] *= *vs[2]; }\r
+  if (strcmp(xs[1], "/") == 0) { *vs[0] /= *vs[2]; }\r
+  if (strcmp(xs[1], "%") == 0) { *vs[0] %= *vs[2]; }\r
+  if (strcmp(xs[1], "+") == 0) { *vs[0] += *vs[2]; }\r
+  if (strcmp(xs[1], "-") == 0) { *vs[0] -= *vs[2]; }\r
+  \r
+  free(xs[1]); free(xs[2]);\r
+  \r
+  return xs[0];\r
+}\r
+\r
+/*\r
+** Printing\r
+*/\r
+\r
+static void mpc_print_unretained(mpc_parser_t *p, int force) {\r
+  \r
+  /* TODO: Print Everything Escaped */\r
+  \r
+  int i;\r
+  char *s, *e;\r
+  char buff[2];\r
+  \r
+  if (p->retained && !force) {;\r
+    if (p->name) { printf("<%s>", p->name); }\r
+    else { printf("<anon>"); }\r
+    return;\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_UNDEFINED) { printf("<?>"); }\r
+  if (p->type == MPC_TYPE_PASS)   { printf("<:>"); }\r
+  if (p->type == MPC_TYPE_FAIL)   { printf("<!>"); }\r
+  if (p->type == MPC_TYPE_LIFT)   { printf("<#>"); }\r
+  if (p->type == MPC_TYPE_STATE)  { printf("<S>"); }\r
+  if (p->type == MPC_TYPE_ANCHOR) { printf("<@>"); }\r
+  if (p->type == MPC_TYPE_EXPECT) {\r
+    printf("%s", p->data.expect.m);\r
+    /*mpc_print_unretained(p->data.expect.x, 0);*/\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_ANY) { printf("<.>"); }\r
+  if (p->type == MPC_TYPE_SATISFY) { printf("<f>"); }\r
+\r
+  if (p->type == MPC_TYPE_SINGLE) {\r
+    buff[0] = p->data.single.x; buff[1] = '\0';\r
+    s = mpcf_escape_new(\r
+      buff,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    printf("'%s'", s);\r
+    free(s);\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_RANGE) {\r
+    buff[0] = p->data.range.x; buff[1] = '\0';\r
+    s = mpcf_escape_new(\r
+      buff,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    buff[0] = p->data.range.y; buff[1] = '\0';\r
+    e = mpcf_escape_new(\r
+      buff,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    printf("[%s-%s]", s, e);\r
+    free(s);\r
+    free(e);\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_ONEOF) {\r
+    s = mpcf_escape_new(\r
+      p->data.string.x,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    printf("[%s]", s);\r
+    free(s);\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_NONEOF) {\r
+    s = mpcf_escape_new(\r
+      p->data.string.x,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    printf("[^%s]", s);\r
+    free(s);\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_STRING) {\r
+    s = mpcf_escape_new(\r
+      p->data.string.x,\r
+      mpc_escape_input_c,\r
+      mpc_escape_output_c);\r
+    printf("\"%s\"", s);\r
+    free(s);\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_APPLY)    { mpc_print_unretained(p->data.apply.x, 0); }\r
+  if (p->type == MPC_TYPE_APPLY_TO) { mpc_print_unretained(p->data.apply_to.x, 0); }\r
+  if (p->type == MPC_TYPE_PREDICT)  { mpc_print_unretained(p->data.predict.x, 0); }\r
+\r
+  if (p->type == MPC_TYPE_NOT)   { mpc_print_unretained(p->data.not.x, 0); printf("!"); }\r
+  if (p->type == MPC_TYPE_MAYBE) { mpc_print_unretained(p->data.not.x, 0); printf("?"); }\r
+\r
+  if (p->type == MPC_TYPE_MANY)  { mpc_print_unretained(p->data.repeat.x, 0); printf("*"); }\r
+  if (p->type == MPC_TYPE_MANY1) { mpc_print_unretained(p->data.repeat.x, 0); printf("+"); }\r
+  if (p->type == MPC_TYPE_COUNT) { mpc_print_unretained(p->data.repeat.x, 0); printf("{%i}", p->data.repeat.n); }\r
+  \r
+  if (p->type == MPC_TYPE_OR) {\r
+    printf("(");\r
+    for(i = 0; i < p->data.or.n-1; i++) {\r
+      mpc_print_unretained(p->data.or.xs[i], 0);\r
+      printf(" | ");\r
+    }\r
+    mpc_print_unretained(p->data.or.xs[p->data.or.n-1], 0);\r
+    printf(")");\r
+  }\r
+  \r
+  if (p->type == MPC_TYPE_AND) {\r
+    printf("(");\r
+    for(i = 0; i < p->data.and.n-1; i++) {\r
+      mpc_print_unretained(p->data.and.xs[i], 0);\r
+      printf(" ");\r
+    }\r
+    mpc_print_unretained(p->data.and.xs[p->data.and.n-1], 0);\r
+    printf(")");\r
+  }\r
+  \r
+}\r
+\r
+void mpc_print(mpc_parser_t *p) {\r
+  mpc_print_unretained(p, 1);\r
+  printf("\n");\r
+}\r
+\r
+/*\r
+** Testing\r
+*/\r
+\r
+/*\r
+** These functions are slightly unwieldy and\r
+** also the whole of the testing suite for mpc\r
+** mpc is pretty shaky.\r
+**\r
+** It could do with a lot more tests and more\r
+** precision. Currently I am only really testing\r
+** changes off of the examples.\r
+**\r
+*/\r
+\r
+int mpc_test_fail(mpc_parser_t *p, const char *s, void *d,\r
+  int(*tester)(void*, void*),\r
+  mpc_dtor_t destructor,\r
+  void(*printer)(void*)) {\r
+\r
+  mpc_result_t r;  \r
+  if (mpc_parse("<test>", s, p, &r)) {\r
+\r
+    if (tester(r.output, d)) {\r
+      destructor(r.output);\r
+      return 0;\r
+    } else {\r
+      destructor(r.output);\r
+      return 1;\r
+    }\r
+  \r
+  } else {\r
+    mpc_err_delete(r.error);\r
+    return 1;\r
+  }\r
+  \r
+}\r
+\r
+int mpc_test_pass(mpc_parser_t *p, const char *s, void *d,\r
+  int(*tester)(void*, void*), \r
+  mpc_dtor_t destructor, \r
+  void(*printer)(void*)) {\r
+\r
+  mpc_result_t r;  \r
+  if (mpc_parse("<test>", s, p, &r)) {\r
+    \r
+    if (tester(r.output, d)) {\r
+      destructor(r.output);\r
+      return 1;\r
+    } else {\r
+      printf("Got "); printer(r.output); printf("\n");\r
+      printf("Expected "); printer(d); printf("\n");\r
+      destructor(r.output);\r
+      return 0;\r
+    }\r
+    \r
+  } else {    \r
+    mpc_err_print(r.error);\r
+    mpc_err_delete(r.error);\r
+    return 0;\r
+    \r
+  }\r
+  \r
+}\r
+\r
+\r
+/*\r
+** AST\r
+*/\r
+\r
+void mpc_ast_delete(mpc_ast_t *a) {\r
+  \r
+  int i;\r
+  \r
+  if (a == NULL) { return; }\r
+  for (i = 0; i < a->children_num; i++) {\r
+    mpc_ast_delete(a->children[i]);\r
+  }\r
+  \r
+  free(a->children);\r
+  free(a->tag);\r
+  free(a->contents);\r
+  free(a);\r
+  \r
+}\r
+\r
+static void mpc_ast_delete_no_children(mpc_ast_t *a) {\r
+  free(a->children);\r
+  free(a->tag);\r
+  free(a->contents);\r
+  free(a);\r
+}\r
+\r
+mpc_ast_t *mpc_ast_new(const char *tag, const char *contents) {\r
+  \r
+  mpc_ast_t *a = malloc(sizeof(mpc_ast_t));\r
+  \r
+  a->tag = malloc(strlen(tag) + 1);\r
+  strcpy(a->tag, tag);\r
+  \r
+  a->contents = malloc(strlen(contents) + 1);\r
+  strcpy(a->contents, contents);\r
+  \r
+  a->state = mpc_state_new();\r
+  \r
+  a->children_num = 0;\r
+  a->children = NULL;\r
+  return a;\r
+  \r
+}\r
+\r
+mpc_ast_t *mpc_ast_build(int n, const char *tag, ...) {\r
+  \r
+  mpc_ast_t *a = mpc_ast_new(tag, "");\r
+  \r
+  int i;\r
+  va_list va;\r
+  va_start(va, tag);\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    mpc_ast_add_child(a, va_arg(va, mpc_ast_t*));\r
+  }\r
+  \r
+  va_end(va);\r
+  \r
+  return a;\r
+  \r
+}\r
+\r
+mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a) {\r
+\r
+  mpc_ast_t *r;\r
+\r
+  if (a == NULL) { return a; }\r
+  if (a->children_num == 0) { return a; }\r
+  if (a->children_num == 1) { return a; }\r
+\r
+  r = mpc_ast_new(">", "");\r
+  mpc_ast_add_child(r, a);\r
+  return r;\r
+}\r
+\r
+int mpc_ast_eq(mpc_ast_t *a, mpc_ast_t *b) {\r
+  \r
+  int i;\r
+\r
+  if (strcmp(a->tag, b->tag) != 0) { return 0; }\r
+  if (strcmp(a->contents, b->contents) != 0) { return 0; }\r
+  if (a->children_num != b->children_num) { return 0; }\r
+  \r
+  for (i = 0; i < a->children_num; i++) {\r
+    if (!mpc_ast_eq(a->children[i], b->children[i])) { return 0; }\r
+  }\r
+  \r
+  return 1;\r
+}\r
+\r
+mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a) {\r
+  r->children_num++;\r
+  r->children = realloc(r->children, sizeof(mpc_ast_t*) * r->children_num);\r
+  r->children[r->children_num-1] = a;\r
+  return r;\r
+}\r
+\r
+mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t) {\r
+  if (a == NULL) { return a; }\r
+  a->tag = realloc(a->tag, strlen(t) + 1 + strlen(a->tag) + 1);\r
+  memmove(a->tag + strlen(t) + 1, a->tag, strlen(a->tag)+1);\r
+  memmove(a->tag, t, strlen(t));\r
+  memmove(a->tag + strlen(t), "|", 1);\r
+  return a;\r
+}\r
+\r
+mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t) {\r
+  a->tag = realloc(a->tag, strlen(t) + 1);\r
+  strcpy(a->tag, t);\r
+  return a;\r
+}\r
+\r
+mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s) {\r
+  if (a == NULL) { return a; }\r
+  a->state = s;\r
+  return a;\r
+}\r
+\r
+static void mpc_ast_print_depth(mpc_ast_t *a, int d, FILE *fp) {\r
+  \r
+  int i;\r
+  for (i = 0; i < d; i++) { fprintf(fp, "  "); }\r
+  \r
+  if (strlen(a->contents)) {\r
+    fprintf(fp, "%s:%i:%i '%s'\n", a->tag, a->state.row+1, a->state.col+1, a->contents);\r
+  } else {\r
+    fprintf(fp, "%s \n", a->tag);\r
+  }\r
+  \r
+  for (i = 0; i < a->children_num; i++) {\r
+    mpc_ast_print_depth(a->children[i], d+1, fp);\r
+  }\r
+  \r
+}\r
+\r
+void mpc_ast_print(mpc_ast_t *a) {\r
+  mpc_ast_print_depth(a, 0, stdout);\r
+}\r
+\r
+void mpc_ast_print_to(mpc_ast_t *a, FILE *fp) {\r
+  mpc_ast_print_depth(a, 0, fp);\r
+}\r
+\r
+mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) {\r
+  \r
+  int i, j;\r
+  mpc_ast_t** as = (mpc_ast_t**)xs;\r
+  mpc_ast_t *r;\r
+  \r
+  if (n == 0) { return NULL; }\r
+  if (n == 1) { return xs[0]; }\r
+  if (n == 2 && xs[1] == NULL) { return xs[0]; }\r
+  if (n == 2 && xs[0] == NULL) { return xs[1]; }\r
+  \r
+  r = mpc_ast_new(">", "");\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    \r
+    if (as[i] == NULL) { continue; }\r
+    \r
+    if (as[i] && as[i]->children_num > 0) {\r
+      \r
+      for (j = 0; j < as[i]->children_num; j++) {\r
+        mpc_ast_add_child(r, as[i]->children[j]);\r
+      }\r
+      \r
+      mpc_ast_delete_no_children(as[i]);\r
+      \r
+    } else if (as[i] && as[i]->children_num == 0) {\r
+      mpc_ast_add_child(r, as[i]);\r
+    }\r
+  \r
+  }\r
+  \r
+  if (r->children_num) {\r
+    r->state = r->children[0]->state;\r
+  }\r
+  \r
+  return r;\r
+}\r
+\r
+mpc_val_t *mpcf_str_ast(mpc_val_t *c) {\r
+  mpc_ast_t *a = mpc_ast_new("", c);\r
+  free(c);\r
+  return a;\r
+}\r
+\r
+mpc_val_t *mpcf_state_ast(int n, mpc_val_t **xs) {\r
+  mpc_state_t *s = ((mpc_state_t**)xs)[0];\r
+  mpc_ast_t *a = ((mpc_ast_t**)xs)[1];\r
+  a = mpc_ast_state(a, *s);\r
+  free(s);\r
+  return a;\r
+}\r
+\r
+mpc_parser_t *mpca_state(mpc_parser_t *a) {\r
+  return mpc_and(2, mpcf_state_ast, mpc_state(), a, free);\r
+}\r
+\r
+mpc_parser_t *mpca_tag(mpc_parser_t *a, const char *t) {\r
+  return mpc_apply_to(a, (mpc_apply_to_t)mpc_ast_tag, (void*)t);\r
+}\r
+\r
+mpc_parser_t *mpca_add_tag(mpc_parser_t *a, const char *t) {\r
+  return mpc_apply_to(a, (mpc_apply_to_t)mpc_ast_add_tag, (void*)t);\r
+}\r
+\r
+mpc_parser_t *mpca_root(mpc_parser_t *a) {\r
+  return mpc_apply(a, (mpc_apply_t)mpc_ast_add_root);\r
+}\r
+\r
+mpc_parser_t *mpca_not(mpc_parser_t *a) { return mpc_not(a, (mpc_dtor_t)mpc_ast_delete); }\r
+mpc_parser_t *mpca_maybe(mpc_parser_t *a) { return mpc_maybe(a); }\r
+mpc_parser_t *mpca_many(mpc_parser_t *a) { return mpc_many(mpcf_fold_ast, a); }\r
+mpc_parser_t *mpca_many1(mpc_parser_t *a) { return mpc_many1(mpcf_fold_ast, a); }\r
+mpc_parser_t *mpca_count(int n, mpc_parser_t *a) { return mpc_count(n, mpcf_fold_ast, a, (mpc_dtor_t)mpc_ast_delete); }\r
+\r
+mpc_parser_t *mpca_or(int n, ...) {\r
+\r
+  int i;\r
+  va_list va;\r
+\r
+  mpc_parser_t *p = mpc_undefined();\r
+  \r
+  p->type = MPC_TYPE_OR;\r
+  p->data.or.n = n;\r
+  p->data.or.xs = malloc(sizeof(mpc_parser_t*) * n);\r
+  \r
+  va_start(va, n);  \r
+  for (i = 0; i < n; i++) {\r
+    p->data.or.xs[i] = va_arg(va, mpc_parser_t*);\r
+  }\r
+  va_end(va);\r
+  \r
+  return p;\r
+  \r
+}\r
+\r
+mpc_parser_t *mpca_and(int n, ...) {\r
+  \r
+  int i;\r
+  va_list va;\r
+  \r
+  mpc_parser_t *p = mpc_undefined();\r
+  \r
+  p->type = MPC_TYPE_AND;\r
+  p->data.and.n = n;\r
+  p->data.and.f = mpcf_fold_ast;\r
+  p->data.and.xs = malloc(sizeof(mpc_parser_t*) * n);\r
+  p->data.and.dxs = malloc(sizeof(mpc_dtor_t) * (n-1));\r
+  \r
+  va_start(va, n);\r
+  for (i = 0; i < n; i++) {\r
+    p->data.and.xs[i] = va_arg(va, mpc_parser_t*);\r
+  }\r
+  for (i = 0; i < (n-1); i++) {\r
+    p->data.and.dxs[i] = (mpc_dtor_t)mpc_ast_delete;\r
+  }    \r
+  va_end(va);\r
+  \r
+  return p;  \r
+}\r
+\r
+mpc_parser_t *mpca_total(mpc_parser_t *a) { return mpc_total(a, (mpc_dtor_t)mpc_ast_delete); }\r
+\r
+/*\r
+** Grammar Parser\r
+*/\r
+\r
+/*\r
+** This is another interesting bootstrapping.\r
+**\r
+** Having a general purpose AST type allows\r
+** users to specify the grammar alone and\r
+** let all fold rules be automatically taken\r
+** care of by existing functions.\r
+**\r
+** You don't get to control the type spat\r
+** out but this means you can make a nice\r
+** parser to take in some grammar in nice\r
+** syntax and spit out a parser that works.\r
+**\r
+** The grammar for this looks surprisingly\r
+** like regex but the main difference is that\r
+** it is now whitespace insensitive and the\r
+** base type takes literals of some form.\r
+*/\r
+\r
+/*\r
+**\r
+**  ### Grammar Grammar\r
+**\r
+**      <grammar> : (<term> "|" <grammar>) | <term>\r
+**     \r
+**      <term> : <factor>*\r
+**\r
+**      <factor> : <base>\r
+**               | <base> "*"\r
+**               | <base> "+"\r
+**               | <base> "?"\r
+**               | <base> "{" <digits> "}"\r
+**           \r
+**      <base> : "<" (<digits> | <ident>) ">"\r
+**             | <string_lit>\r
+**             | <char_lit>\r
+**             | <regex_lit>\r
+**             | "(" <grammar> ")"\r
+*/\r
+\r
+typedef struct {\r
+  va_list *va;\r
+  int parsers_num;\r
+  mpc_parser_t **parsers;\r
+  int flags;\r
+} mpca_grammar_st_t;\r
+\r
+static mpc_val_t *mpcaf_grammar_or(int n, mpc_val_t **xs) {\r
+  if (xs[1] == NULL) { return xs[0]; }\r
+  else { return mpca_or(2, xs[0], xs[1]); }\r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_and(int n, mpc_val_t **xs) {\r
+  int i;\r
+  mpc_parser_t *p = mpc_pass();  \r
+  for (i = 0; i < n; i++) {\r
+    if (xs[i] != NULL) { p = mpca_and(2, p, xs[i]); }\r
+  }\r
+  return p;\r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_repeat(int n, mpc_val_t **xs) {\r
+  \r
+  int num;\r
+  if (xs[1] == NULL) { return xs[0]; }  \r
+  if (strcmp(xs[1], "*") == 0) { free(xs[1]); return mpca_many(xs[0]); }\r
+  if (strcmp(xs[1], "+") == 0) { free(xs[1]); return mpca_many1(xs[0]); }\r
+  if (strcmp(xs[1], "?") == 0) { free(xs[1]); return mpca_maybe(xs[0]); }\r
+  if (strcmp(xs[1], "!") == 0) { free(xs[1]); return mpca_not(xs[0]); }\r
+  num = *((int*)xs[1]);\r
+  free(xs[1]);\r
+  return mpca_count(num, xs[0]);\r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_string(mpc_val_t *x, void *s) {\r
+  mpca_grammar_st_t *st = s;\r
+  char *y = mpcf_unescape(x);\r
+  mpc_parser_t *p = (st->flags & MPCA_LANG_WHITESPACE_SENSITIVE) ? mpc_string(y) : mpc_tok(mpc_string(y));\r
+  free(y);\r
+  return mpca_state(mpca_tag(mpc_apply(p, mpcf_str_ast), "string"));\r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_char(mpc_val_t *x, void *s) {\r
+  mpca_grammar_st_t *st = s;\r
+  char *y = mpcf_unescape(x);\r
+  mpc_parser_t *p = (st->flags & MPCA_LANG_WHITESPACE_SENSITIVE) ? mpc_char(y[0]) : mpc_tok(mpc_char(y[0]));\r
+  free(y);\r
+  return mpca_state(mpca_tag(mpc_apply(p, mpcf_str_ast), "char"));\r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_regex(mpc_val_t *x, void *s) {\r
+  mpca_grammar_st_t *st = s;\r
+  char *y = mpcf_unescape_regex(x);\r
+  mpc_parser_t *p = (st->flags & MPCA_LANG_WHITESPACE_SENSITIVE) ? mpc_re(y) : mpc_tok(mpc_re(y));\r
+  free(y);\r
+  return mpca_state(mpca_tag(mpc_apply(p, mpcf_str_ast), "regex"));\r
+}\r
+\r
+/* Should this just use `isdigit` instead */\r
+static int is_number(const char* s) {\r
+  int i;\r
+  for (i = 0; i < strlen(s); i++) { if (!strchr("0123456789", s[i])) { return 0; } }\r
+  return 1;\r
+}\r
+\r
+static mpc_parser_t *mpca_grammar_find_parser(char *x, mpca_grammar_st_t *st) {\r
+  \r
+  int i;\r
+  mpc_parser_t *p;\r
+  \r
+  /* Case of Number */\r
+  if (is_number(x)) {\r
+\r
+    i = strtol(x, NULL, 10);\r
+    \r
+    while (st->parsers_num <= i) {\r
+      st->parsers_num++;\r
+      st->parsers = realloc(st->parsers, sizeof(mpc_parser_t*) * st->parsers_num);\r
+      st->parsers[st->parsers_num-1] = va_arg(*st->va, mpc_parser_t*);\r
+      if (st->parsers[st->parsers_num-1] == NULL) {\r
+        return mpc_failf("No Parser in position %i! Only supplied %i Parsers!", i, st->parsers_num);\r
+      }\r
+    }\r
+    \r
+    return st->parsers[st->parsers_num-1];\r
+  \r
+  /* Case of Identifier */\r
+  } else {\r
+    \r
+    /* Search Existing Parsers */\r
+    for (i = 0; i < st->parsers_num; i++) {\r
+      mpc_parser_t *p = st->parsers[i];\r
+      if (p == NULL) { return mpc_failf("Unknown Parser '%s'!", x); }\r
+      if (p->name && strcmp(p->name, x) == 0) { return p; }\r
+    }\r
+    \r
+    /* Search New Parsers */\r
+    while (1) {\r
+    \r
+      p = va_arg(*st->va, mpc_parser_t*);\r
+      \r
+      st->parsers_num++;\r
+      st->parsers = realloc(st->parsers, sizeof(mpc_parser_t*) * st->parsers_num);\r
+      st->parsers[st->parsers_num-1] = p;\r
+      \r
+      if (p == NULL) { return mpc_failf("Unknown Parser '%s'!", x); }\r
+      if (p->name && strcmp(p->name, x) == 0) { return p; }\r
+      \r
+    }\r
+  \r
+  }  \r
+  \r
+}\r
+\r
+static mpc_val_t *mpcaf_grammar_id(mpc_val_t *x, void *s) {\r
+  \r
+  mpca_grammar_st_t *st = s;\r
+  mpc_parser_t *p = mpca_grammar_find_parser(x, st);\r
+  free(x);\r
+\r
+  if (p->name) {\r
+    return mpca_state(mpca_root(mpca_add_tag(p, p->name)));\r
+  } else {\r
+    return mpca_state(mpca_root(p));\r
+  }\r
+}\r
+\r
+mpc_parser_t *mpca_grammar_st(const char *grammar, mpca_grammar_st_t *st) {\r
+  \r
+  char *err_msg;\r
+  mpc_parser_t *err_out;\r
+  mpc_result_t r;\r
+  mpc_parser_t *GrammarTotal, *Grammar, *Term, *Factor, *Base;\r
+  \r
+  GrammarTotal = mpc_new("grammar_total");\r
+  Grammar = mpc_new("grammar");\r
+  Term = mpc_new("term");\r
+  Factor = mpc_new("factor");\r
+  Base = mpc_new("base");\r
+  \r
+  mpc_define(GrammarTotal,\r
+    mpc_predictive(mpc_total(Grammar, mpc_soft_delete))\r
+  );\r
+  \r
+  mpc_define(Grammar, mpc_and(2, mpcaf_grammar_or,\r
+    Term,\r
+    mpc_maybe(mpc_and(2, mpcf_snd_free, mpc_sym("|"), Grammar, free)),\r
+    mpc_soft_delete\r
+  ));\r
+  \r
+  mpc_define(Term, mpc_many1(mpcaf_grammar_and, Factor));\r
+  \r
+  mpc_define(Factor, mpc_and(2, mpcaf_grammar_repeat,\r
+    Base,\r
+      mpc_or(6,\r
+        mpc_sym("*"),\r
+        mpc_sym("+"),\r
+        mpc_sym("?"),\r
+        mpc_sym("!"),\r
+        mpc_tok_brackets(mpc_int(), free),\r
+        mpc_pass()),\r
+    mpc_soft_delete\r
+  ));\r
+  \r
+  mpc_define(Base, mpc_or(5,\r
+    mpc_apply_to(mpc_tok(mpc_string_lit()), mpcaf_grammar_string, st),\r
+    mpc_apply_to(mpc_tok(mpc_char_lit()),   mpcaf_grammar_char, st),\r
+    mpc_apply_to(mpc_tok(mpc_regex_lit()),  mpcaf_grammar_regex, st),\r
+    mpc_apply_to(mpc_tok_braces(mpc_or(2, mpc_digits(), mpc_ident()), free), mpcaf_grammar_id, st),\r
+    mpc_tok_parens(Grammar, mpc_soft_delete)\r
+  ));\r
+  \r
+  if(!mpc_parse("<mpc_grammar_compiler>", grammar, GrammarTotal, &r)) {\r
+    err_msg = mpc_err_string(r.error);\r
+    err_out = mpc_failf("Invalid Grammar: %s", err_msg);\r
+    mpc_err_delete(r.error);\r
+    free(err_msg);\r
+    r.output = err_out;\r
+  }\r
+  \r
+  mpc_cleanup(5, GrammarTotal, Grammar, Term, Factor, Base);\r
+  \r
+  return (st->flags & MPCA_LANG_PREDICTIVE) ? mpc_predictive(r.output) : r.output;\r
+  \r
+}\r
+\r
+mpc_parser_t *mpca_grammar(int flags, const char *grammar, ...) {\r
+  mpca_grammar_st_t st;\r
+  mpc_parser_t *res;\r
+  va_list va;\r
+  va_start(va, grammar);\r
+  \r
+  st.va = &va;\r
+  st.parsers_num = 0;\r
+  st.parsers = NULL;\r
+  st.flags = flags;\r
+  \r
+  res = mpca_grammar_st(grammar, &st);  \r
+  free(st.parsers);\r
+  va_end(va);\r
+  return res;\r
+}\r
+\r
+typedef struct {\r
+  char *ident;\r
+  char *name;\r
+  mpc_parser_t *grammar;\r
+} mpca_stmt_t;\r
+\r
+static mpc_val_t *mpca_stmt_afold(int n, mpc_val_t **xs) {\r
+  \r
+  mpca_stmt_t *stmt = malloc(sizeof(mpca_stmt_t));\r
+  stmt->ident = ((char**)xs)[0];\r
+  stmt->name = ((char**)xs)[1];\r
+  stmt->grammar = ((mpc_parser_t**)xs)[3];\r
+  \r
+  free(((char**)xs)[2]);\r
+  free(((char**)xs)[4]);\r
+  \r
+  return stmt;\r
+}\r
+\r
+static mpc_val_t *mpca_stmt_fold(int n, mpc_val_t **xs) {\r
+  \r
+  int i;\r
+  mpca_stmt_t **stmts = malloc(sizeof(mpca_stmt_t*) * (n+1));\r
+  \r
+  for (i = 0; i < n; i++) {\r
+    stmts[i] = xs[i];\r
+  }\r
+  stmts[n] = NULL;  \r
+  \r
+  return stmts;\r
+}\r
+\r
+static void mpca_stmt_list_delete(mpc_val_t *x) {\r
+\r
+  mpca_stmt_t **stmts = x;\r
+\r
+  while(*stmts) {\r
+    mpca_stmt_t *stmt = *stmts; \r
+    free(stmt->ident);\r
+    free(stmt->name);\r
+    mpc_soft_delete(stmt->grammar);\r
+    free(stmt);  \r
+    stmts++;\r
+  }\r
+  free(x);\r
+\r
+}\r
+\r
+static mpc_val_t *mpca_stmt_list_apply_to(mpc_val_t *x, void *s) {\r
+\r
+  mpca_grammar_st_t *st = s;\r
+  mpca_stmt_t *stmt;\r
+  mpca_stmt_t **stmts = x;\r
+  mpc_parser_t *left;\r
+\r
+  while(*stmts) {\r
+    stmt = *stmts;\r
+    left = mpca_grammar_find_parser(stmt->ident, st);\r
+    if (st->flags & MPCA_LANG_PREDICTIVE) { stmt->grammar = mpc_predictive(stmt->grammar); }\r
+    if (stmt->name) { stmt->grammar = mpc_expect(stmt->grammar, stmt->name); }\r
+    mpc_define(left, stmt->grammar);\r
+    free(stmt->ident);\r
+    free(stmt->name);\r
+    free(stmt);\r
+    stmts++;\r
+  }\r
+  free(x);\r
+  \r
+  return NULL;\r
+}\r
+\r
+static mpc_err_t *mpca_lang_st(mpc_input_t *i, mpca_grammar_st_t *st) {\r
+  \r
+  mpc_result_t r;\r
+  mpc_err_t *e;\r
+  mpc_parser_t *Lang, *Stmt, *Grammar, *Term, *Factor, *Base; \r
+  \r
+  Lang    = mpc_new("lang");\r
+  Stmt    = mpc_new("stmt");\r
+  Grammar = mpc_new("grammar");\r
+  Term    = mpc_new("term");\r
+  Factor  = mpc_new("factor");\r
+  Base    = mpc_new("base");\r
+  \r
+  mpc_define(Lang, mpc_apply_to(\r
+    mpc_total(mpc_predictive(mpc_many(mpca_stmt_fold, Stmt)), mpca_stmt_list_delete),\r
+    mpca_stmt_list_apply_to, st\r
+  ));\r
+  \r
+  mpc_define(Stmt, mpc_and(5, mpca_stmt_afold,\r
+    mpc_tok(mpc_ident()), mpc_maybe(mpc_tok(mpc_string_lit())), mpc_sym(":"), Grammar, mpc_sym(";"),\r
+    free, free, free, mpc_soft_delete\r
+  ));\r
+  \r
+  mpc_define(Grammar, mpc_and(2, mpcaf_grammar_or,\r
+      Term,\r
+      mpc_maybe(mpc_and(2, mpcf_snd_free, mpc_sym("|"), Grammar, free)),\r
+      mpc_soft_delete\r
+  ));\r
+  \r
+  mpc_define(Term, mpc_many1(mpcaf_grammar_and, Factor));\r
+  \r
+  mpc_define(Factor, mpc_and(2, mpcaf_grammar_repeat,\r
+    Base,\r
+      mpc_or(6,\r
+        mpc_sym("*"),\r
+        mpc_sym("+"),\r
+        mpc_sym("?"),\r
+        mpc_sym("!"),\r
+        mpc_tok_brackets(mpc_int(), free),\r
+        mpc_pass()),\r
+    mpc_soft_delete\r
+  ));\r
+  \r
+  mpc_define(Base, mpc_or(5,\r
+    mpc_apply_to(mpc_tok(mpc_string_lit()), mpcaf_grammar_string, st),\r
+    mpc_apply_to(mpc_tok(mpc_char_lit()),   mpcaf_grammar_char, st),\r
+    mpc_apply_to(mpc_tok(mpc_regex_lit()),  mpcaf_grammar_regex, st),\r
+    mpc_apply_to(mpc_tok_braces(mpc_or(2, mpc_digits(), mpc_ident()), free), mpcaf_grammar_id, st),\r
+    mpc_tok_parens(Grammar, mpc_soft_delete)\r
+  ));\r
+  \r
+  \r
+  if (!mpc_parse_input(i, Lang, &r)) {\r
+    e = r.error;\r
+  } else {\r
+    e = NULL;\r
+  }\r
+  \r
+  mpc_cleanup(6, Lang, Stmt, Grammar, Term, Factor, Base);\r
+  \r
+  return e;\r
+}\r
+\r
+mpc_err_t *mpca_lang_file(int flags, FILE *f, ...) {\r
+  mpca_grammar_st_t st;\r
+  mpc_input_t *i;\r
+  mpc_err_t *err;\r
+\r
+  va_list va;  \r
+  va_start(va, f);\r
+  \r
+  st.va = &va;\r
+  st.parsers_num = 0;\r
+  st.parsers = NULL;\r
+  st.flags = flags;\r
+  \r
+  i = mpc_input_new_file("<mpca_lang_file>", f);\r
+  err = mpca_lang_st(i, &st);\r
+  mpc_input_delete(i);\r
+  \r
+  free(st.parsers);\r
+  va_end(va);\r
+  return err;\r
+}\r
+\r
+mpc_err_t *mpca_lang_pipe(int flags, FILE *p, ...) {\r
+  mpca_grammar_st_t st;\r
+  mpc_input_t *i;\r
+  mpc_err_t *err;\r
+\r
+  va_list va;  \r
+  va_start(va, p);\r
+  \r
+  st.va = &va;\r
+  st.parsers_num = 0;\r
+  st.parsers = NULL;\r
+  st.flags = flags;\r
+  \r
+  i = mpc_input_new_pipe("<mpca_lang_pipe>", p);\r
+  err = mpca_lang_st(i, &st);\r
+  mpc_input_delete(i);\r
+  \r
+  free(st.parsers);\r
+  va_end(va);\r
+  return err;\r
+}\r
+\r
+mpc_err_t *mpca_lang(int flags, const char *language, ...) {\r
+  \r
+  mpca_grammar_st_t st;\r
+  mpc_input_t *i;\r
+  mpc_err_t *err;\r
+  \r
+  va_list va;  \r
+  va_start(va, language);\r
+  \r
+  st.va = &va;\r
+  st.parsers_num = 0;\r
+  st.parsers = NULL;\r
+  st.flags = flags;\r
+  \r
+  i = mpc_input_new_string("<mpca_lang>", language);\r
+  err = mpca_lang_st(i, &st);\r
+  mpc_input_delete(i);\r
+  \r
+  free(st.parsers);\r
+  va_end(va);\r
+  return err;\r
+}\r
+\r
+mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...) {\r
+  \r
+  mpca_grammar_st_t st;\r
+  mpc_input_t *i;\r
+  mpc_err_t *err;\r
+  \r
+  va_list va;\r
+\r
+  FILE *f = fopen(filename, "rb");\r
+  \r
+  if (f == NULL) {\r
+    return mpc_err_fail(filename, mpc_state_new(), "Unable to open file!");\r
+  }\r
+  \r
+  va_start(va, filename);\r
+  \r
+  st.va = &va;\r
+  st.parsers_num = 0;\r
+  st.parsers = NULL;\r
+  st.flags = flags;\r
+  \r
+  i = mpc_input_new_file(filename, f);\r
+  err = mpca_lang_st(i, &st);\r
+  mpc_input_delete(i);\r
+  \r
+  free(st.parsers);\r
+  va_end(va);  \r
+  \r
+  fclose(f);\r
+  \r
+  return err;\r
+}\r
diff --git a/source/sclpl/mpc.h b/source/sclpl/mpc.h
new file mode 100644 (file)
index 0000000..7814700
--- /dev/null
@@ -0,0 +1,330 @@
+/*\r
+** mpc - Micro Parser Combinator library for C\r
+**\r
+** https://github.com/orangeduck/mpc\r
+**\r
+** Daniel Holden - contact@daniel-holden.com\r
+** Licensed under BSD3\r
+*/\r
+\r
+#ifndef mpc_h\r
+#define mpc_h\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <math.h>\r
+#include <errno.h>\r
+\r
+/*\r
+** State Type\r
+*/\r
+\r
+typedef struct {\r
+  int pos;\r
+  int row;\r
+  int col;\r
+} mpc_state_t;\r
+\r
+/*\r
+** Error Type\r
+*/\r
+\r
+typedef struct {\r
+  mpc_state_t state;\r
+  int expected_num;\r
+  char *filename;\r
+  char *failure;\r
+  char **expected;\r
+  char recieved;\r
+} mpc_err_t;\r
+\r
+void mpc_err_delete(mpc_err_t *e);\r
+char *mpc_err_string(mpc_err_t *e);\r
+void mpc_err_print(mpc_err_t *e);\r
+void mpc_err_print_to(mpc_err_t *e, FILE *f);\r
+\r
+/*\r
+** Parsing\r
+*/\r
+\r
+typedef void mpc_val_t;\r
+\r
+typedef union {\r
+  mpc_err_t *error;\r
+  mpc_val_t *output;\r
+} mpc_result_t;\r
+\r
+struct mpc_parser_t;\r
+typedef struct mpc_parser_t mpc_parser_t;\r
+\r
+int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r);\r
+int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result_t *r);\r
+int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result_t *r);\r
+int mpc_parse_contents(const char *filename, mpc_parser_t *p, mpc_result_t *r);\r
+\r
+/*\r
+** Function Types\r
+*/\r
+\r
+typedef void(*mpc_dtor_t)(mpc_val_t*);\r
+typedef mpc_val_t*(*mpc_ctor_t)(void);\r
+\r
+typedef mpc_val_t*(*mpc_apply_t)(mpc_val_t*);\r
+typedef mpc_val_t*(*mpc_apply_to_t)(mpc_val_t*,void*);\r
+typedef mpc_val_t*(*mpc_fold_t)(int,mpc_val_t**);\r
+\r
+/*\r
+** Building a Parser\r
+*/\r
+\r
+mpc_parser_t *mpc_new(const char *name);\r
+mpc_parser_t *mpc_define(mpc_parser_t *p, mpc_parser_t *a);\r
+mpc_parser_t *mpc_undefine(mpc_parser_t *p);\r
+\r
+void mpc_delete(mpc_parser_t *p);\r
+void mpc_cleanup(int n, ...);\r
+\r
+/*\r
+** Basic Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_any(void);\r
+mpc_parser_t *mpc_char(char c);\r
+mpc_parser_t *mpc_range(char s, char e);\r
+mpc_parser_t *mpc_oneof(const char *s);\r
+mpc_parser_t *mpc_noneof(const char *s);\r
+mpc_parser_t *mpc_satisfy(int(*f)(char));\r
+mpc_parser_t *mpc_string(const char *s);\r
+\r
+/*\r
+** Other Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_pass(void);\r
+mpc_parser_t *mpc_fail(const char *m);\r
+mpc_parser_t *mpc_failf(const char *fmt, ...);\r
+mpc_parser_t *mpc_lift(mpc_ctor_t f);\r
+mpc_parser_t *mpc_lift_val(mpc_val_t *x);\r
+mpc_parser_t *mpc_anchor(int(*f)(char,char));\r
+mpc_parser_t *mpc_state(void);\r
+\r
+/*\r
+** Combinator Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *e);\r
+mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...);\r
+mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f);\r
+mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x);\r
+\r
+mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da);\r
+mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf);\r
+mpc_parser_t *mpc_maybe(mpc_parser_t *a);\r
+mpc_parser_t *mpc_maybe_lift(mpc_parser_t *a, mpc_ctor_t lf);\r
+\r
+mpc_parser_t *mpc_many(mpc_fold_t f, mpc_parser_t *a);\r
+mpc_parser_t *mpc_many1(mpc_fold_t f, mpc_parser_t *a);\r
+mpc_parser_t *mpc_count(int n, mpc_fold_t f, mpc_parser_t *a, mpc_dtor_t da);\r
+\r
+mpc_parser_t *mpc_or(int n, ...);\r
+mpc_parser_t *mpc_and(int n, mpc_fold_t f, ...);\r
+\r
+mpc_parser_t *mpc_predictive(mpc_parser_t *a);\r
+\r
+/*\r
+** Common Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_eoi(void);\r
+mpc_parser_t *mpc_soi(void);\r
+\r
+mpc_parser_t *mpc_boundary(void);\r
+\r
+mpc_parser_t *mpc_whitespace(void);\r
+mpc_parser_t *mpc_whitespaces(void);\r
+mpc_parser_t *mpc_blank(void);\r
+\r
+mpc_parser_t *mpc_newline(void);\r
+mpc_parser_t *mpc_tab(void);\r
+mpc_parser_t *mpc_escape(void);\r
+\r
+mpc_parser_t *mpc_digit(void);\r
+mpc_parser_t *mpc_hexdigit(void);\r
+mpc_parser_t *mpc_octdigit(void);\r
+mpc_parser_t *mpc_digits(void);\r
+mpc_parser_t *mpc_hexdigits(void);\r
+mpc_parser_t *mpc_octdigits(void);\r
+\r
+mpc_parser_t *mpc_lower(void);\r
+mpc_parser_t *mpc_upper(void);\r
+mpc_parser_t *mpc_alpha(void);\r
+mpc_parser_t *mpc_underscore(void);\r
+mpc_parser_t *mpc_alphanum(void);\r
+\r
+mpc_parser_t *mpc_int(void);\r
+mpc_parser_t *mpc_hex(void);\r
+mpc_parser_t *mpc_oct(void);\r
+mpc_parser_t *mpc_number(void);\r
+\r
+mpc_parser_t *mpc_real(void);\r
+mpc_parser_t *mpc_float(void);\r
+\r
+mpc_parser_t *mpc_char_lit(void);\r
+mpc_parser_t *mpc_string_lit(void);\r
+mpc_parser_t *mpc_regex_lit(void);\r
+\r
+mpc_parser_t *mpc_ident(void);\r
+\r
+/*\r
+** Useful Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_startwith(mpc_parser_t *a);\r
+mpc_parser_t *mpc_endwith(mpc_parser_t *a, mpc_dtor_t da);\r
+mpc_parser_t *mpc_whole(mpc_parser_t *a, mpc_dtor_t da);\r
+\r
+mpc_parser_t *mpc_stripl(mpc_parser_t *a);\r
+mpc_parser_t *mpc_stripr(mpc_parser_t *a);\r
+mpc_parser_t *mpc_strip(mpc_parser_t *a);\r
+mpc_parser_t *mpc_tok(mpc_parser_t *a);\r
+mpc_parser_t *mpc_sym(const char *s);\r
+mpc_parser_t *mpc_total(mpc_parser_t *a, mpc_dtor_t da);\r
+\r
+mpc_parser_t *mpc_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);\r
+mpc_parser_t *mpc_parens(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);\r
+\r
+mpc_parser_t *mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);\r
+mpc_parser_t *mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);\r
+mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);\r
+\r
+/*\r
+** Common Function Parameters\r
+*/\r
+\r
+void mpcf_dtor_null(mpc_val_t *x);\r
+\r
+mpc_val_t *mpcf_ctor_null(void);\r
+mpc_val_t *mpcf_ctor_str(void);\r
+\r
+mpc_val_t *mpcf_free(mpc_val_t *x);\r
+mpc_val_t *mpcf_int(mpc_val_t *x);\r
+mpc_val_t *mpcf_hex(mpc_val_t *x);\r
+mpc_val_t *mpcf_oct(mpc_val_t *x);\r
+mpc_val_t *mpcf_float(mpc_val_t *x);\r
+\r
+mpc_val_t *mpcf_escape(mpc_val_t *x);\r
+mpc_val_t *mpcf_escape_regex(mpc_val_t *x);\r
+mpc_val_t *mpcf_escape_string_raw(mpc_val_t *x);\r
+mpc_val_t *mpcf_escape_char_raw(mpc_val_t *x);\r
+\r
+mpc_val_t *mpcf_unescape(mpc_val_t *x);\r
+mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);\r
+mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);\r
+mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);\r
+\r
+mpc_val_t *mpcf_null(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_fst(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_snd(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_trd(int n, mpc_val_t** xs);\r
+\r
+mpc_val_t *mpcf_fst_free(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_snd_free(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_trd_free(int n, mpc_val_t** xs);\r
+\r
+mpc_val_t *mpcf_strfold(int n, mpc_val_t** xs);\r
+mpc_val_t *mpcf_maths(int n, mpc_val_t** xs);\r
+\r
+/*\r
+** Regular Expression Parsers\r
+*/\r
+\r
+mpc_parser_t *mpc_re(const char *re);\r
+\r
+/*\r
+** AST\r
+*/\r
+\r
+typedef struct mpc_ast_t {\r
+  char *tag;\r
+  char *contents;\r
+  mpc_state_t state;\r
+  int children_num;\r
+  struct mpc_ast_t** children;\r
+} mpc_ast_t;\r
+\r
+mpc_ast_t *mpc_ast_new(const char *tag, const char *contents);\r
+mpc_ast_t *mpc_ast_build(int n, const char *tag, ...);\r
+mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a);\r
+mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a);\r
+mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t);\r
+mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t);\r
+mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s);\r
+\r
+void mpc_ast_delete(mpc_ast_t *a);\r
+void mpc_ast_print(mpc_ast_t *a);\r
+void mpc_ast_print_to(mpc_ast_t *a, FILE *fp);\r
+\r
+/*\r
+** Warning: This function currently doesn't test for equality of the `state` member!\r
+*/\r
+int mpc_ast_eq(mpc_ast_t *a, mpc_ast_t *b);\r
+\r
+mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **as);\r
+mpc_val_t *mpcf_str_ast(mpc_val_t *c);\r
+mpc_val_t *mpcf_state_ast(int n, mpc_val_t **xs);\r
+\r
+mpc_parser_t *mpca_tag(mpc_parser_t *a, const char *t);\r
+mpc_parser_t *mpca_add_tag(mpc_parser_t *a, const char *t);\r
+mpc_parser_t *mpca_root(mpc_parser_t *a);\r
+mpc_parser_t *mpca_state(mpc_parser_t *a);\r
+mpc_parser_t *mpca_total(mpc_parser_t *a);\r
+\r
+mpc_parser_t *mpca_not(mpc_parser_t *a);\r
+mpc_parser_t *mpca_maybe(mpc_parser_t *a);\r
+\r
+mpc_parser_t *mpca_many(mpc_parser_t *a);\r
+mpc_parser_t *mpca_many1(mpc_parser_t *a);\r
+mpc_parser_t *mpca_count(int n, mpc_parser_t *a);\r
+\r
+mpc_parser_t *mpca_or(int n, ...);\r
+mpc_parser_t *mpca_and(int n, ...);\r
+\r
+enum {\r
+  MPCA_LANG_DEFAULT              = 0,\r
+  MPCA_LANG_PREDICTIVE           = 1,\r
+  MPCA_LANG_WHITESPACE_SENSITIVE = 2\r
+};\r
+\r
+mpc_parser_t *mpca_grammar(int flags, const char *grammar, ...);\r
+\r
+mpc_err_t *mpca_lang(int flags, const char *language, ...);\r
+mpc_err_t *mpca_lang_file(int flags, FILE *f, ...);\r
+mpc_err_t *mpca_lang_pipe(int flags, FILE *f, ...);\r
+mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...);\r
+\r
+/*\r
+** Debug & Testing\r
+*/\r
+\r
+void mpc_print(mpc_parser_t *p);\r
+\r
+int mpc_test_pass(mpc_parser_t *p, const char *s, void *d,\r
+  int(*tester)(void*, void*),\r
+  mpc_dtor_t destructor,\r
+  void(*printer)(void*));\r
+\r
+int mpc_test_fail(mpc_parser_t *p, const char *s, void *d,\r
+  int(*tester)(void*, void*),\r
+  mpc_dtor_t destructor,\r
+  void(*printer)(void*));\r
+\r
+\r
+\r
+#endif\r