1%code requires { 2#include "thrift/parse/t_program.h" 3} 4%{ 5/* 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 24/** 25 * Thrift parser. 26 * 27 * This parser is used on a thrift definition file. 28 * 29 */ 30 31#ifndef __STDC_LIMIT_MACROS 32#define __STDC_LIMIT_MACROS 33#endif 34#ifndef __STDC_FORMAT_MACROS 35#define __STDC_FORMAT_MACROS 36#endif 37#include <stdio.h> 38#include <string.h> 39#ifndef _MSC_VER 40#include <inttypes.h> 41#else 42#include <stdint.h> 43#endif 44#include <limits.h> 45#ifdef _MSC_VER 46#include "thrift/windows/config.h" 47#endif 48#include "thrift/main.h" 49#include "thrift/common.h" 50#include "thrift/globals.h" 51#include "thrift/parse/t_program.h" 52#include "thrift/parse/t_scope.h" 53 54#ifdef _MSC_VER 55//warning C4065: switch statement contains 'default' but no 'case' labels 56#pragma warning(disable:4065) 57#endif 58 59/** 60 * This global variable is used for automatic numbering of field indices etc. 61 * when parsing the members of a struct. Field values are automatically 62 * assigned starting from -1 and working their way down. 63 */ 64int y_field_val = -1; 65/** 66 * This global variable is used for automatic numbering of enum values. 67 * y_enum_val is the last value assigned; the next auto-assigned value will be 68 * y_enum_val+1, and then it continues working upwards. Explicitly specified 69 * enum values reset y_enum_val to that value. 70 */ 71int32_t y_enum_val = -1; 72int g_arglist = 0; 73const int struct_is_struct = 0; 74const int struct_is_union = 1; 75 76%} 77 78/** 79 * This structure is used by the parser to hold the data types associated with 80 * various parse nodes. 81 */ 82%union { 83 char* id; 84 int64_t iconst; 85 double dconst; 86 bool tbool; 87 t_doc* tdoc; 88 t_type* ttype; 89 t_base_type* tbase; 90 t_typedef* ttypedef; 91 t_enum* tenum; 92 t_enum_value* tenumv; 93 t_const* tconst; 94 t_const_value* tconstv; 95 t_struct* tstruct; 96 t_service* tservice; 97 t_function* tfunction; 98 t_field* tfield; 99 char* dtext; 100 t_field::e_req ereq; 101 t_annotation* tannot; 102 t_field_id tfieldid; 103} 104 105/** 106 * Strings identifier 107 */ 108%token<id> tok_identifier 109%token<id> tok_literal 110%token<dtext> tok_doctext 111 112/** 113 * Constant values 114 */ 115%token<iconst> tok_int_constant 116%token<dconst> tok_dub_constant 117 118/** 119 * Header keywords 120 */ 121%token tok_include 122%token tok_namespace 123%token tok_cpp_include 124%token tok_cpp_type 125%token tok_xsd_all 126%token tok_xsd_optional 127%token tok_xsd_nillable 128%token tok_xsd_attrs 129 130/** 131 * Base datatype keywords 132 */ 133%token tok_void 134%token tok_bool 135%token tok_string 136%token tok_binary 137%token tok_slist 138%token tok_senum 139%token tok_i8 140%token tok_i16 141%token tok_i32 142%token tok_i64 143%token tok_double 144 145/** 146 * Complex type keywords 147 */ 148%token tok_map 149%token tok_list 150%token tok_set 151 152/** 153 * Function modifiers 154 */ 155%token tok_oneway 156 157/** 158 * Thrift language keywords 159 */ 160%token tok_typedef 161%token tok_struct 162%token tok_xception 163%token tok_throws 164%token tok_extends 165%token tok_service 166%token tok_enum 167%token tok_const 168%token tok_required 169%token tok_optional 170%token tok_union 171%token tok_reference 172 173/** 174 * Grammar nodes 175 */ 176 177%type<ttype> BaseType 178%type<ttype> SimpleBaseType 179%type<ttype> ContainerType 180%type<ttype> SimpleContainerType 181%type<ttype> MapType 182%type<ttype> SetType 183%type<ttype> ListType 184 185%type<tdoc> Definition 186%type<ttype> TypeDefinition 187 188%type<ttypedef> Typedef 189 190%type<ttype> TypeAnnotations 191%type<ttype> TypeAnnotationList 192%type<tannot> TypeAnnotation 193%type<id> TypeAnnotationValue 194 195%type<tfield> Field 196%type<tfieldid> FieldIdentifier 197%type<ereq> FieldRequiredness 198%type<ttype> FieldType 199%type<tconstv> FieldValue 200%type<tstruct> FieldList 201%type<tbool> FieldReference 202 203%type<tenum> Enum 204%type<tenum> EnumDefList 205%type<tenumv> EnumDef 206%type<tenumv> EnumValue 207 208%type<ttypedef> Senum 209%type<tbase> SenumDefList 210%type<id> SenumDef 211 212%type<tconst> Const 213%type<tconstv> ConstValue 214%type<tconstv> ConstList 215%type<tconstv> ConstListContents 216%type<tconstv> ConstMap 217%type<tconstv> ConstMapContents 218 219%type<iconst> StructHead 220%type<tstruct> Struct 221%type<tstruct> Xception 222%type<tservice> Service 223 224%type<tfunction> Function 225%type<ttype> FunctionType 226%type<tservice> FunctionList 227 228%type<tstruct> Throws 229%type<tservice> Extends 230%type<tbool> Oneway 231%type<tbool> XsdAll 232%type<tbool> XsdOptional 233%type<tbool> XsdNillable 234%type<tstruct> XsdAttributes 235%type<id> CppType 236 237%type<dtext> CaptureDocText 238 239%% 240 241/** 242 * Thrift Grammar Implementation. 243 * 244 * For the most part this source file works its way top down from what you 245 * might expect to find in a typical .thrift file, i.e. type definitions and 246 * namespaces up top followed by service definitions using those types. 247 */ 248 249Program: 250 HeaderList DefinitionList 251 { 252 pdebug("Program -> Headers DefinitionList"); 253 if((g_program_doctext_candidate != NULL) && (g_program_doctext_status != ALREADY_PROCESSED)) 254 { 255 g_program->set_doc(g_program_doctext_candidate); 256 g_program_doctext_status = ALREADY_PROCESSED; 257 } 258 clear_doctext(); 259 } 260 261CaptureDocText: 262 { 263 if (g_parse_mode == PROGRAM) { 264 $$ = g_doctext; 265 g_doctext = NULL; 266 } else { 267 $$ = NULL; 268 } 269 } 270 271/* TODO(dreiss): Try to DestroyDocText in all sorts or random places. */ 272DestroyDocText: 273 { 274 if (g_parse_mode == PROGRAM) { 275 clear_doctext(); 276 } 277 } 278 279/* We have to DestroyDocText here, otherwise it catches the doctext 280 on the first real element. */ 281HeaderList: 282 HeaderList DestroyDocText Header 283 { 284 pdebug("HeaderList -> HeaderList Header"); 285 } 286| 287 { 288 pdebug("HeaderList -> "); 289 } 290 291Header: 292 Include 293 { 294 pdebug("Header -> Include"); 295 } 296| tok_namespace tok_identifier tok_identifier TypeAnnotations 297 { 298 pdebug("Header -> tok_namespace tok_identifier tok_identifier"); 299 declare_valid_program_doctext(); 300 if (g_parse_mode == PROGRAM) { 301 g_program->set_namespace($2, $3); 302 } 303 if ($4 != NULL) { 304 g_program->set_namespace_annotations($2, $4->annotations_); 305 delete $4; 306 } 307 } 308| tok_namespace '*' tok_identifier 309 { 310 pdebug("Header -> tok_namespace * tok_identifier"); 311 declare_valid_program_doctext(); 312 if (g_parse_mode == PROGRAM) { 313 g_program->set_namespace("*", $3); 314 } 315 } 316| tok_cpp_include tok_literal 317 { 318 pdebug("Header -> tok_cpp_include tok_literal"); 319 declare_valid_program_doctext(); 320 if (g_parse_mode == PROGRAM) { 321 g_program->add_cpp_include($2); 322 } 323 } 324 325Include: 326 tok_include tok_literal 327 { 328 pdebug("Include -> tok_include tok_literal"); 329 declare_valid_program_doctext(); 330 if (g_parse_mode == INCLUDES) { 331 std::string path = include_file(std::string($2)); 332 if (!path.empty()) { 333 g_program->add_include(path, std::string($2)); 334 } 335 } 336 } 337 338DefinitionList: 339 DefinitionList CaptureDocText Definition 340 { 341 pdebug("DefinitionList -> DefinitionList Definition"); 342 if ($2 != NULL && $3 != NULL) { 343 $3->set_doc($2); 344 } 345 } 346| 347 { 348 pdebug("DefinitionList -> "); 349 } 350 351Definition: 352 Const 353 { 354 pdebug("Definition -> Const"); 355 if (g_parse_mode == PROGRAM) { 356 g_program->add_const($1); 357 } 358 $$ = $1; 359 } 360| TypeDefinition 361 { 362 pdebug("Definition -> TypeDefinition"); 363 if (g_parse_mode == PROGRAM) { 364 g_scope->add_type($1->get_name(), $1); 365 if (g_parent_scope != NULL) { 366 g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1); 367 } 368 if (! g_program->is_unique_typename($1)) { 369 yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); 370 exit(1); 371 } 372 } 373 $$ = $1; 374 } 375| Service 376 { 377 pdebug("Definition -> Service"); 378 if (g_parse_mode == PROGRAM) { 379 g_scope->add_service($1->get_name(), $1); 380 if (g_parent_scope != NULL) { 381 g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1); 382 } 383 g_program->add_service($1); 384 if (! g_program->is_unique_typename($1)) { 385 yyerror("Type \"%s\" is already defined.", $1->get_name().c_str()); 386 exit(1); 387 } 388 } 389 $$ = $1; 390 } 391 392TypeDefinition: 393 Typedef 394 { 395 pdebug("TypeDefinition -> Typedef"); 396 if (g_parse_mode == PROGRAM) { 397 g_program->add_typedef($1); 398 } 399 } 400| Enum 401 { 402 pdebug("TypeDefinition -> Enum"); 403 if (g_parse_mode == PROGRAM) { 404 g_program->add_enum($1); 405 } 406 } 407| Senum 408 { 409 pdebug("TypeDefinition -> Senum"); 410 if (g_parse_mode == PROGRAM) { 411 g_program->add_typedef($1); 412 } 413 } 414| Struct 415 { 416 pdebug("TypeDefinition -> Struct"); 417 if (g_parse_mode == PROGRAM) { 418 g_program->add_struct($1); 419 } 420 } 421| Xception 422 { 423 pdebug("TypeDefinition -> Xception"); 424 if (g_parse_mode == PROGRAM) { 425 g_program->add_xception($1); 426 } 427 } 428 429CommaOrSemicolonOptional: 430 ',' 431 {} 432| ';' 433 {} 434| 435 {} 436 437Typedef: 438 tok_typedef FieldType tok_identifier TypeAnnotations CommaOrSemicolonOptional 439 { 440 pdebug("TypeDef -> tok_typedef FieldType tok_identifier"); 441 validate_simple_identifier( $3); 442 t_typedef *td = new t_typedef(g_program, $2, $3); 443 $$ = td; 444 if ($4 != NULL) { 445 $$->annotations_ = $4->annotations_; 446 delete $4; 447 } 448 } 449 450Enum: 451 tok_enum tok_identifier '{' EnumDefList '}' TypeAnnotations 452 { 453 pdebug("Enum -> tok_enum tok_identifier { EnumDefList }"); 454 $$ = $4; 455 validate_simple_identifier( $2); 456 $$->set_name($2); 457 if ($6 != NULL) { 458 $$->annotations_ = $6->annotations_; 459 delete $6; 460 } 461 462 // make constants for all the enum values 463 if (g_parse_mode == PROGRAM) { 464 const std::vector<t_enum_value*>& enum_values = $$->get_constants(); 465 std::vector<t_enum_value*>::const_iterator c_iter; 466 for (c_iter = enum_values.begin(); c_iter != enum_values.end(); ++c_iter) { 467 std::string const_name = $$->get_name() + "." + (*c_iter)->get_name(); 468 t_const_value* const_val = new t_const_value((*c_iter)->get_value()); 469 const_val->set_enum($$); 470 g_scope->add_constant(const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); 471 if (g_parent_scope != NULL) { 472 g_parent_scope->add_constant(g_parent_prefix + const_name, new t_const(g_type_i32, (*c_iter)->get_name(), const_val)); 473 } 474 } 475 } 476 } 477 478EnumDefList: 479 EnumDefList EnumDef 480 { 481 pdebug("EnumDefList -> EnumDefList EnumDef"); 482 $$ = $1; 483 $$->append($2); 484 } 485| 486 { 487 pdebug("EnumDefList -> "); 488 $$ = new t_enum(g_program); 489 y_enum_val = -1; 490 } 491 492EnumDef: 493 CaptureDocText EnumValue TypeAnnotations CommaOrSemicolonOptional 494 { 495 pdebug("EnumDef -> EnumValue"); 496 $$ = $2; 497 if ($1 != NULL) { 498 $$->set_doc($1); 499 } 500 if ($3 != NULL) { 501 $$->annotations_ = $3->annotations_; 502 delete $3; 503 } 504 } 505 506EnumValue: 507 tok_identifier '=' tok_int_constant 508 { 509 pdebug("EnumValue -> tok_identifier = tok_int_constant"); 510 if ($3 < INT32_MIN || $3 > INT32_MAX) { 511 // Note: this used to be just a warning. However, since thrift always 512 // treats enums as i32 values, I'm changing it to a fatal error. 513 // I doubt this will affect many people, but users who run into this 514 // will have to update their thrift files to manually specify the 515 // truncated i32 value that thrift has always been using anyway. 516 failure("64-bit value supplied for enum %s will be truncated.", $1); 517 } 518 y_enum_val = static_cast<int32_t>($3); 519 $$ = new t_enum_value($1, y_enum_val); 520 } 521 | 522 tok_identifier 523 { 524 pdebug("EnumValue -> tok_identifier"); 525 validate_simple_identifier( $1); 526 if (y_enum_val == INT32_MAX) { 527 failure("enum value overflow at enum %s", $1); 528 } 529 ++y_enum_val; 530 $$ = new t_enum_value($1, y_enum_val); 531 } 532 533Senum: 534 tok_senum tok_identifier '{' SenumDefList '}' TypeAnnotations 535 { 536 pdebug("Senum -> tok_senum tok_identifier { SenumDefList }"); 537 validate_simple_identifier( $2); 538 $$ = new t_typedef(g_program, $4, $2); 539 if ($6 != NULL) { 540 $$->annotations_ = $6->annotations_; 541 delete $6; 542 } 543 } 544 545SenumDefList: 546 SenumDefList SenumDef 547 { 548 pdebug("SenumDefList -> SenumDefList SenumDef"); 549 $$ = $1; 550 $$->add_string_enum_val($2); 551 } 552| 553 { 554 pdebug("SenumDefList -> "); 555 $$ = new t_base_type("string", t_base_type::TYPE_STRING); 556 $$->set_string_enum(true); 557 } 558 559SenumDef: 560 tok_literal CommaOrSemicolonOptional 561 { 562 pdebug("SenumDef -> tok_literal"); 563 $$ = $1; 564 } 565 566Const: 567 tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional 568 { 569 pdebug("Const -> tok_const FieldType tok_identifier = ConstValue"); 570 if (g_parse_mode == PROGRAM) { 571 validate_simple_identifier( $3); 572 g_scope->resolve_const_value($5, $2); 573 $$ = new t_const($2, $3, $5); 574 validate_const_type($$); 575 576 g_scope->add_constant($3, $$); 577 if (g_parent_scope != NULL) { 578 g_parent_scope->add_constant(g_parent_prefix + $3, $$); 579 } 580 } else { 581 $$ = NULL; 582 } 583 } 584 585ConstValue: 586 tok_int_constant 587 { 588 pdebug("ConstValue => tok_int_constant"); 589 $$ = new t_const_value(); 590 $$->set_integer($1); 591 if (!g_allow_64bit_consts && ($1 < INT32_MIN || $1 > INT32_MAX)) { 592 pwarning(1, "64-bit constant \"%" PRIi64"\" may not work in all languages.\n", $1); 593 } 594 } 595| tok_dub_constant 596 { 597 pdebug("ConstValue => tok_dub_constant"); 598 $$ = new t_const_value(); 599 $$->set_double($1); 600 } 601| tok_literal 602 { 603 pdebug("ConstValue => tok_literal"); 604 $$ = new t_const_value($1); 605 } 606| tok_identifier 607 { 608 pdebug("ConstValue => tok_identifier"); 609 $$ = new t_const_value(); 610 $$->set_identifier($1); 611 } 612| ConstList 613 { 614 pdebug("ConstValue => ConstList"); 615 $$ = $1; 616 } 617| ConstMap 618 { 619 pdebug("ConstValue => ConstMap"); 620 $$ = $1; 621 } 622 623ConstList: 624 '[' ConstListContents ']' 625 { 626 pdebug("ConstList => [ ConstListContents ]"); 627 $$ = $2; 628 } 629 630ConstListContents: 631 ConstListContents ConstValue CommaOrSemicolonOptional 632 { 633 pdebug("ConstListContents => ConstListContents ConstValue CommaOrSemicolonOptional"); 634 $$ = $1; 635 $$->add_list($2); 636 } 637| 638 { 639 pdebug("ConstListContents =>"); 640 $$ = new t_const_value(); 641 $$->set_list(); 642 } 643 644ConstMap: 645 '{' ConstMapContents '}' 646 { 647 pdebug("ConstMap => { ConstMapContents }"); 648 $$ = $2; 649 } 650 651ConstMapContents: 652 ConstMapContents ConstValue ':' ConstValue CommaOrSemicolonOptional 653 { 654 pdebug("ConstMapContents => ConstMapContents ConstValue CommaOrSemicolonOptional"); 655 $$ = $1; 656 $$->add_map($2, $4); 657 } 658| 659 { 660 pdebug("ConstMapContents =>"); 661 $$ = new t_const_value(); 662 $$->set_map(); 663 } 664 665StructHead: 666 tok_struct 667 { 668 $$ = struct_is_struct; 669 } 670| tok_union 671 { 672 $$ = struct_is_union; 673 } 674 675Struct: 676 StructHead tok_identifier XsdAll '{' FieldList '}' TypeAnnotations 677 { 678 pdebug("Struct -> tok_struct tok_identifier { FieldList }"); 679 validate_simple_identifier( $2); 680 $5->set_xsd_all($3); 681 $5->set_union($1 == struct_is_union); 682 $$ = $5; 683 $$->set_name($2); 684 if ($7 != NULL) { 685 $$->annotations_ = $7->annotations_; 686 delete $7; 687 } 688 } 689 690XsdAll: 691 tok_xsd_all 692 { 693 $$ = true; 694 } 695| 696 { 697 $$ = false; 698 } 699 700XsdOptional: 701 tok_xsd_optional 702 { 703 $$ = true; 704 } 705| 706 { 707 $$ = false; 708 } 709 710XsdNillable: 711 tok_xsd_nillable 712 { 713 $$ = true; 714 } 715| 716 { 717 $$ = false; 718 } 719 720XsdAttributes: 721 tok_xsd_attrs '{' FieldList '}' 722 { 723 $$ = $3; 724 } 725| 726 { 727 $$ = NULL; 728 } 729 730Xception: 731 tok_xception tok_identifier '{' FieldList '}' TypeAnnotations 732 { 733 pdebug("Xception -> tok_xception tok_identifier { FieldList }"); 734 validate_simple_identifier( $2); 735 $4->set_name($2); 736 $4->set_xception(true); 737 $$ = $4; 738 if ($6 != NULL) { 739 $$->annotations_ = $6->annotations_; 740 delete $6; 741 } 742 } 743 744Service: 745 tok_service tok_identifier Extends '{' FlagArgs FunctionList UnflagArgs '}' TypeAnnotations 746 { 747 pdebug("Service -> tok_service tok_identifier { FunctionList }"); 748 validate_simple_identifier( $2); 749 $$ = $6; 750 $$->set_name($2); 751 $$->set_extends($3); 752 if ($9 != NULL) { 753 $$->annotations_ = $9->annotations_; 754 delete $9; 755 } 756 } 757 758FlagArgs: 759 { 760 g_arglist = 1; 761 } 762 763UnflagArgs: 764 { 765 g_arglist = 0; 766 } 767 768Extends: 769 tok_extends tok_identifier 770 { 771 pdebug("Extends -> tok_extends tok_identifier"); 772 $$ = NULL; 773 if (g_parse_mode == PROGRAM) { 774 $$ = g_scope->get_service($2); 775 if ($$ == NULL) { 776 yyerror("Service \"%s\" has not been defined.", $2); 777 exit(1); 778 } 779 } 780 } 781| 782 { 783 $$ = NULL; 784 } 785 786FunctionList: 787 FunctionList Function 788 { 789 pdebug("FunctionList -> FunctionList Function"); 790 $$ = $1; 791 $1->add_function($2); 792 } 793| 794 { 795 pdebug("FunctionList -> "); 796 $$ = new t_service(g_program); 797 } 798 799Function: 800 CaptureDocText Oneway FunctionType tok_identifier '(' FieldList ')' Throws TypeAnnotations CommaOrSemicolonOptional 801 { 802 validate_simple_identifier( $4); 803 $6->set_name(std::string($4) + "_args"); 804 $$ = new t_function($3, $4, $6, $8, $2); 805 if ($1 != NULL) { 806 $$->set_doc($1); 807 } 808 if ($9 != NULL) { 809 $$->annotations_ = $9->annotations_; 810 delete $9; 811 } 812 } 813 814Oneway: 815 tok_oneway 816 { 817 $$ = true; 818 } 819| 820 { 821 $$ = false; 822 } 823 824Throws: 825 tok_throws '(' FieldList ')' 826 { 827 pdebug("Throws -> tok_throws ( FieldList )"); 828 $$ = $3; 829 if (g_parse_mode == PROGRAM && !validate_throws($$)) { 830 yyerror("Throws clause may not contain non-exception types"); 831 exit(1); 832 } 833 } 834| 835 { 836 $$ = new t_struct(g_program); 837 } 838 839FieldList: 840 FieldList Field 841 { 842 pdebug("FieldList -> FieldList , Field"); 843 $$ = $1; 844 if (!($$->append($2))) { 845 yyerror("\"%d: %s\" - field identifier/name has already been used", $2->get_key(), $2->get_name().c_str()); 846 exit(1); 847 } 848 } 849| 850 { 851 pdebug("FieldList -> "); 852 y_field_val = -1; 853 $$ = new t_struct(g_program); 854 } 855 856Field: 857 CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional 858 { 859 pdebug("tok_int_constant : Field -> FieldType tok_identifier"); 860 if ($2.auto_assigned) { 861 pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6); 862 if (g_strict >= 192) { 863 yyerror("Implicit field keys are deprecated and not allowed with -strict"); 864 exit(1); 865 } 866 } 867 validate_simple_identifier($6); 868 $$ = new t_field($4, $6, $2.value); 869 $$->set_reference($5); 870 $$->set_req($3); 871 if ($7 != NULL) { 872 g_scope->resolve_const_value($7, $4); 873 validate_field_value($$, $7); 874 $$->set_value($7); 875 } 876 $$->set_xsd_optional($8); 877 $$->set_xsd_nillable($9); 878 if ($1 != NULL) { 879 $$->set_doc($1); 880 } 881 if ($10 != NULL) { 882 $$->set_xsd_attrs($10); 883 } 884 if ($11 != NULL) { 885 $$->annotations_ = $11->annotations_; 886 delete $11; 887 } 888 } 889 890FieldIdentifier: 891 tok_int_constant ':' 892 { 893 if ($1 <= 0) { 894 if (g_allow_neg_field_keys) { 895 /* 896 * g_allow_neg_field_keys exists to allow users to add explicitly 897 * specified key values to old .thrift files without breaking 898 * protocol compatibility. 899 */ 900 if ($1 != y_field_val) { 901 /* 902 * warn if the user-specified negative value isn't what 903 * thrift would have auto-assigned. 904 */ 905 pwarning(1, "Nonpositive field key (%" PRIi64") differs from what would be " 906 "auto-assigned by thrift (%d).\n", $1, y_field_val); 907 } 908 /* 909 * Leave $1 as-is, and update y_field_val to be one less than $1. 910 * The FieldList parsing will catch any duplicate key values. 911 */ 912 y_field_val = static_cast<int32_t>($1 - 1); 913 $$.value = static_cast<int32_t>($1); 914 $$.auto_assigned = false; 915 } else { 916 pwarning(1, "Nonpositive value (%d) not allowed as a field key.\n", 917 $1); 918 $$.value = y_field_val--; 919 $$.auto_assigned = true; 920 } 921 } else { 922 $$.value = static_cast<int32_t>($1); 923 $$.auto_assigned = false; 924 } 925 if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { 926 pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", 927 $$.value, SHRT_MIN, SHRT_MAX); 928 } 929 } 930| 931 { 932 $$.value = y_field_val--; 933 $$.auto_assigned = true; 934 if( (SHRT_MIN > $$.value) || ($$.value > SHRT_MAX)) { 935 pwarning(1, "Field key (%d) exceeds allowed range (%d..%d).\n", 936 $$.value, SHRT_MIN, SHRT_MAX); 937 } 938 } 939 940FieldReference: 941 tok_reference 942 { 943 $$ = true; 944 } 945| 946 { 947 $$ = false; 948 } 949 950FieldRequiredness: 951 tok_required 952 { 953 $$ = t_field::T_REQUIRED; 954 } 955| tok_optional 956 { 957 if (g_arglist) { 958 if (g_parse_mode == PROGRAM) { 959 pwarning(1, "optional keyword is ignored in argument lists.\n"); 960 } 961 $$ = t_field::T_OPT_IN_REQ_OUT; 962 } else { 963 $$ = t_field::T_OPTIONAL; 964 } 965 } 966| 967 { 968 $$ = t_field::T_OPT_IN_REQ_OUT; 969 } 970 971FieldValue: 972 '=' ConstValue 973 { 974 if (g_parse_mode == PROGRAM) { 975 $$ = $2; 976 } else { 977 $$ = NULL; 978 } 979 } 980| 981 { 982 $$ = NULL; 983 } 984 985FunctionType: 986 FieldType 987 { 988 pdebug("FunctionType -> FieldType"); 989 $$ = $1; 990 } 991| tok_void 992 { 993 pdebug("FunctionType -> tok_void"); 994 $$ = g_type_void; 995 } 996 997FieldType: 998 tok_identifier 999 { 1000 pdebug("FieldType -> tok_identifier"); 1001 if (g_parse_mode == INCLUDES) { 1002 // Ignore identifiers in include mode 1003 $$ = NULL; 1004 } else { 1005 // Lookup the identifier in the current scope 1006 $$ = g_scope->get_type($1); 1007 if ($$ == NULL) { 1008 /* 1009 * Either this type isn't yet declared, or it's never 1010 declared. Either way allow it and we'll figure it out 1011 during generation. 1012 */ 1013 $$ = new t_typedef(g_program, $1, true); 1014 } 1015 } 1016 } 1017| BaseType 1018 { 1019 pdebug("FieldType -> BaseType"); 1020 $$ = $1; 1021 } 1022| ContainerType 1023 { 1024 pdebug("FieldType -> ContainerType"); 1025 $$ = $1; 1026 } 1027 1028BaseType: SimpleBaseType TypeAnnotations 1029 { 1030 pdebug("BaseType -> SimpleBaseType TypeAnnotations"); 1031 if ($2 != NULL) { 1032 $$ = new t_base_type(*static_cast<t_base_type*>($1)); 1033 $$->annotations_ = $2->annotations_; 1034 delete $2; 1035 } else { 1036 $$ = $1; 1037 } 1038 } 1039 1040SimpleBaseType: 1041 tok_string 1042 { 1043 pdebug("BaseType -> tok_string"); 1044 $$ = g_type_string; 1045 } 1046| tok_binary 1047 { 1048 pdebug("BaseType -> tok_binary"); 1049 $$ = g_type_binary; 1050 } 1051| tok_slist 1052 { 1053 pdebug("BaseType -> tok_slist"); 1054 $$ = g_type_slist; 1055 } 1056| tok_bool 1057 { 1058 pdebug("BaseType -> tok_bool"); 1059 $$ = g_type_bool; 1060 } 1061| tok_i8 1062 { 1063 pdebug("BaseType -> tok_i8"); 1064 $$ = g_type_i8; 1065 } 1066| tok_i16 1067 { 1068 pdebug("BaseType -> tok_i16"); 1069 $$ = g_type_i16; 1070 } 1071| tok_i32 1072 { 1073 pdebug("BaseType -> tok_i32"); 1074 $$ = g_type_i32; 1075 } 1076| tok_i64 1077 { 1078 pdebug("BaseType -> tok_i64"); 1079 $$ = g_type_i64; 1080 } 1081| tok_double 1082 { 1083 pdebug("BaseType -> tok_double"); 1084 $$ = g_type_double; 1085 } 1086 1087ContainerType: SimpleContainerType TypeAnnotations 1088 { 1089 pdebug("ContainerType -> SimpleContainerType TypeAnnotations"); 1090 $$ = $1; 1091 if ($2 != NULL) { 1092 $$->annotations_ = $2->annotations_; 1093 delete $2; 1094 } 1095 } 1096 1097SimpleContainerType: 1098 MapType 1099 { 1100 pdebug("SimpleContainerType -> MapType"); 1101 $$ = $1; 1102 } 1103| SetType 1104 { 1105 pdebug("SimpleContainerType -> SetType"); 1106 $$ = $1; 1107 } 1108| ListType 1109 { 1110 pdebug("SimpleContainerType -> ListType"); 1111 $$ = $1; 1112 } 1113 1114MapType: 1115 tok_map CppType '<' FieldType ',' FieldType '>' 1116 { 1117 pdebug("MapType -> tok_map <FieldType, FieldType>"); 1118 $$ = new t_map($4, $6); 1119 if ($2 != NULL) { 1120 ((t_container*)$$)->set_cpp_name(std::string($2)); 1121 } 1122 } 1123 1124SetType: 1125 tok_set CppType '<' FieldType '>' 1126 { 1127 pdebug("SetType -> tok_set<FieldType>"); 1128 $$ = new t_set($4); 1129 if ($2 != NULL) { 1130 ((t_container*)$$)->set_cpp_name(std::string($2)); 1131 } 1132 } 1133 1134ListType: 1135 tok_list '<' FieldType '>' CppType 1136 { 1137 pdebug("ListType -> tok_list<FieldType>"); 1138 check_for_list_of_bytes($3); 1139 $$ = new t_list($3); 1140 if ($5 != NULL) { 1141 ((t_container*)$$)->set_cpp_name(std::string($5)); 1142 } 1143 } 1144 1145CppType: 1146 tok_cpp_type tok_literal 1147 { 1148 $$ = $2; 1149 } 1150| 1151 { 1152 $$ = NULL; 1153 } 1154 1155TypeAnnotations: 1156 '(' TypeAnnotationList ')' 1157 { 1158 pdebug("TypeAnnotations -> ( TypeAnnotationList )"); 1159 $$ = $2; 1160 } 1161| 1162 { 1163 $$ = NULL; 1164 } 1165 1166TypeAnnotationList: 1167 TypeAnnotationList TypeAnnotation 1168 { 1169 pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation"); 1170 $$ = $1; 1171 $$->annotations_[$2->key] = $2->val; 1172 delete $2; 1173 } 1174| 1175 { 1176 /* Just use a dummy structure to hold the annotations. */ 1177 $$ = new t_struct(g_program); 1178 } 1179 1180TypeAnnotation: 1181 tok_identifier TypeAnnotationValue CommaOrSemicolonOptional 1182 { 1183 pdebug("TypeAnnotation -> TypeAnnotationValue"); 1184 $$ = new t_annotation; 1185 $$->key = $1; 1186 $$->val = $2; 1187 } 1188 1189TypeAnnotationValue: 1190 '=' tok_literal 1191 { 1192 pdebug("TypeAnnotationValue -> = tok_literal"); 1193 $$ = $2; 1194 } 1195| 1196 { 1197 pdebug("TypeAnnotationValue ->"); 1198 $$ = strdup("1"); 1199 } 1200 1201%% 1202