/* */
/* */
/* */
-/* (C) 2000-2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
* true.
*/
{
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
Error ("String constant expected");
SkipUntilSep ();
return 0;
TokList* List = NewTokList ();
/* Determine if the list is enclosed in curly braces. */
- Token Term = GetTokListTerm (TOK_RPAREN);
+ token_t Term = GetTokListTerm (TOK_RPAREN);
/* Read the token list */
unsigned Current = 0;
- while (Tok != Term) {
+ while (CurTok.Tok != Term) {
/* Check for end of line or end of input */
- if (TokIsSep (Tok)) {
+ if (TokIsSep (CurTok.Tok)) {
Error ("Unexpected end of line");
return List;
}
static void FuncConcat (void)
/* Handle the .CONCAT function */
{
- char Buf[MAX_STR_LEN+1];
- char* B;
- unsigned Length;
- unsigned L;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
/* Skip it */
NextTok ();
ConsumeLParen ();
/* Concatenate any number of strings */
- B = Buf;
- B[0] = '\0';
- Length = 0;
while (1) {
/* Next token must be a string */
if (!LookAtStrCon ()) {
+ SB_Done (&Buf);
return;
}
- /* Get the length of the string const and check total length */
- L = strlen (SVal);
- if (Length + L > MAX_STR_LEN) {
- Error ("String is too long");
- /* Try to recover */
- SkipUntilSep ();
- return;
- }
-
- /* Add the new string */
- memcpy (B, SVal, L);
- Length += L;
- B += L;
+ /* Append the string */
+ SB_Append (&Buf, &CurTok.SVal);
/* Skip the string token */
NextTok ();
/* Comma means another argument */
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
} else {
/* Done */
}
}
- /* 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) {
+ if (CurTok.Tok != TOK_RPAREN) {
Error ("`)' expected");
} else {
- Tok = TOK_STRCON;
- strcpy (SVal, Buf);
+ CurTok.Tok = TOK_STRCON;
+ SB_Copy (&CurTok.SVal, &Buf);
}
+
+ /* Free the string buffer */
+ SB_Done (&Buf);
}
static void FuncIdent (void)
/* Handle the .IDENT function */
{
- char Buf[sizeof(SVal)];
- Token Id;
- unsigned Len;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+ token_t Id;
unsigned I;
/* Skip it */
/* Check that the string contains a valid identifier. While doing so,
* determine if it is a cheap local, or global one.
*/
- Len = strlen (SVal);
- if (Len == 0) {
- NoIdent ();
- return;
- }
- I = 0;
- if (SVal[0] == LocalStart) {
- if (Len < 2) {
- NoIdent ();
- return;
- }
- I = 1;
+ SB_Reset (&CurTok.SVal);
+
+ /* Check for a cheap local symbol */
+ if (SB_Peek (&CurTok.SVal) == LocalStart) {
+ SB_Skip (&CurTok.SVal);
Id = TOK_LOCAL_IDENT;
} else {
Id = TOK_IDENT;
}
- if (!IsIdStart (SVal[I])) {
+
+ /* Next character must be a valid identifier start */
+ if (!IsIdStart (SB_Get (&CurTok.SVal))) {
NoIdent ();
return;
}
- while (I < Len) {
- if (!IsIdChar (SVal[I])) {
+ for (I = SB_GetIndex (&CurTok.SVal); I < SB_GetLen (&CurTok.SVal); ++I) {
+ if (!IsIdChar (SB_AtUnchecked (&CurTok.SVal, I))) {
NoIdent ();
return;
}
- ++I;
}
if (IgnoreCase) {
UpcaseSVal ();
}
/* If anything is ok, save and skip the string. Check that the next token
- * is a right paren, in which case SVal is untouched. Replace the token by
- * a identifier token.
+ * is a right paren, then replace the token by an identifier token.
*/
- memcpy (Buf, SVal, Len+1);
+ SB_Copy (&Buf, &CurTok.SVal);
NextTok ();
- if (Tok != TOK_RPAREN) {
+ if (CurTok.Tok != TOK_RPAREN) {
Error ("`)' expected");
} else {
- Tok = Id;
- memcpy (SVal, Buf, Len+1);
+ CurTok.Tok = Id;
+ SB_Copy (&CurTok.SVal, &Buf);
}
+
+ /* Free buffer memory */
+ SB_Done (&Buf);
}
/* Count argument. Correct negative counts to zero. */
Count = ConstExpression ();
if (Count < 0) {
- Count = 1;
+ Count = 0;
}
ConsumeComma ();
static void FuncSPrintF (void)
/* Handle the .SPRINTF function */
{
- char Format[sizeof (SVal)]; /* User given format */
- const char* F = Format; /* User format pointer */
- StrBuf R = AUTO_STRBUF_INITIALIZER; /* Result string */
- StrBuf F1 = AUTO_STRBUF_INITIALIZER; /* One format spec from F */
- StrBuf R1 = AUTO_STRBUF_INITIALIZER; /* One result */
+ StrBuf Format = STATIC_STRBUF_INITIALIZER; /* User supplied format */
+ StrBuf R = STATIC_STRBUF_INITIALIZER; /* Result string */
+ StrBuf F1 = STATIC_STRBUF_INITIALIZER; /* One format spec from F */
+ StrBuf R1 = STATIC_STRBUF_INITIALIZER; /* One result */
+ char C;
int Done;
long IVal; /* Integer value */
if (!LookAtStrCon ()) {
return;
}
- strcpy (Format, SVal);
+ SB_Copy (&Format, &CurTok.SVal);
NextTok ();
/* Walk over the format string, generating the function result in R */
while (1) {
/* Get the next char from the format string and check for EOS */
- if (*F == '\0') {
+ if (SB_Peek (&Format) == '\0') {
break;
}
/* Check for a format specifier */
- if (*F != '%') {
+ if (SB_Peek (&Format) != '%') {
/* No format specifier, just copy */
- SB_AppendChar (&R, *F++);
+ SB_AppendChar (&R, SB_Get (&Format));
continue;
}
- if (*++F == '%') {
+ SB_Skip (&Format);
+ if (SB_Peek (&Format) == '%') {
/* %% */
SB_AppendChar (&R, '%');
- ++F;
+ SB_Skip (&Format);
continue;
}
- if (*F == '\0') {
+ if (SB_Peek (&Format) == '\0') {
InvalidFormatString ();
break;
}
/* Check for flags */
Done = 0;
- while (*F != '\0' && !Done) {
- switch (*F) {
+ while ((C = SB_Peek (&Format)) != '\0' && !Done) {
+ switch (C) {
case '-': /* FALLTHROUGH */
case '+': /* FALLTHROUGH */
case ' ': /* FALLTHROUGH */
case '#': /* FALLTHROUGH */
- case '0': SB_AppendChar (&F1, *F++); break;
- default: Done = 1; break;
+ case '0': SB_AppendChar (&F1, SB_Get (&Format)); break;
+ default: Done = 1; break;
}
}
/* We do only support a numerical width field */
- while (IsDigit (*F)) {
- SB_AppendChar (&F1, *F++);
+ while (IsDigit (SB_Peek (&Format))) {
+ SB_AppendChar (&F1, SB_Get (&Format));
}
/* Precision - only positive numerical fields supported */
- if (*F == '.') {
- SB_AppendChar (&F1, *F++);
- while (IsDigit (*F)) {
- SB_AppendChar (&F1, *F++);
+ if (SB_Peek (&Format) == '.') {
+ SB_AppendChar (&F1, SB_Get (&Format));
+ while (IsDigit (SB_Peek (&Format))) {
+ SB_AppendChar (&F1, SB_Get (&Format));
}
}
/* Length modifiers aren't supported, so read the conversion specs */
- switch (*F) {
+ switch (SB_Peek (&Format)) {
case 'd':
case 'i':
* calling xsprintf later. Terminate the format string.
*/
SB_AppendChar (&F1, 'l');
- SB_AppendChar (&F1, *F++);
+ SB_AppendChar (&F1, SB_Get (&Format));
SB_Terminate (&F1);
/* The argument must be a constant expression */
case 's':
/* Add the format spec and terminate the format */
- SB_AppendChar (&F1, *F++);
+ SB_AppendChar (&F1, SB_Get (&Format));
SB_Terminate (&F1);
/* The argument must be a string constant */
if (!LookAtStrCon ()) {
/* Make it one */
- strcpy (SVal, "**undefined**");
+ SB_CopyStr (&CurTok.SVal, "**undefined**");
}
/* Format this argument according to the spec */
- SB_Printf (&R1, SB_GetConstBuf (&F1), SVal);
+ SB_Printf (&R1, SB_GetConstBuf (&F1), CurTok.SVal);
/* Skip the string constant */
NextTok ();
case 'c':
/* Add the format spec and terminate the format */
- SB_AppendChar (&F1, *F++);
+ SB_AppendChar (&F1, SB_Get (&Format));
SB_Terminate (&F1);
/* The argument must be a constant expression */
default:
Error ("Invalid format string");
- if (*F) {
- /* Don't skip beyond end of string */
- ++F;
- }
+ SB_Skip (&Format);
break;
}
}
- /* The length of the final result may not exceed the size of a string */
- if (SB_GetLen (&R) >= sizeof (SVal)) {
- Error ("Resulting string is too long");
- SB_Cut (&R, sizeof (SVal) - 1);
- }
-
/* Terminate the result string */
SB_Terminate (&R);
/* We expect a closing parenthesis, but will not skip it but replace it
* by the string token just created.
*/
- if (Tok != TOK_RPAREN) {
+ if (CurTok.Tok != TOK_RPAREN) {
Error ("`)' expected");
} else {
- Tok = TOK_STRCON;
- memcpy (SVal, SB_GetConstBuf (&R), SB_GetLen (&R) + 1);
+ CurTok.Tok = TOK_STRCON;
+ SB_Copy (&CurTok.SVal, &R);
}
/* Delete the string buffers */
- DoneStrBuf (&R);
- DoneStrBuf (&F1);
- DoneStrBuf (&R1);
+ SB_Done (&Format);
+ SB_Done (&R);
+ SB_Done (&F1);
+ SB_Done (&R1);
}
-
+
static void FuncString (void)
/* Handle the .STRING function */
{
- char Buf[MAX_STR_LEN+1];
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
/* Skip it */
NextTok ();
ConsumeLParen ();
/* Accept identifiers or numeric expressions */
- if (Tok == TOK_IDENT || Tok == TOK_LOCAL_IDENT) {
+ if (CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) {
/* Save the identifier, then skip it */
- strcpy (Buf, SVal);
+ SB_Copy (&Buf, &CurTok.SVal);
NextTok ();
} else {
/* Numeric expression */
long Val = ConstExpression ();
- sprintf (Buf, "%ld", Val);
+ SB_Printf (&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) {
+ if (CurTok.Tok != TOK_RPAREN) {
Error ("`)' expected");
} else {
- Tok = TOK_STRCON;
- strcpy (SVal, Buf);
+ CurTok.Tok = TOK_STRCON;
+ SB_Copy (&CurTok.SVal, &Buf);
}
+
+ /* Free string memory */
+ SB_Done (&Buf);
}
if (RawMode == 0) {
/* Execute token handling functions */
- switch (Tok) {
+ switch (CurTok.Tok) {
case TOK_CONCAT:
FuncConcat ();
-void Consume (Token Expected, const char* ErrMsg)
+void Consume (token_t Expected, const char* ErrMsg)
/* Consume Expected, print an error if we don't find it */
{
- if (Tok == Expected) {
+ if (CurTok.Tok == Expected) {
NextTok ();
} else {
- Error (ErrMsg);
+ Error ("%s", ErrMsg);
}
}
ExpectSep ();
/* If we are at end of line, skip it */
- if (Tok == TOK_SEP) {
+ if (CurTok.Tok == TOK_SEP) {
NextTok ();
}
}
void SkipUntilSep (void)
/* Skip tokens until we reach a line separator or end of file */
{
- while (!TokIsSep (Tok)) {
+ while (!TokIsSep (CurTok.Tok)) {
NextTok ();
}
}
* not skip the line separator.
*/
{
- if (!TokIsSep (Tok)) {
+ if (!TokIsSep (CurTok.Tok)) {
ErrorSkip ("Unexpected trailing garbage characters");
}
}