It's been a while! I hope all is well.
First, as you can tell I'm not dead. (But, I may be a zombie.) Most important, I am still working on the decompiler and have been since the last update!
Back in May I was preparing a status update, but stopped because I didn't like the code. I couldn't say why, exactly. It worked, it was fast. But, for some reason I wasn't satisfied. So, I scrapped the code and started over. And I finally saw what the problem was: the original code wasn't written to be easily extended. Which was important, since it still needed features. (If I had to guess, I would say it was 5%-10% complete.)
Since then, I've made significant progress:
To do:
Embedding NWScript function declarations into the binary
Complete (Yes, all 877! No nwscript.nss needed!!!)
Identifying simple expressions (e.g. addition, assignment, bitwise operations, and function calls)
Complete
Fixed handling of STORE_STATE op code
Identifying statements
Declarations
Complete
Assignment
Complete
Iteration, selection and jump statements
Still working
Operator associativity and precedence
This is irrelevant at the byte code level
Type conversions
This does not appear to exist in NWScript
Byte code conversion to source code
Still working
Source code conversion to byte code
Not started
GUI
Not started
Analysis of NCS file bugs
Still working
Given what I've learned over the last few months, I would say progress is now 30%. Here's an example of what the decompiler currently does:
02 03 [RSADDI, create a named variable of type int on the stack]
04 03 00000002 [CONSTI, Place a constant (i.e. temporary) value of type int onto the stack]
05 00 0300 01 [Action, Call the function 0x300, popping 1 argument off the stack]
01 01 FFFFFFF8 0004 [CPDOWNSP, Copy the result from the top of the stack to an existing variable]
This series of four operations is represented by the following psuedo-NWScript:
02 03 int I0;
04 03 00000002 2;
05 00 0300 01 int GetScriptParameter(int nIndex); [Function 0x300 (768) returns an int onto the top of the stack!!!]
01 01 FFFFFFF8 0004 <some variable -8 bytes from the top of the stack> = <value at top of stack>;
Continued evaluation:
int I0;
I0 = GetScriptParameter(2);
We have a variable declaration, and then assignment of the function result to the declared variable. In C terminology, that's a variable definition:
int I0 = GetScriptParameter(2);
Some of the steps are omitted, but we see the following:
Some NCS op codes translate directly to NWScript statements (e.g. RSADDx results in a named variable)
Some NCS op codes translate directly to expressions (e.g. CONSTx places a constant, or literal, into the script, ADDxx places addition into the script)
Multiple NCS op codes will need to be combined to make complex NWScript statements, as in the example above
At the moment, I have partially decompiled scripts. And, the binary does not choke on global variables initialized by functions the way DeNCS does! @Salk and @DarthParametric should be happy, since this means the swoop race scripts from Manaan and Tatooine can finally be decompiled! I'm also tallying errors I've found in scripts. Here's one in pseudo-code:
string S1 = "Blah";
string S2 = "Meh";
object(S1) == object(S2);
NWScript does not have casts!
Casts added to illustrate the problem!
What's wrong with this? NWScript is based on C, and C is a strongly-typed language. This means an entity of type string is different from an entity of type object! So, when NWScript is told to test for equality, it needs to compare the entities using their type information. That means strings should be compared byte by byte, up to the length of the shortest string.
But, we told NWScript that S1 and S2 are object types, which are pointers! The pointers are compared, but not the strings to which they point! Thus, they will likely never test correctly even when the strings have the same contents! This is a real bug I found, and while I don't think it breaks the script I found it in, it could explain weird issues I've had with the game over the years. (I once tried to leave Peragus, only to find the Ebon Hawk surrounded by 30-40 robots. There're supposed to be two or three!!!)
That's all for now. Hopefully, I'll have more progress by next week.