Redoing the pragma stuff

git-svn-id: svn://svn.cc65.org/cc65/trunk@1413 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz
2002-09-29 21:09:47 +00:00
parent 092f10862e
commit ea50befaac
12 changed files with 763 additions and 234 deletions

View File

@@ -373,7 +373,9 @@ void AsmStatement (void)
NextToken (); NextToken ();
/* Need left parenthesis */ /* Need left parenthesis */
ConsumeLParen (); if (!ConsumeLParen ()) {
return;
}
/* String literal */ /* String literal */
if (CurTok.Tok != TOK_SCONST) { if (CurTok.Tok != TOK_SCONST) {

67
src/cc65/hexval.c Normal file
View File

@@ -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;
}
}

60
src/cc65/hexval.h Normal file
View File

@@ -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

View File

@@ -56,6 +56,7 @@ OBJS = anonname.o \
function.o \ function.o \
global.o \ global.o \
goto.o \ goto.o \
hexval.o \
ident.o \ ident.o \
incpath.o \ incpath.o \
input.o \ input.o \
@@ -70,6 +71,7 @@ OBJS = anonname.o \
pragma.o \ pragma.o \
reginfo.o \ reginfo.o \
scanner.o \ scanner.o \
scanstrbuf.o \
segments.o \ segments.o \
stdfunc.o \ stdfunc.o \
stmt.o \ stmt.o \

View File

@@ -101,6 +101,7 @@ OBJS = anonname.obj \
function.obj \ function.obj \
global.obj \ global.obj \
goto.obj \ goto.obj \
hexval.obj \
ident.obj \ ident.obj \
incpath.obj \ incpath.obj \
input.obj \ input.obj \
@@ -115,6 +116,7 @@ OBJS = anonname.obj \
pragma.obj \ pragma.obj \
reginfo.obj \ reginfo.obj \
scanner.obj \ scanner.obj \
scanstrbuf.obj \
segments.obj \ segments.obj \
stdfunc.obj \ stdfunc.obj \
stmt.obj \ stmt.obj \
@@ -179,7 +181,8 @@ FILE exprnode.obj
FILE funcdesc.obj FILE funcdesc.obj
FILE function.obj FILE function.obj
FILE global.obj FILE global.obj
FILE goto.obj FILE goto.obj
FILE hexval.obj
FILE ident.obj FILE ident.obj
FILE incpath.obj FILE incpath.obj
FILE input.obj FILE input.obj
@@ -194,6 +197,7 @@ FILE preproc.obj
FILE pragma.obj FILE pragma.obj
FILE reginfo.obj FILE reginfo.obj
FILE scanner.obj FILE scanner.obj
FILE scanstrbuf.obj
FILE segments.obj FILE segments.obj
FILE stdfunc.obj FILE stdfunc.obj
FILE stmt.obj FILE stmt.obj

View File

@@ -46,6 +46,7 @@
#include "global.h" #include "global.h"
#include "litpool.h" #include "litpool.h"
#include "scanner.h" #include "scanner.h"
#include "scanstrbuf.h"
#include "segments.h" #include "segments.h"
#include "symtab.h" #include "symtab.h"
#include "pragma.h" #include "pragma.h"
@@ -70,7 +71,7 @@ typedef enum {
PR_RODATASEG, PR_RODATASEG,
PR_SIGNEDCHARS, PR_SIGNEDCHARS,
PR_STATICLOCALS, PR_STATICLOCALS,
PR_ZPSYM, PR_ZPSYM,
PR_COUNT PR_COUNT
} pragma_t; } 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) static int CmpKey (const void* Key, const void* Elem)
/* Compare function for bsearch */ /* 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 */ /* Handle a pragma that expects a string parameter */
{ {
if (CurTok.Tok != TOK_SCONST) { StrBuf S;
Error ("String literal expected");
} else {
/* Get the string */
const char* Name = GetLiteral (CurTok.IVal);
if (SB_GetString (B, &S)) {
/* Call the given function with the string argument */ /* Call the given function with the string argument */
Func (Name); Func (SB_GetConstBuf (&S));
} else {
/* Reset the string pointer, removing the string from the pool */ Error ("String literal expected");
ResetLiteralPoolOffs (CurTok.IVal);
} }
/* 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 */ /* Handle a pragma that expects a segment name parameter */
{ {
if (CurTok.Tok != TOK_SCONST) { StrBuf S;
Error ("String literal expected");
} else { if (SB_GetString (B, &S)) {
/* Get the segment name */
const char* Name = GetLiteral (CurTok.IVal); /* Get the string */
const char* Name = SB_GetConstBuf (&S);
/* Check if the name is valid */ /* Check if the name is valid */
if (ValidSegName (Name)) { if (ValidSegName (Name)) {
@@ -163,17 +169,14 @@ static void SegNamePragma (segment_t Seg)
} }
/* Reset the string pointer, removing the string from the pool */ } else {
ResetLiteralPoolOffs (CurTok.IVal); Error ("String literal expected");
} }
/* Skip the string (or error) token */
NextToken ();
} }
static void CharMapPragma (void) static void CharMapPragma (StrBuf* B)
/* Change the character map */ /* Change the character map */
{ {
unsigned Index, C; 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 */ /* Handle a pragma that expects a boolean paramater */
{ {
/* Read a constant integer expression */ ident Ident;
ExprDesc Val;
ConstIntExpr (&Val);
/* Store the value into the flag parameter */ if (SB_Peek (B) == '0') {
*Flag = (Val.ConstVal != 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) static void ParsePragma (void)
/* Handle pragmas */ /* Parse the contents of the _Pragma statement */
{ {
pragma_t Pragma; 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 (); NextToken ();
/* Identifier must follow */ /* Get the pragma name from the string */
if (CurTok.Tok != TOK_IDENT) { SB_SkipWhite (&B);
Error ("Identifier expected"); if (!SB_GetSym (&B, Ident)) {
return; Error ("Invalid pragma");
return;
} }
/* Search for the name, then skip the identifier */ /* Search for the name */
Pragma = FindPragma (CurTok.Ident); Pragma = FindPragma (Ident);
NextToken ();
/* Do we know this pragma? */ /* Do we know this pragma? */
if (Pragma == PR_ILLEGAL) { if (Pragma == PR_ILLEGAL) {
@@ -244,60 +272,111 @@ void DoPragma (void)
* for unknown pragmas, however, we're allowed to warn - and we will * for unknown pragmas, however, we're allowed to warn - and we will
* do so. Otherwise one typo may give you hours of bug hunting... * do so. Otherwise one typo may give you hours of bug hunting...
*/ */
Warning ("Unknown #pragma `%s'", CurTok.Ident); Warning ("Unknown pragma `%s'", Ident);
return; return;
} }
/* Check for an open paren */ /* 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 for the different pragmas */
switch (Pragma) { switch (Pragma) {
case PR_BSSSEG: case PR_BSSSEG:
SegNamePragma (SEG_BSS); SegNamePragma (&B, SEG_BSS);
break; break;
case PR_CHARMAP: case PR_CHARMAP:
CharMapPragma (); CharMapPragma (&B);
break; break;
case PR_CHECKSTACK: case PR_CHECKSTACK:
FlagPragma (&CheckStack); FlagPragma (&B, &CheckStack);
break; break;
case PR_CODESEG: case PR_CODESEG:
SegNamePragma (SEG_CODE); SegNamePragma (&B, SEG_CODE);
break; break;
case PR_DATASEG: case PR_DATASEG:
SegNamePragma (SEG_DATA); SegNamePragma (&B, SEG_DATA);
break; break;
case PR_REGVARADDR: case PR_REGVARADDR:
FlagPragma (&AllowRegVarAddr); FlagPragma (&B, &AllowRegVarAddr);
break; break;
case PR_RODATASEG: case PR_RODATASEG:
SegNamePragma (SEG_RODATA); SegNamePragma (&B, SEG_RODATA);
break; break;
case PR_SIGNEDCHARS: case PR_SIGNEDCHARS:
FlagPragma (&SignedChars); FlagPragma (&B, &SignedChars);
break; break;
case PR_STATICLOCALS: case PR_STATICLOCALS:
FlagPragma (&StaticLocals); FlagPragma (&B, &StaticLocals);
break; break;
case PR_ZPSYM: case PR_ZPSYM:
StringPragma (MakeZPSym); StringPragma (&B, MakeZPSym);
break; break;
default: default:
Internal ("Invalid pragma"); 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 */ /* Closing paren needed */
ConsumeRParen (); ConsumeRParen ();
} }

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2001 Ullrich von Bassewitz */ /* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@@ -39,13 +39,13 @@
/*****************************************************************************/ /*****************************************************************************/
/* code */ /* Code */
/*****************************************************************************/ /*****************************************************************************/
void DoPragma (void); void DoPragma (void);
/* Handle pragmas */ /* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */

View File

@@ -9,6 +9,7 @@
/* common */ /* common */
#include "chartype.h" #include "chartype.h"
#include "check.h" #include "check.h"
#include "inline.h"
#include "print.h" #include "print.h"
#include "xmalloc.h" #include "xmalloc.h"
@@ -62,9 +63,6 @@ static char mlinebuf [LINESIZE];
static char* mline = mlinebuf; static char* mline = mlinebuf;
static char* mptr; 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. */ /* Put character c into translation buffer. */
{ {
*mptr++ = c; *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. */ /* Put string str into translation buffer. */
{ {
unsigned Len = strlen (S); 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) static void OldStyleComment (void)
/* Remove an old style C comment from line. */ /* Remove an old style C comment from line. */
{ {
@@ -236,7 +275,7 @@ static char* CopyQuotedString (char* Target)
/* Copy the characters inside the string */ /* Copy the characters inside the string */
while (CurC != '\0' && CurC != Quote) { while (CurC != '\0' && CurC != Quote) {
/* Keep an escaped char */ /* Keep an escaped char */
if (CurC == '\\') { if (CurC == '\\') {
*Target++ = CurC; *Target++ = CurC;
NextChar (); NextChar ();
} }
@@ -298,41 +337,27 @@ static void ExpandMacroArgs (Macro* M)
Replacement = FindMacroArg (M, Ident); Replacement = FindMacroArg (M, Ident);
if (Replacement) { if (Replacement) {
/* Macro arg, keep the replacement */ /* Macro arg, keep the replacement */
keepstr (Replacement); KeepStr (Replacement);
} else { } else {
/* No macro argument, keep the original identifier */ /* No macro argument, keep the original identifier */
keepstr (Ident); KeepStr (Ident);
} }
} else if (CurC == '#' && IsIdent (NextC)) { } else if (CurC == '#' && IsIdent (NextC)) {
NextChar (); NextChar ();
SymName (Ident); SymName (Ident);
Replacement = FindMacroArg (M, Ident); Replacement = FindMacroArg (M, Ident);
if (Replacement) { if (Replacement) {
keepch ('\"'); /* Make a valid string from Replacement */
/* We have to escape any characters inside replacement that Stringize (Replacement);
* may not be part of a string unescaped.
*/
while (*Replacement) {
switch (*Replacement) {
case '\"':
case '\\':
keepch ('\\');
/* FALLTHROUGH */
default:
keepch (*Replacement);
break;
}
++Replacement;
}
keepch ('\"');
} else { } else {
keepch ('#'); /* No replacement - keep the input */
keepstr (Ident); KeepChar ('#');
KeepStr (Ident);
} }
} else if (IsQuote (CurC)) { } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr); mptr = CopyQuotedString (mptr);
} else { } else {
*mptr++ = CurC; KeepChar (CurC);
NextChar (); NextChar ();
} }
} }
@@ -408,7 +433,7 @@ static int MacroCall (Macro* M)
--ParCount; --ParCount;
} }
*B++ = CurC; *B++ = CurC;
NextChar (); NextChar ();
} }
} else if (IsBlank (CurC)) { } else if (IsBlank (CurC)) {
/* Squeeze runs of blanks */ /* Squeeze runs of blanks */
@@ -461,7 +486,7 @@ static void ExpandMacro (Macro* M)
} }
} else { } else {
/* Just copy the replacement text */ /* 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; done = 1;
while (CurC != '\0') { while (CurC != '\0') {
if (IsBlank (CurC)) { if (IsBlank (CurC)) {
keepch (' '); KeepChar (' ');
SkipBlank (); SkipBlank ();
} else if (IsIdent (CurC)) { } else if (IsIdent (CurC)) {
SymName (Ident); SymName (Ident);
@@ -585,15 +610,15 @@ static int Pass1 (const char* From, char* To)
} }
if (!IsIdent (CurC)) { if (!IsIdent (CurC)) {
PPError ("Identifier expected"); PPError ("Identifier expected");
*mptr++ = '0'; KeepChar ('0');
} else { } else {
SymName (Ident); SymName (Ident);
*mptr++ = IsMacro (Ident)? '1' : '0'; KeepChar (IsMacro (Ident)? '1' : '0');
if (HaveParen) { if (HaveParen) {
SkipBlank(); SkipBlank();
if (CurC != ')') { if (CurC != ')') {
PPError ("`)' expected"); PPError ("`)' expected");
} else { } else {
NextChar (); NextChar ();
} }
} }
@@ -602,22 +627,22 @@ static int Pass1 (const char* From, char* To)
if (MaybeMacro (Ident[0])) { if (MaybeMacro (Ident[0])) {
done = 0; done = 0;
} }
keepstr (Ident); KeepStr (Ident);
} }
} else if (IsQuote (CurC)) { } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr); mptr = CopyQuotedString (mptr);
} else if (CurC == '/' && NextC == '*') { } else if (CurC == '/' && NextC == '*') {
keepch (' '); KeepChar (' ');
OldStyleComment (); OldStyleComment ();
} else if (ANSI == 0 && CurC == '/' && NextC == '/') { } else if (ANSI == 0 && CurC == '/' && NextC == '/') {
keepch (' '); KeepChar (' ');
NewStyleComment (); NewStyleComment ();
} else { } else {
*mptr++ = CurC; KeepChar (CurC);
NextChar (); NextChar ();
} }
} }
keepch ('\0'); KeepChar ('\0');
return done; return done;
} }
@@ -639,7 +664,7 @@ static int Pass2 (const char* From, char* To)
/* Loop substituting macros */ /* Loop substituting macros */
no_chg = 1; no_chg = 1;
while (CurC != '\0') { 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)) { if (IsIdent (CurC)) {
SymName (Ident); SymName (Ident);
M = FindMacro (Ident); M = FindMacro (Ident);
@@ -647,12 +672,12 @@ static int Pass2 (const char* From, char* To)
ExpandMacro (M); ExpandMacro (M);
no_chg = 0; no_chg = 0;
} else { } else {
keepstr (Ident); KeepStr (Ident);
} }
} else if (IsQuote (CurC)) { } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr); mptr = CopyQuotedString (mptr);
} else { } else {
*mptr++ = CurC; KeepChar (CurC);
NextChar (); NextChar ();
} }
} }
@@ -661,28 +686,28 @@ static int Pass2 (const char* From, char* To)
static void TranslateLine (void) static void PreprocessLine (void)
/* Translate one line. */ /* Translate one line. */
{ {
int cnt; unsigned I;
int Done;
Done = Pass1 (line, mline); /* Trim whitespace and remove comments. The function returns false if no
if (ExpandMacros == 0) { * identifiers were found that may be macros. If this is the case, no
Done = 1; * macro substitution is performed.
ExpandMacros = 1; /* Reset to default */ */
} int Done = Pass1 (line, mline);
cnt = 5;
do { /* Repeatedly expand macros in the line */
for (I = 0; I < 5; ++I) {
/* Swap mline and line */ /* Swap mline and line */
char* p = line; SwapLineBuffers ();
line = mline; if (Done) {
mline = p; break;
if (Done) }
break; /* Perform macro expansion */
Done = Pass2 (line, mline); Done = Pass2 (line, mline);
keepch ('\0'); KeepChar ('\0');
} while (--cnt); }
/* Reinitialize line parsing */ /* Reinitialize line parsing */
InitLine (line); InitLine (line);
@@ -741,18 +766,18 @@ static int DoIf (int Skip)
/* Make sure the line infos for the tokens won't get removed */ /* Make sure the line infos for the tokens won't get removed */
if (sv1.LI) { if (sv1.LI) {
UseLineInfo (sv1.LI); UseLineInfo (sv1.LI);
} }
if (sv2.LI) { if (sv2.LI) {
UseLineInfo (sv2.LI); UseLineInfo (sv2.LI);
} }
/* Remove the #if from the line and add two semicolons as sentinels */ /* Remove the #if from the line and add two semicolons as sentinels */
SkipBlank (); SkipBlank ();
S = line; S = line;
while (CurC != '\0') { while (CurC != '\0') {
*S++ = CurC; *S++ = CurC;
NextChar (); NextChar ();
} }
*S++ = ';'; *S++ = ';';
*S++ = ';'; *S++ = ';';
@@ -765,7 +790,7 @@ static int DoIf (int Skip)
Preprocessing = 1; Preprocessing = 1;
/* Expand macros in this line */ /* Expand macros in this line */
TranslateLine (); PreprocessLine ();
/* Prime the token pump (remove old tokens from the stream) */ /* Prime the token pump (remove old tokens from the stream) */
NextToken (); NextToken ();
@@ -838,7 +863,7 @@ static void DoInclude (void)
*/ */
mptr = mline; mptr = mline;
while (CurC != '\0' && CurC != RTerm) { while (CurC != '\0' && CurC != RTerm) {
*mptr++ = CurC; KeepChar (CurC);
NextChar (); NextChar ();
} }
*mptr = '\0'; *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) void Preprocess (void)
/* Preprocess a line */ /* Preprocess a line */
{ {
int Skip; int Skip;
ident Directive; ident Directive;
/* Skip white space at the beginning of the line */ /* Skip white space at the beginning of the line */
SkipBlank (); SkipBlank ();
@@ -911,22 +960,22 @@ void Preprocess (void)
} }
break; break;
case PP_ELIF: case PP_ELIF:
if (IfIndex >= 0) { if (IfIndex >= 0) {
if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) { if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
/* Handle as #else/#if combination */ /* Handle as #else/#if combination */
if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) { if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
Skip = !Skip; Skip = !Skip;
} }
IfStack[IfIndex] |= IFCOND_ELSE; IfStack[IfIndex] |= IFCOND_ELSE;
Skip = DoIf (Skip); Skip = DoIf (Skip);
/* #elif doesn't need a terminator */ /* #elif doesn't need a terminator */
IfStack[IfIndex] &= ~IFCOND_NEEDTERM; IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
} else { } else {
PPError ("Duplicate #else/#elif"); PPError ("Duplicate #else/#elif");
} }
} else { } else {
PPError ("Unexpected #elif"); PPError ("Unexpected #elif");
} }
@@ -952,7 +1001,7 @@ void Preprocess (void)
/* Remove any clauses on top of stack that do not /* Remove any clauses on top of stack that do not
* need a terminating #endif. * need a terminating #endif.
*/ */
while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) { while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
--IfIndex; --IfIndex;
} }
@@ -991,20 +1040,18 @@ void Preprocess (void)
break; break;
case PP_LINE: case PP_LINE:
/* Not allowed in strict ANSI mode */ /* Not allowed in strict ANSI mode */
if (!Skip && ANSI) { if (!Skip && ANSI) {
PPError ("Preprocessor directive expected"); PPError ("Preprocessor directive expected");
ClearLine (); ClearLine ();
} }
break; break;
case PP_PRAGMA: case PP_PRAGMA:
if (!Skip) { if (!Skip) {
/* Don't expand macros in this line */ DoPragma ();
ExpandMacros = 0; goto Done;
/* #pragma is handled on the scanner level */ }
goto Done;
}
break; break;
case PP_UNDEF: case PP_UNDEF:
@@ -1017,7 +1064,7 @@ void Preprocess (void)
PPError ("Preprocessor directive expected"); PPError ("Preprocessor directive expected");
ClearLine (); ClearLine ();
} }
} }
} }
if (NextLine () == 0) { if (NextLine () == 0) {
@@ -1026,11 +1073,12 @@ void Preprocess (void)
} }
return; return;
} }
SkipBlank (); SkipBlank ();
} }
PreprocessLine ();
Done: Done:
TranslateLine ();
Print (stdout, 2, "line: %s\n", line); Print (stdout, 2, "line: %s\n", line);
} }

View File

@@ -48,6 +48,7 @@
#include "error.h" #include "error.h"
#include "function.h" #include "function.h"
#include "global.h" #include "global.h"
#include "hexval.h"
#include "ident.h" #include "ident.h"
#include "input.h" #include "input.h"
#include "litpool.h" #include "litpool.h"
@@ -79,6 +80,7 @@ static const struct Keyword {
unsigned char Tok; /* The token */ unsigned char Tok; /* The token */
unsigned char Type; /* Token type */ unsigned char Type; /* Token type */
} Keywords [] = { } Keywords [] = {
{ "_Pragma", TOK_PRAGMA, TT_C },
{ "__A__", TOK_A, TT_C }, { "__A__", TOK_A, TT_C },
{ "__AX__", TOK_AX, TT_C }, { "__AX__", TOK_AX, TT_C },
{ "__EAX__", TOK_EAX, 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) static void SetTok (int tok)
/* Set NextTok.Tok and bump line ptr */ /* Set NextTok.Tok and bump line ptr */
{ {
@@ -780,18 +767,6 @@ void NextToken (void)
SetTok (TOK_COMP); SetTok (TOK_COMP);
break; 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: default:
UnknownChar (CurC); 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 /* 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) { if (CurTok.Tok == Token) {
NextToken (); NextToken ();
return 1;
} else { } else {
Error (ErrorMsg); Error (ErrorMsg);
return 0;
} }
} }
void ConsumeColon (void) int ConsumeColon (void)
/* Check for a colon and skip it. */ /* 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. */ /* Check for a semicolon and skip it. */
{ {
/* Try do be smart about typos... */ /* Try do be smart about typos... */
if (CurTok.Tok == TOK_SEMI) { if (CurTok.Tok == TOK_SEMI) {
NextToken (); NextToken ();
return 1;
} else { } else {
Error ("`;' expected"); Error ("`;' expected");
if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) { if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
NextToken (); NextToken ();
} }
return 0;
} }
} }
void ConsumeComma (void) int ConsumeComma (void)
/* Check for a comma and skip it. */ /* Check for a comma and skip it. */
{ {
/* Try do be smart about typos... */ /* Try do be smart about typos... */
if (CurTok.Tok == TOK_COMMA) { if (CurTok.Tok == TOK_COMMA) {
NextToken (); NextToken ();
return 1;
} else { } else {
Error ("`,' expected"); Error ("`,' expected");
if (CurTok.Tok == TOK_SEMI) { if (CurTok.Tok == TOK_SEMI) {
NextToken (); NextToken ();
} }
return 0;
} }
} }
void ConsumeLParen (void) int ConsumeLParen (void)
/* Check for a left parenthesis and skip it */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* Check for a right curly brace and skip it */
{ {
Consume (TOK_RCURLY, "`}' expected"); return Consume (TOK_RCURLY, "`}' expected");
} }

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2001 Ullrich von Bassewitz */ /* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
@@ -210,36 +210,36 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount);
* This routine is used for error recovery. * 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 /* 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. */ /* Check for a colon and skip it. */
void ConsumeSemi (void); int ConsumeSemi (void);
/* Check for a semicolon and skip it. */ /* Check for a semicolon and skip it. */
void ConsumeComma (void); int ConsumeComma (void);
/* Check for a comma and skip it. */ /* Check for a comma and skip it. */
void ConsumeLParen (void); int ConsumeLParen (void);
/* Check for a left parenthesis and skip it */ /* Check for a left parenthesis and skip it */
void ConsumeRParen (void); int ConsumeRParen (void);
/* Check for a right parenthesis and skip it */ /* Check for a right parenthesis and skip it */
void ConsumeLBrack (void); int ConsumeLBrack (void);
/* Check for a left bracket and skip it */ /* Check for a left bracket and skip it */
void ConsumeRBrack (void); int ConsumeRBrack (void);
/* Check for a right bracket and skip it */ /* Check for a right bracket and skip it */
void ConsumeLCurly (void); int ConsumeLCurly (void);
/* Check for a left curly brace and skip it */ /* Check for a left curly brace and skip it */
void ConsumeRCurly (void); int ConsumeRCurly (void);
/* Check for a right curly brace and skip it */ /* Check for a right curly brace and skip it */

211
src/cc65/scanstrbuf.c Normal file
View File

@@ -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;
}
}

75
src/cc65/scanstrbuf.h Normal file
View File

@@ -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