/* */
/* */
/* */
-/* (C) 2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 2000-2003 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
+#include <stdio.h>
+#include <string.h>
+
+/* common */
+#include "check.h"
+
+/* ca65 */
#include "error.h"
#include "expr.h"
#include "scanner.h"
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+static unsigned RawMode = 0; /* Raw token mode flag/counter */
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/* Read the token list */
unsigned Current = 0;
unsigned Parens = 0;
- while (Parens != 0 && Tok != TOK_RPAREN) {
+ 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 (TokIsSep (Tok)) {
+ 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 */
- NextTok ();
+ /* Get the next token */
+ ++Current;
+ NextTok ();
}
/* Eat the closing paren */
+static void FuncConcat (void)
+/* Handle the .CONCAT function */
+{
+ char Buf[MAX_STR_LEN+1];
+ char* B;
+ unsigned Length;
+ unsigned L;
+
+ /* Skip it */
+ NextTok ();
+
+ /* Left paren expected */
+ ConsumeLParen ();
+
+ /* Concatenate any number of strings */
+ B = Buf;
+ B[0] = '\0';
+ Length = 0;
+ while (1) {
+
+ /* Next token must be a string */
+ if (Tok != TOK_STRCON) {
+ Error (ERR_STRCON_EXPECTED);
+ SkipUntilSep ();
+ return;
+ }
+
+ /* Get the length of the string const and check total length */
+ L = strlen (SVal);
+ if (Length + L > MAX_STR_LEN) {
+ Error (ERR_STRING_TOO_LONG);
+ /* Try to recover */
+ SkipUntilSep ();
+ return;
+ }
+
+ /* Add the new string */
+ memcpy (B, SVal, L);
+ Length += L;
+ B += L;
+
+ /* Skip the string token */
+ NextTok ();
+
+ /* Comma means another argument */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ /* Done */
+ break;
+ }
+ }
+
+ /* Terminate the string */
+ *B = '\0';
+
+ /* We expect a closing parenthesis, but will not skip it but replace it
+ * by the string token just created.
+ */
+ if (Tok != TOK_RPAREN) {
+ Error (ERR_RPAREN_EXPECTED);
+ } else {
+ Tok = TOK_STRCON;
+ strcpy (SVal, Buf);
+ }
+}
+
+
+
+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 */
{
- long Start;
+ long Start;
long Count;
TokList* List;
NextTok ();
/* Left paren expected */
- ConsumeRParen ();
+ ConsumeLParen ();
/* Start argument */
Start = ConstExpression ();
if (Start < 0 || Start > 100) {
- Error (ERR_RANGE);
- Start = 0;
+ Error (ERR_RANGE);
+ Start = 0;
}
ConsumeComma ();
/* Count argument */
Count = ConstExpression ();
- if (Count > 100) {
- Error (ERR_RANGE);
- Count = 1;
+ if (Count < 0 || Count > 100) {
+ 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 > (unsigned) 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 ();
+}
+
+
+
+static void FuncString (void)
+/* Handle the .STRING function */
+{
+ char Buf[MAX_STR_LEN+1];
+
+ /* Skip it */
+ NextTok ();
+
+ /* Left paren expected */
+ ConsumeLParen ();
+
+ /* Accept identifiers or numeric expressions */
+ if (Tok == TOK_IDENT) {
+ /* Save the identifier, then skip it */
+ strcpy (Buf, SVal);
+ NextTok ();
+ } else {
+ /* Numeric expression */
+ long Val = ConstExpression ();
+ sprintf (Buf, "%ld", Val);
+ }
+
+ /* We expect a closing parenthesis, but will not skip it but replace it
+ * by the string token just created.
+ */
+ if (Tok != TOK_RPAREN) {
+ Error (ERR_RPAREN_EXPECTED);
+ } else {
+ Tok = TOK_STRCON;
+ strcpy (SVal, Buf);
+ }
}
/* 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_MID:
- FuncMid ();
- break;
+ case TOK_CONCAT:
+ FuncConcat ();
+ break;
- default:
- /* Quiet down gcc */
- break;
+ case TOK_LEFT:
+ FuncLeft ();
+ break;
+ case TOK_MID:
+ FuncMid ();
+ 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) {
+ while (!TokIsSep (Tok)) {
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;
+}
+
+
+