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();
+ }
+
+%%