/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
+/* (C) 1998-2004 Ullrich von Bassewitz */
/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Handle the .MATCH and .XMATCH builtin functions */
{
int Result;
+ enum Token Term;
TokNode* Root = 0;
TokNode* Last = 0;
TokNode* Node;
/* A list of tokens follows. Read this list and remember it building a
* single linked list of tokens including attributes. The list is
- * terminated by a comma.
+ * either enclosed in curly braces, or terminated by a comma.
*/
- while (Tok != TOK_COMMA) {
+ if (Tok == TOK_LCURLY) {
+ NextTok ();
+ Term = TOK_RCURLY;
+ } else {
+ Term = TOK_COMMA;
+ }
+ while (Tok != Term) {
/* We may not end-of-line of end-of-file here */
if (TokIsSep (Tok)) {
NextTok ();
}
- /* Skip the comma */
+ /* Skip the terminator token*/
NextTok ();
- /* Read the second list which is terminated by the right parenthesis and
- * compare each token against the one in the first list.
+ /* If the token list was enclosed in curly braces, we expect a comma */
+ if (Term == TOK_RCURLY) {
+ ConsumeComma ();
+ }
+
+ /* Read the second list which is optionally enclosed in curly braces and
+ * terminated by the right parenthesis. Compare each token against the
+ * one in the first list.
*/
+ if (Tok == TOK_LCURLY) {
+ NextTok ();
+ Term = TOK_RCURLY;
+ } else {
+ Term = TOK_RPAREN;
+ }
Result = 1;
Node = Root;
- while (Tok != TOK_RPAREN) {
+ while (Tok != Term) {
/* We may not end-of-line of end-of-file here */
if (TokIsSep (Tok)) {
NextTok ();
}
+ /* If the token list was enclosed in curly braces, eat the closing brace */
+ if (Term == TOK_RCURLY) {
+ NextTok ();
+ }
+
/* Check if there are remaining tokens in the first list */
if (Node != 0) {
Result = 0;
static void StartExpClassic (Macro* M)
/* Start expanding the classic macro M */
{
- MacExp* E;
+ MacExp* E;
+ enum Token Term;
+
/* Skip the macro name */
NextTok ();
/* Check for maximum parameter count */
if (E->ParamCount >= M->ParamCount) {
- Error ("Too many macro parameters");
- SkipUntilSep ();
+ ErrorSkip ("Too many macro parameters");
break;
}
- /* Read tokens for one parameter, accept empty params */
+ /* The macro may optionally be enclosed in curly braces */
+ if (Tok == TOK_LCURLY) {
+ NextTok ();
+ Term = TOK_RCURLY;
+ } else {
+ Term = TOK_COMMA;
+ }
+
+ /* Read tokens for one parameter, accept empty params */
Last = 0;
- while (Tok != TOK_COMMA && Tok != TOK_SEP) {
+ while (Tok != Term && Tok != TOK_SEP) {
TokNode* T;
/* Check for end of file */
if (Tok == TOK_EOF) {
- Error ("Unexpected end of file");
- return;
+ Error ("Unexpected end of file");
+ FreeMacExp (E);
+ return;
}
/* Get the next token in a node */
if (Last == 0) {
E->Params [E->ParamCount] = T;
} else {
- Last->Next = T;
+ Last->Next = T;
}
Last = T;
/* 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 (Tok == TOK_SEP) {
+ Error ("End of line encountered within macro argument");
+ break;
+ }
+ NextTok ();
+ }
+
/* Check for a comma */
if (Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
- }
+ 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");
}
/* Read the actual parameters */
while (Count--) {
- TokNode* Last;
+ enum Token Term;
+ TokNode* Last;
+
+ /* The macro may optionally be enclosed in curly braces */
+ if (Tok == TOK_LCURLY) {
+ NextTok ();
+ Term = TOK_RCURLY;
+ } else {
+ Term = TOK_COMMA;
+ }
/* Check if there is really a parameter */
- if (TokIsSep (Tok) || Tok == TOK_COMMA) {
- Error ("Macro parameter expected");
- SkipUntilSep ();
- return;
- }
+ if (TokIsSep (Tok) || Tok == Term) {
+ ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
+ FreeMacExp (E);
+ return;
+ }
/* Read tokens for one parameter */
Last = 0;
/* And skip it... */
NextTok ();
- } while (Tok != TOK_COMMA && !TokIsSep (Tok));
+ } while (Tok != Term && !TokIsSep (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 (Tok)) {
+ Error ("End of line encountered within macro argument");
+ break;
+ }
+ NextTok ();
+ }
+
/* Check for a comma */
if (Count > 0) {
if (Tok == TOK_COMMA) {
/* 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 if macro
+ * To avoid it, remember the current token and re-insert it, once macro
* expansion is done.
*/
E->Final = NewTokNode ();
static TokList* CollectTokens (unsigned Start, unsigned Count)
-/* Read a list of tokens that is terminated by a right paren. For all tokens
- * starting at the one with index Start, and ending at (Start+Count-1), place
- * them into a token list, and return this token list.
+/* Read a list of tokens that is optionally enclosed in curly braces and
+ * terminated by a right paren. For all tokens starting at the one with index
+ * Start, and ending at (Start+Count-1), place them into a token list, and
+ * return this token list.
*/
{
+ enum Token Term;
+ unsigned Current;
+
/* Create the token list */
TokList* List = NewTokList ();
+ /* Determine if the list is enclosed in curly braces. */
+ if (Tok == TOK_LCURLY) {
+ NextTok ();
+ Term = TOK_RCURLY;
+ } else {
+ Term = TOK_LCURLY;
+ }
+
/* Read the token list */
- unsigned Current = 0;
- unsigned Parens = 0;
- while (Parens != 0 || Tok != TOK_RPAREN) {
+ Current = 0;
+ while (Tok != Term) {
/* Check for end of line or end of input */
if (TokIsSep (Tok)) {
AddCurTok (List);
}
- /* Check for and count parenthesii */
- if (Tok == TOK_LPAREN) {
- ++Parens;
- } else if (Tok == TOK_RPAREN) {
- --Parens;
- }
-
/* Get the next token */
++Current;
NextTok ();
}
- /* Eat the closing paren */
- ConsumeRParen ();
+ /* Eat the terminator token */
+ NextTok ();
+
+ /* If the list was enclosed in curly braces, we do expect now a right paren */
+ if (Term == TOK_RCURLY) {
+ ConsumeRParen ();
+ }
/* Return the list of collected tokens */
return List;
/* We expect a separator token */
ExpectSep ();
- /* If we have one, skip it */
+ /* If we are at end of line, skip it */
if (Tok == TOK_SEP) {
NextTok ();
}
Tok = TOK_RBRACK;
return;
+ case '{':
+ NextChar ();
+ Tok = TOK_LCURLY;
+ return;
+
+ case '}':
+ NextChar ();
+ Tok = TOK_RCURLY;
+ return;
+
case '<':
NextChar ();
if (C == '=') {
TOK_RPAREN, /* ) */
TOK_LBRACK, /* [ */
TOK_RBRACK, /* ] */
+ TOK_LCURLY, /* { */
+ TOK_RCURLY, /* } */
TOK_OVERRIDE_ZP, /* z: */
TOK_OVERRIDE_ABS, /* a: */