open_toontown_panda3d/panda/src/egg/lexer.lxx

757 lines
13 KiB
Plaintext

/*
// Filename: lexer.l
// Created by: drose (16Jan99)
//
////////////////////////////////////////////////////////////////////
*/
%{
#include "pandabase.h"
#include "lexerDefs.h"
#include "parserDefs.h"
#include "config_egg.h"
#include "parser.h"
#include "indent.h"
#include "pnotify.h"
#include "lightMutex.h"
#include "thread.h"
#include "pstrtod.h"
#include <math.h>
extern "C" int eggyywrap(void); // declared below.
static int yyinput(void); // declared by flex.
////////////////////////////////////////////////////////////////////
// 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 *inp = NULL;
// 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;
////////////////////////////////////////////////////////////////////
// Defining the interface to the lexer.
////////////////////////////////////////////////////////////////////
void
egg_init_lexer(istream &in, const string &filename) {
inp = &in;
egg_filename = filename;
line_number = 0;
col_number = 0;
error_count = 0;
warning_count = 0;
initial_token = START_EGG;
}
void
egg_start_group_body() {
/* 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;
}
void
egg_start_texture_body() {
initial_token = START_TEXTURE_BODY;
}
void
egg_start_primitive_body() {
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) {
if (egg_cat.is_error()) {
ostream &out = egg_cat.error(false);
out << "\nError";
if (!egg_filename.empty()) {
out << " in " << egg_filename;
}
out
<< " at line " << line_number << ", column " << col_number << ":\n"
<< setiosflags(Notify::get_literal_flag())
<< current_line << "\n";
indent(out, col_number-1)
<< "^\n" << msg << "\n\n"
<< resetiosflags(Notify::get_literal_flag()) << flush;
}
error_count++;
}
void
eggyyerror(ostringstream &strm) {
string s = strm.str();
eggyyerror(s);
}
void
eggyywarning(const string &msg) {
if (egg_cat.is_warning()) {
ostream &out = egg_cat.warning(false);
out << "\nWarning";
if (!egg_filename.empty()) {
out << " in " << egg_filename;
}
out
<< " at line " << line_number << ", column " << col_number << ":\n"
<< setiosflags(Notify::get_literal_flag())
<< current_line << "\n";
indent(out, col_number-1)
<< "^\n" << msg << "\n\n"
<< resetiosflags(Notify::get_literal_flag()) << flush;
}
warning_count++;
}
void
eggyywarning(ostringstream &strm) {
string s = strm.str();
eggyywarning(s);
}
// 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(inp != NULL);
if (*inp) {
inp->read(buffer, max_size);
result = inp->gcount();
if (line_number == 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
// normally, doesn't catch the first line.
int length = min(max_error_width, result);
strncpy(current_line, buffer, length);
current_line[length] = '\0';
line_number++;
col_number = 0;
// Truncate it at the newline.
char *end = strchr(current_line, '\n');
if (end != NULL) {
*end = '\0';
}
}
} else {
// End of file or I/O error.
result = 0;
}
Thread::consider_yield();
}
#undef YY_INPUT
#define YY_INPUT(buffer, result, max_size) input_chars(buffer, result, max_size)
// read_char reads and returns a single character, incrementing the
// 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();
if (c == '\n') {
line++;
col = 0;
} else {
col++;
}
return c;
}
// 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;
int c;
c = read_char(line, col);
while (c != '"' && c != EOF) {
result += c;
c = read_char(line, col);
}
if (c == EOF) {
eggyyerror("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;
int c, last_c;
last_c = '\0';
c = read_char(line, col);
while (c != EOF && !(last_c == '*' && c == '/')) {
if (last_c == '/' && c == '*') {
ostringstream errmsg;
errmsg << "This comment contains a nested /* symbol at line "
<< line << ", column " << col-1 << "--possibly unclosed?"
<< ends;
eggyywarning(errmsg);
}
last_c = c;
c = read_char(line, col);
}
if (c == EOF) {
eggyyerror("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;
}
%}
HEX 0x[0-9a-fA-F]*
BINARY 0b[01]*
NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
%%
%{
if (initial_token != 0) {
int t = initial_token;
initial_token = 0;
return t;
}
%}
\n.* {
// 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;
// Return the whole line to the lexer, except the newline character,
// which we eat.
yyless(1);
}
[ \t\r] {
// Eat whitespace.
accept();
}
"//".* {
// Eat C++-style comments.
accept();
}
"/*" {
// Eat C-style comments.
accept();
eat_c_comment();
}
[{}] {
// Send curly braces as themselves.
accept();
return eggyytext[0];
}
"<ANIMPRELOAD>" {
accept();
return ANIMPRELOAD;
}
"<BEZIERCURVE>" {
accept();
return BEZIERCURVE;
}
"<BFACE>" {
accept();
return BFACE;
}
"<BILLBOARD>" {
accept();
return BILLBOARD;
}
"<BILLBOARDCENTER>" {
accept();
return BILLBOARDCENTER;
}
"<BINORMAL>" {
accept();
return BINORMAL;
}
"<BUNDLE>" {
accept();
return BUNDLE;
}
"<CHAR*>" {
accept();
return SCALAR;
}
"<CLOSED>" {
accept();
return CLOSED;
}
"<COLLIDE>" {
accept();
return COLLIDE;
}
"<COMMENT>" {
accept();
return COMMENT;
}
"<COMPONENT>" {
accept();
return COMPONENT;
}
"<COORDINATESYSTEM>" {
accept();
return COORDSYSTEM;
}
"<CV>" {
accept();
return CV;
}
"<DART>" {
accept();
return DART;
}
"<DNORMAL>" {
accept();
return DNORMAL;
}
"<DRGBA>" {
accept();
return DRGBA;
}
"<DUV>" {
accept();
return DUV;
}
"<DXYZ>" {
accept();
return DXYZ;
}
"<DCS>" {
accept();
return DCS;
}
"<DISTANCE>" {
accept();
return DISTANCE;
}
"<DTREF>" {
accept();
return DTREF;
}
"<DYNAMICVERTEXPOOL>" {
accept();
return DYNAMICVERTEXPOOL;
}
"<FILE>" {
accept();
return EXTERNAL_FILE;
}
"<GROUP>" {
accept();
return GROUP;
}
"<DEFAULTPOSE>" {
accept();
return DEFAULTPOSE;
}
"<JOINT>" {
accept();
return JOINT;
}
"<KNOTS>" {
accept();
return KNOTS;
}
"<INCLUDE>" {
accept();
return INCLUDE;
}
"<INSTANCE>" {
accept();
return INSTANCE;
}
"<LINE>" {
accept();
return LINE;
}
"<LOOP>" {
accept();
return LOOP;
}
"<MATERIAL>" {
accept();
return MATERIAL;
}
"<MATRIX3>" {
accept();
return MATRIX3;
}
"<MATRIX4>" {
accept();
return MATRIX4;
}
"<MODEL>" {
accept();
return MODEL;
}
"<MREF>" {
accept();
return MREF;
}
"<NORMAL>" {
accept();
return NORMAL;
}
"<NURBSCURVE>" {
accept();
return NURBSCURVE;
}
"<NURBSSURFACE>" {
accept();
return NURBSSURFACE;
}
"<OBJECTTYPE>" {
accept();
return OBJECTTYPE;
}
"<ORDER>" {
accept();
return ORDER;
}
"<OUTTANGENT>" {
accept();
return OUTTANGENT;
}
"<POINTLIGHT>" {
accept();
return POINTLIGHT;
}
"<POLYGON>" {
accept();
return POLYGON;
}
"<REF>" {
accept();
return REF;
}
"<RGBA>" {
accept();
return RGBA;
}
"<ROTATE>" {
accept();
return ROTATE;
}
"<ROTX>" {
accept();
return ROTX;
}
"<ROTY>" {
accept();
return ROTY;
}
"<ROTZ>" {
accept();
return ROTZ;
}
"<S$ANIM>" {
accept();
return SANIM;
}
"<SCALAR>" {
accept();
return SCALAR;
}
"<SCALE>" {
accept();
return SCALE;
}
"<SEQUENCE>" {
accept();
return SEQUENCE;
}
"<SHADING>" {
accept();
return SHADING;
}
"<SWITCH>" {
accept();
return SWITCH;
}
"<SWITCHCONDITION>" {
accept();
return SWITCHCONDITION;
}
"<TABLE>" {
accept();
return TABLE;
}
"<V>" {
accept();
return TABLE_V;
}
"<TAG>" {
accept();
return TAG;
}
"<TANGENT>" {
accept();
return TANGENT;
}
"<TEXLIST>" {
accept();
return TEXLIST;
}
"<TEXTURE>" {
accept();
return TEXTURE;
}
"<TLENGTHS>" {
accept();
return TLENGTHS;
}
"<TRANSFORM>" {
accept();
return TRANSFORM;
}
"<TRANSLATE>" {
accept();
return TRANSLATE;
}
"<TREF>" {
accept();
return TREF;
}
"<TRIANGLEFAN>" {
accept();
return TRIANGLEFAN;
}
"<TRIANGLESTRIP>" {
accept();
return TRIANGLESTRIP;
}
"<TRIM>" {
accept();
return TRIM;
}
"<TXT>" {
accept();
return TXT;
}
"<U-KNOTS>" {
accept();
return UKNOTS;
}
"<U_KNOTS>" {
accept();
return UKNOTS;
}
"<UV>" {
accept();
return UV;
}
"<V-KNOTS>" {
accept();
return VKNOTS;
}
"<V_KNOTS>" {
accept();
return VKNOTS;
}
"<VERTEX>" {
accept();
return VERTEX;
}
"<VERTEXANIM>" {
accept();
return VERTEXANIM;
}
"<VERTEXPOOL>" {
accept();
return VERTEXPOOL;
}
"<VERTEXREF>" {
accept();
return VERTEXREF;
}
"<XFM$ANIM>" {
accept();
return XFMANIM;
}
"<XFM$ANIM_S$>" {
accept();
return XFMSANIM;
}
{NUMERIC} {
// An integer or floating-point number.
accept();
eggyylval._number = patof(eggyytext);
eggyylval._string = yytext;
return EGG_NUMBER;
}
{HEX} {
// A hexadecimal integer number.
accept();
eggyylval._ulong = strtoul(yytext+2, NULL, 16);
eggyylval._string = yytext;
return EGG_ULONG;
}
{BINARY} {
// A binary integer number.
accept();
eggyylval._ulong = strtoul(yytext+2, NULL, 2);
eggyylval._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, NULL, 0);
eggyylval._string = yytext;
return EGG_NUMBER;
}
"inf" {
// infinity. As above.
accept();
eggyylval._number = HUGE_VAL;
eggyylval._string = yytext;
return EGG_NUMBER;
}
"-inf" {
// minus infinity. As above.
accept();
eggyylval._number = -HUGE_VAL;
eggyylval._string = yytext;
return EGG_NUMBER;
}
"1.#inf" {
// infinity, on Win32. As above.
accept();
eggyylval._number = HUGE_VAL;
eggyylval._string = yytext;
return EGG_NUMBER;
}
"-1.#inf" {
// minus infinity, on Win32. As above.
accept();
eggyylval._number = -HUGE_VAL;
eggyylval._string = yytext;
return EGG_NUMBER;
}
["] {
// Quoted string.
accept();
eggyylval._string = scan_quoted_string();
return EGG_STRING;
}
[^ \t\n\r{}"]+ {
// Unquoted string.
accept();
eggyylval._string = yytext;
return EGG_STRING;
}