|  | %{ | 
|  | /* | 
|  | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | * or more contributor license agreements. See the NOTICE file | 
|  | * distributed with this work for additional information | 
|  | * regarding copyright ownership. The ASF licenses this file | 
|  | * to you under the Apache License, Version 2.0 (the | 
|  | * "License"); you may not use this file except in compliance | 
|  | * with the License. You may obtain a copy of the License at | 
|  | * | 
|  | *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, | 
|  | * software distributed under the License is distributed on an | 
|  | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|  | * KIND, either express or implied. See the License for the | 
|  | * specific language governing permissions and limitations | 
|  | * under the License. | 
|  | */ | 
|  |  | 
|  | /** | 
|  | * Thrift parser. | 
|  | * | 
|  | * This parser is used on a thrift definition file. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #define __STDC_LIMIT_MACROS | 
|  | #define __STDC_FORMAT_MACROS | 
|  | #include <stdio.h> | 
|  | #ifndef _MSC_VER | 
|  | #include <inttypes.h> | 
|  | #else | 
|  | #include <stdint.h> | 
|  | #endif | 
|  | #include <limits.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; | 
|  | int g_arglist = 0; | 
|  | const int struct_is_struct = 0; | 
|  | const int struct_is_union = 1; | 
|  |  | 
|  | %} | 
|  |  | 
|  | /** | 
|  | * This structure is used by the parser to hold the data types associated with | 
|  | * various parse nodes. | 
|  | */ | 
|  | %union { | 
|  | char*          id; | 
|  | int64_t        iconst; | 
|  | double         dconst; | 
|  | bool           tbool; | 
|  | t_doc*         tdoc; | 
|  | 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*          dtext; | 
|  | t_field::e_req ereq; | 
|  | t_annotation*  tannot; | 
|  | t_field_id     tfieldid; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Strings identifier | 
|  | */ | 
|  | %token<id>     tok_identifier | 
|  | %token<id>     tok_literal | 
|  | %token<dtext>  tok_doctext | 
|  | %token<id>     tok_st_identifier | 
|  |  | 
|  | /** | 
|  | * Constant values | 
|  | */ | 
|  | %token<iconst> tok_int_constant | 
|  | %token<dconst> tok_dub_constant | 
|  |  | 
|  | /** | 
|  | * Header keywords | 
|  | */ | 
|  | %token tok_include | 
|  | %token tok_namespace | 
|  | %token tok_cpp_namespace | 
|  | %token tok_cpp_include | 
|  | %token tok_cpp_type | 
|  | %token tok_php_namespace | 
|  | %token tok_py_module | 
|  | %token tok_perl_package | 
|  | %token tok_java_package | 
|  | %token tok_xsd_all | 
|  | %token tok_xsd_optional | 
|  | %token tok_xsd_nillable | 
|  | %token tok_xsd_namespace | 
|  | %token tok_xsd_attrs | 
|  | %token tok_ruby_namespace | 
|  | %token tok_smalltalk_category | 
|  | %token tok_smalltalk_prefix | 
|  | %token tok_cocoa_prefix | 
|  | %token tok_csharp_namespace | 
|  | %token tok_delphi_namespace | 
|  |  | 
|  | /** | 
|  | * Base datatype keywords | 
|  | */ | 
|  | %token tok_void | 
|  | %token tok_bool | 
|  | %token tok_byte | 
|  | %token tok_string | 
|  | %token tok_binary | 
|  | %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_oneway | 
|  |  | 
|  | /** | 
|  | * 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 | 
|  | %token tok_required | 
|  | %token tok_optional | 
|  | %token tok_union | 
|  |  | 
|  | /** | 
|  | * Grammar nodes | 
|  | */ | 
|  |  | 
|  | %type<ttype>     BaseType | 
|  | %type<ttype>     SimpleBaseType | 
|  | %type<ttype>     ContainerType | 
|  | %type<ttype>     SimpleContainerType | 
|  | %type<ttype>     MapType | 
|  | %type<ttype>     SetType | 
|  | %type<ttype>     ListType | 
|  |  | 
|  | %type<tdoc>      Definition | 
|  | %type<ttype>     TypeDefinition | 
|  |  | 
|  | %type<ttypedef>  Typedef | 
|  |  | 
|  | %type<ttype>     TypeAnnotations | 
|  | %type<ttype>     TypeAnnotationList | 
|  | %type<tannot>    TypeAnnotation | 
|  |  | 
|  | %type<tfield>    Field | 
|  | %type<tfieldid>  FieldIdentifier | 
|  | %type<ereq>      FieldRequiredness | 
|  | %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<iconst>    StructHead | 
|  | %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>     Oneway | 
|  | %type<tbool>     XsdAll | 
|  | %type<tbool>     XsdOptional | 
|  | %type<tbool>     XsdNillable | 
|  | %type<tstruct>   XsdAttributes | 
|  | %type<id>        CppType | 
|  |  | 
|  | %type<dtext>     CaptureDocText | 
|  |  | 
|  | %% | 
|  |  | 
|  | /** | 
|  | * 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"); | 
|  | /* | 
|  | TODO(dreiss): Decide whether full-program doctext is worth the trouble. | 
|  | if ($1 != NULL) { | 
|  | g_program->set_doc($1); | 
|  | } | 
|  | */ | 
|  | clear_doctext(); | 
|  | } | 
|  |  | 
|  | CaptureDocText: | 
|  | { | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | $$ = g_doctext; | 
|  | g_doctext = NULL; | 
|  | } else { | 
|  | $$ = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */ | 
|  | DestroyDocText: | 
|  | { | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | clear_doctext(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* We have to DestroyDocText here, otherwise it catches the doctext | 
|  | on the first real element. */ | 
|  | HeaderList: | 
|  | HeaderList DestroyDocText Header | 
|  | { | 
|  | pdebug("HeaderList -> HeaderList Header"); | 
|  | } | 
|  | | | 
|  | { | 
|  | pdebug("HeaderList -> "); | 
|  | } | 
|  |  | 
|  | Header: | 
|  | Include | 
|  | { | 
|  | pdebug("Header -> Include"); | 
|  | } | 
|  | | tok_namespace tok_identifier tok_identifier | 
|  | { | 
|  | pdebug("Header -> tok_namespace tok_identifier tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace($2, $3); | 
|  | } | 
|  | } | 
|  | | tok_namespace '*' tok_identifier | 
|  | { | 
|  | pdebug("Header -> tok_namespace * tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("*", $3); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_cpp_namespace tok_identifier | 
|  | { | 
|  | pwarning(1, "'cpp_namespace' is deprecated. Use 'namespace cpp' instead"); | 
|  | pdebug("Header -> tok_cpp_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("cpp", $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 | 
|  | { | 
|  | pwarning(1, "'php_namespace' is deprecated. Use 'namespace php' instead"); | 
|  | pdebug("Header -> tok_php_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("php", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_py_module tok_identifier | 
|  | { | 
|  | pwarning(1, "'py_module' is deprecated. Use 'namespace py' instead"); | 
|  | pdebug("Header -> tok_py_module tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("py", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_perl_package tok_identifier | 
|  | { | 
|  | pwarning(1, "'perl_package' is deprecated. Use 'namespace perl' instead"); | 
|  | pdebug("Header -> tok_perl_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("perl", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_ruby_namespace tok_identifier | 
|  | { | 
|  | pwarning(1, "'ruby_namespace' is deprecated. Use 'namespace rb' instead"); | 
|  | pdebug("Header -> tok_ruby_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("rb", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_smalltalk_category tok_st_identifier | 
|  | { | 
|  | pwarning(1, "'smalltalk_category' is deprecated. Use 'namespace smalltalk.category' instead"); | 
|  | pdebug("Header -> tok_smalltalk_category tok_st_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("smalltalk.category", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_smalltalk_prefix tok_identifier | 
|  | { | 
|  | pwarning(1, "'smalltalk_prefix' is deprecated. Use 'namespace smalltalk.prefix' instead"); | 
|  | pdebug("Header -> tok_smalltalk_prefix tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("smalltalk.prefix", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_java_package tok_identifier | 
|  | { | 
|  | pwarning(1, "'java_package' is deprecated. Use 'namespace java' instead"); | 
|  | pdebug("Header -> tok_java_package tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("java", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_cocoa_prefix tok_identifier | 
|  | { | 
|  | pwarning(1, "'cocoa_prefix' is deprecated. Use 'namespace cocoa' instead"); | 
|  | pdebug("Header -> tok_cocoa_prefix tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("cocoa", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_xsd_namespace tok_literal | 
|  | { | 
|  | pwarning(1, "'xsd_namespace' is deprecated. Use 'namespace xsd' instead"); | 
|  | pdebug("Header -> tok_xsd_namespace tok_literal"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("cocoa", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_csharp_namespace tok_identifier | 
|  | { | 
|  | pwarning(1, "'csharp_namespace' is deprecated. Use 'namespace csharp' instead"); | 
|  | pdebug("Header -> tok_csharp_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("csharp", $2); | 
|  | } | 
|  | } | 
|  | /* TODO(dreiss): Get rid of this once everyone is using the new hotness. */ | 
|  | | tok_delphi_namespace tok_identifier | 
|  | { | 
|  | pwarning(1, "'delphi_namespace' is deprecated. Use 'namespace delphi' instead"); | 
|  | pdebug("Header -> tok_delphi_namespace tok_identifier"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->set_namespace("delphi", $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, std::string($2)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DefinitionList: | 
|  | DefinitionList CaptureDocText Definition | 
|  | { | 
|  | pdebug("DefinitionList -> DefinitionList Definition"); | 
|  | if ($2 != NULL && $3 != NULL) { | 
|  | $3->set_doc($2); | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | pdebug("DefinitionList -> "); | 
|  | } | 
|  |  | 
|  | Definition: | 
|  | Const | 
|  | { | 
|  | pdebug("Definition -> Const"); | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | g_program->add_const($1); | 
|  | } | 
|  | $$ = $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); | 
|  | } | 
|  | } | 
|  | $$ = $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); | 
|  | } | 
|  | $$ = $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: | 
|  | tok_typedef FieldType tok_identifier TypeAnnotations | 
|  | { | 
|  | pdebug("TypeDef -> tok_typedef FieldType tok_identifier"); | 
|  | t_typedef *td = new t_typedef(g_program, $2, $3); | 
|  | $$ = td; | 
|  | if ($4 != NULL) { | 
|  | $$->annotations_ = $4->annotations_; | 
|  | delete $4; | 
|  | } | 
|  | } | 
|  |  | 
|  | CommaOrSemicolonOptional: | 
|  | ',' | 
|  | {} | 
|  | | ';' | 
|  | {} | 
|  | | | 
|  | {} | 
|  |  | 
|  | Enum: | 
|  | tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations | 
|  | { | 
|  | pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); | 
|  | $$ = $4; | 
|  | $$->set_name($2); | 
|  | if ($6 != NULL) { | 
|  | $$->annotations_ = $6->annotations_; | 
|  | delete $6; | 
|  | } | 
|  | $$->resolve_values(); | 
|  | // make constants for all the enum values | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | const std::vector<t_enum_value*>& enum_values = $$->get_constants(); | 
|  | std::vector<t_enum_value*>::const_iterator c_iter; | 
|  | for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { | 
|  | std::string const_name = $$->get_name() + "." + (*c_iter)->get_name(); | 
|  | t_const_value* const_val = new t_const_value((*c_iter)->get_value()); | 
|  | const_val->set_enum($$); | 
|  | g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); | 
|  | if (g_parent_scope != NULL) { | 
|  | g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | EnumDefList: | 
|  | EnumDefList EnumDef | 
|  | { | 
|  | pdebug("EnumDefList -> EnumDefList EnumDef"); | 
|  | $$ = $1; | 
|  | $$->append($2); | 
|  | } | 
|  | | | 
|  | { | 
|  | pdebug("EnumDefList -> "); | 
|  | $$ = new t_enum(g_program); | 
|  | } | 
|  |  | 
|  | EnumDef: | 
|  | CaptureDocText tok_identifier '=' tok_int_constant TypeAnnotations CommaOrSemicolonOptional | 
|  | { | 
|  | pdebug("EnumDef -> tok_identifier = tok_int_constant"); | 
|  | if ($4 < 0) { | 
|  | pwarning(1, "Negative value supplied for enum %s.\n", $2); | 
|  | } | 
|  | if ($4 > INT_MAX) { | 
|  | pwarning(1, "64-bit value supplied for enum %s.\n", $2); | 
|  | } | 
|  | $$ = new t_enum_value($2, $4); | 
|  | if ($1 != NULL) { | 
|  | $$->set_doc($1); | 
|  | } | 
|  | if ($5 != NULL) { | 
|  | $$->annotations_ = $5->annotations_; | 
|  | delete $5; | 
|  | } | 
|  | } | 
|  | | | 
|  | CaptureDocText tok_identifier TypeAnnotations CommaOrSemicolonOptional | 
|  | { | 
|  | pdebug("EnumDef -> tok_identifier"); | 
|  | $$ = new t_enum_value($2); | 
|  | if ($1 != NULL) { | 
|  | $$->set_doc($1); | 
|  | } | 
|  | if ($3 != NULL) { | 
|  | $$->annotations_ = $3->annotations_; | 
|  | delete $3; | 
|  | } | 
|  | } | 
|  |  | 
|  | Senum: | 
|  | tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations | 
|  | { | 
|  | pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); | 
|  | $$ = new t_typedef(g_program, $4, $2); | 
|  | if ($6 != NULL) { | 
|  | $$->annotations_ = $6->annotations_; | 
|  | delete $6; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | g_scope->resolve_const_value($5, $2); | 
|  | $$ = new t_const($2, $3, $5); | 
|  | validate_const_type($$); | 
|  |  | 
|  | g_scope->add_constant($3, $$); | 
|  | if (g_parent_scope != NULL) { | 
|  | g_parent_scope->add_constant(g_parent_prefix + $3, $$); | 
|  | } | 
|  | } else { | 
|  | $$ = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | ConstValue: | 
|  | tok_int_constant | 
|  | { | 
|  | pdebug("ConstValue => tok_int_constant"); | 
|  | $$ = new t_const_value(); | 
|  | $$->set_integer($1); | 
|  | if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) { | 
|  | pwarning(1, "64-bit constant \"%"PRIi64"\" may not work in all languages.\n", $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($1); | 
|  | } | 
|  | | tok_identifier | 
|  | { | 
|  | pdebug("ConstValue => tok_identifier"); | 
|  | $$ = new t_const_value(); | 
|  | $$->set_identifier($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(); | 
|  | } | 
|  |  | 
|  | StructHead: | 
|  | tok_struct | 
|  | { | 
|  | $$ = struct_is_struct; | 
|  | } | 
|  | | tok_union | 
|  | { | 
|  | $$ = struct_is_union; | 
|  | } | 
|  |  | 
|  | Struct: | 
|  | StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations | 
|  | { | 
|  | pdebug("Struct -> tok_struct tok_identifier { FieldList }"); | 
|  | $5->set_xsd_all($3); | 
|  | $5->set_union($1 == struct_is_union); | 
|  | $$ = $5; | 
|  | $$->set_name($2); | 
|  | if ($7 != NULL) { | 
|  | $$->annotations_ = $7->annotations_; | 
|  | delete $7; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 '}' TypeAnnotations | 
|  | { | 
|  | pdebug("Xception -> tok_xception tok_identifier { FieldList }"); | 
|  | $4->set_name($2); | 
|  | $4->set_xception(true); | 
|  | $$ = $4; | 
|  | if ($6 != NULL) { | 
|  | $$->annotations_ = $6->annotations_; | 
|  | delete $6; | 
|  | } | 
|  | } | 
|  |  | 
|  | Service: | 
|  | tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations | 
|  | { | 
|  | pdebug("Service -> tok_service tok_identifier { FunctionList }"); | 
|  | $$ = $6; | 
|  | $$->set_name($2); | 
|  | $$->set_extends($3); | 
|  | if ($9 != NULL) { | 
|  | $$->annotations_ = $9->annotations_; | 
|  | delete $9; | 
|  | } | 
|  | } | 
|  |  | 
|  | FlagArgs: | 
|  | { | 
|  | g_arglist = 1; | 
|  | } | 
|  |  | 
|  | UnflagArgs: | 
|  | { | 
|  | g_arglist = 0; | 
|  | } | 
|  |  | 
|  | 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: | 
|  | CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional | 
|  | { | 
|  | $6->set_name(std::string($4) + "_args"); | 
|  | $$ = new t_function($3, $4, $6, $8, $2); | 
|  | if ($1 != NULL) { | 
|  | $$->set_doc($1); | 
|  | } | 
|  | if ($9 != NULL) { | 
|  | $$->annotations_ = $9->annotations_; | 
|  | delete $9; | 
|  | } | 
|  | } | 
|  |  | 
|  | Oneway: | 
|  | tok_oneway | 
|  | { | 
|  | $$ = true; | 
|  | } | 
|  | | | 
|  | { | 
|  | $$ = false; | 
|  | } | 
|  |  | 
|  | Throws: | 
|  | tok_throws '(' FieldList ')' | 
|  | { | 
|  | pdebug("Throws -> tok_throws ( FieldList )"); | 
|  | $$ = $3; | 
|  | if (g_parse_mode == PROGRAM && !validate_throws($$)) { | 
|  | yyerror("Throws clause may not contain non-exception types"); | 
|  | exit(1); | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | $$ = new t_struct(g_program); | 
|  | } | 
|  |  | 
|  | FieldList: | 
|  | FieldList Field | 
|  | { | 
|  | pdebug("FieldList -> FieldList , Field"); | 
|  | $$ = $1; | 
|  | if (!($$->append($2))) { | 
|  | yyerror("Field identifier %d for \"%s\" has already been used", $2->get_key(), $2->get_name().c_str()); | 
|  | exit(1); | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | pdebug("FieldList -> "); | 
|  | y_field_val = -1; | 
|  | $$ = new t_struct(g_program); | 
|  | } | 
|  |  | 
|  | Field: | 
|  | CaptureDocText FieldIdentifier FieldRequiredness FieldType tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional | 
|  | { | 
|  | pdebug("tok_int_constant : Field -> FieldType tok_identifier"); | 
|  | if ($2.auto_assigned) { | 
|  | pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $5); | 
|  | if (g_strict >= 192) { | 
|  | yyerror("Implicit field keys are deprecated and not allowed with -strict"); | 
|  | exit(1); | 
|  | } | 
|  | } | 
|  | $$ = new t_field($4, $5, $2.value); | 
|  | $$->set_req($3); | 
|  | if ($6 != NULL) { | 
|  | g_scope->resolve_const_value($6, $4); | 
|  | validate_field_value($$, $6); | 
|  | $$->set_value($6); | 
|  | } | 
|  | $$->set_xsd_optional($7); | 
|  | $$->set_xsd_nillable($8); | 
|  | if ($1 != NULL) { | 
|  | $$->set_doc($1); | 
|  | } | 
|  | if ($9 != NULL) { | 
|  | $$->set_xsd_attrs($9); | 
|  | } | 
|  | if ($10 != NULL) { | 
|  | $$->annotations_ = $10->annotations_; | 
|  | delete $10; | 
|  | } | 
|  | } | 
|  |  | 
|  | FieldIdentifier: | 
|  | tok_int_constant ':' | 
|  | { | 
|  | if ($1 <= 0) { | 
|  | if (g_allow_neg_field_keys) { | 
|  | /* | 
|  | * g_allow_neg_field_keys exists to allow users to add explicitly | 
|  | * specified key values to old .thrift files without breaking | 
|  | * protocol compatibility. | 
|  | */ | 
|  | if ($1 != y_field_val) { | 
|  | /* | 
|  | * warn if the user-specified negative value isn't what | 
|  | * thrift would have auto-assigned. | 
|  | */ | 
|  | pwarning(1, "Negative field key (%d) differs from what would be " | 
|  | "auto-assigned by thrift (%d).\n", $1, y_field_val); | 
|  | } | 
|  | /* | 
|  | * Leave $1 as-is, and update y_field_val to be one less than $1. | 
|  | * The FieldList parsing will catch any duplicate key values. | 
|  | */ | 
|  | y_field_val = $1 - 1; | 
|  | $$.value = $1; | 
|  | $$.auto_assigned = false; | 
|  | } else { | 
|  | pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", | 
|  | $1); | 
|  | $$.value = y_field_val--; | 
|  | $$.auto_assigned = true; | 
|  | } | 
|  | } else { | 
|  | $$.value = $1; | 
|  | $$.auto_assigned = false; | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | $$.value = y_field_val--; | 
|  | $$.auto_assigned = true; | 
|  | } | 
|  |  | 
|  | FieldRequiredness: | 
|  | tok_required | 
|  | { | 
|  | $$ = t_field::T_REQUIRED; | 
|  | } | 
|  | | tok_optional | 
|  | { | 
|  | if (g_arglist) { | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | pwarning(1, "optional keyword is ignored in argument lists.\n"); | 
|  | } | 
|  | $$ = t_field::T_OPT_IN_REQ_OUT; | 
|  | } else { | 
|  | $$ = t_field::T_OPTIONAL; | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | $$ = t_field::T_OPT_IN_REQ_OUT; | 
|  | } | 
|  |  | 
|  | FieldValue: | 
|  | '=' ConstValue | 
|  | { | 
|  | if (g_parse_mode == PROGRAM) { | 
|  | $$ = $2; | 
|  | } else { | 
|  | $$ = NULL; | 
|  | } | 
|  | } | 
|  | | | 
|  | { | 
|  | $$ = NULL; | 
|  | } | 
|  |  | 
|  | 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: SimpleBaseType TypeAnnotations | 
|  | { | 
|  | pdebug("BaseType -> SimpleBaseType TypeAnnotations"); | 
|  | if ($2 != NULL) { | 
|  | $$ = new t_base_type(*static_cast<t_base_type*>($1)); | 
|  | $$->annotations_ = $2->annotations_; | 
|  | delete $2; | 
|  | } else { | 
|  | $$ = $1; | 
|  | } | 
|  | } | 
|  |  | 
|  | SimpleBaseType: | 
|  | tok_string | 
|  | { | 
|  | pdebug("BaseType -> tok_string"); | 
|  | $$ = g_type_string; | 
|  | } | 
|  | | tok_binary | 
|  | { | 
|  | pdebug("BaseType -> tok_binary"); | 
|  | $$ = g_type_binary; | 
|  | } | 
|  | | 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: SimpleContainerType TypeAnnotations | 
|  | { | 
|  | pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); | 
|  | $$ = $1; | 
|  | if ($2 != NULL) { | 
|  | $$->annotations_ = $2->annotations_; | 
|  | delete $2; | 
|  | } | 
|  | } | 
|  |  | 
|  | SimpleContainerType: | 
|  | MapType | 
|  | { | 
|  | pdebug("SimpleContainerType -> MapType"); | 
|  | $$ = $1; | 
|  | } | 
|  | | SetType | 
|  | { | 
|  | pdebug("SimpleContainerType -> SetType"); | 
|  | $$ = $1; | 
|  | } | 
|  | | ListType | 
|  | { | 
|  | pdebug("SimpleContainerType -> 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; | 
|  | } | 
|  |  | 
|  | TypeAnnotations: | 
|  | '(' TypeAnnotationList ')' | 
|  | { | 
|  | pdebug("TypeAnnotations -> ( TypeAnnotationList )"); | 
|  | $$ = $2; | 
|  | } | 
|  | | | 
|  | { | 
|  | $$ = NULL; | 
|  | } | 
|  |  | 
|  | TypeAnnotationList: | 
|  | TypeAnnotationList TypeAnnotation | 
|  | { | 
|  | pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); | 
|  | $$ = $1; | 
|  | $$->annotations_[$2->key] = $2->val; | 
|  | delete $2; | 
|  | } | 
|  | | | 
|  | { | 
|  | /* Just use a dummy structure to hold the annotations. */ | 
|  | $$ = new t_struct(g_program); | 
|  | } | 
|  |  | 
|  | TypeAnnotation: | 
|  | tok_identifier '=' tok_literal CommaOrSemicolonOptional | 
|  | { | 
|  | pdebug("TypeAnnotation -> tok_identifier = tok_literal"); | 
|  | $$ = new t_annotation; | 
|  | $$->key = $1; | 
|  | $$->val = $3; | 
|  | } | 
|  |  | 
|  | %% |