1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-10 19:29:45 +00:00

Merge pull request #232 from greg-king5/arg-count

Fix ca65's ".paramcount" Assembly-code read-only variable.
This commit is contained in:
Oliver Schmidt 2015-11-17 21:23:30 +01:00
commit d54e515e08
3 changed files with 259 additions and 240 deletions

View File

@ -2,8 +2,9 @@
<article>
<title>ca65 Users Guide
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
<date>2015-08-01
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:greg.king5@verizon.net" name="Greg King">
<date>2015-11-17
<abstract>
ca65 is a powerful macro assembler for the 6502, 65C02, and 65816 CPUs. It is
@ -3960,10 +3961,10 @@ When using macro parameters, macros can be even more useful:
.macro inc16 addr
clc
lda addr
adc #$01
adc #<$0001
sta addr
lda addr+1
adc #$00
adc #>$0001
sta addr+1
.endmacro
</verb></tscreen>
@ -3981,10 +3982,10 @@ will be expanded to
<tscreen><verb>
clc
lda $1000
adc #$01
adc #<$0001
sta $1000
lda $1000+1
adc #$00
adc #>$0001
sta $1000+1
</verb></tscreen>
@ -4019,7 +4020,7 @@ Look at this example:
.endmacro
</verb></tscreen>
This macro may be called as follows:
That macro may be called as follows:
<tscreen><verb>
ldaxy 1, 2, 3 ; Load all three registers
@ -4029,9 +4030,9 @@ This macro may be called as follows:
ldaxy , , 3 ; Load y only
</verb></tscreen>
There's another helper command for determining, which macro parameters are
valid: <tt><ref id=".PARAMCOUNT" name=".PARAMCOUNT"></tt> This command is
replaced by the parameter count given, <em/including/ intermediate empty macro
There's another helper command for determining which macro parameters are
valid: <tt><ref id=".PARAMCOUNT" name=".PARAMCOUNT"></tt>. That command is
replaced by the parameter count given, <em/including/ explicitly empty
parameters:
<tscreen><verb>
@ -4056,10 +4057,10 @@ case of a macro parameter).
</verb></tscreen>
In the first case, the macro is called with two parameters: '<tt/(&dollar;00/'
and 'x)'. The comma is not passed to the macro, since it is part of the
and '<tt/x)/'. The comma is not passed to the macro, because it is part of the
calling sequence, not the parameters.
In the second case, '(&dollar;00,x)' is passed to the macro, this time
In the second case, '<tt/(&dollar;00,x)/' is passed to the macro; this time,
including the comma.
@ -4112,15 +4113,15 @@ Macros may be used recursively:
.macro push r1, r2, r3
lda r1
pha
.if .paramcount > 1
.ifnblank r2
push r2, r3
.endif
.endmacro
</verb></tscreen>
There's also a special macro to help writing recursive macros: <tt><ref
id=".EXITMACRO" name=".EXITMACRO"></tt> This command will stop macro expansion
immediately:
There's also a special macro command to help with writing recursive macros:
<tt><ref id=".EXITMACRO" name=".EXITMACRO"></tt>. That command will stop macro
expansion immediately:
<tscreen><verb>
.macro push r1, r2, r3, r4, r5, r6, r7
@ -4135,7 +4136,7 @@ immediately:
.endmacro
</verb></tscreen>
When expanding this macro, the expansion will push all given parameters
When expanding that macro, the expansion will push all given parameters
until an empty one is encountered. The macro may be called like this:
<tscreen><verb>
@ -4154,10 +4155,10 @@ Have a look at the inc16 macro above. Here is it again:
.macro inc16 addr
clc
lda addr
adc #$01
adc #<$0001
sta addr
lda addr+1
adc #$00
adc #>$0001
sta addr+1
.endmacro
</verb></tscreen>
@ -4288,7 +4289,7 @@ don't like that, use classic macros instead:
.endmacro
</verb></tscreen>
(This is an example where a problem can be solved with both macro types).
(That is an example where a problem can be solved with both macro types).
<sect1>Characters in macros<p>
@ -4308,7 +4309,7 @@ be sure to take the translation into account.
<sect1>Deleting macros<p>
Macros can be deleted. This will not work if the macro that should be deleted
is currently expanded as in the following non working example:
is currently expanded as in the following non-working example:
<tscreen><verb>
.macro notworking
@ -4348,6 +4349,7 @@ argument to <tt>.UNDEFINE</tt> is not allowed to come from another
different commands increases flexibility.
<sect>Macro packages<label id="macropackages"><p>
Using the <tt><ref id=".MACPACK" name=".MACPACK"></tt> directive, predefined
@ -4862,6 +4864,3 @@ freely, subject to the following restrictions:
</article>

View File

@ -147,7 +147,7 @@ static int DoMacAbort = 0;
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
/* Define style macros disabled if != 0 */
/* Define-style macros disabled if != 0 */
static unsigned DisableDefines = 0;
@ -422,8 +422,8 @@ void MacDef (unsigned Style)
EnterRawTokenMode ();
NextTok ();
/* If we have a DEFINE style macro, we may have parameters in braces,
** otherwise we may have parameters without braces.
/* If we have a DEFINE-style macro, we may have parameters in parentheses;
** otherwise, we may have parameters without parentheses.
*/
if (Style == MAC_STYLE_CLASSIC) {
HaveParams = 1;
@ -475,7 +475,7 @@ void MacDef (unsigned Style)
}
}
/* For class macros, we expect a separator token, for define style macros,
/* For classic macros, we expect a separator token, for define-style macros,
** we expect the closing paren.
*/
if (Style == MAC_STYLE_CLASSIC) {
@ -485,9 +485,9 @@ void MacDef (unsigned Style)
}
/* Preparse the macro body. We will read the tokens until we reach end of
** file, or a .endmacro (or end of line for DEFINE style macros) and store
** them into an token list internal to the macro. For classic macros, there
** the .LOCAL command is detected and removed at this time.
** file, or a .endmacro (or end of line for DEFINE-style macros) and store
** them into a token list internal to the macro. For classic macros,
** the .LOCAL command is detected and removed, at this time.
*/
while (1) {
@ -752,11 +752,11 @@ ExpandParam:
FreeTokNode (Mac->Final);
Mac->Final = 0;
/* Problem: When a .define style macro is expanded within the call
/* Problem: When a .define-style macro is expanded within the call
** of a classic one, the latter may be terminated and removed while
** the expansion of the .define style macro is still active. Because
** the expansion of the .define-style macro is still active. Because
** line info slots are "stacked", this runs into a CHECK FAILED. For
** now, we will fix that by removing the .define style macro expansion
** now, we will fix that by removing the .define-style macro expansion
** immediately, once the final token is placed. The better solution
** would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
** to be called in FIFO order, but this is a bigger change.
@ -790,9 +790,11 @@ static void StartExpClassic (MacExp* E)
/* Skip the macro name */
NextTok ();
/* Read the actual parameters */
while (!TokIsSep (CurTok.Tok)) {
/* Does this invocation have any arguments? */
if (!TokIsSep (CurTok.Tok)) {
/* Read the actual parameters */
while (1) {
TokNode* Last;
/* Check for maximum parameter count */
@ -801,13 +803,12 @@ static void StartExpClassic (MacExp* E)
break;
}
/* The macro may optionally be enclosed in curly braces */
/* The macro argument optionally may be enclosed in curly braces */
Term = GetTokListTerm (TOK_COMMA);
/* Read tokens for one parameter, accept empty params */
Last = 0;
while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
TokNode* T;
/* Check for end of file */
@ -853,6 +854,7 @@ static void StartExpClassic (MacExp* E)
break;
}
}
}
/* We must be at end of line now, otherwise something is wrong */
ExpectSep ();
@ -864,9 +866,9 @@ static void StartExpClassic (MacExp* E)
static void StartExpDefine (MacExp* E)
/* Start expanding a DEFINE style macro */
/* Start expanding a DEFINE-style macro */
{
/* A define style macro must be called with as many actual parameters
/* A define-style macro must be called with as many actual parameters
** as there are formal ones. Get the parameter count.
*/
unsigned Count = E->M->ParamCount;
@ -876,10 +878,9 @@ static void StartExpDefine (MacExp* E)
/* Read the actual parameters */
while (Count--) {
TokNode* Last;
/* The macro may optionally be enclosed in curly braces */
/* The macro argument optionally may be enclosed in curly braces */
token_t Term = GetTokListTerm (TOK_COMMA);
/* Check if there is really a parameter */
@ -892,7 +893,6 @@ static void StartExpDefine (MacExp* E)
/* Read tokens for one parameter */
Last = 0;
do {
TokNode* T;
/* Get the next token in a node */
@ -936,7 +936,7 @@ static void StartExpDefine (MacExp* E)
}
/* Macro expansion will overwrite the current token. This is a problem
** for define style macros since these are called from the scanner level.
** for define-style macros since these are called from the scanner level.
** To avoid it, remember the current token and re-insert it, once macro
** expansion is done.
*/
@ -1007,8 +1007,8 @@ Macro* FindMacro (const StrBuf* Name)
Macro* FindDefine (const StrBuf* Name)
/* Try to find the define style macro with the given name and return it. If no
** such macro was found, return NULL.
/* Try to find the define-style macro with the given name; and, return it.
** If no such macro was found, return NULL.
*/
{
Macro* M;
@ -1034,7 +1034,7 @@ int InMacExpansion (void)
void DisableDefineStyleMacros (void)
/* Disable define style macros until EnableDefineStyleMacros is called */
/* Disable define-style macros until EnableDefineStyleMacros() is called */
{
++DisableDefines;
}
@ -1042,8 +1042,8 @@ void DisableDefineStyleMacros (void)
void EnableDefineStyleMacros (void)
/* Re-enable define style macros previously disabled with
** DisableDefineStyleMacros.
/* Re-enable define-style macros previously disabled with
** DisableDefineStyleMacros().
*/
{
PRECONDITION (DisableDefines > 0);

View File

@ -0,0 +1,20 @@
; Test ca65's handling of the .paramcount read-only variable.
; .paramcount should see all given arguments, even when they are empty.
.macro push r1, r2, r3, r4, r5, r6
.out .sprintf(" .paramcount = %u", .paramcount)
.if .paramcount <> 0
.ifblank r1
.warning "r1 is blank!"
.exitmacro
.endif
lda r1
pha
push r2, r3, r4, r5, r6
.endif
.endmacro
push 1, , {}
push 1, ,
push 1