Sign in to follow this  
Rain Dog


Recommended Posts

Hello, I have a question regarding AS. My goal is to retrieve all of the user variables from a script and display them in a treeview in my host application. I believe the extraction of the variables is going to be rather easy because of as's rich api, but I do have a programming question that perhaps someone here could assist me with. With an stl map it is possible to map a key with a value, such as mymap["MyVar: "] = MyVar; So I will know the data type of the script variable as a string, and I will be able to have simple maps of all of the basic types. How will i indirect a variable to the correct type so that its display is correct only know by string what data type it is? Would i use a macro, and 2 maps, one for the varname (eg "MyVar")and a void * (eg &MyVar), and the other with the varname (eg "MyVar") and the data type (eg "double") and then use a macro to cast the void* ? And if the macro would be best, what is the syntax exactly to make a string literal into not a string?

Share this post

Link to post
Share on other sites
I've read your post 3 times and I'm still not entirely sure what you're asking, but I'll give it a try.

You can use pretty much anything as a key for a map, as long as it has an overloaded < (or >, not sure) operator.

I'm assuming that you want to store different types of variables in the same map, correct? If you want a single indexing mechanism, I would recommend doing this:

enum Types {


struct Var {
char type;
union {
void* ptr; //for all pointers
double dbl; //for all floating points
signed long lng; //for all numeric values, you can also use a 64bit int type here

std::map<const char*, Var> mymap;
int var = 5;
Var newvar;
newvar.type = VT_INT32;
newvar.lng = var;
mymap["var"] = newvar;

This allows you to retrieve the type later on (add all your pointer types to the enum if you want to). You can change the char type to a char* with a string literal, too.

I hope this way helpful in some way.

Share this post

Link to post
Share on other sites
I have to wonder if Gyrbo ever really grasped the question.

That's a workable solution, though you would deffinitly want to expand the 'var' type a bit - make it a bit more usable.

And index the map with std::string, not char*s.

What's all this stuff with Macros? Don't use macros unless you have to - and you don't!

Share this post

Link to post
Share on other sites
I think I understand what you want to do, but not 100% sure!

If all you do is want to show the variable to the user, then do you need to convert it? (e.g. if the variable is a double, and you already have the string representation of that, do you need to convert that string to a double as all your going to do is display it to the user?)

If you don't need to convert it, then it's really simple:

class ASVariable
ASVariable(std::string type, std::string value):_type(type), _value(value) {}
~ASVariable() {}

std::string GetType() const {return _type;}
std::string GetValue() const {return _value;}
std::string _type, _value;

std::map<std::string, ASVariable> myVariables;

Now, if you do need to actually make the strings into the relevant variables (if you want to be able to edit the value in your application for example), then you may want to consider boost any, or at least look how that manages to solve the problem of storing any type in a safe way (e.g. not MACROS and no void *!)

Hope that helps!

Share this post

Link to post
Share on other sites
Original post by Rain Dog
What my question is though, is to display it to the end user, i will need the data type otherwise i will not be able to display the variable to the user in the correct format, ie: do not want to display an 8bit float as an 8 bit int, there would be bad results.

Perhaps you misunderstood me, you would do the formating when you retrieve the variables value. So, when you find out that the variable is a double, you would then apply any formating and store value as a string. There is no need to later on find out its type, convert it and then format it to a string.

This way, continuing from my old example, you could do:

void PrintVariables()
std::map<std::string, ASVariable>::iterator it;
for (it = myVariables.begin(); it != myVariables.end(); ++it)
std::cout << "Name:\t" << it->first();
std::cout << "\tType:\t" << it->second().GetType();
std::cout << "\tValue:\t" << it->second().GetValue() << std::endl;

Share this post

Link to post
Share on other sites
That's a good idea w/ the class representation. I think i'll do something like that.

What i want however is the most efficient method possible. I'm possibly going to be accessing the data many times a second so as to keep an accurate display of the variables' value for the end user.

So i guess what it would mean is that i would have a collection of these objects and just be able to call a tostring like method on them.

What i estimate still to be the toughest part is the actual extraction of the pointer to the variable. Im going to have to use

virtual const char *GetGlobalVarDeclaration(int gvarID, int *length = 0) = 0;

To get the declaration, which will give me the name and the type. From that I will have to parse the name of the variable and then the type. I will have the type of the variable in string representation, My first idea was to store that with the variable name in one map, and then a void* and the variable name in another map. That way, with the variable name i can track both the type, the name and lastly a pointer to the variable so that I can display that information to the user dynamically.

Share this post

Link to post
Share on other sites
If you're trying to display all Global Variables that are basic types and display them to users then you should use GetGlobalVarDeclaration that will give you the name and the type of the variable. Then using GetGlobalVarPointer you get a pointer to that variable.
Now you have to print the values, so you'de better have a class as other said before that encapsulate this print function.
But you've got to parse the type, and that where AS came to recue.

You can use this kind of code :

#include "as_builder.h"
#include "as_tokendef.h"


asCDataType type;
asCString name;

// First, make an asCBuilder
asCBuilder bld((asCScriptEngine *)GetEngine(), 0);
// Then ask it to parse 'declaration' ex: "int myIntValue;"
if(bld.VerifyProperty(0, declaration, name, type) == asSUCCESS) {
// Here the name should be "muIntValue"
// and type should contain the information about what's being pointer by the GetGlobalVarPointer returned value
// if type.pointerLevel == true then the variable is a pointer
// if type.extendedType == NULL then the var is a basic type so you can use type.tokenType to print the variable the right way
// if type.extendedType != NULL then this is one of your added datatype

Hope it gives you some more clues to find a way in doing your programm !


Oops, foget to mention that the code is valid for 1.9.2a and haven't been tested on newer version.

Share this post

Link to post
Share on other sites
The name of the variable can be gotten with GetGlobalVarName().

Determining the type of the variable can easily be done with a simple parser. But if you wish to use the code that AngelScript already has, then you might as well change the script engine to return its internal datastructure directly. For example:

const asCDataType *asCScriptEngine::GetGlobalVarType(int gvarID)
asCModule *mod = GetModule(gvarID);
if( mod == 0 ) return 0;

int id = gvarID & 0xFFFF;
if( id > mod->scriptGlobals.GetLength() )
return 0;

asCProperty *prop = mod->scriptGlobals[id];
return &prop->type;

Where asCDataType has the following class interface:

class asCDataType
... // irrelevant stuff

asCString Format() const;

eTokenType tokenType;
asCObjectType *extendedType;
int pointerLevel;
int arrayDimensions;
bool isReference;
bool isReadOnly;

tokenType will be either of ttVoid, ttInt, ttInt8, ttInt16, ttUInt, ttUInt8, ttUInt16, ttBits, ttBits8, ttBits16, ttFloat, ttDouble, ttBool, or ttIdentifier (in case of a registered object). If tokenType is ttIdentifier then extendedType will give the name of the registered object type. These constants are found in as_tokendef.h.

Although making these changes to AngelScript is an easy thing to do, you'll also have to weigh the costs of future upgrades of AngelScript. You'll have to make the same changes everytime, and you also have the risk that AngelScript changes it's internal representation.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this