|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Sun Mar 09, 2008 10:11 pm
%expand and local variables |
It looks like %expand isn't working when its argument is a local variable
#SAY %expand(@str) expands str variable
but
#SAY %expand($str) simply prints "$str" |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Mar 10, 2008 12:16 am |
I can confirm that behaviour, but it's possibly not a bug - %expand might've been intended for use with real variables only. If you post the script you're trying to use it in, we can suggest alternatives.
|
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Mon Mar 10, 2008 5:55 am |
I write a function that expands its parameter and returns the result (with some modifications)
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Mar 10, 2008 5:10 pm |
%expand is really left over from zMUD compatibility and shouldn't be needed in CMUD. Just use
#SAY $str
and that will work fine. In any case, %expand does not support local variables, sorry. If you are doing something fancy, you might want to use %eval instead. |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Mon Mar 10, 2008 6:25 pm |
I write a function that generates a string-command, later I may send it to the server.
#SAY won't help me.
I tried %eval, but I'm not sure how exactly it works. For example, it removes spaces between words (because it concatinates words?) which is an inconvenience.
Basically, I have a string that may have aliases and I want to produce a command ready to be sent. I expand aliases within the string with %alias and I need to expand variables too. Currently the only hack way I found: I copy the function argument into a global variable, then %expand it, so all variable/function references are exapanded within the string.
If it is not supposed to be done in CMUD, any suggestion how I can achieve my goal? |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Mar 10, 2008 6:40 pm |
If you are trying to execute a command stored in a string, then you should use #EXEC. If you show us more details on the script you are using, then one of the other Gurus might be able to help more.
|
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Mar 10, 2008 6:53 pm |
Just to clarify, "more details" means "the code you're using" as well as what you want to type to use it, what its purpose is, and what you intend it to do when you run it.
|
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Mon Mar 10, 2008 8:13 pm |
No script, sorry, it's complicated. In my specific case I've found a workaround with global variables.
But, in general, I need something that expands aliases and variables. I don't need to evaluate it and I don't need to execute it. I need just expansion.
I pass a string containing some command (as if I would type in the input window). It can be a real server command or an alias name with parameters.
As a result, I need to get a string containing a command exactly as it would be sent to the server (with aliases and variables expanded).
I don't want to %exec it because I may modifiy it if needed. I do some regex-replace on the resulting command. |
|
|
|
Fang Xianfu GURU
Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Mar 10, 2008 8:20 pm |
Have you seen some of the scripts in the Finished Scripts section? We're no strangers to complexity :P
Really, there's very little we can do to help you without seeing your code. It's probably something systemic in the way you're tackling the problem rather than changing a couple of lines. Without knowing what you're trying to do specifically - that is, whatever it is on your MUD you're trying to script, not "expand a string" - and how you're going about doing it, there's not much we can do. |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Mon Mar 10, 2008 9:26 pm |
Also, please note that, unlike #EXEC, the %exec function does NOT send stuff to your MUD. Instead, it evaluates the argument as a command, and RETURNS the commands that would have been sent (as a string list). E.g.
Code: |
#show %exec(%concat("#10",%char(32),"sneeze")) |
will print a stringlist with 10 'sneeze's in it, but nothing is sent to the MUD.
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Mon Mar 10, 2008 9:34 pm |
If you don't like %exec then you might like %alias better.
Finally you probably should be using functions for what you are doing in the first place.
Cmud recently gained the ability to use real functions with return statements.
The odds are that if you are constructing a string to be used elsewhere that you would be better off using a function. |
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Mon Mar 10, 2008 10:17 pm |
It looks like %exec doen't work correctly with local variables too.
I stumble in some wierdness and I'm not sure what are conditions for it, probably some mess with nested %exec and local variables.
Here is a short example:
#ALIAS test {ok}
#Function testfunc { #RETURN %exec(test) }
#ALIAS wtf
{
$s = "@testfunc()"
#SAY {"1:" %exec($s)}
#var globalS $s
#SAY {"2:" %exec(@globalS)}
}
I get output:
ok
1:
2: ok |
|
|
|
Vijilante SubAdmin
Joined: 18 Nov 2001 Posts: 5182
|
Posted: Tue Mar 11, 2008 1:04 am |
Whatever you are actually trying to do, you are making for too hard. An old saying is, "There are 6 ways to skin a cat." With CMud there are usually at least 12 ways to code something, and probably 3 of them are only known by a few really old scripters. Those 3 ways are generally next to useless, but we know them for the 1 time they will be useful. You are trying to use such a method at the wrong time.
One should rarely if ever need to use #EXEC, and even more rarely should one need to use %exec. They are pretty much only needed when one wants to work around a limitation in the parsing of a script. Those limitations are in place to protect most users from themselves, and very rarely need to be bypassed.
I would have to quote Fang:
Quote: |
Really, there's very little we can do to help you without seeing your code. It's probably something systemic in the way you're tackling the problem rather than changing a couple of lines. Without knowing what you're trying to do specifically - that is, whatever it is on your MUD you're trying to script, not "expand a string" - and how you're going about doing it, there's not much we can do. |
If you feel that your script contains something highly proprietary that you do not wish to publish, then I would suggest you contact one of the people that has replied so far with PM to see if they will work with you one on one. Both Arminas an JQuilici are long time respected contributors to this community; Fang and I are moderators in these forums. If you can't trust at least one of us then we have been doing something wrong. |
|
_________________ The only good questions are the ones we have never answered before.
Search the Forums |
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Tue Mar 11, 2008 1:37 am |
What were you expecting? The code seems to be working fine.
The first command actually executes the code (i.e. sends it as a command to the mud). You have say of the output but because there is none, nothing occurs when you do "1:".
When you print "2:" you actually seeing an artifact of the fact that functions were implemented as variables in zMUD and some of that is maintained for compatibility. The global variable evaluates the function call that you assign. Since it just evaluates to text thats essentially what the variable gets set to 'ok'. Note that it's displayed with the #SAY command (note it's in blue) versus being executed (i.e. sent to the mud) as in case "1:' which is why "1:" shows up as yellow. |
|
_________________ Asati di tempari! |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Tue Mar 11, 2008 2:53 am |
Tech wrote: |
What were you expecting? The code seems to be working fine.
The first command actually executes the code (i.e. sends it as a command to the mud). You have say of the output but because there is none, nothing occurs when you do "1:".
When you print "2:" you actually seeing an artifact of the fact that functions were implemented as variables in zMUD and some of that is maintained for compatibility. The global variable evaluates the function call that you assign. Since it just evaluates to text thats essentially what the variable gets set to 'ok'. Note that it's displayed with the #SAY command (note it's in blue) versus being executed (i.e. sent to the mud) as in case "1:' which is why "1:" shows up as yellow. |
I expect both SAYs work similarly.
The only difference between them is local vs. global variables.
I don't post my script because I don't want to go through the pain of cutting what is relevant and what is not in my set of macroses.
And I stated my goal clearly, I wish to write a function that fully expands its argument and returns the result as a string. I don't want to send it right away, execute it or put as #SAY argument. I just need a string with all variables and simple aliases expanded, because I want to do some post-processing later. Until now I played with %expand, %alias and temporary global variables. Keep in mind, that in my case I'm talking about primitive aliases that are just shortcuts but may call nested primitive aliases, so right now I use recursive %alias/%expand calls.
Whoever has a good idea how to do that, feel free to give a hint or post a script.
Vijilante wrote: |
One should rarely if ever need to use #EXEC, and even more rarely should one need to use %exec. |
I didn't even use %exec until now, it wasn't my idea. In my original post I discuss %expand behavior.
However, %exec's behavior is somewhat wierd too, I'm not sure if it is a feature or a bug.
In normal programming languages you may expect it work the same way with global and local variables. (Thus produce the same "output"). |
|
|
|
Vijilante SubAdmin
Joined: 18 Nov 2001 Posts: 5182
|
Posted: Tue Mar 11, 2008 10:17 am |
Quote: |
In normal programming languages you may expect it work the same way with global and local variables. (Thus produce the same "output"). |
I will use a simple example in C to show this is not the case, and why local variables shouldn't actually be expected to work with %exec and #EXEC. If you read Zugg's first post again you will see he says %expand wasn't removed from zScript for zMud compatibility, and that %eval will handle the local variable for you.
Now the explanation for %exec and #EXEC
Code: |
int global = 1;
void exec (char *text, int size) {
int i = 0;
while (i<size) {text[i++]+=local;} //line fails can't access local
}
void exec2 (char *text, int size) {
int i = 0;
while (i<size) {text[i++]+=global;} //line works with global variable
}
void main (void) {
int local = 1;
char testfunc[5]="ok";
exec(testfunc,strlen(testfunc));
//this can't work because local will not be defined there %exec and #EXEC without
//expansion control tricks involving %concat and "" placements.
} |
There you have it. |
|
_________________ The only good questions are the ones we have never answered before.
Search the Forums |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Tue Mar 11, 2008 2:19 pm |
Ok, let me explain my cause for suggesting functions.
$localvar = %concat("blah", %rightback("big bunch of bolarky",3),%if(%1==3,"this","that"),%2)
Now you want to do with all of this stuff...
#send/loop/whatever %expand($localvar) //That isn't working.
If instead of setting that local variable to this you simply used a function
#function rlocalvar {#return %concat("blah", %rightback("big bunch of bolarky",3),%if(%1==3,"this","that"),%2)}
then do.
#send/loop/whatever @rlocalvar(%1,%2)
For that matter if you go in and tic the use default option on a regular variable it is supposed to be as fast as a local variable anyway.
Mind that I have not run any of this through a syntax checker. I'm typing from the top of my head but. I build strings all of the time and have used everything that has been suggested in this entire thread. Yes I have been annoyed a time or two by local variables not working with some of the functions like expand. But like Vijilante said there are lots of ways to work around those annoyances.
The problem being that there are also a lot of things that can be done to cause you to think you need it to work a certain way. We need a specific example of what you are trying to do so that we can show you another way to do it. |
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Tue Mar 11, 2008 5:58 pm |
Dynamic function creatin is interesting, though how fast it is?
Also, I don't set a local variable, I just have a source string as an argument of my function. One more question: a named argument acts the same way as a local variable? And what will happen if I construct a dynamic function from a named argument (if anything). |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Tue Mar 11, 2008 6:45 pm |
I'm not talking about dynamically creating a function... I'm talking about using functions to transform your string.
You would have the function created and waiting to be used in your script.
As far as named arguments acting like local variables. %1 should be the same as first named argument %2 should be the same as second named argument etc. And those SHOULD still work with expand. Though you should not NEED to use it. |
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
Larkin Wizard
Joined: 25 Mar 2003 Posts: 1113 Location: USA
|
Posted: Tue Mar 11, 2008 6:45 pm |
A named argument is a local variable, for all intents and purposes.
I think Arminas was suggesting that you could create a single function for processing the arguments and re-use it in your alias to do whatever it is you're doing. I don't know that you'd want to create a new function each time you use the alias.
Another route would be to use Lua, Python, or some other script language for your complex processing. You could make a CMUD function that utilizes Lua and that might help you circumnavigate some of the limitations you're up against, maybe?
Again, we still don't know exactly what you're doing or why, so it's a little hard to give accurate and specific suggestions. |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Tue Mar 11, 2008 8:51 pm |
Ok, I've tried to make a simple example to demostrate what problems I have:
Below in black bold what I type in the input window
in blue #SAYs
in green (instead of default yellow) what has been sent to the server
Let's assume I have some simple aliases which I can use as standalone, so I don't want to change them.
#VAR Name Zugg
#VAR text Hello
#ALIAS alias1 {tell %1 @text}
Now I want to have another alias that can take alias1 as a parameter. I would like to use it as a standalone too.
I can do it using %exec:
#ALIAS alias2 {do %exec(%-1 " " @Name)} - this alias is working fine, but I can't use it in my final alias "test" below because it executes it's parameter and I get wierd "output".
alias2 alias1
do tell Zugg Hello
Or I can try to "expand" (in wide sense, expand aliases and variables) it's parameter so it will be sent to the server when I use this alias as a standalone:
#ALIAS alias3 {do %alias(%-1, @Name)} - this variant isn't working because @Name variable isn't expanded and I don't know how to expand it. This is one of my problems
alias3 alias1
do tell Zugg @text - I want to modify it so my variables are expanded too.
Now my final alias "test":
#ALIAS test {
#SAY {-------------------}
$s = %exec(%-1)
#IF (%match($s, "Zugg") > 0) { #SEND {$s} } { #SEND {$s Zugg}}
}
I used %exec here too, but it doesn't work as I want. So here I would prefer another full expansion until all aliases and variables are expanded.
test
-------------------
Zugg
test alias1 Zugg
-------------------
tell Zugg Hello
test alias2 alias1
-------------------
do tell Zugg Hello - I send two lines to the server and it is not what I wanted.
Zugg
test alias3 alias1
-------------------
do tell Zugg @text - the variable isn't expanded and the server will not understand it.
So that's why I need some sort of expansion. I can't get it working using exec (because it executes too early for me?) as I get several lines of output.
Or I need some different approach to the problem.
In short, I want my alias1 and alias2(3) work as standalone aliases. And I want to able to use them as paramteres for my "test" alias. |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Wed Mar 12, 2008 2:46 am |
I STILL think there is a better way to do this, Like say using functions instead of aliases.., but.
This does what you are talking about. Note the use of %quote...
Code: |
<?xml version="1.0" encoding="ISO-8859-1" ?>
<cmud>
<func name="expandA">
<value>#return %quote(%alias(%1,%2))</value>
</func>
<var name="text">Hello</var>
<var name="Name">Zugg</var>
<alias name="test">
<value>#SAY {-------------------}
$s = @expandA(%1,%2)
#IF (%match($s, "Zugg") > 0) { #SEND {$s}} { #SEND {$s Zugg}}</value>
</alias>
<alias name="alias3">
<value>#send {do @expandA(%1,@name)}</value>
</alias>
<alias name="alias1">
<value>tell %1 @text</value>
</alias>
</cmud>
|
|
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Wed Mar 12, 2008 3:31 am |
Note that I did replace a couple of %-1 with %1 or %1, %2.
I think between what I showed you and some inventive uses of %quote you can do what you want the way that you want to.
Even if I think it is weird to even try. |
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
Dwoggurd Wanderer
Joined: 29 Jan 2008 Posts: 63
|
Posted: Wed Mar 12, 2008 4:37 am |
Hmm, I tried your script but I don't understand how it should work.
test alias3 alias1
produces:
-------------------
~#send {do tell Zugg Hello}
%-1 was used for a purpose, I don't know how many arguments will be passed to my aliases. I can also pass not aliases, but "literal" commands. So in my actual alias I analyze the argument word by word, leave literals unchanged and expand aliases with %alias. |
|
|
|
Arminas Wizard
Joined: 11 Jul 2002 Posts: 1265 Location: USA
|
Posted: Wed Mar 12, 2008 1:18 pm |
Ok well, have I mentioned that you are going about this a really odd way? Yes... I think I have. Have you considered oninput triggers?
Also note that I mentioned tinkering would be in order.
Code: |
<?xml version="1.0" encoding="ISO-8859-1" ?>
<cmud>
<alias name="alias1">
<value>tell %1 @text</value>
</alias>
<alias name="alias3">
<value>do @expandA(%1,@name)</value>
</alias>
<alias name="test">
<value>#SAY {-------------------}
$s = @expandA(%1,%-2)
#IF (%match($s, "Zugg") > 0) { #SEND {$s}} { #SEND {$s Zugg}}</value>
</alias>
<var name="Name">Zugg</var>
<var name="text">Hello</var>
<func name="expandA">
<value>#return %subchar(%quote(%alias(%1,%2)),~~)</value>
</func>
</cmud> |
Is closer than it was. This IS looking more like you should start trying #oninput triggers with the #noinput option.
Zugg has also stated that he is going to change the way %-1 is expanded. This will make doing odd things like this easier. |
|
_________________ Arminas, The Invisible horseman
Windows 7 Pro 32 bit
AMD 64 X2 2.51 Dual Core, 2 GB of Ram |
|
|
|
|
|