static void StartExpDefine (MacExp* E) /* 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. */ unsigned Count = E->M->ParamCount; /* Skip the current token */ NextTok (); /* Read the actual parameters */ while (Count--) { TokNode* Last; /* The macro may optionally be enclosed in curly braces */ token_t Term = GetTokListTerm (TOK_COMMA); /* Check if there is really a parameter */ if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) { ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1); FreeMacExp (E); return; } /* 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) { E->Params [E->ParamCount] = T; } else { Last->Next = T; } Last = T; /* And skip it... */ NextTok (); } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok)); /* One parameter more */ ++E->ParamCount; /* If the macro argument was enclosed in curly braces, end-of-line * is an error. Skip the closing curly brace. */ if (Term == TOK_RCURLY) { if (TokIsSep (CurTok.Tok)) { Error ("End of line encountered within macro argument"); break; } NextTok (); } /* Check for a comma */ if (Count > 0) { if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { Error ("`,' expected"); } } } /* Macro expansion will overwrite the current token. This is a problem * for define style macros since these are called from the scanner level. * To avoid it, remember the current token and re-insert it, once macro * expansion is done. */ E->Final = NewTokNode (); /* Insert a new token input function */ PushInput (MacExpand, E, ".DEFINE"); }
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. */ ExpandParam: if (Mac->ParamExp) { /* Ok, use token from parameter list */ TokSet (Mac->ParamExp); /* Create new line info for this parameter token */ if (Mac->ParamLI) { EndLine (Mac->ParamLI); } Mac->ParamLI = StartLine (&CurTok.Pos, LI_TYPE_MACPARAM, Mac->MacExpansions); /* Set pointer to next token */ Mac->ParamExp = Mac->ParamExp->Next; /* Done */ return 1; } else if (Mac->ParamLI) { /* There's still line info open from the parameter expansion - end it */ EndLine (Mac->ParamLI); Mac->ParamLI = 0; } /* We're not expanding macro parameters. Check if we have tokens left from * the macro itself. */ if (Mac->Exp) { /* Use next macro token */ TokSet (Mac->Exp); /* Create new line info for this token */ if (Mac->LI) { EndLine (Mac->LI); } Mac->LI = StartLine (&CurTok.Pos, LI_TYPE_MACRO, Mac->MacExpansions); /* Set pointer to next token */ Mac->Exp = Mac->Exp->Next; /* Is it a request for actual parameter count? */ if (CurTok.Tok == TOK_PARAMCOUNT) { CurTok.Tok = TOK_INTCON; CurTok.IVal = Mac->ParamCount; return 1; } /* Is it the name of a macro parameter? */ if (CurTok.Tok == TOK_MACPARAM) { /* Start to expand the parameter token list */ Mac->ParamExp = Mac->Params[CurTok.IVal]; /* Go back and expand the parameter */ goto ExpandParam; } /* If it's an identifier, it may in fact be a local symbol */ if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) && Mac->M->LocalCount) { /* Search for the local symbol in the list */ unsigned Index = 0; IdDesc* I = Mac->M->Locals; while (I) { if (SB_Compare (&CurTok.SVal, &I->Id) == 0) { /* 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. */ if (SB_At (&I->Id, 0) == LocalStart) { /* Must generate a local symbol */ SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X", LocalStart, Mac->LocalStart + Index); } else { /* Global symbol */ SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X", Mac->LocalStart + Index); } 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 */ TokSet (Mac->Final); FreeTokNode (Mac->Final); Mac->Final = 0; /* Problem: When a .define style macro is expanded within the call * of a classic one, the latter may be terminated and removed while * the expansion of the .define style macro is still active. Because * line info slots are "stacked", this runs into a CHECK FAILED. For * now, we will fix that by removing the .define style macro expansion * immediately, once the final token is placed. The better solution * would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot * to be called in FIFO order, but this is a bigger change. */ /* End of macro expansion and pop the input function */ FreeMacExp (Mac); PopInput (); /* The token was successfully set */ return 1; } MacEnd: /* End of macro expansion */ FreeMacExp (Mac); /* Pop the input function */ PopInput (); /* No token available */ return 0; }
static void StartExpClassic (MacExp* E) /* Start expanding a classic macro */ { token_t Term; /* Skip the macro name */ NextTok (); /* Read the actual parameters */ while (!TokIsSep (CurTok.Tok)) { TokNode* Last; /* Check for maximum parameter count */ if (E->ParamCount >= E->M->ParamCount) { ErrorSkip ("Too many macro parameters"); break; } /* The macro may optionally be enclosed in curly braces */ Term = GetTokListTerm (TOK_COMMA); /* Read tokens for one parameter, accept empty params */ Last = 0; while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) { TokNode* T; /* Check for end of file */ if (CurTok.Tok == TOK_EOF) { Error ("Unexpected end of file"); FreeMacExp (E); return; } /* Get the next token in a node */ T = NewTokNode (); /* Insert it into the list */ if (Last == 0) { E->Params [E->ParamCount] = T; } else { Last->Next = T; } Last = T; /* And skip it... */ NextTok (); } /* One parameter more */ ++E->ParamCount; /* If the macro argument was enclosed in curly braces, end-of-line * is an error. Skip the closing curly brace. */ if (Term == TOK_RCURLY) { if (CurTok.Tok == TOK_SEP) { Error ("End of line encountered within macro argument"); break; } NextTok (); } /* Check for a comma */ if (CurTok.Tok == TOK_COMMA) { NextTok (); } else { break; } } /* We must be at end of line now, otherwise something is wrong */ ExpectSep (); /* Insert a new token input function */ PushInput (MacExpand, E, ".MACRO"); }
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) { /* Ok, use token from parameter list */ TokSet (Mac->ParamExp); /* 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 */ TokSet (Mac->Exp); /* Set pointer to next token */ Mac->Exp = Mac->Exp->Next; /* Is it a request for actual parameter count? */ if (Tok == TOK_PARAMCOUNT) { Tok = TOK_INTCON; IVal = Mac->ParamCount; return 1; } /* Is it the name of a macro parameter? */ if (Tok == TOK_MACPARAM) { /* Start to expand the parameter token list */ Mac->ParamExp = Mac->Params [IVal]; /* Recursive call to expand the parameter */ return MacExpand (Mac); } /* If it's an identifier, it may in fact be a local symbol */ if ((Tok == TOK_IDENT || Tok == TOK_LOCAL_IDENT) && Mac->M->LocalCount) { /* Search for the local symbol in the list */ unsigned Index = 0; IdDesc* I = Mac->M->Locals; while (I) { if (SB_Compare (&SVal, &I->Id) == 0) { /* 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. */ if (SB_At (&I->Id, 0) == LocalStart) { /* Must generate a local symbol */ SB_Printf (&SVal, "%cLOCAL-MACRO_SYMBOL-%04X", LocalStart, Mac->LocalStart + Index); } else { /* Global symbol */ SB_Printf (&SVal, "LOCAL-MACRO_SYMBOL-%04X", Mac->LocalStart + Index); } 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 */ TokSet (Mac->Final); 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; }