From ea50befaac9228edb2bab7f0bbf41881b4abc925 Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 29 Sep 2002 21:09:47 +0000 Subject: [PATCH] Redoing the pragma stuff git-svn-id: svn://svn.cc65.org/cc65/trunk@1413 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/asmstmt.c | 4 +- src/cc65/hexval.c | 67 +++++++++++ src/cc65/hexval.h | 60 ++++++++++ src/cc65/make/gcc.mak | 2 + src/cc65/make/watcom.mak | 6 +- src/cc65/pragma.c | 229 +++++++++++++++++++++++++------------ src/cc65/pragma.h | 6 +- src/cc65/preproc.c | 238 +++++++++++++++++++++++---------------- src/cc65/scanner.c | 75 +++++------- src/cc65/scanner.h | 24 ++-- src/cc65/scanstrbuf.c | 211 ++++++++++++++++++++++++++++++++++ src/cc65/scanstrbuf.h | 75 ++++++++++++ 12 files changed, 763 insertions(+), 234 deletions(-) create mode 100644 src/cc65/hexval.c create mode 100644 src/cc65/hexval.h create mode 100644 src/cc65/scanstrbuf.c create mode 100644 src/cc65/scanstrbuf.h diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index 25ab944fc..f3bad1601 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -373,7 +373,9 @@ void AsmStatement (void) NextToken (); /* Need left parenthesis */ - ConsumeLParen (); + if (!ConsumeLParen ()) { + return; + } /* String literal */ if (CurTok.Tok != TOK_SCONST) { diff --git a/src/cc65/hexval.c b/src/cc65/hexval.c new file mode 100644 index 000000000..21c8ef8b8 --- /dev/null +++ b/src/cc65/hexval.c @@ -0,0 +1,67 @@ +/*****************************************************************************/ +/* */ +/* 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; + } +} + + + diff --git a/src/cc65/hexval.h b/src/cc65/hexval.h new file mode 100644 index 000000000..edba95bf4 --- /dev/null +++ b/src/cc65/hexval.h @@ -0,0 +1,60 @@ +/*****************************************************************************/ +/* */ +/* 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 + + + + + diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index a22ae93e5..9d33f3387 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -56,6 +56,7 @@ OBJS = anonname.o \ function.o \ global.o \ goto.o \ + hexval.o \ ident.o \ incpath.o \ input.o \ @@ -70,6 +71,7 @@ OBJS = anonname.o \ pragma.o \ reginfo.o \ scanner.o \ + scanstrbuf.o \ segments.o \ stdfunc.o \ stmt.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 5fb562d4c..72bb31087 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -101,6 +101,7 @@ OBJS = anonname.obj \ function.obj \ global.obj \ goto.obj \ + hexval.obj \ ident.obj \ incpath.obj \ input.obj \ @@ -115,6 +116,7 @@ OBJS = anonname.obj \ pragma.obj \ reginfo.obj \ scanner.obj \ + scanstrbuf.obj \ segments.obj \ stdfunc.obj \ stmt.obj \ @@ -179,7 +181,8 @@ FILE exprnode.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 @@ -194,6 +197,7 @@ FILE preproc.obj FILE pragma.obj FILE reginfo.obj FILE scanner.obj +FILE scanstrbuf.obj FILE segments.obj FILE stdfunc.obj FILE stmt.obj diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index 5103063c3..21203944f 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -46,6 +46,7 @@ #include "global.h" #include "litpool.h" #include "scanner.h" +#include "scanstrbuf.h" #include "segments.h" #include "symtab.h" #include "pragma.h" @@ -70,7 +71,7 @@ typedef enum { PR_RODATASEG, PR_SIGNEDCHARS, PR_STATICLOCALS, - PR_ZPSYM, + PR_ZPSYM, PR_COUNT } pragma_t; @@ -99,6 +100,17 @@ static const struct Pragma { +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 */ { @@ -119,36 +131,30 @@ static pragma_t FindPragma (const char* Key) -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)) { @@ -163,17 +169,14 @@ static void SegNamePragma (segment_t Seg) } - /* 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; @@ -207,36 +210,61 @@ static void CharMapPragma (void) -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); + ident Ident; - /* Store the value into the flag parameter */ - *Flag = (Val.ConstVal != 0); + 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) { @@ -244,60 +272,111 @@ void DoPragma (void) * 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 (); } diff --git a/src/cc65/pragma.h b/src/cc65/pragma.h index 82026b35c..86ef28697 100644 --- a/src/cc65/pragma.h +++ b/src/cc65/pragma.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ +/* (C) 1998-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@cc65.org */ @@ -39,13 +39,13 @@ /*****************************************************************************/ -/* code */ +/* Code */ /*****************************************************************************/ void DoPragma (void); -/* Handle pragmas */ +/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */ diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 67aaeee62..60c8417e8 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -9,6 +9,7 @@ /* common */ #include "chartype.h" #include "check.h" +#include "inline.h" #include "print.h" #include "xmalloc.h" @@ -62,9 +63,6 @@ static char mlinebuf [LINESIZE]; static char* mline = mlinebuf; static char* mptr; -/* Flag: Expand macros in this line */ -static int ExpandMacros = 1; - /*****************************************************************************/ @@ -142,15 +140,19 @@ static pptoken_t FindPPToken (const char* Ident) -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); @@ -160,6 +162,43 @@ static void keepstr (const char* 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. */ { @@ -236,7 +275,7 @@ static char* CopyQuotedString (char* Target) /* Copy the characters inside the string */ while (CurC != '\0' && CurC != Quote) { /* Keep an escaped char */ - if (CurC == '\\') { + if (CurC == '\\') { *Target++ = CurC; NextChar (); } @@ -298,41 +337,27 @@ static void ExpandMacroArgs (Macro* M) 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 (); } } @@ -408,7 +433,7 @@ static int MacroCall (Macro* M) --ParCount; } *B++ = CurC; - NextChar (); + NextChar (); } } else if (IsBlank (CurC)) { /* Squeeze runs of blanks */ @@ -461,7 +486,7 @@ static void ExpandMacro (Macro* M) } } else { /* Just copy the replacement text */ - keepstr (M->Replacement); + KeepStr (M->Replacement); } } @@ -570,7 +595,7 @@ static int Pass1 (const char* From, char* To) done = 1; while (CurC != '\0') { if (IsBlank (CurC)) { - keepch (' '); + KeepChar (' '); SkipBlank (); } else if (IsIdent (CurC)) { SymName (Ident); @@ -585,15 +610,15 @@ static int Pass1 (const char* From, char* To) } 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 (); } } @@ -602,22 +627,22 @@ static int Pass1 (const char* From, char* To) 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; } @@ -639,7 +664,7 @@ static int Pass2 (const char* From, char* To) /* 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); @@ -647,12 +672,12 @@ static int Pass2 (const char* From, char* To) ExpandMacro (M); no_chg = 0; } else { - keepstr (Ident); + KeepStr (Ident); } } else if (IsQuote (CurC)) { mptr = CopyQuotedString (mptr); } else { - *mptr++ = CurC; + KeepChar (CurC); NextChar (); } } @@ -661,28 +686,28 @@ static int Pass2 (const char* From, char* To) -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); @@ -741,18 +766,18 @@ static int DoIf (int Skip) /* 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++ = ';'; @@ -765,7 +790,7 @@ static int DoIf (int Skip) Preprocessing = 1; /* Expand macros in this line */ - TranslateLine (); + PreprocessLine (); /* Prime the token pump (remove old tokens from the stream) */ NextToken (); @@ -838,7 +863,7 @@ static void DoInclude (void) */ mptr = mline; while (CurC != '\0' && CurC != RTerm) { - *mptr++ = CurC; + KeepChar (CurC); NextChar (); } *mptr = '\0'; @@ -878,11 +903,35 @@ static void DoError (void) +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 (); @@ -911,22 +960,22 @@ void Preprocess (void) } break; - case PP_ELIF: - if (IfIndex >= 0) { - if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) { + 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); + /* 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"); - } + /* #elif doesn't need a terminator */ + IfStack[IfIndex] &= ~IFCOND_NEEDTERM; + } else { + PPError ("Duplicate #else/#elif"); + } } else { PPError ("Unexpected #elif"); } @@ -952,7 +1001,7 @@ void Preprocess (void) /* 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; } @@ -991,20 +1040,18 @@ void Preprocess (void) 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: @@ -1017,7 +1064,7 @@ void Preprocess (void) PPError ("Preprocessor directive expected"); ClearLine (); } - } + } } if (NextLine () == 0) { @@ -1026,11 +1073,12 @@ void Preprocess (void) } return; } - SkipBlank (); + SkipBlank (); } + PreprocessLine (); + Done: - TranslateLine (); Print (stdout, 2, "line: %s\n", line); } diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 6de50ed32..b6321780e 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -48,6 +48,7 @@ #include "error.h" #include "function.h" #include "global.h" +#include "hexval.h" #include "ident.h" #include "input.h" #include "litpool.h" @@ -79,6 +80,7 @@ static const struct Keyword { 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 }, @@ -226,21 +228,6 @@ static void UnknownChar (char 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 */ { @@ -780,18 +767,6 @@ void NextToken (void) 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); @@ -825,104 +800,110 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount) -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"); } diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index e78446efb..8bf668691 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ +/* (C) 1998-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ /* EMail: uz@musoftware.de */ @@ -210,36 +210,36 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount); * 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 */ diff --git a/src/cc65/scanstrbuf.c b/src/cc65/scanstrbuf.c new file mode 100644 index 000000000..82418f763 --- /dev/null +++ b/src/cc65/scanstrbuf.c @@ -0,0 +1,211 @@ +/*****************************************************************************/ +/* */ +/* 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; + } +} + + + diff --git a/src/cc65/scanstrbuf.h b/src/cc65/scanstrbuf.h new file mode 100644 index 000000000..9bd971441 --- /dev/null +++ b/src/cc65/scanstrbuf.h @@ -0,0 +1,75 @@ +/*****************************************************************************/ +/* */ +/* 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 + + + + +