]> git.sur5r.net Git - cc65/blobdiff - src/ca65/nexttok.c
Add co65 utility
[cc65] / src / ca65 / nexttok.c
index 39341263411aa32628a2dcee75c919eaa9d3b0a2..9c3b709b2e2f99a44c0a68cd5349082fe0807400 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (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                                    */
 /*****************************************************************************/
@@ -59,29 +76,30 @@ static TokList* CollectTokens (unsigned Start, unsigned Count)
     /* 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 */
@@ -93,10 +111,120 @@ static TokList* CollectTokens (unsigned Start, unsigned Count)
 
 
 
+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;
 
@@ -104,31 +232,132 @@ static void FuncMid (void)
     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);
+    }
 }
 
 
@@ -139,17 +368,37 @@ void NextTok (void)
     /* 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;
+
+       }
     }
 }
 
@@ -208,12 +457,34 @@ void ConsumeComma (void)
 
 
 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;
+}
+
+
+