open_toontown_panda3d/direct/src/dcparser/dcParser.yxx

671 lines
13 KiB
Plaintext

// Filename: dcParser.yxx
// Created by: drose (05Oct00)
//
////////////////////////////////////////////////////////////////////
%{
#include "dcLexerDefs.h"
#include "dcParserDefs.h"
#include "dcFile.h"
#include "dcClass.h"
#include "dcAtomicField.h"
#include "dcMolecularField.h"
#include "dcClassParameter.h"
#include "dcArrayParameter.h"
#include "dcSimpleParameter.h"
#include "dcTypedef.h"
#include "dcPacker.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 DCAtomicField *current_atomic = (DCAtomicField *)NULL;
static DCMolecularField *current_molecular = (DCMolecularField *)NULL;
static DCAtomicField::ElementType atomic_element(new DCSimpleParameter(ST_invalid));
static DCParameter *current_parameter = (DCParameter *)NULL;
static DCPacker default_packer;
static DCPacker *current_packer;
////////////////////////////////////////////////////////////////////
// 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_cleanup_parser() {
dc_file = (DCFile *)NULL;
}
%}
%token <u.integer> 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_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_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
%type <u.flag> kw_struct_or_kw_dclass
%type <u.dclass> dclass_name
%type <u.atomic> atomic_name
%type <u.subatomic> type_token
%type <u.parameter> type_name
%type <u.parameter> type_definition
%type <u.parameter> named_parameter
%type <u.parameter> unnamed_parameter
%type <u.parameter> parameter
%type <u.parameter> parameter_definition
%type <str> import_identifier
%type <str> slash_identifier
%%
grammar:
START_DC dc
| START_PARAMETER_VALUE parameter_value
;
dc:
empty
| dc ';'
| dc dclass
| dc import
| dc typedef_decl
;
dclass:
kw_struct_or_kw_dclass IDENTIFIER
{
current_class = new DCClass($2, $1, false);
if (!dc_file->add_class(current_class)) {
DCClass *old_class = dc_file->get_class_by_name(current_class->get_name());
if (old_class->is_bogus_class()) {
yyerror("Base class defined after its first reference: " + current_class->get_name());
} else {
yyerror("Duplicate class name: " + current_class->get_name());
}
}
}
dclass_derivation '{' dclass_fields '}'
;
kw_struct_or_kw_dclass:
KW_STRUCT
{
$$ = true;
}
| KW_DCLASS
{
$$ = false;
}
;
dclass_name:
IDENTIFIER
{
DCClass *dclass = dc_file->get_class_by_name($1);
if (dclass == (DCClass *)NULL) {
dclass = new DCClass($1, false, true);
dc_file->add_class(dclass);
}
$$ = dclass;
}
;
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
{
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_derivation:
empty
| ':' base_list
;
base_list:
dclass_name
{
if ($1 != (DCClass *)NULL) {
current_class->add_parent($1);
}
}
| base_list ',' dclass_name
{
if ($3 != (DCClass *)NULL) {
current_class->add_parent($3);
}
}
;
dclass_fields:
empty
| dclass_fields ';'
| dclass_fields atomic_field
| dclass_fields molecular_field
| dclass_fields unnamed_parameter ';'
{
current_class->add_parameter($2);
}
| dclass_fields named_parameter
{
if (!current_class->add_parameter($2)) {
yyerror("Duplicate parameter name: " + $2->get_name());
}
}
;
atomic_field:
IDENTIFIER '('
{
current_atomic = new DCAtomicField($1);
if (!current_class->add_field(current_atomic)) {
yyerror("Duplicate field name: " + current_atomic->get_name());
}
}
parameter_list ')' atomic_flags
;
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);
}
}
}
;
parameter_list:
empty
| nonempty_parameter_list
;
nonempty_parameter_list:
atomic_element
| nonempty_parameter_list ',' atomic_element
;
atomic_element:
parameter
{
atomic_element = DCAtomicField::ElementType($1);
current_atomic->add_element(atomic_element);
}
| parameter '='
{
current_packer = &default_packer;
current_packer->begin_pack($1);
}
parameter_value
{
bool is_valid = $1->is_valid();
atomic_element = DCAtomicField::ElementType($1);
if (current_packer->end_pack()) {
atomic_element.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.
}
current_atomic->add_element(atomic_element);
}
;
named_parameter:
type_definition
{
current_parameter = $1;
}
parameter_definition
{
$$ = $3;
}
;
unnamed_parameter:
type_definition
;
parameter:
named_parameter
| unnamed_parameter
;
type_name:
type_token
{
$$ = new DCSimpleParameter($1);
}
| type_token '/' INTEGER
{
DCSimpleParameter *simple_param = new DCSimpleParameter($1);
if ($3 == 0) {
yyerror("Invalid divisor.");
} else if (!simple_param->set_divisor($3)) {
yyerror("A divisor is only valid on a numeric type.");
}
$$ = simple_param;
}
| IDENTIFIER
{
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 {
// It's an undefined typedef. Create a bogus forward reference.
dtypedef = new DCTypedef($1);
}
dc_file->add_typedef(dtypedef);
}
$$ = dtypedef->make_new_parameter();
}
;
type_definition:
type_name
| type_definition '[' ']'
{
$$ = new DCArrayParameter($1);
}
| type_definition '[' INTEGER ']'
{
$$ = new DCArrayParameter($1, $3);
}
;
parameter_definition:
IDENTIFIER
{
current_parameter->set_name($1);
$$ = current_parameter;
}
| parameter_definition '/' INTEGER
{
if ($3 == 0) {
yyerror("Invalid divisor.");
} else if ($1->as_simple_parameter() == NULL || $1->get_typedef() != (DCTypedef *)NULL) {
yyerror("A divisor is only allowed on a primitive type.");
} else {
if (!$1->as_simple_parameter()->set_divisor($3)) {
yyerror("A divisor is only valid on a numeric type.");
}
}
}
| parameter_definition '[' ']'
{
$$ = new DCArrayParameter($1);
}
| parameter_definition '[' INTEGER ']'
{
$$ = new DCArrayParameter($1, $3);
}
;
parameter_value:
INTEGER
{
current_packer->pack_int64($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();
}
| INTEGER '*' INTEGER
{
for (int i = 0; i < $3; i++) {
current_packer->pack_int64($1);
}
}
| REAL '*' INTEGER
{
for (int i = 0; i < $3; i++) {
current_packer->pack_double($1);
}
}
| HEX_STRING '*' INTEGER
{
for (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;
}
;
atomic_flags:
empty
| atomic_flags KW_REQUIRED
{
current_atomic->add_flag(DCAtomicField::F_required);
}
| atomic_flags KW_BROADCAST
{
current_atomic->add_flag(DCAtomicField::F_broadcast);
}
| atomic_flags KW_P2P
{
current_atomic->add_flag(DCAtomicField::F_p2p);
}
| atomic_flags KW_RAM
{
current_atomic->add_flag(DCAtomicField::F_ram);
}
| atomic_flags KW_DB
{
current_atomic->add_flag(DCAtomicField::F_db);
}
| atomic_flags KW_CLSEND
{
current_atomic->add_flag(DCAtomicField::F_clsend);
}
| atomic_flags KW_CLRECV
{
current_atomic->add_flag(DCAtomicField::F_clrecv);
}
| atomic_flags KW_OWNSEND
{
current_atomic->add_flag(DCAtomicField::F_ownsend);
}
| atomic_flags KW_AIRECV
{
current_atomic->add_flag(DCAtomicField::F_airecv);
}
;
molecular_field:
IDENTIFIER ':'
{
current_molecular = new DCMolecularField($1);
if (!current_class->add_field(current_molecular)) {
yyerror("Duplicate field name: " + current_molecular->get_name());
}
}
molecular_atom_list
;
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->get_atomic(0)->compare_flags(*$3)) {
yyerror("Mismatched flags in molecule between " +
current_molecular->get_atomic(0)->get_name() + " and " +
$3->get_name());
}
}
}
;
empty:
;