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