Rev 30 | Blame | Compare with Previous | Last modification | View Log | RSS feed
%{/** 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>#include <inttypes.h>#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;}/*** 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/*** 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> DefinitionType%type<ttype> TypeAnnotations%type<ttype> TypeAnnotationList%type<tannot> TypeAnnotation%type<tfield> Field%type<iconst> 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 doctexton 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);}}/* 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);}}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 DefinitionType tok_identifier{pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");t_typedef *td = new t_typedef(g_program, $2, $3);$$ = td;}CommaOrSemicolonOptional:','{}| ';'{}|{}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($2);}|{pdebug("EnumDefList -> ");$$ = new t_enum(g_program);}EnumDef:CaptureDocText 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);}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 (g_parse_mode == PROGRAM) {g_scope->add_constant($2, new t_const(g_type_i32, $2, new t_const_value($4)));if (g_parent_scope != NULL) {g_parent_scope->add_constant(g_parent_prefix + $2, new t_const(g_type_i32, $2, new t_const_value($4)));}}}|CaptureDocText tok_identifier CommaOrSemicolonOptional{pdebug("EnumDef -> tok_identifier");$$ = new t_enum_value($2);if ($1 != NULL) {$$->set_doc($1);}}Senum:tok_senum tok_identifier '{' SenumDefList '}'{pdebug("Senum -> tok_senum tok_identifier { SenumDefList }");$$ = new t_typedef(g_program, $4, $2);}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($$);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 ($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");t_const* constant = g_scope->get_constant($1);if (constant != NULL) {$$ = constant->get_value();} else {if (g_parse_mode == PROGRAM) {pwarning(1, "Constant strings should be quoted: %s\n", $1);}$$ = new t_const_value($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 '}'{pdebug("Xception -> tok_xception tok_identifier { FieldList }");$4->set_name($2);$4->set_xception(true);$$ = $4;}Service:tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}'{pdebug("Service -> tok_service tok_identifier { FunctionList }");$$ = $6;$$->set_name($2);$$->set_extends($3);}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 CommaOrSemicolonOptional{$6->set_name(std::string($4) + "_args");$$ = new t_function($3, $4, $6, $8, $2);if ($1 != NULL) {$$->set_doc($1);}}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 CommaOrSemicolonOptional{pdebug("tok_int_constant : Field -> FieldType tok_identifier");if ($2 < 0) {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);$$->set_req($3);if ($6 != NULL) {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);}}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--;}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;}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: 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;}%%