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