X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fca65%2Fnexttok.c;h=9c3b709b2e2f99a44c0a68cd5349082fe0807400;hb=b7c44015f78b5f65f0a45ebb75d7c163a999ad97;hp=39341263411aa32628a2dcee75c919eaa9d3b0a2;hpb=522c7e8c46d0aae3b13885a769ca4a9e87e36733;p=cc65 diff --git a/src/ca65/nexttok.c b/src/ca65/nexttok.c index 393412634..9c3b709b2 100644 --- a/src/ca65/nexttok.c +++ b/src/ca65/nexttok.c @@ -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 */ @@ -33,6 +33,13 @@ +#include +#include + +/* common */ +#include "check.h" + +/* ca65 */ #include "error.h" #include "expr.h" #include "scanner.h" @@ -41,6 +48,16 @@ +/*****************************************************************************/ +/* 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; +} + + +