Suppose we wanted to read a string from a file, and, if any bytes were read, print out how many were read. In SCI Studio syntax:
= temp0 FGets(strBuffer, 100, hFile)
(if (temp0)
FormatPrint("Read %d bytes" temp0)
)
But in the actual disassembly, a temp variable might not be used. It might be (in pseudo assembly syntax):
callk FGets .... // result goes into accumulator
bnt -> B // if zero, then branch to B, otherwise...
push2 // two parameters to FormatPrint
lofss // push a reference to string "Read %d bytes" to the stack
push // push the accumulator to the stack... this was the result of FGets
calle FormatPrint // print
B: more code...
Which is conceptually (in SCI Studio syntax) the following impossible code:
(if (FGets(strBuffer, 100, hFile))
FormatPrint("Read %d bytes" <the result of FGets>)
)
If I make my decompiler look backwards to see what was last put in the accumulator, and repeat that, I would get:
(if (FGets(strBuffer, 100, hFile))
FormatPrint("Read %d bytes" FGets(strBuffer, 100, hFile))
)
... which has a totally different meaning, since calling FGets a second time will retrieve the next string in the file.
The only way to have equivalent functionality (in SCIStudio syntax) is to create an additional temp variable and store the result.
Clearly Sierra's original code would not have had two calls to FGets (Since that is different functionality). So the only possibilities are:
1) Sierra's original code had a temp variable, and their compiler was able to figure out it wasn't needed outside that particular scenario, and thus optimize it out., or
2) Sierra's original syntax had the ability to say "if this expression is not nil, then do the following code with the expression"
For the purposes of my decompiler, I can probably just duplicate the expression (so the functionality would be wrong if the expression had side effects like FGets), and then tag it with a comment saying to look at this in more detail because it might be wrong.
As for "unoptimized" Sierra code, I just ran across this example in Laura Bow's code for DSelector::advance. Note the 3 jmp instructions in a row. There is no way to reach the second or third instruction, they are pointless.
(method (advance) // method_0637
0637:3f 01 link 1 // (var $1)
0639:35 00 ldi 0
063b:a5 00 sat temp0
code_063d
063d:87 01 lap param1
063f:30 0039 bnt code_067b
0642:7a push2
0643:67 22 pTos cursor
0645:67 1c pTos x
0647:43 66 04 callk StrAt 4
064a:30 002e bnt code_067b
064d:35 01 ldi 1
064f:a5 00 sat temp0
0651:67 22 pTos cursor
0653:63 1c pToa x
0655:02 add
0656:65 22 aTop cursor
0658:67 26 pTos mark
065a:35 01 ldi 1
065c:02 add
065d:36 push
065e:63 1e pToa y
0660:22 lt?
0661:30 0005 bnt code_0669
0664:6b 26 ipToa mark
0666:32 0007 jmp code_0670
code_0669
0669:67 24 pTos lsTop
066b:63 1c pToa x
066d:02 add
066e:65 24 aTop lsTop
code_0670
0670:e7 01 -ap param1
0672:32 ffc8 jmp code_063d
0675:32 0003 jmp code_067b
0678:32 ffc2 jmp code_063d
code_067b
067b:85 00 lat temp0
067d:30 0005 bnt code_0685
0680:39 53 pushi 53 // $53 draw
0682:76 push0
0683:54 04 self 4
code_0685
0685:48 ret
)