2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* macro.c */
|
|
|
|
/* */
|
|
|
|
/* Macros for the ca65 macroassembler */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
2011-01-16 16:05:43 +00:00
|
|
|
/* (C) 1998-2011, Ullrich von Bassewitz */
|
|
|
|
/* Roemerstrasse 52 */
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
/* */
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
/* */
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
/* distribution. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2000-08-01 15:17:43 +00:00
|
|
|
/* common */
|
|
|
|
#include "check.h"
|
|
|
|
#include "hashstr.h"
|
2003-10-22 19:13:21 +00:00
|
|
|
#include "hashtab.h"
|
2000-08-01 15:17:43 +00:00
|
|
|
#include "xmalloc.h"
|
2001-09-01 19:13:36 +00:00
|
|
|
|
2000-08-01 15:17:43 +00:00
|
|
|
/* ca65 */
|
2000-06-03 11:15:11 +00:00
|
|
|
#include "condasm.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "error.h"
|
2002-09-25 21:35:00 +00:00
|
|
|
#include "global.h"
|
2004-04-20 12:49:36 +00:00
|
|
|
#include "instr.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
#include "istack.h"
|
2011-01-29 20:24:44 +00:00
|
|
|
#include "lineinfo.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
#include "nexttok.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "pseudo.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
#include "toklist.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "macro.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-22 19:13:21 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* Forwards */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned HT_GenHash (const void* Key);
|
|
|
|
/* Generate the hash over a key. */
|
|
|
|
|
|
|
|
static const void* HT_GetKey (void* Entry);
|
|
|
|
/* Given a pointer to the user entry data, return a pointer to the key */
|
|
|
|
|
|
|
|
static HashNode* HT_GetHashNode (void* Entry);
|
|
|
|
/* Given a pointer to the user entry data, return a pointer to the hash node */
|
|
|
|
|
|
|
|
static int HT_Compare (const void* Key1, const void* Key2);
|
2003-10-23 14:54:58 +00:00
|
|
|
/* Compare two keys. The function must return a value less than zero if
|
|
|
|
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
|
|
|
* than zero if Key1 is greater then Key2.
|
|
|
|
*/
|
2003-10-22 19:13:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* Data */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Struct that describes an identifer (macro param, local list) */
|
2003-10-22 19:13:21 +00:00
|
|
|
typedef struct IdDesc IdDesc;
|
|
|
|
struct IdDesc {
|
|
|
|
IdDesc* Next; /* Linked list */
|
2008-03-31 20:54:45 +00:00
|
|
|
StrBuf Id; /* Identifier, dynamically allocated */
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Struct that describes a macro definition */
|
2003-10-22 19:13:21 +00:00
|
|
|
typedef struct Macro Macro;
|
|
|
|
struct Macro {
|
|
|
|
HashNode Node; /* Hash list node */
|
2000-05-28 13:40:48 +00:00
|
|
|
Macro* List; /* List of all macros */
|
|
|
|
unsigned LocalCount; /* Count of local symbols */
|
|
|
|
IdDesc* Locals; /* List of local symbols */
|
|
|
|
unsigned ParamCount; /* Parameter count of macro */
|
|
|
|
IdDesc* Params; /* Identifiers of macro parameters */
|
|
|
|
unsigned TokCount; /* Number of tokens for this macro */
|
|
|
|
TokNode* TokRoot; /* Root of token list */
|
|
|
|
TokNode* TokLast; /* Pointer to last token in list */
|
2011-06-11 22:18:48 +00:00
|
|
|
StrBuf Name; /* Macro name, dynamically allocated */
|
|
|
|
unsigned Expansions; /* Number of active macro expansions */
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned char Style; /* Macro style */
|
2011-06-07 21:17:35 +00:00
|
|
|
unsigned char Incomplete; /* Macro is currently built */
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
|
2003-10-22 19:13:21 +00:00
|
|
|
/* Hash table functions */
|
|
|
|
static const HashFunctions HashFunc = {
|
|
|
|
HT_GenHash,
|
|
|
|
HT_GetKey,
|
|
|
|
HT_GetHashNode,
|
|
|
|
HT_Compare
|
|
|
|
};
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Macro hash table */
|
2003-10-22 19:13:21 +00:00
|
|
|
static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Structs that holds data for a macro expansion */
|
2003-10-22 19:13:21 +00:00
|
|
|
typedef struct MacExp MacExp;
|
|
|
|
struct MacExp {
|
2011-01-29 20:24:44 +00:00
|
|
|
MacExp* Next; /* Pointer to next expansion */
|
|
|
|
Macro* M; /* Which macro do we expand? */
|
|
|
|
unsigned IfSP; /* .IF stack pointer at start of expansion */
|
2000-05-28 13:40:48 +00:00
|
|
|
TokNode* Exp; /* Pointer to current token */
|
2011-01-29 20:24:44 +00:00
|
|
|
TokNode* Final; /* Pointer to final token */
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned LocalStart; /* Start of counter for local symbol names */
|
2011-01-29 20:24:44 +00:00
|
|
|
unsigned ParamCount; /* Number of actual parameters */
|
|
|
|
TokNode** Params; /* List of actual parameters */
|
|
|
|
TokNode* ParamExp; /* Node for expanding parameters */
|
2011-06-13 08:53:41 +00:00
|
|
|
int LISlot; /* Slot for additional line infos */
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
|
2011-06-07 21:17:35 +00:00
|
|
|
/* Maximum number of nested macro expansions */
|
|
|
|
#define MAX_MACEXPANSIONS 256U
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Number of active macro expansions */
|
|
|
|
static unsigned MacExpansions = 0;
|
|
|
|
|
|
|
|
/* Flag if a macro expansion should get aborted */
|
|
|
|
static int DoMacAbort = 0;
|
|
|
|
|
|
|
|
/* Counter to create local names for symbols */
|
|
|
|
static unsigned LocalName = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* Define style macros disabled if != 0 */
|
|
|
|
static unsigned DisableDefines = 0;
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
2003-10-22 19:13:21 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* Hash table functions */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned HT_GenHash (const void* Key)
|
|
|
|
/* Generate the hash over a key. */
|
|
|
|
{
|
2008-03-31 20:54:45 +00:00
|
|
|
return HashBuf (Key);
|
2003-10-22 19:13:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const void* HT_GetKey (void* Entry)
|
|
|
|
/* Given a pointer to the user entry data, return a pointer to the index */
|
|
|
|
{
|
2008-03-31 20:54:45 +00:00
|
|
|
return &((Macro*) Entry)->Name;
|
2003-10-22 19:13:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static HashNode* HT_GetHashNode (void* Entry)
|
|
|
|
/* Given a pointer to the user entry data, return a pointer to the hash node */
|
|
|
|
{
|
|
|
|
return &((Macro*) Entry)->Node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int HT_Compare (const void* Key1, const void* Key2)
|
2003-10-23 14:54:58 +00:00
|
|
|
/* Compare two keys. The function must return a value less than zero if
|
|
|
|
* Key1 is smaller than Key2, zero if both are equal, and a value greater
|
|
|
|
* than zero if Key1 is greater then Key2.
|
|
|
|
*/
|
2003-10-22 19:13:21 +00:00
|
|
|
{
|
2008-03-31 20:54:45 +00:00
|
|
|
return SB_Compare (Key1, Key2);
|
2003-10-22 19:13:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* Code */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
static IdDesc* NewIdDesc (const StrBuf* Id)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Create a new IdDesc, initialize and return it */
|
|
|
|
{
|
|
|
|
/* Allocate memory */
|
2011-06-12 21:29:07 +00:00
|
|
|
IdDesc* ID = xmalloc (sizeof (IdDesc));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Initialize the struct */
|
2011-06-12 21:29:07 +00:00
|
|
|
ID->Next = 0;
|
|
|
|
SB_Init (&ID->Id);
|
|
|
|
SB_Copy (&ID->Id, Id);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Return the new struct */
|
2011-06-12 21:29:07 +00:00
|
|
|
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) {
|
2011-06-13 08:53:41 +00:00
|
|
|
IdDesc* This = ID;
|
2011-06-12 21:29:07 +00:00
|
|
|
ID = ID->Next;
|
|
|
|
FreeIdDesc (This);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Generate a new macro entry, initialize and return it */
|
|
|
|
{
|
|
|
|
/* Allocate memory */
|
2008-03-31 20:54:45 +00:00
|
|
|
Macro* M = xmalloc (sizeof (Macro));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Initialize the macro struct */
|
2003-10-22 19:13:21 +00:00
|
|
|
InitHashNode (&M->Node, M);
|
2000-05-28 13:40:48 +00:00
|
|
|
M->LocalCount = 0;
|
2003-06-27 15:46:20 +00:00
|
|
|
M->Locals = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
M->ParamCount = 0;
|
|
|
|
M->Params = 0;
|
|
|
|
M->TokCount = 0;
|
|
|
|
M->TokRoot = 0;
|
|
|
|
M->TokLast = 0;
|
2009-10-08 10:51:45 +00:00
|
|
|
SB_Init (&M->Name);
|
2008-03-31 20:54:45 +00:00
|
|
|
SB_Copy (&M->Name, Name);
|
2011-06-11 22:18:48 +00:00
|
|
|
M->Expansions = 0;
|
|
|
|
M->Style = Style;
|
|
|
|
M->Incomplete = 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Insert the macro into the hash table */
|
2003-10-22 19:13:21 +00:00
|
|
|
HT_Insert (&MacroTab, &M->Node);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Return the new macro struct */
|
|
|
|
return M;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-12 21:29:07 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
static MacExp* NewMacExp (Macro* M)
|
|
|
|
/* Create a new expansion structure for the given macro */
|
|
|
|
{
|
|
|
|
unsigned I;
|
|
|
|
|
|
|
|
/* Allocate memory */
|
2000-06-14 09:32:22 +00:00
|
|
|
MacExp* E = xmalloc (sizeof (MacExp));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Initialize the data */
|
|
|
|
E->M = M;
|
2011-01-29 20:24:44 +00:00
|
|
|
E->IfSP = GetIfStack ();
|
2000-05-28 13:40:48 +00:00
|
|
|
E->Exp = M->TokRoot;
|
2011-01-29 20:24:44 +00:00
|
|
|
E->Final = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
E->LocalStart = LocalName;
|
|
|
|
LocalName += M->LocalCount;
|
|
|
|
E->ParamCount = 0;
|
2000-06-14 09:32:22 +00:00
|
|
|
E->Params = xmalloc (M->ParamCount * sizeof (TokNode*));
|
2000-05-28 13:40:48 +00:00
|
|
|
for (I = 0; I < M->ParamCount; ++I) {
|
2011-01-29 20:24:44 +00:00
|
|
|
E->Params[I] = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2011-06-11 22:18:48 +00:00
|
|
|
E->ParamExp = 0;
|
2011-01-29 22:16:03 +00:00
|
|
|
E->LISlot = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* Mark the macro as expanding */
|
|
|
|
++M->Expansions;
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* One macro expansion more */
|
|
|
|
++MacExpansions;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Return the new macro expansion */
|
|
|
|
return E;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
static void FreeMacExp (MacExp* E)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Remove and free the current macro expansion */
|
|
|
|
{
|
|
|
|
unsigned I;
|
2000-06-03 11:15:11 +00:00
|
|
|
|
|
|
|
/* One macro expansion less */
|
|
|
|
--MacExpansions;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* No longer expanding this macro */
|
|
|
|
--E->M->Expansions;
|
|
|
|
|
2004-05-10 21:06:53 +00:00
|
|
|
/* Free the parameter lists */
|
2000-06-03 11:15:11 +00:00
|
|
|
for (I = 0; I < E->ParamCount; ++I) {
|
2004-05-10 21:06:53 +00:00
|
|
|
/* Free one parameter list */
|
|
|
|
TokNode* N = E->Params[I];
|
|
|
|
while (N) {
|
|
|
|
TokNode* P = N->Next;
|
|
|
|
FreeTokNode (N);
|
|
|
|
N = P;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2000-06-14 09:32:22 +00:00
|
|
|
xfree (E->Params);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-01-29 20:24:44 +00:00
|
|
|
/* Free the additional line info slot */
|
|
|
|
FreeLineInfoSlot (E->LISlot);
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Free the final token if we have one */
|
2000-06-03 11:15:11 +00:00
|
|
|
if (E->Final) {
|
|
|
|
FreeTokNode (E->Final);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the structure itself */
|
2000-06-14 09:32:22 +00:00
|
|
|
xfree (E);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void MacSkipDef (unsigned Style)
|
|
|
|
/* Skip a macro definition */
|
|
|
|
{
|
|
|
|
if (Style == MAC_STYLE_CLASSIC) {
|
2011-06-11 22:18:48 +00:00
|
|
|
/* Skip tokens until we reach the final .endmacro */
|
|
|
|
while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
|
|
|
|
NextTok ();
|
|
|
|
}
|
|
|
|
if (CurTok.Tok != TOK_EOF) {
|
|
|
|
SkipUntilSep ();
|
|
|
|
} else {
|
|
|
|
Error ("`.ENDMACRO' expected");
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2011-06-11 22:18:48 +00:00
|
|
|
/* Skip until end of line */
|
|
|
|
SkipUntilSep ();
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MacDef (unsigned Style)
|
|
|
|
/* Parse a macro definition */
|
|
|
|
{
|
|
|
|
Macro* M;
|
2011-01-20 20:54:30 +00:00
|
|
|
TokNode* N;
|
2000-05-28 13:40:48 +00:00
|
|
|
int HaveParams;
|
|
|
|
|
|
|
|
/* We expect a macro name here */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok != TOK_IDENT) {
|
2003-11-08 17:20:21 +00:00
|
|
|
Error ("Identifier expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
MacSkipDef (Style);
|
|
|
|
return;
|
2011-01-16 16:05:43 +00:00
|
|
|
} else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
|
2004-04-20 12:49:36 +00:00
|
|
|
/* The identifier is a name of a 6502 instruction, which is not
|
|
|
|
* allowed if not explicitly enabled.
|
|
|
|
*/
|
|
|
|
Error ("Cannot use an instruction as macro name");
|
|
|
|
MacSkipDef (Style);
|
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Did we already define that macro? */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Macro is already defined */
|
2011-01-16 16:05:43 +00:00
|
|
|
Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Skip tokens until we reach the final .endmacro */
|
|
|
|
MacSkipDef (Style);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Define the macro */
|
2011-01-16 16:05:43 +00:00
|
|
|
M = NewMacro (&CurTok.SVal, Style);
|
2000-07-08 14:01:43 +00:00
|
|
|
|
|
|
|
/* Switch to raw token mode and skip the macro name */
|
|
|
|
EnterRawTokenMode ();
|
2000-05-28 13:40:48 +00:00
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
/* If we have a DEFINE style macro, we may have parameters in braces,
|
|
|
|
* otherwise we may have parameters without braces.
|
|
|
|
*/
|
|
|
|
if (Style == MAC_STYLE_CLASSIC) {
|
2008-03-31 20:54:45 +00:00
|
|
|
HaveParams = 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_LPAREN) {
|
2008-03-31 20:54:45 +00:00
|
|
|
HaveParams = 1;
|
|
|
|
NextTok ();
|
|
|
|
} else {
|
|
|
|
HaveParams = 0;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the parameter list */
|
|
|
|
if (HaveParams) {
|
|
|
|
|
2011-01-16 16:05:43 +00:00
|
|
|
while (CurTok.Tok == TOK_IDENT) {
|
2008-03-31 20:54:45 +00:00
|
|
|
|
|
|
|
/* Create a struct holding the identifier */
|
2011-01-16 16:05:43 +00:00
|
|
|
IdDesc* I = NewIdDesc (&CurTok.SVal);
|
2008-03-31 20:54:45 +00:00
|
|
|
|
|
|
|
/* Insert the struct into the list, checking for duplicate idents */
|
|
|
|
if (M->ParamCount == 0) {
|
|
|
|
M->Params = I;
|
|
|
|
} else {
|
|
|
|
IdDesc* List = M->Params;
|
|
|
|
while (1) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
|
|
|
|
Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
|
2008-03-31 20:54:45 +00:00
|
|
|
}
|
|
|
|
if (List->Next == 0) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
List = List->Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
List->Next = I;
|
|
|
|
}
|
|
|
|
++M->ParamCount;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Skip the name */
|
2008-03-31 20:54:45 +00:00
|
|
|
NextTok ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Maybe there are more params... */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_COMMA) {
|
2000-05-28 13:40:48 +00:00
|
|
|
NextTok ();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For class macros, we expect a separator token, for define style macros,
|
|
|
|
* we expect the closing paren.
|
|
|
|
*/
|
|
|
|
if (Style == MAC_STYLE_CLASSIC) {
|
|
|
|
ConsumeSep ();
|
|
|
|
} else if (HaveParams) {
|
|
|
|
ConsumeRParen ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
/* Check for end of macro */
|
|
|
|
if (Style == MAC_STYLE_CLASSIC) {
|
|
|
|
/* In classic macros, only .endmacro is allowed */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_ENDMACRO) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Done */
|
|
|
|
break;
|
|
|
|
}
|
2011-06-11 22:18:48 +00:00
|
|
|
/* May not have end of file in a macro definition */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_EOF) {
|
2003-11-08 17:20:21 +00:00
|
|
|
Error ("`.ENDMACRO' expected");
|
2000-07-08 14:01:43 +00:00
|
|
|
goto Done;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Accept a newline or end of file for new style macros */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (TokIsSep (CurTok.Tok)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for a .LOCAL declaration */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
IdDesc* I;
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Skip .local or comma */
|
2000-05-28 13:40:48 +00:00
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
/* Need an identifer */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
|
2003-11-08 17:20:21 +00:00
|
|
|
Error ("Identifier expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
SkipUntilSep ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Put the identifier into the locals list and skip it */
|
2011-01-16 16:05:43 +00:00
|
|
|
I = NewIdDesc (&CurTok.SVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
I->Next = M->Locals;
|
|
|
|
M->Locals = I;
|
|
|
|
++M->LocalCount;
|
2011-06-11 22:18:48 +00:00
|
|
|
NextTok ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check for end of list */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok != TOK_COMMA) {
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need end of line after the locals */
|
|
|
|
ConsumeSep ();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a token node for the current token */
|
2011-01-20 20:54:30 +00:00
|
|
|
N = NewTokNode ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If the token is an ident, check if it is a local parameter */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_IDENT) {
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned Count = 0;
|
|
|
|
IdDesc* I = M->Params;
|
|
|
|
while (I) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Local param name, replace it */
|
2011-01-20 20:54:30 +00:00
|
|
|
N->T.Tok = TOK_MACPARAM;
|
|
|
|
N->T.IVal = Count;
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++Count;
|
|
|
|
I = I->Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert the new token in the list */
|
|
|
|
if (M->TokCount == 0) {
|
|
|
|
/* First token */
|
2011-01-20 20:54:30 +00:00
|
|
|
M->TokRoot = M->TokLast = N;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* We have already tokens */
|
2011-01-20 20:54:30 +00:00
|
|
|
M->TokLast->Next = N;
|
|
|
|
M->TokLast = N;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
++M->TokCount;
|
|
|
|
|
|
|
|
/* Read the next token */
|
|
|
|
NextTok ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip the .endmacro for a classic macro */
|
|
|
|
if (Style == MAC_STYLE_CLASSIC) {
|
|
|
|
NextTok ();
|
|
|
|
}
|
2000-07-08 14:01:43 +00:00
|
|
|
|
2011-06-07 21:17:35 +00:00
|
|
|
/* Reset the Incomplete flag now that parsing is done */
|
|
|
|
M->Incomplete = 0;
|
|
|
|
|
2000-07-08 14:01:43 +00:00
|
|
|
Done:
|
|
|
|
/* Switch out of raw token mode */
|
|
|
|
LeaveRawTokenMode ();
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-12 21:29:07 +00:00
|
|
|
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.
|
|
|
|
*/
|
2011-06-11 22:18:48 +00:00
|
|
|
{
|
|
|
|
/* Search for the macro */
|
|
|
|
Macro* M = HT_FindEntry (&MacroTab, Name);
|
|
|
|
|
|
|
|
/* Don't let the user kid with us */
|
2011-06-12 21:29:07 +00:00
|
|
|
if (M == 0 || M->Style != Style) {
|
2011-06-11 22:18:48 +00:00
|
|
|
Error ("No such macro: %m%p", Name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (M->Expansions > 0) {
|
|
|
|
Error ("Cannot delete a macro that is currently expanded");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the macro from the macro table */
|
|
|
|
HT_RemoveEntry (&MacroTab, M);
|
2011-06-12 21:29:07 +00:00
|
|
|
|
|
|
|
/* Free the macro structure */
|
|
|
|
FreeMacro (M);
|
2011-06-11 22:18:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
static int MacExpand (void* Data)
|
|
|
|
/* If we're currently expanding a macro, set the the scanner token and
|
|
|
|
* attribute to the next value and return true. If we are not expanding
|
|
|
|
* a macro, return false.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/* Cast the Data pointer to the actual data structure */
|
|
|
|
MacExp* Mac = (MacExp*) Data;
|
|
|
|
|
|
|
|
/* Check if we should abort this macro */
|
|
|
|
if (DoMacAbort) {
|
|
|
|
|
|
|
|
/* Reset the flag */
|
|
|
|
DoMacAbort = 0;
|
|
|
|
|
|
|
|
/* Abort any open .IF statements in this macro expansion */
|
|
|
|
CleanupIfStack (Mac->IfSP);
|
|
|
|
|
|
|
|
/* Terminate macro expansion */
|
|
|
|
goto MacEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're expanding a macro. Check if we are expanding one of the
|
|
|
|
* macro parameters.
|
|
|
|
*/
|
|
|
|
if (Mac->ParamExp) {
|
|
|
|
|
2011-06-13 08:53:41 +00:00
|
|
|
/* Ok, use token from parameter list, but don't use its line info */
|
|
|
|
TokSet (Mac->ParamExp, LI_SLOT_INV);
|
2011-06-13 08:55:48 +00:00
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Set pointer to next token */
|
|
|
|
Mac->ParamExp = Mac->ParamExp->Next;
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're not expanding macro parameters. Check if we have tokens left from
|
|
|
|
* the macro itself.
|
|
|
|
*/
|
|
|
|
if (Mac->Exp) {
|
|
|
|
|
|
|
|
/* Use next macro token */
|
2011-01-29 20:24:44 +00:00
|
|
|
TokSet (Mac->Exp, Mac->LISlot);
|
2000-06-03 11:15:11 +00:00
|
|
|
|
|
|
|
/* Set pointer to next token */
|
|
|
|
Mac->Exp = Mac->Exp->Next;
|
|
|
|
|
|
|
|
/* Is it a request for actual parameter count? */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_PARAMCOUNT) {
|
|
|
|
CurTok.Tok = TOK_INTCON;
|
|
|
|
CurTok.IVal = Mac->ParamCount;
|
2000-06-03 11:15:11 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is it the name of a macro parameter? */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_MACPARAM) {
|
2000-06-03 11:15:11 +00:00
|
|
|
|
|
|
|
/* Start to expand the parameter token list */
|
2011-01-16 16:05:43 +00:00
|
|
|
Mac->ParamExp = Mac->Params [CurTok.IVal];
|
2000-06-03 11:15:11 +00:00
|
|
|
|
|
|
|
/* Recursive call to expand the parameter */
|
|
|
|
return MacExpand (Mac);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If it's an identifier, it may in fact be a local symbol */
|
2011-01-16 16:05:43 +00:00
|
|
|
if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
|
|
|
|
Mac->M->LocalCount) {
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Search for the local symbol in the list */
|
|
|
|
unsigned Index = 0;
|
|
|
|
IdDesc* I = Mac->M->Locals;
|
|
|
|
while (I) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
|
2002-09-25 21:35:00 +00:00
|
|
|
/* This is in fact a local symbol, change the name. Be sure
|
|
|
|
* to generate a local label name if the original name was
|
|
|
|
* a local label, and also generate a name that cannot be
|
|
|
|
* generated by a user.
|
|
|
|
*/
|
2008-03-31 20:54:45 +00:00
|
|
|
if (SB_At (&I->Id, 0) == LocalStart) {
|
|
|
|
/* Must generate a local symbol */
|
2011-01-16 16:05:43 +00:00
|
|
|
SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
|
2008-03-31 20:54:45 +00:00
|
|
|
LocalStart, Mac->LocalStart + Index);
|
|
|
|
} else {
|
|
|
|
/* Global symbol */
|
2011-01-16 16:05:43 +00:00
|
|
|
SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
|
2008-03-31 20:54:45 +00:00
|
|
|
Mac->LocalStart + Index);
|
|
|
|
}
|
2000-06-03 11:15:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Next symbol */
|
|
|
|
++Index;
|
|
|
|
I = I->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The token was successfully set */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more macro tokens. Do we have a final token? */
|
|
|
|
if (Mac->Final) {
|
|
|
|
|
|
|
|
/* Set the final token and remove it */
|
2011-06-13 08:55:48 +00:00
|
|
|
TokSet (Mac->Final, LI_SLOT_INV);
|
2000-06-03 11:15:11 +00:00
|
|
|
FreeTokNode (Mac->Final);
|
|
|
|
Mac->Final = 0;
|
|
|
|
|
|
|
|
/* The token was successfully set */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
MacEnd:
|
|
|
|
/* End of macro expansion */
|
|
|
|
FreeMacExp (Mac);
|
|
|
|
|
|
|
|
/* Pop the input function */
|
|
|
|
PopInput ();
|
|
|
|
|
|
|
|
/* No token available */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
static void StartExpClassic (MacExp* E)
|
|
|
|
/* Start expanding a classic macro */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2011-01-16 14:51:13 +00:00
|
|
|
token_t Term;
|
2004-05-09 19:45:07 +00:00
|
|
|
|
2011-06-05 14:45:37 +00:00
|
|
|
/* Skip the macro name */
|
|
|
|
NextTok ();
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Read the actual parameters */
|
2011-01-16 16:05:43 +00:00
|
|
|
while (!TokIsSep (CurTok.Tok)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
TokNode* Last;
|
|
|
|
|
|
|
|
/* Check for maximum parameter count */
|
2011-06-11 22:18:48 +00:00
|
|
|
if (E->ParamCount >= E->M->ParamCount) {
|
2004-05-09 19:45:07 +00:00
|
|
|
ErrorSkip ("Too many macro parameters");
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
2011-06-11 22:18:48 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-09 19:45:07 +00:00
|
|
|
/* The macro may optionally be enclosed in curly braces */
|
2004-05-09 20:24:51 +00:00
|
|
|
Term = GetTokListTerm (TOK_COMMA);
|
2004-05-09 19:45:07 +00:00
|
|
|
|
|
|
|
/* Read tokens for one parameter, accept empty params */
|
2000-05-28 13:40:48 +00:00
|
|
|
Last = 0;
|
2011-01-16 16:05:43 +00:00
|
|
|
while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
TokNode* T;
|
|
|
|
|
|
|
|
/* Check for end of file */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_EOF) {
|
2004-05-09 19:45:07 +00:00
|
|
|
Error ("Unexpected end of file");
|
|
|
|
FreeMacExp (E);
|
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the next token in a node */
|
|
|
|
T = NewTokNode ();
|
|
|
|
|
|
|
|
/* Insert it into the list */
|
|
|
|
if (Last == 0) {
|
|
|
|
E->Params [E->ParamCount] = T;
|
|
|
|
} else {
|
2004-05-09 19:45:07 +00:00
|
|
|
Last->Next = T;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2011-06-11 22:18:48 +00:00
|
|
|
Last = T;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* And skip it... */
|
|
|
|
NextTok ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* One parameter more */
|
|
|
|
++E->ParamCount;
|
|
|
|
|
2004-05-09 19:45:07 +00:00
|
|
|
/* If the macro argument was enclosed in curly braces, end-of-line
|
|
|
|
* is an error. Skip the closing curly brace.
|
|
|
|
*/
|
|
|
|
if (Term == TOK_RCURLY) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_SEP) {
|
2004-05-09 19:45:07 +00:00
|
|
|
Error ("End of line encountered within macro argument");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NextTok ();
|
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Check for a comma */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_COMMA) {
|
2011-06-11 22:18:48 +00:00
|
|
|
NextTok ();
|
|
|
|
} else {
|
2004-05-09 19:45:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-09 19:45:07 +00:00
|
|
|
/* We must be at end of line now, otherwise something is wrong */
|
|
|
|
ExpectSep ();
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Insert a new token input function */
|
|
|
|
PushInput (MacExpand, E, ".MACRO");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
static void StartExpDefine (MacExp* E)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Start expanding a DEFINE style macro */
|
|
|
|
{
|
|
|
|
/* A define style macro must be called with as many actual parameters
|
|
|
|
* as there are formal ones. Get the parameter count.
|
2000-08-01 15:17:43 +00:00
|
|
|
*/
|
2011-06-11 22:18:48 +00:00
|
|
|
unsigned Count = E->M->ParamCount;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Skip the current token */
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
/* Read the actual parameters */
|
|
|
|
while (Count--) {
|
|
|
|
|
2004-05-09 19:45:07 +00:00
|
|
|
TokNode* Last;
|
|
|
|
|
|
|
|
/* The macro may optionally be enclosed in curly braces */
|
2011-01-16 14:51:13 +00:00
|
|
|
token_t Term = GetTokListTerm (TOK_COMMA);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check if there is really a parameter */
|
2011-01-16 16:05:43 +00:00
|
|
|
if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
|
2004-05-09 19:45:07 +00:00
|
|
|
ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
|
|
|
|
FreeMacExp (E);
|
|
|
|
return;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Read tokens for one parameter */
|
|
|
|
Last = 0;
|
|
|
|
do {
|
|
|
|
|
|
|
|
TokNode* T;
|
|
|
|
|
|
|
|
/* Get the next token in a node */
|
|
|
|
T = NewTokNode ();
|
|
|
|
|
|
|
|
/* Insert it into the list */
|
|
|
|
if (Last == 0) {
|
2003-01-19 12:04:33 +00:00
|
|
|
E->Params [E->ParamCount] = T;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2003-01-19 12:04:33 +00:00
|
|
|
Last->Next = T;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
Last = T;
|
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* And skip it... */
|
|
|
|
NextTok ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-01-16 16:05:43 +00:00
|
|
|
} while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* One parameter more */
|
|
|
|
++E->ParamCount;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-09 19:45:07 +00:00
|
|
|
/* If the macro argument was enclosed in curly braces, end-of-line
|
|
|
|
* is an error. Skip the closing curly brace.
|
|
|
|
*/
|
|
|
|
if (Term == TOK_RCURLY) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (TokIsSep (CurTok.Tok)) {
|
2004-05-09 19:45:07 +00:00
|
|
|
Error ("End of line encountered within macro argument");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NextTok ();
|
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Check for a comma */
|
|
|
|
if (Count > 0) {
|
2011-01-16 16:05:43 +00:00
|
|
|
if (CurTok.Tok == TOK_COMMA) {
|
2000-05-28 13:40:48 +00:00
|
|
|
NextTok ();
|
|
|
|
} else {
|
2003-11-08 17:20:21 +00:00
|
|
|
Error ("`,' expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Macro expansion will overwrite the current token. This is a problem
|
|
|
|
* for define style macros since these are called from the scanner level.
|
2004-05-09 19:45:07 +00:00
|
|
|
* To avoid it, remember the current token and re-insert it, once macro
|
2000-05-28 13:40:48 +00:00
|
|
|
* expansion is done.
|
|
|
|
*/
|
|
|
|
E->Final = NewTokNode ();
|
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Insert a new token input function */
|
|
|
|
PushInput (MacExpand, E, ".DEFINE");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MacExpandStart (void)
|
|
|
|
/* Start expanding the macro in SVal */
|
|
|
|
{
|
2011-06-11 22:18:48 +00:00
|
|
|
MacExp* E;
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Search for the macro */
|
2011-01-16 16:05:43 +00:00
|
|
|
Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
|
2011-06-11 22:18:48 +00:00
|
|
|
CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2011-06-07 21:17:35 +00:00
|
|
|
/* We cannot expand an incomplete macro */
|
|
|
|
if (M->Incomplete) {
|
|
|
|
Error ("Cannot expand an incomplete macro");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't allow too many nested macro expansions - otherwise it is possible
|
|
|
|
* to force an endless loop and assembler crash.
|
|
|
|
*/
|
|
|
|
if (MacExpansions >= MAX_MACEXPANSIONS) {
|
|
|
|
Error ("Too many nested macro expansions");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
/* Create a structure holding expansion data */
|
|
|
|
E = NewMacExp (M);
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Call the apropriate subroutine */
|
|
|
|
switch (M->Style) {
|
2011-06-11 22:18:48 +00:00
|
|
|
case MAC_STYLE_CLASSIC: StartExpClassic (E); break;
|
|
|
|
case MAC_STYLE_DEFINE: StartExpDefine (E); break;
|
|
|
|
default: Internal ("Invalid macro style: %d", M->Style);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MacAbort (void)
|
|
|
|
/* Abort the current macro expansion */
|
|
|
|
{
|
|
|
|
/* Must have an expansion */
|
2000-06-03 11:15:11 +00:00
|
|
|
CHECK (MacExpansions > 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-03 11:15:11 +00:00
|
|
|
/* Set a flag so macro expansion will terminate on the next call */
|
|
|
|
DoMacAbort = 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
int IsMacro (const StrBuf* Name)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Return true if the given name is the name of a macro */
|
|
|
|
{
|
2003-10-22 19:13:21 +00:00
|
|
|
return (HT_Find (&MacroTab, Name) != 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
int IsDefine (const StrBuf* Name)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Return true if the given name is the name of a define style macro */
|
2011-06-12 21:29:07 +00:00
|
|
|
{
|
2011-06-11 22:18:48 +00:00
|
|
|
Macro* M;
|
|
|
|
|
|
|
|
/* Never if disabled */
|
2011-06-12 21:29:07 +00:00
|
|
|
if (DisableDefines) {
|
2011-06-11 22:18:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we have such a macro */
|
|
|
|
M = HT_FindEntry (&MacroTab, Name);
|
2000-05-28 13:40:48 +00:00
|
|
|
return (M != 0 && M->Style == MAC_STYLE_DEFINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int InMacExpansion (void)
|
|
|
|
/* Return true if we're currently expanding a macro */
|
|
|
|
{
|
2000-06-03 11:15:11 +00:00
|
|
|
return (MacExpansions > 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-11 22:18:48 +00:00
|
|
|
void DisableDefineStyleMacros (void)
|
|
|
|
/* Disable define style macros until EnableDefineStyleMacros is called */
|
|
|
|
{
|
|
|
|
++DisableDefines;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EnableDefineStyleMacros (void)
|
|
|
|
/* Re-enable define style macros previously disabled with
|
|
|
|
* DisableDefineStyleMacros.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PRECONDITION (DisableDefines > 0);
|
|
|
|
--DisableDefines;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-16 16:05:43 +00:00
|
|
|
|