egg: Make egg parser and lexer reentrant

This avoids the need for the global mutex lock and allows two egg files to be read simultaneously.

Error reporting has also been improved by specifically pinpointing the offending token when an error occurs.
This commit is contained in:
rdb 2021-01-02 20:08:15 +01:00
parent 06484566b3
commit 91380e8718
17 changed files with 3823 additions and 3399 deletions

View File

@ -4396,7 +4396,7 @@ if GetTarget() == 'windows' and not PkgSkip("DX9"):
#
if not PkgSkip("EGG"):
OPTS=['DIR:panda/src/egg', 'BUILDING:PANDAEGG', 'ZLIB', 'BISONPREFIX_eggyy', 'FLEXDASHI', 'FLEXVERSION:2.5.9']
OPTS=['DIR:panda/src/egg', 'BUILDING:PANDAEGG', 'ZLIB', 'BISONPREFIX_eggyy', 'FLEXDASHI', 'FLEXVERSION:2.5.6']
CreateFile(GetOutputDir()+"/include/parser.h")
TargetAdd('p3egg_parser.obj', opts=OPTS, input='parser.yxx')
TargetAdd('parser.h', input='p3egg_parser.obj', opts=['DEPENDENCYONLY'])

View File

@ -114,13 +114,12 @@ read(istream &in) {
// set it.
PT(EggData) data = new EggData(*this);
int error_count;
bool success;
{
LightMutexHolder holder(egg_lock);
egg_init_parser(in, get_egg_filename(), data, data);
eggyyparse();
egg_cleanup_parser();
error_count = egg_error_count();
EggLexerState lexer_state;
egg_init_lexer_state(lexer_state, in, get_egg_filename());
success = egg_parse(lexer_state, data, data);
egg_cleanup_lexer_state(lexer_state);
}
data->post_read();
@ -128,7 +127,7 @@ read(istream &in) {
steal_children(*data);
(*this) = *data;
return (error_count == 0);
return success;
}
/**

View File

@ -1094,8 +1094,8 @@ write_vertex_ref(ostream &out, int indent_level) const {
* return false.
*/
bool EggGroup::
egg_start_parse_body() {
egg_start_group_body();
egg_start_parse_body(EggLexerState &state) {
egg_start_group_body(state);
return true;
}

View File

@ -369,7 +369,7 @@ public:
protected:
void write_vertex_ref(std::ostream &out, int indent_level) const;
virtual bool egg_start_parse_body();
virtual bool egg_start_parse_body(EggLexerState &state);
virtual void adjust_under();
virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
CoordinateSystem to_cs);

View File

@ -229,19 +229,13 @@ parse_egg(const std::string &egg_syntax) {
std::istringstream in(egg_syntax);
LightMutexHolder holder(egg_lock);
egg_init_parser(in, "", this, group);
if (!egg_start_parse_body()) {
egg_cleanup_parser();
EggLexerState lexer_state;
egg_init_lexer_state(lexer_state, in, "");
if (!egg_start_parse_body(lexer_state)) {
return false;
}
eggyyparse();
egg_cleanup_parser();
return (egg_error_count() == 0);
return egg_parse(lexer_state, this, group);
}
#ifdef _DEBUG
@ -287,7 +281,7 @@ test_under_integrity() const {
* return false.
*/
bool EggNode::
egg_start_parse_body() {
egg_start_parse_body(EggLexerState &state) {
return false;
}

View File

@ -28,6 +28,8 @@ class EggGroupNode;
class EggRenderMode;
class EggTextureCollection;
struct EggLexerState;
/**
* A base class for things that may be directly added into the egg hierarchy.
* This includes groups, joints, polygons, vertex pools, etc., but does not
@ -100,7 +102,7 @@ protected:
UF_local_coord = 0x004,
};
virtual bool egg_start_parse_body();
virtual bool egg_start_parse_body(EggLexerState &state);
virtual void update_under(int depth_offset);
virtual void adjust_under();

View File

@ -905,8 +905,8 @@ write_body(std::ostream &out, int indent_level) const {
* return false.
*/
bool EggPrimitive::
egg_start_parse_body() {
egg_start_primitive_body();
egg_start_parse_body(EggLexerState &state) {
egg_start_primitive_body(state);
return true;
}

View File

@ -211,7 +211,7 @@ protected:
protected:
void write_body(std::ostream &out, int indent_level) const;
virtual bool egg_start_parse_body();
virtual bool egg_start_parse_body(EggLexerState &state);
virtual void r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
CoordinateSystem to_cs);
virtual void r_flatten_transforms();

View File

@ -1063,8 +1063,8 @@ as_transform() {
* return false.
*/
bool EggTexture::
egg_start_parse_body() {
egg_start_texture_body();
egg_start_parse_body(EggLexerState &state) {
egg_start_texture_body(state);
return true;
}

View File

@ -365,7 +365,7 @@ public:
virtual EggTransform *as_transform();
protected:
virtual bool egg_start_parse_body();
virtual bool egg_start_parse_body(EggLexerState &state);
private:
typedef pset<EggTexture *> MultiTextures;

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,10 @@
* @date 1999-01-16
*/
%option reentrant bison-bridge bison-locations
%option noyywrap
%option case-insensitive
%{
#include "pandabase.h"
#include "lexerDefs.h"
@ -18,182 +22,156 @@
#include <math.h>
using std::istream;
using std::ostream;
using std::string;
extern "C" int eggyywrap(void); // declared below.
static int yyinput(void); // declared by flex.
int eggyylex_destroy(void);
////////////////////////////////////////////////////////////////////
// Static variables
////////////////////////////////////////////////////////////////////
// This mutex protects all of these global variables.
LightMutex egg_lock;
// We'll increment line_number and col_number as we parse the file, so
// that we can report the position of an error.
static int line_number = 0;
static int col_number = 0;
// current_line holds as much of the current line as will fit. Its
// only purpose is for printing it out to report an error to the user.
static const int max_error_width = 1024;
static char current_line[max_error_width + 1];
static int error_count = 0;
static int warning_count = 0;
// This is the pointer to the current input stream.
static istream *input_p = nullptr;
// This is the name of the egg file we're parsing. We keep it so we
// can print it out for error messages.
static string egg_filename;
// This is the initial token state returned by the lexer. It allows
// the yacc grammar to start from initial points.
static int initial_token;
// These are declared by flex.
static int yyinput(yyscan_t yyscanner);
static EggLexerState *eggyyget_extra(yyscan_t scanner);
////////////////////////////////////////////////////////////////////
// Defining the interface to the lexer.
////////////////////////////////////////////////////////////////////
void
egg_init_lexer(istream &in, const string &filename) {
input_p = &in;
egg_filename = filename;
line_number = 0;
col_number = 0;
error_count = 0;
warning_count = 0;
initial_token = START_EGG;
egg_init_lexer_state(EggLexerState &state, std::istream &in, const std::string &filename) {
state._error_count = 0;
state._warning_count = 0;
state._input_p = &in;
state._egg_filename = filename;
state._initial_token = START_EGG;
}
void
egg_cleanup_lexer() {
// Reset the lexer state.
yylex_destroy();
input_p = nullptr;
egg_filename.clear();
egg_cleanup_lexer_state(EggLexerState &state) {
state._input_p = nullptr;
state._egg_filename.clear();
}
void
egg_start_group_body() {
egg_start_group_body(EggLexerState &state) {
/* Set the initial state to begin within a group_body context,
instead of at the beginning of the egg file. */
initial_token = START_GROUP_BODY;
state._initial_token = START_GROUP_BODY;
}
void
egg_start_texture_body() {
initial_token = START_TEXTURE_BODY;
egg_start_texture_body(EggLexerState &state) {
state._initial_token = START_TEXTURE_BODY;
}
void
egg_start_primitive_body() {
initial_token = START_PRIMITIVE_BODY;
egg_start_primitive_body(EggLexerState &state) {
state._initial_token = START_PRIMITIVE_BODY;
}
int
egg_error_count() {
return error_count;
}
int
egg_warning_count() {
return warning_count;
}
////////////////////////////////////////////////////////////////////
// Internal support functions.
////////////////////////////////////////////////////////////////////
int
eggyywrap(void) {
return 1;
}
void
eggyyerror(const string &msg) {
eggyyerror(YYLTYPE *loc, yyscan_t scanner, const std::string &msg) {
EggLexerState *lexer_state = eggyyget_extra(scanner);
if (egg_cat.is_error()) {
ostream &out = egg_cat.error(false);
std::ostream &out = egg_cat.error(false);
out << "\nError";
if (!egg_filename.empty()) {
out << " in " << egg_filename;
if (!lexer_state->_egg_filename.empty()) {
out << " in " << lexer_state->_egg_filename;
}
if (loc != nullptr) {
out
<< " at line " << loc->first_line << ", column " << loc->first_column << ":\n"
<< std::setiosflags(Notify::get_literal_flag())
<< lexer_state->_current_line << "\n";
indent(out, loc->first_column - 1)
<< "^";
int last_column;
if (loc->first_line == loc->last_line) {
last_column = loc->last_column;
} else {
last_column = strlen(lexer_state->_current_line);
}
for (int i = loc->first_column; i < last_column; ++i) {
out.put('~');
}
out
<< "\n" << msg << "\n\n"
<< std::resetiosflags(Notify::get_literal_flag()) << std::flush;
}
else {
out << ":\n" << msg << "\n\n" << std::flush;
}
out
<< " at line " << line_number << ", column " << col_number << ":\n"
<< std::setiosflags(Notify::get_literal_flag())
<< current_line << "\n";
indent(out, col_number-1)
<< "^\n" << msg << "\n\n"
<< std::resetiosflags(Notify::get_literal_flag()) << std::flush;
}
error_count++;
lexer_state->_error_count++;
}
void
eggyyerror(std::ostringstream &strm) {
string s = strm.str();
eggyyerror(s);
}
eggyywarning(YYLTYPE *loc, yyscan_t scanner, const std::string &msg) {
EggLexerState *lexer_state = eggyyget_extra(scanner);
void
eggyywarning(const string &msg) {
if (egg_cat.is_warning()) {
ostream &out = egg_cat.warning(false);
std::ostream &out = egg_cat.warning(false);
out << "\nWarning";
if (!egg_filename.empty()) {
out << " in " << egg_filename;
if (!lexer_state->_egg_filename.empty()) {
out << " in " << lexer_state->_egg_filename;
}
out
<< " at line " << line_number << ", column " << col_number << ":\n"
<< std::setiosflags(Notify::get_literal_flag())
<< current_line << "\n";
indent(out, col_number-1)
<< "^\n" << msg << "\n\n"
<< std::resetiosflags(Notify::get_literal_flag()) << std::flush;
}
warning_count++;
}
if (loc != nullptr) {
out
<< " at line " << loc->first_line << ", column " << loc->first_column << ":\n"
<< std::setiosflags(Notify::get_literal_flag())
<< lexer_state->_current_line << "\n";
indent(out, loc->first_column - 1)
<< "^";
void
eggyywarning(std::ostringstream &strm) {
string s = strm.str();
eggyywarning(s);
int last_column;
if (loc->first_line == loc->last_line) {
last_column = loc->last_column;
} else {
last_column = strlen(lexer_state->_current_line);
}
for (int i = loc->first_column; i < last_column; ++i) {
out.put('~');
}
out
<< "\n" << msg << "\n\n"
<< std::resetiosflags(Notify::get_literal_flag()) << std::flush;
}
else {
out << ":\n" << msg << "\n\n" << std::flush;
}
}
lexer_state->_warning_count++;
}
// Now define a function to take input from an istream instead of a
// stdio FILE pointer. This is flex-specific.
static void
input_chars(char *buffer, int &result, int max_size) {
nassertv(input_p != nullptr);
if (*input_p) {
input_p->read(buffer, max_size);
result = input_p->gcount();
input_chars(YYLTYPE *yylloc, yyscan_t yyscanner, char *buffer, int &result, int max_size) {
EggLexerState &state = *yyget_extra(yyscanner);
if (line_number == 0) {
nassertv(state._input_p != nullptr);
if (*state._input_p) {
state._input_p->read(buffer, max_size);
result = state._input_p->gcount();
if (yylloc->last_line == 0) {
// This is a special case. If we are reading the very first bit
// from the stream, copy it into the current_line array. This
// is because the \n.* rule below, which fills current_line
// from the stream, copy it into the _current_line array. This
// is because the \n.* rule below, which fills _current_line
// normally, doesn't catch the first line.
int length = std::min(max_error_width, result);
strncpy(current_line, buffer, length);
current_line[length] = '\0';
line_number++;
col_number = 0;
size_t length = std::min(egg_max_error_width, (size_t)result);
strncpy(state._current_line, buffer, length);
state._current_line[length] = '\0';
yylloc->first_line = 1;
yylloc->last_line = 1;
yylloc->first_column = 0;
yylloc->last_column = 0;
// Truncate it at the newline.
char *end = strchr(current_line, '\n');
char *end = strchr(state._current_line, '\n');
if (end != nullptr) {
*end = '\0';
}
@ -211,7 +189,7 @@ input_chars(char *buffer, int &result, int max_size) {
// with a different type for result.
#define YY_INPUT(buffer, result, max_size) { \
int int_result = 0; \
input_chars((buffer), int_result, (max_size)); \
input_chars(yylloc, yyscanner, (buffer), int_result, (max_size)); \
(result) = int_result; \
}
@ -219,8 +197,8 @@ input_chars(char *buffer, int &result, int max_size) {
// supplied line and column numbers as appropriate. A convenience
// function for the scanning functions below.
static int
read_char(int &line, int &col) {
int c = yyinput();
read_char(yyscan_t yyscanner, int &line, int &col) {
int c = yyinput(yyscanner);
if (c == '\n') {
line++;
col = 0;
@ -232,78 +210,56 @@ read_char(int &line, int &col) {
// scan_quoted_string reads a string delimited by quotation marks and
// returns it.
static string
scan_quoted_string() {
string result;
// We don't touch the current line number and column number during
// scanning, so that if we detect an error while scanning the string
// (e.g. an unterminated string), we'll report the error as
// occurring at the start of the string, not at the end--somewhat
// more convenient for the user.
// Instead of adjusting the global line_number and col_number
// variables, we'll operate on our own local variables for the
// interim.
int line = line_number;
int col = col_number;
static std::string
scan_quoted_string(YYLTYPE *yylloc, yyscan_t yyscanner) {
std::string result;
int c;
c = read_char(line, col);
c = read_char(yyscanner, yylloc->last_line, yylloc->last_column);
while (c != '"' && c != 0 && c != EOF) {
result += c;
c = read_char(line, col);
c = read_char(yyscanner, yylloc->last_line, yylloc->last_column);
}
if (c == 0 || c == EOF) {
eggyyerror("This quotation mark is unterminated.");
eggyyerror(yylloc, yyscanner, "This quotation mark is unterminated.");
}
line_number = line;
col_number = col;
return result;
}
// eat_c_comment scans past all characters up until the first */
// encountered.
static void
eat_c_comment() {
// As above, we'll operate on our own local copies of line_number
// and col_number within this function.
int line = line_number;
int col = col_number;
eat_c_comment(YYLTYPE *yylloc, yyscan_t yyscanner) {
int c, last_c;
last_c = '\0';
c = read_char(line, col);
c = read_char(yyscanner, yylloc->last_line, yylloc->last_column);
while (c != 0 && c != EOF && !(last_c == '*' && c == '/')) {
if (last_c == '/' && c == '*') {
std::ostringstream errmsg;
errmsg << "This comment contains a nested /* symbol at line "
<< line << ", column " << col-1 << "--possibly unclosed?"
<< std::ends;
eggyywarning(errmsg);
<< yylloc->last_line << ", column " << yylloc->last_column - 1
<< "--possibly unclosed?" << std::ends;
eggyywarning(yylloc, yyscanner, errmsg.str());
}
last_c = c;
c = read_char(line, col);
c = read_char(yyscanner, yylloc->last_line, yylloc->last_column);
}
if (c == 0 || c == EOF) {
eggyyerror("This comment marker is unclosed.");
eggyyerror(yylloc, yyscanner, "This comment marker is unclosed.");
}
line_number = line;
col_number = col;
}
// accept() is called below as each piece is pulled off and
// accepted by the lexer; it increments the current column number.
INLINE void accept() {
col_number += yyleng;
#define accept() { \
yylloc->first_line = yylloc->last_line; \
yylloc->first_column = yylloc->last_column + 1; \
yylloc->last_column += yyleng; \
}
%}
@ -315,9 +271,9 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
%%
%{
if (initial_token != 0) {
int t = initial_token;
initial_token = 0;
if (yyextra->_initial_token != 0) {
int t = yyextra->_initial_token;
yyextra->_initial_token = 0;
return t;
}
%}
@ -326,10 +282,13 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
// New line. Save a copy of the line so we can print it out for the
// benefit of the user in case we get an error.
strncpy(current_line, yytext+1, max_error_width);
current_line[max_error_width] = '\0';
line_number++;
col_number=0;
strncpy(yyextra->_current_line, yytext+1, egg_max_error_width);
yyextra->_current_line[egg_max_error_width] = '\0';
yylloc->first_line++;
yylloc->last_line++;
yylloc->first_column = 0;
yylloc->last_column = 0;
// Return the whole line to the lexer, except the newline character,
// which we eat.
@ -349,13 +308,13 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
"/*" {
// Eat C-style comments.
accept();
eat_c_comment();
eat_c_comment(yylloc, yyscanner);
}
[{}] {
// Send curly braces as themselves.
accept();
return eggyytext[0];
return yytext[0];
}
@ -706,65 +665,65 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
{NUMERIC} {
// An integer or floating-point number.
accept();
eggyylval._number = patof(eggyytext);
eggyylval._string = yytext;
yylval->_number = patof(yytext);
yylval->_string = yytext;
return EGG_NUMBER;
}
{HEX} {
// A hexadecimal integer number.
accept();
eggyylval._ulong = strtoul(yytext+2, nullptr, 16);
eggyylval._string = yytext;
yylval->_ulong = strtoul(yytext+2, nullptr, 16);
yylval->_string = yytext;
return EGG_ULONG;
}
{BINARY} {
// A binary integer number.
accept();
eggyylval._ulong = strtoul(yytext+2, nullptr, 2);
eggyylval._string = yytext;
yylval->_ulong = strtoul(yytext+2, nullptr, 2);
yylval->_string = yytext;
return EGG_ULONG;
}
"nan"{HEX} {
// not-a-number. These sometimes show up in egg files accidentally.
accept();
memset(&eggyylval._number, 0, sizeof(eggyylval._number));
*(unsigned long *)&eggyylval._number = strtoul(yytext+3, nullptr, 0);
eggyylval._string = yytext;
memset(&yylval->_number, 0, sizeof(yylval->_number));
*(unsigned long *)&yylval->_number = strtoul(yytext+3, nullptr, 0);
yylval->_string = yytext;
return EGG_NUMBER;
}
"inf" {
// infinity. As above.
accept();
eggyylval._number = HUGE_VAL;
eggyylval._string = yytext;
yylval->_number = HUGE_VAL;
yylval->_string = yytext;
return EGG_NUMBER;
}
"-inf" {
// minus infinity. As above.
accept();
eggyylval._number = -HUGE_VAL;
eggyylval._string = yytext;
yylval->_number = -HUGE_VAL;
yylval->_string = yytext;
return EGG_NUMBER;
}
"1.#inf" {
// infinity, on Win32. As above.
accept();
eggyylval._number = HUGE_VAL;
eggyylval._string = yytext;
yylval->_number = HUGE_VAL;
yylval->_string = yytext;
return EGG_NUMBER;
}
"-1.#inf" {
// minus infinity, on Win32. As above.
accept();
eggyylval._number = -HUGE_VAL;
eggyylval._string = yytext;
yylval->_number = -HUGE_VAL;
yylval->_string = yytext;
return EGG_NUMBER;
}
@ -772,13 +731,13 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
["] {
// Quoted string.
accept();
eggyylval._string = scan_quoted_string();
yylval->_string = scan_quoted_string(yylloc, yyscanner);
return EGG_STRING;
}
[^ \t\n\r{}"]+ {
// Unquoted string.
accept();
eggyylval._string = yytext;
yylval->_string = yytext;
return EGG_STRING;
}

View File

@ -15,26 +15,56 @@
#define LEXER_H
#include "pandabase.h"
#include "parserDefs.h"
#include "typedef.h"
#include <string>
void egg_init_lexer(std::istream &in, const std::string &filename);
void egg_cleanup_lexer();
void egg_start_group_body();
void egg_start_texture_body();
void egg_start_primitive_body();
int egg_error_count();
int egg_warning_count();
typedef void *yyscan_t;
struct EggLexerState;
struct EggParserState;
struct EggTokenType;
struct EggLocType;
void eggyyerror(const std::string &msg);
void eggyyerror(std::ostringstream &strm);
void egg_init_lexer_state(EggLexerState &state, std::istream &in, const std::string &filename);
void egg_cleanup_lexer_state(EggLexerState &state);
void eggyywarning(const std::string &msg);
void eggyywarning(std::ostringstream &strm);
void egg_start_group_body(EggLexerState &state);
void egg_start_texture_body(EggLexerState &state);
void egg_start_primitive_body(EggLexerState &state);
int eggyylex();
// These functions are declared by flex.
int eggyylex_init_extra(EggLexerState *state, yyscan_t *scanner);
int eggyylex_destroy(yyscan_t scanner);
void eggyyerror(EggLocType *loc, yyscan_t scanner, const std::string &msg);
void eggyywarning(EggLocType *loc, yyscan_t scanner, const std::string &msg);
int eggyylex(EggTokenType *yylval_param, EggLocType *yylloc_param, yyscan_t yyscanner);
static const size_t egg_max_error_width = 1024;
struct EggLexerState {
// current_line holds as much of the current line as will fit. Its
// only purpose is for printing it out to report an error to the user.
char _current_line[egg_max_error_width + 1];
int _error_count = 0;
int _warning_count = 0;
// This is the pointer to the current input stream.
std::istream *_input_p = nullptr;
// This is the name of the egg file we're parsing. We keep it so we
// can print it out for error messages.
std::string _egg_filename;
// This is the initial token state returned by the lexer. It allows
// the yacc grammar to start from initial points.
int _initial_token = 0;
};
#define YY_EXTRA_TYPE EggLexerState *
// always read from files
#define YY_NEVER_INTERACTIVE 1

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
/* A Bison parser, made by GNU Bison 3.2.2. */
/* A Bison parser, made by GNU Bison 3.7.2. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc.
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -30,8 +31,9 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Undocumented macros, especially those whose name start with YY_,
are private implementation details. Do not rely on them. */
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
especially those whose name start with YY_ or yy_. They are
private implementation details that can be changed or removed. */
#ifndef YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED
# define YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED
@ -43,103 +45,111 @@
extern int eggyydebug;
#endif
/* Token type. */
/* Token kinds. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
EGG_NUMBER = 258,
EGG_ULONG = 259,
EGG_STRING = 260,
ANIMPRELOAD = 261,
BEZIERCURVE = 262,
BFACE = 263,
BILLBOARD = 264,
BILLBOARDCENTER = 265,
BINORMAL = 266,
BUNDLE = 267,
CLOSED = 268,
COLLIDE = 269,
COMMENT = 270,
COMPONENT = 271,
COORDSYSTEM = 272,
CV = 273,
DART = 274,
DNORMAL = 275,
DRGBA = 276,
DUV = 277,
DXYZ = 278,
DCS = 279,
DISTANCE = 280,
DTREF = 281,
DYNAMICVERTEXPOOL = 282,
EXTERNAL_FILE = 283,
GROUP = 284,
DEFAULTPOSE = 285,
JOINT = 286,
KNOTS = 287,
INCLUDE = 288,
INSTANCE = 289,
LINE = 290,
LOOP = 291,
MATERIAL = 292,
MATRIX3 = 293,
MATRIX4 = 294,
MODEL = 295,
MREF = 296,
NORMAL = 297,
NURBSCURVE = 298,
NURBSSURFACE = 299,
OBJECTTYPE = 300,
ORDER = 301,
OUTTANGENT = 302,
PATCH = 303,
POINTLIGHT = 304,
POLYGON = 305,
REF = 306,
RGBA = 307,
ROTATE = 308,
ROTX = 309,
ROTY = 310,
ROTZ = 311,
SANIM = 312,
SCALAR = 313,
SCALE = 314,
SEQUENCE = 315,
SHADING = 316,
SWITCH = 317,
SWITCHCONDITION = 318,
TABLE = 319,
TABLE_V = 320,
TAG = 321,
TANGENT = 322,
TEXLIST = 323,
TEXTURE = 324,
TLENGTHS = 325,
TRANSFORM = 326,
TRANSLATE = 327,
TREF = 328,
TRIANGLEFAN = 329,
TRIANGLESTRIP = 330,
TRIM = 331,
TXT = 332,
UKNOTS = 333,
UV = 334,
AUX = 335,
VKNOTS = 336,
VERTEX = 337,
VERTEXANIM = 338,
VERTEXPOOL = 339,
VERTEXREF = 340,
XFMANIM = 341,
XFMSANIM = 342,
START_EGG = 343,
START_GROUP_BODY = 344,
START_TEXTURE_BODY = 345,
START_PRIMITIVE_BODY = 346
YYEMPTY = -2,
YYEOF = 0, /* "end of file" */
YYerror = 256, /* error */
YYUNDEF = 257, /* "invalid token" */
EGG_NUMBER = 258, /* EGG_NUMBER */
EGG_ULONG = 259, /* EGG_ULONG */
EGG_STRING = 260, /* EGG_STRING */
ANIMPRELOAD = 261, /* ANIMPRELOAD */
BEZIERCURVE = 262, /* BEZIERCURVE */
BFACE = 263, /* BFACE */
BILLBOARD = 264, /* BILLBOARD */
BILLBOARDCENTER = 265, /* BILLBOARDCENTER */
BINORMAL = 266, /* BINORMAL */
BUNDLE = 267, /* BUNDLE */
CLOSED = 268, /* CLOSED */
COLLIDE = 269, /* COLLIDE */
COMMENT = 270, /* COMMENT */
COMPONENT = 271, /* COMPONENT */
COORDSYSTEM = 272, /* COORDSYSTEM */
CV = 273, /* CV */
DART = 274, /* DART */
DNORMAL = 275, /* DNORMAL */
DRGBA = 276, /* DRGBA */
DUV = 277, /* DUV */
DXYZ = 278, /* DXYZ */
DCS = 279, /* DCS */
DISTANCE = 280, /* DISTANCE */
DTREF = 281, /* DTREF */
DYNAMICVERTEXPOOL = 282, /* DYNAMICVERTEXPOOL */
EXTERNAL_FILE = 283, /* EXTERNAL_FILE */
GROUP = 284, /* GROUP */
DEFAULTPOSE = 285, /* DEFAULTPOSE */
JOINT = 286, /* JOINT */
KNOTS = 287, /* KNOTS */
INCLUDE = 288, /* INCLUDE */
INSTANCE = 289, /* INSTANCE */
LINE = 290, /* LINE */
LOOP = 291, /* LOOP */
MATERIAL = 292, /* MATERIAL */
MATRIX3 = 293, /* MATRIX3 */
MATRIX4 = 294, /* MATRIX4 */
MODEL = 295, /* MODEL */
MREF = 296, /* MREF */
NORMAL = 297, /* NORMAL */
NURBSCURVE = 298, /* NURBSCURVE */
NURBSSURFACE = 299, /* NURBSSURFACE */
OBJECTTYPE = 300, /* OBJECTTYPE */
ORDER = 301, /* ORDER */
OUTTANGENT = 302, /* OUTTANGENT */
PATCH = 303, /* PATCH */
POINTLIGHT = 304, /* POINTLIGHT */
POLYGON = 305, /* POLYGON */
REF = 306, /* REF */
RGBA = 307, /* RGBA */
ROTATE = 308, /* ROTATE */
ROTX = 309, /* ROTX */
ROTY = 310, /* ROTY */
ROTZ = 311, /* ROTZ */
SANIM = 312, /* SANIM */
SCALAR = 313, /* SCALAR */
SCALE = 314, /* SCALE */
SEQUENCE = 315, /* SEQUENCE */
SHADING = 316, /* SHADING */
SWITCH = 317, /* SWITCH */
SWITCHCONDITION = 318, /* SWITCHCONDITION */
TABLE = 319, /* TABLE */
TABLE_V = 320, /* TABLE_V */
TAG = 321, /* TAG */
TANGENT = 322, /* TANGENT */
TEXLIST = 323, /* TEXLIST */
TEXTURE = 324, /* TEXTURE */
TLENGTHS = 325, /* TLENGTHS */
TRANSFORM = 326, /* TRANSFORM */
TRANSLATE = 327, /* TRANSLATE */
TREF = 328, /* TREF */
TRIANGLEFAN = 329, /* TRIANGLEFAN */
TRIANGLESTRIP = 330, /* TRIANGLESTRIP */
TRIM = 331, /* TRIM */
TXT = 332, /* TXT */
UKNOTS = 333, /* UKNOTS */
UV = 334, /* UV */
AUX = 335, /* AUX */
VKNOTS = 336, /* VKNOTS */
VERTEX = 337, /* VERTEX */
VERTEXANIM = 338, /* VERTEXANIM */
VERTEXPOOL = 339, /* VERTEXPOOL */
VERTEXREF = 340, /* VERTEXREF */
XFMANIM = 341, /* XFMANIM */
XFMSANIM = 342, /* XFMSANIM */
START_EGG = 343, /* START_EGG */
START_GROUP_BODY = 344, /* START_GROUP_BODY */
START_TEXTURE_BODY = 345, /* START_TEXTURE_BODY */
START_PRIMITIVE_BODY = 346 /* START_PRIMITIVE_BODY */
};
typedef enum yytokentype yytoken_kind_t;
#endif
/* Tokens. */
/* Token kinds. */
#define YYEOF 0
#define YYerror 256
#define YYUNDEF 257
#define EGG_NUMBER 258
#define EGG_ULONG 259
#define EGG_STRING 260
@ -232,9 +242,22 @@ extern int eggyydebug;
/* Value type. */
/* Location type. */
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE YYLTYPE;
struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
};
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE eggyylval;
int eggyyparse (void);
int eggyyparse (EggParserState &state, yyscan_t scanner);
#endif /* !YY_EGGYY_BUILT_TMP_PARSER_YXX_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -27,12 +27,9 @@
class EggGroupNode;
class LightMutex;
extern LightMutex egg_lock;
struct EggLexerState;
void egg_init_parser(std::istream &in, const std::string &filename,
EggObject *tos, EggGroupNode *egg_top_node);
void egg_cleanup_parser();
bool egg_parse(EggLexerState &lexer, EggObject *tos, EggGroupNode *egg_top_node);
// This structure holds the return value for each token. Traditionally, this
// is a union, and is declared with the %union declaration in the parser.y
@ -40,8 +37,7 @@ void egg_cleanup_parser();
// that has member functions in a union), so we'll use a class instead. That
// means we need to declare it externally, here.
class EXPCL_PANDA_EGG EggTokenType {
public:
struct EggTokenType {
double _number;
unsigned long _ulong;
std::string _string;
@ -53,4 +49,14 @@ public:
// above class.
#define YYSTYPE EggTokenType
struct EggLocType {
// Bison expects these members to be part of this struct.
int first_line;
int first_column;
int last_line;
int last_column;
};
#define YYLTYPE EggLocType
#endif