diff --git a/source/compile.c b/source/compile.c
index ecc391f..c1d583b 100644
--- a/source/compile.c
+++ b/source/compile.c
@@ -27,7 +27,10 @@ int compile_deinit(void) {
 
 static
 void dump_variable_to_assembler(void * data) {
-    variable_t * variable = (variable_t*)data;
+    symbol_t * variable = (symbol_t*)data;
+    if (variable->symbol_type != VARIABLE) {
+        return;
+    }
 
     append_instructions(ASMDIRMEM, variable->_id, ASMDIRIMM, type2size(variable->type));
 
@@ -44,7 +47,7 @@ void dump_variable_to_assembler(void * data) {
 
 static
 void dump_variables_to_assembler(void) {
-    tommy_hashtable_foreach(&variable_table, dump_variable_to_assembler);
+    tommy_hashtable_foreach(&symbol_table, dump_variable_to_assembler);
 }
 
 static
diff --git a/source/compile.h b/source/compile.h
index 7696c11..c6b09df 100644
--- a/source/compile.h
+++ b/source/compile.h
@@ -13,10 +13,6 @@ extern int compile(void);
 
 extern void append_label (int rel);
 
-extern void append_fastcall_begin     (int rel);
-extern void append_fastcall_end       (void);
-extern void append_fastcall_arguments (int rel, int wid, int imm);
-
 /* --- Token appending
  * The core problem is that we want an interface where we can append {instructoin}
  *  tokens without modifying the counter as that gets old fast and error prone
diff --git a/source/debug.h b/source/debug.h
index 9deac89..eb3711d 100644
--- a/source/debug.h
+++ b/source/debug.h
@@ -18,7 +18,7 @@ void debug_printf(const char * const fmt, ...) {
 
 static
 void dump_variable(void * data) {
-    variable_t * variable = (variable_t*)data;
+    symbol_t * variable = (symbol_t*)data;
     if (variable->elements == 1) {
         printf("{ .name = '%s', .value = '%ld' }\n",
                 variable->name,
@@ -36,7 +36,7 @@ void dump_variable(void * data) {
 
 static
 void debug_dump_variables(void) {
-    tommy_hashtable_foreach(&variable_table, dump_variable);
+    tommy_hashtable_foreach(&symbol_table, dump_variable);
 }
 
 static
diff --git a/source/eaxhla.c b/source/eaxhla.c
index 1f3c7ec..bd72161 100644
--- a/source/eaxhla.c
+++ b/source/eaxhla.c
@@ -18,7 +18,8 @@
 
 unsigned long long anon_variable_counter = 0;
 
-tommy_hashtable variable_table;
+static unsigned symbol_id = 0;
+tommy_hashtable symbol_table;
 
 int has_encountered_error = 0;
 int is_program_found      = 0;
@@ -29,20 +30,20 @@ char * yyfilename = "";
 
 
 int eaxhla_init(void) {
-    tommy_hashtable_init(&variable_table, 256);
+    tommy_hashtable_init(&symbol_table, 256);
     return 0;
 }
 
 static
 void free_variable(void * data) {
-    variable_t * variable = (variable_t*)data;
+    symbol_t * variable = (symbol_t*)data;
     free(variable->name);
     free(variable);
 }
 
 int eaxhla_deinit(void) {
-    tommy_hashtable_foreach(&variable_table, free_variable);
-    tommy_hashtable_done(&variable_table);
+    tommy_hashtable_foreach(&symbol_table, free_variable);
+    tommy_hashtable_done(&symbol_table);
     return 0;
 }
 
@@ -50,31 +51,46 @@ int eaxhla_deinit(void) {
 
 static
 int table_compare_unsigned(const void * arg, const void * obj) {
-  return *(const unsigned *) arg != ((const variable_t*)obj)->_hash;
+  return *(const unsigned *) arg != ((const symbol_t*)obj)->_hash;
 }
 
-void add_variable(variable_t variable) {
-    static unsigned vid = 0;
+void add_variable(symbol_t variable) {
     if (get_variable(variable.name)) {
         // XXX: this should say the varname, but this function does not know it
         //       in fact this source file should not be reporting errors,
         //       it should be returning an error and the parser should check.
-        issue_error("variable declared twice");
+        issue_error("symbol '%s' declared twice", variable.name);
         return;
     }
-    variable._id = vid++;
+    variable._id = symbol_id++;
     // XXX this is cursed
-    variable_t * heap_variable = malloc(sizeof(variable));
+    symbol_t * heap_variable = malloc(sizeof(variable));
     memcpy(heap_variable, &variable, sizeof(variable));
     // */
     heap_variable->_hash = tommy_strhash_u32(0, heap_variable->name);
-    tommy_hashtable_insert(&variable_table,
+    tommy_hashtable_insert(&symbol_table,
                             &heap_variable->_node,
                             heap_variable,
                             heap_variable->_hash
                         );
 }
 
+void add_procedure(symbol_t procedure) {
+    procedure._id = symbol_id++;
+    // XXX this is cursed
+    symbol_t * heap_procedure = malloc(sizeof(procedure));
+    memcpy(heap_procedure, &procedure, sizeof(procedure));
+    // */
+    heap_procedure->_hash = tommy_strhash_u32(0, heap_procedure->name);
+    tommy_hashtable_insert(&symbol_table,
+                            &heap_procedure->_node,
+                            heap_procedure,
+                            heap_procedure->_hash
+                        );
+    //
+    append_instructions(ASMDIRMEM, procedure._id);
+}
+
 /* Are these literals ugly? yes.
  * However it would be much more painful to calculate the values inline.
  */
@@ -161,16 +177,36 @@ char * make_scoped_name(const char * const scope, char * name) {
     return r;
 }
 
-variable_t * get_variable(const char * const name) {
+static
+void * symbol_lookup(const char * const name) {
     unsigned lookup_hash = tommy_strhash_u32(0, name);
-    variable_t * r = tommy_hashtable_search(&variable_table,
-                                            table_compare_unsigned,
-                                            &lookup_hash,
-                                            lookup_hash
-                                        );
+    void * r = tommy_hashtable_search(&symbol_table,
+                                      table_compare_unsigned,
+                                      &lookup_hash,
+                                      lookup_hash
+                                    );
     return r;
 }
 
+symbol_t * get_variable(const char * const name) {
+    symbol_t *r = symbol_lookup(name);
+    if (r
+    &&  r->symbol_type != VARIABLE) {
+        issue_error("the symbol '%s' is not a variable", name);
+        return NULL;
+    }
+    return r;
+}
+
+symbol_t * get_function(const char * const name) {
+    symbol_t * r = symbol_lookup(name);
+    if (r
+    &&  r->symbol_type != FUNCTION) {
+        issue_error("the symbol '%s' is not a function", name);
+        return NULL;
+    }
+    return r;
+}
 
 
 void issue_warning(const char * const format, ...) {
diff --git a/source/eaxhla.h b/source/eaxhla.h
index e6f83fc..52bd7c0 100644
--- a/source/eaxhla.h
+++ b/source/eaxhla.h
@@ -4,21 +4,35 @@
 
 #define WORD_SIZE_IN_BYTES (64/8)
 
+typedef enum {
+    VARIABLE,
+    FUNCTION,
+} symbol_type_t;
+
 typedef struct {
-  union {
-      long   value;
-      void * array_value;
-  };
-  unsigned long long elements;
-  char *     name;
-  int        type;
-  unsigned   _id;
-  unsigned   _hash;
-  tommy_node _node;
-} variable_t;
+    symbol_type_t symbol_type;
+    union {
+        struct { // VARIABLE
+            int type;
+            unsigned long long elements;
+            union {
+                long   value;
+                void * array_value;
+            };
+        };
+        struct { // FUNCTION
+            void * unused;
+        };
+    };
+    char *     name;
+    unsigned   _id;
+    unsigned   _hash;
+    tommy_node _node;
+} symbol_t;
 
-extern tommy_hashtable variable_table;
+extern tommy_hashtable symbol_table;
 
+// Used for naming variables constructed from literals
 extern unsigned long long anon_variable_counter;
 
 typedef struct {
@@ -43,8 +57,12 @@ extern char * make_scoped_name(const char * const scope, char * name);
 extern int can_fit(int type, long long value);
 extern int validate_array_size(int size);
 
-extern void add_variable(variable_t variable);
-extern variable_t * get_variable(const char * const name);
+extern void add_variable(symbol_t variable);
+extern symbol_t * get_variable(const char * const name);
+
+//extern void add_function(symbol_t function);
+extern symbol_t * get_function(const char * const name);
+extern void add_procedure(symbol_t procedure);
 
 extern int type2size(int type);
 
diff --git a/source/eaxhla.y b/source/eaxhla.y
index f957c0f..e0cc6d3 100644
--- a/source/eaxhla.y
+++ b/source/eaxhla.y
@@ -29,7 +29,7 @@
         unsigned long long len;
         void * data;
     } blobval;
-    variable_t varval;
+    symbol_t varval;
     cpuregister_t regval;
 }
 
@@ -127,10 +127,17 @@ system_specifier: UNIX { system_type = UNIX; }
     ;
 
     // XXX: end procedure thing
-function: function_head declaration_section MYBEGIN code END_PROCEDURE { scope = NULL; }
+function: function_head declaration_section MYBEGIN code END_PROCEDURE {
+        scope = NULL;
+        append_instructions(RETN);
+    }
     ;
 
-function_head: function_specifier PROCEDURE IDENTIFIER { scope = $3; }
+function_head: function_specifier PROCEDURE IDENTIFIER {
+        scope = $3;
+        symbol_t procedure;
+        add_procedure(procedure);
+    }
     ;
 
 function_specifier: %empty
@@ -207,7 +214,7 @@ type: S8    { $$ =  S8; }
 immediate: LITERAL { $$.type = IMM; $$.value = $1; }
     | IDENTIFIER   {
         char * varname = make_scoped_name(scope, $1);
-        variable_t * variable = get_variable(varname);
+        symbol_t * variable = get_variable(varname);
         $$.type = REL;
         $$.value = variable->_id;
         free(varname);
@@ -227,7 +234,7 @@ value: artimetric_block
     | LITERAL
     | IDENTIFIER        {
         char * varname = make_scoped_name(scope, $1);
-        variable_t * var = get_variable(varname);
+        symbol_t * var = get_variable(varname);
         $$ = var->value;
         free(var);
     }
@@ -292,9 +299,9 @@ machine_code: %empty
     ;
 
 call: FASTCALL IDENTIFIER arguments {
-        //append_fastcall_begin(/**/);
-        //append_fastcall_arguments();
-        append_fastcall_end();
+        // XXX
+        symbol_t * function = get_function($2);
+        append_instructions(CALL, REL, function->_id);
         free($2);
     }
     ;