1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +00:00

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 ();
/* Need left parenthesis */
ConsumeLParen ();
if (!ConsumeLParen ()) {
return;
}
/* String literal */
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 \
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 \

View File

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

View File

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

View File

@ -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. */

View File

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

View File

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

View File

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

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