Redoing the pragma stuff
git-svn-id: svn://svn.cc65.org/cc65/trunk@1413 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -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
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 \
|
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 \
|
||||||
|
|||||||
@@ -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 \
|
||||||
@@ -180,6 +182,7 @@ 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
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -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 ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user