Usecode questions (and comments)

NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Forum rules
NOTICE: This forum is archived as read only.
Please use the Github Discussions at https://github.com/exult/exult/discussions
Locked
Alun Bestor

Usecode questions (and comments)

Post by Alun Bestor »

Hi there,
I figured I'd try and move usecode discussion to a focused thread rather than post more in the patch thread with my usecode-related questions. I have a couple to kick off with:

1. Implicit function numbers
------------------------------------
The standard usecode function definition includes a unique function address, like so:
functionName 0xFFF() { }

But this address is redundant for functions that do not replace an original or do not apply directly to a shape, egg, spell or NPC: i.e. new generic or helper functions.

The current version of the ucc compiler appears to support implicit addresses, like so:
functionName() { }
Which would be a real boon for code organisation, as when code is split over several include files it can be a pain working out what address you're up to.

Except that the compiler numbers them starting from the last explicitly-declared address (be it for a function or an extern). And it also numbers them in the same pass as it takes in all the explicit addresses functions, which means if you do:

//explicit address
functionName1 0xF00() { }

//implicit address, which will be assigned 0xF01
functionName2() { }

//explicit address, which will now conflict with functionName2()
functionName3() 0xF01() { }

You get into trouble.

Another wrinkle: By default, if you have no explicit functions or externs defined (i.e. no place for it to start numbering), it will number them starting at before the last of the original functions, which will get you into even MORE trouble!


2. Function names as pointers/constants
------------------------------------------------------
This is a feature request I'm really keen on. Currently, when you call a function from inside a script{} block or UI_execute_usecode_array(), you are required to refer to the function address, e.g.:
script item { call 0xF00; }

Instead of the name of the function, e.g.:
script item { call functionName; } //This produces a "cannot use functionName here" compile error

This makes code organisation much more difficult and harder to maintain. In fact, the easiest way to refer to a common function in a script{} block is to define a constant with the function's address and use that instead. Which is silly, given the function name is already in the symbol table and could do that exact job itself.


Is there any chance of these two issues being improved? I don't know how much work they would be by themselves, but it seems that it would only be the ucc.exe compiler that would need updating, rather than Exult itself.
nadir
Site Admin
Posts: 407
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by nadir »

this sort of thing is usually better discussed on the mailing list
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by drcode »

Starting with #2: This is just an oversight that I need to address.

#1 won't be too hard as long as we continue the requirement that all the compiling is done with one main file, and everything else #include'd. We'd have to reserve a range of numbers for Exult that aren't used in the original games' usecode files. And to avoid conflicts, we'd probably want to print an error if you explicitly specify a function # in that range.
Alun Bestor

Re: Usecode questions (and comments)

Post by Alun Bestor »

Ahh, that sounds great! (including the errors for explicitly defining a function within the reserved range). I take it that implicit extern declarations would work just as well? I've forgotten to test this O:)
Beryllium

Re: Usecode questions (and comments)

Post by Beryllium »

For part of #1, how about a pragma to set the start of implicit address assignments.
Alun Bestor

Re: Usecode questions (and comments)

Post by Alun Bestor »

Another couple of wondering-abouts with the usecode compiler:

1. Why do original usecode functions get their arguments reversed?
-----------------------------------------------------------------------------------
I've asked about this in a previous thread, and never got an authoritative answer about it. It applies to original decompiled usecode functions that have more than one argument.

Function calls in decompiled usecode have their arguments in the order that you would expect. Likewise, the decompiled function and extern declarations have them in the expected order. However, *inside* those functions themselves, the argument order is completely flipped. e.g. the first argument (which is typically an itemref of the target of the function) is actually expected to come last.

So if you call these functions with their expected argument order, they won't work: instead, you have to completely flip the argument order when you call them, either in your new functions or in decompiled functions.

This is a real irritation when you're trying to use original functions that have more than 1 argument. Working around it requires writing a wrapper function with the arguments in the correct order, e.g.:

extern originalFunction 0x678 (var var3, var var2, var var1);
wrapperFunction 0xFFF (var var1, var var2, var var3)
{
originalFunction 0x678(var3, var2, var1);
}

Why is this quirk occuring in the first place?

2. How does functionName.original() work with arguments?
----------------------------------------------------------------------------
I've seen this construction used in some of the usecode samples, and it appears to work fine when there are no arguments provided. But I have tried to use it as a solution to the above problem, like so:

replacementFunction 0x678 (var var1, var var2, var var3)
{
replacementFunction.original(var3, var2, var1);
}

Which, if it worked, would save a function declaration. However, it doesn't work, and it's difficult to figure out why since it requires an original function to test with. I have tried it with both flipped and unflipped argument order with a couple of originals, with no joy. So, I was hoping one of the Devs could shed some light on how it is implemented, and what argument order (if any) it expects.
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by drcode »

Beryllium: For your suggestion for #1, maybe that's pretty much all we need to do. In other words, the automatic assignment of usecode #'s should only be reset when you add a special command (maybe something like "functions 0x500;".

#2: Just added support last night so you can put "call myfun;" in scripts. Just be careful not to use "call myfun();" unless you really want to first call myfun, then place it's return value in the "call" entry of the script (and I didn't check to see if that would really work right).

As for the reversed params., I don't really understand, since I've never seen this. Maybe it's a bug in ucc. I'll try to experiment this weekend.
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by drcode »

Whoops. I think you're right about ucc reversing the params. I didn't notice because both the caller and callee were reversed. I've switched them both now, so the following works. Iolo should report first, his intelligence (prop. 2), and then his combat (prop. 4). Give the latest ucc a try, and let me know if this fixes things for you.

extern var getprop 0x910(var npc, var prop);
testfun 0x700(var npc, var var1, var var2)
{
npc->say("I was passed ", var1, " and ", var2);
var prop = getprop(npc, var1);
npc->say("My property ", var1, " is ", prop);
prop = getprop(npc, var2);
npc->say("My property ", var2, " is ", prop);
}

iolo 0x401()
{
testfun(item, 2, 4);
}
Alun Bestor

Re: Usecode questions (and comments)

Post by Alun Bestor »

Okay, feedback on the new compiler changes (should these start going to the mailinglist instead, as suggested?)

Reversed argument orders
----------------------------------
I have tested with the 22-April-2005 Exult Tools snapshot downloaded from the Exult site, and the arguments are still reversed. Am I missing out on a newer version that hasn't been released as a binary yet?

For the record anyway: when trying your testcase with the 22-April-2005 version or the 02-July-2004 version, Iolo reports Spark's strength (14) followed by Dupre's strength (21) - instead of Iolo's own intelligence (20) and combat (19). This is because Iolo's NPC number (1), passed as the first parameter, is getting treated as the property number; and the property number (2 and then 4), passed as the second parameter, is getting treated as the NPC number.

Passing function names
------------------------------
The 22-April-2005 version does now allow you to use function names in script blocks, which is brilliant and a great improvement. However, it still doesn't allow you to pass function names outside of script blocks: e.g. as parameters to UI_run_path_usecode() or UI_execute_usecode_array(). These cases still require you to use the function number instead.


Implicit function numbers
--------------------------------
Another wrinkle to the current implicit-function-name support... the following case will cause a compile error:

extern newFunction();
newFunction();

This fails, saying that "Decl. of 'newFunction' does not match previous decl".


Another compiler issue: empty arrays
-----------------------------------------------
Currently, declaring an empty array (e.g. arrayvar = []) is unsupported and results in a parse error. This makes cases like this have undesired behaviour:

var arrayvar;
var newvar;

while (condition)
{
arrayvar = arrayvar & newvar;
}

arrayvar is initialised to false, so when newvar is pushed onto arrayvar on the first loop, it:
1. converts arrayvar into an actual array,
2. assigns the old value of arrayvar (false) as the first array entry,
3. adds new_var as the second array entry.
Dominus
Site Admin
Posts: 5656
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by Dominus »

changes came in this morning (GMT), snapshot is not yet updated it seems.

I do think these specific usecode stuff is better on the ML. But then I'd suggest for everyone interested in usecode to join it (especially you and Tawn).
The link to the subscribe page is:
http://lists.sourceforge.net/lists/list ... lt-general

You only have to be patient on the list. Mostly if anyone has no real opinion on something there won't be an answer from him/her (for example on your suggested webpage, I really have no opinion whether we need a new design or not and thus remained silent). Forums tend to be more lively the ML a bit more precise mostly.

For the record I really appreciate this recent spike of usecode interest and hope it inspires more people. Thanks a lot guys.
--
Read the documentation and the FAQ! There is no excuse for not reading them! RTFM
Read the Rules!
We do not support Piracy/Abandonware/Warez!
drcode
Site Admin
Posts: 2267
Joined: Thu May 14, 2020 1:34 pm

Re: Usecode questions (and comments)

Post by drcode »

Yes, you must not have the change yet, since you're getting the same results I saw before making the change.

Function names: Looks like the compiler is too strict about these. I'll allow them anywhere. Of course, that means a greater likelihood that someone will make mistakes between "fun" and "fun()", but that's the way it goes.

The other two issues just look like bugs to be fixed. It'll probably be a day or two before I get a chance to work on these.
Alun Bestor

Re: Usecode questions (and comments)

Post by Alun Bestor »

Thanks for the improvements to the compiler so far, they already make UCC a much friendlier and cleaner language :) I'm looking forward to the additional changes, but there's no rush.

As far as the difference between fun and fun() goes: people make that mistake in any language that supports that sort of thing, so I think it's a matter for the tutorials to cover.
Locked