summaryrefslogtreecommitdiff
path: root/compiler/cpp/src/thrifty.yy
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/cpp/src/thrifty.yy')
-rw-r--r--compiler/cpp/src/thrifty.yy1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
new file mode 100644
index 000000000..bf5408e3a
--- /dev/null
+++ b/compiler/cpp/src/thrifty.yy
@@ -0,0 +1,1127 @@
+%{
+/*
+ * 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;
+
+%}
+
+/**
+ * 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
+
+/**
+ * Grammar nodes
+ */
+
+%type<ttype> BaseType
+%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<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);
+ }
+ }
+/* 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();
+ }
+
+Struct:
+ tok_struct tok_identifier XsdAll '{' FieldList '}' TypeAnnotations
+ {
+ pdebug("Struct -> tok_struct tok_identifier { FieldList }");
+ $5->set_xsd_all($3);
+ $$ = $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
+ {
+ if (g_arglist) {
+ if (g_parse_mode == PROGRAM) {
+ pwarning(1, "required keyword is ignored in argument lists.\n");
+ }
+ $$ = t_field::T_OPT_IN_REQ_OUT;
+ } else {
+ $$ = 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:
+ 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;
+ }
+
+%%