Much improved diagnostics for macros.
This commit is contained in:
@@ -102,10 +102,12 @@ struct Macro {
|
||||
unsigned TokCount; /* Number of tokens for this macro */
|
||||
TokNode* TokRoot; /* Root of token list */
|
||||
TokNode* TokLast; /* Pointer to last token in list */
|
||||
FilePos DefPos; /* Position of definition */
|
||||
StrBuf Name; /* Macro name, dynamically allocated */
|
||||
unsigned Expansions; /* Number of active macro expansions */
|
||||
unsigned char Style; /* Macro style */
|
||||
unsigned char Incomplete; /* Macro is currently built */
|
||||
unsigned char HasError; /* Macro has errors */
|
||||
};
|
||||
|
||||
/* Hash table functions */
|
||||
@@ -232,7 +234,7 @@ static void FreeIdDescList (IdDesc* ID)
|
||||
|
||||
|
||||
|
||||
static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
|
||||
static Macro* NewMacro (const StrBuf* Name, const FilePos* P, unsigned char Style)
|
||||
/* Generate a new macro entry, initialize and return it */
|
||||
{
|
||||
/* Allocate memory */
|
||||
@@ -247,11 +249,14 @@ static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
|
||||
M->TokCount = 0;
|
||||
M->TokRoot = 0;
|
||||
M->TokLast = 0;
|
||||
M->DefPos = *P;
|
||||
SB_Init (&M->Name);
|
||||
SB_Copy (&M->Name, Name);
|
||||
SB_Terminate (&M->Name); /* So the name can be used with %s */
|
||||
M->Expansions = 0;
|
||||
M->Style = Style;
|
||||
M->Incomplete = 1;
|
||||
M->HasError = 0;
|
||||
|
||||
/* Insert the macro into the hash table */
|
||||
HT_Insert (&MacroTab, &M->Node);
|
||||
@@ -364,19 +369,26 @@ static void FreeMacExp (MacExp* E)
|
||||
|
||||
|
||||
|
||||
static void MacSkipDef (unsigned Style)
|
||||
static void MacSkipDef (unsigned Style, const FilePos* StartPos)
|
||||
/* Skip a macro definition */
|
||||
{
|
||||
if (Style == MAC_STYLE_CLASSIC) {
|
||||
/* Skip tokens until we reach the final .endmacro */
|
||||
while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
|
||||
/* Skip tokens until we reach the final .endmacro. Be liberal about
|
||||
** .endmacro here since we had errors anyway when this function is
|
||||
** called.
|
||||
*/
|
||||
while (1) {
|
||||
if (CurTok.Tok == TOK_EOF) {
|
||||
ErrorExpect ("Expected '.ENDMACRO'");
|
||||
PNotification (StartPos, "Macro definition started here");
|
||||
break;
|
||||
}
|
||||
if (CurTok.Tok == TOK_ENDMACRO) {
|
||||
NextTok ();
|
||||
break;
|
||||
}
|
||||
NextTok ();
|
||||
}
|
||||
if (CurTok.Tok != TOK_EOF) {
|
||||
SkipUntilSep ();
|
||||
} else {
|
||||
Error ("'.ENDMACRO' expected");
|
||||
}
|
||||
} else {
|
||||
/* Skip until end of line */
|
||||
SkipUntilSep ();
|
||||
@@ -388,26 +400,23 @@ static void MacSkipDef (unsigned Style)
|
||||
void MacDef (unsigned Style)
|
||||
/* Parse a macro definition */
|
||||
{
|
||||
Macro* Existing;
|
||||
Macro* M;
|
||||
TokNode* N;
|
||||
FilePos Pos;
|
||||
int HaveParams;
|
||||
int LastTokWasSep;
|
||||
|
||||
/* Remember the current file position */
|
||||
FilePos StartPos = CurTok.Pos;
|
||||
|
||||
/* For classic macros, remember if we are at the beginning of the line.
|
||||
** If the macro name and parameters pass our checks then we will be on a
|
||||
** new line, so set it now
|
||||
*/
|
||||
LastTokWasSep = 1;
|
||||
|
||||
/* Save the position of the start of the macro definition to allow
|
||||
** using Perror to display the error if .endmacro isn't found
|
||||
*/
|
||||
Pos = CurTok.Pos;
|
||||
int LastTokWasSep = 1;
|
||||
|
||||
/* We expect a macro name here */
|
||||
if (!Expect (TOK_IDENT, "Expected an identifier")) {
|
||||
MacSkipDef (Style);
|
||||
MacSkipDef (Style, &StartPos);
|
||||
return;
|
||||
}
|
||||
if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
|
||||
@@ -415,21 +424,25 @@ void MacDef (unsigned Style)
|
||||
** allowed if not explicitly enabled.
|
||||
*/
|
||||
Error ("Cannot use an instruction as macro name");
|
||||
MacSkipDef (Style);
|
||||
MacSkipDef (Style, &StartPos);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Did we already define that macro? */
|
||||
if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
|
||||
Existing = HT_Find (&MacroTab, &CurTok.SVal);
|
||||
if (Existing != 0) {
|
||||
/* Macro is already defined */
|
||||
Error ("A macro named '%m%p' is already defined", &CurTok.SVal);
|
||||
PNotification (&Existing->DefPos,
|
||||
"Previous definition of macro '%s' was here",
|
||||
SB_GetConstBuf (&Existing->Name));
|
||||
/* Skip tokens until we reach the final .endmacro */
|
||||
MacSkipDef (Style);
|
||||
MacSkipDef (Style, &StartPos);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Define the macro */
|
||||
M = NewMacro (&CurTok.SVal, Style);
|
||||
M = NewMacro (&CurTok.SVal, &StartPos, Style);
|
||||
|
||||
/* Switch to raw token mode and skip the macro name */
|
||||
EnterRawTokenMode ();
|
||||
@@ -463,7 +476,8 @@ void MacDef (unsigned Style)
|
||||
|
||||
while (1) {
|
||||
if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
|
||||
Error ("Duplicate symbol '%m%p'", &CurTok.SVal);
|
||||
Error ("Duplicate macro parameter '%m%p'", &CurTok.SVal);
|
||||
M->HasError = 1;
|
||||
}
|
||||
if (List->Next == 0) {
|
||||
break;
|
||||
@@ -513,7 +527,10 @@ void MacDef (unsigned Style)
|
||||
}
|
||||
/* May not have end of file in a macro definition */
|
||||
if (CurTok.Tok == TOK_EOF) {
|
||||
PError (&Pos, "'.ENDMACRO' expected for macro '%m%p'", &M->Name);
|
||||
Error ("Missing '.ENDMACRO' for definition of macro '%s'",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
PNotification (&StartPos, "Macro definition started here");
|
||||
M->HasError = 1;
|
||||
goto Done;
|
||||
}
|
||||
} else {
|
||||
@@ -535,6 +552,7 @@ void MacDef (unsigned Style)
|
||||
if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
|
||||
ErrorExpect ("Expected an identifier");
|
||||
SkipUntilSep ();
|
||||
M->HasError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -553,7 +571,10 @@ void MacDef (unsigned Style)
|
||||
}
|
||||
|
||||
/* We need end of line after the locals */
|
||||
ConsumeSep ();
|
||||
if (!ExpectSep ()) {
|
||||
M->HasError = 1;
|
||||
}
|
||||
NextTok ();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -626,7 +647,8 @@ void MacUndef (const StrBuf* Name, unsigned char Style)
|
||||
return;
|
||||
}
|
||||
if (M->Expansions > 0) {
|
||||
Error ("Cannot delete a macro that is currently expanded");
|
||||
Error ("Cannot delete macro '%s' which is currently expanded",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -813,7 +835,11 @@ static void StartExpClassic (MacExp* E)
|
||||
|
||||
/* Check for maximum parameter count */
|
||||
if (E->ParamCount >= E->M->ParamCount) {
|
||||
ErrorSkip ("Too many macro parameters");
|
||||
ErrorSkip ("Too many parameters for macro '%s'",
|
||||
SB_GetConstBuf (&E->M->Name));
|
||||
PNotification (&E->M->DefPos,
|
||||
"See definition of macro '%s' which was here",
|
||||
SB_GetConstBuf (&E->M->Name));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -827,7 +853,7 @@ static void StartExpClassic (MacExp* E)
|
||||
|
||||
/* Check for end of file */
|
||||
if (CurTok.Tok == TOK_EOF) {
|
||||
Error ("Unexpected end of file");
|
||||
Error ("Unexpected end of file in macro parameter list");
|
||||
FreeMacExp (E);
|
||||
return;
|
||||
}
|
||||
@@ -970,9 +996,21 @@ void MacExpandStart (Macro* M)
|
||||
Pos = CurTok.Pos;
|
||||
NextTok ();
|
||||
|
||||
/* We cannot expand a macro with errors */
|
||||
if (M->HasError) {
|
||||
PError (&Pos, "Macro '%s' contains errors and cannot be expanded",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
PNotification (&M->DefPos, "Definition of macro '%s' was here",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* We cannot expand an incomplete macro */
|
||||
if (M->Incomplete) {
|
||||
PError (&Pos, "Cannot expand an incomplete macro");
|
||||
PError (&Pos, "Macro '%s' is incomplete and cannot be expanded",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
PNotification (&M->DefPos, "Definition of macro '%s' was here",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -980,7 +1018,8 @@ void MacExpandStart (Macro* M)
|
||||
** to force an endless loop and assembler crash.
|
||||
*/
|
||||
if (MacExpansions >= MAX_MACEXPANSIONS) {
|
||||
PError (&Pos, "Too many nested macro expansions");
|
||||
PError (&Pos, "Too many nested macro expansions for macro '%s'",
|
||||
SB_GetConstBuf (&M->Name));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user