]> git.sur5r.net Git - cc65/commitdiff
Finished implemenation of commands to delete macros. Added the new commands to
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 12 Jun 2011 21:29:07 +0000 (21:29 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 12 Jun 2011 21:29:07 +0000 (21:29 +0000)
the docs.

git-svn-id: svn://svn.cc65.org/cc65/trunk@5050 b7a2c559-68d2-44c3-8de9-860c34a00d81

doc/ca65.sgml
src/ca65/macro.c
src/ca65/macro.h
src/ca65/pseudo.c
src/ca65/scanner.c
src/ca65/token.h

index 9c40084f1fcb8c5f1dadcfabb5c132762202efd1..3f5e9e9ef3101e2864b02218f8e79bd8aaa9dcf0 100644 (file)
@@ -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>
index 21db6e81ff4f5c73d8fdb8d9c42b93eafb08fb28..a5c86e9ad9975455f6bc8b21a6059bbe874fbbac 100644 (file)
@@ -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;
     }
 
index 921b601dbd6c85cd0c540cb6434a381178c212a9..61ec567610baca996a4501fa3518932c5bd47508 100644 (file)
@@ -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 */
index 85891e471426cfdb291cf32b72e125723bf93fb8..5437f07401aa46457bef5a8ac578e78098cc28a3 100644 (file)
@@ -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 */
index a49c8a2224ddd61147615060cc8fac96930d47db..723978a864b492c68cac3b9eaba10cc8804999a1 100644 (file)
@@ -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        },
index a95edfb5257c155be87a89ae2b11d7316695e3d5..ad22b885cd6fea9dc98e6735814dea6be79320c7 100644 (file)
@@ -147,6 +147,7 @@ typedef enum token_t {
     TOK_DEBUGINFO,
     TOK_DEFINE,
     TOK_DEFINED,
+    TOK_DELMAC,
     TOK_DESTRUCTOR,
     TOK_DWORD,
     TOK_ELSE,