Pages: [1] 2
  Print  
Author Topic: variable_* Functions  (Read 2443 times)
Offline (Male) RetroX
Posted on: December 05, 2010, 03:29:29 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
This is one thing that I stumbled upon today.  Like execute_string, these functions will be a bit tricky.  And I happened to use one in a GM project, and they don't work in ENIGMA currently.

Code: [Select]
variable_global_exists(name)
variable_global_get(name)
variable_global_array_get(name,ind)
variable_global_array2_get(name,ind1,ind2)
variable_global_set(name,value)
variable_global_array_set(name,ind,value)
variable_global_array2_set(name,ind1,ind2,value)
variable_local_exists(name)
variable_local_get(name)
variable_local_array_get(name,ind)
variable_local_array2_get(name,ind1,ind2)
variable_local_set(name,value)
variable_local_array_set(name,ind,value)
variable_local_array2_set(name,ind1,ind2,value)

I'm not entirely sure how to go about doing these, but the best idea that I can think of is keeping an array of variable names from the parser and storing pointers during runtime.  It would really decrease speed, though, and I think that it would be best to make this kind of system enable/disable-able.  Nonetheless, these do happen to be relatively common functions that will have to be supported by ENIGMA.

Usually, code tends to be:

Code: [Select]
if (variable_global_exists('bob'))
{
  bob = global.bob;
}
which would cause a compile error in C++.

You also face the problem of:
Code: [Select]
bobvar = "bob"
if (variable_global_exists(bobvar))
{
  bob = global.bob;
}

Which would run into even more problems.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Unknown gender) TheExDeus
Reply #1 Posted on: December 05, 2010, 03:49:12 PM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
Yeah, I have used them too. There are always ways to not use them and make that particular piece of code another way. But it is still nice to use them, for example, in translations. You could have a file like so:
introduction="This is blah blah"
And in the game you could have something like:
variable_global_set("str_"+variable,string);
And then just use str_introduction anywhere where you want to use your string. Its better than to save them inside arrays or something because you can more easily get the correct string. Arrays and such of course would be faster.

edit: Also, my example works only if variable_global_set actually creates the variable as well. I haven't tested so I don't know. In GM I actually used execute_string() to do this. I used variable_ functions for other things, like setting correct values to checkboxes with names etc.
« Last Edit: December 05, 2010, 03:51:05 PM by HaRRiKiRi » Logged
Offline (Male) Josh @ Dreamland
Reply #2 Posted on: December 05, 2010, 10:03:03 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
There's no way to implement them... efficiently. Doing so requires two modifications. They're difficult to make, but only because it pains me to do so. Each variant needs a bool to indicate whether it's been assigned, then each operator needs overloaded to a hash table needs constructed in each instance for new variables added, and a table needs constructed for each object to reference hard-compiled variables.

Honestly, I hardly intend on doing it. But I'm sure someone will cry about it at some point and I'll implement it.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) freezway
Reply #3 Posted on: December 06, 2010, 08:36:31 PM

Member
Joined: Dec 2009
Posts: 220

View Profile
since enigma allows pointers the *_set_* ones are easy enough to work around. honestly you should really need these
Logged
if you drop a cat with buttered toast strapped to its back, which side lands down?
joshdreamland: our languages are based on the idea that it's going to end up FUBAR
/kick retep998
Offline (Male) Josh @ Dreamland
Reply #4 Posted on: December 06, 2010, 10:05:13 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
...
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) RetroX
Reply #5 Posted on: December 07, 2010, 07:23:19 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
it would be a massive map of pointers, which would be slow as hell
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Female) serprex
Reply #6 Posted on: December 13, 2010, 09:04:15 AM
Smooth ER
Developer
Joined: Apr 2008
Posts: 106

View Profile WWW
These are better replaced by string indices
Logged
Offline (Unknown gender) luiscubal
Reply #7 Posted on: December 13, 2010, 07:08:36 PM
Member
Joined: Jun 2009
Posts: 452

View Profile Email
Regarding global variables, I'm pretty sure some nasty executable file format-based hacks might work. However, only if the variable type is known ahead-of-time. In other words, if you declared a global int x and then accessed it as a var it would fail miserably.

I mean, LLVM does stuff like that.
Note that on Windows it could require declaring all globals with __declspec(dllexport).

All this without requiring massive maps of pointers.
For local variables, though, you guys would be totally screwed.
Logged
Offline (Male) RetroX
Reply #8 Posted on: December 13, 2010, 07:42:09 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Regarding global variables, I'm pretty sure some nasty executable file format-based hacks might work. However, only if the variable type is known ahead-of-time. In other words, if you declared a global int x and then accessed it as a var it would fail miserably.

I mean, LLVM does stuff like that.
Note that on Windows it could require declaring all globals with __declspec(dllexport).

All this without requiring massive maps of pointers.
For local variables, though, you guys would be totally screwed.
That would only work if the game was compiled as a shared library, and it wouldn't work with how ENIGMA's instances are organised.

You can't just access variables by symbol at runtime; it doesn't work that way.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Unknown gender) luiscubal
Reply #9 Posted on: December 14, 2010, 08:51:09 AM
Member
Joined: Jun 2009
Posts: 452

View Profile Email
@RetroX  I do not see how this would conflict with ENIGMA's instances.

Also, see http://llvm.org/docs/tutorial/LangImpl4.html#jit
Executables are basically shared libraries.

See also GetModuleHandle(NULL) and GetProcAddress (Windows-only, Linux has similar functions)

EDIT: Windows source-code:
Code: (C) [Select]
#include <stdio.h>
#include <windows.h>

typedef void (*func)(const char*);

extern "C" {
__declspec(dllexport) char* message = "HELLO WORLD!";

__declspec(dllexport) void display_message(const char* msg) {
        printf("Message: %s\n", msg);
}
}

int main() {
        HMODULE module = GetModuleHandle(NULL);
        char** msg = (char**) GetProcAddress(module, "message");
        func disp = (func) GetProcAddress(module, "display_message");

        disp(*msg);

        return 0;
}

This works fine as an executable, without compile-time tricks. Note that this is NOT a DLL.
This probably would also work on Linux with some minor changes(dlopen instead of GetModuleHandle?)
« Last Edit: December 14, 2010, 10:37:25 AM by luiscubal » Logged
Offline (Male) RetroX
Reply #10 Posted on: December 14, 2010, 06:07:18 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
@RetroX  I do not see how this would conflict with ENIGMA's instances.

Also, see http://llvm.org/docs/tutorial/LangImpl4.html#jit
Executables are basically shared libraries.

See also GetModuleHandle(NULL) and GetProcAddress (Windows-only, Linux has similar functions)

EDIT: Windows source-code:
Code: (C) [Select]
#include <stdio.h>
#include <windows.h>

typedef void (*func)(const char*);

extern "C" {
__declspec(dllexport) char* message = "HELLO WORLD!";

__declspec(dllexport) void display_message(const char* msg) {
        printf("Message: %s\n", msg);
}
}

int main() {
        HMODULE module = GetModuleHandle(NULL);
        char** msg = (char**) GetProcAddress(module, "message");
        func disp = (func) GetProcAddress(module, "display_message");

        disp(*msg);

        return 0;
}

This works fine as an executable, without compile-time tricks. Note that this is NOT a DLL.
This probably would also work on Linux with some minor changes(dlopen instead of GetModuleHandle?)
Yes, this works with globals.  It does not work with locals.

Also, a string map would probably be faster.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) Rusky
Reply #11 Posted on: December 15, 2010, 12:46:46 PM

Resident Troll
Joined: Feb 2008
Posts: 960
MSN Messenger - rpjohnst@gmail.com
View Profile WWW Email
GetProcAddress uses a string map constructed with the symbols declared __declspec(dllexport). It's the same thing but a string map gives you control over the implementation and is cross-platform.
Logged
Offline (Unknown gender) luiscubal
Reply #12 Posted on: December 15, 2010, 02:06:12 PM
Member
Joined: Jun 2009
Posts: 452

View Profile Email
I'm just saying that the OS already provides the functionality built-in.
variable_get_global/variable_set_global would probably be 10 lines of code long(and that's counting the platform differences!) and the parser would probably need one line changed for Windows compatibility.
Efficient or not, it's simple to implement, and it does not feel like a hack.

Also, regarding whether the string map would be faster. This kind of thing is built-in by the OS, so I'm guessing it's pretty optimized by now. That is, unless it uses kernel system calls via interrupts or something like that. But even if the string map is faster, would it even be worth the trouble considering how simple this solution is?
Logged
Offline (Male) RetroX
Reply #13 Posted on: December 15, 2010, 04:22:47 PM

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
GetProcAddress uses a string map constructed with the symbols declared __declspec(dllexport). It's the same thing but a string map gives you control over the implementation and is cross-platform.
I also wasn't thinking when I made that other post. :V

Yeah, you're right.  That makes more sense, now that I think about it.

The problem that I still see is that you're getting a symbol for a variable.  You're not getting its value; that value is stored in memory, and not the binary.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Unknown gender) luiscubal
Reply #14 Posted on: December 15, 2010, 05:21:20 PM
Member
Joined: Jun 2009
Posts: 452

View Profile Email
I'm getting the POINTER to the variable.
If you are wondering, this is the behavior:
Code: (C) [Select]
int signal = 0;
...
printf("%d\n", signal); //Prints 0
*GetProcAddress(GetModuleHandle(NULL), "signal")) = 2;
printf("%d\n", signal); //Prints 2
Logged
Pages: [1] 2
  Print