Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'repeat' statements break the decompiler #20

Open
OmerMor opened this issue Jan 15, 2019 · 2 comments
Open

'repeat' statements break the decompiler #20

OmerMor opened this issue Jan 15, 2019 · 2 comments

Comments

@OmerMor
Copy link
Contributor

OmerMor commented Jan 15, 2019

The decompiler can't handle repeat statements, gives up, and makes it an asm block instead.
This affects things like "death message" procedures, save-restore and asking for a new path.

Sierra's documentation for repeat statemenets:

(repeat code)

Continually execute the code until some condition in the code (a break) causes the loop to be exited. This is equivalent to
(while TRUE code)
or
(for () TRUE () code)

Originally reported here:
http://sciprogramming.com/community/index.php?topic=1420.msg12241#msg12241

@OmerMor OmerMor changed the title 'repeat' statements breaks the decompiler 'repeat' statements break the decompiler Jan 15, 2019
@OmerMor OmerMor changed the title 'repeat' statements break the decompiler 'repeat' statements break the decompiler Jan 15, 2019
@EricOakford
Copy link

EricOakford commented Jan 16, 2019

A close investigation suggests that the issue is with the break statement. As shown with the EgoDead procedure in my SCI01 template...
Decompile log:

Decompiling script 0
WARNING:  ::EgoDead: Analyzing control flow: Expected node with two successors (then/else): 1 at 0178
Falling back to disassembly for EgoDead
Generated c:\scicompanion\templategame\sci0.1\src\Main.sc
Decompiled 13 of 14 functions successfully (92%).
Overall bytecount success rate: 84%.
Fell back to assembly for the remaining functions.

Uncompiled code:

(procedure (EgoDead message &tmp printRet)
	;This procedure handles when Ego dies. It closely matches that of QFG1EGA.
	;To use it: "(EgoDead {death message})". You can add a title and icon in the same way as a normal Print message.
	(HandsOff)
	(Wait 100)
	(= normalCursor ARROW_CURSOR)
	(theGame setCursor: normalCursor TRUE)
	(SFX stop:)
	(music number: deathSound play:)
		(repeat
			(= printRet
				(Print message
					&rest
					#width 250
					#button	{Restore} 1
					#button {Restart} 2
					#button {__Quit__} 3
				)
			)
				(switch printRet
					(1
						(theGame restore:)
					)
					(2
						(theGame restart:)
					)
					(3
						(= quit TRUE) (break)
					)
				)
		)
)

Asm output:

(procedure (EgoDead param1 param2 &tmp temp0)
	(asm
		pushi    0
		call     HandsOff,  0
		pushi    1
		pushi    100
		callk    Wait,  2
		ldi      999
		sal      normalCursor
		pushi    #setCursor
		pushi    2
		lsl      normalCursor
		pushi    1
		lal      theGame
		send     8
		pushi    #stop
		pushi    0
		lal      SFX
		send     4
		pushi    #number
		pushi    1
		lsl      deathSound
		pushi    42
		pushi    0
		lal      music
		send     10
code_012d:
		ldi      1
		bnt      code_0187
		pushi    12
		lsp      param1
		&rest    param2
		pushi    70
		pushi    250
		pushi    81
		lofss    {Restore}
		pushi    1
		pushi    81
		lofss    {Restart}
		pushi    2
		pushi    81
		lofss    {__Quit__}
		pushi    3
		calle    Print,  24
		sat      temp0
		lst      temp0
		dup     
		ldi      1
		eq?     
		bnt      code_0168
		pushi    #restore
		pushi    0
		lal      theGame
		send     4
		jmp      code_0184
code_0168:
		dup     
		ldi      2
		eq?     
		bnt      code_0178
		pushi    #restart
		pushi    0
		lal      theGame
		send     4
		jmp      code_0184
code_0178:
		dup     
		ldi      3
		eq?     
		bnt      code_0184
		ldi      1
		sal      quit
		jmp      code_0187
code_0184:
		toss    
		jmp      code_012d
code_0187:
		ret     
	)
)

@Kawa-oneechan
Copy link

Minimal example:

(procedure (TheTest)
    (repeat
        (switch (== 1 1)
            (1 (break))
        )
    )
)

"decompiles" to

(procedure (TheTest)
    (asm
code_000a:
        ldi      1
        bnt      code_001a
        pushi    1
        dup     
        ldi      1
        eq?     
        bnt      code_0017
        jmp      code_001a
code_0017:
        toss    
        jmp      code_000a
code_001a:
        ret     
    )
)

Note that using if is fine:

(procedure (TheTest)
	(repeat
		(if (== 1 1) (break))
	)
)

decompiles to

(procedure (TheTest)
	(repeat
		(if 1 (break))
	)
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants