I still need to read the nano-pass paper, but the kestrel computing github.io link seems to be dead.
I'm at the point of needing to add macros to my assembler. Curious how you might be approaching it for yours.
At the same time I need to add things like IF etc. (macros aren't completely pointless without conditional assembly, but…almost).
And along with conditional assembly I need to add "local" labels.
It's been a thought exercise to now, and I think I finally have an approach.
I contemplated just trying to use something like m4(1) from Unix, but I just don't like it. It might be fine for simple macros, but not for conditional assembly, as it has no insight into the values of things like labels and what not. So, in the end I need to tear in to my assembler, and may as well put macros in to it.
Right now, as I mentioned before, take the raw text, as a list of lines, and run them through my lexer which produces a blob of tokens.
I thought about adding a macro expansion phase between the lex phase and parse phase. But macro expansion requires both.
So, the expansion will happen during the parse phase.
During macro definitions, I will just capture the tokens found between the .macro and .endmacro directive, along with a header detailing the macro definition.
Macro expansions will happen inline. When I encounter a macro invocation, I'll capture the argument list. Then I'll literally "print" the tokens captured during macro expansion in to text, do the parameter substitution, run the lexer on them, then feed them in to the parsers token stream.
Currently, the parser is simply iterating on the token collection passed to it. Instead, I'll add a stack of token collections for the parser to get it's next token from, and then each nested macro expansion will just stuff it's expanded tokens collection on to the stack.
The clever part of my plan is I'll just be using the assembler directives to do the work. In many ways, save the actual detection for expansion, the parser does not have a "macro runtime". The macro expands in to instructions to the assembler, just like normal. Things like parameters and such
So, for this crude example something like this:
Code: Select all
.MACRO INCR addr, inc
.IF %0 = 2 ;; inc is optional, %0 is number of args, check if we have 2 args
CLC
LDA addr
ADC #inc
STA addr
BCC done
INC addr + 1
.ELSE
INC addr
BNE DONE
INC addr +1
.ENDIF
DONE
.ENDM
During expansion: INCR mylabel, 2 expands to:
Code: Select all
%0 = 2 ;; number of arguments
%1 = mylabel
%2 = 2
.IF %0 = 2
CLC
LDA mylabel
ADC #2
STA mylabel
BCC done
INC mylabel + 1
.ELSE
INC mylabel
BNE DONE
INC mylabel +1
.ENDIF
DONE
The parser needs to already know about things like .IF etc. So, the macro expansion is basically "stupid" and "literal", leaving the heavy lifting to the parser itself.
Mind this is only partially thought out.
But that's my plan so far. See how it pans out.