Saturday, August 06, 2022

scanf %ms ou scanf %n?

 it should have been quickly done. Almost trivial. Edit "DHud.cpp", revive calls to the MuadDebug class, change the GOB number so that it tracks the scorpeye rather than Bilou, and make it rewind time

  • when the shell's horizontal speed turns to zero
  • after it has been thrown (there's a flag telling us that)
  • after it has been picked up (need a new flag for that).

Except that however I tried to do it, and regardless of the amount of instruction-by-instruction stepping I made, I couldn't get the second condition to trigger. The optimizer did a great job at packing the expression evaluation code -- I mean there, that you can't tell anymore where you're in the source while doing it, and thus mostly can't set a breakpoint on a specific instruction.

Hopefully, there's the B opcode (not D, which is for Detach) to break at the script expression level. That one at least allowed me to realise that the expression for that second condition was indeed evaluated. But for some reason, the part I was interested in, with flag-setting, never got executed. A 'all done, bye' opcode always showed first. Mysterious...

Faire des essais dans le jeu pour essayer de reproduire un 'trick' pas fréquent, et avoir programmé un critère d'arrêt qui nous permet de passer en débugging pas-à-pas mais en revenant une image en arrière dans le temps, donc en revivant exactement l'évènement qui fait que tout est parti de travers en bullet-time pour pouvoir le comprendre et savoir ce qui doit être corrigé. J'appelle ça le muad-debugging, et c'est vachement pratique.

Enfin, surtout quand ça marche.

It turned out the reason was the expression got truncated even before it was turned into bytecode. Such a thing is not viable to extend the game to "Bilou Dreamland" level.

The code to parse an expression basically looks like

siscanf(base+cont,"[%64[^]]] (%64[^)])",predicate, axion)

And both 'predicate' and 'axion' arrays are static-sized. I know there's another way you could do the 'same' thing, but with any-sized arrays. That'd be something like

siscanf(base+cont,"[%m[^]]] (%m[^)])",predicate, axion)

in which case the siscanf function will allocate some memory by itself and you'll have to invoke free(predicate) when you're done with it. It is sure the way to go in most of your production code, but to be honest, I do not want this within GEDS script parsing code. Parsing a level already takes too much time. Adding dynamic memory for strings processing will only make things worse. Not to mention that it will fragment memory with temporary strings requested while we're making big blocks for the 'tank'.

But there's another trick I could (and likely will) use:

%n Nothing is expected; instead, the number of characters consumed thus far from the input is stored through the next pointer, which must be a pointer to int. This is not a conversion and does not increase the count returned by the function

Combined with the fact that %*s scans a 'string', but does not store it, I should be able to write

siscanf(base+cont, "[%n%*[^]]%n] (%n%*[^)]%n)", &predistart, &prediend, &axstart, &axend);

Now, I'd have start and end pointers for both expressions (if they're actually there), plus that would be copy-less and I would directly perform ascii-to-bytecode conversion. The conversion code would have to be adjusted, of course, so that it takes two pointers instead of one and that it does not expect a terminating \0 character at the end of the expression. So that will be a new "todo" item for when ongoing things are cleared and time is right to start something more experimental.

Oh, yes. And I could just grow the static arrays, of course. That's what I did in the past when they were 32-character long each, and I thought "well, 64-bytes predicates ought to be enough for everybody, right ? ". In another context, I could pick ridiculously large arrays (like 2048 bytes each) and forget about the issues for decades until it strikes back with some auto-generated script. But that would be a bad idea on the Nintendo DS with its fairly small stack. And nah, I won't make the arrays global either. That would sure break so many things in the ability to run that code out of its current context that it has even been considered as an evil thing to do by the former generation of developers.

No comments:

Post a Comment

this is the right place for quickstuff