make an effort to use the official grammar

This commit is contained in:
David Rose 2004-10-04 10:25:04 +00:00
parent 8b29617612
commit 365a7db25f
8 changed files with 439 additions and 265 deletions

View File

@ -92,8 +92,12 @@ write_text(ostream &out, int indent_level) const {
out << "UCHAR";
break;
case T_byte:
out << "BYTE";
case T_sword:
out << "SWORD";
break;
case T_sdword:
out << "SDWORD";
break;
case T_string:

View File

@ -41,7 +41,8 @@ public:
T_double,
T_char,
T_uchar,
T_byte,
T_sword,
T_sdword,
T_string,
T_cstring,
T_unicode,

View File

@ -32,7 +32,7 @@ get_guid() const {
// Access: Public
// Description: Sets whether the template is considered "open" or
// not. If it is open (this flag is true), the set of
// restrictions is ignored and the instances of this
// options is ignored and the instances of this
// template may include any types of children. If it is
// closed (false), only the named types may be added.
////////////////////////////////////////////////////////////////////
@ -46,7 +46,7 @@ set_open(bool open) {
// Access: Public
// Description: Returns whether the template is considered "open" or
// not. If it is open (this flag is true), the set of
// restrictions is ignored and the instances of this
// options is ignored and the instances of this
// template may include any types of children. If it is
// closed (false), only the named types may be added.
////////////////////////////////////////////////////////////////////
@ -56,36 +56,34 @@ get_open() const {
}
////////////////////////////////////////////////////////////////////
// Function: XFileTemplate::add_restriction
// Function: XFileTemplate::add_option
// Access: Public
// Description: Adds a new type to the list of allowable types of
// child nodes for an instance of this template. The
// method is a little misnamed; we are actually removing
// a restriction by adding this type to the list.
// child nodes for an instance of this template.
////////////////////////////////////////////////////////////////////
INLINE void XFileTemplate::
add_restriction(XFileTemplate *restriction) {
_restrictions.push_back(restriction);
add_option(XFileTemplate *option) {
_options.push_back(option);
}
////////////////////////////////////////////////////////////////////
// Function: XFileTemplate::get_num_restrictions
// Function: XFileTemplate::get_num_options
// Access: Public
// Description: Returns the number of templates on the restrictions
// Description: Returns the number of templates on the options
// list.
////////////////////////////////////////////////////////////////////
INLINE int XFileTemplate::
get_num_restrictions() const {
return _restrictions.size();
get_num_options() const {
return _options.size();
}
////////////////////////////////////////////////////////////////////
// Function: XFileTemplate::get_restriction
// Function: XFileTemplate::get_option
// Access: Public
// Description: Returns the nth template on the restrictions list.
// Description: Returns the nth template on the options list.
////////////////////////////////////////////////////////////////////
INLINE XFileTemplate *XFileTemplate::
get_restriction(int n) const {
nassertr(n >= 0 && n < (int)_restrictions.size(), NULL);
return _restrictions[n];
get_option(int n) const {
nassertr(n >= 0 && n < (int)_options.size(), NULL);
return _options[n];
}

View File

@ -53,7 +53,7 @@ XFileTemplate::
void XFileTemplate::
clear() {
XFileNode::clear();
_restrictions.clear();
_options.clear();
}
////////////////////////////////////////////////////////////////////
@ -76,16 +76,16 @@ write_text(ostream &out, int indent_level) const {
indent(out, indent_level + 2)
<< "[ ... ]\n";
} else if (!_restrictions.empty()) {
} else if (!_options.empty()) {
// A restricted template
indent(out, indent_level + 2);
char delimiter = '[';
Restrictions::const_iterator ri;
for (ri = _restrictions.begin(); ri != _restrictions.end(); ++ri) {
XFileTemplate *restriction = (*ri);
Options::const_iterator ri;
for (ri = _options.begin(); ri != _options.end(); ++ri) {
XFileTemplate *option = (*ri);
out << delimiter << " "
<< restriction->get_name() << " <" << restriction->get_guid()
<< option->get_name() << " <" << option->get_guid()
<< ">";
delimiter = ',';
}

View File

@ -43,16 +43,16 @@ public:
INLINE void set_open(bool open);
INLINE bool get_open() const;
INLINE void add_restriction(XFileTemplate *restriction);
INLINE int get_num_restrictions() const;
INLINE XFileTemplate *get_restriction(int n) const;
INLINE void add_option(XFileTemplate *option);
INLINE int get_num_options() const;
INLINE XFileTemplate *get_option(int n) const;
private:
WindowsGuid _guid;
bool _open;
typedef pvector< PT(XFileTemplate) > Restrictions;
Restrictions _restrictions;
typedef pvector< PT(XFileTemplate) > Options;
Options _options;
public:
static TypeHandle get_class_type() {

View File

@ -10,6 +10,7 @@
#include "xParserDefs.h"
#include "xParser.h"
#include "indent.h"
#include "string_utils.h"
#include "notify.h"
static int yyinput(void); // declared by flex.
@ -340,6 +341,42 @@ scan_guid_string() {
return result;
}
// Parses the text into a list of integers and returns them.
static PTA_int
parse_int_list(const string &text, const string &delimiter) {
PTA_int result;
vector_string words;
tokenize(text, words, delimiter);
vector_string::const_iterator wi;
for (wi = words.begin(); wi != words.end(); ++wi) {
int number = 0;
string_to_int(*wi, number);
result.push_back(number);
}
return result;
}
// Parses the text into a list of doubles and returns them.
static PTA_double
parse_double_list(const string &text, const string &delimiter) {
PTA_double result;
vector_string words;
tokenize(text, words, delimiter);
vector_string::const_iterator wi;
for (wi = words.begin(); wi != words.end(); ++wi) {
double number = 0;
string_to_double(*wi, number);
result.push_back(number);
}
return result;
}
// accept() is called below as each piece is pulled off and
@ -351,7 +388,6 @@ inline void accept() {
%}
INTEGERNUM ([+-]?([0-9]+))
UNSIGNED_HEXNUM (0x[0-9a-fA-F]*)
REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
%%
@ -388,128 +424,161 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
accept();
}
"{" {
accept();
return TOKEN_OBRACE;
}
"}" {
accept();
return TOKEN_CBRACE;
}
"[" {
accept();
return TOKEN_OBRACKET;
}
"]" {
accept();
return TOKEN_CBRACKET;
}
"." {
accept();
return TOKEN_DOT;
}
"," {
accept();
return TOKEN_COMMA;
}
";" {
accept();
return TOKEN_SEMICOLON;
}
"array" {
accept();
return KW_ARRAY;
}
"binary" {
accept();
return KW_BINARY;
return TOKEN_ARRAY;
}
"byte" {
accept();
return KW_BYTE;
return TOKEN_UCHAR;
}
"char" {
accept();
return KW_CHAR;
return TOKEN_CHAR;
}
"cstring" {
accept();
return KW_CSTRING;
return TOKEN_CSTRING;
}
"double" {
accept();
return KW_DOUBLE;
return TOKEN_DOUBLE;
}
"dword" {
accept();
return KW_DWORD;
return TOKEN_DWORD;
}
"sdword" {
accept();
return TOKEN_SDWORD;
}
"float" {
accept();
return KW_FLOAT;
return TOKEN_FLOAT;
}
"string" {
accept();
return KW_STRING;
return TOKEN_LPSTR;
}
"template" {
accept();
return KW_TEMPLATE;
return TOKEN_TEMPLATE;
}
"uchar" {
accept();
return KW_UCHAR;
return TOKEN_UCHAR;
}
"unicode" {
accept();
return KW_UNICODE;
return TOKEN_UNICODE;
}
"sword" {
accept();
return TOKEN_SWORD;
}
"word" {
accept();
return KW_WORD;
return TOKEN_WORD;
}
{INTEGERNUM} {
// A signed or unsigned integer number.
accept();
xyylval.u.s_int = atol(xyytext);
xyylval.u.number = atol(xyytext);
xyylval.str = yytext;
return INTEGER;
return TOKEN_INTEGER;
}
{UNSIGNED_HEXNUM} {
// A hexadecimal integer number.
accept();
({INTEGERNUM};)+ {
// An integer as part of a semicolon-delimited list.
accept();
xyylval.int_list = parse_int_list(xyytext, ";");
xyylval.u.separator_token = TOKEN_SEMICOLON;
// As above, we'll decode the hex string by hand.
xyylval.str = xyytext;
xyylval.u.s_int = 0;
const char *p = xyytext + 2;
while (*p != '\0') {
int next_value = xyylval.u.s_int * 16;
if (next_value < xyylval.u.s_int) {
xyyerror("Number out of range.");
xyylval.u.s_int = 1;
return INTEGER;
}
if (isalpha(*p)) {
xyylval.u.s_int = next_value + (tolower(*p) - 'a' + 10);
} else {
xyylval.u.s_int = next_value + (*p - '0');
}
++p;
}
return INTEGER;
return TOKEN_INTEGER_LIST;
}
{REALNUM} {
// A floating-point number.
({REALNUM};)+ {
// A floating-point number as part of a semicolon-delimited list.
accept();
xyylval.u.real = atof(xyytext);
xyylval.str = xyytext;
return REAL;
xyylval.double_list = parse_double_list(xyytext, ";");
xyylval.u.separator_token = TOKEN_SEMICOLON;
return TOKEN_REALNUM_LIST;
}
({INTEGERNUM},)+ {
// An integer as part of a semicolon-delimited list.
accept();
xyylval.int_list = parse_int_list(xyytext, ",");
xyylval.u.separator_token = TOKEN_COMMA;
return TOKEN_INTEGER_LIST;
}
({REALNUM},)+ {
// A floating-point number as part of a semicolon-delimited list.
accept();
xyylval.double_list = parse_double_list(xyytext, ",");
xyylval.u.separator_token = TOKEN_COMMA;
return TOKEN_REALNUM_LIST;
}
["] {
// Quoted string.
accept();
xyylval.str = scan_quoted_string('"');
return STRING;
}
['] {
// Single-quoted string.
accept();
xyylval.str = scan_quoted_string('\'');
return STRING;
return TOKEN_STRING;
}
[<] {
@ -521,20 +590,14 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
xyyerror("Malformed GUID.");
}
return WINDOWS_GUID;
return TOKEN_GUID;
}
[A-Za-z_-][A-Za-z_0-9-]* {
// Identifier.
accept();
xyylval.str = xyytext;
return IDENTIFIER;
return TOKEN_NAME;
}
. {
// Send any other printable character as itself.
accept();
return xyytext[0];
}

View File

@ -3,6 +3,12 @@
//
////////////////////////////////////////////////////////////////////
// The grammar defined in this file is taken more-or-less from the
// Microsoft DirectX File Format Specification document, version 1.13.
// The document actually describes a slightly incomplete and incorrect
// grammar, so small changes had to be made, but an attempt was made
// to be as faithful as possible to the intention of the spec.
%{
#include "xLexerDefs.h"
#include "xParserDefs.h"
@ -45,114 +51,119 @@ x_cleanup_parser() {
%}
%token <u.s_int> INTEGER
%token <u.real> REAL
%token <str> STRING IDENTIFIER
%token <guid> WINDOWS_GUID
// These token values are taken from the DirectX spec; the particular
// numeric values are useful when reading an .x file in binary mode
// (which basically just streams the tokens retrieved by the lexer).
%token KW_ARRAY
%token KW_BINARY
%token KW_BYTE
%token KW_CHAR
%token KW_CSTRING
%token KW_DOUBLE
%token KW_DWORD
%token KW_FLOAT
%token KW_STRING
%token KW_TEMPLATE
%token KW_UCHAR
%token KW_UNICODE
%token KW_WORD
%token <str> TOKEN_NAME 1
%token <str> TOKEN_STRING 2
%token <u.number> TOKEN_INTEGER 3
%token <guid> TOKEN_GUID 5
%token <int_list> TOKEN_INTEGER_LIST 6
%token <double_list> TOKEN_REALNUM_LIST 7
%type <u.node> xtemplate
%type <u.node> data_object
%type <str> optional_identifier
%token TOKEN_OBRACE 10
%token TOKEN_CBRACE 11
%token TOKEN_OPAREN 12
%token TOKEN_CPAREN 13
%token TOKEN_OBRACKET 14
%token TOKEN_CBRACKET 15
%token TOKEN_OANGLE 16
%token TOKEN_CANGLE 17
%token TOKEN_DOT 18
%token TOKEN_COMMA 19
%token TOKEN_SEMICOLON 20
%token TOKEN_TEMPLATE 31
%token TOKEN_WORD 40
%token TOKEN_DWORD 41
%token TOKEN_FLOAT 42
%token TOKEN_DOUBLE 43
%token TOKEN_CHAR 44
%token TOKEN_UCHAR 45
%token TOKEN_SWORD 46
%token TOKEN_SDWORD 47
%token TOKEN_VOID 48
%token TOKEN_LPSTR 49
%token TOKEN_UNICODE 50
%token TOKEN_CSTRING 51
%token TOKEN_ARRAY 52
%type <u.node> template
%type <u.node> object
%type <u.primitive_type> primitive_type
%type <int_list> integer_list
%type <double_list> realnum_list
%type <str> name
%type <str> optional_name
%type <guid> class_id
%type <guid> optional_class_id
%%
xfile:
empty
| xfile xtemplate
| xfile data_object
| xfile template
| xfile object
;
xtemplate:
KW_TEMPLATE IDENTIFIER '{' WINDOWS_GUID
template:
TOKEN_TEMPLATE name TOKEN_OBRACE class_id
{
$$ = current_node;
XFileTemplate *templ = new XFileTemplate($2, $4);
current_node->add_child(templ);
current_node = templ;
}
template_members template_restrictions '}'
template_parts TOKEN_CBRACE
{
$$ = current_node;
current_node = $<u.node>5;
}
;
;
template_members:
empty
| template_members template_member ';'
;
template_parts:
template_members_part TOKEN_OBRACKET template_option_info TOKEN_CBRACKET
| template_members_list
;
template_member:
data_def
| KW_ARRAY data_def array_dimensions
;
template_members_part:
empty
| template_members_list
;
data_def:
KW_WORD optional_identifier
template_option_info:
ellipsis
{
current_data_def = new XFileDataDef(XFileDataDef::T_word, $2);
DCAST(XFileTemplate, current_node)->set_open(true);
}
| template_option_list
;
template_members_list:
template_members
| template_members_list template_members
;
template_members:
primitive
| array
| template_reference
;
primitive:
primitive_type optional_name TOKEN_SEMICOLON
{
current_data_def = new XFileDataDef($1, $2);
current_node->add_child(current_data_def);
}
| KW_DWORD optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_dword, $2);
current_node->add_child(current_data_def);
}
| KW_FLOAT optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_float, $2);
current_node->add_child(current_data_def);
}
| KW_DOUBLE optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_double, $2);
current_node->add_child(current_data_def);
}
| KW_CHAR optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_char, $2);
current_node->add_child(current_data_def);
}
| KW_UCHAR optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_uchar, $2);
current_node->add_child(current_data_def);
}
| KW_BYTE optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_byte, $2);
current_node->add_child(current_data_def);
}
| KW_STRING optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_string, $2);
current_node->add_child(current_data_def);
}
| KW_CSTRING optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_cstring, $2);
current_node->add_child(current_data_def);
}
| KW_UNICODE optional_identifier
{
current_data_def = new XFileDataDef(XFileDataDef::T_unicode, $2);
current_node->add_child(current_data_def);
}
| IDENTIFIER optional_identifier
;
array:
TOKEN_ARRAY array_data_type dimension_list TOKEN_SEMICOLON
;
template_reference:
name optional_name TOKEN_SEMICOLON
{
XFileTemplate *xtemplate = x_file->find_template($1);
if (xtemplate == (XFileTemplate *)NULL) {
@ -162,58 +173,118 @@ data_def:
current_node->add_child(current_data_def);
}
}
;
;
array_dimensions:
array_level
| array_dimensions array_level
;
primitive_type:
TOKEN_WORD
{
$$ = XFileDataDef::T_word;
}
| TOKEN_DWORD
{
$$ = XFileDataDef::T_dword;
}
| TOKEN_FLOAT
{
$$ = XFileDataDef::T_float;
}
| TOKEN_DOUBLE
{
$$ = XFileDataDef::T_double;
}
| TOKEN_CHAR
{
$$ = XFileDataDef::T_char;
}
| TOKEN_UCHAR
{
$$ = XFileDataDef::T_uchar;
}
| TOKEN_SWORD
{
$$ = XFileDataDef::T_sword;
}
| TOKEN_SDWORD
{
$$ = XFileDataDef::T_sdword;
}
| TOKEN_LPSTR
{
$$ = XFileDataDef::T_string;
}
| TOKEN_UNICODE
{
$$ = XFileDataDef::T_unicode;
}
| TOKEN_CSTRING
{
$$ = XFileDataDef::T_cstring;
}
;
array_level:
'[' INTEGER ']'
array_data_type:
primitive_type name
{
current_data_def->add_array_def(XFileArrayDef($2));
current_data_def = new XFileDataDef($1, $2);
current_node->add_child(current_data_def);
}
| '[' IDENTIFIER ']'
{
XFileNode *data_def = current_node->find_child($2);
if (data_def == (XFileNode *)NULL) {
yyerror("Unknown identifier: " + $2);
} else {
current_data_def->add_array_def(XFileArrayDef(DCAST(XFileDataDef, data_def)));
}
}
;
template_restrictions:
empty
| '[' '.' '.' '.' ']'
{
DCAST(XFileTemplate, current_node)->set_open(true);
}
| '[' template_restriction_list ']'
;
template_restriction_list:
template_restriction_element
{
}
| template_restriction_list ',' template_restriction_element
{
}
;
template_restriction_element:
IDENTIFIER
| name name
{
XFileTemplate *xtemplate = x_file->find_template($1);
if (xtemplate == (XFileTemplate *)NULL) {
yyerror("Unknown template: " + $1);
} else {
DCAST(XFileTemplate, current_node)->add_restriction(xtemplate);
current_data_def = new XFileDataDef(XFileDataDef::T_template, $2, xtemplate);
current_node->add_child(current_data_def);
}
}
| IDENTIFIER WINDOWS_GUID
;
dimension_list:
dimension
| dimension_list dimension
;
dimension:
TOKEN_OBRACKET dimension_size TOKEN_CBRACKET
;
dimension_size:
TOKEN_INTEGER
{
current_data_def->add_array_def(XFileArrayDef($1));
}
| name
{
XFileNode *data_def = current_node->find_child($1);
if (data_def == (XFileNode *)NULL) {
yyerror("Unknown identifier: " + $1);
} else {
current_data_def->add_array_def(XFileArrayDef(DCAST(XFileDataDef, data_def)));
}
}
;
template_option_list:
template_option_part
{
}
| template_option_list template_option_part
{
}
;
template_option_part:
name
{
XFileTemplate *xtemplate = x_file->find_template($1);
if (xtemplate == (XFileTemplate *)NULL) {
yyerror("Unknown template: " + $1);
} else {
DCAST(XFileTemplate, current_node)->add_option(xtemplate);
}
}
| name TOKEN_GUID
{
XFileTemplate *xtemplate = x_file->find_template($2);
if (xtemplate == (XFileTemplate *)NULL) {
@ -223,13 +294,41 @@ template_restriction_element:
xyywarning("GUID identifies template " + xtemplate->get_name() +
", not " + $1);
}
DCAST(XFileTemplate, current_node)->add_restriction(xtemplate);
DCAST(XFileTemplate, current_node)->add_option(xtemplate);
}
}
;
;
data_object:
IDENTIFIER optional_identifier '{'
name:
TOKEN_NAME
;
optional_name:
empty
{
$$ = string();
}
| name
;
class_id:
TOKEN_GUID
;
optional_class_id:
empty
{
$$ = WindowsGuid();
}
| class_id
;
ellipsis:
TOKEN_DOT TOKEN_DOT TOKEN_DOT
;
object:
name optional_name TOKEN_OBRACE
{
XFileTemplate *xtemplate = x_file->find_template($1);
$$ = current_node;
@ -243,55 +342,59 @@ data_object:
current_node = templ;
}
}
data_object_members '}'
optional_class_id data_parts_list TOKEN_CBRACE
{
$$ = current_node;
current_node = $<u.node>4;
}
;
data_parts_list:
data_part
| data_parts_list data_part
;
data_object_members:
empty
| data_object_members data_object_member
;
data_part:
data_reference
{
}
| object
{
}
| integer_list
{
}
| realnum_list
{
}
| string list_separator
{
}
| list_separator
{
}
;
integer_list:
TOKEN_INTEGER_LIST
;
data_object_member:
data_object
{
}
| data_reference
{
}
| INTEGER
{
}
| REAL
{
}
| STRING
{
}
| ';'
{
}
| ','
{
}
realnum_list:
TOKEN_REALNUM_LIST
;
string:
TOKEN_STRING
;
list_separator:
TOKEN_SEMICOLON
| TOKEN_COMMA
;
data_reference:
'{' IDENTIFIER '}'
;
optional_identifier:
empty
{
$$ = string();
}
| IDENTIFIER
;
TOKEN_OBRACE name optional_class_id TOKEN_CBRACE
;
empty:
;

View File

@ -20,8 +20,10 @@
#define XPARSERDEFS_H
#include "pandatoolbase.h"
#include "windowsGuid.h"
#include "xFileDataDef.h"
#include "pta_int.h"
#include "pta_double.h"
class XFile;
class XFileNode;
@ -40,12 +42,15 @@ int xyyparse();
class XTokenType {
public:
union U {
int s_int;
double real;
int number;
XFileNode *node;
XFileDataDef::Type primitive_type;
int separator_token; // This is filled in for double_list and int_list.
} u;
string str;
WindowsGuid guid;
PTA_double double_list;
PTA_int int_list;
};
// The yacc-generated code expects to use the symbol 'YYSTYPE' to