NextToken ();
/* Need left parenthesis */
- ConsumeLParen ();
+ if (!ConsumeLParen ()) {
+ return;
+ }
/* String literal */
if (CurTok.Tok != TOK_SCONST) {
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hexval.c */
+/* */
+/* Convert hex digits to numeric values */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "chartype.h"
+
+/* cc65 */
+#include "error.h"
+#include "hexval.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HexVal (int C)
+/* Convert a hex digit into a value. The function will emit an error for
+ * invalid hex digits.
+ */
+{
+ if (!IsXDigit (C)) {
+ Error ("Invalid hexadecimal digit: `%c'", C);
+ }
+ if (IsDigit (C)) {
+ return C - '0';
+ } else {
+ return toupper (C) - 'A' + 10;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hexval.h */
+/* */
+/* Convert hex digits to numeric values */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef HEXVAL_H
+#define HEXVAL_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HexVal (int C);
+/* Convert a hex digit into a value. The function will emit an error for
+ * invalid hex digits.
+ */
+
+
+
+/* End of hexval.h */
+#endif
+
+
+
+
+
function.o \
global.o \
goto.o \
+ hexval.o \
ident.o \
incpath.o \
input.o \
pragma.o \
reginfo.o \
scanner.o \
+ scanstrbuf.o \
segments.o \
stdfunc.o \
stmt.o \
function.obj \
global.obj \
goto.obj \
+ hexval.obj \
ident.obj \
incpath.obj \
input.obj \
pragma.obj \
reginfo.obj \
scanner.obj \
+ scanstrbuf.obj \
segments.obj \
stdfunc.obj \
stmt.obj \
FILE funcdesc.obj
FILE function.obj
FILE global.obj
-FILE goto.obj
+FILE goto.obj
+FILE hexval.obj
FILE ident.obj
FILE incpath.obj
FILE input.obj
FILE pragma.obj
FILE reginfo.obj
FILE scanner.obj
+FILE scanstrbuf.obj
FILE segments.obj
FILE stdfunc.obj
FILE stmt.obj
#include "global.h"
#include "litpool.h"
#include "scanner.h"
+#include "scanstrbuf.h"
#include "segments.h"
#include "symtab.h"
#include "pragma.h"
PR_RODATASEG,
PR_SIGNEDCHARS,
PR_STATICLOCALS,
- PR_ZPSYM,
+ PR_ZPSYM,
PR_COUNT
} pragma_t;
+static void PragmaErrorSkip (void)
+/* Called in case of an error, skips tokens until the closing paren or a
+ * semicolon is reached.
+ */
+{
+ static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
+ SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
+}
+
+
+
static int CmpKey (const void* Key, const void* Elem)
/* Compare function for bsearch */
{
-static void StringPragma (void (*Func) (const char*))
+static void StringPragma (StrBuf* B, void (*Func) (const char*))
/* Handle a pragma that expects a string parameter */
{
- if (CurTok.Tok != TOK_SCONST) {
- Error ("String literal expected");
- } else {
- /* Get the string */
- const char* Name = GetLiteral (CurTok.IVal);
+ StrBuf S;
+ if (SB_GetString (B, &S)) {
/* Call the given function with the string argument */
- Func (Name);
-
- /* Reset the string pointer, removing the string from the pool */
- ResetLiteralPoolOffs (CurTok.IVal);
+ Func (SB_GetConstBuf (&S));
+ } else {
+ Error ("String literal expected");
}
-
- /* Skip the string (or error) token */
- NextToken ();
}
-static void SegNamePragma (segment_t Seg)
+static void SegNamePragma (StrBuf* B, segment_t Seg)
/* Handle a pragma that expects a segment name parameter */
{
- if (CurTok.Tok != TOK_SCONST) {
- Error ("String literal expected");
- } else {
- /* Get the segment name */
- const char* Name = GetLiteral (CurTok.IVal);
+ StrBuf S;
+
+ if (SB_GetString (B, &S)) {
+
+ /* Get the string */
+ const char* Name = SB_GetConstBuf (&S);
/* Check if the name is valid */
if (ValidSegName (Name)) {
}
- /* Reset the string pointer, removing the string from the pool */
- ResetLiteralPoolOffs (CurTok.IVal);
+ } else {
+ Error ("String literal expected");
}
-
- /* Skip the string (or error) token */
- NextToken ();
}
-static void CharMapPragma (void)
+static void CharMapPragma (StrBuf* B)
/* Change the character map */
{
unsigned Index, C;
-static void FlagPragma (unsigned char* Flag)
+static void FlagPragma (StrBuf* B, unsigned char* Flag)
/* Handle a pragma that expects a boolean paramater */
{
- /* Read a constant integer expression */
- ExprDesc Val;
- ConstIntExpr (&Val);
-
- /* Store the value into the flag parameter */
- *Flag = (Val.ConstVal != 0);
+ ident Ident;
+
+ if (SB_Peek (B) == '0') {
+ SB_Skip (B);
+ *Flag = 0;
+ } else if (SB_Peek (B) == '1') {
+ SB_Skip (B);
+ *Flag = 1;
+ } else if (SB_GetSym (B, Ident)) {
+ if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) {
+ *Flag = 1;
+ } else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) {
+ *Flag = 0;
+ } else {
+ Error ("Pragma argument must be one of `on', `off', `true' or `false'");
+ }
+ } else {
+ Error ("Invalid pragma argument");
+ }
}
-void DoPragma (void)
-/* Handle pragmas */
+static void ParsePragma (void)
+/* Parse the contents of the _Pragma statement */
{
pragma_t Pragma;
+ ident Ident;
- /* Skip the token itself */
+ /* Create a string buffer from the string literal */
+ StrBuf B = AUTO_STRBUF_INITIALIZER;
+ GetLiteralStrBuf (&B, CurTok.IVal);
+
+ /* Reset the string pointer, effectivly clearing the string from the
+ * string table. Since we're working with one token lookahead, this
+ * will fail if the next token is also a string token, but that's a
+ * syntax error anyway, because we expect a right paren.
+ */
+ ResetLiteralPoolOffs (CurTok.IVal);
+
+ /* Skip the string token */
NextToken ();
- /* Identifier must follow */
- if (CurTok.Tok != TOK_IDENT) {
- Error ("Identifier expected");
- return;
+ /* Get the pragma name from the string */
+ SB_SkipWhite (&B);
+ if (!SB_GetSym (&B, Ident)) {
+ Error ("Invalid pragma");
+ return;
}
- /* Search for the name, then skip the identifier */
- Pragma = FindPragma (CurTok.Ident);
- NextToken ();
+ /* Search for the name */
+ Pragma = FindPragma (Ident);
/* Do we know this pragma? */
if (Pragma == PR_ILLEGAL) {
* for unknown pragmas, however, we're allowed to warn - and we will
* do so. Otherwise one typo may give you hours of bug hunting...
*/
- Warning ("Unknown #pragma `%s'", CurTok.Ident);
+ Warning ("Unknown pragma `%s'", Ident);
return;
}
/* Check for an open paren */
- ConsumeLParen ();
+ SB_SkipWhite (&B);
+ if (SB_Get (&B) != '(') {
+ Error ("'(' expected");
+ return;
+ }
+
+ /* Skip white space before the argument */
+ SB_SkipWhite (&B);
/* Switch for the different pragmas */
switch (Pragma) {
- case PR_BSSSEG:
- SegNamePragma (SEG_BSS);
- break;
+ case PR_BSSSEG:
+ SegNamePragma (&B, SEG_BSS);
+ break;
- case PR_CHARMAP:
- CharMapPragma ();
- break;
+ case PR_CHARMAP:
+ CharMapPragma (&B);
+ break;
- case PR_CHECKSTACK:
- FlagPragma (&CheckStack);
- break;
+ case PR_CHECKSTACK:
+ FlagPragma (&B, &CheckStack);
+ break;
- case PR_CODESEG:
- SegNamePragma (SEG_CODE);
- break;
+ case PR_CODESEG:
+ SegNamePragma (&B, SEG_CODE);
+ break;
- case PR_DATASEG:
- SegNamePragma (SEG_DATA);
- break;
+ case PR_DATASEG:
+ SegNamePragma (&B, SEG_DATA);
+ break;
- case PR_REGVARADDR:
- FlagPragma (&AllowRegVarAddr);
- break;
+ case PR_REGVARADDR:
+ FlagPragma (&B, &AllowRegVarAddr);
+ break;
- case PR_RODATASEG:
- SegNamePragma (SEG_RODATA);
- break;
+ case PR_RODATASEG:
+ SegNamePragma (&B, SEG_RODATA);
+ break;
- case PR_SIGNEDCHARS:
- FlagPragma (&SignedChars);
- break;
+ case PR_SIGNEDCHARS:
+ FlagPragma (&B, &SignedChars);
+ break;
- case PR_STATICLOCALS:
- FlagPragma (&StaticLocals);
- break;
+ case PR_STATICLOCALS:
+ FlagPragma (&B, &StaticLocals);
+ break;
- case PR_ZPSYM:
- StringPragma (MakeZPSym);
- break;
+ case PR_ZPSYM:
+ StringPragma (&B, MakeZPSym);
+ break;
- default:
+ default:
Internal ("Invalid pragma");
}
+ /* Closing paren expected */
+ SB_SkipWhite (&B);
+ if (SB_Get (&B) != ')') {
+ Error ("')' expected");
+ return;
+ }
+
+ /* Make sure nothing follows */
+ SB_SkipWhite (&B);
+ if (SB_Peek (&B) != '\0') {
+ Error ("Unexpected input following pragma directive");
+ }
+}
+
+
+
+void DoPragma (void)
+/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
+{
+ /* Skip the token itself */
+ NextToken ();
+
+ /* We expect an opening paren */
+ if (!ConsumeLParen ()) {
+ return;
+ }
+
+ /* String literal */
+ if (CurTok.Tok != TOK_SCONST) {
+
+ /* Print a diagnostic */
+ Error ("String literal expected");
+
+ /* Try some smart error recovery: Skip tokens until we reach the
+ * enclosing paren, or a semicolon.
+ */
+ PragmaErrorSkip ();
+
+ } else {
+
+ /* Parse the _Pragma statement */
+ ParsePragma ();
+ }
+
/* Closing paren needed */
ConsumeRParen ();
}
/* */
/* */
/* */
-/* (C) 1998-2001 Ullrich von Bassewitz */
+/* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/*****************************************************************************/
-/* code */
+/* Code */
/*****************************************************************************/
void DoPragma (void);
-/* Handle pragmas */
+/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
/* common */
#include "chartype.h"
#include "check.h"
+#include "inline.h"
#include "print.h"
#include "xmalloc.h"
static char* mline = mlinebuf;
static char* mptr;
-/* Flag: Expand macros in this line */
-static int ExpandMacros = 1;
-
/*****************************************************************************/
-static void keepch (char c)
+#ifdef HAVE_INLINE
+INLINE void KeepChar (char c)
/* Put character c into translation buffer. */
{
*mptr++ = c;
}
+#else
+#define KeepChar(c) *mptr++ = (c)
+#endif
-static void keepstr (const char* S)
+static void KeepStr (const char* S)
/* Put string str into translation buffer. */
{
unsigned Len = strlen (S);
+static void Stringize (const char* S)
+/* Stringize the given string: Add double quotes at start and end and preceed
+ * each occurance of " and \ by a backslash.
+ */
+{
+ KeepChar ('\"');
+ /* Replace any characters inside the string may not be part of a string
+ * unescaped.
+ */
+ while (*S) {
+ switch (*S) {
+ case '\"':
+ case '\\':
+ KeepChar ('\\');
+ /* FALLTHROUGH */
+ default:
+ KeepChar (*S);
+ break;
+ }
+ ++S;
+ }
+ KeepChar ('\"');
+}
+
+
+
+static void SwapLineBuffers (void)
+/* Swap both line buffers */
+{
+ /* Swap mline and line */
+ char* p = line;
+ line = mline;
+ mline = p;
+}
+
+
+
static void OldStyleComment (void)
/* Remove an old style C comment from line. */
{
/* Copy the characters inside the string */
while (CurC != '\0' && CurC != Quote) {
/* Keep an escaped char */
- if (CurC == '\\') {
+ if (CurC == '\\') {
*Target++ = CurC;
NextChar ();
}
Replacement = FindMacroArg (M, Ident);
if (Replacement) {
/* Macro arg, keep the replacement */
- keepstr (Replacement);
+ KeepStr (Replacement);
} else {
/* No macro argument, keep the original identifier */
- keepstr (Ident);
+ KeepStr (Ident);
}
} else if (CurC == '#' && IsIdent (NextC)) {
NextChar ();
SymName (Ident);
Replacement = FindMacroArg (M, Ident);
if (Replacement) {
- keepch ('\"');
- /* We have to escape any characters inside replacement that
- * may not be part of a string unescaped.
- */
- while (*Replacement) {
- switch (*Replacement) {
- case '\"':
- case '\\':
- keepch ('\\');
- /* FALLTHROUGH */
- default:
- keepch (*Replacement);
- break;
- }
- ++Replacement;
- }
- keepch ('\"');
+ /* Make a valid string from Replacement */
+ Stringize (Replacement);
} else {
- keepch ('#');
- keepstr (Ident);
+ /* No replacement - keep the input */
+ KeepChar ('#');
+ KeepStr (Ident);
}
} else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
}
--ParCount;
}
*B++ = CurC;
- NextChar ();
+ NextChar ();
}
} else if (IsBlank (CurC)) {
/* Squeeze runs of blanks */
}
} else {
/* Just copy the replacement text */
- keepstr (M->Replacement);
+ KeepStr (M->Replacement);
}
}
done = 1;
while (CurC != '\0') {
if (IsBlank (CurC)) {
- keepch (' ');
+ KeepChar (' ');
SkipBlank ();
} else if (IsIdent (CurC)) {
SymName (Ident);
}
if (!IsIdent (CurC)) {
PPError ("Identifier expected");
- *mptr++ = '0';
+ KeepChar ('0');
} else {
SymName (Ident);
- *mptr++ = IsMacro (Ident)? '1' : '0';
+ KeepChar (IsMacro (Ident)? '1' : '0');
if (HaveParen) {
SkipBlank();
if (CurC != ')') {
PPError ("`)' expected");
- } else {
+ } else {
NextChar ();
}
}
if (MaybeMacro (Ident[0])) {
done = 0;
}
- keepstr (Ident);
+ KeepStr (Ident);
}
} else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else if (CurC == '/' && NextC == '*') {
- keepch (' ');
+ KeepChar (' ');
OldStyleComment ();
} else if (ANSI == 0 && CurC == '/' && NextC == '/') {
- keepch (' ');
+ KeepChar (' ');
NewStyleComment ();
} else {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
}
- keepch ('\0');
+ KeepChar ('\0');
return done;
}
/* Loop substituting macros */
no_chg = 1;
while (CurC != '\0') {
- /* If we have an identifier, check if it's a macro */
+ /* If we have an identifier, check if it's a macro */
if (IsIdent (CurC)) {
SymName (Ident);
M = FindMacro (Ident);
ExpandMacro (M);
no_chg = 0;
} else {
- keepstr (Ident);
+ KeepStr (Ident);
}
} else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
}
-static void TranslateLine (void)
+static void PreprocessLine (void)
/* Translate one line. */
{
- int cnt;
- int Done;
+ unsigned I;
- Done = Pass1 (line, mline);
- if (ExpandMacros == 0) {
- Done = 1;
- ExpandMacros = 1; /* Reset to default */
- }
- cnt = 5;
- do {
+ /* Trim whitespace and remove comments. The function returns false if no
+ * identifiers were found that may be macros. If this is the case, no
+ * macro substitution is performed.
+ */
+ int Done = Pass1 (line, mline);
+
+ /* Repeatedly expand macros in the line */
+ for (I = 0; I < 5; ++I) {
/* Swap mline and line */
- char* p = line;
- line = mline;
- mline = p;
- if (Done)
- break;
- Done = Pass2 (line, mline);
- keepch ('\0');
- } while (--cnt);
+ SwapLineBuffers ();
+ if (Done) {
+ break;
+ }
+ /* Perform macro expansion */
+ Done = Pass2 (line, mline);
+ KeepChar ('\0');
+ }
/* Reinitialize line parsing */
InitLine (line);
/* Make sure the line infos for the tokens won't get removed */
if (sv1.LI) {
- UseLineInfo (sv1.LI);
+ UseLineInfo (sv1.LI);
}
if (sv2.LI) {
- UseLineInfo (sv2.LI);
+ UseLineInfo (sv2.LI);
}
/* Remove the #if from the line and add two semicolons as sentinels */
SkipBlank ();
S = line;
while (CurC != '\0') {
- *S++ = CurC;
- NextChar ();
+ *S++ = CurC;
+ NextChar ();
}
*S++ = ';';
*S++ = ';';
Preprocessing = 1;
/* Expand macros in this line */
- TranslateLine ();
+ PreprocessLine ();
/* Prime the token pump (remove old tokens from the stream) */
NextToken ();
*/
mptr = mline;
while (CurC != '\0' && CurC != RTerm) {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
*mptr = '\0';
+static void DoPragma (void)
+/* Handle a #pragma line by converting the #pragma preprocessor directive into
+ * the _Pragma() compiler operator.
+ */
+{
+ /* Skip blanks following the #pragma directive */
+ SkipBlank ();
+
+ /* Copy the remainder of the line into mline removing comments and ws */
+ Pass1 (lptr, mline);
+
+ /* Convert the directive into the operator */
+ mptr = line;
+ KeepStr ("_Pragma (");
+ Stringize (mline);
+ KeepChar (')');
+ *mptr = '\0';
+
+ /* Initialize reading from line */
+ InitLine (line);
+}
+
+
+
void Preprocess (void)
/* Preprocess a line */
{
- int Skip;
- ident Directive;
+ int Skip;
+ ident Directive;
/* Skip white space at the beginning of the line */
SkipBlank ();
}
break;
- case PP_ELIF:
- if (IfIndex >= 0) {
- if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
-
- /* Handle as #else/#if combination */
- if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
- Skip = !Skip;
- }
- IfStack[IfIndex] |= IFCOND_ELSE;
- Skip = DoIf (Skip);
-
- /* #elif doesn't need a terminator */
- IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
- } else {
- PPError ("Duplicate #else/#elif");
- }
+ case PP_ELIF:
+ if (IfIndex >= 0) {
+ if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
+
+ /* Handle as #else/#if combination */
+ if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
+ Skip = !Skip;
+ }
+ IfStack[IfIndex] |= IFCOND_ELSE;
+ Skip = DoIf (Skip);
+
+ /* #elif doesn't need a terminator */
+ IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
+ } else {
+ PPError ("Duplicate #else/#elif");
+ }
} else {
PPError ("Unexpected #elif");
}
/* Remove any clauses on top of stack that do not
* need a terminating #endif.
*/
- while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
+ while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
--IfIndex;
}
break;
case PP_LINE:
- /* Not allowed in strict ANSI mode */
+ /* Not allowed in strict ANSI mode */
if (!Skip && ANSI) {
PPError ("Preprocessor directive expected");
ClearLine ();
- }
- break;
+ }
+ break;
case PP_PRAGMA:
- if (!Skip) {
- /* Don't expand macros in this line */
- ExpandMacros = 0;
- /* #pragma is handled on the scanner level */
- goto Done;
- }
+ if (!Skip) {
+ DoPragma ();
+ goto Done;
+ }
break;
case PP_UNDEF:
PPError ("Preprocessor directive expected");
ClearLine ();
}
- }
+ }
}
if (NextLine () == 0) {
}
return;
}
- SkipBlank ();
+ SkipBlank ();
}
+ PreprocessLine ();
+
Done:
- TranslateLine ();
Print (stdout, 2, "line: %s\n", line);
}
#include "error.h"
#include "function.h"
#include "global.h"
+#include "hexval.h"
#include "ident.h"
#include "input.h"
#include "litpool.h"
unsigned char Tok; /* The token */
unsigned char Type; /* Token type */
} Keywords [] = {
+ { "_Pragma", TOK_PRAGMA, TT_C },
{ "__A__", TOK_A, TT_C },
{ "__AX__", TOK_AX, TT_C },
{ "__EAX__", TOK_EAX, TT_C },
-static unsigned HexVal (int c)
-/* Convert a hex digit into a value */
-{
- if (!IsXDigit (c)) {
- Error ("Invalid hexadecimal digit: `%c'", c);
- }
- if (IsDigit (c)) {
- return c - '0';
- } else {
- return toupper (c) - 'A' + 10;
- }
-}
-
-
-
static void SetTok (int tok)
/* Set NextTok.Tok and bump line ptr */
{
SetTok (TOK_COMP);
break;
- case '#':
- /* Skip it and following whitespace */
- do {
- NextChar ();
- } while (CurC == ' ');
- if (!IsSym (token) || strcmp (token, "pragma") != 0) {
- /* OOPS - should not happen */
- Error ("Preprocessor directive expected");
- }
- NextTok.Tok = TOK_PRAGMA;
- break;
-
default:
UnknownChar (CurC);
-void Consume (token_t Token, const char* ErrorMsg)
+int Consume (token_t Token, const char* ErrorMsg)
/* Eat token if it is the next in the input stream, otherwise print an error
- * message.
+ * message. Returns true if the token was found and false otherwise.
*/
{
if (CurTok.Tok == Token) {
NextToken ();
+ return 1;
} else {
Error (ErrorMsg);
+ return 0;
}
}
-void ConsumeColon (void)
+int ConsumeColon (void)
/* Check for a colon and skip it. */
{
- Consume (TOK_COLON, "`:' expected");
+ return Consume (TOK_COLON, "`:' expected");
}
-void ConsumeSemi (void)
+int ConsumeSemi (void)
/* Check for a semicolon and skip it. */
{
/* Try do be smart about typos... */
if (CurTok.Tok == TOK_SEMI) {
- NextToken ();
+ NextToken ();
+ return 1;
} else {
Error ("`;' expected");
if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
NextToken ();
}
+ return 0;
}
}
-void ConsumeComma (void)
+int ConsumeComma (void)
/* Check for a comma and skip it. */
{
/* Try do be smart about typos... */
if (CurTok.Tok == TOK_COMMA) {
- NextToken ();
+ NextToken ();
+ return 1;
} else {
Error ("`,' expected");
if (CurTok.Tok == TOK_SEMI) {
NextToken ();
}
+ return 0;
}
}
-void ConsumeLParen (void)
+int ConsumeLParen (void)
/* Check for a left parenthesis and skip it */
{
- Consume (TOK_LPAREN, "`(' expected");
+ return Consume (TOK_LPAREN, "`(' expected");
}
-void ConsumeRParen (void)
+int ConsumeRParen (void)
/* Check for a right parenthesis and skip it */
{
- Consume (TOK_RPAREN, "`)' expected");
+ return Consume (TOK_RPAREN, "`)' expected");
}
-void ConsumeLBrack (void)
+int ConsumeLBrack (void)
/* Check for a left bracket and skip it */
{
- Consume (TOK_LBRACK, "`[' expected");
+ return Consume (TOK_LBRACK, "`[' expected");
}
-void ConsumeRBrack (void)
+int ConsumeRBrack (void)
/* Check for a right bracket and skip it */
{
- Consume (TOK_RBRACK, "`]' expected");
+ return Consume (TOK_RBRACK, "`]' expected");
}
-void ConsumeLCurly (void)
+int ConsumeLCurly (void)
/* Check for a left curly brace and skip it */
{
- Consume (TOK_LCURLY, "`{' expected");
+ return Consume (TOK_LCURLY, "`{' expected");
}
-void ConsumeRCurly (void)
+int ConsumeRCurly (void)
/* Check for a right curly brace and skip it */
{
- Consume (TOK_RCURLY, "`}' expected");
+ return Consume (TOK_RCURLY, "`}' expected");
}
/* */
/* */
/* */
-/* (C) 1998-2001 Ullrich von Bassewitz */
+/* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
* This routine is used for error recovery.
*/
-void Consume (token_t Token, const char* ErrorMsg);
+int Consume (token_t Token, const char* ErrorMsg);
/* Eat token if it is the next in the input stream, otherwise print an error
- * message.
+ * message. Returns true if the token was found and false otherwise.
*/
-void ConsumeColon (void);
+int ConsumeColon (void);
/* Check for a colon and skip it. */
-void ConsumeSemi (void);
+int ConsumeSemi (void);
/* Check for a semicolon and skip it. */
-void ConsumeComma (void);
+int ConsumeComma (void);
/* Check for a comma and skip it. */
-void ConsumeLParen (void);
+int ConsumeLParen (void);
/* Check for a left parenthesis and skip it */
-void ConsumeRParen (void);
+int ConsumeRParen (void);
/* Check for a right parenthesis and skip it */
-void ConsumeLBrack (void);
+int ConsumeLBrack (void);
/* Check for a left bracket and skip it */
-void ConsumeRBrack (void);
+int ConsumeRBrack (void);
/* Check for a right bracket and skip it */
-void ConsumeLCurly (void);
+int ConsumeLCurly (void);
/* Check for a left curly brace and skip it */
-void ConsumeRCurly (void);
+int ConsumeRCurly (void);
/* Check for a right curly brace and skip it */
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanstrbuf.c */
+/* */
+/* Small scanner for input from a StrBuf */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "chartype.h"
+
+/* cc65 */
+#include "error.h"
+#include "hexval.h"
+#include "ident.h"
+#include "scanstrbuf.h"
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static char ParseChar (StrBuf* B)
+/* Parse a character. Converts \n into EOL, etc. */
+{
+ unsigned I;
+ int C;
+
+ /* Check for escape chars */
+ if ((C = SB_Get (B)) == '\\') {
+ switch (SB_Get (B)) {
+ case 'b':
+ C = '\b';
+ break;
+ case 'f':
+ C = '\f';
+ break;
+ case 'r':
+ C = '\r';
+ break;
+ case 'n':
+ C = '\n';
+ break;
+ case 't':
+ C = '\t';
+ break;
+ case '\"':
+ C = '\"';
+ break;
+ case '\'':
+ C = '\'';
+ break;
+ case '\\':
+ C = '\\';
+ break;
+ case 'x':
+ case 'X':
+ /* Hex character constant */
+ C = HexVal (SB_Get (B)) << 4;
+ C |= HexVal (SB_Get (B));
+ break;
+ case '0':
+ /* Octal constant */
+ C = 0;
+ goto Octal;
+ case '1':
+ /* Octal constant */
+ C = 1;
+Octal: I = 0;
+ while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && I++ < 4) {
+ C = (C << 3) | (SB_Get (B) - '0');
+ }
+ break;
+ default:
+ Error ("Illegal character constant");
+ C = ' ';
+ break;
+ }
+ }
+
+ /* Return the character */
+ return C;
+}
+
+
+
+
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void SB_SkipWhite (StrBuf* B)
+/* Skip whitespace in the string buffer */
+{
+ while (IsBlank (SB_Peek (B))) {
+ SB_Skip (B);
+ }
+}
+
+
+
+int SB_GetSym (StrBuf* B, char* S)
+/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
+ * characters. Returns 1 if a symbol was found and 0 otherwise.
+ */
+{
+ if (IsIdent (SB_Peek (B))) {
+ unsigned I = 0;
+ char C = SB_Peek (B);
+ do {
+ if (I < MAX_IDENTLEN) {
+ ++I;
+ *S++ = C;
+ }
+ SB_Skip (B);
+ C = SB_Peek (B);
+ } while (IsIdent (C) || IsDigit (C));
+ *S = '\0';
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+
+int SB_GetString (StrBuf* B, StrBuf* S)
+/* Get a string from the string buffer. S will be initialized by the function
+ * and will return the correctly terminated string on return. The function
+ * returns 1 if a string was found and 0 otherwise.
+ */
+{
+ char C;
+
+ /* Initialize S */
+ *S = AUTO_STRBUF_INITIALIZER;
+ if (SB_Peek (B) == '\"') {
+
+ /* String follows, be sure to concatenate strings */
+ while (SB_Peek (B) == '\"') {
+
+ /* Skip the quote char */
+ SB_Skip (B);
+
+ /* Read the actual string contents */
+ while ((C = SB_Peek (B)) != '\"') {
+ if (C == '\0') {
+ Error ("Unexpected end of string");
+ break;
+ }
+ SB_AppendChar (S, ParseChar (B));
+ }
+
+ /* Skip the closing quote char if there was one */
+ SB_Skip (B);
+
+ /* Skip white space, read new input */
+ SB_SkipWhite (B);
+ }
+
+ /* Terminate the string */
+ SB_Terminate (S);
+
+ /* Success */
+ return 1;
+
+ } else {
+
+ /* Not a string */
+ SB_Terminate (S);
+ return 0;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanstrbuf.h */
+/* */
+/* Small scanner for input from a StrBuf */
+/* */
+/* */
+/* */
+/* (C) 2002 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SCANSTRBUF_H
+#define SCANSTRBUF_H
+
+
+
+/* common */
+#include "strbuf.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void SB_SkipWhite (StrBuf* B);
+/* Skip whitespace in the string buffer */
+
+int SB_GetSym (StrBuf* B, char* S);
+/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
+ * characters. Returns 1 if a symbol was found and 0 otherwise.
+ */
+
+int SB_GetString (StrBuf* B, StrBuf* S);
+/* Get a string from the string buffer. S will be initialized by the function
+ * and will return the correctly terminated string on return. The function
+ * returns 1 if a string was found and 0 otherwise.
+ */
+
+
+
+
+/* End of scanstrbuf.h */
+#endif
+
+
+
+
+