Jumps in Ikarus are implemented by direct manipulation of the stack pointer, achieved with two lines of code. These lines enable the change of the current position within the parser stack, representing machine-level code generated during script compilation. By querying and setting this position, the execution flow can be redirected to a new location in the code.
Initialization
To ensure the correct functioning of this jump mechanism, it is crucial to execute the MEM_InitLabels() function once after loading a saved game. The recommended practice is to integrate this initialization function within INIT_GLOBAL. It's only after MEM_InitLabels() has been called that accessing MEM_StackPos.position becomes valid.
It's worth noting that MEM_InitLabels is also invoked by the MEM_InitAll function.
Usage
Label Initialization Before attempting a jump, it's important to initialize the label to which the jump is intended. Forward jumps, where the jump point is encountered before the jump target, can be challenging. Label initialization looks like that:
flowchart TD
A(Start) --> B["var int label; \n label = MEM_StackPos.position;"];
B --> C{Your code}
C -->D["MEM_StackPos.position = label;"];
C --> E(End)
D --> |Jump| B;
Notes and warnings
Validity of Labels Labels become invalid after saving and loading. Consequently, labels should be used immediately, and there is generally no reason to persist them for an extended period.
Caution with Jumping Jumping between different functions without a clear understanding of the code structure can lead to unexpected issues. Similarly, using labels without a thorough comprehension of their purpose may result in undesired consequences. It's crucial to exercise caution, especially when making assignments involving labels.
Examples
The following code outputs the numbers from 0 to 42:
funcvoidfoo(){/* Initialization */MEM_InitLabels();varintcount;count=0;/* Record the execution position in label. */varintlabel;label=MEM_StackPos.position;/* <---- label now points here, * i.e. to the position AFTER the assignment of label. */Print(ConcatStrings("COUNT: ",IntToString(count)));count+=1;if(count<=42){/* Replace the execution position, * with the "<-----" the system then continues */MEM_StackPos.position=label;};/* Once 43 is reached, the “loop” is exited. */};
The following code should enumerate all pairs (x,y) with 0 <= x < max_x, 0 <= y < max_y
Besides the normal jumps Ikarus implements MEM_Label and MEM_Goto functions. They work similar to the stack manipulation with var int label but the interface is much more user-friendly and defining new variables is not needed.
MEM_Label
Function that works like a label = MEM_StackPos.position;. You could jump to it with MEM_Goto.
varintlbl Number of the label, the function will jump to
Usage
Usage of Label and Goto is probably self-explanatory, since it is same as in the regular Ikarus Jump. But before using it reading the Notes and warnings of the Jumps is recommended.
Label-Goto loop flowchart
flowchart TD
A(Start) --> B["MEM_Label(0);"];
B --> C{Your code}
C -->D["MEM_Goto(0);"];
C --> E(End)
D --> |Jump| B;
funcvoidfoo(){varintcount;count=0;MEM_Label(0);/* <---- label now points here, * i.e. to the position AFTER the assignment of label. */Print(ConcatStrings("COUNT: ",IntToString(count)));count+=1;if(count<=42){// Jump to the MEM_LabelMEM_Goto(0);};/* Once 43 is reached, the “loop” is exited. */};
The following code should enumerate all pairs (x,y) with 0 <= x < max_x, 0 <= y < max_y
Ikarus also implements a while loop. Its syntax isn't as good as the loop from zParserExtender, due to the daedalus limitations, but it works as a normal while loop that can be found in many programming languages.
Syntax
The Ikarus while loop consist of three things:
while function That works like a while statement and start of the brace while(var int b){.
funcvoidfoo(){varintcount;count=0;while(count<=42);//{Print(ConcatStrings("COUNT: ",IntToString(count)));count+=1;end;//}/* Once 43 is reached, the loop is exited. */};
The following code should enumerate all pairs (x,y) with 0 <= x < max_x, 0 <= y < max_y
In addition Ikarus implements something called Repeat loop.
Initialization
To use Repeat loop you must first call MEM_InitRepeat() function once after loading a saved game. The recommended practice is to integrate this initialization function within INIT_GLOBAL.
It's worth noting that MEM_InitRepeat is also invoked by the MEM_InitAll function.
Syntax
Repeat loop has a syntax very similar to the while loop. It also uses end constant as an ending brace. break and continue statements can be used within it as well. The main difference is the main loop function Repeat that has following properties:
funcvoidfoo(){Repeat(count,43);varintcount;//{Print(ConcatStrings("COUNT: ",IntToString(count)));end;//}/* Once 43 is reached, the loop is exited. */};
The following code should enumerate all pairs (x,y) with 0 <= x < max_x, 0 <= y < max_y