| %{ | 
 |  | 
 | /** | 
 |  * 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" | 
 | #include "parse/t_scope.h" | 
 |  | 
 | /** | 
 |  * This global variable is used for automatic numbering of field indices etc. | 
 |  * when parsing the members of a struct. Field values are automatically | 
 |  * assigned starting from -1 and working their way down. | 
 |  */ | 
 | int y_field_val = -1; | 
 |  | 
 | %} | 
 |  | 
 | /** | 
 |  * This structure is used by the parser to hold the data types associated with | 
 |  * various parse nodes. | 
 |  */ | 
 | %union { | 
 |   char*          id; | 
 |   int            iconst; | 
 |   double         dconst; | 
 |   bool           tbool; | 
 |   t_type*        ttype; | 
 |   t_base_type*   tbase; | 
 |   t_typedef*     ttypedef; | 
 |   t_enum*        tenum; | 
 |   t_enum_value*  tenumv; | 
 |   t_const*       tconst; | 
 |   t_const_value* tconstv; | 
 |   t_struct*      tstruct; | 
 |   t_service*     tservice; | 
 |   t_function*    tfunction; | 
 |   t_field*       tfield; | 
 |   char*          tdoc; | 
 | } | 
 |  | 
 | /** | 
 |  * Strings identifier | 
 |  */ | 
 | %token<id>     tok_identifier | 
 | %token<id>     tok_literal | 
 | %token<tdoc>   tok_doctext | 
 |  | 
 | /** | 
 |  * Constant values | 
 |  */ | 
 | %token<iconst> tok_int_constant | 
 | %token<dconst> tok_dub_constant | 
 |  | 
 | /** | 
 |  * Header keywoards | 
 |  */ | 
 | %token tok_include | 
 | %token tok_namespace | 
 | %token tok_cpp_namespace | 
 | %token tok_cpp_include | 
 | %token tok_cpp_type | 
 | %token tok_php_namespace | 
 | %token tok_java_package | 
 | %token tok_xsd_all | 
 | %token tok_xsd_optional | 
 | %token tok_xsd_nillable | 
 | %token tok_xsd_namespace | 
 | %token tok_xsd_attrs | 
 |  | 
 | /** | 
 |  * Base datatype keywords | 
 |  */ | 
 | %token tok_void | 
 | %token tok_bool | 
 | %token tok_byte | 
 | %token tok_string | 
 | %token tok_slist | 
 | %token tok_senum | 
 | %token tok_i16 | 
 | %token tok_i32 | 
 | %token tok_i64 | 
 | %token tok_double | 
 |  | 
 | /** | 
 |  * Complex type keywords | 
 |  */ | 
 | %token tok_map | 
 | %token tok_list | 
 | %token tok_set | 
 |  | 
 | /** | 
 |  * Function modifiers | 
 |  */  | 
 | %token tok_async | 
 |  | 
 | /** | 
 |  * Thrift language keywords | 
 |  */ | 
 | %token tok_typedef | 
 | %token tok_struct | 
 | %token tok_xception | 
 | %token tok_throws | 
 | %token tok_extends | 
 | %token tok_service | 
 | %token tok_enum | 
 | %token tok_const | 
 |  | 
 | /** | 
 |  * Grammar nodes | 
 |  */ | 
 |  | 
 | %type<ttype>     BaseType | 
 | %type<ttype>     ContainerType | 
 | %type<ttype>     MapType | 
 | %type<ttype>     SetType | 
 | %type<ttype>     ListType | 
 |  | 
 | %type<ttype>     TypeDefinition | 
 |  | 
 | %type<ttypedef>  Typedef | 
 | %type<ttype>     DefinitionType | 
 |  | 
 | %type<tfield>    Field | 
 | %type<iconst>    FieldIdentifier | 
 | %type<ttype>     FieldType | 
 | %type<tconstv>   FieldValue | 
 | %type<tstruct>   FieldList | 
 |  | 
 | %type<tenum>     Enum | 
 | %type<tenum>     EnumDefList | 
 | %type<tenumv>    EnumDef | 
 |  | 
 | %type<ttypedef>  Senum | 
 | %type<tbase>     SenumDefList | 
 | %type<id>        SenumDef | 
 |  | 
 | %type<tconst>    Const | 
 | %type<tconstv>   ConstValue | 
 | %type<tconstv>   ConstList | 
 | %type<tconstv>   ConstListContents | 
 | %type<tconstv>   ConstMap | 
 | %type<tconstv>   ConstMapContents | 
 |  | 
 | %type<tstruct>   Struct | 
 | %type<tstruct>   Xception | 
 | %type<tservice>  Service | 
 |  | 
 | %type<tfunction> Function | 
 | %type<ttype>     FunctionType | 
 | %type<tservice>  FunctionList | 
 |  | 
 | %type<tstruct>   Throws | 
 | %type<tservice>  Extends | 
 | %type<tbool>     Async | 
 | %type<tbool>     XsdAll | 
 | %type<tbool>     XsdOptional | 
 | %type<tbool>     XsdNillable | 
 | %type<tstruct>   XsdAttributes | 
 | %type<id>        CppType | 
 |  | 
 | %type<tdoc>      DocTextOptional | 
 |  | 
 | %% | 
 |  | 
 | /** | 
 |  * Thrift Grammar Implementation. | 
 |  * | 
 |  * For the most part this source file works its way top down from what you | 
 |  * might expect to find in a typical .thrift file, i.e. type definitions and | 
 |  * namespaces up top followed by service definitions using those types. | 
 |  */ | 
 |  | 
 | Program: | 
 |   HeaderList DefinitionList | 
 |     { | 
 |       pdebug("Program -> Headers DefinitionList"); | 
 |     } | 
 |  | 
 | HeaderList: | 
 |   HeaderList Header | 
 |     { | 
 |       pdebug("HeaderList -> HeaderList Header"); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("HeaderList -> "); | 
 |     } | 
 |  | 
 | Header: | 
 |   Include | 
 |     { | 
 |       pdebug("Header -> Include"); | 
 |     } | 
 | | tok_namespace tok_identifier | 
 |     { | 
 |       pwarning(1, "'namespace' is deprecated. Use 'cpp_namespace' and/or 'java_package' instead"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->set_cpp_namespace($2); | 
 |         g_program->set_java_package($2); | 
 |       } | 
 |     } | 
 | | tok_cpp_namespace tok_identifier | 
 |     { | 
 |       pdebug("Header -> tok_cpp_namespace tok_identifier"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->set_cpp_namespace($2); | 
 |       } | 
 |     } | 
 | | tok_cpp_include tok_literal | 
 |     { | 
 |       pdebug("Header -> tok_cpp_include tok_literal"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_cpp_include($2); | 
 |       } | 
 |     } | 
 | | tok_php_namespace tok_identifier | 
 |     { | 
 |       pdebug("Header -> tok_php_namespace tok_identifier"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->set_php_namespace($2); | 
 |       } | 
 |     } | 
 | | tok_java_package tok_identifier | 
 |     { | 
 |       pdebug("Header -> tok_java_package tok_identifier"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->set_java_package($2); | 
 |       } | 
 |     } | 
 | | tok_xsd_namespace tok_literal | 
 |     { | 
 |       pdebug("Header -> tok_xsd_namespace tok_literal"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->set_xsd_namespace($2); | 
 |       } | 
 |     } | 
 |  | 
 | Include: | 
 |   tok_include tok_literal | 
 |     { | 
 |       pdebug("Include -> tok_include tok_literal");      | 
 |       if (g_parse_mode == INCLUDES) { | 
 |         std::string path = include_file(std::string($2)); | 
 |         if (!path.empty()) { | 
 |           g_program->add_include(path); | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 | DefinitionList: | 
 |   DefinitionList Definition | 
 |     { | 
 |       pdebug("DefinitionList -> DefinitionList Definition"); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("DefinitionList -> "); | 
 |     } | 
 |  | 
 | Definition: | 
 |   Const | 
 |     { | 
 |       pdebug("Definition -> Const"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_const($1); | 
 |       }     | 
 |     } | 
 | | TypeDefinition | 
 |     { | 
 |       pdebug("Definition -> TypeDefinition"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_scope->add_type($1->get_name(), $1); | 
 |         if (g_parent_scope != NULL) { | 
 |           g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1); | 
 |         } | 
 |       } | 
 |     } | 
 | | Service | 
 |     { | 
 |       pdebug("Definition -> Service"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_scope->add_service($1->get_name(), $1); | 
 |         if (g_parent_scope != NULL) { | 
 |           g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1); | 
 |         } | 
 |         g_program->add_service($1); | 
 |       } | 
 |     } | 
 |  | 
 | TypeDefinition: | 
 |   Typedef | 
 |     { | 
 |       pdebug("TypeDefinition -> Typedef"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_typedef($1); | 
 |       } | 
 |     } | 
 | | Enum | 
 |     { | 
 |       pdebug("TypeDefinition -> Enum"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_enum($1); | 
 |       } | 
 |     } | 
 | | Senum | 
 |     { | 
 |       pdebug("TypeDefinition -> Senum"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_typedef($1); | 
 |       } | 
 |     } | 
 | | Struct | 
 |     { | 
 |       pdebug("TypeDefinition -> Struct"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_struct($1); | 
 |       } | 
 |     } | 
 | | Xception | 
 |     {  | 
 |       pdebug("TypeDefinition -> Xception"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         g_program->add_xception($1); | 
 |       } | 
 |     } | 
 |  | 
 | Typedef: | 
 |   DocTextOptional tok_typedef DefinitionType tok_identifier  | 
 |     { | 
 |       pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier"); | 
 |       t_typedef *td = new t_typedef(g_program, $3, $4); | 
 |       $$ = td; | 
 |       if ($1 != NULL) { | 
 |         td->set_doc($1); | 
 |       } | 
 |     } | 
 |  | 
 | DocTextOptional: | 
 |   tok_doctext | 
 |     { | 
 |       pdebug("DocTextOptional -> tok_doctext"); | 
 |       $$ = $1; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = NULL;  | 
 |     } | 
 |      | 
 | CommaOrSemicolonOptional: | 
 |   ',' | 
 |     {} | 
 | | ';' | 
 |     {} | 
 | | | 
 |     {} | 
 |  | 
 | Enum: | 
 |   DocTextOptional tok_enum tok_identifier '{' EnumDefList '}' | 
 |     { | 
 |       pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); | 
 |       $$ = $5; | 
 |       $$->set_name($3); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |     } | 
 |  | 
 | EnumDefList: | 
 |   EnumDefList EnumDef | 
 |     { | 
 |       pdebug("EnumDefList -> EnumDefList EnumDef"); | 
 |       $$ = $1; | 
 |       $$->append($2); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("EnumDefList -> "); | 
 |       $$ = new t_enum(g_program); | 
 |     } | 
 |  | 
 | EnumDef: | 
 |   DocTextOptional tok_identifier '=' tok_int_constant CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("EnumDef -> tok_identifier = tok_int_constant"); | 
 |       if ($4 < 0) { | 
 |         pwarning(1, "Negative value supplied for enum %s.\n", $2); | 
 |       } | 
 |       $$ = new t_enum_value($2, $4); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |     } | 
 | | | 
 |   DocTextOptional tok_identifier CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("EnumDef -> tok_identifier"); | 
 |       $$ = new t_enum_value($2); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |     } | 
 |  | 
 | Senum: | 
 |   DocTextOptional tok_senum tok_identifier '{' SenumDefList '}' | 
 |     { | 
 |       pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); | 
 |       $$ = new t_typedef(g_program, $5, $3); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |     } | 
 |  | 
 | SenumDefList: | 
 |   SenumDefList SenumDef | 
 |     { | 
 |       pdebug("SenumDefList -> SenumDefList SenumDef"); | 
 |       $$ = $1; | 
 |       $$->add_string_enum_val($2); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("SenumDefList -> "); | 
 |       $$ = new t_base_type("string", t_base_type::TYPE_STRING); | 
 |       $$->set_string_enum(true); | 
 |     } | 
 |  | 
 | SenumDef: | 
 |   tok_literal CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("SenumDef -> tok_literal"); | 
 |       $$ = $1; | 
 |     } | 
 |  | 
 | Const: | 
 |   tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         $$ = new t_const($2, $3, $5); | 
 |         validate_const_type($$); | 
 |       } else { | 
 |         $$ = NULL; | 
 |       } | 
 |     } | 
 |  | 
 | ConstValue: | 
 |   tok_int_constant | 
 |     { | 
 |       pdebug("ConstValue => tok_int_constant"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_integer($1); | 
 |     } | 
 | | tok_dub_constant | 
 |     { | 
 |       pdebug("ConstValue => tok_dub_constant"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_double($1); | 
 |     } | 
 | | tok_literal | 
 |     { | 
 |       pdebug("ConstValue => tok_literal"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_string($1); | 
 |     } | 
 | | tok_identifier | 
 |     { | 
 |       pdebug("ConstValue => tok_identifier"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_string($1); | 
 |     } | 
 | | ConstList | 
 |     { | 
 |       pdebug("ConstValue => ConstList"); | 
 |       $$ = $1; | 
 |     } | 
 | | ConstMap | 
 |     { | 
 |       pdebug("ConstValue => ConstMap"); | 
 |       $$ = $1;  | 
 |     } | 
 |  | 
 | ConstList: | 
 |   '[' ConstListContents ']' | 
 |     { | 
 |       pdebug("ConstList => [ ConstListContents ]"); | 
 |       $$ = $2; | 
 |     } | 
 |  | 
 | ConstListContents: | 
 |   ConstListContents ConstValue CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); | 
 |       $$ = $1; | 
 |       $$->add_list($2); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("ConstListContents =>"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_list(); | 
 |     } | 
 |  | 
 | ConstMap: | 
 |   '{' ConstMapContents '}' | 
 |     { | 
 |       pdebug("ConstMap => { ConstMapContents }"); | 
 |       $$ = $2; | 
 |     } | 
 |  | 
 | ConstMapContents: | 
 |   ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); | 
 |       $$ = $1; | 
 |       $$->add_map($2, $4); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("ConstMapContents =>"); | 
 |       $$ = new t_const_value(); | 
 |       $$->set_map(); | 
 |     } | 
 |  | 
 | Struct: | 
 |   DocTextOptional tok_struct tok_identifier XsdAll '{' FieldList '}' | 
 |     { | 
 |       pdebug("Struct -> tok_struct tok_identifier { FieldList }"); | 
 |       $6->set_name($3); | 
 |       if ($1 != NULL) { | 
 |         $6->set_doc($1); | 
 |       } | 
 |       $6->set_xsd_all($4); | 
 |       $$ = $6; | 
 |       y_field_val = -1; | 
 |     } | 
 |  | 
 | XsdAll: | 
 |   tok_xsd_all | 
 |     { | 
 |       $$ = true; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = false; | 
 |     } | 
 |  | 
 | XsdOptional: | 
 |   tok_xsd_optional | 
 |     { | 
 |       $$ = true; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = false; | 
 |     } | 
 |  | 
 | XsdNillable: | 
 |   tok_xsd_nillable | 
 |     { | 
 |       $$ = true; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = false; | 
 |     } | 
 |  | 
 | XsdAttributes: | 
 |   tok_xsd_attrs '{' FieldList '}' | 
 |     { | 
 |       $$ = $3; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = NULL; | 
 |     } | 
 |  | 
 | Xception: | 
 |   tok_xception tok_identifier '{' FieldList '}' | 
 |     { | 
 |       pdebug("Xception -> tok_xception tok_identifier { FieldList }"); | 
 |       $4->set_name($2); | 
 |       $4->set_xception(true); | 
 | /* | 
 |       if ($4 != NULL) { | 
 |         $5->set_doc($4); | 
 |       } | 
 | */ | 
 |       $$ = $4; | 
 |       y_field_val = -1; | 
 |     } | 
 |  | 
 | Service: | 
 |   DocTextOptional tok_service tok_identifier Extends '{' FunctionList '}' | 
 |     { | 
 |       pdebug("Service -> tok_service tok_identifier { FunctionList }"); | 
 |       $$ = $6; | 
 |       $$->set_name($3); | 
 |       $$->set_extends($4); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |     } | 
 |  | 
 | Extends: | 
 |   tok_extends tok_identifier | 
 |     { | 
 |       pdebug("Extends -> tok_extends tok_identifier"); | 
 |       $$ = NULL; | 
 |       if (g_parse_mode == PROGRAM) { | 
 |         $$ = g_scope->get_service($2); | 
 |         if ($$ == NULL) { | 
 |           yyerror("Service \"%s\" has not been defined.", $2); | 
 |           exit(1); | 
 |         } | 
 |       } | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = NULL; | 
 |     } | 
 |  | 
 | FunctionList: | 
 |   FunctionList Function | 
 |     { | 
 |       pdebug("FunctionList -> FunctionList Function"); | 
 |       $$ = $1; | 
 |       $1->add_function($2); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("FunctionList -> "); | 
 |       $$ = new t_service(g_program); | 
 |     } | 
 |  | 
 | Function: | 
 |   DocTextOptional Async FunctionType tok_identifier '(' FieldList ')' Throws CommaOrSemicolonOptional | 
 |     { | 
 |       $6->set_name(std::string($4) + "_args"); | 
 |       $$ = new t_function($3, $4, $6, $8, $2); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |       y_field_val = -1; | 
 |     } | 
 |  | 
 | Async: | 
 |   tok_async | 
 |     { | 
 |       $$ = true; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = false; | 
 |     } | 
 |  | 
 | Throws: | 
 |   tok_throws '(' FieldList ')' | 
 |     { | 
 |       pdebug("Throws -> tok_throws ( FieldList )"); | 
 |       $$ = $3; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = new t_struct(g_program); | 
 |     } | 
 |  | 
 | FieldList: | 
 |   FieldList Field | 
 |     { | 
 |       pdebug("FieldList -> FieldList , Field"); | 
 |       $$ = $1; | 
 |       $$->append($2); | 
 |     } | 
 | | | 
 |     { | 
 |       pdebug("FieldList -> "); | 
 |       $$ = new t_struct(g_program); | 
 |     } | 
 |  | 
 | Field: | 
 |   DocTextOptional FieldIdentifier FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes CommaOrSemicolonOptional | 
 |     { | 
 |       pdebug("tok_int_constant : Field -> FieldType tok_identifier"); | 
 |       if ($2 < 0) { | 
 |         pwarning(2, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $4); | 
 |       } | 
 |       $$ = new t_field($3, $4, $2); | 
 |       if ($5 != NULL) { | 
 |         validate_field_value($$, $5); | 
 |         $$->set_value($5); | 
 |       } | 
 |       $$->set_xsd_optional($6); | 
 |       $$->set_xsd_nillable($7); | 
 |       if ($1 != NULL) { | 
 |         $$->set_doc($1); | 
 |       } | 
 |       if ($8 != NULL) { | 
 |         $$->set_xsd_attrs($8); | 
 |       } | 
 |     } | 
 |  | 
 | FieldIdentifier: | 
 |   tok_int_constant ':' | 
 |     { | 
 |       if ($1 <= 0) { | 
 |         pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", $1); | 
 |         $1 = y_field_val--; | 
 |       } | 
 |       $$ = $1; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = y_field_val--; | 
 |     } | 
 |  | 
 | FieldValue: | 
 |   '=' ConstValue | 
 |     { | 
 |       if (g_parse_mode == PROGRAM) {      | 
 |         $$ = $2; | 
 |       } else { | 
 |         $$ = NULL; | 
 |       } | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = NULL; | 
 |     } | 
 |  | 
 | DefinitionType: | 
 |   BaseType | 
 |     { | 
 |       pdebug("DefinitionType -> BaseType"); | 
 |       $$ = $1; | 
 |     } | 
 | | ContainerType | 
 |     { | 
 |       pdebug("DefinitionType -> ContainerType"); | 
 |       $$ = $1; | 
 |     } | 
 |  | 
 | FunctionType: | 
 |   FieldType | 
 |     { | 
 |       pdebug("FunctionType -> FieldType"); | 
 |       $$ = $1; | 
 |     } | 
 | | tok_void | 
 |     { | 
 |       pdebug("FunctionType -> tok_void"); | 
 |       $$ = g_type_void; | 
 |     } | 
 |  | 
 | FieldType: | 
 |   tok_identifier | 
 |     { | 
 |       pdebug("FieldType -> tok_identifier"); | 
 |       if (g_parse_mode == INCLUDES) { | 
 |         // Ignore identifiers in include mode | 
 |         $$ = NULL; | 
 |       } else { | 
 |         // Lookup the identifier in the current scope | 
 |         $$ = g_scope->get_type($1); | 
 |         if ($$ == NULL) { | 
 |           yyerror("Type \"%s\" has not been defined.", $1); | 
 |           exit(1); | 
 |         } | 
 |       } | 
 |     } | 
 | | BaseType | 
 |     { | 
 |       pdebug("FieldType -> BaseType"); | 
 |       $$ = $1; | 
 |     } | 
 | | ContainerType | 
 |     { | 
 |       pdebug("FieldType -> ContainerType"); | 
 |       $$ = $1; | 
 |     } | 
 |  | 
 | BaseType: | 
 |   tok_string | 
 |     { | 
 |       pdebug("BaseType -> tok_string"); | 
 |       $$ = g_type_string; | 
 |     } | 
 | | tok_slist | 
 |     { | 
 |       pdebug("BaseType -> tok_slist"); | 
 |       $$ = g_type_slist; | 
 |     } | 
 | | tok_bool | 
 |     { | 
 |       pdebug("BaseType -> tok_bool"); | 
 |       $$ = g_type_bool; | 
 |     } | 
 | | tok_byte | 
 |     { | 
 |       pdebug("BaseType -> tok_byte"); | 
 |       $$ = g_type_byte; | 
 |     } | 
 | | tok_i16 | 
 |     { | 
 |       pdebug("BaseType -> tok_i16"); | 
 |       $$ = g_type_i16; | 
 |     } | 
 | | tok_i32 | 
 |     { | 
 |       pdebug("BaseType -> tok_i32"); | 
 |       $$ = g_type_i32; | 
 |     } | 
 | | tok_i64 | 
 |     { | 
 |       pdebug("BaseType -> tok_i64"); | 
 |       $$ = g_type_i64; | 
 |     } | 
 | | tok_double | 
 |     { | 
 |       pdebug("BaseType -> tok_double"); | 
 |       $$ = g_type_double; | 
 |     } | 
 |  | 
 | ContainerType: | 
 |   MapType | 
 |     { | 
 |       pdebug("ContainerType -> MapType"); | 
 |       $$ = $1; | 
 |     } | 
 | | SetType | 
 |     { | 
 |       pdebug("ContainerType -> SetType"); | 
 |       $$ = $1; | 
 |     } | 
 | | ListType | 
 |     { | 
 |       pdebug("ContainerType -> ListType"); | 
 |       $$ = $1; | 
 |     } | 
 |  | 
 | MapType: | 
 |   tok_map CppType '<' FieldType ',' FieldType '>' | 
 |     { | 
 |       pdebug("MapType -> tok_map <FieldType, FieldType>"); | 
 |       $$ = new t_map($4, $6); | 
 |       if ($2 != NULL) { | 
 |         ((t_container*)$$)->set_cpp_name(std::string($2)); | 
 |       } | 
 |     } | 
 |  | 
 | SetType: | 
 |   tok_set CppType '<' FieldType '>' | 
 |     { | 
 |       pdebug("SetType -> tok_set<FieldType>"); | 
 |       $$ = new t_set($4); | 
 |       if ($2 != NULL) { | 
 |         ((t_container*)$$)->set_cpp_name(std::string($2)); | 
 |       } | 
 |     } | 
 |  | 
 | ListType: | 
 |   tok_list '<' FieldType '>' CppType | 
 |     { | 
 |       pdebug("ListType -> tok_list<FieldType>"); | 
 |       $$ = new t_list($3); | 
 |       if ($5 != NULL) { | 
 |         ((t_container*)$$)->set_cpp_name(std::string($5)); | 
 |       } | 
 |     } | 
 |  | 
 | CppType: | 
 |   tok_cpp_type tok_literal | 
 |     { | 
 |       $$ = $2; | 
 |     } | 
 | | | 
 |     { | 
 |       $$ = NULL; | 
 |     } | 
 |  | 
 | %% |