flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > [fasmg] Is there a way to do a lookup table using CALM? |
| Author |
|
|
bitRAKE 03 Jul 2026, 23:30
Code: repeat 10,i:0 calminstruction jumptable.i display "Jump at " bappend `i bappend 10 end calminstruction end repeat calminstruction jumptable target* ; this catches negative numbers, too match index|number, target, | jno nan check index > 9 jyes out ; "dynamic" labels must be baked at assemble-time arrange target,=jumptable.index assemble target exit nan: err "only numbers are supported" exit out: err "jump value out of range" end calminstruction jumptable 7 jumptable 0 jumptable 17 _________________ ¯\(°_o)/¯ AI may [not] have aided with the above reply. |
|||
|
|
Jessé 05 Jul 2026, 12:52
Interesting (and creatve) approach.
It kind of resolves the quest, but at the cost of exiting current CALM statement. Anyways, I just find a way to use it on what I first came up when I had this usage idea. Thanks, bitRAKE! P.S.: tested and working fine! |
|||
|
|
bitRAKE 05 Jul 2026, 15:56
The other technique that might work is the CALM builder technique - super meta though. Look at the start of x86-2.inc for an example.
|
|||
|
|
Jessé 07 Jul 2026, 00:03
bitRAKE wrote: The other technique that might work is the CALM builder technique - super meta though. Look at the start of x86-2.inc for an example. Great suggestion! I stare at this header very often, because it is a very rich resource of things that work with fasmg. But, so far, most of them are quite misterious to me yet. Tomasz has a very unique way of implementing his ideas, which is quite afar from my way of doing things. And that's the reason that keeps me interested, and retrying to decipher those enigmatic headers bundled with fasm2 and fasmg. It's a (somehow) new way of implementing stuff (to me), and one that works nicely. ... By the way, this is the main reason I pushed this thread here. Thats my converted internal function: Code: define __q_reg calminstruction get_q_register register* local RegID, info, class compute info, register metadata 1 compute class, info metadata 1 check class relativeto x86.reg jyes next error: err "register not found or unknown/unsupported type" exit next: compute RegID, 0 scaleof info next0: check RegID = 0 jno next1 compute __q_reg, rax jump done next1: check RegID = 1 jno next2 compute __q_reg, rcx jump done next2: check RegID = 2 jno next3 compute __q_reg, rdx jump done next3: check RegID = 3 jno next4 compute __q_reg, rbx jump done next4: check RegID = 4 jno next5 compute __q_reg, rsp jump done next5: check RegID = 5 jno next6 compute __q_reg, rbp jump done next6: check RegID = 6 jno next7 compute __q_reg, rsi jump done next7: check RegID = 7 jno next8 compute __q_reg, rdi jump done next8: check RegID = 8 jno next9 compute __q_reg, r8 jump done next9: check RegID = 9 jno next10 compute __q_reg, r9 jump done next10: check RegID = 10 jno next11 compute __q_reg, r10 jump done next11: check RegID = 11 jno next12 compute __q_reg, r11 jump done next12: check RegID = 12 jno next13 compute __q_reg, r12 jump done next13: check RegID = 13 jno next14 compute __q_reg, r13 jump done next14: check RegID = 14 jno next15 compute __q_reg, r14 jump done next15: check RegID = 15 jno error compute __q_reg, r15 jump done done: end calminstruction At least judging by the way it looks like, it seems clear why a "jump lookup" might be useful, avoiding all those checks, and going straight to the point, pointed by the already known (scaleof) number (to jump). I think I can put your suggestion to work here, although I've not tried yet. The original previous macro version is: Code: macro get_q_register register* local RegID, info, class info = register metadata 1 class = info metadata 1 if class relativeto x86.reg RegID = 0 scaleof info if RegID = 0 __q_reg = rax else if RegID = 1 __q_reg = rcx else if RegID = 2 __q_reg = rdx else if RegID = 3 __q_reg = rbx else if RegID = 4 __q_reg = rsp else if RegID = 5 __q_reg = rbp else if RegID = 6 __q_reg = rsi else if RegID = 7 __q_reg = rdi else if RegID = 8 __q_reg = r8 else if RegID = 9 __q_reg = r9 else if RegID = 10 __q_reg = r10 else if RegID = 11 __q_reg = r11 else if RegID = 12 __q_reg = r12 else if RegID = 13 __q_reg = r13 else if RegID = 14 __q_reg = r14 else if RegID = 15 __q_reg = r15 else err "Error: register not found or unknown/unsupported type.", 10 end if else err "Error: register not found or unknown/unsupported type.", 10 end if end macro I also noted that compute, as well as transform, have no support to synthesize labels based on variables, unlike arrange does. But I must be wrong about this, because arrange may not do it either, but its result resolve those symbols after. I thought on an idea of achieving it using 'eval', but, 'eval' is not a valid statement under CALM, as I had figured out. Also important: I understand (I guess) that, as 'Compiled' assembly-like macro, it means that it leaves to be a text thing on fasmg at the time of its definition/processing, so, I really don't know how viable (or impactful in terms of performance) would be to implement such things. Maybe the cost-efficiency of it, or the added complexity may not pay itself off, I suppose. Anyways, I'm looking forward to make good use of it sooner. |
|||
|
|
Jessé 07 Jul 2026, 01:07
Working (first attempt) approach, with embedded diagnosis:
Code: define __q_reg iterate <ID,reg,name>, 0,rax,'rax', 1,rcx,'rcx', 2,rdx,'rdx', 3,rbx,'rbx', 4,rsp,'rsp', 5,rbp,'rbp', 6,rsi,'rsi', 7,rdi,'rdi' calminstruction get_reg_id_#ID compute __q_reg, reg display "Result: " bappend name bappend 10 end calminstruction end iterate repeat 8, ID:8 calminstruction get_reg_id_#ID local name arrange reg, =r#ID arrange name, reg stringify name compute __q_reg, reg display "Result: " bappend name bappend 10 end calminstruction end repeat calminstruction get_q_register register* local RegID, info, class, select compute info, register metadata 1 compute class, info metadata 1 check class relativeto x86.reg jyes next error: err "register not found or unknown/unsupported type" exit next: compute RegID, 0 scaleof info arrange select, =get_reg_id_#RegID assemble select done: end calminstruction get_q_register cl get_q_register r12w get_q_register sp At production code: Code: define __q_reg iterate <ID,reg>, 0,rax, 1,rcx, 2,rdx, 3,rbx, 4,rsp, 5,rbp, 6,rsi, 7,rdi calminstruction get_reg_id_#ID compute __q_reg, reg end calminstruction end iterate repeat 8, ID:8 calminstruction get_reg_id_#ID arrange reg, =r#ID compute __q_reg, reg end calminstruction end repeat calminstruction get_q_register register* local RegID, info, class, select compute info, register metadata 1 compute class, info metadata 1 check class relativeto x86.reg jyes next error: err "register not found or unknown/unsupported type" exit next: compute RegID, 0 scaleof info arrange select, =get_reg_id_#RegID assemble select end calminstruction Seems working fine, so far... |
|||
|
|
Tomasz Grysztar 07 Jul 2026, 08:04
Jessé wrote: I also noted that compute, as well as transform, have no support to synthesize labels based on variables, unlike arrange does. But I must be wrong about this, because arrange may not do it either, but its result resolve those symbols after. For example, TRANSFORM would take the text contained in this variable and look for identifiers of other symbolic variables to replace each of them with its content (and each has a value containing tokenized source text, since this is what "symbolic variable" is in fasm) and put this final unrolled text into the same variable. Here your newly constructed identifier (like one with appended index) would get recognized. As for COMPUTE, normally it does not deal with tokenized text at all, it computes a pre-compiled expression and stores the numeric (not symbolic) result in a variable. Only if the pre-compiled expression uses a variable that happens to have a symbolic value, COMPUTE parses this text as a new sub-expression and the evaluates it. This is obviously slower, as it requires additional parsing, while the main expression for the COMPUTE has been already parsed at the time when the instruction was compiled (that is: during the definition of CALM instruction). However this means that if you construct an indexed identifier and put it into a variable that is accessed by pre-compiled expression of COMPUTE, it is going to be parsed and evaluated as a sub-expression, and thus it can also access a symbol with newly synthesised name. And, of course, the target variable of ARRANGE, TRANSFORM, COMPUTE is always just a pre-compiled reference to a symbol, so it is static, already decided at the time when the instruction is defined. The target of a CALL is also a static reference to a symbol, in this case an instruction-class symbol. You can still alter the value of such symbol, by redefining a macro, or with MVMACRO/PURGE. However in case of JUMP/JYES/JNO the target is doubly static, because it is compiled into an internal reference to a specific position inside CALM bytecode. Once the instruction is compiled, this target cannot be changed in any way. Hope that clarifies a little. |
|||
|
|
Jessé 08 Jul 2026, 00:44
Yes, it helped a lot, good explanation on those internals. I appreciate it.
Quote:
I must say that this is a great behavior (for this directive), it feels quite natural to me to deal with, leading to almost no mistakes when I use 'arrange' on something. But maybe this is due to the fact that I'm already very used to 'match' characteristics as well, because they're related to each other (one joins, and the other splits). |
|||
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2026, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.