mirror of
https://github.com/cc65/cc65.git
synced 2025-04-06 20:37:16 +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:
parent
092f10862e
commit
ea50befaac
@ -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
67
src/cc65/hexval.c
Normal 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
60
src/cc65/hexval.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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. */
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
211
src/cc65/scanstrbuf.c
Normal 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
75
src/cc65/scanstrbuf.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user