flat assembler
Message board for the users of flat assembler.
Index
> Macroinstructions > Metaprogramming with nested CALM-instruction. Goto page 1, 2 Next |
Author |
|
Tomasz Grysztar 28 Feb 2020, 12:15
MaoKo wrote: because the instruction calminstruction is not defined inside the namespace calminstruction?. In my recent update to the fasmg overview I tried to explain the concept of CALM instruction by describing it as a specialized preprocessor. It operates on the same layer, in which classic preprocessor prepares a line from macro to be assembled by replacing parameters with their values, processing "`" operator, etc. Therefore CALM instruction can prepare a line containing a command like DISPLAY and then pass it to assembly (analogously to how macro produces lines), but the current state of assembler may be such that this command would not be executed (like when you are inside an IF block with false condition, or inside of a definition of a macro, or inside of a definition of CALM instruction). For example, if your CALM instruction is called while a macro is being defined, the generated DISPLAY is going to become part of the definition of a macro instead of being executed immediately. And similarly, if your instruction generates a DISPLAY line while there is another CALM instruction being defined, this line is going to be treated by assembler as part of the definition and interpreted accordingly. It may end up calling some macro, if you have "calminstruction.display" defined, but after all such macros get unrolled, the assembler needs to have only compilable CALM statements. Just like when a macro is defined, normal directives are not recognized and processed at that time. |
|||
28 Feb 2020, 12:15 |
|
Tomasz Grysztar 28 Feb 2020, 18:37
PS. You could probably achieve the results you wanted by making a framework of customized language definitions that would collect statements and only later generate complete "calminstruction" definitions under the hood.
|
|||
28 Feb 2020, 18:37 |
|
MaoKo 28 Feb 2020, 18:56
Quote:
Yes I agree. But what I want is not to declare calm inside another declaration. In fact, I wanted to create nested calm instruction on the fly, for executing code at "assembly time". So the calm that defined such nested calm is already defined. Something like this. Code: calminstruction calminstruction?._exec_once? command?*& ; ... end calminstruction holder = $00 calminstruction poc_1? _exec_once { compute holder, $01 } end calminstruction display holder+"0", $0A ; display 1 without execution poc_1 The only solution that I see, is to declare a nested calminstruction with random name that contain the code betweem brace and execute it. This allow me to do a kind of preprocessing at the time of CALM compilation. But unfortunately, I don't know if _exec_once can declare such thing. Code: debug? := $01 macro calminstruction?._asmcmd? invoke?*, command?*& local invoke arrange invoke, command assemble invoke end macro retaincomments calminstruction poc_1? _exec_once {\ check (debug) ;\ jyes next ;\ exit ;\ next: ;\ _amcmd invoke, =_asmcmd =invoke, ===display "DEBUG ON", $0A ;\ } end calminstruction removecomments poc_1 thanks best regard Last edited by MaoKo on 01 Mar 2020, 14:07; edited 2 times in total |
|||
28 Feb 2020, 18:56 |
|
Tomasz Grysztar 28 Feb 2020, 19:59
MaoKo wrote: Yes I agree. But what I want is not to declare calm inside another declaration. In fact, I wanted to create nested calm instruction on the fly, for executing code at "assembly time". So the calm that defined such nested calm is already defined. (...) |
|||
28 Feb 2020, 19:59 |
|
Tomasz Grysztar 28 Feb 2020, 20:13
For your specific example of "exec_once" I can propose the following solution:
Code: define _global calminstruction calminstruction?._exec_once? command?*& take _global._exec_once, command end calminstruction calminstruction calminstruction.end? instruction local command, buffer arrange command, =end instruction assemble command arrange command, =calminstruction =__tmp assemble command reverse: take buffer, _global._exec_once jyes reverse exec: take command, buffer jno done assemble command jump exec done: arrange command, =end =calminstruction assemble command arrange command, =__tmp assemble command end calminstruction holder = $00 calminstruction poc_1? _exec_once compute holder, $01 end calminstruction display holder+"0", $0A ; display 1 without execution poc_1 As I noted earlier, the only general solution would be to define a customized language for definitions with set of macros that would only collect and prepare statements, and at the end construct the actual CALM definitions and pass them to assembler. |
|||
28 Feb 2020, 20:13 |
|
MaoKo 29 Feb 2020, 09:48
Thank you. As always, you find a solution .
I'm not thinking about redefining calminstruction?.end? instruction. But what do you mean by a set of macro for definition? Also I'm going to be off topics, for the remaining line. I'v seen that you can do stuff like that: Code: calminstruction abc? arrange A, =I, =J, =K compute B, $02 publish A, B end calminstruction I think that it's a great feature to assign to the first identifier. But I've not seen this in the man. Do you think that I can reliably use this feature? Thanks best regard |
|||
29 Feb 2020, 09:48 |
|
Tomasz Grysztar 29 Feb 2020, 10:06
MaoKo wrote: But I've not seen this in the man. Do you think that I can reliably use this feature? |
|||
29 Feb 2020, 10:06 |
|
MaoKo 02 Mar 2020, 12:06
Hello!
Currently, I'm trying go further the above solution for allowing _execonce to do execution on the "fly". The solution given above work pretty fine with many situation, but postponed execution may include subtle behavior. Code: debug = $00 calminstruction calminstruction?._initsym? target?*, value?& publish target, value end calminstruction calminstruction calminstruction?._incdebg? compute debug, debug + $01 end calminstruction calminstruction calminstruction?._ensure? local target, holder, A _initsym _A, A arrange A, =INT3 arrange holder, =_execonce =arrange _A, ===compute ===variable, $01 assemble holder assemble A end calminstruction calminstruction poc? _incdebg _initsym random, $00 _ensure end calminstruction The problem here is that the instruction INT3 will be executed because arrange A, compute ... is executed at end. I'm also trying to use almost everytime the bare bone calm instruction set. I've thinking about sandboxing the instructions one by one the see if the assemble of _execonce can occur. Something like this (simplified version): Code: calminstruction calminstruction? prefix?*, arguments?& ; ... ; create calminstruction ?! line?& ; if end calminstruction encounter ; create calminstruction prefix with all line collected ; purge of ? ; exit ; calminstruction sandbox? ; line ; end calminstruction ; purge of sandbox? end calminstruction The problem with this is that such calmcode like _incdedb is executed 2 time and therefore inc debug 2 time. Another theoritical solution will be: Code: calminstruction calminstruction?._execonce? command?*& _asmcmd invoke, =end =calminstruction _asmcmd invoke, =calminstruction =calminstruction?.=__tmp? _asmcmd invoke, command _asmcmd invoke, =end =calminstruction _asmcmd invoke, =calminstruction ; current calminstruction name _asmcmd invoke, =__tmp end calminstruction But the problem here is that previous declaration (eg: "init symbl, $01") will be lost. I've no idea how to do to that. I can declare a subset mini language but I don't known if it's will be useful. If someone have an idea? regard |
|||
02 Mar 2020, 12:06 |
|
Tomasz Grysztar 02 Mar 2020, 12:29
I'm not sure what is your actual goal here, but once the macros start to resemble a multi-layered spaghetti, it is often a signal that it might not be a good way to approach the problem (at least not in case of fasmg, as opposed to fasm 1 where limitations of language really pushed the obscure solutions). What are you trying to accomplish with this?
|
|||
02 Mar 2020, 12:29 |
|
MaoKo 02 Mar 2020, 13:01
The ideal solution would be to replace in a dynamic fashion each _execonce with some nested calminstruction.
In an instruction that "assemble" _execonce, I would like to execute it not a the end. Because possibly an "assembly time" variable after the instruction can use some value created by the _execonce instruction. But as you stated, it's impossible to declare an instruction while another instruction is currently declared. So, it's pretty difficult but I hope it's not impossible. Code: calminstruction calminstruction?._poc_1? local A init build, _execonce arrange A, =compute =B, $01 init A, ERROR assemble build assemble A ; Here ERROR (but I want to "compute" to be executed) end calminstruction calminstruction _poc_2? _poc_1 end calminstruction |
|||
02 Mar 2020, 13:01 |
|
Tomasz Grysztar 02 Mar 2020, 13:36
I was really asking about what original problem you had that you are trying to solve this way. Because seeing this line:
Code: arrange holder, =_execonce =arrange _A, ===compute ===variable, $01 |
|||
02 Mar 2020, 13:36 |
|
MaoKo 02 Mar 2020, 14:20
Yes I agree with you that this line is pretty awful. But I really need this feature for my lib.
I made two distinction about what is executed at (assembly/compile time) and runtime in my lib. The tilde say "at assembly time". (_xcalm_exec ~ = _execonce) So for instance: Code: calminstruction test? _xcalm_init ~ [symbl] A, B ; declare a symbol A that point to B (like init in calm package) _xcalm_init ~ [symbl] B, C _xcalm_init ~ [symbl] C, D ; so now we are a chain like this A -> B -> C -> D ; I want to transform A so that A -> D (so 2 time transform) _xcalm_exec ~ [rpeat:2] { transform A } ; This is why I need execonce because I don't want generate code here _xcalm_init ~ [symbl|const] E, [expnd] A ; E = D ([expnd] expand behave like arrange does) end calminstruction _execonce need to create dynamicly a nested calminstruction and afterward call it. I can't wait the end of test for exec the "_execonce" otherwise E would have the B value. But sometime I use _execonce in nested calm in more complex form: Code: calminstruction calminstruction?.duptop_5? target?* arrange duplicate, target transform duplicate _xcalm_exec { _xcalm_exec ~ [rpeat:5] { publish :target, duplicate } } ; exec without ~ is the normal exec that generate an "assemble" statement end calminstruction The problem is to implement (_xcalm_exec ~). |
|||
02 Mar 2020, 14:20 |
|
Tomasz Grysztar 02 Mar 2020, 14:26
Perhaps instead you should implement _xcalm_init in such way, that it would only get executed at the end of definition, together with _xcalm_exec? In fact, you could probably make a wrapper that would convert _xcalm_init into _xcalm_exec line, and then all these statements would be _xcalm_exec statements, solving the problem of out-of-sync execution.
|
|||
02 Mar 2020, 14:26 |
|
MaoKo 02 Mar 2020, 14:33
Yes, I've thinking about that too. But if an user want to make it's own init calminstruction?
This make portability with other libs more difficult. What do you think? |
|||
02 Mar 2020, 14:33 |
|
MaoKo 02 Mar 2020, 14:34
But peraphs for now, it would be suffice.
|
|||
02 Mar 2020, 14:34 |
|
Tomasz Grysztar 02 Mar 2020, 14:39
_xcalm_exec is more general than _xcalm_init, you can always customize the internal instruction that gets executed with _xcalm_exec. You _xcalm_init could just be a shortcut to something like "_xcalm_exec _xcalm__init ...".
|
|||
02 Mar 2020, 14:39 |
|
MaoKo 02 Mar 2020, 14:49
Ok. Thank you, you help me alot. I think that I will try to create a calminstruction ?! that look for predefined instruction and if not it will prefix by _xcalm_exec. I need also to check if a user redefined predefined instruction too but this will not be so difficult.
|
|||
02 Mar 2020, 14:49 |
|
Tomasz Grysztar 02 Mar 2020, 14:51
Once you use an "?!" interceptor, you may collect the lines directly and not even need a separate _xcalm_exec macro then.
|
|||
02 Mar 2020, 14:51 |
|
MaoKo 02 Mar 2020, 17:40
A problem that arise too is if you want to include some conditional block.
If the collected line is executed in front or back the order may be broken: Code: debug_v1 = $00 debug_v2 = $01 retaincomments calminstruction abc? local buffer _exec_xcalm ~ {\ check (debug_v1) ;\ jyes next_1 ;\ exit ;\ next_1: ;\ _exec_xcalm { display "DEBUG V1 ON } ;\ } arrange buffer, =display "MIDDLE" assemble buffer _exec_xcalm ~ {\ check (debug_v2) ;\ jyes next_2 ;\ exit ;\ next_2: ;\ _exec_xcalm { display "DEBUG V2 ON } ;\ } arrange buffer, =display "END" assemble buffer end calminstruction removecomments Peraphs I need to take 3 pass. The first pass to collect all instruction. The second pass to collect all instruction issue with _execonce. And the latter to build the real calminstruction with good order. But if somme instruction update somme global variable, it's update twice . |
|||
02 Mar 2020, 17:40 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.