Skip to content

Commit

Permalink
Merge pull request #7 from Megatokio/literal-text-replacement-in-macro
Browse files Browse the repository at this point in the history
Literal text replacement in macro
  • Loading branch information
Megatokio authored Jan 8, 2020
2 parents cadea88 + 0fc947d commit f1424ad
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 23 deletions.
14 changes: 12 additions & 2 deletions Documentation/Version History.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,15 @@ pre 1.0.0 1996: First version for private use. Mac OS 7.0. No public release.
4.0.20 2017: minor rework of c-compiler handling, bug fixes
4.0.21 2017: allow multiple opcodes per line after '\'
4.0.24 2017: define NAME_size and NAME_end labels for all segments
4.1.0 2017: included Einar Saukas' ZX7 "optimal" LZ77 compressor

4.1.0 2017: included Einar Saukas' ZX7 "optimal" LZ77 compressor
4.1.2 2017: fixed problems with compressed size validity
4.1.3 2017: new function sin() and cos() to easily build wave tables
4.1.4 2017: added pseudo instructions DUP and EDUP as an alias for REPT and ENDM
4.1.5 2017: reworked the regression test framework. Added support for '#!' in line 1 of the source file
4.2.0 2018: new #target TZX: directly write to .tzx tape files
4.2.1 2018: Bug fixes. This was to be expected.
4.2.2 2018: Fixed bug where the binary file was appended to the hex or s19 file
4.2.3 2018: Fixed bug where error messages were garbled
4.2.4 2019: Fixed bug in .rept/.endm or .dup/.edup sanity check
4.2.6 2020: added text replacement in macros for values between '{' and '}'.

Empty file modified Documentation/automate.vs
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions Documentation/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<td> <a href="javascript:history.back()"><img src="b/left.gif" style="border:hidden;" width=11 height=20 alt="&lt;--"></a> </td>
<td> &nbsp;<a href="javascript:history.back()">back</a> </td>
<td width="100%"> &nbsp; </td>
<td style="white-space:nowrap;"> <i>Last regenerated: 2018-05-27 22:10:33 kio</i> </td>
<td style="white-space:nowrap;"> <i>Last regenerated: 2020-01-08 17:18:33 kio</i> </td>
</tr></table>


Expand All @@ -43,7 +43,7 @@ <h1 class="head"><a href="index.html">Table of Contents</a></h1>
<p><a href="z85.htm#A">Targets</a></p>
<p><a href="z117.htm#A">List File</a></p>
<p><a href="z118.htm#A">Legal and Version History</a></p></div>
<p class=c><i>Last updated: 2018-05-27 22:10:33.</i></p>
<p class=c><i>Last updated: 2020-01-08 17:18:33.</i></p>
<p><b class=red>zasm</b> is a multiple pass <a class=L href="z84.htm#A">assembler</a> for the historic 8-bit CPU <i>Zilog <span class=LL id=D><a href="z17.htm#A">Command Line Options: --z80</a><br><a href="z67.htm#A">Pseudo instructions: .z80, .z180 and .8080</a><br><a href="z89.htm#A">Targets: #target Z80</a></span><a class=L href="javascript:S('D')">Z80</a></i> and it's variants, e.g. <i>Intel 8080</i> (it's predecessor) or the <i><span class=LL id=E><a href="z18.htm#A">Command Line Options: --z180</a><br><a href="z67.htm#A">Pseudo instructions: .z80, .z180 and .8080</a></span><a class=L href="javascript:S('E')">Z180</a> / HD64180</i>.</p>
<p><b class=red>zasm</b> is available for Unix-like operating systems like OSX, Linux, BSD.</p>
<p class=b>Download page and Git archive:</p>
Expand Down
48 changes: 35 additions & 13 deletions Documentation/macro endm.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@

h3 macro, .macro, endm and .endm
macro, endm

p 'macro' starts a macro definition and 'endm' terminates it. Macros are assigned a name by which they can later be used at the place of an ordinary instruction.

p There are quite numerous formats used by different assemblers and zasm tries to support at least some of them out of the box. In the following code examples the instruction names with or without a dor can be used interchangeable.
p 'macro' starts a macro definition and 'endm' terminates it. Macros are assigned a name by which they can later be used at the place of an ordinary instruction.

p There are quite numerous formats used by different assemblers and zasm tries to support at least some of them out of the box. In the following code examples the instruction names with or without a dot can be used interchangeably.

p Frequently you need some kind of label in a macro, but you cannot redefine ordinary labels. Frequently this can be solved with redefinable labels which are defined with 'defl' or 'set'.

p Since version 4.2.6 expressions between '{' and '}' are evaluated and replaced with the resulting text. This can be used to generate label names. The expression must be evaluatable in pass 1 because macro replacement is done in pass 1.

p It is possible to conditionally exclude portions of the macro by use of the pseudo instructions 'if' and 'endif'. (<u>not</u> '#if' and '#endif'!)

p Assembler directives (starting with '#') are not allowed inside macros.


h5 Define a simple macro without arguments

pre <name> macro
pre <name> macro
<instr>
...
endm

p Alternate syntax:

pre macro <name>
pre macro <name>
<instr>
...
endm
Expand All @@ -33,7 +35,7 @@ pre counter defl 0
COUNT .macro
counter defl counter + 1
.endm
 

...

COUNT
Expand All @@ -50,9 +52,9 @@ pre <name> macro <name1> [ , <name2> … ]
<instr>
...
endm

p Alternate syntax:

pre macro <name> <name1> [ , <name2> … ]
<instr>
...
Expand All @@ -61,7 +63,7 @@ pre macro <name> <name1> [ , <name2> … ]
p Invocation:

pre <name> <some text> [ , <some text> … ]

p This defines a macro with some arguments. Either of both definition styles are possible. Additionally there are different methods for defining and referencing the symbol arguments:

pre foo: macro A, B
Expand Down Expand Up @@ -104,7 +106,7 @@ pre foo: macro &A
foo 20
...
foo 8

p In this example the argument is used as the second argument for 'ld b,N' and to construct a unique label name for each invocation. Obviously the passed argument must be a number literal else the label name thing won't work. A better solution would have been to use a redefinable label.


Expand All @@ -126,10 +128,30 @@ p Complex arguments start with an opening '<' and run up to the next '>' which i
pre foo <,>, <;>, <"> ; 3 arguments: , ; and "
foo <<>, < >, <ld a,b> ; 3 arguments: < space and ld a,b
foo >, ><, ; 3 arguments: > >< and nothing

p There are still some impossible combinations, e.g. it is not possible to pass <b class=blue><>,</b> (3 characters) as an argument.


h5 Evaluation and literal text replacement of expresions
p.i since versio 4.2.6

pre L: .equ 0 ; initialize redefinable label 'L'

; calculate unsigned max
; &A = umax(&A,&B)
; usable for a and hl.

umax: .macro &A, &B
and a
sbc &A,&B
jr nc,L{L} ; e.g. L0 in first call
ld &A,&B
jr L{L+1} ; e.g. L1 in first call
L{L}: add &A,&B
L{L+1}:
L .equ L+2 ; next macro call will use L2 and L3
.endm


h5 Not implemented in macros:

Expand All @@ -142,7 +164,7 @@ li keyword 'local': try to use 'defl' instead. (not possible in all cases)







1 change: 1 addition & 0 deletions Linux/zasm.pro
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ HEADERS += \
Source/Segment.h \
Source/settings.h \
Source/Source.h \
Source/Value.h \
Source/zx7.h \
Source/SyntaxError.h \
Source/Z80Assembler.h \
Expand Down
2 changes: 2 additions & 0 deletions Source/Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ cstr SourceLine::nextWord ()
case ')': return ")";
case ',': return ",";
case '=': return "=";
case '{': return "{";
case '}': return "}";

case '\'': // 'abcd' ''' or ''
if (*p==c) { p++; if (*p!=c) return "''"; p++; return "'''"; } // special test for '''
Expand Down
22 changes: 19 additions & 3 deletions Source/Z80Assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2151,7 +2151,7 @@ void Z80Assembler::asmMacroCall (SourceLine& q, Macro& m) throws
{
SourceLine& s = zsource[i];

for (int32 j=0;;j++) // loop over occurance of '&'
for (ssize_t j=0;;j++) // loop over occurance of '&'
{
cptr p = strchr(s.text+j,m.tag); // at next '&'
if (!p) break; // no more '&'
Expand All @@ -2166,9 +2166,25 @@ void Z80Assembler::asmMacroCall (SourceLine& q, Macro& m) throws
// w is the name of argument #a
// it was found starting at p+1 in s.text (p points to the '&')

j = p + strlen(rpl[a]) - s.text;
s.text = catstr(substr(s.text,p), rpl[a], s.p);
j = p + strlen(rpl[a]) - s.text; // calculate index j after text replacement
s.text = catstr(substr(s.text,p), rpl[a], s.p); // … because this reallocates s.text!
}

// calculate and replace values between '{' and '}' with plain text:
// e.g. for calculated label names in macros.
for (ssize_t j=0;;j++) // loop over occurrences of '{'
{
cptr p = strchr(s.text+j,'{'); // at next '{'
if (!p) break; // no more '{'
s.p = p+1; // set the parser position behind '{'
Value v = value(s, pAny); // get the value
s.expect('}');
if (!v.is_valid()) throw syntax_error("value must be valid in pass 1"); // because replacement is done in pass 1
cstr rpl = numstr(v.value); // textual replacement
j = p + strlen(rpl) - s.text; // calculate index j after text replacement
s.text = catstr(substr(s.text,p), rpl, s.p); // … because this reallocates s.text!
}

s.rewind(); // superflux. but makes s.p valid
}

Expand Down
6 changes: 3 additions & 3 deletions Source/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) Günter Woigk 1994 - 2019
/* Copyright (c) Günter Woigk 1994 - 2020
mailto:[email protected]
This file is free software
Expand Down Expand Up @@ -44,14 +44,14 @@


//static const char appl_name[] = "zasm";
static const char version[] = "4.2.5";
static const char version[] = "4.2.6";

// Hilfstext:
// Anzeige optimiert für 80-Zeichen-Terminal
//
static const char help[] =
"–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––\n"
" zasm - z80/8080 assembler (c) 1994 - 2019 Günter Woigk.\n"
" zasm - z80/8080 assembler (c) 1994 - 2020 Günter Woigk.\n"
" version %s, %s, for %s.\n" // version, date, platform
" homepage: https://k1.spdns.de/Develop/Projects/zasm/\n"
" send bug reports to: [email protected]\n\n"
Expand Down
165 changes: 165 additions & 0 deletions Test/Z80/callstack.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/local/bin/zasm -o original/

ORG $0000

_STACK_SIZE DEFL 0
_PARAM_COUNT_0 DEFL 0 ;Redefinable labels initialization


;Adds the content of &reg to the stack and increment the _PARAM_COUNT_0 label.
MACRO _ADD_PARAM &reg
PUSH &reg
_PARAM_COUNT_0 DEFL {_PARAM_COUNT_0+1}
ENDM

;Adds a litteral 16 bits parameter to the stack then increment the
;_PARAM_COUNT_0 label. Register values are preserved.
MACRO _ADD_LPARAM &lit
PUSH HL
LD HL,&lit
EX (SP),HL
_PARAM_COUNT_0 DEFL {_PARAM_COUNT_0+1}
ENDM

;Macro that calls a procedure &proc. This macro cleans the stack from the
;parameters added with _ADD_PARAM or ADD_LPARAM. Register HL and DE may be
;changed if the subroutine returns respectively a 16 or 32 bits value.
MACRO _CALL &proc
_PUSH_STACK
CALL &proc
_POP_STACK
_CLEAN_PARAMS {_PARAM_COUNT_0}
_PARAM_COUNT_0 DEFL 0
ENDM

;Increments the _STACK_SIZE label and shift _PARAM_COUNT_# labels value to
;_PARAM_COUNT_#+1, up to _PARAM_COUNT_{STACK_SIZE}, then save all the Z80
;registers on the stack.
MACRO _PUSH_STACK
_STACK_SIZE DEFL {_STACK_SIZE+1}
_SHIFT_STACK {_STACK_SIZE+1}
CALL _PUSH
ENDM

;Shift _PARAM_COUNT_# values up the stack.
MACRO _SHIFT_STACK &cnt
IF &cnt > 0
_PARAM_COUNT_{&cnt} DEFL _PARAM_COUNT_{&cnt-1}
_PARAM_COUNT_{&cnt-1} DEFL 0
_SHIFT_STACK {&cnt-1}
ENDIF
ENDM

;Shift _PARAM_COUNT_# down the stack and then restores Z80 registers. Then
;decrement _STACK_SIZE label.
MACRO _POP_STACK
_UNSHIFT_STACK _STACK_SIZE
_STACK_SIZE DEFL {_STACK_SIZE-1}
CALL _POP
ENDM

;Shift _PARAM_COUNT_# values down the stack.
MACRO _UNSHIFT_STACK &cnt
IF &cnt > 0
_PARAM_COUNT_{&cnt-1} DEFL _PARAM_COUNT_{&cnt}
_PARAM_COUNT_{&cnt} DEFL 0
_UNSHIFT_STACK {&cnt-1}
ENDIF
ENDM


;Macro that cleans &count parameters from the stack.
MACRO _CLEAN_PARAMS &cnt
IF &cnt > 0
EX (SP),HL
POP HL
_CLEAN_PARAMS {&cnt-1}
ENDIF
ENDM


;Loads the register &reg with the parameter at index &idx
;Since IY is used to get at parameters, its not possible to load
;a parameter into IY using this macro.
MACRO _GET_PARAM &reg, &idx
LD IY,14
ADD IY,SP
LD &reg, (IY+{&idx*2})
ENDM


;Return the content of &reg1 at the stack position of HL. The content of IY
;can not be returned using this macro.
MACRO _RET_HL &reg1
LD IY,0
ADD IY,SP
LD (IY+12),&reg1
RET
ENDM



;Return the content of &reg1 at the stack position of HL and the
;content of &reg2 at the DE stack position. The content of IY canot
;be returned by this macro.
MACRO _RET_HLDE &reg1, &reg2
LD IY,0
ADD IY,SP
LD (IY+12),&reg1
LD (IY+10),&reg2
RET
ENDM


;Save all registers
_PUSH: EX (SP),HL
PUSH DE
PUSH BC
PUSH AF
PUSH IY
PUSH IX
PUSH HL
RET


;restore all registers
_POP: POP HL
POP IX
POP IY
POP AF
POP BC
POP DE
EX (SP),HL
RET


; *** Actual test starts here ***

_ADD_LPARAM 6 ;param 2
_ADD_LPARAM 5 ;param 1
_CALL EXP

LOOP: JR LOOP


;Make parameter 1 exponent parameter 2. I.E. Param1 is the base and param2
;is the exponent. Returns value in HL.
EXP: _GET_PARAM DE,1 ;base
_GET_PARAM HL,1 ;initialize HL with base
_GET_PARAM BC,2 ;exponent
EXP_1: _ADD_PARAM DE
_ADD_PARAM HL
_CALL MUL
DEC BC
JR NZ,EXP_1
_RET_HL HL


;Multiply parameter 1 with parameter 2. Returns result in HL.
MUL: _GET_PARAM DE,1
_GET_PARAM BC,2
LD HL,0
MUL_1: ADD HL,DE
DEC BC
JR NZ,MUL_1
_RET_HL HL
Binary file added Test/Z80/original/callstack.rom
Binary file not shown.

0 comments on commit f1424ad

Please sign in to comment.