thelink2012 / gta3sc

GTA3script compiler
MIT License
71 stars 13 forks source link

Idea: short circuit AND #120

Open aap opened 5 years ago

aap commented 5 years ago

I have been working on a decompiler recently and noticed quite a lot of nested IFs that are essentially a short circuit AND. I think these were written as a chain of manual 'GOTO else' by the scripters. The language would benefit from a proper short circuit AND. If we can decide on a syntax and you implement it, the decompiler output could be a bit nicer. Two ideas for a syntax: either use a modified IF (say IFX) and only allows AND or use a modified AND (say ANDX) with the regular old IF. I don't know which one is better, but I think I'd prefer the second.

EDIT: an example:

01A722           IF IS_PLAYER_PLAYING global_210 
01A732              IF IS_PLAYER_IN_ZONE global_210 'SWANKS' 
01A74A                  IF IS_PLAYER_IN_AREA_3D global_210 -367.250000 241.000000 59.000000 -358.750000 259.562500 65.000000 0 
01A76E                      IF IS_PLAYER_IN_MODEL global_210 138 
01A77A                      OR IS_PLAYER_IN_AREA_3D global_210 -367.250000 251.000000 59.000000 -358.750000 259.562500 65.000000 0 
thelink2012 commented 5 years ago

Hi ape, good to see you out here!

I the issue to gta3script-specs, since this seems like a language design issue rather than an implementation one, I assume it's ok on your side (EDIT: Ok, GitHub does not allow transfers between organizations, great).

Indeed. The lack of short-circuits made the scripters perform these deeply nested IF chains.

It's interesting to note GTA2script had a more complex if construct, which among other things, permitted short-circuit evaluation.

I think the correct way to handle this is by IFX not ANDX. Think at MISS2.EXE intermediate language level, there is no command named AND. The IF (and IFNOT) construct is compiled to a IF n (IFNOT n) command followed by n commands. The semantics of the IF(IFNOT) command is to evaluate the n following commands and jumps to its corresponding ELSE/ENDIF command if their conjunction is (not) false.

Similarly, an IFX statement would compile into IFX n similarly to above, except it would evaluate at most n commands, and jump on the first false.

I think IFAND could be a good name.

All that said, I'm against the addition of this feature. It seems to be a fundamental design choice, and they coded five games without bothering. It's rather easy to transform a very simple language into a complex language by adding syntactic changes every here and there. Given scripters annoyed by this pattern, I would rethink my position.

Hope you understand.

aap commented 5 years ago

Sure, i understand not wanting to change the language spec. I have implemented a short circuit and in my decompiler now and this:

030C30               IF IS_PLAYER_PLAYING global_218
030C3B                   IF IS_PLAYER_IN_ANY_CAR global_218
030C46                       IF global_8f1 == 0
030C52                           IF DOES_VEHICLE_EXIST global_8f1
030C5D                               IF NOT IS_CAR_DEAD global_8f1
030C68                                   IF IS_CAR_MODEL global_8f1 162
030C76                                       PRINT_HELP 'TANK'
030C80                                       CALL F4284 5000
030C8D                                       global_1e4 = 1
000000                                   ENDIF
000000                               ENDIF
000000                           ENDIF
000000                       ENDIF
000000                   ENDIF
000000               ENDIF

turns into

030C30               IF IS_PLAYER_PLAYING global_218
030C3C               ALSO IS_PLAYER_IN_ANY_CAR global_218
030C47               ALSO global_8f1 == 0
030C53               ALSO DOES_VEHICLE_EXIST global_8f1
030C5E               ALSO NOT IS_CAR_DEAD global_8f1
030C69               ALSO IS_CAR_MODEL global_8f1 162
030C76                   PRINT_HELP 'TANK'
030C80                   CALL F4284 5000
030C8D                   global_1e4 = 1
000000               ENDIF

It also improves else-analysis because now a deeply nested IF with a GOTO to after an ELSE part of an outer IF can now be analyzed as a proper ELSE, even if they used a manual GOTO in the source.