panda3d/direct/src/dcparser/dcParser.yxx
2005-05-24 17:53:40 +00:00

1295 lines
25 KiB
Plaintext

// Filename: dcParser.yxx
// Created by: drose (05Oct00)
//
////////////////////////////////////////////////////////////////////
%{
#include "dcLexerDefs.h"
#include "dcParserDefs.h"
#include "dcFile.h"
#include "dcClass.h"
#include "dcSwitch.h"
#include "dcAtomicField.h"
#include "dcMolecularField.h"
#include "dcClassParameter.h"
#include "dcSwitchParameter.h"
#include "dcArrayParameter.h"
#include "dcSimpleParameter.h"
#include "dcTypedef.h"
#include "dcPacker.h"
#include "dcNumericRange.h"
// Because our token type contains objects of type string, which
// require correct copy construction (and not simply memcpying), we
// cannot use bison's built-in auto-stack-grow feature. As an easy
// solution, we ensure here that we have enough yacc stack to start
// with, and that it doesn't ever try to grow.
#define YYINITDEPTH 1000
#define YYMAXDEPTH 1000
static DCFile *dc_file = (DCFile *)NULL;
static DCClass *current_class = (DCClass *)NULL;
static DCSwitch *current_switch = (DCSwitch *)NULL;
static DCAtomicField *current_atomic = (DCAtomicField *)NULL;
static DCMolecularField *current_molecular = (DCMolecularField *)NULL;
static DCParameter *current_parameter = (DCParameter *)NULL;
static DCPacker default_packer;
static DCPacker *current_packer;
static DCDoubleRange double_range;
static DCUnsignedIntRange uint_range;
static DCField *parameter_description = (DCField *)NULL;
////////////////////////////////////////////////////////////////////
// Defining the interface to the parser.
////////////////////////////////////////////////////////////////////
void
dc_init_parser(istream &in, const string &filename, DCFile &file) {
dc_file = &file;
dc_init_lexer(in, filename);
}
void
dc_init_parser_parameter_value(istream &in, const string &filename,
DCPacker &packer) {
dc_file = NULL;
current_packer = &packer;
dc_init_lexer(in, filename);
dc_start_parameter_value();
}
void
dc_init_parser_parameter_description(istream &in, const string &filename,
DCFile *file) {
dc_file = file;
dc_init_lexer(in, filename);
parameter_description = NULL;
dc_start_parameter_description();
}
DCField *
dc_get_parameter_description() {
return parameter_description;
}
void
dc_cleanup_parser() {
dc_file = (DCFile *)NULL;
}
%}
%token <u.uint64> UNSIGNED_INTEGER
%token <u.int64> SIGNED_INTEGER
%token <u.real> REAL
%token <str> STRING HEX_STRING IDENTIFIER
%token KW_DCLASS
%token KW_STRUCT
%token KW_FROM
%token KW_IMPORT
%token KW_TYPEDEF
%token KW_SWITCH
%token KW_CASE
%token KW_DEFAULT
%token KW_BREAK
%token KW_INT8
%token KW_INT16
%token KW_INT32
%token KW_INT64
%token KW_UINT8
%token KW_UINT16
%token KW_UINT32
%token KW_UINT64
%token KW_FLOAT64
%token KW_STRING
%token KW_BLOB
%token KW_BLOB32
%token KW_INT8ARRAY
%token KW_INT16ARRAY
%token KW_INT32ARRAY
%token KW_UINT8ARRAY
%token KW_UINT16ARRAY
%token KW_UINT32ARRAY
%token KW_UINT32UINT8ARRAY
%token KW_CHAR
%token KW_REQUIRED
%token KW_BROADCAST
%token KW_P2P
%token KW_RAM
%token KW_DB
%token KW_CLSEND
%token KW_CLRECV
%token KW_OWNSEND
%token KW_AIRECV
/* These special tokens are used to set the starting state of the
parser. The lexer places the appropriate one of these on the head
of the input stream. */
%token START_DC
%token START_PARAMETER_VALUE
%token START_PARAMETER_DESCRIPTION
%type <u.atomic> atomic_name
%type <u.s_int> server_flags
%type <u.s_int> no_server_flags
%type <u.dclass> dclass_or_struct
%type <u.dclass> dclass_name
%type <u.dclass> dclass
%type <u.field> dclass_field
%type <u.dclass> struct_name
%type <u.dclass> struct
%type <u.field> struct_field
%type <u.field> parameter_description
%type <u.dswitch> switch
%type <u.field> switch_field
%type <u.field> atomic_field
%type <u.field> molecular_field
%type <u.subatomic> type_token
%type <u.parameter> simple_type_name
%type <u.parameter> type_name
%type <u.parameter> type_definition
%type <u.parameter> named_parameter
%type <u.parameter> unnamed_parameter
%type <u.parameter> named_parameter_with_default
%type <u.parameter> unnamed_parameter_with_default
%type <u.parameter> parameter
%type <u.parameter> parameter_with_default
%type <u.parameter> parameter_definition
%type <str> import_identifier
%type <str> slash_identifier
%type <str> optional_name
%type <u.s_uint> char_or_uint
%type <u.s_uint> small_unsigned_integer
%type <u.s_uint> small_negative_integer
%type <u.int64> signed_integer
%type <u.uint64> unsigned_integer
%type <u.real> char_or_number
%type <u.real> number
%%
grammar:
START_DC dc
| START_PARAMETER_VALUE parameter_value
| START_PARAMETER_DESCRIPTION parameter_description
{
parameter_description = $2;
}
;
dc:
empty
| dc ';'
| dc dclass_or_struct
{
if (!dc_file->add_class($2)) {
DCClass *old_class = dc_file->get_class_by_name($2->get_name());
if (old_class != (DCClass *)NULL && old_class->is_bogus_class()) {
yyerror("Base class defined after its first reference: " + $2->get_name());
} else {
yyerror("Duplicate class name: " + $2->get_name());
}
}
}
| dc switch
{
if (!dc_file->add_switch($2)) {
yyerror("Duplicate class name: " + $2->get_name());
}
}
| dc import
| dc typedef_decl
;
slash_identifier:
IDENTIFIER
| slash_identifier '/' IDENTIFIER
{
$$ = $1 + string("/") + $3;
}
;
import_identifier:
slash_identifier
| import_identifier '.' slash_identifier
{
$$ = $1 + string(".") + $3;
}
;
import:
KW_IMPORT import_identifier
{
dc_file->add_import_module($2);
}
| KW_FROM import_identifier KW_IMPORT
{
dc_file->add_import_module($2);
}
import_symbol_list_or_star
;
import_symbol_list_or_star:
import_symbol_list
| '*'
{
dc_file->add_import_symbol("*");
}
;
import_symbol_list:
slash_identifier
{
dc_file->add_import_symbol($1);
}
| import_symbol_list ',' slash_identifier
{
dc_file->add_import_symbol($3);
}
;
typedef_decl:
KW_TYPEDEF parameter_with_default
{
if ($2 != (DCParameter *)NULL) {
DCTypedef *dtypedef = new DCTypedef($2);
if (!dc_file->add_typedef(dtypedef)) {
DCTypedef *old_typedef = dc_file->get_typedef_by_name(dtypedef->get_name());
if (old_typedef->is_bogus_typedef()) {
yyerror("typedef defined after its first reference: " + dtypedef->get_name());
} else {
yyerror("Duplicate typedef name: " + dtypedef->get_name());
}
}
}
}
;
dclass_or_struct:
dclass
| struct
;
dclass:
KW_DCLASS optional_name
{
$$ = current_class;
current_class = new DCClass(dc_file, $2, false, false);
}
dclass_derivation '{' dclass_fields '}'
{
$$ = current_class;
current_class = $<u.dclass>3;
}
;
dclass_name:
IDENTIFIER
{
if (dc_file == (DCFile *)NULL) {
yyerror("No DCFile available, so no class names are predefined.");
$$ = NULL;
} else {
DCClass *dclass = dc_file->get_class_by_name($1);
if (dclass == (DCClass *)NULL) {
// Create a bogus class as a forward reference.
dclass = new DCClass(dc_file, $1, false, true);
dc_file->add_class(dclass);
}
if (dclass->is_struct()) {
yyerror("struct name not allowed");
}
$$ = dclass;
}
}
;
dclass_derivation:
empty
| ':' dclass_base_list
;
dclass_base_list:
dclass_name
{
if ($1 != (DCClass *)NULL) {
current_class->add_parent($1);
}
}
| dclass_base_list ',' dclass_name
{
if (!dc_multiple_inheritance) {
yyerror("Multiple inheritance is not supported without \"dc-multiple-inheritance 1\" in your Config.prc file.");
} else {
if ($3 != (DCClass *)NULL) {
current_class->add_parent($3);
}
}
}
;
dclass_fields:
empty
| dclass_fields ';'
| dclass_fields dclass_field
{
if ($2 == (DCField *)NULL) {
// Pass this error up.
} else if (!current_class->add_field($2)) {
yyerror("Duplicate field name: " + $2->get_name());
} else if ($2->get_number() < 0) {
yyerror("A non-network field cannot be stored on a dclass");
}
}
;
dclass_field:
atomic_field server_flags
{
if ($1 != (DCField *)NULL) {
if ($1->get_name().empty()) {
yyerror("Field name required.");
}
$1->set_flags($2);
}
$$ = $1;
}
| molecular_field no_server_flags
| unnamed_parameter_with_default server_flags ';'
{
yyerror("Unnamed parameters are not allowed on a dclass");
if ($1 != (DCField *)NULL) {
$1->set_flags($2);
}
$$ = $1;
}
| named_parameter_with_default server_flags
{
if ($1 != (DCField *)NULL) {
$1->set_flags($2);
}
$$ = $1;
}
;
struct:
KW_STRUCT optional_name
{
$$ = current_class;
current_class = new DCClass(dc_file, $2, true, false);
}
struct_derivation '{' struct_fields '}'
{
$$ = current_class;
current_class = $<u.dclass>3;
}
;
struct_name:
IDENTIFIER
{
if (dc_file == (DCFile *)NULL) {
yyerror("No DCFile available, so no struct names are predefined.");
$$ = NULL;
} else {
DCClass *dstruct = dc_file->get_class_by_name($1);
if (dstruct == (DCClass *)NULL) {
// Create a bogus class as a forward reference.
dstruct = new DCClass(dc_file, $1, false, true);
dc_file->add_class(dstruct);
}
if (!dstruct->is_struct()) {
yyerror("struct name required");
}
$$ = dstruct;
}
}
;
struct_derivation:
empty
| ':' struct_base_list
;
struct_base_list:
struct_name
{
if ($1 != (DCClass *)NULL) {
current_class->add_parent($1);
}
}
| struct_base_list ',' struct_name
{
if ($3 != (DCClass *)NULL) {
current_class->add_parent($3);
}
}
;
struct_fields:
empty
| struct_fields ';'
| struct_fields struct_field
{
if ($2 == (DCField *)NULL) {
// Pass this error up.
} else if (!current_class->add_field($2)) {
yyerror("Duplicate field name: " + $2->get_name());
}
}
;
struct_field:
atomic_field no_server_flags
{
if ($1->get_name().empty()) {
yyerror("Field name required.");
}
$$ = $1;
}
| molecular_field no_server_flags
| unnamed_parameter_with_default no_server_flags ';'
{
$$ = $1;
}
| named_parameter_with_default no_server_flags
{
$$ = $1;
}
;
atomic_field:
optional_name '('
{
$$ = current_atomic;
current_atomic = new DCAtomicField($1, current_class);
}
parameter_list ')'
{
$$ = current_atomic;
current_atomic = $<u.atomic>3;
}
;
parameter_list:
empty
| nonempty_parameter_list
;
nonempty_parameter_list:
atomic_element
| nonempty_parameter_list ',' atomic_element
;
atomic_element:
parameter_with_default
{
if ($1 != (DCParameter *)NULL) {
current_atomic->add_element($1);
}
}
;
named_parameter:
type_definition
{
current_parameter = $1;
}
parameter_definition
{
$$ = $3;
}
;
unnamed_parameter:
type_definition
;
named_parameter_with_default:
named_parameter
| named_parameter '='
{
current_packer = &default_packer;
current_packer->clear_data();
if ($1 != (DCField *)NULL) {
current_packer->begin_pack($1);
}
}
parameter_value
{
bool is_valid = false;
if ($1 != (DCField *)NULL) {
is_valid = $1->is_valid();
}
if (current_packer->end_pack()) {
$1->set_default_value(current_packer->get_string());
} else {
if (is_valid) {
yyerror("Invalid default value for type");
}
// If the current parameter isn't valid, we don't mind a pack
// error (there's no way for us to validate the syntax). So we'll
// just ignore the default value in this case.
}
}
;
unnamed_parameter_with_default:
unnamed_parameter
| unnamed_parameter '='
{
current_packer = &default_packer;
current_packer->clear_data();
if ($1 != (DCField *)NULL) {
current_packer->begin_pack($1);
}
}
parameter_value
{
bool is_valid = false;
if ($1 != (DCField *)NULL) {
is_valid = $1->is_valid();
}
if (current_packer->end_pack()) {
$1->set_default_value(current_packer->get_string());
} else {
if (is_valid) {
yyerror("Invalid default value for type");
}
// If the current parameter isn't valid, we don't mind a pack
// error (there's no way for us to validate the syntax). So we'll
// just ignore the default value in this case.
}
}
;
parameter:
named_parameter
| unnamed_parameter
;
parameter_with_default:
named_parameter_with_default
| unnamed_parameter_with_default
;
parameter_description:
atomic_field no_server_flags
{
$$ = $1;
}
| unnamed_parameter_with_default no_server_flags
{
$$ = $1;
}
| named_parameter_with_default no_server_flags
{
$$ = $1;
}
;
simple_type_name:
type_token
{
$$ = new DCSimpleParameter($1);
}
| simple_type_name '(' double_range ')'
{
DCSimpleParameter *simple_param = $1->as_simple_parameter();
nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
if (!simple_param->set_range(double_range)) {
yyerror("Inappropriate range for type");
}
$$ = simple_param;
}
| simple_type_name '/' small_unsigned_integer
{
DCSimpleParameter *simple_param = $1->as_simple_parameter();
nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
if (!simple_param->is_numeric_type()) {
yyerror("A divisor is only valid on a numeric type.");
} else if (!simple_param->set_divisor($3)) {
yyerror("Invalid divisor.");
} else if (simple_param->has_modulus() && !simple_param->set_modulus(simple_param->get_modulus())) {
// Changing the divisor may change the valid range for the modulus.
yyerror("Invalid modulus.");
}
$$ = simple_param;
}
| simple_type_name '%' number
{
DCSimpleParameter *simple_param = $1->as_simple_parameter();
nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
if (!simple_param->is_numeric_type()) {
yyerror("A divisor is only valid on a numeric type.");
} else if (!simple_param->set_modulus($3)) {
yyerror("Invalid modulus.");
}
$$ = simple_param;
}
;
type_name:
simple_type_name
| IDENTIFIER
{
if (dc_file == (DCFile *)NULL) {
yyerror("Invalid type.");
$$ = NULL;
} else {
DCTypedef *dtypedef = dc_file->get_typedef_by_name($1);
if (dtypedef == (DCTypedef *)NULL) {
// Maybe it's a class name.
DCClass *dclass = dc_file->get_class_by_name($1);
if (dclass != (DCClass *)NULL) {
// Create an implicit typedef for this.
dtypedef = new DCTypedef(new DCClassParameter(dclass), true);
} else {
// Maybe it's a switch name.
DCSwitch *dswitch = dc_file->get_switch_by_name($1);
if (dswitch != (DCSwitch *)NULL) {
// This also gets an implicit typedef.
dtypedef = new DCTypedef(new DCSwitchParameter(dswitch), true);
} else {
// It's an undefined typedef. Create a bogus forward reference.
dtypedef = new DCTypedef($1);
}
}
dc_file->add_typedef(dtypedef);
}
$$ = dtypedef->make_new_parameter();
}
}
| struct
{
// This is an inline struct definition.
if ($1 == (DCClass *)NULL) {
$$ = NULL;
} else {
if (dc_file != (DCFile *)NULL) {
dc_file->add_thing_to_delete($1);
} else {
// This is a memory leak--this happens when we put an anonymous
// struct reference within the string passed to
// DCPackerInterface::check_match(). Maybe it doesn't really matter.
}
$$ = new DCClassParameter($1);
}
}
| switch
{
// This is an inline switch definition.
if ($1 == (DCSwitch *)NULL) {
$$ = NULL;
} else {
if (dc_file != (DCFile *)NULL) {
dc_file->add_thing_to_delete($1);
} else {
// This is a memory leak--this happens when we put an anonymous
// switch reference within the string passed to
// DCPackerInterface::check_match(). Maybe it doesn't really matter.
}
$$ = new DCSwitchParameter($1);
}
}
;
double_range:
empty
{
double_range.clear();
}
| char_or_number
{
double_range.clear();
if (!double_range.add_range($1, $1)) {
yyerror("Overlapping range");
}
}
| char_or_number '-' char_or_number
{
double_range.clear();
if (!double_range.add_range($1, $3)) {
yyerror("Overlapping range");
}
}
| char_or_number number
{
double_range.clear();
if ($2 >= 0) {
yyerror("Syntax error");
} else if (!double_range.add_range($1, -$2)) {
yyerror("Overlapping range");
}
}
| double_range ',' char_or_number
{
if (!double_range.add_range($3, $3)) {
yyerror("Overlapping range");
}
}
| double_range ',' char_or_number '-' char_or_number
{
if (!double_range.add_range($3, $5)) {
yyerror("Overlapping range");
}
}
| double_range ',' char_or_number number
{
if ($4 >= 0) {
yyerror("Syntax error");
} else if (!double_range.add_range($3, -$4)) {
yyerror("Overlapping range");
}
}
;
uint_range:
empty
{
uint_range.clear();
}
| char_or_uint
{
uint_range.clear();
if (!uint_range.add_range($1, $1)) {
yyerror("Overlapping range");
}
}
| char_or_uint '-' char_or_uint
{
uint_range.clear();
if (!uint_range.add_range($1, $3)) {
yyerror("Overlapping range");
}
}
| char_or_uint small_negative_integer
{
uint_range.clear();
if (!uint_range.add_range($1, $2)) {
yyerror("Overlapping range");
}
}
| uint_range ',' char_or_uint
{
if (!uint_range.add_range($3, $3)) {
yyerror("Overlapping range");
}
}
| uint_range ',' char_or_uint '-' char_or_uint
{
if (!uint_range.add_range($3, $5)) {
yyerror("Overlapping range");
}
}
| uint_range ',' char_or_uint small_negative_integer
{
if (!uint_range.add_range($3, $4)) {
yyerror("Overlapping range");
}
}
;
type_definition:
type_name
| type_definition '[' uint_range ']'
{
if ($1 == (DCParameter *)NULL) {
$$ = NULL;
} else {
$$ = $1->append_array_specification(uint_range);
}
}
;
parameter_definition:
IDENTIFIER
{
current_parameter->set_name($1);
$$ = current_parameter;
}
| parameter_definition '/' small_unsigned_integer
{
DCSimpleParameter *simple_param = $1->as_simple_parameter();
if (simple_param == NULL || simple_param->get_typedef() != (DCTypedef *)NULL) {
yyerror("A divisor is only allowed on a primitive type.");
} else if (!simple_param->is_numeric_type()) {
yyerror("A divisor is only valid on a numeric type.");
} else {
if (!simple_param->set_divisor($3)) {
yyerror("Invalid divisor.");
}
}
}
| parameter_definition '%' number
{
DCSimpleParameter *simple_param = $1->as_simple_parameter();
if (simple_param == NULL || simple_param->get_typedef() != (DCTypedef *)NULL) {
yyerror("A modulus is only allowed on a primitive type.");
} else if (!simple_param->is_numeric_type()) {
yyerror("A modulus is only valid on a numeric type.");
} else {
if (!simple_param->set_modulus($3)) {
yyerror("Invalid modulus.");
}
}
}
| parameter_definition '[' uint_range ']'
{
$$ = $1->append_array_specification(uint_range);
}
;
char_or_uint:
STRING
{
if ($1.length() != 1) {
yyerror("Single character required.");
$$ = 0;
} else {
$$ = (unsigned char)$1[0];
}
}
| small_unsigned_integer
;
small_unsigned_integer:
UNSIGNED_INTEGER
{
$$ = (unsigned int)$1;
if ($$ != $1) {
yyerror("Number out of range.");
$$ = 1;
}
}
;
small_negative_integer:
SIGNED_INTEGER
{
$$ = (unsigned int)-$1;
if ($1 >= 0) {
yyerror("Syntax error.");
} else if ($$ != -$1) {
yyerror("Number out of range.");
$$ = 1;
}
}
;
signed_integer:
SIGNED_INTEGER
;
unsigned_integer:
UNSIGNED_INTEGER
;
number:
unsigned_integer
{
$$ = (double)$1;
}
| signed_integer
{
$$ = (double)$1;
}
| REAL
;
char_or_number:
STRING
{
if ($1.length() != 1) {
yyerror("Single character required.");
$$ = 0;
} else {
$$ = (double)(unsigned char)$1[0];
}
}
| number
;
parameter_value:
signed_integer
{
current_packer->pack_int64($1);
}
| unsigned_integer
{
current_packer->pack_uint64($1);
}
| REAL
{
current_packer->pack_double($1);
}
| STRING
{
current_packer->pack_string($1);
}
| HEX_STRING
{
current_packer->pack_literal_value($1);
}
| '{'
{
current_packer->push();
}
array '}'
{
current_packer->pop();
}
| '['
{
current_packer->push();
}
array ']'
{
current_packer->pop();
}
| '('
{
current_packer->push();
}
array ')'
{
current_packer->pop();
}
| signed_integer '*' small_unsigned_integer
{
for (unsigned int i = 0; i < $3; i++) {
current_packer->pack_int64($1);
}
}
| unsigned_integer '*' small_unsigned_integer
{
for (unsigned int i = 0; i < $3; i++) {
current_packer->pack_uint64($1);
}
}
| REAL '*' small_unsigned_integer
{
for (unsigned int i = 0; i < $3; i++) {
current_packer->pack_double($1);
}
}
| HEX_STRING '*' small_unsigned_integer
{
for (unsigned int i = 0; i < $3; i++) {
current_packer->pack_literal_value($1);
}
}
;
array:
maybe_comma
| array_def maybe_comma
;
maybe_comma:
empty
| ','
;
array_def:
parameter_value
| array_def ',' parameter_value
;
type_token:
KW_INT8
{
$$ = ST_int8;
}
| KW_INT16
{
$$ = ST_int16;
}
| KW_INT32
{
$$ = ST_int32;
}
| KW_INT64
{
$$ = ST_int64;
}
| KW_UINT8
{
$$ = ST_uint8;
}
| KW_UINT16
{
$$ = ST_uint16;
}
| KW_UINT32
{
$$ = ST_uint32;
}
| KW_UINT64
{
$$ = ST_uint64;
}
| KW_FLOAT64
{
$$ = ST_float64;
}
| KW_STRING
{
$$ = ST_string;
}
| KW_BLOB
{
$$ = ST_blob;
}
| KW_BLOB32
{
$$ = ST_blob32;
}
| KW_INT8ARRAY
{
$$ = ST_int8array;
}
| KW_INT16ARRAY
{
$$ = ST_int16array;
}
| KW_INT32ARRAY
{
$$ = ST_int32array;
}
| KW_UINT8ARRAY
{
$$ = ST_uint8array;
}
| KW_UINT16ARRAY
{
$$ = ST_uint16array;
}
| KW_UINT32ARRAY
{
$$ = ST_uint32array;
}
| KW_UINT32UINT8ARRAY
{
$$ = ST_uint32uint8array;
}
| KW_CHAR
{
$$ = ST_char;
}
;
server_flags:
empty
{
$$ = 0;
}
| server_flags KW_REQUIRED
{
$$ = $1 | DCAtomicField::F_required;
}
| server_flags KW_BROADCAST
{
$$ = $1 | DCAtomicField::F_broadcast;
}
| server_flags KW_P2P
{
$$ = $1 | DCAtomicField::F_p2p;
}
| server_flags KW_RAM
{
$$ = $1 | DCAtomicField::F_ram;
}
| server_flags KW_DB
{
$$ = $1 | DCAtomicField::F_db;
}
| server_flags KW_CLSEND
{
$$ = $1 | DCAtomicField::F_clsend;
}
| server_flags KW_CLRECV
{
$$ = $1 | DCAtomicField::F_clrecv;
}
| server_flags KW_OWNSEND
{
$$ = $1 | DCAtomicField::F_ownsend;
}
| server_flags KW_AIRECV
{
$$ = $1 | DCAtomicField::F_airecv;
}
;
no_server_flags:
server_flags
{
if ($1 != 0) {
yyerror("Server flags are not allowed here.");
}
$$ = $1;
}
;
molecular_field:
IDENTIFIER ':'
{
current_molecular = new DCMolecularField($1, current_class);
}
molecular_atom_list
{
$$ = current_molecular;
}
;
atomic_name:
IDENTIFIER
{
DCField *field = current_class->get_field_by_name($1);
$$ = (DCAtomicField *)NULL;
if (field == (DCField *)NULL) {
yyerror("Unknown field: " + $1);
} else {
$$ = field->as_atomic_field();
if ($$ == (DCAtomicField *)NULL) {
yyerror("Not an atomic field: " + $1);
}
}
}
;
molecular_atom_list:
atomic_name
{
if ($1 != (DCAtomicField *)NULL) {
current_molecular->add_atomic($1);
}
}
| molecular_atom_list ',' atomic_name
{
if ($3 != (DCAtomicField *)NULL) {
current_molecular->add_atomic($3);
if (!current_molecular->compare_flags(*$3)) {
yyerror("Mismatched flags in molecule between " +
current_molecular->get_atomic(0)->get_name() + " and " +
$3->get_name());
}
}
}
;
optional_name:
empty
{
$$ = "";
}
| IDENTIFIER
;
switch:
KW_SWITCH optional_name '(' parameter ')' '{'
{
$$ = current_switch;
current_switch = new DCSwitch($2, $4);
}
switch_fields '}'
{
$$ = current_switch;
current_switch = (DCSwitch *)$<u.parameter>7;
}
;
switch_fields:
empty
| switch_fields ';'
| switch_fields switch_case
| switch_fields switch_default
| switch_fields switch_break
| switch_fields switch_field
{
if (!current_switch->is_field_valid()) {
yyerror("case declaration required before first element");
} else if ($2 != (DCField *)NULL) {
if (!current_switch->add_field($2)) {
yyerror("Duplicate field name: " + $2->get_name());
}
}
}
;
switch_case:
KW_CASE
{
current_packer = &default_packer;
current_packer->clear_data();
current_packer->begin_pack(current_switch->get_key_parameter());
}
parameter_value ':'
{
if (!current_packer->end_pack()) {
yyerror("Invalid value for switch parameter");
} else {
int case_index = current_switch->add_case(current_packer->get_string());
if (case_index == -1) {
yyerror("Duplicate case value");
}
}
}
;
switch_default:
KW_DEFAULT ':'
{
if (!current_switch->add_default()) {
yyerror("Default case already defined");
}
}
;
switch_break:
KW_BREAK ';'
{
current_switch->add_break();
}
;
switch_field:
unnamed_parameter_with_default ';'
{
$$ = $1;
}
| named_parameter_with_default
{
$$ = $1;
}
;
empty:
;