• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Asset - Scripts [FREE] NSP 2 - A GML String Interpreter

Surgeon_

Symbian Curator
Released another hotfix (read the log if you're interested in details).

Also, I found out that if you switch over to the new variable getter/setter system (NSP_VAR_SYS enum in the NSP_initialize() script) you don't need to write global. in front of built-in variables anymore (like room_speed and the bunch).
 

Surgeon_

Symbian Curator
Version 2.6.5 Released
No changes to any functionality, BUT - NSP can now be imported into GMS2.0 projects and will work properly without any compatibility scripts! I can't say anything as to how future-proof it is because I don't know what changes to the GML itself are planned.
 

MeBoingus

Member
I don't know how this extension hasn't gotten more attention! Incredibly useful.

Any chance of nested statements in the future?
 

MeBoingus

Member
The parser is recursive so nested statements should work.
I run into this error:

Code:
SCRIPT: nsp_convert_to_list. ERROR: Types could not be determined.
 at gml_Script_NSP_notify (line 22) - show_error(argument[0], false);

When running this testing script:

Code:
a = 10;
b = 5;
if (a == 10) { if (b == 5) { show_message("TEST"); } }
 

Surgeon_

Symbian Curator
@Liam Jacobs Unless you've changed the NSP_initialize() script, the parser accepts only single quotes as string delimiters (that is the default). You can change it to double quotes, but it can't support both at the same time. Either way, I tried that code and it works fine with single quotes, but prints the same error with double quotes (as expected).

Some additional notes:
- You don't need curly braces for single statements (it would work as if (a == 10) if (b == 5) show_message('TEST'); ).
- Clear out any newline characters (CR, LF or CRLF depending on the system) from the string before parsing because they will not be ignored like spaces and will cause an error instead (they may work within string literals, however, though I've never tried this myself).
 
I had a quick question about NSP_free() and where I should be calling it. I thought calling it when a room ends might be a good spot but I'm getting an error so my understanding is incorrect of when I need to call this function.


Code:
############################################################################################
ERROR in
action number 1
of Other Event: Room End
for object obj_SharedTweener:

Data structure with index does not exist.
 at gml_Object_obj_SharedTweener_Other_5 (line 113) -     var _index = ds_list_size(_tweens);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_SharedTweener_Other_5 (line 113)
my use case for your parser is essentially storing a condition in a string b/c I have many children objects of a parent and each child could potentially have an alternate condition for when a statement is true


in the child object I am storing it via this variable

Code:
altDamageClearCondition = "image_index == 0";

then in the parent object I do a check

Code:
if (NSP_evaluate(altDamageClearCondition) || sprite_index == idleSprite)
{
    ds_list_clear(damageList);
}
 
Last edited:

Surgeon_

Symbian Curator
I had a quick question about NSP_free() and where I should be calling it. I thought calling it when a room ends might be a good spot but I'm getting an error so my understanding is incorrect of when I need to call this function.


Code:
############################################################################################
ERROR in
action number 1
of Other Event: Room End
for object obj_SharedTweener:

Data structure with index does not exist.
 at gml_Object_obj_SharedTweener_Other_5 (line 113) -     var _index = ds_list_size(_tweens);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_SharedTweener_Other_5 (line 113)
my use case for your parser is essentially storing a condition in a string b/c I have many children objects of a parent and each child could potentially have an alternate condition for when a statement is true


in the child object I am storing it via this variable

Code:
altDamageClearCondition = "image_index == 0";

then in the parent object I do a check

Code:
if (NSP_evaluate(altDamageClearCondition) || sprite_index == idleSprite)
{
    ds_list_clear(damageList);
}
The error message you've posted does not even mention NSP functions anywhere so maybe you've made an error in another place (It's saying that your list named "_tween" does not exist).

Also, you may want to consider using NSP_save() and NSP_evaluate_saved() functions in your child objects (don't forget to free the memory afterwards) because you're evaluating the same string over and over and there's no reason to go through the (very expensive) lexical analysis every time. And even so, having many of those child objects at once will send your performance down the drain because parsing is slooooow.

EDIT: To answer your question, you can call NSP_free() once you no longer plan to use any NSP functions (other than initialize, of course), so it can be at room end, game end, which ever.
 

MeBoingus

Member
Howdy Surgeon,

Is there any way to add the 'exit' statement into NSP as it stands? For example, running 'NSP_execute_saved' in a draw event will obviously cause lag, but would being able to 'exit' the draw event early (for example; if some conditions aren't met and the draw event doesn't need to continue) save on some resources?

Are there any tricks you know of (I figured I'd come to the source ;)) to speed up NSP in recursive events?
 

ZeDuval

Member
You can only ever exit the current context. If you use the exit keyword inside a script, you exit the script. If you want to exit a draw event, you must use the exit keyword directly inside that event. You could exit inside the draw event based on the return value of your NSP_execute_saved call.

Code:
if( NSP_execute_saved( "what", "ever" ) == -1337 ) exit;
Now you need to use

Code:
return -1337;
inside your NSP-interpreted-code. And I think Surgeon even built in the possibility to add custom keywords, or macros, which you could utilize to have something like

Code:
Exit
being interpreted as your

Code:
return -1337;
Hope that helps somewhat or can give you an idea.
 

MeBoingus

Member
You can only ever exit the current context. If you use the exit keyword inside a script, you exit the script. If you want to exit a draw event, you must use the exit keyword directly inside that event. You could exit inside the draw event based on the return value of your NSP_execute_saved call.

Code:
if( NSP_execute_saved( "what", "ever" ) == -1337 ) exit;
Now you need to use

Code:
return -1337;
inside your NSP-interpreted-code. And I think Surgeon even built in the possibility to add custom keywords, or macros, which you could utilize to have something like

Code:
Exit
being interpreted as your

Code:
return -1337;
Hope that helps somewhat or can give you an idea.
I'm only ever executing a single 'NSP_execute_saved' in the draw event, as it's one large script that I want to be able to exit out of. The goal isn't to exit out of the draw event, it's to exit out of the parsed script if some conditions are not met. I.E. If the draw event is only going to run if vk_space is pressed, I'd rather not look at the rest of the code if that condition is not met.

However, I thank you - as you have provided me with a useful piece of information :)! There's a good chance that using 'return' will have a similar effect to 'exiting' the parsed script early.

Will investigate and get back to you.
 

Surgeon_

Symbian Curator
I'm only ever executing a single 'NSP_execute_saved' in the draw event, as it's one large script that I want to be able to exit out of. The goal isn't to exit out of the draw event, it's to exit out of the parsed script if some conditions are not met. I.E. If the draw event is only going to run if vk_space is pressed, I'd rather not look at the rest of the code if that condition is not met.

However, I thank you - as you have provided me with a useful piece of information :)! There's a good chance that using 'return' will have a similar effect to 'exiting' the parsed script early.

Will investigate and get back to you.
Usually, the lexer would have to process the entire script no matter what logic it represents. However, since you are using the "saved" version of the functions (which save and reuse the result of the lexical analysis), this is not an issue for you. If I recall correctly, calling "return [value]" will prevent the rest of the script being interpreted, and will immediately return the value - which should be what you need.

As for speeding things up... I have no idea. I made this parser a long time ago, and even then, its primary purpose was testing games, so speed wasn't a big concern (not that I think you can squeeze out much more performance out of an ad-hoc interpreter running inside of a virtual machine...). I seem to remember there being some heavy duty scripting engines around the forums (based on Lua, I think). Those are much more complicated and probably cost some money, but could also result in much better performance if things get dire.
 
Top