mirror of
https://github.com/cc65/cc65.git
synced 2025-01-01 03:30:20 +00:00
Finished implemenation of commands to delete macros. Added the new commands to
the docs. git-svn-id: svn://svn.cc65.org/cc65/trunk@5050 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
eaa45269e7
commit
d1426aaa43
202
doc/ca65.sgml
202
doc/ca65.sgml
@ -2113,7 +2113,22 @@ Here's a list of all control commands and a description, what they do:
|
||||
Start a define style macro definition. The command is followed by an
|
||||
identifier (the macro name) and optionally by a list of formal arguments
|
||||
in braces.
|
||||
See section <ref id="macros" name="Macros">.
|
||||
See also the <tt><ref id=".UNDEFINE" name=".UNDEFINE"></tt> command and
|
||||
section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.DELMAC, .DELMACRO</tt><label id=".DELMACRO"><p>
|
||||
|
||||
Delete a classic macro (defined with <tt><ref id=".MACRO"
|
||||
name=".MACRO"></tt>) . The command is followed by the name of an
|
||||
existing macro. Its definition will be deleted together with the name.
|
||||
If necessary, another macro with this name may be defined later.
|
||||
|
||||
See: <tt><ref id=".ENDMACRO" name=".ENDMACRO"></tt>,
|
||||
<tt><ref id=".EXITMACRO" name=".EXITMACRO"></tt>,
|
||||
<tt><ref id=".MACRO" name=".MACRO"></tt>
|
||||
|
||||
See also section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.DEF, .DEFINED</tt><label id=".DEFINED"><p>
|
||||
@ -2125,7 +2140,7 @@ Here's a list of all control commands and a description, what they do:
|
||||
<tt><ref id=".IFDEF" name=".IFDEF"></tt> statement may be replaced by
|
||||
|
||||
<tscreen><verb>
|
||||
.if .defined(a)
|
||||
.if .defined(a)
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
@ -2201,7 +2216,13 @@ Here's a list of all control commands and a description, what they do:
|
||||
|
||||
<sect1><tt>.ENDMAC, .ENDMACRO</tt><label id=".ENDMACRO"><p>
|
||||
|
||||
End of macro definition (see section <ref id="macros" name="Macros">).
|
||||
Marks the end of a macro definition.
|
||||
|
||||
See: <tt><ref id=".DELMACRO" name=".DELMACRO"></tt>,
|
||||
<tt><ref id=".EXITMACRO" name=".EXITMACRO"></tt>,
|
||||
<tt><ref id=".MACRO" name=".MACRO"></tt>
|
||||
|
||||
See also section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.ENDPROC</tt><label id=".ENDPROC"><p>
|
||||
@ -2315,7 +2336,13 @@ Here's a list of all control commands and a description, what they do:
|
||||
<sect1><tt>.EXITMAC, .EXITMACRO</tt><label id=".EXITMACRO"><p>
|
||||
|
||||
Abort a macro expansion immediately. This command is often useful in
|
||||
recursive macros. See separate section <ref id="macros" name="Macros">.
|
||||
recursive macros.
|
||||
|
||||
See: <tt><ref id=".DELMACRO" name=".DELMACRO"></tt>,
|
||||
<tt><ref id=".ENDMACRO" name=".ENDMACRO"></tt>,
|
||||
<tt><ref id=".MACRO" name=".MACRO"></tt>
|
||||
|
||||
See also section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.EXPORT</tt><label id=".EXPORT"><p>
|
||||
@ -3081,13 +3108,26 @@ Here's a list of all control commands and a description, what they do:
|
||||
id="macropackages" name="Macro packages">.
|
||||
|
||||
|
||||
<sect1><tt>.MAC, .MACRO</tt><label id=".MAC"><p>
|
||||
<sect1><tt>.MAC, .MACRO</tt><label id=".MACRO"><p>
|
||||
|
||||
Start a classic macro definition. The command is followed by an identifier
|
||||
(the macro name) and optionally by a comma separated list of identifiers
|
||||
that are macro parameters.
|
||||
that are macro parameters. A macro definition is terminated by <tt><ref
|
||||
id=".ENDMACRO" name=".ENDMACRO"></tt>.
|
||||
|
||||
See section <ref id="macros" name="Macros">.
|
||||
Example:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro ldax arg ; Define macro ldax
|
||||
lda arg
|
||||
ldx arg+1
|
||||
</verb></tscreen>
|
||||
|
||||
See: <tt><ref id=".DELMACRO" name=".DELMACRO"></tt>,
|
||||
<tt><ref id=".ENDMACRO" name=".ENDMACRO"></tt>,
|
||||
<tt><ref id=".EXITMACRO" name=".EXITMACRO"></tt>
|
||||
|
||||
See also section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.ORG</tt><label id=".ORG"><p>
|
||||
@ -3519,6 +3559,17 @@ Here's a list of all control commands and a description, what they do:
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
<sect1><tt>.UNDEF, .UNDEFINE</tt><label id=".UNDEFINE"><p>
|
||||
|
||||
Delete a define style macro definition. The command is followed by an
|
||||
identifier which specifies the name of the macro to delete. Macro
|
||||
replacement is switched of when reading the token following the command
|
||||
(otherwise the macro name would be replaced by it's replacement list).
|
||||
|
||||
See also the <tt><ref id=".DEFINE" name=".DEFINE"></tt> command and
|
||||
section <ref id="macros" name="Macros">.
|
||||
|
||||
|
||||
<sect1><tt>.WARNING</tt><label id=".WARNING"><p>
|
||||
|
||||
Force an assembly warning. The assembler will output a warning message
|
||||
@ -3599,9 +3650,9 @@ example:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro asr ; Arithmetic shift right
|
||||
cmp #$80 ; Put bit 7 into carry
|
||||
ror ; Rotate right with carry
|
||||
.endmacro
|
||||
cmp #$80 ; Put bit 7 into carry
|
||||
ror ; Rotate right with carry
|
||||
.endmacro
|
||||
</verb></tscreen>
|
||||
|
||||
The macro above consists of two real instructions, that are inserted into
|
||||
@ -3609,9 +3660,9 @@ the code, whenever the macro is expanded. Macro expansion is simply done
|
||||
by using the name, like this:
|
||||
|
||||
<tscreen><verb>
|
||||
lda $2010
|
||||
asr
|
||||
sta $2010
|
||||
lda $2010
|
||||
asr
|
||||
sta $2010
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
@ -3620,15 +3671,15 @@ by using the name, like this:
|
||||
When using macro parameters, macros can be even more useful:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro inc16 addr
|
||||
clc
|
||||
lda addr
|
||||
adc #$01
|
||||
sta addr
|
||||
lda addr+1
|
||||
adc #$00
|
||||
sta addr+1
|
||||
.endmacro
|
||||
.macro inc16 addr
|
||||
clc
|
||||
lda addr
|
||||
adc #$01
|
||||
sta addr
|
||||
lda addr+1
|
||||
adc #$00
|
||||
sta addr+1
|
||||
.endmacro
|
||||
</verb></tscreen>
|
||||
|
||||
When calling the macro, you may give a parameter, and each occurrence of
|
||||
@ -3636,19 +3687,19 @@ the name "addr" in the macro definition will be replaced by the given
|
||||
parameter. So
|
||||
|
||||
<tscreen><verb>
|
||||
inc16 $1000
|
||||
inc16 $1000
|
||||
</verb></tscreen>
|
||||
|
||||
will be expanded to
|
||||
|
||||
<tscreen><verb>
|
||||
clc
|
||||
lda $1000
|
||||
adc #$01
|
||||
sta $1000
|
||||
lda $1000+1
|
||||
adc #$00
|
||||
sta $1000+1
|
||||
clc
|
||||
lda $1000
|
||||
adc #$01
|
||||
sta $1000
|
||||
lda $1000+1
|
||||
adc #$00
|
||||
sta $1000+1
|
||||
</verb></tscreen>
|
||||
|
||||
A macro may have more than one parameter, in this case, the parameters
|
||||
@ -3669,23 +3720,23 @@ opposite.
|
||||
Look at this example:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro ldaxy a, x, y
|
||||
.ifnblank a
|
||||
lda #a
|
||||
.endif
|
||||
.ifnblank x
|
||||
ldx #x
|
||||
.endif
|
||||
.ifnblank y
|
||||
ldy #y
|
||||
.endif
|
||||
.endmacro
|
||||
.macro ldaxy a, x, y
|
||||
.ifnblank a
|
||||
lda #a
|
||||
.endif
|
||||
.ifnblank x
|
||||
ldx #x
|
||||
.endif
|
||||
.ifnblank y
|
||||
ldy #y
|
||||
.endif
|
||||
.endmacro
|
||||
</verb></tscreen>
|
||||
|
||||
This macro may be called as follows:
|
||||
|
||||
<tscreen><verb>
|
||||
ldaxy 1, 2, 3 ; Load all three registers
|
||||
ldaxy 1, 2, 3 ; Load all three registers
|
||||
|
||||
ldaxy 1, , 3 ; Load only a and y
|
||||
|
||||
@ -3786,24 +3837,24 @@ id=".EXITMACRO" name=".EXITMACRO"></tt> This command will stop macro expansion
|
||||
immediately:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro push r1, r2, r3, r4, r5, r6, r7
|
||||
.ifblank r1
|
||||
; First parameter is empty
|
||||
.exitmacro
|
||||
.else
|
||||
lda r1
|
||||
pha
|
||||
.endif
|
||||
push r2, r3, r4, r5, r6, r7
|
||||
.endmacro
|
||||
.macro push r1, r2, r3, r4, r5, r6, r7
|
||||
.ifblank r1
|
||||
; First parameter is empty
|
||||
.exitmacro
|
||||
.else
|
||||
lda r1
|
||||
pha
|
||||
.endif
|
||||
push r2, r3, r4, r5, r6, r7
|
||||
.endmacro
|
||||
</verb></tscreen>
|
||||
|
||||
When expanding this macro, the expansion will push all given parameters
|
||||
until an empty one is encountered. The macro may be called like this:
|
||||
|
||||
<tscreen><verb>
|
||||
push $20, $21, $32 ; Push 3 ZP locations
|
||||
push $21 ; Push one ZP location
|
||||
push $20, $21, $32 ; Push 3 ZP locations
|
||||
push $21 ; Push one ZP location
|
||||
</verb></tscreen>
|
||||
|
||||
|
||||
@ -3909,7 +3960,7 @@ different:
|
||||
be omitted.
|
||||
|
||||
<item> Since <tt><ref id=".DEFINE" name=".DEFINE"></tt> style macros may not
|
||||
contain end-of-line tokens, there are things that cannot be done. They
|
||||
contain end-of-line tokens, there are things that cannot be done. They
|
||||
may not contain several processor instructions for example. So, while
|
||||
some things may be done with both macro types, each type has special
|
||||
usages. The types complement each other.
|
||||
@ -3974,6 +4025,47 @@ doing more complex macros. If you compare characters against numeric values,
|
||||
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:
|
||||
|
||||
<tscreen><verb>
|
||||
.macro notworking
|
||||
.delmacro notworking
|
||||
.endmacro
|
||||
|
||||
notworking ; Will not work
|
||||
</verb></tscreen>
|
||||
|
||||
The commands to delete classic and define style macros differ. Classic macros
|
||||
can be deleted by use of <tt><ref id=".DELMACRO" name=".DELMACRO"></tt>, while
|
||||
for <tt><ref id=".DEFINE" name=".DEFINE"></tt> style macros, <tt><ref
|
||||
id=".UNDEFINE" name=".UNDEFINE"></tt> must be used. Example:
|
||||
|
||||
<tscreen><verb>
|
||||
.define value 1
|
||||
.macro mac
|
||||
.byte 2
|
||||
.endmacro
|
||||
|
||||
.byte value ; Emit one byte with value 1
|
||||
mac ; Emit another byte with value 2
|
||||
|
||||
.undefine value
|
||||
.delmacro mac
|
||||
|
||||
.byte value ; Error: Unknown identifier
|
||||
mac ; Error: Missing ":"
|
||||
</verb></tscreen>
|
||||
|
||||
A separate command for <tt>.DEFINE</tt> style macros was necessary, because
|
||||
the name of such a macro is replaced by its replacement list on a very low
|
||||
level. To get the actual name, macro replacement has to be switched off when
|
||||
reading the argument to <tt>.UNDEFINE</tt>. This does also mean that the
|
||||
argument to <tt>.UNDEFINE</tt> is not allowed to come from another
|
||||
<tt>.DEFINE</tt>. All this is not necessary for classic macros, so having two
|
||||
different commands increases flexibility.
|
||||
|
||||
|
||||
<sect>Macro packages<label id="macropackages"><p>
|
||||
|
@ -206,15 +206,39 @@ static IdDesc* NewIdDesc (const StrBuf* Id)
|
||||
/* Create a new IdDesc, initialize and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
IdDesc* I = xmalloc (sizeof (IdDesc));
|
||||
IdDesc* ID = xmalloc (sizeof (IdDesc));
|
||||
|
||||
/* Initialize the struct */
|
||||
I->Next = 0;
|
||||
SB_Init (&I->Id);
|
||||
SB_Copy (&I->Id, Id);
|
||||
ID->Next = 0;
|
||||
SB_Init (&ID->Id);
|
||||
SB_Copy (&ID->Id, Id);
|
||||
|
||||
/* Return the new struct */
|
||||
return I;
|
||||
return ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void FreeIdDesc (IdDesc* ID)
|
||||
/* Free an IdDesc */
|
||||
{
|
||||
/* Free the name */
|
||||
SB_Done (&ID->Id);
|
||||
|
||||
/* Free the structure itself */
|
||||
xfree (ID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void FreeIdDescList (IdDesc* ID)
|
||||
/* Free a complete list of IdDesc structures */
|
||||
{
|
||||
while (ID) {
|
||||
IdDesc* This = ID;
|
||||
ID = ID->Next;
|
||||
FreeIdDesc (This);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -249,6 +273,32 @@ static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
|
||||
|
||||
|
||||
|
||||
static void FreeMacro (Macro* M)
|
||||
/* Free a macro entry which has already been removed from the macro table. */
|
||||
{
|
||||
TokNode* T;
|
||||
|
||||
/* Free locals */
|
||||
FreeIdDescList (M->Locals);
|
||||
|
||||
/* Free identifiers of parameters */
|
||||
FreeIdDescList (M->Params);
|
||||
|
||||
/* Free the token list for the macro */
|
||||
while ((T = M->TokRoot) != 0) {
|
||||
M->TokRoot = T->Next;
|
||||
FreeTokNode (T);
|
||||
}
|
||||
|
||||
/* Free the macro name */
|
||||
SB_Done (&M->Name);
|
||||
|
||||
/* Free the macro structure itself */
|
||||
xfree (M);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static MacExp* NewMacExp (Macro* M)
|
||||
/* Create a new expansion structure for the given macro */
|
||||
{
|
||||
@ -552,14 +602,16 @@ Done:
|
||||
|
||||
|
||||
|
||||
void MacUndef (const StrBuf* Name)
|
||||
/* Undefine the macro with the given name. */
|
||||
void MacUndef (const StrBuf* Name, unsigned char Style)
|
||||
/* Undefine the macro with the given name and style. A style mismatch is
|
||||
* treated as if the macro didn't exist.
|
||||
*/
|
||||
{
|
||||
/* Search for the macro */
|
||||
Macro* M = HT_FindEntry (&MacroTab, Name);
|
||||
|
||||
/* Don't let the user kid with us */
|
||||
if (M == 0) {
|
||||
if (M == 0 || M->Style != Style) {
|
||||
Error ("No such macro: %m%p", Name);
|
||||
return;
|
||||
}
|
||||
@ -570,6 +622,9 @@ void MacUndef (const StrBuf* Name)
|
||||
|
||||
/* Remove the macro from the macro table */
|
||||
HT_RemoveEntry (&MacroTab, M);
|
||||
|
||||
/* Free the macro structure */
|
||||
FreeMacro (M);
|
||||
}
|
||||
|
||||
|
||||
@ -928,11 +983,11 @@ int IsMacro (const StrBuf* Name)
|
||||
|
||||
int IsDefine (const StrBuf* Name)
|
||||
/* Return true if the given name is the name of a define style macro */
|
||||
{
|
||||
{
|
||||
Macro* M;
|
||||
|
||||
/* Never if disabled */
|
||||
if (DisableDefines) {
|
||||
if (DisableDefines) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -69,8 +69,10 @@ struct StrBuf;
|
||||
void MacDef (unsigned Style);
|
||||
/* Parse a macro definition */
|
||||
|
||||
void MacUndef (const struct StrBuf* Name);
|
||||
/* Undefine the macro with the given name. */
|
||||
void MacUndef (const StrBuf* Name, unsigned char Style);
|
||||
/* Undefine the macro with the given name and style. A style mismatch is
|
||||
* treated as if the macro didn't exist.
|
||||
*/
|
||||
|
||||
void MacExpandStart (void);
|
||||
/* Start expanding the macro in SVal */
|
||||
|
@ -753,6 +753,20 @@ static void DoDefine (void)
|
||||
|
||||
|
||||
|
||||
static void DoDelMac (void)
|
||||
/* Delete a classic macro */
|
||||
{
|
||||
/* We expect an identifier */
|
||||
if (CurTok.Tok != TOK_IDENT) {
|
||||
ErrorSkip ("Identifier expected");
|
||||
} else {
|
||||
MacUndef (&CurTok.SVal, MAC_STYLE_CLASSIC);
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DoDestructor (void)
|
||||
/* Export a symbol as destructor */
|
||||
{
|
||||
@ -1779,11 +1793,11 @@ static void DoTag (void)
|
||||
|
||||
|
||||
static void DoUnDef (void)
|
||||
/* Undefine a macro */
|
||||
{
|
||||
/* Undefine a define style macro */
|
||||
{
|
||||
/* The function is called with the .UNDEF token in place, because we need
|
||||
* to disable .define macro expansions before reading the next token.
|
||||
* Otherwise the name of the macro would be expanded, so we would never
|
||||
* to disable .define macro expansions before reading the next token.
|
||||
* Otherwise the name of the macro would be expanded, so we would never
|
||||
* see it.
|
||||
*/
|
||||
DisableDefineStyleMacros ();
|
||||
@ -1794,7 +1808,7 @@ static void DoUnDef (void)
|
||||
if (CurTok.Tok != TOK_IDENT) {
|
||||
ErrorSkip ("Identifier expected");
|
||||
} else {
|
||||
MacUndef (&CurTok.SVal);
|
||||
MacUndef (&CurTok.SVal, MAC_STYLE_DEFINE);
|
||||
NextTok ();
|
||||
}
|
||||
}
|
||||
@ -1893,6 +1907,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
||||
{ ccNone, DoDebugInfo },
|
||||
{ ccNone, DoDefine },
|
||||
{ ccNone, DoUnexpected }, /* .DEFINED */
|
||||
{ ccNone, DoDelMac },
|
||||
{ ccNone, DoDestructor },
|
||||
{ ccNone, DoDWord },
|
||||
{ ccKeepToken, DoConditionals }, /* .ELSE */
|
||||
|
@ -166,6 +166,8 @@ struct DotKeyword {
|
||||
{ ".DEF", TOK_DEFINED },
|
||||
{ ".DEFINE", TOK_DEFINE },
|
||||
{ ".DEFINED", TOK_DEFINED },
|
||||
{ ".DELMAC", TOK_DELMAC },
|
||||
{ ".DELMACRO", TOK_DELMAC },
|
||||
{ ".DESTRUCTOR", TOK_DESTRUCTOR },
|
||||
{ ".DWORD", TOK_DWORD },
|
||||
{ ".ELSE", TOK_ELSE },
|
||||
|
@ -147,6 +147,7 @@ typedef enum token_t {
|
||||
TOK_DEBUGINFO,
|
||||
TOK_DEFINE,
|
||||
TOK_DEFINED,
|
||||
TOK_DELMAC,
|
||||
TOK_DESTRUCTOR,
|
||||
TOK_DWORD,
|
||||
TOK_ELSE,
|
||||
|
Loading…
Reference in New Issue
Block a user