Move stuff for graff
diff --git a/bc/Makefile b/bc/Makefile
new file mode 100644
index 0000000..9d232a8
--- /dev/null
+++ b/bc/Makefile
@@ -0,0 +1,18 @@
+CFLAGS += -Wall -Wextra -I./include/ -I../arbprec/include -std=c99 -fsanitize=address -fsanitize=undefined -g -O0
+
+BC_OBJ = $(shell for i in *.c ; do printf "%s\n" $${i%.c}.o ; done )
+
+BC_EXEC = bc
+
+all:
+
+	$(MAKE) create_bc
+
+create_bc: $(BC_OBJ)
+
+	$(CC) $(CFLAGS) -o $(BC_EXEC) *.o ../arbprec/libarbprec.a
+
+clean:
+
+	$(RM) $(BC_OBJ)
+	$(RM) $(BC_EXEC)
diff --git a/bc/bc.c b/bc/bc.c
new file mode 100644
index 0000000..76fff7b
--- /dev/null
+++ b/bc/bc.c
@@ -0,0 +1,98 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "vm.h"
+
+uint32_t bc_ibase = 10;
+uint32_t bc_obase = 10;
+
+int bc_mathlib = 0;
+int bc_quiet = 0;
+int bc_std = 0;
+int bc_warn = 0;
+
+static const struct option bc_opts[] = {
+    { "help", no_argument, NULL, 'h' },
+    { "mathlib", no_argument, &bc_mathlib, 'l' },
+    { "quiet", no_argument, &bc_quiet, 'q' },
+    { "standard", no_argument, &bc_std, 's' },
+    { "version", no_argument, NULL, 'v' },
+    { "warn", no_argument, &bc_warn, 'w' },
+    { 0, 0, 0, 0},
+};
+
+static const char* const bc_short_opts = "hlqsvw";
+
+int main(int argc, char* argv[]) {
+
+	BcStatus status;
+	BcVm vm;
+
+	// Getopt needs this.
+	int opt_idx = 0;
+
+	int c = getopt_long(argc, argv, bc_short_opts, bc_opts, &opt_idx);
+
+	while (c != -1) {
+
+		switch (c) {
+
+			case 0:
+				// This is the case when a long option is
+				// found, so we don't need to do anything.
+				break;
+
+			case 'h':
+				// TODO: Print help.
+				break;
+
+			case 'l':
+				bc_mathlib = 'l';
+				break;
+
+			case 'q':
+				bc_quiet = 'q';
+				break;
+
+			case 's':
+				bc_std = 's';
+				break;
+
+			case 'v':
+				// TODO: Print version.
+				break;
+
+			case 'w':
+				bc_warn = 'w';
+				break;
+
+			case '?':
+				// Getopt printed an error message, but we should exit.
+			default:
+				exit(BC_STATUS_INVALID_OPTION);
+				break;
+		}
+
+		// Get the next option.
+		c = getopt_long(argc, argv, bc_short_opts, bc_opts, &opt_idx);
+	}
+
+	uint32_t num_files = argc - optind;
+	const char** file_names = (const char**) (argv + optind);
+
+	status = bc_vm_init(&vm, num_files, file_names);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_vm_exec(&vm);
+
+	bc_vm_free(&vm);
+
+	return status;
+}
diff --git a/bc/include/bc/bc.h b/bc/include/bc/bc.h
new file mode 100644
index 0000000..7be978c
--- /dev/null
+++ b/bc/include/bc/bc.h
@@ -0,0 +1,39 @@
+#ifndef BC_H
+#define BC_H
+
+#include <stdint.h>
+
+typedef enum BcStatus {
+
+	BC_STATUS_SUCCESS,
+
+	BC_STATUS_INVALID_OPTION,
+
+	BC_STATUS_MALLOC_FAIL,
+	BC_STATUS_INVALID_PARAM,
+
+	BC_STATUS_VM_FILE_ERR,
+	BC_STATUS_VM_FILE_READ_ERR,
+	BC_STATUS_VM_DIVIDE_BY_ZERO,
+	BC_STATUS_VM_NEG_SQRT,
+	BC_STATUS_VM_MISMATCHED_PARAMS,
+	BC_STATUS_VM_UNDEFINED_FUNC,
+
+	BC_STATUS_LEX_INVALID_TOKEN,
+	BC_STATUS_LEX_NO_STRING_END,
+	BC_STATUS_LEX_NO_COMMENT_END,
+	BC_STATUS_LEX_EOF,
+
+	BC_STATUS_PARSE_INVALID_TOKEN,
+	BC_STATUS_PARSE_INVALID_EXPR,
+	BC_STATUS_PARSE_INVALID_PRINT,
+	BC_STATUS_PARSE_INVALID_FUNC,
+	BC_STATUS_PARSE_EOF,
+	BC_STATUS_PARSE_BUG,
+
+} BcStatus;
+
+void bc_error(BcStatus status);
+void bc_error_file(const char* file, uint32_t line, BcStatus status);
+
+#endif // BC_H
diff --git a/bc/include/bc/lex.h b/bc/include/bc/lex.h
new file mode 100644
index 0000000..062b499
--- /dev/null
+++ b/bc/include/bc/lex.h
@@ -0,0 +1,124 @@
+#ifndef BC_LEX_H
+#define BC_LEX_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "bc.h"
+
+#define BC_LEX_GEN_ENUM(ENUM) ENUM,
+#define BC_LEX_GEN_STR(STRING) #STRING,
+
+// BC_LEX_OP_NEGATE is not used in lexing;
+// it is only for parsing.
+#define BC_LEX_TOKEN_FOREACH(TOKEN) \
+	TOKEN(BC_LEX_OP_INC)  \
+	TOKEN(BC_LEX_OP_DEC)  \
+	                      \
+	TOKEN(BC_LEX_OP_POWER)  \
+	                        \
+	TOKEN(BC_LEX_OP_MULTIPLY)  \
+	TOKEN(BC_LEX_OP_DIVIDE)    \
+	TOKEN(BC_LEX_OP_MODULUS)   \
+	                           \
+	TOKEN(BC_LEX_OP_PLUS)   \
+	TOKEN(BC_LEX_OP_MINUS)  \
+	                        \
+	TOKEN(BC_LEX_OP_ASSIGN)           \
+	TOKEN(BC_LEX_OP_ASSIGN_PLUS)      \
+	TOKEN(BC_LEX_OP_ASSIGN_MINUS)     \
+	TOKEN(BC_LEX_OP_ASSIGN_MULTIPLY)  \
+	TOKEN(BC_LEX_OP_ASSIGN_DIVIDE)    \
+	TOKEN(BC_LEX_OP_ASSIGN_MODULUS)   \
+	TOKEN(BC_LEX_OP_ASSIGN_POWER)     \
+	                                  \
+	TOKEN(BC_LEX_OP_REL_EQUAL)       \
+	TOKEN(BC_LEX_OP_REL_LESS_EQ)     \
+	TOKEN(BC_LEX_OP_REL_GREATER_EQ)  \
+	TOKEN(BC_LEX_OP_REL_NOT_EQ)      \
+	TOKEN(BC_LEX_OP_REL_LESS)        \
+	TOKEN(BC_LEX_OP_REL_GREATER)     \
+	                                 \
+	TOKEN(BC_LEX_OP_BOOL_NOT)  \
+	                           \
+	TOKEN(BC_LEX_OP_BOOL_OR)   \
+	TOKEN(BC_LEX_OP_BOOL_AND)  \
+	                           \
+	TOKEN(BC_LEX_OP_NEGATE)    \
+	                           \
+	TOKEN(BC_LEX_NEWLINE)  \
+	                       \
+	TOKEN(BC_LEX_WHITESPACE)  \
+	                          \
+	TOKEN(BC_LEX_LEFT_PAREN)   \
+	TOKEN(BC_LEX_RIGHT_PAREN)  \
+	                           \
+	TOKEN(BC_LEX_LEFT_BRACKET)   \
+	TOKEN(BC_LEX_RIGHT_BRACKET)  \
+	                             \
+	TOKEN(BC_LEX_LEFT_BRACE)   \
+	TOKEN(BC_LEX_RIGHT_BRACE)  \
+	                           \
+	TOKEN(BC_LEX_COMMA)      \
+	TOKEN(BC_LEX_SEMICOLON)  \
+	                         \
+	TOKEN(BC_LEX_STRING)  \
+	TOKEN(BC_LEX_NAME)    \
+	TOKEN(BC_LEX_NUMBER)  \
+	                      \
+	TOKEN(BC_LEX_KEY_AUTO)      \
+	TOKEN(BC_LEX_KEY_BREAK)     \
+	TOKEN(BC_LEX_KEY_CONTINUE)  \
+	TOKEN(BC_LEX_KEY_DEFINE)    \
+	TOKEN(BC_LEX_KEY_ELSE)      \
+	TOKEN(BC_LEX_KEY_FOR)       \
+	TOKEN(BC_LEX_KEY_HALT)      \
+	TOKEN(BC_LEX_KEY_IBASE)     \
+	TOKEN(BC_LEX_KEY_IF)        \
+	TOKEN(BC_LEX_KEY_LAST)      \
+	TOKEN(BC_LEX_KEY_LENGTH)    \
+	TOKEN(BC_LEX_KEY_LIMITS)    \
+	TOKEN(BC_LEX_KEY_OBASE)     \
+	TOKEN(BC_LEX_KEY_PRINT)     \
+	TOKEN(BC_LEX_KEY_QUIT)      \
+	TOKEN(BC_LEX_KEY_READ)      \
+	TOKEN(BC_LEX_KEY_RETURN)    \
+	TOKEN(BC_LEX_KEY_SCALE)     \
+	TOKEN(BC_LEX_KEY_SQRT)      \
+	TOKEN(BC_LEX_KEY_WHILE)     \
+	                            \
+	TOKEN(BC_LEX_EOF)           \
+	                            \
+	TOKEN(BC_LEX_INVALID)       \
+
+typedef enum BcLexTokenType {
+	BC_LEX_TOKEN_FOREACH(BC_LEX_GEN_ENUM)
+} BcLexTokenType;
+
+typedef struct BcLexToken {
+
+	BcLexTokenType type;
+	char* string;
+
+} BcLexToken;
+
+typedef struct BcLex {
+
+	const char* buffer;
+	size_t idx;
+	uint32_t line;
+	bool newline;
+	const char* file;
+	size_t len;
+
+} BcLex;
+
+BcStatus bc_lex_init(BcLex* lex);
+
+BcStatus bc_lex_text(BcLex* lex, const char* text);
+
+BcStatus bc_lex_next(BcLex* lex, BcLexToken* token);
+
+BcStatus bc_lex_printToken(BcLexToken* token);
+
+#endif // BC_LEX_H
diff --git a/bc/include/bc/parse.h b/bc/include/bc/parse.h
new file mode 100644
index 0000000..5fcbf69
--- /dev/null
+++ b/bc/include/bc/parse.h
@@ -0,0 +1,106 @@
+#ifndef BC_PARSE_H
+#define BC_PARSE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "stack.h"
+#include "program.h"
+#include "lex.h"
+
+#define BC_PARSE_TOP_FLAG(parse)  \
+	(*((uint8_t*) bc_stack_top(&(parse)->flag_stack)))
+
+#define BC_PARSE_FLAG_FUNC_INNER (0x0001)
+
+#define BC_PARSE_FUNC_INNER(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
+
+#define BC_PARSE_FLAG_FUNC (0x0002)
+
+#define BC_PARSE_FUNC(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
+
+#define BC_PARSE_FLAG_HEADER (0x0004)
+
+#define BC_PARSE_HEADER(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_HEADER)
+
+#define BC_PARSE_FLAG_AUTO (0x0008)
+
+#define BC_PARSE_AUTO(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_AUTO)
+
+#define BC_PARSE_FLAG_FOR_LOOP (0x0010)
+
+#define BC_PARSE_FOR_LOOP(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FOR_LOOP)
+
+#define BC_PARSE_FLAG_WHILE_LOOP (0x0020)
+
+#define BC_PARSE_WHILE_LOOP(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_WHILE_LOOP)
+
+#define BC_PARSE_FLAG_LOOP_INNER (0x0040)
+
+#define BC_PARSE_LOOP_INNER(parse) \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
+
+#define BC_PARSE_FLAG_IF (0x0080)
+
+#define BC_PARSE_IF(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
+
+#define BC_PARSE_FLAG_ELSE (0x0100)
+
+#define BC_PARSE_ELSE(parse)  \
+	(BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
+
+#define BC_PARSE_CAN_EXEC(parse)  \
+	(!(BC_PARSE_TOP_FLAG(parse) & (BC_PARSE_FLAG_FUNC_INNER |  \
+	                               BC_PARSE_FLAG_FUNC |        \
+	                               BC_PARSE_FLAG_HEADER |      \
+	                               BC_PARSE_FLAG_FOR_LOOP |    \
+	                               BC_PARSE_FLAG_WHILE_LOOP |  \
+	                               BC_PARSE_FLAG_LOOP_INNER |  \
+	                               BC_PARSE_FLAG_IF)))
+
+// We can calculate the conversion between tokens and exprs
+// by subtracting the position of the first operator in the
+// lex enum and adding the position of the first in the expr
+// enum. WARNING: This only works for binary operators.
+#define BC_PARSE_TOKEN_TO_EXPR(type) ((type) - BC_LEX_OP_POWER + BC_EXPR_POWER)
+
+typedef struct BcOp {
+
+	uint8_t prec;
+	bool left;
+
+} BcOp;
+
+typedef struct BcParse {
+
+	BcProgram* program;
+	BcLex lex;
+	BcLexToken token;
+
+	BcStack flag_stack;
+
+	BcStack ctx_stack;
+
+	BcFunc* func;
+
+	BcStmt partial;
+
+	uint32_t num_braces;
+
+} BcParse;
+
+BcStatus bc_parse_init(BcParse* parse, BcProgram* program);
+BcStatus bc_parse_text(BcParse* parse, const char* text);
+
+BcStatus bc_parse_parse(BcParse* parse, BcProgram* program);
+
+void bc_parse_free(BcParse* parse);
+
+#endif // BC_PARSE_H
diff --git a/bc/include/bc/program.h b/bc/include/bc/program.h
new file mode 100644
index 0000000..d518f67
--- /dev/null
+++ b/bc/include/bc/program.h
@@ -0,0 +1,245 @@
+#ifndef BC_PROGRAM_H
+#define BC_PROGRAM_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arbprec/arbprec.h>
+
+#include "segarray.h"
+#include "bc.h"
+
+#define BC_PROGRAM_MAX_STMTS (128)
+
+#define BC_PROGRAM_DEF_SIZE (16)
+
+typedef enum BcExprType {
+
+	BC_EXPR_INC_PRE,
+	BC_EXPR_DEC_PRE,
+
+	BC_EXPR_INC_POST,
+	BC_EXPR_DEC_POST,
+
+	BC_EXPR_NEGATE,
+
+	BC_EXPR_POWER,
+
+	BC_EXPR_MULTIPLY,
+	BC_EXPR_DIVIDE,
+	BC_EXPR_MODULUS,
+
+	BC_EXPR_PLUS,
+	BC_EXPR_MINUS,
+
+	BC_EXPR_ASSIGN,
+	BC_EXPR_ASSIGN_PLUS,
+	BC_EXPR_ASSIGN_MINUS,
+	BC_EXPR_ASSIGN_MULTIPLY,
+	BC_EXPR_ASSIGN_DIVIDE,
+	BC_EXPR_ASSIGN_MODULUS,
+	BC_EXPR_ASSIGN_POWER,
+
+	BC_EXPR_REL_EQUAL,
+	BC_EXPR_REL_LESS_EQ,
+	BC_EXPR_REL_GREATER_EQ,
+	BC_EXPR_REL_NOT_EQ,
+	BC_EXPR_REL_LESS,
+	BC_EXPR_REL_GREATER,
+
+	BC_EXPR_BOOL_NOT,
+
+	BC_EXPR_BOOL_OR,
+	BC_EXPR_BOOL_AND,
+
+	BC_EXPR_NUMBER,
+	BC_EXPR_VAR,
+	BC_EXPR_ARRAY_ELEM,
+
+	BC_EXPR_FUNC_CALL,
+
+	BC_EXPR_SCALE,
+	BC_EXPR_SCALE_FUNC,
+	BC_EXPR_IBASE,
+	BC_EXPR_OBASE,
+	BC_EXPR_LAST,
+	BC_EXPR_LENGTH,
+	BC_EXPR_READ,
+	BC_EXPR_SQRT,
+
+	BC_EXPR_PRINT,
+
+} BcExprType;
+
+typedef enum BcStmtType {
+
+	BC_STMT_EXPR,
+
+	BC_STMT_STRING,
+
+	BC_STMT_BREAK,
+	BC_STMT_CONTINUE,
+
+	BC_STMT_HALT,
+
+	BC_STMT_RETURN,
+
+	BC_STMT_IF,
+	BC_STMT_WHILE,
+
+	BC_STMT_LIST,
+
+} BcStmtType;
+
+typedef struct BcCall {
+
+	char* name;
+	BcSegArray params;
+
+} BcCall;
+
+typedef struct BcExpr {
+
+	BcExprType type;
+	union {
+		char* string;
+		BcStack* expr_stack;
+		BcCall* call;
+	};
+
+} BcExpr;
+
+typedef struct BcStmtList BcStmtList;
+
+typedef struct BcIf {
+
+	BcStack cond;
+	BcStmtList* then_list;
+	BcStmtList* else_list;
+
+} BcIf;
+
+typedef struct BcWhile {
+
+	BcStack cond;
+	BcStmtList* body;
+
+} BcWhile;
+
+typedef struct BcFor {
+
+	BcStmtList* body;
+	BcStack cond;
+	BcStack update;
+	BcStack init;
+
+} BcFor;
+
+typedef union BcStmtData {
+
+	char* string;
+	BcStmtList* list;
+	BcStack* expr_stack;
+	BcIf* if_stmt;
+	BcWhile* while_stmt;
+	BcFor* for_stmt;
+
+} BcStmtData;
+
+typedef struct BcStmt {
+
+	BcStmtType type;
+	BcStmtData data;
+
+} BcStmt;
+
+typedef struct BcStmtList {
+
+	struct BcStmtList* next;
+
+	uint32_t num_stmts;
+
+	BcStmt stmts[BC_PROGRAM_MAX_STMTS];
+
+} BcStmtList;
+
+typedef struct BcAuto {
+
+	char* name;
+	bool var;
+
+} BcAuto;
+
+typedef struct BcFunc {
+
+	char* name;
+
+	BcStmtList* first;
+
+	BcStmtList* cur;
+
+	BcAuto* params;
+	uint32_t num_params;
+	uint32_t param_cap;
+
+	BcAuto* autos;
+	uint32_t num_autos;
+	uint32_t auto_cap;
+
+} BcFunc;
+
+typedef struct BcVar {
+
+	char* name;
+
+	fxdpnt* data;
+
+} BcVar;
+
+/**
+ * An array.
+ */
+typedef struct BcArray {
+
+	char* name;
+
+	BcSegArray array;
+
+} BcArray;
+
+typedef struct BcProgram {
+
+	const char* file;
+
+	BcStmtList* first;
+
+	BcStmtList* cur;
+
+	BcSegArray funcs;
+
+	BcSegArray vars;
+
+	BcSegArray arrays;
+
+} BcProgram;
+
+BcStatus bc_program_init(BcProgram* p, const char* file);
+BcStatus bc_program_list_insert(BcStmtList* list, BcStmt* stmt);
+BcStatus bc_program_func_add(BcProgram* p, BcFunc* func);
+BcStatus bc_program_var_add(BcProgram* p, BcVar* var);
+BcStatus bc_program_array_add(BcProgram* p, BcArray* array);
+BcStatus bc_program_exec(BcProgram* p);
+void bc_program_free(BcProgram* program);
+
+BcStmtList* bc_program_list_create();
+void bc_program_list_free(BcStmtList* list);
+
+BcStatus bc_program_func_init(BcFunc* func, char* name);
+BcStatus bc_program_func_insertParam(BcFunc* func, char* name, bool var);
+BcStatus bc_program_func_insertAuto(BcFunc* func, char* name, bool var);
+BcStatus bc_program_var_init(BcVar* var, char* name);
+BcStatus bc_program_array_init(BcArray* array, char* name);
+
+BcStatus bc_program_stmt_init(BcStmt* stmt);
+
+#endif // BC_PROGRAM_H
diff --git a/bc/include/bc/segarray.h b/bc/include/bc/segarray.h
new file mode 100644
index 0000000..7b72f9f
--- /dev/null
+++ b/bc/include/bc/segarray.h
@@ -0,0 +1,55 @@
+#ifndef BC_SEGARRAY_H
+#define BC_SEGARRAY_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "stack.h"
+
+#define BC_SEGARRAY_NUM_ARRAYS (32)
+
+#define BC_SEGARRAY_SEG_POWER (10)
+
+#define BC_SEGARRAY_SEG_SIZE (1 << BC_SEGARRAY_SEG_POWER)
+
+#define BC_SEGARRAY_SEG_LAST (BC_SEGARRAY_SEG_SIZE - 1)
+
+#define BC_SEGARRAY_SEG_IDX2_MASK (BC_SEGARRAY_SEG_SIZE - 1)
+
+#define BC_SEGARRAY_SEG_IDX1_MASK (~BC_SEGARRAY_SEG_IDX2_MASK)
+
+#define BC_SEGARRAY_IDX1(idx)  \
+	(((idx) & BC_SEGARRAY_SEG_IDX1_MASK) >> BC_SEGARRAY_SEG_POWER)
+
+#define BC_SEGARRAY_IDX2(idx) ((idx) & BC_SEGARRAY_SEG_IDX2_MASK)
+
+#define BC_SEGARRAY_MAX (BC_SEGARRAY_NUM_ARRAYS << (BC_SEGARRAY_SEG_POWER))
+
+typedef void (*BcSegArrayFreeFunc)(void*);
+typedef int (*BcSegArrayCmpFunc)(void*, void*);
+
+typedef struct BcSegArray {
+
+	size_t esize;
+	uint32_t num;
+	uint32_t num_ptrs;
+	uint32_t ptr_cap;
+	uint8_t** ptrs;
+	BcSegArrayCmpFunc cmp;
+	BcSegArrayFreeFunc sfree;
+
+} BcSegArray;
+
+BcStatus bc_segarray_init(BcSegArray* sa, size_t esize, BcSegArrayFreeFunc sfree, BcSegArrayCmpFunc cmp);
+
+BcStatus bc_segarray_add(BcSegArray* sa, void* data);
+
+void* bc_segarray_item(BcSegArray* sa, uint32_t idx);
+
+void* bc_segarray_item2(BcSegArray* sa, uint32_t idx1, uint32_t idx2);
+
+uint32_t bc_segarray_find(BcSegArray* sa, void* data);
+
+void bc_segarray_free(BcSegArray* sa);
+
+#endif // BC_SEGARRAY_H
diff --git a/bc/include/bc/stack.h b/bc/include/bc/stack.h
new file mode 100644
index 0000000..c7a87bf
--- /dev/null
+++ b/bc/include/bc/stack.h
@@ -0,0 +1,32 @@
+#ifndef BC_STACK_H
+#define BC_STACK_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "bc.h"
+
+#define BC_STACK_START (16)
+
+typedef struct BcStack {
+
+	size_t size;
+	uint8_t* stack;
+	uint32_t len;
+	uint32_t cap;
+
+} BcStack;
+
+BcStatus bc_stack_init(BcStack* stack, size_t esize);
+
+BcStatus bc_stack_push(BcStack* stack, void* data);
+
+void* bc_stack_top(BcStack* stack);
+
+void* bc_stack_item(BcStack* stack, uint32_t idx);
+
+BcStatus bc_stack_pop(BcStack* stack);
+
+void bc_stack_free(void* stack);
+
+#endif // BC_STACK_H
diff --git a/bc/include/bc/vm.h b/bc/include/bc/vm.h
new file mode 100644
index 0000000..e1f5976
--- /dev/null
+++ b/bc/include/bc/vm.h
@@ -0,0 +1,28 @@
+#ifndef BC_VM_H
+#define BC_VM_H
+
+#include "program.h"
+#include "stack.h"
+#include "parse.h"
+
+#define BC_VM_BUF_SIZE (1024)
+
+typedef struct BcVm {
+
+	BcProgram program;
+	BcParse parse;
+
+	BcStack ctx_stack;
+
+	int filec;
+	const char** filev;
+
+} BcVm;
+
+BcStatus bc_vm_init(BcVm* vm, int filec, const char* filev[]);
+
+BcStatus bc_vm_exec(BcVm* vm);
+
+void bc_vm_free(BcVm* vm);
+
+#endif // BC_VM_H
diff --git a/bc/src/error.c b/bc/src/error.c
new file mode 100644
index 0000000..75f9129
--- /dev/null
+++ b/bc/src/error.c
@@ -0,0 +1,90 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bc.h"
+
+static const char* const bc_err_types[] = {
+
+    NULL,
+
+    "bc",
+    "bc",
+    "bc",
+
+    "runtime",
+    "runtime",
+    "runtime",
+    "runtime",
+    "runtime",
+    "runtime",
+
+    "lex",
+    "lex",
+    "lex",
+    "lex",
+
+    "parse",
+    "parse",
+    "parse",
+    "parse",
+    "parse",
+    "parse",
+
+};
+
+static const char* const bc_err_descs[] = {
+
+    NULL,
+
+    "invalid option",
+
+    "memory allocation error",
+    "invalid parameter",
+
+    "couldn't open file"
+    "file read error",
+    "divide by zero",
+    "negative square root",
+    "mismatched parameters",
+    "undefined function",
+
+    "invalid token",
+    "string end could not be found",
+    "comment end could not be found",
+    "end of file",
+
+    "invalid token",
+    "invalid expression",
+    "invalid print statement",
+    "invalid function definition",
+    "end of file",
+    "bug in parser",
+
+};
+
+void bc_error(BcStatus status) {
+
+	if (!status) {
+		return;
+	}
+
+	fprintf(stderr, "%s error: %s\n", bc_err_types[status], bc_err_descs[status]);
+}
+
+void bc_error_file(const char* file, uint32_t line, BcStatus status) {
+
+	if (!status || !file) {
+		return;
+	}
+
+	fprintf(stderr, "%s error: %s\n", bc_err_types[status], bc_err_descs[status]);
+	fprintf(stderr, "    %s", file);
+
+	if (line) {
+		fprintf(stderr, ":%d\n", line);
+	}
+	else {
+		fputc('\n', stderr);
+	}
+}
diff --git a/bc/src/lex.c b/bc/src/lex.c
new file mode 100644
index 0000000..ca7a6c5
--- /dev/null
+++ b/bc/src/lex.c
@@ -0,0 +1,819 @@
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bc.h"
+#include "lex.h"
+
+static const char* const token_type_strs[] = {
+    BC_LEX_TOKEN_FOREACH(BC_LEX_GEN_STR)
+};
+
+static const char* const keywords[] = {
+
+    "auto",
+    "break",
+    "continue",
+    "define",
+    "else",
+    "for",
+    "halt",
+    "ibase",
+    "if",
+    "last",
+    "length",
+    "limits",
+    "obase",
+    "print",
+    "quit",
+    "read",
+    "return",
+    "scale",
+    "sqrt",
+    "while",
+
+};
+
+static const uint32_t keyword_lens[] = {
+
+    4, // auto
+    5, // break
+    8, // continue
+    6, // define
+    4, // else
+    3, // for
+    4, // halt
+    5, // ibase
+    2, // if
+    4, // last
+    6, // length
+    6, // limits
+    5, // obase
+    5, // print
+    4, // quit
+    4, // read
+    6, // return
+    5, // scale
+    4, // sqrt
+    5, // while
+
+};
+
+static BcStatus bc_lex_token(BcLex* lex, BcLexToken* token);
+static BcStatus bc_lex_whitespace(BcLex* lex, BcLexToken* token);
+static BcStatus bc_lex_string(BcLex* lex, BcLexToken* token);
+static BcStatus bc_lex_comment(BcLex* lex, BcLexToken* token);
+static BcStatus bc_lex_number(BcLex* lex, BcLexToken* token, char start);
+static BcStatus bc_lex_name(BcLex* lex, BcLexToken* token);
+
+BcStatus bc_lex_printToken(BcLexToken* token) {
+
+	// Print the type.
+	printf("<%s", token_type_strs[token->type]);
+
+	// Figure out if more needs to be done.
+	switch (token->type) {
+
+		case BC_LEX_STRING:
+		case BC_LEX_NAME:
+		case BC_LEX_NUMBER:
+			printf(":%s", token->string);
+			break;
+
+		default:
+			break;
+	}
+
+	// Print the end.
+	putchar('>');
+	putchar('\n');
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_lex_init(BcLex* lex) {
+
+	if (lex == NULL ) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	lex->line = 1;
+	lex->newline = false;
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_lex_text(BcLex* lex, const char* text) {
+
+	if (lex == NULL || text == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	lex->buffer = text;
+	lex->idx = 0;
+	lex->len = strlen(text);
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_lex_next(BcLex* lex, BcLexToken* token) {
+
+	BcStatus status;
+
+	if (lex == NULL || token == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	if (lex->idx == lex->len) {
+		token->type = BC_LEX_EOF;
+		return BC_STATUS_LEX_EOF;
+	}
+
+	if (lex->newline) {
+		++lex->line;
+		lex->newline = false;
+	}
+
+	// Loop until failure or we don't have whitespace. This
+	// is so the parser doesn't get inundated with whitespace.
+	do {
+		status = bc_lex_token(lex, token);
+	} while (!status && token->type == BC_LEX_WHITESPACE);
+
+	return status;
+}
+
+static BcStatus bc_lex_token(BcLex* lex, BcLexToken* token) {
+
+	// We want to make sure this is cleared.
+	BcStatus status = BC_STATUS_SUCCESS;
+
+	// Get the character.
+	char c = lex->buffer[lex->idx];
+
+	// Increment the index.
+	++lex->idx;
+
+	char c2;
+
+	// This is the workhorse of the lexer.
+	switch (c) {
+
+		case '\0':
+		{
+			token->type = BC_LEX_EOF;
+			break;
+		}
+
+		case '\t':
+		{
+			status = bc_lex_whitespace(lex, token);
+			break;
+		}
+
+		case '\n':
+		{
+			lex->newline = true;
+			token->type = BC_LEX_NEWLINE;
+			break;
+		}
+
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+		{
+			status = bc_lex_whitespace(lex, token);
+			break;
+		}
+
+		case '!':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// The only valid way to have a bang is a NOT_EQ token.
+			// If it's not valid, we do not want to increment twice.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_REL_NOT_EQ;
+			}
+			else {
+				token->type = BC_LEX_OP_BOOL_NOT;
+			}
+
+			break;
+		}
+
+		case '"':
+		{
+			status = bc_lex_string(lex, token);
+			break;
+		}
+
+		case '%':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_MODULUS;
+			}
+			else {
+				token->type = BC_LEX_OP_MODULUS;
+			}
+
+			break;
+		}
+
+		case '&':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '&') {
+				++lex->idx;
+				token->type = BC_LEX_OP_BOOL_AND;
+			}
+			else {
+				token->type = BC_LEX_INVALID;
+				status = BC_STATUS_LEX_INVALID_TOKEN;
+			}
+
+			break;
+		}
+
+		case '(':
+		{
+			token->type = BC_LEX_LEFT_PAREN;
+			break;
+		}
+
+		case ')':
+		{
+			token->type = BC_LEX_RIGHT_PAREN;
+			break;
+		}
+
+		case '*':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_MULTIPLY;
+			}
+			else {
+				token->type = BC_LEX_OP_MULTIPLY;
+			}
+
+			break;
+		}
+
+		case '+':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_PLUS;
+			}
+			else if (c2 == '+') {
+				++lex->idx;
+				token->type = BC_LEX_OP_INC;
+			}
+			else {
+				token->type = BC_LEX_OP_PLUS;
+			}
+
+			break;
+		}
+
+		case ',':
+		{
+			token->type = BC_LEX_COMMA;
+			break;
+		}
+
+		case '-':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			// We also need to handle numbers.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_MINUS;
+			}
+			else if (c2 == '-') {
+				++lex->idx;
+				token->type = BC_LEX_OP_DEC;
+			}
+			else {
+				token->type = BC_LEX_OP_MINUS;
+			}
+
+			break;
+		}
+
+		case '.':
+		{
+			status = bc_lex_number(lex, token, c);
+			break;
+		}
+
+		case '/':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			// We also need to handle comments.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_DIVIDE;
+			}
+			else if (c2 == '*') {
+				status = bc_lex_comment(lex, token);
+			}
+			else {
+				token->type = BC_LEX_OP_DIVIDE;
+			}
+
+			break;
+		}
+
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		{
+			status = bc_lex_number(lex, token, c);
+			break;
+		}
+
+		case ';':
+		{
+			token->type = BC_LEX_SEMICOLON;
+			break;
+		}
+
+		case '<':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or with an equals.
+			// If with an equals, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_REL_LESS_EQ;
+			}
+			else {
+				token->type = BC_LEX_OP_REL_LESS;
+			}
+
+			break;
+		}
+
+		case '=':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or with another equals.
+			// If with another equals, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_REL_EQUAL;
+			}
+			else {
+				token->type = BC_LEX_OP_ASSIGN;
+			}
+
+			break;
+		}
+
+		case '>':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or with an equals.
+			// If with an equals, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_REL_GREATER_EQ;
+			}
+			else {
+				token->type = BC_LEX_OP_REL_GREATER;
+			}
+
+			break;
+		}
+
+		case 'A':
+		case 'B':
+		case 'C':
+		case 'D':
+		case 'E':
+		case 'F':
+		{
+			status = bc_lex_number(lex, token, c);
+			break;
+		}
+
+		case '[':
+		{
+			token->type = BC_LEX_LEFT_BRACKET;
+			break;
+		}
+
+		case '\\':
+		{
+			status = bc_lex_whitespace(lex, token);
+			break;
+		}
+
+		case ']':
+		{
+			token->type = BC_LEX_RIGHT_BRACKET;
+			break;
+		}
+
+		case '^':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '=') {
+				++lex->idx;
+				token->type = BC_LEX_OP_ASSIGN_POWER;
+			}
+			else {
+				token->type = BC_LEX_OP_POWER;
+			}
+
+			break;
+		}
+
+		case 'a':
+		case 'b':
+		case 'c':
+		case 'd':
+		case 'e':
+		case 'f':
+		case 'g':
+		case 'h':
+		case 'i':
+		case 'j':
+		case 'k':
+		case 'l':
+		case 'm':
+		case 'n':
+		case 'o':
+		case 'p':
+		case 'q':
+		case 'r':
+		case 's':
+		case 't':
+		case 'u':
+		case 'v':
+		case 'w':
+		case 'x':
+		case 'y':
+		case 'z':
+		{
+			status = bc_lex_name(lex, token);
+			break;
+		}
+
+		case '{':
+		{
+			token->type = BC_LEX_LEFT_BRACE;
+			break;
+		}
+
+		case '|':
+		{
+			// Get the next character.
+			c2 = lex->buffer[lex->idx];
+
+			// This character can either be alone or as an assignment.
+			// If it's an assignment, we need to increment the index.
+			if (c2 == '|') {
+				++lex->idx;
+				token->type = BC_LEX_OP_BOOL_OR;
+			}
+			else {
+				token->type = BC_LEX_INVALID;
+				status = BC_STATUS_LEX_INVALID_TOKEN;
+			}
+
+			break;
+		}
+
+		case '}':
+		{
+			token->type = BC_LEX_RIGHT_BRACE;
+			break;
+		}
+
+		default:
+		{
+			// All other characters are invalid.
+			token->type = BC_LEX_INVALID;
+			status = BC_STATUS_LEX_INVALID_TOKEN;
+			break;
+		}
+	}
+
+	return status;
+}
+
+static BcStatus bc_lex_whitespace(BcLex* lex, BcLexToken* token) {
+
+	// Set the token type.
+	token->type = BC_LEX_WHITESPACE;
+
+	// Get the character.
+	char c = lex->buffer[lex->idx];
+
+	// Eat all whitespace (and non-newline) characters.
+	while ((isspace(c) && c != '\n') || c == '\\') {
+		++lex->idx;
+		c = lex->buffer[lex->idx];
+	}
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_lex_string(BcLex* lex, BcLexToken* token) {
+
+	// Set the token type.
+	token->type = BC_LEX_STRING;
+
+	// Get the starting index and character.
+	size_t i = lex->idx;
+	char c = lex->buffer[i];
+
+	// Find the end of the string, one way or the other.
+	while (c != '"' && c != '\0') {
+		c = lex->buffer[++i];
+	}
+
+	// If we have reached the end of the buffer, complain.
+	if (c == '\0') {
+		lex->idx = i;
+		return BC_STATUS_LEX_NO_STRING_END;
+	}
+
+	// Calculate the length of the string.
+	size_t len = i - lex->idx;
+
+	// Figure out the number of backslash newlines in a string.
+	size_t backslashes = 0;
+	for (size_t j = lex->idx; j < i; ++j) {
+		c = lex->buffer[j];
+		backslashes += c == '\\' && lex->buffer[j + 1] == '\n' ? 1 : 0;
+	}
+
+	// Allocate the string.
+	token->string = malloc(len - backslashes + 1);
+
+	// Check for error.
+	if (token->string == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	// The copy start and the number of backslash
+	// hits. These are for the upcoming loop.
+	const char* start = lex->buffer + lex->idx;
+	size_t hits = 0;
+
+	// Copy the string.
+	for (size_t j = 0; j < len; ++j) {
+
+		// Get the character.
+		char c = start[j];
+
+		// If we have hit a backslash, skip it.
+		if (hits < backslashes && c == '\\' && start[j + 1] == '\n') {
+			++hits;
+			continue;
+		}
+
+		// Copy the character.
+		token->string[j - hits] = c;
+	}
+
+	// Make sure to set the null character.
+	token->string[len] = '\0';
+
+	// Set the index. We need to go one
+	// past because of the closing quote.
+	lex->idx = i + 1;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_lex_comment(BcLex* lex, BcLexToken* token) {
+
+	// Set the token type.
+	token->type = BC_LEX_WHITESPACE;
+
+	// Increment the index.
+	++lex->idx;
+
+	// Get the starting index and character.
+	size_t i = lex->idx;
+	const char* buffer = lex->buffer;
+	char c = buffer[i];
+
+	// The end condition.
+	int end = 0;
+
+	// Loop until we have found the end.
+	while (!end) {
+
+		// Find the end of the string, one way or the other.
+		while (c != '*' && c != '\0') {
+			c = buffer[++i];
+		}
+
+		// If we've reached the end of the string,
+		// but not the comment, complain.
+		if (c == '\0' || buffer[i + 1] == '\0') {
+			lex->idx = i;
+			return BC_STATUS_LEX_NO_COMMENT_END;
+		}
+
+		// If we've reached the end, set the end.
+		end = buffer[i + 1] == '/';
+		i += end ? 0 : 1;
+	}
+
+	// Set the index. Plus 2 is to get past the comment end.
+	lex->idx = i + 2;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_lex_number(BcLex* lex, BcLexToken* token, char start) {
+
+	// Set the token type.
+	token->type = BC_LEX_NUMBER;
+
+	// Whether or not we already have passed a decimal point.
+	int point = start == '.';
+
+	// Get a pointer to the place in the buffer.
+	const char* buffer = lex->buffer + lex->idx;
+
+	// Cache these for the upcoming loop.
+	size_t backslashes = 0;
+	size_t i = 0;
+	char c = buffer[i];
+
+	// Find the end of the number.
+	while (c && (isdigit(c) || (c >= 'A' && c <= 'F') || (c == '.' && !point) ||
+	             (c == '\\' && buffer[i + 1] == '\n')))
+	{
+		// If we ran into a backslash, handle it.
+		if (c == '\\') {
+			++i;
+			backslashes += 1;
+		}
+
+		// Increment and get the character.
+		c = buffer[++i];
+	}
+
+	// Calculate the length of the string.
+	size_t len = i + 1;
+
+	// Allocate the string.
+	token->string = malloc(len - backslashes + 1);
+
+	// Check for error.
+	if (token->string == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	// Set the starting character.
+	token->string[0] = start;
+
+	// The copy start and the number of backslash
+	// hits. These are for the upcoming loop.
+	const char* buf = buffer - 1;
+	size_t hits = 0;
+
+	// Copy the string.
+	for (size_t j = 1; j < len; ++j) {
+
+		// Get the character.
+		char c = buf[j];
+
+		// If we have hit a backslash, skip it.
+		// We don't have to check for a newline
+		// because it's guaranteed.
+		if (hits < backslashes && c == '\\') {
+			++hits;
+			++j;
+			continue;
+		}
+
+		// Copy the character.
+		token->string[j - (hits * 2)] = c;
+	}
+
+	// Make sure to set the null character.
+	token->string[len] = '\0';
+
+	// Set the index. We need to go one
+	// past because of the closing quote.
+	lex->idx += i;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_lex_name(BcLex* lex, BcLexToken* token) {
+
+	// Get a pointer to the place in the buffer. We subtract
+	// one because the index is already incremented.
+	const char* buffer = lex->buffer + lex->idx - 1;
+
+	// Loop through the keywords.
+	for (uint32_t i = 0; i < sizeof(keywords) / sizeof(char*); ++i) {
+
+		// If a keyword matches, set it, increment, and return.
+		if (!strncmp(buffer, keywords[i], keyword_lens[i])) {
+
+			// We just need to add the starting
+			// index of keyword token types.
+			token->type = BC_LEX_KEY_AUTO + i;
+
+			// We need to minus one because the
+			// index has already been incremented.
+			lex->idx += keyword_lens[i] - 1;
+
+			return BC_STATUS_SUCCESS;
+		}
+	}
+
+	// Set the type.
+	token->type = BC_LEX_NAME;
+
+	// These are for the next loop.
+	size_t i = 0;
+	char c = buffer[i];
+
+	// Find the end of the name.
+	while (islower(c) || isdigit(c) || c == '_') {
+		++i;
+		c = buffer[i];
+	}
+
+	// Malloc the name.
+	token->string = malloc(i + 1);
+
+	// Check for error.
+	if (token->string == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	// Copy the string.
+	strncpy(token->string, buffer, i);
+	token->string[i] = '\0';
+
+	// Increment the index. It is minus one
+	// because it has already been incremented.
+	lex->idx += i - 1;
+
+	return BC_STATUS_SUCCESS;
+}
diff --git a/bc/src/parse.c b/bc/src/parse.c
new file mode 100644
index 0000000..3753641
--- /dev/null
+++ b/bc/src/parse.c
@@ -0,0 +1,1720 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "lex.h"
+#include "parse.h"
+
+// This is an array that corresponds to token types. An entry is
+// true if the token is valid in an expression, false otherwise.
+static const bool bc_token_exprs[] = {
+
+    true,
+    true,
+
+    true,
+
+    true,
+    true,
+    true,
+
+    true,
+    true,
+
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+
+    true,
+
+    true,
+    true,
+
+    false,
+
+    false,
+
+    true,
+    true,
+
+    false,
+    false,
+
+    false,
+    false,
+
+    false,
+    false,
+
+    false,
+    true,
+    true,
+
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    false,
+    true,
+    false,
+    true,
+    true,
+    true,
+    true,
+    false,
+    false,
+    true,
+    false,
+    true,
+    true,
+    false,
+
+    false,
+
+    false,
+};
+
+// This is an array of data for operators that correspond to token types.
+// The last corresponds to BC_PARSE_OP_NEGATE_IDX since it doesn't have
+// its own token type (it is the same token at the binary minus operator).
+static const BcOp bc_ops[] = {
+
+    { 0, false },
+    { 0, false },
+
+    { 2, false },
+
+    { 3, true },
+    { 3, true },
+    { 3, true },
+
+    { 4, true },
+    { 4, true },
+
+    { 5, false },
+    { 5, false },
+    { 5, false },
+    { 5, false },
+    { 5, false },
+    { 5, false },
+    { 5, false },
+
+    { 6, true },
+    { 6, true },
+    { 6, true },
+    { 6, true },
+    { 6, true },
+    { 6, true },
+
+    { 7, false },
+
+    { 8, true },
+    { 8, true },
+
+    { 1, false }
+
+};
+
+static BcStatus bc_parse_func(BcParse* parse, BcProgram* program);
+static BcStatus bc_parse_funcStart(BcParse* parse, BcFunc* func);
+static BcStatus bc_parse_semicolonList(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_semicolonListEnd(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_stmt(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_expr(BcParse* parse, BcStack** exprs);
+static BcStatus bc_parse_operator(BcStack* exs, BcStack* ops,BcLexTokenType t,
+                                  uint32_t* num_exprs);
+static BcStatus bc_parse_rightParen(BcStack* exs, BcStack* ops, uint32_t* nexs);
+static BcStatus bc_parse_expr_name(BcParse* parse, BcStack* exprs,
+                                   BcExprType* type);
+static BcStatus bc_parse_call(BcParse* parse, BcExpr* expr);
+static BcStatus bc_parse_params(BcParse* parse, BcExpr* expr);
+static BcStatus bc_parse_read(BcParse* parse, BcStack* exprs);
+static BcStatus bc_parse_builtin(BcParse* parse, BcStack* exs, BcExprType type);
+static BcStatus bc_parse_scale(BcParse* parse, BcStack* exs, BcExprType* type);
+static BcStatus bc_parse_incdec(BcParse* parse, BcStack* exs, BcExprType* prev);
+static BcStatus bc_parse_minus(BcParse* parse, BcStack* exs, BcStack* ops,
+                               BcExprType* prev, bool rparen, uint32_t* nexprs);
+static BcStatus bc_parse_string(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_string(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_string(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_return(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_print(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_if(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_while(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_for(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_loop(BcParse* parse, BcStmtList* list);
+static BcStatus bc_parse_startBody(BcParse* parse, BcStmtList** new_list,
+                                   uint16_t flags);
+static BcStatus bc_parse_loopExit(BcParse* parse, BcStmtList* list,
+                                  BcLexTokenType type);
+static BcStatus bc_parse_rightBrace(BcParse* parse, BcStmtList* list);
+
+BcStatus bc_parse_init(BcParse* parse, BcProgram* program) {
+
+	if (parse == NULL || program == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	parse->program = program;
+
+	BcStatus status = bc_stack_init(&parse->flag_stack, sizeof(uint16_t));
+
+	if (status != BC_STATUS_SUCCESS) {
+		return status;
+	}
+
+	status = bc_stack_init(&parse->ctx_stack, sizeof(BcStmtList*));
+
+	if (status != BC_STATUS_SUCCESS) {
+		return status;
+	}
+
+	uint16_t flags = 0;
+
+	status = bc_stack_push(&parse->flag_stack, &flags);
+	if (status != BC_STATUS_SUCCESS) {
+		return status;
+	}
+
+	status = bc_stack_push(&parse->ctx_stack, &program->first);
+
+	if (status) {
+		return status;
+	}
+
+	parse->func = NULL;
+	parse->num_braces = 0;
+
+	return bc_lex_init(&parse->lex);
+}
+
+BcStatus bc_parse_text(BcParse* parse, const char* text) {
+
+	if (parse == NULL || text == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	return bc_lex_text(&parse->lex, text);
+}
+
+BcStatus bc_parse_parse(BcParse* parse, BcProgram* program) {
+
+	BcStmtList** ptr;
+
+	if (parse == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	BcStatus status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status != BC_STATUS_SUCCESS) {
+		return status;
+	}
+
+	switch (parse->token.type) {
+
+		case BC_LEX_NEWLINE:
+		{
+			// We don't do anything if there is a newline.
+			break;
+		}
+
+		case BC_LEX_KEY_DEFINE:
+		{
+			if (!BC_PARSE_CAN_EXEC(parse)) {
+				return BC_STATUS_PARSE_INVALID_TOKEN;
+			}
+
+			status = bc_parse_func(parse, program);
+
+			break;
+		}
+
+		case BC_LEX_EOF:
+		{
+			status = BC_STATUS_PARSE_EOF;
+			break;
+		}
+
+		default:
+		{
+			ptr = bc_stack_top(&parse->ctx_stack);
+			status = bc_parse_stmt(parse, *ptr);
+			break;
+		}
+	}
+
+	return status;
+}
+
+void bc_parse_free(BcParse* parse) {
+
+	if (!parse) {
+		return;
+	}
+
+	bc_stack_free(&parse->flag_stack);
+	bc_stack_free(&parse->ctx_stack);
+
+	switch (parse->token.type) {
+
+		case BC_LEX_STRING:
+		case BC_LEX_NAME:
+		case BC_LEX_NUMBER:
+		{
+			if (parse->token.string) {
+				free(parse->token.string);
+			}
+
+			break;
+		}
+
+		default:
+		{
+			// We don't have have to free anything.
+			break;
+		}
+	}
+}
+
+static BcStatus bc_parse_func(BcParse* parse, BcProgram* program) {
+
+	BcLexTokenType type;
+	BcStatus status;
+	BcFunc func;
+	bool comma;
+	uint16_t flags;
+	char* name;
+	bool var;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_NAME) {
+		return BC_STATUS_PARSE_INVALID_FUNC;
+	}
+
+	status = bc_program_func_init(&func, parse->token.string);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_LEFT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_FUNC;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	comma = false;
+
+	type = parse->token.type;
+
+	while (!status && type != BC_LEX_RIGHT_PAREN) {
+
+		if (type != BC_LEX_NAME) {
+			return BC_STATUS_PARSE_INVALID_FUNC;
+		}
+
+		name = parse->token.string;
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			break;
+		}
+
+		if (parse->token.type == BC_LEX_LEFT_BRACKET) {
+
+			status = bc_lex_next(&parse->lex, &parse->token);
+
+			if (status) {
+				break;
+			}
+
+			if (parse->token.type != BC_LEX_RIGHT_BRACKET) {
+				return BC_STATUS_PARSE_INVALID_FUNC;
+			}
+
+			status = bc_lex_next(&parse->lex, &parse->token);
+
+			if (status) {
+				break;
+			}
+
+			var = false;
+		}
+		else {
+			var = true;
+		}
+
+		if (parse->token.type == BC_LEX_COMMA) {
+			comma = true;
+			status = bc_lex_next(&parse->lex, &parse->token);
+		}
+		else {
+			comma = false;
+		}
+
+		status = bc_program_func_insertParam(&func, name, var);
+
+		if (status) {
+			return status;
+		}
+
+		type = parse->token.type;
+	}
+
+	if (status) {
+		return status;
+	}
+
+	if (comma) {
+		return BC_STATUS_PARSE_INVALID_FUNC;
+	}
+
+	flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_HEADER;
+	status = bc_stack_push(&parse->flag_stack, &flags);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_stack_push(&parse->ctx_stack, &func.first);
+
+	parse->func = bc_segarray_item(&program->funcs, program->funcs.num - 1);
+
+	if (!parse->func) {
+		return BC_STATUS_PARSE_BUG;
+	}
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_parse_funcStart(BcParse* parse, BcFunc* func) {
+
+	// TODO: Write this function.
+
+}
+
+static BcStatus bc_parse_semicolonList(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status = BC_STATUS_SUCCESS;
+
+	switch (parse->token.type) {
+
+		case BC_LEX_OP_INC:
+		case BC_LEX_OP_DEC:
+		case BC_LEX_OP_MINUS:
+		case BC_LEX_OP_BOOL_NOT:
+		case BC_LEX_NEWLINE:
+		case BC_LEX_LEFT_PAREN:
+		{
+			status = bc_parse_stmt(parse, list);
+			break;
+		}
+
+		case BC_LEX_SEMICOLON:
+		{
+			status = bc_parse_semicolonListEnd(parse, list);
+			break;
+		}
+
+		case BC_LEX_STRING:
+		case BC_LEX_NAME:
+		case BC_LEX_NUMBER:
+		case BC_LEX_KEY_BREAK:
+		case BC_LEX_KEY_CONTINUE:
+		case BC_LEX_KEY_FOR:
+		case BC_LEX_KEY_HALT:
+		case BC_LEX_KEY_IBASE:
+		case BC_LEX_KEY_IF:
+		case BC_LEX_KEY_LAST:
+		case BC_LEX_KEY_LENGTH:
+		case BC_LEX_KEY_OBASE:
+		case BC_LEX_KEY_PRINT:
+		{
+			status = bc_parse_stmt(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_LIMITS:
+		{
+			// TODO: Print limits and get next token.
+			// Limit is a compile-time command.
+			break;
+		}
+
+		case BC_LEX_KEY_QUIT:
+		{
+			// Quit is a compile-time command,
+			// so we just do it.
+			exit(status);
+			break;
+		}
+
+		case BC_LEX_KEY_READ:
+		case BC_LEX_KEY_RETURN:
+		case BC_LEX_KEY_SCALE:
+		case BC_LEX_KEY_SQRT:
+		case BC_LEX_KEY_WHILE:
+		{
+			status = bc_parse_stmt(parse, list);
+			break;
+		}
+
+		case BC_LEX_EOF:
+		{
+			if (parse->ctx_stack.len > 0) {
+				status = BC_STATUS_PARSE_INVALID_TOKEN;
+			}
+
+			break;
+		}
+
+		default:
+		{
+			status = BC_STATUS_PARSE_INVALID_TOKEN;
+			break;
+		}
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_semicolonListEnd(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+
+	if (parse->token.type == BC_LEX_SEMICOLON) {
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_parse_semicolonList(parse, list);
+	}
+	else if (parse->token.type == BC_LEX_NEWLINE) {
+		status = BC_STATUS_SUCCESS;
+	}
+	else {
+		status = BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_stmt(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+	BcStmt stmt;
+	uint16_t* flag_ptr;
+
+	status = BC_STATUS_SUCCESS;
+
+	switch (parse->token.type) {
+
+		case BC_LEX_OP_INC:
+		case BC_LEX_OP_DEC:
+		case BC_LEX_OP_MINUS:
+		case BC_LEX_OP_BOOL_NOT:
+		case BC_LEX_LEFT_PAREN:
+		case BC_LEX_NAME:
+		case BC_LEX_NUMBER:
+		case BC_LEX_KEY_IBASE:
+		case BC_LEX_KEY_LAST:
+		case BC_LEX_KEY_LENGTH:
+		case BC_LEX_KEY_OBASE:
+		case BC_LEX_KEY_READ:
+		case BC_LEX_KEY_SCALE:
+		case BC_LEX_KEY_SQRT:
+		{
+			status = bc_parse_expr(parse, &stmt.data.expr_stack);
+			break;
+		}
+
+		case BC_LEX_NEWLINE:
+		{
+			// Do nothing.
+			break;
+		}
+
+		case BC_LEX_LEFT_BRACE:
+		{
+			stmt.type = BC_STMT_LIST;
+			++parse->num_braces;
+
+			if (BC_PARSE_HEADER(parse)) {
+
+				flag_ptr = bc_stack_top(&parse->flag_stack);
+				*flag_ptr = *flag_ptr & ~(BC_PARSE_FLAG_HEADER);
+
+				if (BC_PARSE_FUNC_INNER(parse)) {
+					status = bc_parse_funcStart(parse, parse->func);
+				}
+				else if (BC_PARSE_FOR_LOOP(parse)) {
+					status = bc_parse_for(parse, list);
+				}
+				else if (BC_PARSE_WHILE_LOOP(parse)) {
+					status = bc_parse_while(parse, list);
+				}
+				else if (BC_PARSE_IF(parse)) {
+					status = bc_parse_if(parse, list);
+				}
+			}
+			else {
+				status = bc_parse_startBody(parse, &stmt.data.list, 0);
+			}
+
+			break;
+		}
+
+		case BC_LEX_RIGHT_BRACE:
+		{
+			status = bc_parse_rightBrace(parse, list);
+			break;
+		}
+
+		case BC_LEX_STRING:
+		{
+			status = bc_parse_string(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_BREAK:
+		case BC_LEX_KEY_CONTINUE:
+		{
+			status = bc_parse_loopExit(parse, list, parse->token.type);
+			break;
+		}
+
+		case BC_LEX_KEY_FOR:
+		{
+			status = bc_parse_for(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_HALT:
+		{
+			BcStmt stmt;
+
+			stmt.type = BC_STMT_HALT;
+			bc_program_list_insert(list, &stmt);
+
+			status = bc_lex_next(&parse->lex, &parse->token);
+
+			if (status) {
+				return status;
+			}
+
+			status = bc_parse_semicolonListEnd(parse, list);
+
+			break;
+		}
+
+		case BC_LEX_KEY_IF:
+		{
+			status = bc_parse_if(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_PRINT:
+		{
+			status = bc_parse_print(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_RETURN:
+		{
+			status = bc_parse_return(parse, list);
+			break;
+		}
+
+		case BC_LEX_KEY_WHILE:
+		{
+			status = bc_parse_while(parse, list);
+			break;
+		}
+
+		default:
+		{
+			status = BC_STATUS_PARSE_INVALID_TOKEN;
+			break;
+		}
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_expr(BcParse* parse, BcStack** exprs) {
+
+	BcStatus status;
+	BcStack ops;
+	BcExpr expr;
+	uint32_t nexprs;
+	uint32_t num_parens;
+	bool paren_first;
+	bool paren_expr;
+	bool rparen;
+	bool done;
+	BcExprType prev;
+	BcLexTokenType type;
+	BcLexTokenType* ptr;
+	BcLexTokenType top;
+	BcStack* stack;
+
+	prev = BC_EXPR_PRINT;
+
+	paren_first = parse->token.type == BC_LEX_LEFT_PAREN;
+	num_parens = paren_first ? 1 : 0;
+
+	stack = malloc(sizeof(BcStack));
+
+	if (!stack) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	status = bc_stack_init(stack, sizeof(BcExpr));
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_stack_init(&ops, sizeof(BcLexTokenType));
+
+	if (status) {
+		return status;
+	}
+
+	nexprs = 0;
+	paren_expr = false;
+	rparen = false;
+	done = false;
+
+	type = parse->token.type;
+
+	while (!status && !done && bc_token_exprs[type]) {
+
+		switch (type) {
+
+			case BC_LEX_OP_INC:
+			case BC_LEX_OP_DEC:
+			{
+				status = bc_parse_incdec(parse, stack, &prev);
+				rparen = false;
+				break;
+			}
+
+			case BC_LEX_OP_MINUS:
+			{
+				status = bc_parse_minus(parse, stack, &ops, &prev,
+				                        rparen, &nexprs);
+				rparen = false;
+				break;
+			}
+
+			case BC_LEX_OP_POWER:
+			case BC_LEX_OP_MULTIPLY:
+			case BC_LEX_OP_DIVIDE:
+			case BC_LEX_OP_MODULUS:
+			case BC_LEX_OP_PLUS:
+			case BC_LEX_OP_ASSIGN:
+			case BC_LEX_OP_ASSIGN_PLUS:
+			case BC_LEX_OP_ASSIGN_MINUS:
+			case BC_LEX_OP_ASSIGN_MULTIPLY:
+			case BC_LEX_OP_ASSIGN_DIVIDE:
+			case BC_LEX_OP_ASSIGN_MODULUS:
+			case BC_LEX_OP_ASSIGN_POWER:
+			case BC_LEX_OP_REL_EQUAL:
+			case BC_LEX_OP_REL_LESS_EQ:
+			case BC_LEX_OP_REL_GREATER_EQ:
+			case BC_LEX_OP_REL_NOT_EQ:
+			case BC_LEX_OP_REL_LESS:
+			case BC_LEX_OP_REL_GREATER:
+			case BC_LEX_OP_BOOL_NOT:
+				// TODO: Handle these specially.
+				// We may not have to though...
+			case BC_LEX_OP_BOOL_OR:
+			case BC_LEX_OP_BOOL_AND:
+			{
+				prev = BC_PARSE_TOKEN_TO_EXPR(type);
+				status = bc_parse_operator(stack, &ops, type, &nexprs);
+				rparen = false;
+				break;
+			}
+
+			case BC_LEX_LEFT_PAREN:
+			{
+				++num_parens;
+				paren_expr = false;
+				rparen = false;
+				status = bc_stack_push(&ops, &type);
+				break;
+			}
+
+			case BC_LEX_RIGHT_PAREN:
+			{
+				if (num_parens == 0) {
+					status = nexprs != 1 ? BC_STATUS_PARSE_INVALID_EXPR :
+					                       BC_STATUS_SUCCESS;
+					done = true;
+				}
+				else if (!paren_expr) {
+					return BC_STATUS_PARSE_INVALID_EXPR;
+				}
+
+				paren_expr = true;
+				rparen = true;
+
+				status = bc_parse_rightParen(stack, &ops, &nexprs);
+
+				break;
+			}
+
+			case BC_LEX_NAME:
+			{
+				paren_expr = true;
+				rparen = false;
+				status = bc_parse_expr_name(parse, stack, &prev);
+				++nexprs;
+				break;
+			}
+
+			case BC_LEX_NUMBER:
+			{
+				expr.type = BC_EXPR_NUMBER;
+				expr.string = parse->token.string;
+				status = bc_stack_push(stack, &expr);
+
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_NUMBER;
+
+				break;
+			}
+
+			case BC_LEX_KEY_IBASE:
+			{
+				expr.type = BC_EXPR_IBASE;
+				status = bc_stack_push(stack, &expr);
+
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_IBASE;
+
+				break;
+			}
+
+			case BC_LEX_KEY_LENGTH:
+			{
+				status = bc_parse_builtin(parse, stack, BC_EXPR_LENGTH);
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_LENGTH;
+				break;
+			}
+
+			case BC_LEX_KEY_OBASE:
+			{
+				expr.type = BC_EXPR_OBASE;
+				status = bc_stack_push(stack, &expr);
+
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_OBASE;
+
+				break;
+			}
+
+			case BC_LEX_KEY_READ:
+			{
+				status = bc_parse_read(parse, stack);
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_READ;
+				break;
+			}
+
+			case BC_LEX_KEY_SCALE:
+			{
+				status = bc_parse_scale(parse, stack, &prev);
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_SCALE;
+				break;
+			}
+
+			case BC_LEX_KEY_SQRT:
+			{
+				status = bc_parse_builtin(parse, stack, BC_EXPR_SQRT);
+				paren_expr = true;
+				rparen = false;
+				++nexprs;
+				prev = BC_EXPR_SQRT;
+				break;
+			}
+
+			default:
+			{
+				status = BC_STATUS_PARSE_INVALID_TOKEN;
+				break;
+			}
+		}
+
+		type = parse->token.type;
+	}
+
+	if (status) {
+		return status;
+	}
+
+	while (!status && ops.len > 0) {
+
+		ptr = bc_stack_top(&ops);
+		top = *ptr;
+
+		if (top == BC_LEX_LEFT_PAREN || top == BC_LEX_RIGHT_PAREN) {
+			return BC_STATUS_PARSE_INVALID_EXPR;
+		}
+
+		expr.type = BC_PARSE_TOKEN_TO_EXPR(top);
+
+		status = bc_stack_push(stack, &expr);
+
+		if (status) {
+			return status;
+		}
+
+		nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_OP_NEGATE ? 1 : 0;
+
+		status = bc_stack_pop(&ops);
+	}
+
+	if (nexprs != 1) {
+		return BC_STATUS_PARSE_INVALID_EXPR;
+	}
+
+	expr.type = ((BcExpr*) bc_stack_top(stack))->type;
+
+	if (expr.type < BC_EXPR_ASSIGN ||
+	    expr.type > BC_EXPR_ASSIGN_POWER ||
+	    paren_first)
+	{
+		expr.type = BC_EXPR_PRINT;
+		status = bc_stack_push(stack, &expr);
+	}
+
+	*exprs = stack;
+
+	return status;
+}
+
+static BcStatus bc_parse_operator(BcStack* exs, BcStack* ops, BcLexTokenType t,
+                                  uint32_t* num_exprs)
+{
+	BcExpr expr;
+	BcStatus status;
+	BcLexTokenType top;
+	BcLexTokenType* ptr;
+	uint8_t lp;
+	uint8_t rp;
+	bool rleft;
+
+	rp = bc_ops[t].prec;
+	rleft = bc_ops[t].left;
+
+	if (ops->len != 0) {
+
+		ptr = bc_stack_top(ops);
+		top = *ptr;
+		lp = bc_ops[top].prec;
+
+		while (top != BC_LEX_LEFT_PAREN && (lp < rp || (lp == rp && rleft))) {
+
+			expr.type = BC_PARSE_TOKEN_TO_EXPR(top);
+
+			status = bc_stack_push(exs, &expr);
+
+			if (status) {
+				return status;
+			}
+
+			status = bc_stack_pop(ops);
+
+			if (status) {
+				return status;
+			}
+
+			*num_exprs -= top != BC_LEX_OP_BOOL_NOT &&
+			              top != BC_LEX_OP_NEGATE ? 1 : 0;
+
+			if (ops->len == 0) {
+				break;
+			}
+
+			ptr = bc_stack_top(ops);
+			top = *ptr;
+			lp = bc_ops[top].prec;
+		}
+	}
+
+	return bc_stack_push(ops, &t);
+}
+
+static BcStatus bc_parse_rightParen(BcStack* exs, BcStack* ops, uint32_t* nexs)
+{
+	BcStatus status;
+	BcExpr expr;
+	BcLexTokenType top;
+	BcLexTokenType* ptr;
+
+	if (ops->len == 0) {
+		return BC_STATUS_PARSE_INVALID_EXPR;
+	}
+
+	ptr = bc_stack_top(ops);
+	top = *ptr;
+
+	while (top != BC_LEX_LEFT_PAREN) {
+
+		expr.type = BC_PARSE_TOKEN_TO_EXPR(top);
+
+		status = bc_stack_push(exs, &expr);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_stack_pop(ops);
+
+		if (status) {
+			return status;
+		}
+
+		*nexs -= top != BC_LEX_OP_BOOL_NOT &&
+		         top != BC_LEX_OP_NEGATE ? 1 : 0;
+
+		if (ops->len == 0) {
+			return BC_STATUS_PARSE_INVALID_EXPR;
+		}
+
+		ptr = bc_stack_top(ops);
+		top = *ptr;
+	}
+
+	return bc_stack_pop(ops);
+}
+
+static BcStatus bc_parse_expr_name(BcParse* parse, BcStack* exprs,
+                                   BcExprType* type)
+{
+	BcStatus status;
+	BcStack* stack;
+	BcExpr expr;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type == BC_LEX_LEFT_BRACKET) {
+
+		expr.type = BC_EXPR_ARRAY_ELEM;
+		*type = BC_EXPR_ARRAY_ELEM;
+		expr.string = parse->token.string;
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_parse_expr(parse, &stack);
+
+		if (status) {
+			return status;
+		}
+
+		if (parse->token.type != BC_LEX_RIGHT_BRACKET) {
+			return BC_STATUS_PARSE_INVALID_TOKEN;
+		}
+	}
+	else if (parse->token.type == BC_LEX_LEFT_PAREN) {
+		*type = BC_EXPR_FUNC_CALL;
+		status = bc_parse_call(parse, &expr);
+	}
+	else {
+		expr.type = BC_EXPR_VAR;
+		*type = BC_EXPR_VAR;
+		expr.string = parse->token.string;
+	}
+
+	return bc_stack_push(exprs, &expr);
+}
+
+static BcStatus bc_parse_call(BcParse* parse, BcExpr* expr) {
+
+	BcStatus status;
+
+	expr->type = BC_EXPR_FUNC_CALL;
+	expr->call->name = parse->token.string;
+
+	status = bc_parse_params(parse, expr);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_RIGHT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_params(BcParse* parse, BcExpr* expr) {
+
+	BcStack* exprs;
+	BcStatus status;
+
+	status = bc_segarray_init(&expr->call->params, sizeof(BcStack),
+	                          bc_stack_free, NULL);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type == BC_LEX_RIGHT_PAREN) {
+		return BC_STATUS_SUCCESS;
+	}
+
+	do {
+
+		status = bc_parse_expr(parse, &exprs);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_segarray_add(&expr->call->params, &exprs);
+
+	} while (!status && parse->token.type == BC_LEX_COMMA);
+
+	return status;
+}
+
+static BcStatus bc_parse_read(BcParse* parse, BcStack* exprs) {
+
+	BcStatus status;
+	BcExpr expr;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_LEFT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_LEFT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	expr.type = BC_EXPR_READ;
+
+	status = bc_stack_push(exprs, &expr);
+
+	if (status) {
+		return status;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_builtin(BcParse* parse, BcStack* exs, BcExprType type)
+{
+	BcStatus status;
+	BcExpr expr;
+
+	expr.type = type;
+
+	expr.expr_stack = malloc(sizeof(BcStack));
+
+	if (!expr.expr_stack) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	status = bc_stack_init(expr.expr_stack, sizeof(BcExpr));
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_LEFT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_parse_expr(parse, &expr.expr_stack);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_RIGHT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	status = bc_stack_push(exs, &expr);
+
+	if (status) {
+		return status;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_scale(BcParse* parse, BcStack* exs, BcExprType* type) {
+
+	BcStatus status;
+	BcExpr expr;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_LEFT_PAREN) {
+
+		expr.type = BC_EXPR_SCALE;
+		*type = BC_EXPR_SCALE;
+
+		return bc_stack_push(exs, &expr);
+	}
+
+	expr.type = BC_EXPR_SCALE_FUNC;
+	*type = BC_EXPR_SCALE_FUNC;
+
+	expr.expr_stack = malloc(sizeof(BcStack));
+
+	if (!expr.expr_stack) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	status = bc_stack_init(expr.expr_stack, sizeof(BcExpr));
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_parse_expr(parse, &expr.expr_stack);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_RIGHT_PAREN) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	status = bc_stack_push(exs, &expr);
+
+	if (status) {
+		return status;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_incdec(BcParse* parse, BcStack* exs, BcExprType* prev)
+{
+	BcStatus status;
+	BcLexTokenType type;
+	BcExpr expr;
+	BcExprType etype;
+
+	etype = *prev;
+
+	if (etype == BC_EXPR_VAR || etype == BC_EXPR_ARRAY_ELEM ||
+	    etype == BC_EXPR_SCALE || etype == BC_EXPR_LAST ||
+	    etype == BC_EXPR_IBASE || etype == BC_EXPR_OBASE)
+	{
+		expr.type = parse->token.type == BC_LEX_OP_INC ?
+		                BC_EXPR_INC_POST : BC_EXPR_DEC_POST;
+		*prev = expr.type;
+
+		status = bc_stack_push(exs, &expr);
+	}
+	else {
+
+		expr.type = parse->token.type == BC_LEX_OP_INC ?
+		                BC_EXPR_INC_PRE : BC_EXPR_DEC_PRE;
+		*prev = expr.type;
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		type = parse->token.type;
+
+		if (type != BC_LEX_NAME && type != BC_LEX_KEY_SCALE &&
+		    type != BC_LEX_KEY_LAST && type != BC_LEX_KEY_IBASE &&
+		    type != BC_LEX_KEY_OBASE)
+		{
+			return BC_STATUS_PARSE_INVALID_TOKEN;
+		}
+
+		status = bc_stack_push(exs, &expr);
+	}
+
+	if (status) {
+		return status;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_minus(BcParse* parse, BcStack* exs, BcStack* ops,
+                               BcExprType* prev, bool rparen, uint32_t* nexprs)
+{
+	BcStatus status;
+	BcLexTokenType type;
+	BcExprType etype;
+
+	etype = *prev;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	type = parse->token.type;
+
+	if (type != BC_LEX_NAME && type != BC_LEX_NUMBER &&
+	    type != BC_LEX_KEY_SCALE && type != BC_LEX_KEY_LAST &&
+	    type != BC_LEX_KEY_IBASE && type != BC_LEX_KEY_OBASE &&
+	    type != BC_LEX_LEFT_PAREN)
+	{
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	type = rparen || etype == BC_EXPR_NUMBER ||
+	            etype == BC_EXPR_VAR || etype == BC_EXPR_ARRAY_ELEM ||
+	            etype == BC_EXPR_SCALE || etype == BC_EXPR_LAST ||
+	            etype == BC_EXPR_IBASE || etype == BC_EXPR_OBASE ?
+	                BC_LEX_OP_MINUS : BC_LEX_OP_NEGATE;
+
+	*prev = BC_PARSE_TOKEN_TO_EXPR(type);
+
+	if (type == BC_LEX_OP_MINUS) {
+		status = bc_parse_operator(exs, ops, type, nexprs);
+	}
+	else {
+
+		// We can just push onto the op stack because this is the largest
+		// precedence operator that gets pushed. Inc/dec does not.
+		status = bc_stack_push(ops, &type);
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_string(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+	BcStmt stmt;
+
+	stmt.type = BC_STMT_STRING;
+	stmt.data.string = parse->token.string;
+
+	status = bc_program_list_insert(list, &stmt);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	return bc_parse_semicolonListEnd(parse, list);
+}
+
+static BcStatus bc_parse_return(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+	BcStmt stmt;
+	BcExpr expr;
+
+	if (BC_PARSE_FUNC(parse)) {
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		stmt.type = BC_STMT_RETURN;
+
+		if (parse->token.type == BC_LEX_NEWLINE ||
+		    parse->token.type == BC_LEX_SEMICOLON)
+		{
+			stmt.data.expr_stack = malloc(sizeof(BcStack));
+
+			if (!stmt.data.expr_stack) {
+				return BC_STATUS_MALLOC_FAIL;
+			}
+
+			status = bc_stack_init(stmt.data.expr_stack, sizeof(BcExpr));
+
+			if (status) {
+				return status;
+			}
+
+			expr.type = BC_EXPR_NUMBER;
+			expr.string = NULL;
+
+			status = bc_stack_push(stmt.data.expr_stack, &expr);
+
+			if (status) {
+				return status;
+			}
+
+			bc_program_list_insert(list, &stmt);
+		}
+		else {
+			status = bc_parse_expr(parse, &stmt.data.expr_stack);
+		}
+	}
+	else {
+		status = BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_print(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+	BcLexTokenType type;
+	BcStack* exprs;
+	BcExpr expr;
+	BcStmt stmt;
+	bool comma;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	type = parse->token.type;
+
+	if (type == BC_LEX_SEMICOLON || type == BC_LEX_NEWLINE) {
+		return BC_STATUS_PARSE_INVALID_PRINT;
+	}
+
+	comma = false;
+
+	while (!status && type != BC_LEX_SEMICOLON && type != BC_LEX_NEWLINE) {
+
+		if (type == BC_LEX_STRING) {
+
+			status = bc_parse_string(parse, list);
+
+			if (status) {
+				return status;
+			}
+
+			stmt.type = BC_STMT_STRING;
+			stmt.data.string = parse->token.string;
+		}
+		else {
+
+			status = bc_parse_expr(parse, &exprs);
+
+			if (status) {
+				return status;
+			}
+
+			expr.type = BC_EXPR_PRINT;
+			status = bc_stack_push(exprs, &expr);
+
+			stmt.type = BC_STMT_EXPR;
+
+			stmt.data.expr_stack = exprs;
+		}
+
+		status = bc_program_list_insert(list, &stmt);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		if (parse->token.type == BC_LEX_COMMA) {
+			comma = true;
+			status = bc_lex_next(&parse->lex, &parse->token);
+		}
+		else {
+			comma = false;
+		}
+
+		type = parse->token.type;
+	}
+
+	if (status) {
+		return status;
+	}
+
+	if (comma) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_if(BcParse* parse, BcStmtList* list) {
+
+	// TODO: Write this function.
+
+	BcStatus status;
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_while(BcParse* parse, BcStmtList* list) {
+
+	// TODO: Write this function.
+
+}
+
+static BcStatus bc_parse_for(BcParse* parse, BcStmtList* list) {
+
+	// TODO: Write this function.
+
+}
+
+static BcStatus bc_parse_loop(BcParse* parse, BcStmtList* list) {
+
+	// TODO: Write this function.
+
+}
+
+static BcStatus bc_parse_startBody(BcParse* parse, BcStmtList** new_list,
+                                   uint16_t flags)
+{
+	BcStatus status;
+	BcStmtList* list;
+	uint16_t* flag_ptr;
+
+	list = bc_program_list_create();
+
+	if (!list) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	status = bc_stack_push(&parse->ctx_stack, &list);
+
+	if (status) {
+		return status;
+	}
+
+	flag_ptr = bc_stack_top(&parse->flag_stack);
+
+	if (!flag_ptr) {
+		return BC_STATUS_PARSE_BUG;
+	}
+
+	flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FOR_LOOP |
+	                       BC_PARSE_FLAG_WHILE_LOOP));
+
+	status = bc_stack_push(&parse->flag_stack, &flags);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type == BC_LEX_LEFT_BRACE) {
+
+		++parse->num_braces;
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		status = bc_parse_stmt(parse, list);
+	}
+	else {
+		status = bc_parse_stmt(parse, list);
+	}
+
+	if (status) {
+		bc_program_list_free(list);
+	}
+	else {
+		*new_list = list;
+	}
+
+	return status;
+}
+
+static BcStatus bc_parse_loopExit(BcParse* parse, BcStmtList* list,
+                                  BcLexTokenType type)
+{
+	BcStatus status;
+	BcStmt stmt;
+
+	if (!BC_PARSE_FOR_LOOP(parse) && !BC_PARSE_WHILE_LOOP(parse)) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	stmt.type = type == BC_LEX_KEY_BREAK ? BC_STMT_BREAK : BC_STMT_CONTINUE;
+
+	status = bc_program_list_insert(list, &stmt);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_lex_next(&parse->lex, &parse->token);
+
+	if (status) {
+		return status;
+	}
+
+	if (parse->token.type != BC_LEX_SEMICOLON &&
+	    parse->token.type != BC_LEX_NEWLINE)
+	{
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	return bc_lex_next(&parse->lex, &parse->token);
+}
+
+static BcStatus bc_parse_rightBrace(BcParse* parse, BcStmtList* list) {
+
+	BcStatus status;
+	BcStmtList** list_ptr;
+
+	if (parse->ctx_stack.len <= 1 || parse->num_braces == 0) {
+		return BC_STATUS_PARSE_INVALID_TOKEN;
+	}
+
+	if (parse->ctx_stack.len != parse->flag_stack.len) {
+		return BC_STATUS_PARSE_BUG;
+	}
+
+	if (BC_PARSE_IF(parse)) {
+
+		status = bc_lex_next(&parse->lex, &parse->token);
+
+		if (status) {
+			return status;
+		}
+
+		if (parse->token.type == BC_LEX_KEY_ELSE) {
+
+			status = bc_lex_next(&parse->lex, &parse->token);
+
+			if (status) {
+				return status;
+			}
+
+			list_ptr = &parse->partial.data.if_stmt->else_list;
+
+			status = bc_parse_startBody(parse, list_ptr, BC_PARSE_FLAG_ELSE);
+
+			if (status) {
+				return status;
+			}
+
+			status = bc_lex_next(&parse->lex, &parse->token);
+
+			if (status) {
+				return status;
+			}
+		}
+	}
+
+	status = bc_stack_pop(&parse->flag_stack);
+
+	if (status) {
+		return status;
+	}
+
+	return bc_stack_pop(&parse->ctx_stack);
+}
diff --git a/bc/src/program.c b/bc/src/program.c
new file mode 100644
index 0000000..bb282a2
--- /dev/null
+++ b/bc/src/program.c
@@ -0,0 +1,471 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arbprec/arbprec.h>
+
+#include "program.h"
+
+static BcStatus bc_program_list_expand(BcStmtList* list);
+
+static int bc_program_func_cmp(void* func1, void* func2);
+static void bc_program_func_free(void* func);
+static int bc_program_var_cmp(void* var1, void* var2);
+static void bc_program_var_free(void* var);
+static int bc_program_array_cmp(void* array1, void* array2);
+static void bc_program_array_free(void* array);
+static void bc_program_stmt_free(BcStmt* stmt);
+
+static void bc_program_num_init(fxdpnt* num);
+
+BcStatus bc_program_init(BcProgram* p, const char* file) {
+
+	BcStatus st;
+
+	if (p == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	p->file = file;
+
+	p->first = bc_program_list_create();
+
+	if (!p->first) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	p->cur = p->first;
+
+	st = bc_segarray_init(&p->funcs, sizeof(BcFunc), bc_program_func_free,
+	                      bc_program_func_cmp);
+
+	if (st) {
+		goto func_err;
+	}
+
+	st = bc_segarray_init(&p->vars, sizeof(BcVar), bc_program_var_free,
+	                      bc_program_var_cmp);
+
+	if (st) {
+		goto var_err;
+	}
+
+	st = bc_segarray_init(&p->arrays, sizeof(BcArray), bc_program_array_free,
+	                      bc_program_array_cmp);
+
+	if (st) {
+		goto array_err;
+	}
+
+	return st;
+
+array_err:
+
+	bc_segarray_free(&p->vars);
+
+var_err:
+
+	bc_segarray_free(&p->funcs);
+
+func_err:
+
+	bc_program_list_free(p->first);
+	p->first = NULL;
+	p->cur = NULL;
+
+	return st;
+}
+
+BcStatus bc_program_func_add(BcProgram* p, BcFunc* func) {
+	assert(p && func);
+	return bc_segarray_add(&p->funcs, func);
+}
+
+BcStatus bc_program_var_add(BcProgram* p, BcVar* var) {
+	assert(p && var);
+	return bc_segarray_add(&p->vars, var);
+}
+
+BcStatus bc_program_array_add(BcProgram* p, BcArray* array) {
+	assert(p && array);
+	return bc_segarray_add(&p->arrays, array);
+}
+
+BcStatus bc_program_exec(BcProgram* p) {
+	// TODO: Write this function.
+}
+
+void bc_program_free(BcProgram* p) {
+
+	if (p == NULL) {
+		return;
+	}
+
+	BcStmtList* temp;
+	BcStmtList* cur = p->first;
+
+	while (cur != NULL) {
+		temp = cur->next;
+		bc_program_list_free(cur);
+		cur = temp;
+	}
+
+	p->cur = NULL;
+	p->first = NULL;
+
+	uint32_t num = p->funcs.num;
+	for (uint32_t i = 0; i < num; ++i) {
+		bc_program_func_free(bc_segarray_item(&p->funcs, i));
+	}
+
+	num = p->vars.num;
+	for (uint32_t i = 0; i < num; ++i) {
+		bc_program_var_free(bc_segarray_item(&p->vars, i));
+	}
+
+	num = p->arrays.num;
+	for (uint32_t i = 0; i < num; ++i) {
+		bc_program_array_free(bc_segarray_item(&p->arrays, i));
+	}
+}
+
+BcStmtList* bc_program_list_create() {
+
+	BcStmtList* list;
+
+	list = malloc(sizeof(BcStmtList));
+
+	if (list == NULL) {
+		return NULL;
+	}
+
+	list->next = NULL;
+	list->num_stmts = 0;
+
+	return list;
+}
+
+BcStatus bc_program_list_insert(BcStmtList* list, BcStmt* stmt) {
+
+	if (list == NULL || stmt == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	// Find the end list.
+	while (list->num_stmts == BC_PROGRAM_MAX_STMTS && list->next) {
+		list = list->next;
+	}
+
+	if (list->num_stmts == BC_PROGRAM_MAX_STMTS) {
+
+		BcStatus status = bc_program_list_expand(list);
+
+		if (status != BC_STATUS_SUCCESS) {
+			return status;
+		}
+
+		list = list->next;
+	}
+
+	memcpy(list->stmts + list->num_stmts, stmt, sizeof(BcStmt));
+	++list->num_stmts;
+
+	return BC_STATUS_SUCCESS;
+}
+
+void bc_program_list_free(BcStmtList* list) {
+
+	BcStmtList* temp;
+	uint32_t num;
+	BcStmt* stmts;
+
+	if (list == NULL) {
+		return;
+	}
+
+	do {
+
+		temp = list->next;
+
+		num = list->num_stmts;
+		stmts = list->stmts;
+
+		for (uint32_t i = 0; i < num; ++i) {
+			bc_program_stmt_free(stmts + i);
+		}
+
+		free(list);
+
+		list = temp;
+
+	} while (list);
+}
+
+static BcStatus bc_program_list_expand(BcStmtList* list) {
+
+	if (list == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	BcStmtList* next = bc_program_list_create();
+
+	if (next == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	list->next = next;
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_program_func_init(BcFunc* func, char* name) {
+
+	BcStatus status;
+
+	status = BC_STATUS_SUCCESS;
+
+	if (!func || !name) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	func->num_params = 0;
+	func->num_autos = 0;
+
+	func->first = bc_program_list_create();
+
+	if (!func->first) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	func->name = name;
+	func->cur = func->first;
+
+	func->param_cap = BC_PROGRAM_DEF_SIZE;
+	func->params = malloc(sizeof(BcAuto) * BC_PROGRAM_DEF_SIZE);
+
+	if (!func->params) {
+		goto param_err;
+	}
+
+	func->auto_cap = BC_PROGRAM_DEF_SIZE;
+	func->autos = malloc(sizeof(BcAuto) * BC_PROGRAM_DEF_SIZE);
+
+	if (!func->autos) {
+		func->auto_cap = 0;
+		goto auto_err;
+	}
+
+	return BC_STATUS_SUCCESS;
+
+auto_err:
+
+	free(func->params);
+	func->param_cap = 0;
+
+param_err:
+
+	bc_program_list_free(func->first);
+	func->first = func->cur = NULL;
+
+	return status;
+}
+
+BcStatus bc_program_func_insertParam(BcFunc* func, char* name, bool var) {
+
+	BcAuto* params;
+	size_t new_cap;
+
+	if (!func || !name) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	if (func->num_params == func->param_cap) {
+
+		new_cap = sizeof(BcAuto) * (func->param_cap + BC_PROGRAM_DEF_SIZE);
+		params = realloc(func->params, new_cap);
+
+		if (!params) {
+			return BC_STATUS_MALLOC_FAIL;
+		}
+
+		func->param_cap = new_cap;
+	}
+
+	func->params[func->num_params].name = name;
+	func->params[func->num_params].var = var;
+
+	++func->num_params;
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_program_func_insertAuto(BcFunc* func, char* name, bool var) {
+
+	BcAuto* autos;
+	size_t new_cap;
+
+	if (!func || !name) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	if (func->num_autos == func->auto_cap) {
+
+		new_cap = sizeof(BcAuto) * (func->auto_cap + BC_PROGRAM_DEF_SIZE);
+		autos = realloc(func->autos, new_cap);
+
+		if (!autos) {
+			return BC_STATUS_MALLOC_FAIL;
+		}
+
+		func->auto_cap = new_cap;
+	}
+
+	func->autos[func->num_autos].name = name;
+	func->autos[func->num_autos].var = var;
+
+	++func->num_autos;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static int bc_program_func_cmp(void* func1, void* func2) {
+
+	assert(func1 && func2);
+
+	BcFunc* f1 = (BcFunc*) func1;
+	char* f2name = (char*) func2;
+
+	return strcmp(f1->name, f2name);
+}
+
+static void bc_program_func_free(void* func) {
+
+	BcFunc* f;
+
+	f = (BcFunc*) func;
+
+	if (f == NULL) {
+		return;
+	}
+
+	free(f->name);
+
+	bc_program_list_free(f->first);
+
+	f->name = NULL;
+	f->first = NULL;
+	f->cur = NULL;
+
+	free(f->params);
+	free(f->autos);
+
+	f->params = NULL;
+	f->num_params = 0;
+	f->param_cap = 0;
+	f->autos = NULL;
+	f->num_autos = 0;
+	f->auto_cap = 0;
+}
+
+BcStatus bc_program_var_init(BcVar* var, char* name) {
+
+	if (!var || !name) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	var->name = name;
+
+	var->data = arb_alloc(16);
+
+	return BC_STATUS_SUCCESS;
+}
+
+static int bc_program_var_cmp(void* var1, void* var2) {
+
+	assert(var1 && var2);
+
+	BcFunc* v1 = (BcFunc*) var1;
+	char* v2name = (char*) var2;
+
+	return strcmp(v1->name, v2name);
+}
+
+static void bc_program_var_free(void* var) {
+
+	BcVar* v;
+
+	v = (BcVar*) var;
+
+	if (v == NULL) {
+		return;
+	}
+
+	free(v->name);
+	arb_free(v->data);
+
+	v->name = NULL;
+	v->data = NULL;
+}
+
+BcStatus bc_program_array_init(BcArray* array, char* name) {
+
+	if (!array || !name) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	array->name = name;
+
+	return bc_segarray_init(&array->array, sizeof(fxdpnt),
+	                        (BcSegArrayFreeFunc) arb_free, NULL);
+}
+
+static int bc_program_array_cmp(void* array1, void* array2) {
+
+	assert(array1 && array2);
+
+	BcFunc* a1 = (BcFunc*) array1;
+	char* a2name = (char*) array2;
+
+	return strcmp(a1->name, a2name);
+}
+
+static void bc_program_array_free(void* array) {
+
+	BcArray* a;
+
+	a = (BcArray*) array;
+
+	if (a == NULL) {
+		return;
+	}
+
+	free(a->name);
+	a->name = NULL;
+
+	bc_segarray_free(&a->array);
+}
+
+BcStatus bc_program_stmt_init(BcStmt* stmt) {
+	// TODO: Write this function.
+}
+
+static void bc_program_stmt_free(BcStmt* stmt) {
+	// TODO: Write this function.
+}
+
+static void bc_program_num_init(fxdpnt* num) {
+
+	num->number = arb_calloc(1, sizeof(ARBT) * BC_PROGRAM_DEF_SIZE);
+	num->sign = '+';
+
+	// FIXME: this should likely be "len"
+	// Look at arb_alloc().
+	num->lp = 0;
+
+	num->rp = 0;
+	num->allocated = BC_PROGRAM_DEF_SIZE;
+	//num->len = len;
+	num->len = 0;
+	num->chunk = 4;
+}
diff --git a/bc/src/segarray.c b/bc/src/segarray.c
new file mode 100644
index 0000000..428a3bd
--- /dev/null
+++ b/bc/src/segarray.c
@@ -0,0 +1,275 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "segarray.h"
+#include "program.h"
+
+static BcStatus bc_segarray_addUnsorted(BcSegArray* sa, void* data) ;
+static BcStatus bc_segarray_addSorted(BcSegArray* sa, void* data);
+static BcStatus bc_segarray_addArray(BcSegArray* sa, uint32_t idx);
+static uint32_t bc_segarray_findIndex(BcSegArray* sa, void* data);
+static inline void bc_segarray_moveLast(BcSegArray* sa, uint32_t end1);
+static void bc_segarray_move(BcSegArray* sa, uint32_t idx1,
+                             uint32_t start, uint32_t num_elems);
+
+BcStatus bc_segarray_init(BcSegArray* sa, size_t esize, BcSegArrayFreeFunc sfree, BcSegArrayCmpFunc cmp) {
+
+	if (sa == NULL || esize == 0) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	sa->esize = esize;
+	sa->cmp = cmp;
+	sa->sfree = sfree;
+	sa->num = 0;
+
+	sa->ptrs = malloc(sizeof(uint8_t*) * BC_SEGARRAY_NUM_ARRAYS);
+	if (!sa->ptrs) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	sa->num_ptrs = 0;
+	sa->ptr_cap = BC_SEGARRAY_NUM_ARRAYS;
+
+	return bc_segarray_addArray(sa, 0);
+}
+
+BcStatus bc_segarray_add(BcSegArray* sa, void* data) {
+
+	BcStatus status;
+
+	if (sa == NULL || data == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	if (sa->cmp) {
+		status = bc_segarray_addSorted(sa, data);
+	}
+	else {
+		status = bc_segarray_addUnsorted(sa, data);
+	}
+
+	return status;
+}
+
+void* bc_segarray_item(BcSegArray* sa, uint32_t idx) {
+	return bc_segarray_item2(sa, BC_SEGARRAY_IDX1(idx), BC_SEGARRAY_IDX2(idx));
+}
+
+void* bc_segarray_item2(BcSegArray* sa, uint32_t idx1, uint32_t idx2) {
+
+	uint32_t num = sa->num;
+	uint32_t num1 = BC_SEGARRAY_IDX1(num);
+	uint32_t num2 = BC_SEGARRAY_IDX2(num);
+	if (sa == NULL || idx1 > num1 || (idx1 == num1 && idx2 >= num2)) {
+		return NULL;
+	}
+
+	uint8_t* ptr = sa->ptrs[idx1];
+
+	if (ptr == NULL) {
+		return NULL;
+	}
+
+	return ptr + sa->esize * idx2;
+}
+
+uint32_t bc_segarray_find(BcSegArray* sa, void* data) {
+
+	if (!sa) {
+		return (uint32_t) -1;
+	}
+
+	uint32_t idx = bc_segarray_findIndex(sa, data);
+
+	if (!sa->cmp(bc_segarray_item(sa, idx), data)) {
+		return idx;
+	}
+
+	return (uint32_t) -1;
+}
+
+void bc_segarray_free(BcSegArray* sa) {
+
+	BcSegArrayFreeFunc sfree;
+	uint32_t num;
+
+	if (sa == NULL) {
+		return;
+	}
+
+	sfree = sa->sfree;
+
+	if (sfree) {
+
+		num = sa->num;
+		for (uint32_t i = 0; i < num; ++i) {
+			sfree(bc_segarray_item(sa, i));
+		}
+	}
+
+	num = BC_SEGARRAY_IDX1(sa->num - 1);
+	for (uint32_t i = num - 1; i < num; --i) {
+		free(sa->ptrs[i]);
+	}
+
+	free(sa->ptrs);
+	sa->ptrs = NULL;
+
+	sa->esize = 0;
+	sa->num = 0;
+	sa->num_ptrs = 0;
+	sa->cmp = NULL;
+	sa->sfree = NULL;
+}
+
+static BcStatus bc_segarray_addUnsorted(BcSegArray* sa, void* data) {
+
+	BcStatus status;
+
+	uint32_t end = sa->num;
+	uint32_t end1 = BC_SEGARRAY_IDX1(end);
+	uint32_t end2 = BC_SEGARRAY_IDX2(end);
+
+	if (end2 == 0 && end1 > 0) {
+
+		status = bc_segarray_addArray(sa, end1);
+
+		if (status != BC_STATUS_SUCCESS) {
+			return status;
+		}
+	}
+
+	uint8_t* ptr = sa->ptrs[end1];
+	memcpy(ptr + sa->esize * end2, data, sa->esize);
+
+	++sa->num;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_segarray_addSorted(BcSegArray* sa, void* data) {
+
+	BcStatus status;
+
+	uint32_t end = sa->num;
+	uint32_t end1 = BC_SEGARRAY_IDX1(end);
+	uint32_t end2 = BC_SEGARRAY_IDX2(end);
+
+	uint32_t idx = bc_segarray_findIndex(sa, data);
+	idx = idx == (uint32_t) -1 ? end : idx;
+	uint32_t idx1 = BC_SEGARRAY_IDX1(idx);
+	uint32_t idx2 = BC_SEGARRAY_IDX2(idx);
+
+	if (end2 == 0 && end1 > 0) {
+
+		status = bc_segarray_addArray(sa, end1);
+
+		if (status != BC_STATUS_SUCCESS) {
+			return status;
+		}
+
+		if ((end1 != 0 && end2 == 0) && idx != end) {
+			bc_segarray_moveLast(sa, end1);
+		}
+	}
+
+	if (end1 > 0) {
+
+		uint32_t move_idx = end2 == 0 ? end1 - 1 : end1;
+		while (move_idx > idx1) {
+			bc_segarray_move(sa, move_idx, 0, BC_SEGARRAY_SEG_LAST);
+			bc_segarray_moveLast(sa, move_idx);
+			--move_idx;
+		}
+	}
+
+	if (idx2 != BC_SEGARRAY_SEG_LAST) {
+		bc_segarray_move(sa, idx1, idx2, BC_SEGARRAY_SEG_LAST - idx2);
+	}
+
+	uint8_t* ptr = sa->ptrs[idx1];
+	memcpy(ptr + sa->esize * idx2, data, sa->esize);
+
+	++sa->num;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static BcStatus bc_segarray_addArray(BcSegArray* sa, uint32_t idx) {
+
+	if (sa->num_ptrs == sa->ptr_cap) {
+
+		uint32_t new_cap = sa->ptr_cap + BC_SEGARRAY_NUM_ARRAYS;
+		uint8_t** temp = realloc(sa->ptrs, sizeof(uint8_t*) * new_cap);
+
+		if (!temp) {
+			return BC_STATUS_MALLOC_FAIL;
+		}
+
+		sa->ptrs = temp;
+		sa->ptr_cap = new_cap;
+	}
+
+	uint8_t* ptr = malloc(sa->esize * BC_SEGARRAY_SEG_SIZE);
+
+	if (ptr == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	sa->ptrs[idx] = ptr;
+	++sa->num_ptrs;
+
+	return BC_STATUS_SUCCESS;
+}
+
+static uint32_t bc_segarray_findIndex(BcSegArray* sa, void* data) {
+
+	BcSegArrayCmpFunc cmp = sa->cmp;
+
+	uint32_t low = 0;
+	uint32_t high = sa->num;
+
+	while (low < high) {
+
+		uint32_t mid = (low + high) / 2;
+
+		uint8_t* ptr = bc_segarray_item(sa, mid);
+
+		if (cmp(ptr, data) > 0) {
+			high = mid;
+		}
+		else {
+			low = mid + 1;
+		}
+	}
+
+	return low;
+}
+
+static void bc_segarray_moveLast(BcSegArray* sa, uint32_t end1) {
+	uint8_t* dest = sa->ptrs[end1];
+	uint8_t* src = sa->ptrs[end1 - 1] + sa->esize * BC_SEGARRAY_SEG_LAST;
+	memcpy(dest, src, sa->esize);
+}
+
+static void bc_segarray_move(BcSegArray* sa, uint32_t idx1, uint32_t start, uint32_t num_elems) {
+
+	assert(num_elems < BC_SEGARRAY_SEG_SIZE &&
+	       start + num_elems < BC_SEGARRAY_SEG_SIZE);
+
+	uint8_t* ptr = sa->ptrs[idx1];
+
+	size_t esize = sa->esize;
+
+	size_t move_size = esize * num_elems;
+
+	uint8_t* src = ptr + esize * start;
+	uint8_t* dest = src + esize;
+
+	memmove(dest, src, move_size);
+}
diff --git a/bc/src/stack.c b/bc/src/stack.c
new file mode 100644
index 0000000..8d6b568
--- /dev/null
+++ b/bc/src/stack.c
@@ -0,0 +1,132 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stack.h"
+
+static BcStatus bc_stack_expand(BcStack* stack);
+
+BcStatus bc_stack_init(BcStack* stack, size_t esize) {
+
+	// Check for invalid params.
+	if (stack == NULL || esize == 0) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	// Set the fields.
+	stack->size = esize;
+	stack->cap = BC_STACK_START;
+	stack->len = 0;
+
+	// Allocate the array.
+	stack->stack = malloc(esize * BC_STACK_START);
+
+	// Check for error.
+	if (stack->stack == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	return BC_STATUS_SUCCESS;
+}
+
+BcStatus bc_stack_push(BcStack* stack, void* data) {
+
+	// Check for invalid params.
+	if (stack == NULL || data == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	// Check if we need to expand.
+	if (stack->len == stack->cap) {
+
+		// Expand the stack.
+		BcStatus status = bc_stack_expand(stack);
+
+		// Check for error.
+		if (status != BC_STATUS_SUCCESS) {
+			return status;
+		}
+	}
+
+	// Copy the data.
+	size_t size = stack->size;
+	memmove(stack->stack + (size * stack->len), data, size);
+
+	// Increment the length.
+	++stack->len;
+
+	return BC_STATUS_SUCCESS;
+}
+
+void* bc_stack_top(BcStack* stack) {
+
+	// Check for invalid state.
+	if (stack == NULL || stack->len == 0) {
+		return NULL;
+	}
+
+	// Calculate the return pointer.
+	return stack->stack + stack->size * (stack->len - 1);
+}
+
+void* bc_stack_item(BcStack* stack, uint32_t idx) {
+
+	// Check for invalid state.
+	if (stack == NULL || stack->len == 0 || idx >= stack->len) {
+		return NULL;
+	}
+
+	// Calculate the return pointer.
+	return stack->stack + stack->size * (stack->len - idx - 1);
+}
+
+BcStatus bc_stack_pop(BcStack* stack) {
+
+	// Check for invalid params.
+	if (stack == NULL) {
+		return BC_STATUS_INVALID_PARAM;
+	}
+
+	// Decrement the length.
+	--stack->len;
+
+	return BC_STATUS_SUCCESS;
+}
+
+void bc_stack_free(void* stack) {
+
+	BcStack* s;
+
+	s = (BcStack*) stack;
+
+	// Check for NULL.
+	if (s == NULL) {
+		return;
+	}
+
+	// Free the stack.
+	free(s->stack);
+
+	// Zero the fields.
+	s->size = 0;
+	s->stack = NULL;
+	s->len = 0;
+	s->cap = 0;
+}
+
+static BcStatus bc_stack_expand(BcStack* stack) {
+
+	// Realloc.
+	uint8_t* ptr = realloc(stack->stack, stack->size * (stack->cap + BC_STACK_START));
+
+	// Check for error.
+	if (ptr == NULL) {
+		return BC_STATUS_MALLOC_FAIL;
+	}
+
+	// Assign the fields.
+	stack->stack = ptr;
+	stack->cap += BC_STACK_START;
+
+	return BC_STATUS_SUCCESS;
+}
diff --git a/bc/src/vm.c b/bc/src/vm.c
new file mode 100644
index 0000000..e799259
--- /dev/null
+++ b/bc/src/vm.c
@@ -0,0 +1,265 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vm.h"
+
+static BcStatus bc_vm_execFile(BcVm* vm, int idx);
+static BcStatus bc_vm_execStdin(BcVm* vm);
+
+BcStatus bc_vm_init(BcVm* vm, int filec, const char* filev[]) {
+
+	vm->filec = filec;
+	vm->filev = filev;
+
+	return bc_stack_init(&vm->ctx_stack, sizeof(BcStmtList*));
+}
+
+BcStatus bc_vm_exec(BcVm* vm) {
+
+	BcStatus status;
+	int num_files;
+
+	status = BC_STATUS_SUCCESS;
+
+	num_files = vm->filec;
+
+	for (int i = 0; !status && i < num_files; ++i) {
+		status = bc_vm_execFile(vm, i);
+	}
+
+	if (status) {
+		return status;
+	}
+
+	return bc_vm_execStdin(vm);
+}
+
+void bc_vm_free(BcVm* vm) {
+	bc_stack_free(&vm->ctx_stack);
+	bc_parse_free(&vm->parse);
+	bc_program_free(&vm->program);
+}
+
+static BcStatus bc_vm_execFile(BcVm* vm, int idx) {
+
+	BcStatus status;
+	FILE* f;
+	size_t size;
+	size_t read_size;
+
+	status = bc_program_init(&vm->program, vm->filev[idx]);
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_parse_init(&vm->parse, &vm->program);
+
+	if (status) {
+		goto parse_err;
+	}
+
+	f = fopen(vm->filev[idx], "r");
+
+	if (!f) {
+		status = BC_STATUS_VM_FILE_ERR;
+		goto file_err;
+	}
+
+	fseek(f, 0, SEEK_END);
+	size = ftell(f);
+
+	fseek(f, 0, SEEK_SET);
+
+	char* data = malloc(size + 1);
+
+	if (!data) {
+		status = BC_STATUS_MALLOC_FAIL;
+		goto data_err;
+	}
+
+	read_size = fread(data, 1, size, f);
+
+	if (read_size != size) {
+		status = BC_STATUS_VM_FILE_READ_ERR;
+		goto read_err;
+	}
+
+	data[size] = '\0';
+
+	fclose(f);
+
+	bc_parse_text(&vm->parse, data);
+
+	status = bc_parse_parse(&vm->parse, &vm->program);
+
+	while (!status) {
+
+		status = bc_program_exec(&vm->program);
+
+		if (status) {
+			bc_error(status);
+			break;
+		}
+
+		status = bc_parse_parse(&vm->parse, &vm->program);
+
+		if (status && (status != BC_STATUS_LEX_EOF ||
+		               status != BC_STATUS_PARSE_EOF))
+		{
+			bc_error_file(vm->program.file, vm->parse.lex.line, status);
+		}
+	}
+
+	bc_program_free(&vm->program);
+	bc_parse_free(&vm->parse);
+
+	free(data);
+
+	return status;
+
+read_err:
+
+	free(data);
+
+data_err:
+
+	fclose(f);
+
+file_err:
+
+	bc_parse_free(&vm->parse);
+
+parse_err:
+
+	bc_program_free(&vm->program);
+
+	return status;
+}
+
+static BcStatus bc_vm_execStdin(BcVm* vm) {
+
+	BcStatus status;
+	char* buf;
+	char* buffer;
+	char* temp;
+	size_t n;
+	size_t bufn;
+	size_t slen;
+	size_t total_len;
+
+	status = bc_program_init(&vm->program, "-");
+
+	if (status) {
+		return status;
+	}
+
+	status = bc_parse_init(&vm->parse, &vm->program);
+
+	if (status) {
+		goto parse_err;
+	}
+
+	n = BC_VM_BUF_SIZE;
+	bufn = BC_VM_BUF_SIZE;
+	buffer = malloc(BC_VM_BUF_SIZE + 1);
+
+	if (!buffer) {
+		status = BC_STATUS_MALLOC_FAIL;
+		goto buffer_err;
+	}
+
+	buf = malloc(BC_VM_BUF_SIZE + 1);
+
+	if (!buf) {
+		status = BC_STATUS_MALLOC_FAIL;
+		goto buf_err;
+	}
+
+	// The following loop is complicated because the vm tries
+	// not to send any lines that end with a backslash to the
+	// parser. The reason for that is because the parser treats
+	// a backslash newline combo as whitespace, per the bc
+	// spec. Thus, the parser will expect more stuff.
+	while (!status && getline(&buf, &bufn, stdin) != -1) {
+
+		size_t len;
+
+		len = strlen(buf);
+		slen = strlen(buffer);
+		total_len = slen + len;
+
+		if (len > 1) {
+
+			if (buf[len - 2] == '\\') {
+
+				if (total_len > n) {
+
+					temp = realloc(buffer, total_len + 1);
+
+					if (!temp) {
+						status = BC_STATUS_MALLOC_FAIL;
+						goto exit_err;
+					}
+
+					buffer = temp;
+					n = slen + len;
+				}
+
+				strcat(buffer, buf);
+
+				continue;
+			}
+		}
+
+		if (total_len > n) {
+
+			temp = realloc(buffer, total_len + 1);
+
+			if (!temp) {
+				status = BC_STATUS_MALLOC_FAIL;
+				goto exit_err;
+			}
+
+			buffer = temp;
+			n = slen + len;
+		}
+
+		strcat(buffer, buf);
+
+		status = bc_parse_text(&vm->parse, buffer);
+
+		if (status) {
+			goto exit_err;
+		}
+
+		status = bc_parse_parse(&vm->parse, &vm->program);
+
+		if (status) {
+			goto exit_err;
+		}
+
+		status = bc_program_exec(&vm->program);
+
+		buffer[0] = '\0';
+	}
+
+exit_err:
+
+	free(buf);
+
+buf_err:
+
+	free(buffer);
+
+buffer_err:
+
+	bc_parse_free(&vm->parse);
+
+parse_err:
+
+	bc_program_free(&vm->program);
+
+	return status;
+}
diff --git a/bc/tests/segarray_test.c b/bc/tests/segarray_test.c
new file mode 100644
index 0000000..00e695c
--- /dev/null
+++ b/bc/tests/segarray_test.c
@@ -0,0 +1,83 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../bc.h"
+#include "../segarray.h"
+#include "../program.h"
+
+int bc_var_cmp(void* var1, void* var2) {
+
+	BcVar* v1 = (BcVar*) var1;
+	BcVar* v2 = (BcVar*) var2;
+
+	return strcmp(v1->name, v2->name);
+}
+
+int main(int argc, char* argv[]) {
+
+	BcStatus status;
+	BcSegArray sa;
+
+	if (argc < 3) {
+		fprintf(stderr, "Need an input file and an output file\n"
+		                "    Usage: test <input_file> <output_file>");
+		exit(BC_STATUS_INVALID_OPTION);
+	}
+
+	status = bc_segarray_init(&sa, sizeof(BcVar), bc_var_cmp);
+
+	if (status) {
+		return status;
+	}
+
+	FILE* in = fopen(argv[1], "r");
+
+	if (!in) {
+		BC_STATUS_VM_FILE_ERR;
+	}
+
+	char* buffer = NULL;
+	size_t n = 0;
+
+	while (getline(&buffer, &n, in) != -1) {
+
+		BcVar var;
+
+		var.name = buffer;
+		var.data = NULL;
+
+		status = bc_segarray_add(&sa, &var);
+
+		if (status) {
+			return status;
+		}
+
+		buffer = NULL;
+		n = 0;
+	}
+
+	fclose(in);
+
+	FILE* out = fopen(argv[2], "w");
+
+	if (!out) {
+		BC_STATUS_VM_FILE_ERR;
+	}
+
+	for (uint32_t i = 0; i < sa.num; ++i) {
+
+		BcVar* v = bc_segarray_item(&sa, i);
+
+		if (!v) {
+			return 1;
+		}
+
+		fprintf(out, "%s", v->name);
+	}
+
+	fclose(out);
+
+	return BC_STATUS_SUCCESS;
+}