blob: 269d163205e7b762dfa8134d95739efce8760f7c [file] [log] [blame]
%{
/**
* Thrift parser.
*
* This parser is used on a thrift definition file.
*
* @author Mark Slee <mcslee@facebook.com>
*/
#include <stdio.h>
#include "main.h"
#include "globals.h"
#include "parse/t_program.h"
int y_field_val = 0;
%}
%union {
char* id;
int iconst;
t_type* ttype;
t_typedef* ttypedef;
t_enum* tenum;
t_struct* tstruct;
t_service* tservice;
t_function* tfunction;
t_field* tfield;
t_constant* tconstant;
}
/** Strings and constants */
%token<id> tok_identifier
%token<iconst> tok_int_constant
/** Base datatypes */
%token tok_byte
%token tok_string
%token tok_i32
%token tok_u32
%token tok_i64
%token tok_u64
/** Complex Types */
%token tok_map
%token tok_list
%token tok_set
/** Function types */
%token tok_void
/** Modifiers */
%token tok_async
/** Thrift actions */
%token tok_typedef
%token tok_struct
%token tok_service
%token tok_enum
/** Types */
%type<ttype> BaseType
%type<ttype> ContainerType
%type<ttype> MapType
%type<ttype> SetType
%type<ttype> ListType
%type<ttypedef> Typedef
%type<ttype> DefinitionType
%type<tfield> Field
%type<ttype> FieldType
%type<tstruct> FieldList
%type<tenum> Enum
%type<tenum> EnumDefList
%type<tconstant> EnumDef
%type<tstruct> Struct
%type<tservice> Service
%type<tfunction> Function
%type<id> FunctionModifiers
%type<ttype> FunctionType
%type<tservice> FunctionList
%%
/** Thrift Grammar */
Program:
DefinitionList
{
pdebug("Program -> DefinitionList");
}
DefinitionList:
DefinitionList Definition
{
pdebug("DefinitionList -> DefinitionList Definition");
}
|
{
pdebug("DefinitionList -> ");
}
Definition:
Typedef
{
pdebug("Definition -> Typedef");
g_program->add_typedef($1);
}
| Enum
{
pdebug("Definition -> Enum");
g_program->add_enum($1);
}
| Struct
{
pdebug("Definition -> Struct");
g_program->add_struct($1);
}
| Service
{
pdebug("Definition -> Service");
g_program->add_service($1);
}
Typedef:
tok_typedef DefinitionType tok_identifier
{
pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
t_typedef *td = new t_typedef($2, $3);
$$ = td;
}
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($3);
}
| EnumDef
{
pdebug("EnumDefList -> EnumDef");
$$ = new t_enum;
$$->append($1);
}
|
{
pdebug("EnumDefList -> ");
$$ = new t_enum;
}
EnumDef:
tok_identifier '=' tok_int_constant
{
pdebug("EnumDef => tok_identifier = tok_int_constant");
if ($3 < 0) {
printf("WARNING (%d): Negative value supplied for enum %s.\n", yylineno, $1);
}
$$ = new t_constant($1, $3);
}
|
tok_identifier
{
pdebug("EnumDef => tok_identifier");
$$ = new t_constant($1);
}
Struct:
tok_struct tok_identifier '{' FieldList '}'
{
pdebug("Struct -> tok_struct tok_identifier { FieldList }");
$4->set_name($2);
$$ = $4;
y_field_val = 0;
}
Service:
tok_service tok_identifier '{' FunctionList '}'
{
pdebug("Service -> tok_service tok_identifier { FunctionList }");
$$ = $4;
$$->set_name($2);
}
FunctionList:
FunctionList Function
{
pdebug("FunctionList -> FunctionList Function");
$$ = $1;
$1->add_function($2);
}
|
{
pdebug("FunctionList -> ");
$$ = new t_service;
}
Function:
FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
{
$5->set_name(std::string($3) + "_args");
$$ = new t_function($1, $3, $5);
y_field_val = 0;
}
FunctionModifiers:
{
/** TODO(mcslee): implement async modifier, etc. */
$$ = 0;
}
FieldList:
FieldList ',' Field
{
pdebug("FieldList -> FieldList , Field");
$$ = $1;
$$->append($3);
}
| Field
{
pdebug("FieldList -> Field");
$$ = new t_struct;
$$->append($1);
}
|
{
pdebug("FieldList -> ");
$$ = new t_struct;
}
Field:
FieldType tok_identifier '=' tok_int_constant
{
pdebug("Field -> FieldType tok_identifier = tok_int_constant");
if ($4 < 0) {
yyerror("Negative value (%d) not allowed as a field key.", $4);
exit(1);
}
$$ = new t_field($1, $2, (uint32_t)$4);
y_field_val = $4+1;
}
| FieldType tok_identifier
{
pdebug("Field -> FieldType tok_identifier");
printf("WARNING (%d): No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
$$ = new t_field($1, $2, y_field_val++);
}
DefinitionType:
BaseType
{
pdebug("DefinitionType -> BaseType");
$$ = $1;
}
| ContainerType
{
pdebug("DefinitionType -> ContainerType");
$$ = $1;
}
FunctionType:
FieldType
{
pdebug("FunctionType -> FieldType");
$$ = $1;
}
| tok_void
{
pdebug("FunctionType -> tok_void");
$$ = g_program->get_void_type();
}
FieldType:
tok_identifier
{
pdebug("FieldType -> tok_identifier");
$$ = g_program->get_custom_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_program->get_string_type();
}
| tok_byte
{
pdebug("BaseType -> tok_byte");
$$ = g_program->get_byte_type();
}
| tok_i32
{
pdebug("BaseType -> tok_i32");
$$ = g_program->get_i32_type();
}
| tok_u32
{
pdebug("BaseType -> tok_u32");
$$ = g_program->get_u32_type();
}
| tok_i64
{
pdebug("BaseType -> tok_i64");
$$ = g_program->get_i64_type();
}
| tok_u64
{
pdebug("BaseType -> tok_u64");
$$ = g_program->get_u64_type();
}
ContainerType:
MapType
{
pdebug("ContainerType -> MapType");
$$ = $1;
}
| SetType
{
pdebug("ContainerType -> SetType");
$$ = $1;
}
| ListType
{
pdebug("ContainerType -> ListType");
$$ = $1;
}
MapType:
tok_map '<' FieldType ',' FieldType '>'
{
pdebug("MapType -> tok_map <FieldType, FieldType>");
$$ = new t_map($3, $5);
}
SetType:
tok_set '<' FieldType '>'
{
pdebug("SetType -> tok_set<FieldType>");
$$ = new t_set($3);
}
ListType:
tok_list '<' FieldType '>'
{
pdebug("ListType -> tok_list<FieldType>");
$$ = new t_list($3);
}
%%