1050 lines
24 KiB
C++
1050 lines
24 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "TypeInfoGen.h"
|
|
|
|
#define TYPE_INFO_GEN_VERSION "1.0"
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::idTypeInfoGen
|
|
================
|
|
*/
|
|
idTypeInfoGen::idTypeInfoGen( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::~idTypeInfoGen
|
|
================
|
|
*/
|
|
idTypeInfoGen::~idTypeInfoGen( void ) {
|
|
constants.DeleteContents( true );
|
|
enums.DeleteContents( true );
|
|
classes.DeleteContents( true );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::GetInheritance
|
|
================
|
|
*/
|
|
int idTypeInfoGen::GetInheritance( const char *typeName ) const {
|
|
int i;
|
|
|
|
for ( i = 0; i < classes.Num(); i++ ) {
|
|
if ( classes[i]->typeName.Cmp( typeName ) == 0 ) {
|
|
if ( classes[i]->superType[0] != '\0' ) {
|
|
return 1 + GetInheritance( classes[i]->superType );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::EvaluateIntegerString
|
|
================
|
|
*/
|
|
int idTypeInfoGen::EvaluateIntegerString( const idStr &string ) {
|
|
idParser src;
|
|
idStr evalString;
|
|
|
|
if ( string.Find( "::" ) != -1 ) {
|
|
return 0;
|
|
}
|
|
evalString = "$evalint(" + string + ")";
|
|
src.LoadMemory( evalString, evalString.Length(), "eval integer" );
|
|
return src.ParseInt();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::EvaluateFloatString
|
|
================
|
|
*/
|
|
float idTypeInfoGen::EvaluateFloatString( const idStr &string ) {
|
|
idParser src;
|
|
idStr evalString;
|
|
|
|
if ( string.Find( "::" ) != -1 ) {
|
|
return 0.0f;
|
|
}
|
|
evalString = "$evalfloat(" + string + ")";
|
|
src.LoadMemory( evalString, evalString.Length(), "eval float" );
|
|
return src.ParseFloat();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::FindConstant
|
|
================
|
|
*/
|
|
idConstantInfo *idTypeInfoGen::FindConstant( const char *name ) {
|
|
int i;
|
|
|
|
for ( i = 0; i < constants.Num(); i++ ) {
|
|
if ( constants[i]->name.Cmp( name ) == 0 ) {
|
|
return constants[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::GetIntegerConstant
|
|
================
|
|
*/
|
|
int idTypeInfoGen::GetIntegerConstant( const char *scope, const char *name, idParser &src ) {
|
|
idConstantInfo *constant = FindConstant( idStr( scope ) + name );
|
|
if ( constant == NULL ) {
|
|
constant = FindConstant( name );
|
|
}
|
|
if ( constant ) {
|
|
return EvaluateIntegerString( constant->value );
|
|
}
|
|
src.Warning( "unknown value '%s' in constant expression", name );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::GetFloatConstant
|
|
================
|
|
*/
|
|
float idTypeInfoGen::GetFloatConstant( const char *scope, const char *name, idParser &src ) {
|
|
idConstantInfo *constant = FindConstant( idStr( scope ) + name );
|
|
if ( constant == NULL ) {
|
|
constant = FindConstant( name );
|
|
}
|
|
if ( constant ) {
|
|
return EvaluateFloatString( constant->value );
|
|
}
|
|
src.Warning( "unknown value '%s' in constant expression", name );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::ParseArraySize
|
|
================
|
|
*/
|
|
int idTypeInfoGen::ParseArraySize( const char *scope, idParser &src ) {
|
|
idToken token;
|
|
idStr sizeString, constantString;
|
|
int size, totalSize;
|
|
|
|
if ( !src.CheckTokenString( "[" ) ) {
|
|
return 0;
|
|
}
|
|
|
|
totalSize = 1;
|
|
sizeString = "";
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "]" ) {
|
|
if ( sizeString.Length() ) {
|
|
size = EvaluateIntegerString( sizeString );
|
|
if ( size ) {
|
|
totalSize *= size;
|
|
}
|
|
sizeString = "";
|
|
}
|
|
if ( !src.CheckTokenString( "[" ) ) {
|
|
break;
|
|
}
|
|
} else if ( token.type == TT_NAME ) {
|
|
constantString = token;
|
|
while( src.CheckTokenString( "::" ) ) {
|
|
src.ExpectTokenType( TT_NAME, 0, &token );
|
|
constantString += "::" + token;
|
|
}
|
|
sizeString += va( "%d", GetIntegerConstant( scope, constantString, src ) );
|
|
} else {
|
|
sizeString += token;
|
|
}
|
|
}
|
|
|
|
return totalSize;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::ParseConstantValue
|
|
================
|
|
*/
|
|
void idTypeInfoGen::ParseConstantValue( const char *scope, idParser &src, idStr &value ) {
|
|
idToken token;
|
|
idStr constantString;
|
|
|
|
int indent = 0;
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "(" ) {
|
|
indent++;
|
|
} else if ( token == ")" ) {
|
|
indent--;
|
|
} else if ( indent == 0 && ( token == ";" || token == "," || token == "}" ) ) {
|
|
src.UnreadToken( &token );
|
|
break;
|
|
} else if ( token.type == TT_NAME ) {
|
|
constantString = token;
|
|
while( src.CheckTokenString( "::" ) ) {
|
|
src.ExpectTokenType( TT_NAME, 0, &token );
|
|
constantString += "::" + token;
|
|
}
|
|
value += va( "%d", GetIntegerConstant( scope, constantString, src ) );
|
|
continue;
|
|
}
|
|
value += token;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::ParseEnumType
|
|
================
|
|
*/
|
|
idEnumTypeInfo *idTypeInfoGen::ParseEnumType( const char *scope, bool isTemplate, bool typeDef, idParser &src ) {
|
|
int value;
|
|
idToken token;
|
|
idEnumTypeInfo *typeInfo;
|
|
idEnumValueInfo enumValue;
|
|
idStr valueString;
|
|
|
|
typeInfo = new idEnumTypeInfo;
|
|
typeInfo->scope = scope;
|
|
typeInfo->isTemplate = isTemplate;
|
|
|
|
if ( src.CheckTokenType( TT_NAME, 0, &token ) ) {
|
|
typeInfo->typeName = token;
|
|
typeInfo->unnamed = false;
|
|
} else {
|
|
sprintf( typeInfo->typeName, "enum_%d", enums.Num() );
|
|
typeInfo->unnamed = true;
|
|
}
|
|
|
|
if ( !src.CheckTokenString( "{" ) ) {
|
|
src.UnreadToken( &token );
|
|
delete typeInfo;
|
|
return NULL;
|
|
}
|
|
|
|
value = -1;
|
|
while( src.ExpectTokenType( TT_NAME, 0, &token ) ) {
|
|
|
|
enumValue.name = token;
|
|
|
|
if ( src.CheckTokenString( "=" ) ) {
|
|
idStr valueString;
|
|
ParseConstantValue( scope, src, valueString );
|
|
if ( valueString.Length() ) {
|
|
value = EvaluateIntegerString( valueString );
|
|
}
|
|
} else {
|
|
value++;
|
|
}
|
|
|
|
enumValue.value = value;
|
|
typeInfo->values.Append( enumValue );
|
|
|
|
// add a constant for the enum value
|
|
idConstantInfo *constantInfo = new idConstantInfo;
|
|
constantInfo->name = scope + enumValue.name;
|
|
constantInfo->type = "int";
|
|
constantInfo->value = va( "%d", value );
|
|
constants.Append( constantInfo );
|
|
|
|
src.CheckTokenString( "," );
|
|
|
|
if ( src.CheckTokenString( "}" ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( typeDef ) {
|
|
if ( src.CheckTokenType( TT_NAME, 0, &token ) ) {
|
|
typeInfo->typeName = token;
|
|
typeInfo->unnamed = false;
|
|
}
|
|
src.ExpectTokenString( ";" );
|
|
}
|
|
|
|
//common->Printf( "enum %s%s\n", typeInfo->scope.c_str(), typeInfo->typeName.c_str() );
|
|
|
|
return typeInfo;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::ParseClassType
|
|
================
|
|
*/
|
|
idClassTypeInfo *idTypeInfoGen::ParseClassType( const char *scope, const char *templateArgs, bool isTemplate, bool typeDef, idParser &src ) {
|
|
idToken token;
|
|
idClassTypeInfo *typeInfo;
|
|
|
|
typeInfo = new idClassTypeInfo;
|
|
typeInfo->scope = scope;
|
|
typeInfo->isTemplate = isTemplate;
|
|
|
|
if ( src.CheckTokenType( TT_NAME, 0, &token ) ) {
|
|
typeInfo->typeName = token + templateArgs;
|
|
typeInfo->unnamed = false;
|
|
} else {
|
|
sprintf( typeInfo->typeName, "class_%d%s", classes.Num(), templateArgs );
|
|
typeInfo->unnamed = true;
|
|
}
|
|
|
|
if ( src.CheckTokenString( ":" ) ) {
|
|
if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) {
|
|
delete typeInfo;
|
|
return NULL;
|
|
}
|
|
while( token == "public" ||
|
|
token == "protected" ||
|
|
token == "private" ) {
|
|
|
|
if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) {
|
|
delete typeInfo;
|
|
return NULL;
|
|
}
|
|
|
|
typeInfo->superType = token;
|
|
|
|
// read template arguments
|
|
if ( src.CheckTokenString( "<" ) ) {
|
|
|
|
int indent = 1;
|
|
typeInfo->superType += "< ";
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "<" ) {
|
|
indent++;
|
|
} else if ( token == ">" ) {
|
|
indent--;
|
|
if ( indent == 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
typeInfo->superType += token + " ";
|
|
}
|
|
typeInfo->superType += ">";
|
|
}
|
|
|
|
// check for multiple inheritance
|
|
if ( !src.CheckTokenString( "," ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) {
|
|
delete typeInfo;
|
|
return NULL;
|
|
}
|
|
|
|
src.Warning( "multiple inheritance not supported for '%s%s'", typeInfo->scope.c_str(), typeInfo->typeName.c_str() );
|
|
}
|
|
}
|
|
|
|
if ( !src.CheckTokenString( "{" ) ) {
|
|
src.UnreadToken( &token );
|
|
delete typeInfo;
|
|
return NULL;
|
|
}
|
|
|
|
ParseScope( typeInfo->scope + typeInfo->typeName + "::", typeInfo->isTemplate, src, typeInfo );
|
|
|
|
if ( typeDef ) {
|
|
if ( src.CheckTokenType( TT_NAME, 0, &token ) ) {
|
|
typeInfo->typeName = token + templateArgs;
|
|
typeInfo->unnamed = false;
|
|
}
|
|
src.ExpectTokenString( ";" );
|
|
}
|
|
|
|
//common->Printf( "class %s%s : %s\n", typeInfo->scope.c_str(), typeInfo->typeName.c_str(), typeInfo->superType.c_str() );
|
|
|
|
return typeInfo;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::ParseScope
|
|
================
|
|
*/
|
|
void idTypeInfoGen::ParseScope( const char *scope, bool isTemplate, idParser &src, idClassTypeInfo *typeInfo ) {
|
|
int indent;
|
|
idToken token;
|
|
idClassTypeInfo *classInfo;
|
|
idEnumTypeInfo *enumInfo;
|
|
idStr varType;
|
|
bool isConst = false;
|
|
bool isStatic = false;
|
|
|
|
indent = 1;
|
|
while( indent ) {
|
|
if ( !src.ReadToken( &token ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( token == "{" ) {
|
|
|
|
do {
|
|
if ( token == "{" ) {
|
|
indent++;
|
|
} else if ( token == "}" ) {
|
|
indent--;
|
|
}
|
|
varType += token + " ";
|
|
} while( indent > 1 && src.ReadToken( &token ) );
|
|
|
|
} else if ( token == "}" ) {
|
|
|
|
assert( indent == 1 );
|
|
indent--;
|
|
|
|
} else if ( token == "<" ) {
|
|
|
|
do {
|
|
if ( token == "<" ) {
|
|
indent++;
|
|
} else if ( token == ">" ) {
|
|
indent--;
|
|
}
|
|
varType += token + " ";
|
|
} while( indent > 1 && src.ReadToken( &token ) );
|
|
|
|
} else if ( token == ";" ) {
|
|
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( token == "public" || token == "protected" || token == "private" ) {
|
|
|
|
if ( !src.ExpectTokenString( ":" ) ) {
|
|
break;
|
|
}
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( token == "friend" ) {
|
|
|
|
// skip friend classes/methods
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "{" ) {
|
|
indent++;
|
|
} else if ( token == "}" ) {
|
|
indent--;
|
|
if ( indent == 1 ) {
|
|
break;
|
|
}
|
|
} else if ( token == ";" && indent == 1 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( token == "template" ) {
|
|
|
|
varType = "";
|
|
|
|
if ( src.CheckTokenString( "<" ) ) {
|
|
|
|
int indent = 1;
|
|
varType += "< ";
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "<" ) {
|
|
indent++;
|
|
} else if ( token == ">" ) {
|
|
indent--;
|
|
if ( indent == 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
varType += token + " ";
|
|
}
|
|
varType += ">";
|
|
}
|
|
|
|
if ( src.CheckTokenString( "class" ) ) {
|
|
|
|
// parse template class
|
|
classInfo = ParseClassType( scope, varType, true, false, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else {
|
|
|
|
// skip template methods
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "{" ) {
|
|
indent++;
|
|
} else if ( token == "}" ) {
|
|
indent--;
|
|
if ( indent == 1 ) {
|
|
break;
|
|
}
|
|
} else if ( token == ";" && indent == 1 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( token == "namespace" ) {
|
|
|
|
// parse namespace
|
|
classInfo = ParseClassType( scope, "", isTemplate, false, src );
|
|
delete classInfo;
|
|
|
|
} else if ( token == "class" ) {
|
|
|
|
// parse class
|
|
classInfo = ParseClassType( scope, "", isTemplate, false, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else if ( token == "struct" ) {
|
|
|
|
// parse struct
|
|
classInfo = ParseClassType( scope, "", isTemplate, false, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
varType = classInfo->scope + classInfo->typeName;
|
|
}
|
|
|
|
} else if ( token == "union" ) {
|
|
|
|
// parse union
|
|
classInfo = ParseClassType( scope, "", isTemplate, false, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else if ( token == "enum" ) {
|
|
|
|
// parse enum
|
|
enumInfo = ParseEnumType( scope, isTemplate, false, src );
|
|
if ( enumInfo ) {
|
|
enums.Append( enumInfo );
|
|
varType = enumInfo->scope + enumInfo->typeName;
|
|
}
|
|
|
|
} else if ( token == "typedef" ) {
|
|
|
|
if ( token == "class" ) {
|
|
|
|
// parse typedef class
|
|
classInfo = ParseClassType( scope, "", isTemplate, true, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else if ( src.CheckTokenString( "struct" ) ) {
|
|
|
|
// parse typedef struct
|
|
classInfo = ParseClassType( scope, "", isTemplate, true, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else if ( src.CheckTokenString( "union" ) ) {
|
|
|
|
// parse typedef union
|
|
classInfo = ParseClassType( scope, "", isTemplate, true, src );
|
|
if ( classInfo ) {
|
|
classes.Append( classInfo );
|
|
}
|
|
|
|
} else if ( src.CheckTokenString( "enum" ) ) {
|
|
|
|
// parse typedef enum
|
|
enumInfo = ParseEnumType( scope, isTemplate, true, src );
|
|
if ( enumInfo ) {
|
|
enums.Append( enumInfo );
|
|
}
|
|
|
|
} else {
|
|
|
|
// skip other typedefs
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "{" ) {
|
|
indent++;
|
|
} else if ( token == "}" ) {
|
|
indent--;
|
|
} else if ( token == ";" && indent == 1 ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( token == "const" ) {
|
|
|
|
varType += token + " ";
|
|
isConst = true;
|
|
|
|
} else if ( token == "static" ) {
|
|
|
|
varType += token + " ";
|
|
isStatic = true;
|
|
|
|
} else if ( token.type == TT_NAME ) {
|
|
|
|
assert( indent == 1 );
|
|
|
|
// if this is a class operator
|
|
if ( token == "operator" ) {
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "(" ) {
|
|
src.UnreadToken( &token );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if this is a class method
|
|
if ( src.CheckTokenString( "(" ) ) {
|
|
|
|
indent++;
|
|
while( indent > 1 && src.ReadToken( &token ) ) {
|
|
if ( token == "(" ) {
|
|
indent++;
|
|
} else if ( token == ")" ) {
|
|
indent--;
|
|
}
|
|
}
|
|
|
|
if ( src.CheckTokenString( "(" ) ) {
|
|
indent++;
|
|
while( indent > 1 && src.ReadToken( &token ) ) {
|
|
if ( token == "(" ) {
|
|
indent++;
|
|
} else if ( token == ")" ) {
|
|
indent--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( src.CheckTokenString( "const" ) ) {
|
|
}
|
|
|
|
if ( src.CheckTokenString( "=" ) ) {
|
|
|
|
src.ExpectTokenString( "0" );
|
|
|
|
} else if ( src.CheckTokenString( "{" ) ) {
|
|
indent++;
|
|
while( indent > 1 && src.ReadToken( &token ) ) {
|
|
if ( token == "{" ) {
|
|
indent++;
|
|
} else if ( token == "}" ) {
|
|
indent--;
|
|
}
|
|
}
|
|
}
|
|
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
|
|
} else if ( ( isStatic || isConst ) && src.CheckTokenString( "=" ) ) {
|
|
|
|
// constant
|
|
idConstantInfo *constantInfo = new idConstantInfo;
|
|
constantInfo->name = scope + token;
|
|
constantInfo->type = varType;
|
|
constantInfo->type.StripTrailing( ' ' );
|
|
ParseConstantValue( scope, src, constantInfo->value );
|
|
constants.Append( constantInfo );
|
|
|
|
} else if ( isStatic ) {
|
|
|
|
// static class variable
|
|
varType += token + " ";
|
|
|
|
} else {
|
|
|
|
// check for class variables
|
|
while( 1 ) {
|
|
|
|
int arraySize = ParseArraySize( scope, src );
|
|
|
|
if ( arraySize ) {
|
|
idClassVariableInfo var;
|
|
|
|
var.name = token;
|
|
var.type = varType;
|
|
var.type.StripTrailing( ' ' );
|
|
var.type += va( "[%d]", arraySize );
|
|
var.bits = 0;
|
|
typeInfo->variables.Append( var );
|
|
if ( !src.CheckTokenString( "," ) ) {
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
break;
|
|
}
|
|
varType.StripTrailing( "* " );
|
|
|
|
} else {
|
|
|
|
int bits = 0;
|
|
|
|
if ( src.CheckTokenString( ":" ) ) {
|
|
idToken bitSize;
|
|
src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &bitSize );
|
|
bits = bitSize.GetIntValue();
|
|
}
|
|
|
|
if ( src.CheckTokenString( "," ) ) {
|
|
idClassVariableInfo var;
|
|
|
|
var.name = token;
|
|
var.type = varType;
|
|
var.type.StripTrailing( ' ' );
|
|
var.bits = bits;
|
|
typeInfo->variables.Append( var );
|
|
varType.StripTrailing( "* " );
|
|
|
|
} else if ( src.CheckTokenString( ";" ) ) {
|
|
idClassVariableInfo var;
|
|
|
|
var.name = token;
|
|
var.type = varType;
|
|
var.type.StripTrailing( ' ' );
|
|
var.bits = bits;
|
|
typeInfo->variables.Append( var );
|
|
varType = "";
|
|
isConst = false;
|
|
isStatic = false;
|
|
break;
|
|
|
|
} else {
|
|
|
|
varType += token + " ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
while( src.CheckTokenString( "*" ) ) {
|
|
varType += "* ";
|
|
}
|
|
|
|
if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
varType += token + " ";
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::AddDefine
|
|
================
|
|
*/
|
|
void idTypeInfoGen::AddDefine( const char *define ) {
|
|
defines.Append( define );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::CreateTypeInfo
|
|
================
|
|
*/
|
|
void idTypeInfoGen::CreateTypeInfo( const char *path ) {
|
|
int i, j, inheritance;
|
|
idStr fileName;
|
|
idFileList *files;
|
|
idParser src;
|
|
|
|
common->Printf( "Type Info Generator v"TYPE_INFO_GEN_VERSION" (c) 2004 id Software\n" );
|
|
common->Printf( "%s\n", path );
|
|
|
|
files = fileSystem->ListFilesTree( path, ".cpp" );
|
|
|
|
for ( i = 0; i < files->GetNumFiles(); i++ ) {
|
|
|
|
fileName = fileSystem->RelativePathToOSPath( files->GetFile( i ) );
|
|
|
|
common->Printf( "processing '%s' for type info...\n", fileName.c_str() );
|
|
|
|
if ( !src.LoadFile( fileName, true ) ) {
|
|
common->Warning( "couldn't load %s", fileName.c_str() );
|
|
continue;
|
|
}
|
|
|
|
src.SetFlags( LEXFL_NOBASEINCLUDES );
|
|
|
|
for ( j = 0; j < defines.Num(); j++ ) {
|
|
src.AddDefine( defines[j] );
|
|
}
|
|
|
|
idClassTypeInfo *typeInfo = new idClassTypeInfo;
|
|
ParseScope( "", false, src, typeInfo );
|
|
delete typeInfo;
|
|
|
|
src.FreeSource();
|
|
|
|
break;
|
|
}
|
|
|
|
fileSystem->FreeFileList( files );
|
|
|
|
numTemplates = 0;
|
|
for ( i = 0; i < classes.Num(); i++ ) {
|
|
if ( classes[i]->isTemplate ) {
|
|
numTemplates++;
|
|
}
|
|
}
|
|
|
|
maxInheritance = 0;
|
|
maxInheritanceClass = "";
|
|
for ( i = 0; i < classes.Num(); i++ ) {
|
|
inheritance = GetInheritance( classes[i]->typeName );
|
|
if ( inheritance > maxInheritance ) {
|
|
maxInheritance = inheritance;
|
|
maxInheritanceClass = classes[i]->typeName;
|
|
}
|
|
}
|
|
|
|
common->Printf( "%d constants\n", constants.Num() );
|
|
common->Printf( "%d enums\n", enums.Num() );
|
|
common->Printf( "%d classes/structs/unions\n", classes.Num() );
|
|
common->Printf( "%d templates\n", numTemplates );
|
|
common->Printf( "%d max inheritance level for '%s'\n", maxInheritance, maxInheritanceClass.c_str() );
|
|
}
|
|
|
|
/*
|
|
================
|
|
CleanName
|
|
================
|
|
*/
|
|
void CleanName( idStr &name ) {
|
|
name.Replace( "::", "_" );
|
|
name.Replace( " , ", "_" );
|
|
name.Replace( "< ", "_" );
|
|
name.Replace( " >", "_" );
|
|
name.Replace( " ", "_" );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeInfoGen::WriteTypeInfo
|
|
================
|
|
*/
|
|
void idTypeInfoGen::WriteTypeInfo( const char *fileName ) const {
|
|
int i, j;
|
|
idStr path, define;
|
|
idFile *file;
|
|
|
|
path = fileSystem->RelativePathToOSPath( fileName );
|
|
|
|
file = fileSystem->OpenExplicitFileWrite( path );
|
|
if ( !file ) {
|
|
common->Warning( "couldn't open %s", path.c_str() );
|
|
return;
|
|
}
|
|
|
|
common->Printf( "writing %s...\n", path.c_str() );
|
|
|
|
path.ExtractFileName( define );
|
|
define.Replace( ".", "_" );
|
|
define.ToUpper();
|
|
|
|
file->WriteFloatString(
|
|
"\n"
|
|
"#ifndef __%s__\n"
|
|
"#define __%s__\n"
|
|
"\n"
|
|
"/*\n"
|
|
"===================================================================================\n"
|
|
"\n"
|
|
"\tThis file has been generated with the Type Info Generator v"TYPE_INFO_GEN_VERSION" (c) 2004 id Software\n"
|
|
"\n"
|
|
"\t%d constants\n"
|
|
"\t%d enums\n"
|
|
"\t%d classes/structs/unions\n"
|
|
"\t%d templates\n"
|
|
"\t%d max inheritance level for '%s'\n"
|
|
"\n"
|
|
"===================================================================================\n"
|
|
"*/\n"
|
|
"\n", define.c_str(), define.c_str(), constants.Num(), enums.Num(), classes.Num(),
|
|
numTemplates, maxInheritance, maxInheritanceClass.c_str() );
|
|
|
|
file->WriteFloatString(
|
|
"typedef struct {\n"
|
|
"\t" "const char * name;\n"
|
|
"\t" "const char * type;\n"
|
|
"\t" "const char * value;\n"
|
|
"} constantInfo_t;\n"
|
|
"\n"
|
|
"typedef struct {\n"
|
|
"\t" "const char * name;\n"
|
|
"\t" "int value;\n"
|
|
"} enumValueInfo_t;\n"
|
|
"\n"
|
|
"typedef struct {\n"
|
|
"\t" "const char * typeName;\n"
|
|
"\t" "const enumValueInfo_t * values;\n"
|
|
"} enumTypeInfo_t;\n"
|
|
"\n"
|
|
"typedef struct {\n"
|
|
"\t" "const char * type;\n"
|
|
"\t" "const char * name;\n"
|
|
"\t" "int offset;\n"
|
|
"\t" "int size;\n"
|
|
"} classVariableInfo_t;\n"
|
|
"\n"
|
|
"typedef struct {\n"
|
|
"\t" "const char * typeName;\n"
|
|
"\t" "const char * superType;\n"
|
|
"\t" "int size;\n"
|
|
"\t" "const classVariableInfo_t * variables;\n"
|
|
"} classTypeInfo_t;\n"
|
|
"\n" );
|
|
|
|
// constants
|
|
file->WriteFloatString( "static constantInfo_t constantInfo[] = {\n" );
|
|
|
|
for ( i = 0; i < constants.Num(); i++ ) {
|
|
idConstantInfo *info = constants[i];
|
|
file->WriteFloatString( "\t{ \"%s\", \"%s\", \"%s\" },\n", info->type.c_str(), info->name.c_str(), info->value.c_str() );
|
|
}
|
|
|
|
file->WriteFloatString( "\t{ NULL, NULL, NULL }\n" );
|
|
file->WriteFloatString( "};\n\n" );
|
|
|
|
// enum values
|
|
for ( i = 0; i < enums.Num(); i++ ) {
|
|
idEnumTypeInfo *info = enums[i];
|
|
|
|
idStr typeInfoName = info->scope + info->typeName;
|
|
CleanName( typeInfoName );
|
|
|
|
file->WriteFloatString( "static enumValueInfo_t %s_typeInfo[] = {\n", typeInfoName.c_str() );
|
|
|
|
for ( j = 0; j < info->values.Num(); j++ ) {
|
|
if ( info->isTemplate ) {
|
|
file->WriteFloatString( "//" );
|
|
}
|
|
file->WriteFloatString( "\t{ \"%s\", %d },\n", info->values[j].name.c_str(), info->values[j].value );
|
|
}
|
|
|
|
file->WriteFloatString( "\t{ NULL, 0 }\n" );
|
|
file->WriteFloatString( "};\n\n" );
|
|
}
|
|
|
|
// enums
|
|
file->WriteFloatString( "static enumTypeInfo_t enumTypeInfo[] = {\n" );
|
|
|
|
for ( i = 0; i < enums.Num(); i++ ) {
|
|
idEnumTypeInfo *info = enums[i];
|
|
|
|
idStr typeName = info->scope + info->typeName;
|
|
idStr typeInfoName = typeName;
|
|
CleanName( typeInfoName );
|
|
|
|
if ( info->isTemplate ) {
|
|
file->WriteFloatString( "//" );
|
|
}
|
|
file->WriteFloatString( "\t{ \"%s\", %s_typeInfo },\n", typeName.c_str(), typeInfoName.c_str() );
|
|
}
|
|
|
|
file->WriteFloatString( "\t{ NULL, NULL }\n" );
|
|
file->WriteFloatString( "};\n\n" );
|
|
|
|
// class variables
|
|
for ( i = 0; i < classes.Num(); i++ ) {
|
|
idClassTypeInfo *info = classes[i];
|
|
|
|
idStr typeName = info->scope + info->typeName;
|
|
idStr typeInfoName = typeName;
|
|
CleanName( typeInfoName );
|
|
|
|
file->WriteFloatString( "static classVariableInfo_t %s_typeInfo[] = {\n", typeInfoName.c_str() );
|
|
|
|
for ( j = 0; j < info->variables.Num(); j++ ) {
|
|
const char *varName = info->variables[j].name.c_str();
|
|
const char *varType = info->variables[j].type.c_str();
|
|
|
|
if ( info->unnamed || info->isTemplate || info->variables[j].bits != 0 ) {
|
|
file->WriteFloatString( "//" );
|
|
}
|
|
file->WriteFloatString( "\t{ \"%s\", \"%s\", (int)(&((%s *)0)->%s), sizeof( ((%s *)0)->%s ) },\n",
|
|
varType, varName, typeName.c_str(), varName, typeName.c_str(), varName );
|
|
}
|
|
|
|
file->WriteFloatString( "\t{ NULL, 0 }\n" );
|
|
file->WriteFloatString( "};\n\n" );
|
|
}
|
|
|
|
// classes
|
|
file->WriteFloatString( "static classTypeInfo_t classTypeInfo[] = {\n" );
|
|
|
|
for ( i = 0; i < classes.Num(); i++ ) {
|
|
idClassTypeInfo *info = classes[i];
|
|
|
|
idStr typeName = info->scope + info->typeName;
|
|
idStr typeInfoName = typeName;
|
|
CleanName( typeInfoName );
|
|
|
|
if ( info->unnamed || info->isTemplate ) {
|
|
file->WriteFloatString( "//" );
|
|
}
|
|
file->WriteFloatString( "\t{ \"%s\", \"%s\", sizeof(%s), %s_typeInfo },\n",
|
|
typeName.c_str(), info->superType.c_str(), typeName.c_str(), typeInfoName.c_str() );
|
|
}
|
|
|
|
file->WriteFloatString( "\t{ NULL, NULL, 0, NULL }\n" );
|
|
file->WriteFloatString( "};\n\n" );
|
|
|
|
file->WriteFloatString( "#endif /* !__%s__ */\n", define.c_str() );
|
|
|
|
fileSystem->CloseFile( file );
|
|
}
|