void AddCurTok (TokList* List) /* Add the current token to the token list */ { /* Create a token node with the current token value */ TokNode* T = NewTokNode (); /* Insert the node into the list */ if (List->Root == 0) { List->Root = T; } else { List->Last->Next = T; } List->Last = T; /* Count nodes */ List->Count++; }
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 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"); }
void MacDef (unsigned Style) /* Parse a macro definition */ { Macro* M; TokNode* N; int HaveParams; /* We expect a macro name here */ if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); MacSkipDef (Style); return; } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) { /* 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; } /* Did we already define that macro? */ if (HT_Find (&MacroTab, &CurTok.SVal) != 0) { /* Macro is already defined */ Error ("A macro named `%m%p' is already defined", &CurTok.SVal); /* Skip tokens until we reach the final .endmacro */ MacSkipDef (Style); return; } /* Define the macro */ M = NewMacro (&CurTok.SVal, Style); /* Switch to raw token mode and skip the macro name */ EnterRawTokenMode (); 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) { HaveParams = 1; } else { if (CurTok.Tok == TOK_LPAREN) { HaveParams = 1; NextTok (); } else { HaveParams = 0; } } /* Parse the parameter list */ if (HaveParams) { while (CurTok.Tok == TOK_IDENT) { /* Create a struct holding the identifier */ IdDesc* I = NewIdDesc (&CurTok.SVal); /* Insert the struct into the list, checking for duplicate idents */ if (M->ParamCount == 0) { M->Params = I; } else { IdDesc* List = M->Params; while (1) { if (SB_Compare (&List->Id, &CurTok.SVal) == 0) { Error ("Duplicate symbol `%m%p'", &CurTok.SVal); } if (List->Next == 0) { break; } else { List = List->Next; } } List->Next = I; } ++M->ParamCount; /* Skip the name */ NextTok (); /* Maybe there are more params... */ if (CurTok.Tok == TOK_COMMA) { 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 */ if (CurTok.Tok == TOK_ENDMACRO) { /* Done */ break; } /* May not have end of file in a macro definition */ if (CurTok.Tok == TOK_EOF) { Error ("`.ENDMACRO' expected"); goto Done; } } else { /* Accept a newline or end of file for new style macros */ if (TokIsSep (CurTok.Tok)) { break; } } /* Check for a .LOCAL declaration */ if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) { while (1) { IdDesc* I; /* Skip .local or comma */ NextTok (); /* Need an identifer */ if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) { Error ("Identifier expected"); SkipUntilSep (); break; } /* Put the identifier into the locals list and skip it */ I = NewIdDesc (&CurTok.SVal); I->Next = M->Locals; M->Locals = I; ++M->LocalCount; NextTok (); /* Check for end of list */ if (CurTok.Tok != TOK_COMMA) { break; } } /* We need end of line after the locals */ ConsumeSep (); continue; } /* Create a token node for the current token */ N = NewTokNode (); /* If the token is an identifier, check if it is a local parameter */ if (CurTok.Tok == TOK_IDENT) { unsigned Count = 0; IdDesc* I = M->Params; while (I) { if (SB_Compare (&I->Id, &CurTok.SVal) == 0) { /* Local param name, replace it */ N->T.Tok = TOK_MACPARAM; N->T.IVal = Count; break; } ++Count; I = I->Next; } } /* Insert the new token in the list */ if (M->TokCount == 0) { /* First token */ M->TokRoot = M->TokLast = N; } else { /* We have already tokens */ M->TokLast->Next = N; M->TokLast = N; } ++M->TokCount; /* Read the next token */ NextTok (); } /* Skip the .endmacro for a classic macro */ if (Style == MAC_STYLE_CLASSIC) { NextTok (); } /* Reset the Incomplete flag now that parsing is done */ M->Incomplete = 0; Done: /* Switch out of raw token mode */ LeaveRawTokenMode (); }