Baseline commit for thrift, which is pillar v2

Reviewed By: aditya




git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664711 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
new file mode 100644
index 0000000..b328a1a
--- /dev/null
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -0,0 +1,510 @@
+#include <sys/stat.h>
+#include "t_cpp_generator.h"
+#include "globals.h"
+using namespace std;
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_cpp_generator::init_generator(t_program* tprogram) {
+  // Make output directory
+  mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+
+  // Make output file
+  string f_types_name = string(T_CPP_DIR)+"/"+tprogram->get_name()+"_types.h";
+  f_types_.open(f_types_name.c_str());
+
+  // Print header
+  f_types_ <<
+    autogen_comment();
+
+  // Start ifndef
+  f_types_ <<
+    "#ifndef thrift_" << tprogram->get_name() << "_types_h" << endl <<
+    "#define thrift_" << tprogram->get_name() << "_types_h" << endl <<
+    endl;
+  
+  // Include base types
+  f_types_ <<
+    "#include <sys/types.h>" << endl <<
+    endl;
+}
+
+/**
+ * Closes the output files.
+ */
+void t_cpp_generator::close_generator() {
+  // Close ifndef
+  f_types_ <<
+    "#endif" << endl;
+  
+  // Close output file
+  f_types_.close();
+}
+
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in C++
+ *
+ * @param ttypedef The type definition
+ */
+void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ <<
+    indent() << "typedef " << type_name(ttypedef->get_type()) << " " << 
+    ttypedef->get_symbolic() << ";" << endl <<
+    endl;
+}
+
+/**
+ * Generates code for an enumerated type. In C++, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C++.
+ *
+ * @param tenum The enumeration
+ */
+void t_cpp_generator::generate_enum(t_enum* tenum) {
+  f_types_ <<
+    indent() << "enum " << tenum->get_name() << " {" << endl;
+
+  indent_up();
+
+  vector<t_constant*> constants = tenum->get_constants();
+  vector<t_constant*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_types_ <<
+        "," << endl;
+    }
+    f_types_ <<
+      indent() << (*c_iter)->get_name();
+    if ((*c_iter)->has_value()) {
+      f_types_ <<
+        " = " << (*c_iter)->get_value();
+    }
+  }
+
+  indent_down();
+
+  f_types_ <<
+    endl <<
+    "};" << endl <<
+    endl;
+}
+
+/**
+ * Generates a struct definition for a thrift data type. In C++, this is just
+ * simple C struct with basic data members. There are no constructors,
+ * initializers, etc.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cpp_generator::generate_struct(t_struct* tstruct) {
+  f_types_ <<
+    indent() << "struct " << tstruct->get_name() << " {" << endl;
+  
+  indent_up();
+
+  const t_list* memberlist = tstruct->get_members();
+  vector<t_field*> members = memberlist->elems();
+  vector<t_field*>::iterator m_iter; 
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    f_types_ <<
+      indent() << (*m_iter)->get_type()->get_name() << " " <<
+      (*m_iter)->get_name() << ";" << endl;
+  }
+  
+  indent_down();
+  
+  f_types_ <<
+    indent() << "};" << endl <<
+    endl;
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_cpp_generator::generate_service(t_service* tservice) {
+  // Make output files
+  string f_header_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".h";
+  f_header_.open(f_header_name.c_str());
+  string f_service_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".cc";
+  f_service_.open(f_service_name.c_str());
+
+  // Print header file includes
+  f_header_ << autogen_comment();
+  f_header_ <<
+    "#ifndef " << tservice->get_name() << "_h" << endl <<
+    "#define " << tservice->get_name() << "_h" << endl <<
+    endl <<
+    "#include \"TInterface.h\"" << endl <<
+    "#include \"TDispatcher.h\"" << endl <<
+    "#include \"TProtocol.h\"" << endl <<   
+    endl;
+  f_service_ << autogen_comment();
+  f_service_ <<
+    "#include \"" << tservice->get_name() << "_h\"" << endl << endl;
+
+  // Generate the three main parts of the service
+  generate_service_interface(tservice);
+  generate_service_server(tservice);
+  generate_service_client(tservice);
+
+  f_header_ <<
+    "#endif" << endl;
+
+  // Close files
+  f_header_.close();
+  f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_interface(t_service* tservice) {
+  f_header_ <<
+    "class " << tservice->get_name() << " : public TInterface {" << endl <<
+    " public: " << endl;
+  indent_up(); 
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
+  }
+  f_header_ <<
+    indent() << "virtual ~" << tservice->get_name() << "() = 0;" << endl;
+  indent_down();
+  f_header_ <<
+    "}; " << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_server(t_service* tservice) {
+  // Generate the header portion
+  f_header_ <<
+    "class " << tservice->get_name() << "Server : " <<
+    "public " << tservice->get_name() << ", " <<
+    "public TDispatcher {" << endl <<
+    " public: " << endl;
+  indent_up();
+  f_header_ << 
+    indent() << "std::string dispatch(const std::string& buff);" << endl <<
+    indent() << "virtual ~" << tservice->get_name() << "Server();" << endl;
+  indent_down();
+  f_header_ <<
+    "};" << endl << endl;
+
+  // Generate the dispatch methods
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    generate_dispatch_function(tservice, *f_iter);
+  }
+}
+
+/**
+ * Generates a dispatch function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_cpp_generator::generate_dispatch_function(t_service* tservice,
+                                                 t_function* tfunction) {
+  f_service_ <<
+    "std::string dispatch_" << tfunction->get_name() <<
+    "(const char *_tbuf, " <<
+    tservice->get_name() << " *dispatcher, " <<
+    "TProtocol *protocol) {" << endl;
+  indent_up();
+
+  // Create a field to represent this function's arguments
+  t_field arg_field(tfunction->get_arglist(), "_targs", 0);
+
+  generate_deserialize_struct(&arg_field);
+
+  // Generate the function call
+  indent(f_service_) <<
+    type_name(tfunction->get_returntype()) << " _tresult = dispatcher." <<
+    tfunction->get_name() << "(";
+  vector<t_field*> fields = tfunction->get_arglist()->get_members()->elems();
+  vector<t_field*>::iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_service_ << ", ";
+    }
+    f_service_ << "_targs." << (*f_iter)->get_name();
+  }
+  f_service_ << ");" << endl;
+
+  // Serialize the result
+  indent(f_service_) <<
+    "std::string _tout = "";" << endl;
+  t_field out_field(tfunction->get_returntype(), "_tout", 0);
+  generate_serialize_field(&out_field);
+  
+  indent_down();
+  f_service_ <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_cpp_generator::generate_deserialize_struct(t_field* tfield) {
+    t_struct* tstruct = (t_struct*)(tfield->get_type());
+  vector<t_field*> fields = tstruct->get_members()->elems();
+  vector<t_field*>::iterator f_iter;
+
+  indent(f_service_) <<
+    declare_field(tfield) << endl;
+  indent(f_service_) <<
+    "map<uint32_t,const char*> fmap = protocol.readFieldMap(_tbuf);" << endl;  
+
+  // Declare the fields up front
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    indent(f_service_) <<
+      declare_field(*f_iter) << endl;
+    indent(f_service_) <<
+      "if (fmap.find(" << tfield->get_key() << ") != fmap.end()) {" << endl;
+    indent_up();
+    indent(f_service_) <<
+      "_tbuf = fmap[" << tfield->get_key() << "];" << endl;
+    generate_deserialize_field(*f_iter);
+    indent_down();
+    indent(f_service_) <<
+      "}" << endl;
+  }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(t_field* tfield) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_struct()) {
+    generate_deserialize_struct(tfield);
+  }
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      return;
+    case t_base_type::TYPE_STRING:
+      return;
+    case t_base_type::TYPE_BYTE:
+      return;
+    case t_base_type::TYPE_I32:
+      return;
+    case t_base_type::TYPE_U32:
+      return;
+    case t_base_type::TYPE_I64:
+      return;
+    case t_base_type::TYPE_U64:
+      return;
+    default:
+      throw "compiler error: no C++ name for base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    
+  }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice) {
+  // Generate the header portion
+  f_header_ <<
+    "class " << tservice->get_name() << "Client : " <<
+    "public " << tservice->get_name() << " {" << endl <<
+    " public:" << endl;
+  
+  indent_up();
+  f_header_ <<
+    indent() << tservice->get_name() <<
+    "(TDispatcher& dispatcher, TProtocol& protocol);" << endl;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter; 
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << function_signature(*f_iter) << ";" << endl;
+  }
+  indent_down();
+  
+  f_header_ <<
+    " private:" << endl;
+  indent_up();
+  f_header_ <<
+    indent() << "TDispatcher& dispatcher;" << endl <<
+    indent() << "TProtocol& protocol;" << endl;
+  indent_down();  
+  f_header_ <<
+    "};" << endl <<
+    endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_serialize_field(t_field* tfield) {
+  t_type* type = tfield->get_type();
+  while (type->is_typedef()) {
+    type = ((t_typedef*)type)->get_type();
+  }
+
+  if (type->is_struct()) {
+
+  }
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      return;
+    case t_base_type::TYPE_STRING:
+      return;
+    case t_base_type::TYPE_BYTE:
+      return;
+    case t_base_type::TYPE_I32:
+      return;
+    case t_base_type::TYPE_U32:
+      return;
+    case t_base_type::TYPE_I64:
+      return;
+    case t_base_type::TYPE_U64:
+      return;
+    default:
+      throw "compiler error: no C++ name for base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    
+  }
+}
+
+
+/**
+ * Generates a comment about this code being autogenerated.
+ *
+ * @return C-style comment mentioning that this file is autogenerated.
+ */
+string t_cpp_generator::autogen_comment() {
+  string result = "";
+  return
+    result +
+    "/**\n" +
+    " * Autogenerated by Thrift\n" +
+    " * " + g_time_str +
+    " *\n" +
+    " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    " */\n";
+}
+
+/**
+ * Returns a C++ type name
+ *
+ * @param ttype The type
+ */
+string t_cpp_generator::type_name(t_type* ttype) {
+  if (ttype->is_base_type()) {
+    return base_type_name(((t_base_type*)ttype)->get_base());
+  } else {
+    return ttype->get_name();
+  }
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_cpp_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "std::string";
+  case t_base_type::TYPE_BYTE:
+    return "uint8_t";
+  case t_base_type::TYPE_I32:
+    return "int32_t";
+  case t_base_type::TYPE_U32:
+    return "uint32_t";
+  case t_base_type::TYPE_I64:
+    return "int64_t";
+  case t_base_type::TYPE_U64:
+    return "uint64_t";
+  default:
+    throw "compiler error: no C++ name for base type " + tbase;
+  }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_cpp_generator::declare_field(t_field* tfield) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  return type_name(tfield->get_type()) + " " + tfield->get_name() + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cpp_generator::function_signature(t_function* tfunction) {
+  return
+    type_name(tfunction->get_returntype()) + " " + tfunction->get_name() +
+    "(" + field_list(tfunction->get_arglist()->get_members()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_cpp_generator::field_list(t_list* tlist) {
+  string result = "";
+
+  vector<t_field*> fields = tlist->elems();
+  vector<t_field*>::iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+  }
+  return result;
+}
diff --git a/compiler/src/generate/t_cpp_generator.h b/compiler/src/generate/t_cpp_generator.h
new file mode 100644
index 0000000..87eb72a
--- /dev/null
+++ b/compiler/src/generate/t_cpp_generator.h
@@ -0,0 +1,56 @@
+#ifndef T_CPP_GENERATOR_H
+#define T_CPP_GENERATOR_H
+
+#include <string>
+#include <fstream>
+
+#include "t_generator.h"
+
+#define T_CPP_DIR "gen-cpp"
+
+/**
+ * C++ code generator
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_cpp_generator : public t_generator {
+ public:
+  t_cpp_generator() {}
+  ~t_cpp_generator() {}
+
+  /** Init and close methods */
+  void init_generator(t_program *tprogram);
+  void close_generator();
+
+  /** Program-level generation functions */
+  void generate_typedef (t_typedef*  ttypedef);
+  void generate_enum    (t_enum*     tenum);
+  void generate_struct  (t_struct*   tstruct);
+  void generate_service (t_service*  tservice);
+
+  /** Service-level generation functions */
+  void generate_service_interface (t_service* tservice);
+  void generate_service_server    (t_service* tservice);
+  void generate_service_client    (t_service* tservice);
+
+  /** Serialization constructs */
+  void generate_dispatch_function (t_service* tservice, t_function* tfunction);
+  void generate_deserialize_struct(t_field* tfield);
+  void generate_deserialize_field(t_field* tfield);
+
+  /** Helper rendering functions */
+  std::string autogen_comment();
+  std::string type_name(t_type* ttype);
+  std::string base_type_name(t_base_type::t_base tbase);
+  std::string declare_field(t_field* tfield);
+  std::string function_signature(t_function* tfunction);
+  std::string field_list(t_list* tlist);
+  
+ private:
+  /** File streams */
+  std::ofstream f_types_;
+  std::ofstream f_header_;
+  std::ofstream f_service_;
+};
+
+#endif
diff --git a/compiler/src/generate/t_generator.cc b/compiler/src/generate/t_generator.cc
new file mode 100644
index 0000000..0ba44ac
--- /dev/null
+++ b/compiler/src/generate/t_generator.cc
@@ -0,0 +1,45 @@
+#include "t_generator.h"
+using namespace std;
+
+/**
+ * Top level program generation function. Calls the generator subclass methods
+ * for preparing file streams etc. then iterates over all the parts of the
+ * program to perform the correct actions.
+ *
+ * @param program The thrift program to compile into C++ source
+ */
+void t_generator::generate_program(t_program *tprogram) {
+  // Initialize the generator
+  init_generator(tprogram);
+
+  // Generate typedefs
+  vector<t_typedef*> typedefs = tprogram->get_typedefs();
+  vector<t_typedef*>::iterator td_iter;
+  for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+    generate_typedef(*td_iter);
+  }
+
+  // Generate enums
+  vector<t_enum*> enums = tprogram->get_enums();
+  vector<t_enum*>::iterator en_iter;
+  for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+    generate_enum(*en_iter);
+  }
+
+  // Generate structs
+  vector<t_struct*> structs = tprogram->get_structs();
+  vector<t_struct*>::iterator st_iter;
+  for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
+    generate_struct(*st_iter);
+  }
+
+  // Generate services
+  vector<t_service*> services = tprogram->get_services();
+  vector<t_service*>::iterator sv_iter;
+  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+    generate_service(*sv_iter);
+  }
+
+  // Close the generator
+  close_generator();
+}
diff --git a/compiler/src/generate/t_generator.h b/compiler/src/generate/t_generator.h
new file mode 100644
index 0000000..71d0318
--- /dev/null
+++ b/compiler/src/generate/t_generator.h
@@ -0,0 +1,63 @@
+#ifndef T_GENERATOR_H
+#define T_GENERATOR_H
+
+#include <string>
+#include <iostream>
+#include "parse/t_program.h"
+
+/**
+ * Base class for a thrift code generator. This class defines the basic
+ * routines for code generation and contains the top level method that
+ * dispatches code generation across various components.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_generator {
+ public:
+  t_generator() {}
+  virtual ~t_generator() {}
+
+  /**
+   * Framework generator method that iterates over all the parts of a program
+   * and performs general actions. This is implemented by the base class and
+   * should not be overwritten in the subclasses.
+   */
+  void generate_program  (t_program*  tprogram);
+
+ protected:
+  /** Optional methods that may be imlemented by subclasses. */
+  virtual void init_generator    (t_program*  tprogram) {}
+  virtual void close_generator   () {}
+
+  /** Pure virtual methods implemented by the generator subclasses. */
+  virtual void generate_typedef  (t_typedef*  ttypedef) = 0;
+  virtual void generate_enum     (t_enum*     tenum)    = 0;
+  virtual void generate_struct   (t_struct*   tstruct)  = 0;
+  virtual void generate_service  (t_service*  tservice) = 0;
+
+  /** Indentation level modifiers */
+  void indent_up()   { ++indent_; }
+  void indent_down() { --indent_; }
+
+  /** Indentation print function */
+  std::string indent() {
+    std::string ind = "";
+    int i;
+    for (i = 0; i < indent_; ++i) {
+      ind += "  ";
+    }
+    return ind;
+  }
+
+  /** Indentation wrapper */
+  std::ostream& indent(std::ostream &os) {
+    return os << indent();
+  }
+
+ private:
+  /** Indentation level */
+  int indent_;
+
+};
+
+#endif
diff --git a/compiler/src/globals.h b/compiler/src/globals.h
new file mode 100644
index 0000000..db7e392
--- /dev/null
+++ b/compiler/src/globals.h
@@ -0,0 +1,15 @@
+#ifndef T_GLOBALS_H
+#define T_GLOBALS_H
+
+class t_program;
+
+/** Global variable: the master program parse tree */
+extern t_program* g_program;
+
+/** Global debug state */
+extern int g_debug;
+
+/** Global time string */
+extern char* g_time_str;
+
+#endif
diff --git a/compiler/src/main.cc b/compiler/src/main.cc
new file mode 100644
index 0000000..cc126f8
--- /dev/null
+++ b/compiler/src/main.cc
@@ -0,0 +1,159 @@
+/**
+ * thrift - a lightweight cross-language rpc/serialization tool
+ *
+ * This file contains the main compiler engine for Thrift, which invokes the
+ * scanner/parser to build the thrift object tree. The interface generation
+ * code for each language lives in a file by the language name.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string>
+
+// Careful: must include globals first
+#include "globals.h"
+
+#include "main.h"
+#include "parse/t_program.h"
+#include "generate/t_cpp_generator.h"
+
+using namespace std;
+
+/** Global program tree */
+t_program* g_program;
+
+/** Global debug state */
+int g_debug = 0;
+
+/** Global time string */
+char* g_time_str;
+
+
+/**
+ * Report an error to the user. This is called yyerror for historical
+ * reasons (lex and yacc expect the error reporting routine to be called
+ * this). Call this function to report any errors to the user.
+ * yyerror takes printf style arguments.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void yyerror(char* fmt, ...) {
+  va_list args;
+  fprintf(stderr,
+          "\n!!! Error: line %d (last token was '%s')",
+          yylineno,
+          yytext);
+  fprintf(stderr, "\n!!! ");
+
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+
+  fprintf(stderr, "\n");
+}
+
+/**
+ * Prints a debug message from the parser.
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pdebug(char* fmt, ...) {
+  if (g_debug == 0) {
+    return;
+  }
+  va_list args;
+  printf("[Parse] ");
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  printf("\n");
+}
+
+/**
+ * Prints a failure message and exits
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void failure(char* fmt, ...) {
+  va_list args; 
+  fprintf(stderr, "\n!!! Failure: ");
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+  printf("\n");
+  exit(1);
+}
+
+/**
+ * Diplays the usage message and then exits with an error code.
+ */
+void usage() {
+  fprintf(stderr, "Usage: thrift [-d] <filename>\n");
+  exit(1);
+}
+
+/**
+ * Parse it up.. then spit it back out, in pretty much every language
+ */
+int main(int argc, char** argv) {
+  int i;
+
+  // Check for necessary arguments
+  if (argc < 2) usage();
+
+  for (i = 1; i < argc-1; i++) {
+    if (strcmp(argv[i], "-d") == 0) {
+      g_debug = 1;
+    } else {
+      fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
+      usage();
+    }
+  }
+  
+  // Setup time string
+  time_t now = time(NULL);
+  g_time_str = ctime(&now);
+
+  // Open input file
+  char* input_file = argv[i];
+  yyin = fopen(input_file, "r");
+  if (yyin == 0) {
+    failure("Could not open input file: \"%s\"", input_file);
+  }
+  
+  // Extract program name by dropping directory and .thrift from filename
+  string name = input_file;
+  string::size_type slash = name.rfind("/");
+  if (slash != string::npos) {
+    name = name.substr(slash+1);
+  }
+  string::size_type dot = name.find(".");
+  if (dot != string::npos) {
+    name = name.substr(0, dot);
+  }
+  
+  // Parse it
+  g_program = new t_program(name);
+  if (yyparse() != 0) {
+    failure("Parser error.");
+  }
+
+  // Generate code
+  try {
+    t_cpp_generator* cpp = new t_cpp_generator();
+    cpp->generate_program(g_program);
+    delete cpp;
+  } catch (const char* exc) {
+    printf("Error: %s\n", exc);
+  }
+
+  // Clean up
+  delete g_program;
+
+  // Finished
+  printf("\nDone!\n");
+  return 0;
+}
diff --git a/compiler/src/main.h b/compiler/src/main.h
new file mode 100644
index 0000000..b26142c
--- /dev/null
+++ b/compiler/src/main.h
@@ -0,0 +1,19 @@
+#ifndef T_MAIN_H
+#define T_MAIN_H
+
+/** Defined in the flex library */
+extern int   yylex(void);
+extern int   yyparse(void);
+
+/** Expected to be defined by Flex/Bison */
+extern void  yyerror(char* fmt, ...);
+
+/** Parse debug output */
+extern void  pdebug(char* fmt, ...);
+
+/** Flex utilities */
+extern int   yylineno;
+extern char  yytext[];
+extern FILE* yyin;
+
+#endif
diff --git a/compiler/src/parse/t_base_type.h b/compiler/src/parse/t_base_type.h
new file mode 100644
index 0000000..bc96122
--- /dev/null
+++ b/compiler/src/parse/t_base_type.h
@@ -0,0 +1,34 @@
+#ifndef T_BASE_TYPE_H
+#define T_BASE_TYPE_H
+
+#include "t_type.h"
+
+/**
+ * A thrift base type, which must be one of the defined enumerated types.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_base_type : public t_type {
+ public:
+  /** Enumeration of thrift base types */
+  enum t_base {
+    TYPE_VOID,
+    TYPE_STRING,
+    TYPE_BYTE,
+    TYPE_I32,
+    TYPE_U32,
+    TYPE_I64,
+    TYPE_U64
+  };
+
+  t_base_type(std::string name, t_base base) :
+    t_type(name), base_(base) {}
+    
+  t_base get_base() const { return base_; }
+  bool is_base_type() const { return true; }
+    
+ private:
+  t_base base_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_constant.h b/compiler/src/parse/t_constant.h
new file mode 100644
index 0000000..1f3c868
--- /dev/null
+++ b/compiler/src/parse/t_constant.h
@@ -0,0 +1,26 @@
+#ifndef T_CONSTANT_H
+#define T_CONSTANT_H
+
+#include <string>
+
+class t_constant {
+ public:
+  t_constant(std::string name) :
+    name_(name), has_value_(false), value_(0) {}
+
+  t_constant(std::string name, int value) :
+    name_(name), has_value_(true), value_(value) {}
+
+  ~t_constant() {}
+
+  const std::string& get_name() { return name_; }
+  bool has_value() { return has_value_; }
+  int get_value() { return value_; }
+  
+ private:
+  std::string name_;
+  bool has_value_;
+  int value_;
+};  
+
+#endif
diff --git a/compiler/src/parse/t_enum.h b/compiler/src/parse/t_enum.h
new file mode 100644
index 0000000..f089150
--- /dev/null
+++ b/compiler/src/parse/t_enum.h
@@ -0,0 +1,22 @@
+#ifndef T_ENUM_H
+#define T_ENUM_H
+
+#include "t_constant.h"
+#include <vector>
+
+class t_enum : public t_type {
+ public:
+  t_enum() {}
+  ~t_enum() {}
+
+  void set_name(std::string name) { name_ = name; }
+  void append(t_constant* constant) { constants_.push_back(constant); }
+
+  const std::vector<t_constant*>& get_constants() { return constants_; }
+  bool is_enum() const { return true; }
+
+ private:
+  std::vector<t_constant*> constants_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_field.h b/compiler/src/parse/t_field.h
new file mode 100644
index 0000000..304bb16
--- /dev/null
+++ b/compiler/src/parse/t_field.h
@@ -0,0 +1,29 @@
+#ifndef T_FIELD_H
+#define T_FIELD_H
+
+#include <string>
+
+/**
+ * Class to represent a field in a thrift structure or in a set of arguments
+ * to a thrift function.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_field {
+ public:
+  t_field(t_type* type, std::string name, uint32_t key) :
+    type_(type), name_(name), key_(key) {}
+
+  ~t_field() {}
+
+  t_type* get_type() const { return type_; }
+  const std::string& get_name() const { return name_; }
+  uint32_t get_key() const { return key_; }
+
+ private:
+  t_type* type_;
+  std::string name_;
+  uint32_t key_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_function.h b/compiler/src/parse/t_function.h
new file mode 100644
index 0000000..1caf54a
--- /dev/null
+++ b/compiler/src/parse/t_function.h
@@ -0,0 +1,51 @@
+#ifndef T_FUNCTION_H
+#define T_FUNCTION_H
+
+#include <string>
+#include "t_type.h"
+#include "t_struct.h"
+
+/**
+ * Representation of a function. Key parst are return type, function name,
+ * optional modifiers, and an argument list. Each function also has a
+ * hash signature that is used in the network protocol.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_function {
+ public:
+  t_function(t_type* returntype, std::string name, t_struct* arglist) :
+    returntype_(returntype), name_(name), arglist_(arglist) {}
+
+  ~t_function() {}
+
+  /**
+   * Implementation of the Fowler / Noll / Vo (FNV) Hash 
+   *	http://www.isthe.com/chongo/tech/comp/fnv/
+   */
+  static uint32_t fnv32(const char *s) {
+    uint32_t hash = (uint32_t)216613626;
+    while (*s) {
+      hash +=
+        (hash << 1) +
+        (hash << 4) +
+        (hash << 7) +
+        (hash << 8) +
+        (hash << 24);
+      hash ^= *s++;
+    }
+    return hash;
+  }
+
+  t_type*      get_returntype() const { return returntype_; }
+  const std::string& get_name() const { return name_; }
+  t_struct*    get_arglist()    const { return arglist_; }
+  uint32_t     get_hash()       const { return fnv32(name_.c_str()); }
+ 
+ private:
+  t_type* returntype_;
+  std::string name_;
+  t_struct* arglist_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_list.h b/compiler/src/parse/t_list.h
new file mode 100644
index 0000000..736ac48
--- /dev/null
+++ b/compiler/src/parse/t_list.h
@@ -0,0 +1,27 @@
+#ifndef T_LIST_H
+#define T_LIST_H
+
+#include "t_field.h"
+#include <vector>
+
+/**
+ * List of elements.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_list {
+ public:
+  t_list() {}
+  ~t_list() {}
+
+  /** Add a new field to the list */
+  void append(t_field* elem) { list_.push_back(elem); }
+
+  /** Retrieve the list contents */
+  const std::vector<t_field*>& elems() const { return list_; }
+
+ private:
+  std::vector<t_field*> list_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_program.h b/compiler/src/parse/t_program.h
new file mode 100644
index 0000000..fd35799
--- /dev/null
+++ b/compiler/src/parse/t_program.h
@@ -0,0 +1,90 @@
+#ifndef T_PROGRAM_H
+#define T_PROGRAM_H
+
+#include <string>
+#include <vector>
+
+#include "t_base_type.h"
+#include "t_typedef.h"
+#include "t_enum.h"
+#include "t_struct.h"
+#include "t_service.h"
+
+/**
+ * Top level class representing an entire thrift program. A program consists
+ * fundamentally of the following:
+ *
+ *   Typedefs
+ *   Enumerations
+ *   Structs
+ *   Services
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_program {
+ public:
+  t_program(std::string name) :
+    name_(name) {
+    type_void   = new t_base_type("void",   t_base_type::TYPE_VOID);
+    type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+    type_byte   = new t_base_type("byte",   t_base_type::TYPE_BYTE);
+    type_i32    = new t_base_type("i32",    t_base_type::TYPE_I32);
+    type_u32    = new t_base_type("u32",    t_base_type::TYPE_U32);
+    type_i64    = new t_base_type("i64",    t_base_type::TYPE_I64);
+    type_u64    = new t_base_type("u64",    t_base_type::TYPE_U64);
+  }
+
+  ~t_program() {
+    delete type_string;
+    delete type_byte;
+    delete type_i32;
+    delete type_u32;
+    delete type_i64;
+    delete type_u64;
+  }
+
+  // Name accessor
+  const std::string& get_name() const { return name_; }
+
+  // Accessors for program elements
+  const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
+  const std::vector<t_enum*>&    get_enums()    const { return enums_;    }
+  const std::vector<t_struct*>&  get_structs()  const { return structs_;  }
+  const std::vector<t_service*>& get_services() const { return services_; }
+
+  // New program element addition
+  void add_typedef(t_typedef *td) { typedefs_.push_back(td); }
+  void add_enum   (t_enum *te)    { enums_.push_back(te);    }
+  void add_struct (t_struct *ts)  { structs_.push_back(ts);  }
+  void add_service(t_service *ts) { services_.push_back(ts); }
+
+  // Accessors for global types
+  t_type* get_void_type()   const { return type_void;   }
+  t_type* get_string_type() const { return type_string; }
+  t_type* get_byte_type()   const { return type_byte;   }
+  t_type* get_i32_type()    const { return type_i32;    }
+  t_type* get_u32_type()    const { return type_u32;    }
+  t_type* get_i64_type()    const { return type_i64;    }
+  t_type* get_u64_type()    const { return type_u64;    }
+
+ private:
+  // Name
+  std::string name_;
+
+  // Components
+  std::vector<t_typedef*> typedefs_;
+  std::vector<t_enum*>    enums_;
+  std::vector<t_struct*>  structs_;
+  std::vector<t_service*> services_;
+  
+  // Global base types
+  t_type* type_void;
+  t_type* type_string;
+  t_type* type_byte;
+  t_type* type_i32;
+  t_type* type_u32;
+  t_type* type_i64;
+  t_type* type_u64;  
+};
+
+#endif
diff --git a/compiler/src/parse/t_service.h b/compiler/src/parse/t_service.h
new file mode 100644
index 0000000..92e59b2
--- /dev/null
+++ b/compiler/src/parse/t_service.h
@@ -0,0 +1,23 @@
+#ifndef T_SERVICE_H
+#define T_SERVICE_H
+
+#include "t_function.h"
+#include <vector>
+
+class t_service {
+ public:
+  t_service() {}
+  ~t_service() {}
+
+  void set_name(std::string name) { name_ = name; }
+  void add_function(t_function* func) { functions_.push_back(func); }
+
+  const std::string& get_name() const { return name_; }
+  const std::vector<t_function*>& get_functions() const { return functions_; }
+
+ private:
+  std::string name_;
+  std::vector<t_function*> functions_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_struct.h b/compiler/src/parse/t_struct.h
new file mode 100644
index 0000000..fcc00e7
--- /dev/null
+++ b/compiler/src/parse/t_struct.h
@@ -0,0 +1,23 @@
+#ifndef T_STRUCT_H
+#define T_STRUCT_H
+
+#include <vector>
+#include <string>
+
+#include "t_type.h"
+#include "t_list.h"
+
+class t_struct : public t_type {
+ public:
+  t_struct(std::string name, t_list* members) :
+    t_type(name), members_(members) {}
+  ~t_struct() {}
+
+  t_list* get_members() { return members_; }
+  bool is_struct() { return true; }
+
+ private:
+  t_list* members_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_type.h b/compiler/src/parse/t_type.h
new file mode 100644
index 0000000..436c59e
--- /dev/null
+++ b/compiler/src/parse/t_type.h
@@ -0,0 +1,31 @@
+#ifndef T_TYPE_H
+#define T_TYPE_H
+
+#include <string>
+
+/**
+ * Generic representation of a thrift type.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_type {
+ public:
+  virtual ~t_type() {}
+
+  virtual const std::string& get_name() const { return name_; }
+
+  virtual bool is_base_type() const { return false; }
+  virtual bool is_typedef()   const { return false; }
+  virtual bool is_enum()      const { return false; }
+  virtual bool is_struct()    const { return false; }
+
+ protected:
+  t_type() {}
+
+  t_type(std::string name) :
+    name_(name) {}
+
+  std::string name_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_typedef.h b/compiler/src/parse/t_typedef.h
new file mode 100644
index 0000000..97284be
--- /dev/null
+++ b/compiler/src/parse/t_typedef.h
@@ -0,0 +1,31 @@
+#ifndef T_TYPEDEF_H
+#define T_TYPEDEF_H
+
+#include <string>
+#include "t_type.h"
+
+/**
+ * A typedef is a mapping from a symbolic name to another type.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_typedef : public t_type {
+ public:
+  t_typedef(t_type* type, std::string symbolic) :
+    t_type(symbolic), type_(type), symbolic_(symbolic) {}
+
+  ~t_typedef() {}
+
+  t_type* get_type() const { return type_; }
+  const std::string& get_symbolic() const { return symbolic_; }
+  bool is_typedef() const { return true; }
+
+ private:
+  /** Type that this definition inherits from */
+  t_type* type_;
+
+  /** Symbolic name for this type */
+  std::string symbolic_;
+};
+
+#endif
diff --git a/compiler/src/thrift.l b/compiler/src/thrift.l
new file mode 100644
index 0000000..5164c89
--- /dev/null
+++ b/compiler/src/thrift.l
@@ -0,0 +1,59 @@
+/**
+ * Thrift scanner.
+ * 
+ * Tokenizes a thrift definition file.
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+%{
+
+#include "main.h"
+#include "parse/t_program.h"
+
+/** Must be included AFTER parse/t_program.h */
+#include "thrift.tab.hh"
+
+%}
+
+/** Provides yylineno global */
+%option lex-compat 	
+
+/** Helper definitions */
+intconstant  ([0-9]+)
+identifier   ([a-zA-Z_][a-zA-Z_0-9]*)
+whitespace   ([ \t\r\n]*)
+multicomm    ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
+comment      ("//"[^\n]*)
+symbol       ([\,\{\}\(\)\=])
+
+%%
+
+{whitespace}  { /* do nothing */ }
+{multicomm}   { /* do nothing */ }
+{comment}     { /* do nothing */ }
+
+{symbol}      { return yytext[0];   }
+
+"byte"        { return tok_byte;     }
+"string"      { return tok_string;   }
+"i32"         { return tok_i32;      }
+"u32"         { return tok_u32;      }
+"i64"         { return tok_i64;      }
+"u64"         { return tok_u64;      }
+
+"map"         { return tok_map;      }
+"list"        { return tok_list;     }
+"set"         { return tok_set;      }
+
+"void"        { return tok_void;     }
+"async"       { return tok_async;    }
+
+"typedef"     { return tok_typedef;  }
+"struct"      { return tok_struct;   }
+"function"    { return tok_function; }
+"service"     { return tok_service;  }
+"enum"        { return tok_enum;     }
+
+{intconstant} { yylval.iconst = atoi(yytext) ; return tok_int_constant; }
+{identifier}  { yylval.id = strdup(yytext); return tok_identifier; }
+
+%%
diff --git a/compiler/src/thrift.y b/compiler/src/thrift.y
new file mode 100644
index 0000000..f0fa3c4
--- /dev/null
+++ b/compiler/src/thrift.y
@@ -0,0 +1,318 @@
+%{
+
+/**
+ * Thrift parser.
+ *
+ * This parser is used on a thrift definition file.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+
+#include <stdio.h>
+#include "main.h"
+#include "globals.h"
+#include "parse/t_program.h"
+
+int y_field_val = 0;
+
+%}
+
+%union {
+  char*       id;
+  int         iconst;
+  t_type*     ttype;
+  t_typedef*  ttypedef;
+  t_enum*     tenum;
+  t_struct*   tstruct;
+  t_service*  tservice;
+  t_function* tfunction;
+  t_field*    tfield;
+  t_list*     tlist;
+  t_constant* tconstant;
+}
+
+/** Strings and constants */
+%token<id>     tok_identifier
+%token<iconst> tok_int_constant
+
+/** Base datatypes */
+%token tok_byte
+%token tok_string
+%token tok_i32
+%token tok_u32
+%token tok_i64
+%token tok_u64
+
+/** Complex Types */
+%token tok_map
+%token tok_list
+%token tok_set
+
+/** Function types */
+%token tok_void
+
+/** Modifiers */ 
+%token tok_async
+
+/** Thrift actions */
+%token tok_typedef
+%token tok_struct
+%token tok_function
+%token tok_service
+%token tok_enum
+
+/** Types */
+%type<ttype>     BaseType
+
+%type<ttypedef>  Typedef
+%type<ttype>     DefinitionType
+
+%type<tfield>    Field
+%type<ttype>     FieldType
+%type<tlist>     FieldList
+
+%type<tenum>     Enum
+%type<tenum>     EnumDefList
+%type<tconstant> EnumDef
+
+%type<tstruct>   Struct
+
+%type<tservice>  Service
+
+%type<tfunction> Function
+%type<id>        FunctionModifiers
+%type<ttype>     FunctionType
+%type<tservice>  FunctionList
+
+%%
+
+/** Thrift Grammar */
+
+Program:
+  DefinitionList
+  {
+    pdebug("Program -> DefinitionList");
+  }
+
+DefinitionList:
+  DefinitionList Definition
+    {
+      pdebug("DefinitionList -> DefinitionList Definition");
+    }
+|
+    {
+      pdebug("DefinitionList -> ");
+    }
+
+Definition:
+  Typedef
+    {
+      pdebug("Definition -> Typedef");
+      g_program->add_typedef($1);
+    }
+| Enum
+    {
+      pdebug("Definition -> Enum");
+      g_program->add_enum($1);
+    }
+| Struct
+    {
+      pdebug("Definition -> Struct");
+      g_program->add_struct($1);
+    }
+| Service
+    {
+      pdebug("Definition -> Service");
+      g_program->add_service($1);
+    }  
+
+Typedef:
+  tok_typedef DefinitionType tok_identifier
+    {
+      pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
+      
+      t_typedef *td = new t_typedef($2, $3);
+      $$ = td;
+    }
+
+Enum:
+  tok_enum tok_identifier '{' EnumDefList '}'
+    {
+      pdebug("Enum -> tok_enum tok_identifier { EnumDefList }");
+      $$ = $4;
+      $$->set_name($2);
+    }
+
+EnumDefList:
+  EnumDefList ',' EnumDef
+    {
+      pdebug("EnumDefList -> EnumDefList EnumDef");
+      $$ = $1;
+      $$->append($3);
+    }
+| EnumDef
+    {
+      pdebug("EnumDefList -> EnumDef");
+      $$ = new t_enum;
+      $$->append($1);
+    }
+|
+    {
+      pdebug("EnumDefList -> ");
+      $$ = new t_enum;
+    }
+
+EnumDef:
+  tok_identifier '=' tok_int_constant
+    {
+      if ($3 < 0) {
+        printf("WARNING (%d): Negative value supplied for enum %s.\n", yylineno, $1);
+      }
+      pdebug("EnumDef => tok_identifier = tok_int_constant");
+      $$ = new t_constant($1, $3);
+    }
+|
+  tok_identifier
+    {
+      pdebug("EnumDef => tok_identifier");
+      $$ = new t_constant($1);
+    }
+
+Struct:
+  tok_struct tok_identifier '{' FieldList '}'
+    {
+      pdebug("Struct -> tok_struct tok_identifier { FieldList }");
+      $$ = new t_struct($2, $4);
+      y_field_val = 0;
+    }
+
+Service:
+  tok_service tok_identifier '{' FunctionList '}'
+    {
+      pdebug("Service -> tok_service tok_identifier { FunctionList }");
+      $$ = $4;
+      $$->set_name($2);
+    }
+
+FunctionList:
+  FunctionList Function
+    {
+      pdebug("FunctionList -> FunctionList Function");
+      $$ = $1;
+      $1->add_function($2);
+    }
+|
+    {
+      pdebug("FunctionList -> ");
+      $$ = new t_service;
+    }
+
+Function:
+  FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
+    {
+      t_struct* fun_args = new t_struct("__targs", $5);
+      $$ = new t_function($1, $3, fun_args);
+      y_field_val = 0;
+    }
+
+FunctionModifiers:
+    {
+      /** TODO(mcslee): implement async modifier, etc. */
+      $$ = 0;
+    }
+
+FieldList:
+  FieldList ',' Field
+    {
+      pdebug("FieldList -> FieldList , Field");
+      $$ = $1;
+      $$->append($3);
+    }
+| Field
+    {
+      pdebug("FieldList -> Field");
+      $$ = new t_list;
+      $$->append($1);
+    }
+|
+    {
+      pdebug("FieldList -> ");
+      $$ = new t_list;
+    }
+
+Field:
+  FieldType tok_identifier '=' tok_int_constant
+    {
+      if ($4 < 0) {
+        yyerror("Negative value (%d) not allowed as a field key.", $4);
+      }
+      $$ = new t_field($1, $2, (uint32_t)$4);
+      y_field_val = $4+1;
+    }
+| FieldType tok_identifier
+    {
+      printf("WARNING (%d): No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
+      $$ = new t_field($1, $2, y_field_val++);
+    }
+
+DefinitionType:
+  BaseType
+    {
+      pdebug("DefinitionType -> BaseType");
+      $$ = $1;
+    }
+
+FunctionType:
+  FieldType
+    {
+      $$ = $1;
+    }
+| tok_void
+    {
+      $$ = g_program->get_void_type();
+    }
+
+FieldType:
+  tok_identifier
+    {
+      /** TODO(mcslee): Dynamic type lookup */
+      yyerror("No dynamic type lookup yet.");
+    }
+| BaseType
+    {
+      $$ = $1;
+    }
+
+BaseType:
+  tok_string
+    {
+      pdebug("BaseType -> tok_string");
+      $$ = g_program->get_string_type();
+    }
+| tok_byte
+    {
+      pdebug("BaseType -> tok_byte");
+      $$ = g_program->get_byte_type();
+    }
+| tok_i32
+    {
+      pdebug("BaseType -> tok_i32");
+      $$ = g_program->get_i32_type();
+    }
+| tok_u32
+    {
+      pdebug("BaseType -> tok_u32");
+      $$ = g_program->get_u32_type();
+    }
+| tok_i64
+    {
+      pdebug("BaseType -> tok_i64");
+      $$ = g_program->get_i64_type();
+    }
+| tok_u64
+    {
+      pdebug("BaseType -> tok_u64");
+      $$ = g_program->get_u64_type();
+    }
+
+%%