Much improved diagnostics for macros.

This commit is contained in:
Kugel Fuhr
2025-07-06 10:41:12 +02:00
parent 7cd137afb4
commit 23086bccff

View File

@@ -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;
}