/* Define the macro */
M = NewMacro (SVal, HashVal, 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,
/* May not have end of file in a macro definition */
if (Tok == TOK_EOF) {
Error (ERR_ENDMACRO_EXPECTED);
- return;
+ goto Done;
}
} else {
/* Accept a newline or end of file for new style macros */
if (Style == MAC_STYLE_CLASSIC) {
NextTok ();
}
+
+Done:
+ /* Switch out of raw token mode */
+ LeaveRawTokenMode ();
}
/* A define style macro must be called with as many actual parameters
* as there are formal ones. Get the parameter count.
- */
+ */
unsigned Count = M->ParamCount;
/* Skip the current token */
* is no colon, it's an assignment.
*/
if (Tok == TOK_EQ) {
- /* Skip the '=' */
- NextTok ();
- /* Define the symbol with the expression following the
- * '='
- */
- SymDef (Ident, Expression (), 0);
- /* Don't allow anything after a symbol definition */
- Done = 1;
+ /* Skip the '=' */
+ NextTok ();
+ /* Define the symbol with the expression following the '=' */
+ SymDef (Ident, Expression (), 0);
+ /* Don't allow anything after a symbol definition */
+ Done = 1;
} else {
- /* Define a label */
- SymDef (Ident, CurrentPC (), IsZPSeg ());
- /* Skip the colon. If NoColonLabels is enabled, allow labels
- * without a colon if there is no whitespace before the
- * identifier.
- */
- if (Tok != TOK_COLON) {
- if (HadWS || !NoColonLabels) {
- Error (ERR_COLON_EXPECTED);
- }
- if (Tok == TOK_NAMESPACE) {
- /* Smart :: handling */
- NextTok ();
- }
- } else {
+ /* Define a label */
+ SymDef (Ident, CurrentPC (), IsZPSeg ());
+ /* Skip the colon. If NoColonLabels is enabled, allow labels
+ * without a colon if there is no whitespace before the
+ * identifier.
+ */
+ if (Tok != TOK_COLON) {
+ if (HadWS || !NoColonLabels) {
+ Error (ERR_COLON_EXPECTED);
+ }
+ if (Tok == TOK_NAMESPACE) {
+ /* Smart :: handling */
+ NextTok ();
+ }
+ } else {
/* Skip the colon */
- NextTok ();
- }
+ NextTok ();
+ }
}
}
}
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+static unsigned RawMode = 0; /* Raw token mode flag/counter */
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned Parens = 0;
while (Parens != 0 || Tok != TOK_RPAREN) {
- /* Check for end of line or end of input */
- if (Tok == TOK_SEP || Tok == TOK_EOF) {
- Error (ERR_UNEXPECTED_EOL);
- return List;
- }
+ /* Check for end of line or end of input */
+ if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ Error (ERR_UNEXPECTED_EOL);
+ return List;
+ }
- /* Collect tokens in the given range */
- if (Current >= Start && Current < Start+Count) {
- /* Add the current token to the list */
- AddCurTok (List);
- }
+ /* Collect tokens in the given range */
+ if (Current >= Start && Current < Start+Count) {
+ /* Add the current token to the list */
+ AddCurTok (List);
+ }
- /* Check for and count parenthesii */
- if (Tok == TOK_LPAREN) {
- ++Parens;
- } else if (Tok == TOK_RPAREN) {
- --Parens;
- }
+ /* Check for and count parenthesii */
+ if (Tok == TOK_LPAREN) {
+ ++Parens;
+ } else if (Tok == TOK_RPAREN) {
+ --Parens;
+ }
- /* Get the next token */
- ++Current;
- NextTok ();
+ /* Get the next token */
+ ++Current;
+ NextTok ();
}
/* Eat the closing paren */
+static void FuncLeft (void)
+/* Handle the .LEFT function */
+{
+ long Count;
+ TokList* List;
+
+ /* Skip it */
+ NextTok ();
+
+ /* Left paren expected */
+ ConsumeLParen ();
+
+ /* Count argument */
+ Count = ConstExpression ();
+ if (Count < 0 || Count > 100) {
+ Error (ERR_RANGE);
+ Count = 1;
+ }
+ ConsumeComma ();
+
+ /* Read the token list */
+ List = CollectTokens (0, (unsigned) Count);
+
+ /* Since we want to insert the list before the now current token, we have
+ * to save the current token in some way and then skip it. To do this, we
+ * will add the current token at the end of the token list (so the list
+ * will never be empty), push the token list, and then skip the current
+ * token. This will replace the current token by the first token from the
+ * list (which will be the old current token in case the list was empty).
+ */
+ AddCurTok (List);
+
+ /* Insert it into the scanner feed */
+ PushTokList (List, ".LEFT");
+
+ /* Skip the current token */
+ NextTok ();
+}
+
+
+
static void FuncMid (void)
/* Handle the .MID function */
{
/* Start argument */
Start = ConstExpression ();
if (Start < 0 || Start > 100) {
- Error (ERR_RANGE);
+ Error (ERR_RANGE);
Start = 0;
}
ConsumeComma ();
/* Count argument */
Count = ConstExpression ();
if (Count < 0 || Count > 100) {
- Error (ERR_RANGE);
- Count = 1;
+ Error (ERR_RANGE);
+ Count = 1;
}
ConsumeComma ();
/* Read the token list */
List = CollectTokens ((unsigned) Start, (unsigned) Count);
+ /* Since we want to insert the list before the now current token, we have
+ * to save the current token in some way and then skip it. To do this, we
+ * will add the current token at the end of the token list (so the list
+ * will never be empty), push the token list, and then skip the current
+ * token. This will replace the current token by the first token from the
+ * list (which will be the old current token in case the list was empty).
+ */
+ AddCurTok (List);
+
/* Insert it into the scanner feed */
PushTokList (List, ".MID");
+
+ /* Skip the current token */
+ NextTok ();
+}
+
+
+
+static void FuncRight (void)
+/* Handle the .RIGHT function */
+{
+ long Count;
+ TokList* List;
+
+ /* Skip it */
+ NextTok ();
+
+ /* Left paren expected */
+ ConsumeLParen ();
+
+ /* Count argument */
+ Count = ConstExpression ();
+ if (Count < 0 || Count > 100) {
+ Error (ERR_RANGE);
+ Count = 1;
+ }
+ ConsumeComma ();
+
+ /* Read the complete token list */
+ List = CollectTokens (0, 9999);
+
+ /* Delete tokens from the list until Count tokens are remaining */
+ while (List->Count > Count) {
+ /* Get the first node */
+ TokNode* T = List->Root;
+
+ /* Remove it from the list */
+ List->Root = List->Root->Next;
+
+ /* Free the node */
+ FreeTokNode (T);
+
+ /* Corrent the token counter */
+ List->Count--;
+ }
+
+ /* Since we want to insert the list before the now current token, we have
+ * to save the current token in some way and then skip it. To do this, we
+ * will add the current token at the end of the token list (so the list
+ * will never be empty), push the token list, and then skip the current
+ * token. This will replace the current token by the first token from the
+ * list (which will be the old current token in case the list was empty).
+ */
+ AddCurTok (List);
+
+ /* Insert it into the scanner feed */
+ PushTokList (List, ".RIGHT");
+
+ /* Skip the current token */
+ NextTok ();
}
/* Get the next raw token */
NextRawTok ();
- /* Check for token handling functions */
- switch (Tok) {
+ /* In raw mode, pass the token unchanged */
+ if (RawMode == 0) {
+
+ /* Execute token handling functions */
+ switch (Tok) {
- case TOK_CONCAT:
- FuncConcat ();
- break;
+ case TOK_CONCAT:
+ FuncConcat ();
+ break;
- case TOK_MID:
- FuncMid ();
- break;
+ case TOK_LEFT:
+ FuncLeft ();
+ break;
- case TOK_STRING:
- FuncString ();
- break;
+ case TOK_MID:
+ FuncMid ();
+ break;
- default:
- /* Quiet down gcc */
- break;
+ case TOK_RIGHT:
+ FuncRight ();
+ break;
+ case TOK_STRING:
+ FuncString ();
+ break;
+
+ default:
+ /* Quiet down gcc */
+ break;
+
+ }
}
}
void SkipUntilSep (void)
-/* Skip tokens until we reach a line separator */
+/* Skip tokens until we reach a line separator or end of file */
{
while (Tok != TOK_SEP && Tok != TOK_EOF) {
NextTok ();
+void EnterRawTokenMode (void)
+/* Enter raw token mode. In raw mode, token handling functions are not
+ * executed, but the function tokens are passed untouched to the upper
+ * layer. Raw token mode is used when storing macro tokens for later
+ * use.
+ * Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
+ */
+{
+ ++RawMode;
+}
+
+
+
+void LeaveRawTokenMode (void)
+/* Leave raw token mode. */
+{
+ PRECONDITION (RawMode > 0);
+ --RawMode;
+}
+
+
+
/* Consume a comma */
void SkipUntilSep (void);
-/* Skip tokens until we reach a line separator */
+/* Skip tokens until we reach a line separator or end of file */
+
+void EnterRawTokenMode (void);
+/* Enter raw token mode. In raw mode, token handling functions are not
+ * executed, but the function tokens are passed untouched to the upper
+ * layer. Raw token mode is used when storing macro tokens for later
+ * use.
+ * Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
+ */
+
+void LeaveRawTokenMode (void);
+/* Leave raw token mode. */
static void DoUnexpected (void);
+/* Got an unexpected keyword */
+
+static void DoInvalid (void);
+/* Handle a token that is invalid here, since it should have been handled on
+ * a much lower level of the expression hierarchy. Getting this sort of token
+ * means that the lower level code has bugs.
+ * This function differs to DoUnexpected in that the latter may be triggered
+ * by the user by using keywords in the wrong location. DoUnexpected is not
+ * an error in the assembler itself, while DoInvalid is.
+ */
+static void DoInvalid (void)
+/* Handle a token that is invalid here, since it should have been handled on
+ * a much lower level of the expression hierarchy. Getting this sort of token
+ * means that the lower level code has bugs.
+ * This function differs to DoUnexpected in that the latter may be triggered
+ * by the user by using keywords in the wrong location. DoUnexpected is not
+ * an error in the assembler itself, while DoInvalid is.
+ */
+{
+ Internal ("Unexpected token: %s", Keyword);
+}
+
+
+
static void DoLineCont (void)
/* Switch the use of line continuations */
{
-static void DoMid (void)
-/* Handle .MID - this should never happen, since the keyword is actually
- * handled on a much lower level of the expression hierarchy.
- */
-{
- Internal ("Unexpected token: .MID");
-}
-
-
-
static void DoNull (void)
/* Switch to the NULL segment */
{
{ ccNone, DoImportZP },
{ ccNone, DoIncBin },
{ ccNone, DoInclude },
+ { ccNone, DoInvalid }, /* .LEFT */
{ ccNone, DoLineCont },
{ ccNone, DoList },
{ ccNone, DoListBytes },
{ ccNone, DoMacPack },
{ ccNone, DoMacro },
{ ccNone, DoUnexpected }, /* .MATCH */
- { ccNone, DoMid },
+ { ccNone, DoInvalid }, /* .MID */
{ ccNone, DoNull },
{ ccNone, DoOrg },
{ ccNone, DoOut },
{ ccNone, DoReloc },
{ ccNone, DoRepeat },
{ ccNone, DoRes },
+ { ccNone, DoInvalid }, /* .RIGHT */
{ ccNone, DoROData },
{ ccNone, DoSegment },
{ ccNone, DoSmart },
{ "IMPORTZP", TOK_IMPORTZP },
{ "INCBIN", TOK_INCBIN },
{ "INCLUDE", TOK_INCLUDE },
+ { "LEFT", TOK_LEFT },
{ "LINECONT", TOK_LINECONT },
{ "LIST", TOK_LIST },
{ "LISTBYTES", TOK_LISTBYTES },
{ "RELOC", TOK_RELOC },
{ "REPEAT", TOK_REPEAT },
{ "RES", TOK_RES },
+ { "RIGHT", TOK_RIGHT },
{ "RODATA", TOK_RODATA },
{ "SEGMENT", TOK_SEGMENT },
{ "SHL", TOK_SHL },
TOK_IMPORTZP,
TOK_INCBIN,
TOK_INCLUDE,
+ TOK_LEFT,
TOK_LINECONT,
TOK_LIST,
TOK_LISTBYTES,
TOK_REFERENCED,
TOK_RELOC,
TOK_REPEAT,
- TOK_RES,
+ TOK_RES,
+ TOK_RIGHT,
TOK_RODATA,
TOK_SEGMENT,
TOK_SMART,
#include "../common/xmalloc.h"
+#include "error.h"
#include "istack.h"
#include "scanner.h"
#include "toklist.h"
/* Cast the generic pointer to an actual list */
TokList* L = List;
+ /* Last may never be a NULL pointer, otherwise there's a bug in the code */
+ CHECK (L->Last != 0);
+
/* Set the next token from the list */
TokSet (L->Last);
+ /* Set the pointer to the next token */
+ L->Last = L->Last->Next;
+
/* If this was the last token, decrement the repeat counter. If it goes
* zero, delete the list and remove the function from the stack.
*/