@@ -837,21 +837,21 @@ This cc65 version has some extensions to the ISO C standard.
|
|||||||
|
|
||||||
<itemize>
|
<itemize>
|
||||||
|
|
||||||
<item> The compiler allows to insert assembler expressions into the output
|
<item> The compiler allows to insert inline assembler code in the form of the
|
||||||
file. The syntax is
|
<tt/asm/ expression into the output file. The syntax is
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
asm [optional volatile] (<string literal>[, optional parameters]) ;
|
asm [optional volatile] (<string literal>[, optional parameters])
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
or
|
or
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
__asm__ [optional volatile] (<string literal>[, optional parameters]) ;
|
__asm__ [optional volatile] (<string literal>[, optional parameters])
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
|
|
||||||
The first form is in the user namespace; and, is disabled if the <tt/-A/
|
The first form is in the user namespace; and, is disabled if the <tt/-A/
|
||||||
switch is given.
|
switch is given.
|
||||||
|
|
||||||
There is a whole section covering inline assembler expressions,
|
There is a whole section covering the inline assembler,
|
||||||
<ref id="inline-asm" name="see there">.
|
<ref id="inline-asm" name="see there">.
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
@@ -1008,6 +1008,13 @@ This cc65 version has some extensions to the ISO C standard.
|
|||||||
<tt/_Static_assert/ is also available as the macro <tt/static_assert/ in
|
<tt/_Static_assert/ is also available as the macro <tt/static_assert/ in
|
||||||
<tt/assert.h/.
|
<tt/assert.h/.
|
||||||
|
|
||||||
|
Note: The string literal as the message in the <tt/_Static_assert/
|
||||||
|
declaration is not subject to string literal translation (see
|
||||||
|
<tt/<ref id="pragma-charmap" name="#pragma charmap()">/) and will
|
||||||
|
always be in the host encoding. On the other hand, any character or
|
||||||
|
string literals present in the condition expression of the
|
||||||
|
<tt/_Static_assert/ declaration will be translated as usual.
|
||||||
|
|
||||||
<item> cc65 supports bit-fields of any integral type that is int-sized or
|
<item> cc65 supports bit-fields of any integral type that is int-sized or
|
||||||
smaller, and enumerated types with those types as their underlying
|
smaller, and enumerated types with those types as their underlying
|
||||||
type. (Only <tt/int/, <tt/signed int/, and <tt/unsigned int/ are
|
type. (Only <tt/int/, <tt/signed int/, and <tt/unsigned int/ are
|
||||||
@@ -1317,7 +1324,9 @@ parameter with the <tt/#pragma/.
|
|||||||
|
|
||||||
<sect1><tt>#pragma charmap (<index>, <code>)</tt><label id="pragma-charmap"><p>
|
<sect1><tt>#pragma charmap (<index>, <code>)</tt><label id="pragma-charmap"><p>
|
||||||
|
|
||||||
Each literal string and each literal character in the source is translated
|
Each literal string and each literal character in the preprocessed source,
|
||||||
|
except when used in an <tt/asm/ expression as the inline assembler code or
|
||||||
|
in a <tt/_Static_assert/ declaration as the failure message, is translated
|
||||||
by use of a translation table. That translation table is preset when the
|
by use of a translation table. That translation table is preset when the
|
||||||
compiler is started, depending on the target system; for example, to map
|
compiler is started, depending on the target system; for example, to map
|
||||||
ISO-8859-1 characters into PETSCII if the target is a Commodore machine.
|
ISO-8859-1 characters into PETSCII if the target is a Commodore machine.
|
||||||
@@ -1714,23 +1723,23 @@ bloated code and a slowdown.
|
|||||||
|
|
||||||
<sect>Inline assembler<label id="inline-asm"><p>
|
<sect>Inline assembler<label id="inline-asm"><p>
|
||||||
|
|
||||||
The compiler allows to insert assembler expressions into the output file. The
|
The compiler allows to insert inline assembler code in the form of the <tt/asm/
|
||||||
syntax is
|
expression into the output file. The syntax is
|
||||||
|
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
asm [optional volatile] (<string literal>[, optional parameters]) ;
|
asm [optional volatile] (<string literal>[, optional parameters])
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
or
|
or
|
||||||
<tscreen><verb>
|
<tscreen><verb>
|
||||||
__asm__ [optional volatile] (<string literal>[, optional parameters]) ;
|
__asm__ [optional volatile] (<string literal>[, optional parameters])
|
||||||
</verb></tscreen>
|
</verb></tscreen>
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
The first form is in the user namespace; and, is disabled by <tt><ref
|
The first form is in the user namespace; and, is disabled by <tt><ref
|
||||||
id="option--standard" name="--standard"></tt> if the argument is not <tt/cc65/.
|
id="option--standard" name="--standard"></tt> if the argument is not <tt/cc65/.
|
||||||
|
|
||||||
The <tt/asm/ expression can be used only inside a function. Please note that
|
The <tt/asm/ expression can be used only inside a function. The result of an
|
||||||
the result of an inline assembler expression is always of type <tt/void/.
|
<tt/asm/ expression is always of type <tt/void/.
|
||||||
|
|
||||||
The contents of the string literal are preparsed by the compiler; and, inserted
|
The contents of the string literal are preparsed by the compiler; and, inserted
|
||||||
into the generated assembly output, so that it can be processed further by
|
into the generated assembly output, so that it can be processed further by
|
||||||
@@ -1757,6 +1766,13 @@ The string literal may contain format specifiers from the following list. For
|
|||||||
each format specifier, an argument is expected which is inserted instead of
|
each format specifier, an argument is expected which is inserted instead of
|
||||||
the format specifier, before passing the assembly code line to the backend.
|
the format specifier, before passing the assembly code line to the backend.
|
||||||
|
|
||||||
|
Note: The string literal as the inline assembler code itself in the <tt/asm/
|
||||||
|
expression is not subject to string literal translation (see
|
||||||
|
<tt/<ref id="pragma-charmap" name="#pragma charmap()">/) and will always
|
||||||
|
be in the host encoding. On the other hand, all character and string literals
|
||||||
|
as the arguments for replacing the format specifiers will be translated as
|
||||||
|
usual.
|
||||||
|
|
||||||
<itemize>
|
<itemize>
|
||||||
<item><tt/%b/ - Numerical 8-bit value
|
<item><tt/%b/ - Numerical 8-bit value
|
||||||
<item><tt/%w/ - Numerical 16-bit value
|
<item><tt/%w/ - Numerical 16-bit value
|
||||||
|
|||||||
@@ -417,6 +417,9 @@ void AsmStatement (void)
|
|||||||
** a string literal in parenthesis.
|
** a string literal in parenthesis.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
/* Prevent from translating the inline code string literal in asm */
|
||||||
|
NoCharMap = 1;
|
||||||
|
|
||||||
/* Skip the ASM */
|
/* Skip the ASM */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -431,9 +434,15 @@ void AsmStatement (void)
|
|||||||
|
|
||||||
/* Need left parenthesis */
|
/* Need left parenthesis */
|
||||||
if (!ConsumeLParen ()) {
|
if (!ConsumeLParen ()) {
|
||||||
|
NoCharMap = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We have got the inline code string untranslated, now reenable string
|
||||||
|
** literal translation for string arguments (if any).
|
||||||
|
*/
|
||||||
|
NoCharMap = 0;
|
||||||
|
|
||||||
/* String literal */
|
/* String literal */
|
||||||
if (CurTok.Tok != TOK_SCONST) {
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
|
|
||||||
|
|||||||
@@ -111,12 +111,6 @@ static void Parse (void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a #pragma */
|
|
||||||
if (CurTok.Tok == TOK_PRAGMA) {
|
|
||||||
DoPragma ();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for a _Static_assert */
|
/* Check for a _Static_assert */
|
||||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
ParseStaticAssert ();
|
ParseStaticAssert ();
|
||||||
|
|||||||
@@ -1336,8 +1336,6 @@ static void Primary (ExprDesc* E)
|
|||||||
/* String literal */
|
/* String literal */
|
||||||
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
E->V.LVal = UseLiteral (CurTok.SVal);
|
E->V.LVal = UseLiteral (CurTok.SVal);
|
||||||
/* Translate into target charset */
|
|
||||||
TranslateLiteral (E->V.LVal);
|
|
||||||
} else {
|
} else {
|
||||||
E->V.LVal = CurTok.SVal;
|
E->V.LVal = CurTok.SVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,9 +245,6 @@ static void DefineBitFieldData (StructInitData* SI)
|
|||||||
|
|
||||||
static void DefineStrData (Literal* Lit, unsigned Count)
|
static void DefineStrData (Literal* Lit, unsigned Count)
|
||||||
{
|
{
|
||||||
/* Translate into target charset */
|
|
||||||
TranslateLiteral (Lit);
|
|
||||||
|
|
||||||
/* Output the data */
|
/* Output the data */
|
||||||
g_defbytes (GetLiteralStr (Lit), Count);
|
g_defbytes (GetLiteralStr (Lit), Count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,13 +160,24 @@ void ReleaseLiteral (Literal* L)
|
|||||||
|
|
||||||
|
|
||||||
void TranslateLiteral (Literal* L)
|
void TranslateLiteral (Literal* L)
|
||||||
/* Translate a literal into the target charset. */
|
/* Translate a literal into the target charset */
|
||||||
{
|
{
|
||||||
TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
|
TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConcatLiteral (Literal* L, const Literal* Appended)
|
||||||
|
/* Concatenate string literals */
|
||||||
|
{
|
||||||
|
if (SB_GetLen (&L->Data) > 0 && SB_LookAtLast (&L->Data) == '\0') {
|
||||||
|
SB_Drop (&L->Data, 1);
|
||||||
|
}
|
||||||
|
SB_Append (&L->Data, &Appended->Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned GetLiteralLabel (const Literal* L)
|
unsigned GetLiteralLabel (const Literal* L)
|
||||||
/* Return the asm label for a literal */
|
/* Return the asm label for a literal */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -75,7 +75,10 @@ void ReleaseLiteral (Literal* L);
|
|||||||
/* Decrement the reference counter for the literal */
|
/* Decrement the reference counter for the literal */
|
||||||
|
|
||||||
void TranslateLiteral (Literal* L);
|
void TranslateLiteral (Literal* L);
|
||||||
/* Translate a literal into the target charset. */
|
/* Translate a literal into the target charset */
|
||||||
|
|
||||||
|
void ConcatLiteral (Literal* L, const Literal* Appended);
|
||||||
|
/* Concatenate string literals */
|
||||||
|
|
||||||
unsigned GetLiteralLabel (const Literal* L);
|
unsigned GetLiteralLabel (const Literal* L);
|
||||||
/* Return the asm label for a literal */
|
/* Return the asm label for a literal */
|
||||||
|
|||||||
@@ -41,12 +41,11 @@
|
|||||||
#include "chartype.h"
|
#include "chartype.h"
|
||||||
#include "segnames.h"
|
#include "segnames.h"
|
||||||
#include "tgttrans.h"
|
#include "tgttrans.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "funcdesc.h"
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@@ -142,6 +141,21 @@ typedef enum {
|
|||||||
PP_ERROR,
|
PP_ERROR,
|
||||||
} PushPopResult;
|
} PushPopResult;
|
||||||
|
|
||||||
|
/* Effective scope of the pragma.
|
||||||
|
** This talks about how far the pragma has effects on whenever it shows up,
|
||||||
|
** even in the middle of an expression, statement or something.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PES_NONE,
|
||||||
|
PES_IMM, /* No way back */
|
||||||
|
PES_EXPR, /* Current expression/declarator */
|
||||||
|
PES_STMT, /* Current statement/declaration */
|
||||||
|
PES_SCOPE, /* Current scope */
|
||||||
|
PES_FUNC, /* Current function */
|
||||||
|
PES_FILE, /* Current file */
|
||||||
|
PES_ALL, /* All */
|
||||||
|
} pragma_scope_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -339,7 +353,7 @@ static void PushInt (IntStack* S, long Val)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int BoolKeyword (StrBuf* Ident)
|
static int IsBoolKeyword (StrBuf* Ident)
|
||||||
/* Check if the identifier in Ident is a keyword for a boolean value. Currently
|
/* Check if the identifier in Ident is a keyword for a boolean value. Currently
|
||||||
** accepted are true/false/on/off.
|
** accepted are true/false/on/off.
|
||||||
*/
|
*/
|
||||||
@@ -364,17 +378,92 @@ static int BoolKeyword (StrBuf* Ident)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ApplyPragma (int PushPop, IntStack* Stack, long Val)
|
||||||
|
/* Apply a pragma immediately */
|
||||||
|
{
|
||||||
|
if (PushPop > 0) {
|
||||||
|
/* Push the new value */
|
||||||
|
PushInt (Stack, Val);
|
||||||
|
} else if (PushPop < 0) {
|
||||||
|
/* Pop the old value */
|
||||||
|
PopInt (Stack);
|
||||||
|
} else {
|
||||||
|
/* Set the new value */
|
||||||
|
IS_Set (Stack, Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void ApplySegNamePragma (pragma_t Token, int PushPop, const char* Name, unsigned char AddrSize)
|
||||||
|
/* Process a segname pragma */
|
||||||
|
{
|
||||||
|
segment_t Seg = SEG_CODE;
|
||||||
|
|
||||||
|
switch (Token) {
|
||||||
|
case PRAGMA_CODE_NAME:
|
||||||
|
case PRAGMA_CODESEG:
|
||||||
|
Seg = SEG_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRAGMA_RODATA_NAME:
|
||||||
|
case PRAGMA_RODATASEG:
|
||||||
|
Seg = SEG_RODATA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRAGMA_DATA_NAME:
|
||||||
|
case PRAGMA_DATASEG:
|
||||||
|
Seg = SEG_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRAGMA_BSS_NAME:
|
||||||
|
case PRAGMA_BSSSEG:
|
||||||
|
Seg = SEG_BSS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Internal ("Unknown segment name pragma: %02X", Token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the new name */
|
||||||
|
if (PushPop > 0) {
|
||||||
|
PushSegName (Seg, Name);
|
||||||
|
} else if (PushPop < 0) {
|
||||||
|
PopSegName (Seg);
|
||||||
|
} else {
|
||||||
|
SetSegName (Seg, Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the optional address size for the segment if valid */
|
||||||
|
if (PushPop >= 0 && AddrSize != ADDR_SIZE_INVALID) {
|
||||||
|
SetSegAddrSize (Name, AddrSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BSS variables are output at the end of the compilation. Don't
|
||||||
|
** bother to change their segment, now.
|
||||||
|
*/
|
||||||
|
if (Seg != SEG_BSS) {
|
||||||
|
g_segname (Seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Pragma handling functions */
|
/* Pragma handling functions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void StringPragma (StrBuf* B, void (*Func) (const char*))
|
static void StringPragma (pragma_scope_t Scope, StrBuf* B, void (*Func) (const char*))
|
||||||
/* Handle a pragma that expects a string parameter */
|
/* Handle a pragma that expects a string parameter */
|
||||||
{
|
{
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* We expect a string here */
|
/* We expect a string here */
|
||||||
if (GetString (B, &S)) {
|
if (GetString (B, &S)) {
|
||||||
/* Call the given function with the string argument */
|
/* Call the given function with the string argument */
|
||||||
@@ -387,14 +476,17 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void SegNamePragma (StrBuf* B, segment_t Seg)
|
static void SegNamePragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B)
|
||||||
/* Handle a pragma that expects a segment name parameter */
|
/* Handle a pragma that expects a segment name parameter */
|
||||||
{
|
{
|
||||||
const char* Name;
|
const char* Name;
|
||||||
unsigned char AddrSize = ADDR_SIZE_INVALID;
|
unsigned char AddrSize = ADDR_SIZE_INVALID;
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
StrBuf A = AUTO_STRBUF_INITIALIZER;
|
StrBuf A = AUTO_STRBUF_INITIALIZER;
|
||||||
int Push = 0;
|
int PushPop = 0;
|
||||||
|
|
||||||
|
/* Unused at the moment */
|
||||||
|
(void)Scope;
|
||||||
|
|
||||||
/* Check for the "push" or "pop" keywords */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
switch (ParsePushPop (B)) {
|
||||||
@@ -403,19 +495,12 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_PUSH:
|
case PP_PUSH:
|
||||||
Push = 1;
|
PushPop = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_POP:
|
case PP_POP:
|
||||||
/* Pop the old value and output it */
|
/* Pop the old value and output it */
|
||||||
PopSegName (Seg);
|
ApplySegNamePragma (Token, -1, 0, 0);
|
||||||
|
|
||||||
/* BSS variables are output at the end of the compilation. Don't
|
|
||||||
** bother to change their segment, now.
|
|
||||||
*/
|
|
||||||
if (Seg != SEG_BSS) {
|
|
||||||
g_segname (Seg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
@@ -454,27 +539,14 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
/* Get the address size for the segment */
|
/* Get the address size for the segment */
|
||||||
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A));
|
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A));
|
||||||
|
|
||||||
/* Set the address size for the segment if valid */
|
/* Check the address size for the segment */
|
||||||
if (AddrSize != ADDR_SIZE_INVALID) {
|
if (AddrSize == ADDR_SIZE_INVALID) {
|
||||||
SetSegAddrSize (Name, AddrSize);
|
Warning ("Invalid address size for segment");
|
||||||
} else {
|
|
||||||
Warning ("Invalid address size for segment!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the new name and optionally address size */
|
/* Set the new name and optionally address size */
|
||||||
if (Push) {
|
ApplySegNamePragma (Token, PushPop, Name, AddrSize);
|
||||||
PushSegName (Seg, Name);
|
|
||||||
} else {
|
|
||||||
SetSegName (Seg, Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BSS variables are output at the end of the compilation. Don't
|
|
||||||
** bother to change their segment, now.
|
|
||||||
*/
|
|
||||||
if (Seg != SEG_BSS) {
|
|
||||||
g_segname (Seg);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -484,13 +556,15 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExitPoint:
|
ExitPoint:
|
||||||
|
|
||||||
/* Call the string buf destructor */
|
/* Call the string buf destructor */
|
||||||
SB_Done (&S);
|
SB_Done (&S);
|
||||||
SB_Done (&A);
|
SB_Done (&A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void WrappedCallPragma (StrBuf* B)
|
|
||||||
|
static void WrappedCallPragma (pragma_scope_t Scope, StrBuf* B)
|
||||||
/* Handle the wrapped-call pragma */
|
/* Handle the wrapped-call pragma */
|
||||||
{
|
{
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
@@ -498,6 +572,9 @@ static void WrappedCallPragma (StrBuf* B)
|
|||||||
long Val;
|
long Val;
|
||||||
SymEntry *Entry;
|
SymEntry *Entry;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* Check for the "push" or "pop" keywords */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
switch (ParsePushPop (B)) {
|
||||||
|
|
||||||
@@ -573,11 +650,14 @@ ExitPoint:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void CharMapPragma (StrBuf* B)
|
static void CharMapPragma (pragma_scope_t Scope, StrBuf* B)
|
||||||
/* Change the character map */
|
/* Change the character map */
|
||||||
{
|
{
|
||||||
long Index, C;
|
long Index, C;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* Read the character index */
|
/* Read the character index */
|
||||||
if (!GetNumber (B, &Index)) {
|
if (!GetNumber (B, &Index)) {
|
||||||
return;
|
return;
|
||||||
@@ -619,7 +699,7 @@ static void CharMapPragma (StrBuf* B)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void WarnPragma (StrBuf* B)
|
static void WarnPragma (pragma_scope_t Scope, StrBuf* B)
|
||||||
/* Enable/disable warnings */
|
/* Enable/disable warnings */
|
||||||
{
|
{
|
||||||
long Val;
|
long Val;
|
||||||
@@ -627,6 +707,10 @@ static void WarnPragma (StrBuf* B)
|
|||||||
|
|
||||||
/* A warning name must follow */
|
/* A warning name must follow */
|
||||||
IntStack* S = GetWarning (B);
|
IntStack* S = GetWarning (B);
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
if (S == 0) {
|
if (S == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -680,48 +764,47 @@ static void WarnPragma (StrBuf* B)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void FlagPragma (StrBuf* B, IntStack* Stack)
|
static void FlagPragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B, IntStack* Stack)
|
||||||
/* Handle a pragma that expects a boolean parameter */
|
/* Handle a pragma that expects a boolean parameter */
|
||||||
{
|
{
|
||||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||||
long Val;
|
long Val;
|
||||||
int Push;
|
int PushPop = 0;
|
||||||
|
|
||||||
|
/* Unused at the moment */
|
||||||
|
(void)Scope;
|
||||||
|
(void)Token;
|
||||||
|
|
||||||
/* Try to read an identifier */
|
/* Try to read an identifier */
|
||||||
int IsIdent = SB_GetSym (B, &Ident, 0);
|
int IsIdent = SB_GetSym (B, &Ident, 0);
|
||||||
|
|
||||||
/* Check if we have a first argument named "pop" */
|
/* Check if we have a first argument named "pop" */
|
||||||
if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
|
if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
|
||||||
PopInt (Stack);
|
/* Pop the old value and bail out */
|
||||||
|
ApplyPragma (-1, Stack, 0);
|
||||||
|
|
||||||
/* No other arguments allowed */
|
/* No other arguments allowed */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we have a first argument named "push" */
|
/* Check if we have a first argument named "push" */
|
||||||
if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
|
if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
|
||||||
Push = 1;
|
PushPop = 1;
|
||||||
if (!GetComma (B)) {
|
if (!GetComma (B)) {
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
IsIdent = SB_GetSym (B, &Ident, 0);
|
IsIdent = SB_GetSym (B, &Ident, 0);
|
||||||
} else {
|
|
||||||
Push = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Boolean argument follows */
|
/* Boolean argument follows */
|
||||||
if (IsIdent) {
|
if (IsIdent) {
|
||||||
Val = BoolKeyword (&Ident);
|
Val = IsBoolKeyword (&Ident);
|
||||||
} else if (!GetNumber (B, &Val)) {
|
} else if (!GetNumber (B, &Val)) {
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set/push the new value */
|
/* Add this pragma and apply it whenever appropriately */
|
||||||
if (Push) {
|
ApplyPragma (PushPop, Stack, Val);
|
||||||
PushInt (Stack, Val);
|
|
||||||
} else {
|
|
||||||
IS_Set (Stack, Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitPoint:
|
ExitPoint:
|
||||||
/* Free the identifier */
|
/* Free the identifier */
|
||||||
@@ -730,12 +813,16 @@ ExitPoint:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
static void IntPragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B, IntStack* Stack, long Low, long High)
|
||||||
/* Handle a pragma that expects an int parameter */
|
/* Handle a pragma that expects an int parameter */
|
||||||
{
|
{
|
||||||
long Val;
|
long Val;
|
||||||
int Push;
|
int Push;
|
||||||
|
|
||||||
|
/* Unused at the moment */
|
||||||
|
(void)Scope;
|
||||||
|
(void)Token;
|
||||||
|
|
||||||
/* Check for the "push" or "pop" keywords */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
switch (ParsePushPop (B)) {
|
||||||
|
|
||||||
@@ -749,7 +836,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
|||||||
|
|
||||||
case PP_POP:
|
case PP_POP:
|
||||||
/* Pop the old value and bail out */
|
/* Pop the old value and bail out */
|
||||||
PopInt (Stack);
|
ApplyPragma (-1, Stack, 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PP_ERROR:
|
case PP_ERROR:
|
||||||
@@ -772,31 +859,32 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set/push the new value */
|
/* Add this pragma and apply it whenever appropriately */
|
||||||
if (Push) {
|
ApplyPragma (Push, Stack, Val);
|
||||||
PushInt (Stack, Val);
|
|
||||||
} else {
|
|
||||||
IS_Set (Stack, Val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void MakeMessage (const char* Message)
|
static void NoteMessagePragma (const char* Message)
|
||||||
|
/* Wrapper for printf-like Note() function protected from user-provided format
|
||||||
|
** specifiers.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
Note ("%s", Message);
|
Note ("%s", Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParsePragma (void)
|
static void ParsePragmaString (void)
|
||||||
/* Parse the contents of the _Pragma statement */
|
/* Parse the contents of _Pragma */
|
||||||
{
|
{
|
||||||
pragma_t Pragma;
|
pragma_t Pragma;
|
||||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
/* Create a string buffer from the string literal */
|
/* Create a string buffer from the string literal */
|
||||||
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
|
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
|
||||||
|
|
||||||
/* Skip the string token */
|
/* Skip the string token */
|
||||||
@@ -837,111 +925,130 @@ static void ParsePragma (void)
|
|||||||
switch (Pragma) {
|
switch (Pragma) {
|
||||||
|
|
||||||
case PRAGMA_ALIGN:
|
case PRAGMA_ALIGN:
|
||||||
IntPragma (&B, &DataAlignment, 1, 4096);
|
/* TODO: PES_EXPR (PES_DECL) */
|
||||||
|
IntPragma (PES_STMT, Pragma, &B, &DataAlignment, 1, 4096);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_ALLOW_EAGER_INLINE:
|
case PRAGMA_ALLOW_EAGER_INLINE:
|
||||||
FlagPragma (&B, &EagerlyInlineFuncs);
|
FlagPragma (PES_STMT, Pragma, &B, &EagerlyInlineFuncs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_BSSSEG:
|
case PRAGMA_BSSSEG:
|
||||||
Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
|
Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_BSS_NAME:
|
case PRAGMA_BSS_NAME:
|
||||||
SegNamePragma (&B, SEG_BSS);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
SegNamePragma (PES_FUNC, PRAGMA_BSS_NAME, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CHARMAP:
|
case PRAGMA_CHARMAP:
|
||||||
CharMapPragma (&B);
|
CharMapPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CHECKSTACK:
|
case PRAGMA_CHECKSTACK:
|
||||||
Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
|
Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_CHECK_STACK:
|
case PRAGMA_CHECK_STACK:
|
||||||
FlagPragma (&B, &CheckStack);
|
/* TODO: PES_SCOPE maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &CheckStack);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CODESEG:
|
case PRAGMA_CODESEG:
|
||||||
Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
|
Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_CODE_NAME:
|
case PRAGMA_CODE_NAME:
|
||||||
SegNamePragma (&B, SEG_CODE);
|
/* PES_FUNC is the only sensible option so far */
|
||||||
|
SegNamePragma (PES_FUNC, PRAGMA_CODE_NAME, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CODESIZE:
|
case PRAGMA_CODESIZE:
|
||||||
IntPragma (&B, &CodeSizeFactor, 10, 1000);
|
/* PES_EXPR would be optimization nightmare */
|
||||||
|
IntPragma (PES_STMT, Pragma, &B, &CodeSizeFactor, 10, 1000);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_DATASEG:
|
case PRAGMA_DATASEG:
|
||||||
Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
|
Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_DATA_NAME:
|
case PRAGMA_DATA_NAME:
|
||||||
SegNamePragma (&B, SEG_DATA);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
SegNamePragma (PES_FUNC, PRAGMA_DATA_NAME, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_INLINE_STDFUNCS:
|
case PRAGMA_INLINE_STDFUNCS:
|
||||||
FlagPragma (&B, &InlineStdFuncs);
|
/* TODO: PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_STMT, Pragma, &B, &InlineStdFuncs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_LOCAL_STRINGS:
|
case PRAGMA_LOCAL_STRINGS:
|
||||||
FlagPragma (&B, &LocalStrings);
|
/* TODO: PES_STMT or even PES_EXPR */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &LocalStrings);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_MESSAGE:
|
case PRAGMA_MESSAGE:
|
||||||
StringPragma (&B, MakeMessage);
|
/* PES_IMM is the only sensible option */
|
||||||
|
StringPragma (PES_IMM, &B, NoteMessagePragma);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_OPTIMIZE:
|
case PRAGMA_OPTIMIZE:
|
||||||
FlagPragma (&B, &Optimize);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_STMT, Pragma, &B, &Optimize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_REGVARADDR:
|
case PRAGMA_REGVARADDR:
|
||||||
FlagPragma (&B, &AllowRegVarAddr);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &AllowRegVarAddr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_REGVARS:
|
case PRAGMA_REGVARS:
|
||||||
Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
|
Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_REGISTER_VARS:
|
case PRAGMA_REGISTER_VARS:
|
||||||
FlagPragma (&B, &EnableRegVars);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &EnableRegVars);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_RODATASEG:
|
case PRAGMA_RODATASEG:
|
||||||
Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
|
Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_RODATA_NAME:
|
case PRAGMA_RODATA_NAME:
|
||||||
SegNamePragma (&B, SEG_RODATA);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_SIGNEDCHARS:
|
case PRAGMA_SIGNEDCHARS:
|
||||||
Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
|
Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_SIGNED_CHARS:
|
case PRAGMA_SIGNED_CHARS:
|
||||||
FlagPragma (&B, &SignedChars);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &SignedChars);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_STATICLOCALS:
|
case PRAGMA_STATICLOCALS:
|
||||||
Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
|
Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_STATIC_LOCALS:
|
case PRAGMA_STATIC_LOCALS:
|
||||||
FlagPragma (&B, &StaticLocals);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &StaticLocals);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WRAPPED_CALL:
|
case PRAGMA_WRAPPED_CALL:
|
||||||
WrappedCallPragma(&B);
|
/* PES_IMM is the only sensible option */
|
||||||
|
WrappedCallPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WARN:
|
case PRAGMA_WARN:
|
||||||
WarnPragma (&B);
|
/* PES_IMM is the only sensible option */
|
||||||
|
WarnPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WRITABLE_STRINGS:
|
case PRAGMA_WRITABLE_STRINGS:
|
||||||
FlagPragma (&B, &WritableStrings);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &WritableStrings);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_ZPSYM:
|
case PRAGMA_ZPSYM:
|
||||||
StringPragma (&B, MakeZPSym);
|
/* PES_IMM is the only sensible option */
|
||||||
|
StringPragma (PES_IMM, &B, MakeZPSym);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -975,20 +1082,31 @@ ExitPoint:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DoPragma (void)
|
/*****************************************************************************/
|
||||||
/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConsumePragma (void)
|
||||||
|
/* Parse a pragma. The pragma comes always in the form of the new C99 _Pragma()
|
||||||
|
** operator.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
/* Skip the token itself */
|
/* Skip the _Pragma token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
|
/* Prevent from translating string literals in _Pragma */
|
||||||
|
++InPragmaParser;
|
||||||
|
|
||||||
/* We expect an opening paren */
|
/* We expect an opening paren */
|
||||||
if (!ConsumeLParen ()) {
|
if (!ConsumeLParen ()) {
|
||||||
|
--InPragmaParser;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* String literal */
|
/* String literal */
|
||||||
if (CurTok.Tok != TOK_SCONST) {
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
|
|
||||||
/* Print a diagnostic */
|
/* Print a diagnostic */
|
||||||
Error ("String literal expected");
|
Error ("String literal expected");
|
||||||
|
|
||||||
@@ -996,13 +1114,13 @@ void DoPragma (void)
|
|||||||
** enclosing paren, or a semicolon.
|
** enclosing paren, or a semicolon.
|
||||||
*/
|
*/
|
||||||
PragmaErrorSkip ();
|
PragmaErrorSkip ();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
/* Parse the pragma */
|
||||||
/* Parse the _Pragma statement */
|
ParsePragmaString ();
|
||||||
ParsePragma ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--InPragmaParser;
|
||||||
|
|
||||||
/* Closing paren needed */
|
/* Closing paren needed */
|
||||||
ConsumeRParen ();
|
ConsumeRParen ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DoPragma (void);
|
void ConsumePragma (void);
|
||||||
/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
|
/* Parse a pragma. The pragma comes always in the form of the new C99 _Pragma()
|
||||||
|
** operator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
#include "ident.h"
|
#include "ident.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
|
#include "pragma.h"
|
||||||
#include "preproc.h"
|
#include "preproc.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
@@ -69,9 +70,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Token CurTok; /* The current token */
|
static Token SavedTok; /* Saved token */
|
||||||
Token NextTok; /* The next token */
|
Token CurTok; /* The current token */
|
||||||
int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
Token NextTok; /* The next token */
|
||||||
|
int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||||
|
int NoCharMap; /* Disable literal translation */
|
||||||
|
unsigned InPragmaParser; /* Depth of pragma parser calling */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -323,7 +327,7 @@ static void SetTok (int tok)
|
|||||||
|
|
||||||
|
|
||||||
static int ParseChar (void)
|
static int ParseChar (void)
|
||||||
/* Parse a character. Converts escape chars into character codes. */
|
/* Parse a character token. Converts escape chars into character codes. */
|
||||||
{
|
{
|
||||||
int C;
|
int C;
|
||||||
int HadError;
|
int HadError;
|
||||||
@@ -425,7 +429,7 @@ static int ParseChar (void)
|
|||||||
|
|
||||||
|
|
||||||
static void CharConst (void)
|
static void CharConst (void)
|
||||||
/* Parse a character constant. */
|
/* Parse a character constant token */
|
||||||
{
|
{
|
||||||
int C;
|
int C;
|
||||||
|
|
||||||
@@ -453,7 +457,7 @@ static void CharConst (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Translate into target charset */
|
/* Translate into target charset */
|
||||||
NextTok.IVal = SignExtendChar (TgtTranslateChar (C));
|
NextTok.IVal = SignExtendChar (C);
|
||||||
|
|
||||||
/* Character constants have type int */
|
/* Character constants have type int */
|
||||||
NextTok.Type = type_int;
|
NextTok.Type = type_int;
|
||||||
@@ -462,7 +466,7 @@ static void CharConst (void)
|
|||||||
|
|
||||||
|
|
||||||
static void StringConst (void)
|
static void StringConst (void)
|
||||||
/* Parse a quoted string */
|
/* Parse a quoted string token */
|
||||||
{
|
{
|
||||||
/* String buffer */
|
/* String buffer */
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
@@ -470,43 +474,34 @@ static void StringConst (void)
|
|||||||
/* Assume next token is a string constant */
|
/* Assume next token is a string constant */
|
||||||
NextTok.Tok = TOK_SCONST;
|
NextTok.Tok = TOK_SCONST;
|
||||||
|
|
||||||
/* Concatenate strings. If at least one of the concenated strings is a wide
|
/* Check if this is a normal or a wide char string */
|
||||||
** character literal, the whole string is a wide char literal, otherwise
|
if (CurC == 'L' && NextC == '\"') {
|
||||||
** it's a normal string literal.
|
/* Wide character literal */
|
||||||
*/
|
NextTok.Tok = TOK_WCSCONST;
|
||||||
while (1) {
|
NextChar ();
|
||||||
|
NextChar ();
|
||||||
|
} else if (CurC == '\"') {
|
||||||
|
/* Skip the quote char */
|
||||||
|
NextChar ();
|
||||||
|
} else {
|
||||||
|
/* No string */
|
||||||
|
goto ExitPoint;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if this is a normal or a wide char string */
|
/* Read until end of string */
|
||||||
if (CurC == 'L' && NextC == '\"') {
|
while (CurC != '\"') {
|
||||||
/* Wide character literal */
|
if (CurC == '\0') {
|
||||||
NextTok.Tok = TOK_WCSCONST;
|
Error ("Unexpected newline");
|
||||||
NextChar ();
|
|
||||||
NextChar ();
|
|
||||||
} else if (CurC == '\"') {
|
|
||||||
/* Skip the quote char */
|
|
||||||
NextChar ();
|
|
||||||
} else {
|
|
||||||
/* No string */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
SB_AppendChar (&S, ParseChar ());
|
||||||
/* Read until end of string */
|
|
||||||
while (CurC != '\"') {
|
|
||||||
if (CurC == '\0') {
|
|
||||||
Error ("Unexpected newline");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SB_AppendChar (&S, ParseChar ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip closing quote char if there was one */
|
|
||||||
NextChar ();
|
|
||||||
|
|
||||||
/* Skip white space, read new input */
|
|
||||||
SkipWhite ();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Skip closing quote char if there was one */
|
||||||
|
NextChar ();
|
||||||
|
|
||||||
|
ExitPoint:
|
||||||
|
|
||||||
/* Terminate the string */
|
/* Terminate the string */
|
||||||
SB_AppendChar (&S, '\0');
|
SB_AppendChar (&S, '\0');
|
||||||
|
|
||||||
@@ -520,7 +515,7 @@ static void StringConst (void)
|
|||||||
|
|
||||||
|
|
||||||
static void NumericConst (void)
|
static void NumericConst (void)
|
||||||
/* Parse a numeric constant */
|
/* Parse a numeric constant token */
|
||||||
{
|
{
|
||||||
unsigned Base; /* Temporary number base according to prefix */
|
unsigned Base; /* Temporary number base according to prefix */
|
||||||
unsigned Index;
|
unsigned Index;
|
||||||
@@ -800,39 +795,49 @@ static void NumericConst (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void NextToken (void)
|
static void GetNextInputToken (void)
|
||||||
/* Get next token from input stream */
|
/* Get next token from input stream */
|
||||||
{
|
{
|
||||||
ident token;
|
ident token;
|
||||||
|
|
||||||
/* We have to skip white space here before shifting tokens, since the
|
if (!NoCharMap && !InPragmaParser) {
|
||||||
** tokens and the current line info is invalid at startup and will get
|
/* Translate string and character literals into target charset */
|
||||||
** initialized by reading the first time from the file. Remember if
|
if (NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST) {
|
||||||
** we were at end of input and handle that later.
|
TranslateLiteral (NextTok.SVal);
|
||||||
*/
|
} else if (NextTok.Tok == TOK_CCONST || NextTok.Tok == TOK_WCCONST) {
|
||||||
int GotEOF = (SkipWhite() == 0);
|
NextTok.IVal = SignExtendChar (TgtTranslateChar (NextTok.IVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Current token is the lookahead token */
|
/* Current token is the lookahead token */
|
||||||
if (CurTok.LI) {
|
if (CurTok.LI) {
|
||||||
ReleaseLineInfo (CurTok.LI);
|
ReleaseLineInfo (CurTok.LI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the current token */
|
||||||
CurTok = NextTok;
|
CurTok = NextTok;
|
||||||
|
|
||||||
/* When reading the first time from the file, the line info in NextTok,
|
if (SavedTok.Tok == TOK_INVALID) {
|
||||||
** which was copied to CurTok is invalid. Since the information from
|
/* We have to skip white space here before shifting tokens, since the
|
||||||
** the token is used for error messages, we must make it valid.
|
** tokens and the current line info is invalid at startup and will get
|
||||||
*/
|
** initialized by reading the first time from the file. Remember if we
|
||||||
if (CurTok.LI == 0) {
|
** were at end of input and handle that later.
|
||||||
CurTok.LI = UseLineInfo (GetCurLineInfo ());
|
*/
|
||||||
}
|
int GotEOF = (SkipWhite () == 0);
|
||||||
|
|
||||||
/* Remember the starting position of the next token */
|
/* Remember the starting position of the next token */
|
||||||
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||||
|
|
||||||
/* Now handle end of input. */
|
/* Now handle end of input */
|
||||||
if (GotEOF) {
|
if (GotEOF) {
|
||||||
/* End of file reached */
|
/* End of file reached */
|
||||||
NextTok.Tok = TOK_CEOF;
|
NextTok.Tok = TOK_CEOF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Just use the saved token */
|
||||||
|
NextTok = SavedTok;
|
||||||
|
SavedTok.Tok = TOK_INVALID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -859,7 +864,8 @@ void NextToken (void)
|
|||||||
|
|
||||||
if (!PPParserRunning) {
|
if (!PPParserRunning) {
|
||||||
/* Check for a keyword */
|
/* Check for a keyword */
|
||||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
NextTok.Tok = FindKey (token);
|
||||||
|
if (NextTok.Tok != TOK_IDENT) {
|
||||||
/* Reserved word found */
|
/* Reserved word found */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1123,90 @@ void NextToken (void)
|
|||||||
UnknownChar (CurC);
|
UnknownChar (CurC);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void NextToken (void)
|
||||||
|
/* Get next non-pragma token from input stream consuming any pragmas
|
||||||
|
** encountered. Adjacent string literal tokens will be concatenated.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Used for string literal concatenation */
|
||||||
|
Token PrevTok;
|
||||||
|
|
||||||
|
/* When reading the first time from the file, the line info in NextTok,
|
||||||
|
** which will be copied to CurTok is invalid. Since the information from
|
||||||
|
** the token is used for error messages, we must make it valid.
|
||||||
|
*/
|
||||||
|
if (NextTok.LI == 0) {
|
||||||
|
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||||
|
}
|
||||||
|
|
||||||
|
PrevTok.Tok = TOK_INVALID;
|
||||||
|
while (1) {
|
||||||
|
/* Read the next token from the file */
|
||||||
|
GetNextInputToken ();
|
||||||
|
|
||||||
|
/* Consume all pragmas at hand, including those nested in a _Pragma() */
|
||||||
|
if (CurTok.Tok == TOK_PRAGMA) {
|
||||||
|
/* Repeated and/or nested _Pragma()'s will be handled recursively */
|
||||||
|
ConsumePragma ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for string concatenation */
|
||||||
|
if (CurTok.Tok == TOK_SCONST || CurTok.Tok == TOK_WCSCONST) {
|
||||||
|
if (PrevTok.Tok == TOK_SCONST || PrevTok.Tok == TOK_WCSCONST) {
|
||||||
|
/* Warn on non-ISO behavior */
|
||||||
|
if (InPragmaParser) {
|
||||||
|
Warning ("Concatenated string literals in _Pragma operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Concatenate strings */
|
||||||
|
ConcatLiteral (PrevTok.SVal, CurTok.SVal);
|
||||||
|
|
||||||
|
/* If at least one of the concatenated strings is a wide
|
||||||
|
** character literal, the whole string is a wide char
|
||||||
|
** literal, otherwise it is a normal string literal.
|
||||||
|
*/
|
||||||
|
if (CurTok.Tok == TOK_WCSCONST) {
|
||||||
|
PrevTok.Tok = TOK_WCSCONST;
|
||||||
|
PrevTok.Type = CurTok.Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NextTok.Tok == TOK_SCONST ||
|
||||||
|
NextTok.Tok == TOK_WCSCONST ||
|
||||||
|
NextTok.Tok == TOK_PRAGMA) {
|
||||||
|
/* Remember current string literal token */
|
||||||
|
if (PrevTok.Tok == TOK_INVALID) {
|
||||||
|
PrevTok = CurTok;
|
||||||
|
PrevTok.LI = UseLineInfo (PrevTok.LI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep looping */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the concatenated string literal token if there is one */
|
||||||
|
if (PrevTok.Tok == TOK_SCONST || PrevTok.Tok == TOK_WCSCONST) {
|
||||||
|
if (CurTok.Tok != TOK_SCONST && CurTok.Tok != TOK_WCSCONST) {
|
||||||
|
/* Push back the incoming tokens */
|
||||||
|
SavedTok = NextTok;
|
||||||
|
NextTok = CurTok;
|
||||||
|
} else {
|
||||||
|
/* The last string literal token can be just replaced */
|
||||||
|
if (CurTok.LI) {
|
||||||
|
ReleaseLineInfo (CurTok.LI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Replace the current token with the concatenated string literal */
|
||||||
|
CurTok = PrevTok;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -219,9 +219,11 @@ struct Token {
|
|||||||
const Type* Type; /* Type if integer or float constant */
|
const Type* Type; /* Type if integer or float constant */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Token CurTok; /* The current token */
|
extern Token CurTok; /* The current token */
|
||||||
extern Token NextTok; /* The next token */
|
extern Token NextTok; /* The next token */
|
||||||
extern int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
extern int PPParserRunning; /* Is tokenizer used by the preprocessor */
|
||||||
|
extern int NoCharMap; /* Disable literal translation */
|
||||||
|
extern unsigned InPragmaParser; /* Depth of pragma parser calling */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -299,7 +301,9 @@ void CopyPPNumber (StrBuf* Target);
|
|||||||
/* Copy a pp-number from the input to Target */
|
/* Copy a pp-number from the input to Target */
|
||||||
|
|
||||||
void NextToken (void);
|
void NextToken (void);
|
||||||
/* Get next token from input stream */
|
/* Get next non-pragma token from input stream consuming any pragmas
|
||||||
|
** encountered. Adjacent string literal tokens will be concatenated.
|
||||||
|
*/
|
||||||
|
|
||||||
void SkipTokens (const token_t* TokenList, unsigned TokenCount);
|
void SkipTokens (const token_t* TokenList, unsigned TokenCount);
|
||||||
/* Skip tokens until we reach TOK_CEOF or a token in the given token list.
|
/* Skip tokens until we reach TOK_CEOF or a token in the given token list.
|
||||||
|
|||||||
@@ -72,9 +72,15 @@ void ParseStaticAssert ()
|
|||||||
** support the C2X syntax with only an expression.
|
** support the C2X syntax with only an expression.
|
||||||
*/
|
*/
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
/* Skip the comma. */
|
/* Prevent from translating the message string literal */
|
||||||
|
NoCharMap = 1;
|
||||||
|
|
||||||
|
/* Skip the comma and get the next token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
|
/* Reenable string literal translation */
|
||||||
|
NoCharMap = 0;
|
||||||
|
|
||||||
/* String literal */
|
/* String literal */
|
||||||
if (CurTok.Tok != TOK_SCONST) {
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
Error ("String literal expected for static_assert message");
|
Error ("String literal expected for static_assert message");
|
||||||
|
|||||||
@@ -735,10 +735,6 @@ int AnyStatement (int* PendingToken)
|
|||||||
GotBreak = 1;
|
GotBreak = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_PRAGMA:
|
|
||||||
DoPragma ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_SEMI:
|
case TOK_SEMI:
|
||||||
/* Empty statement. Ignore it */
|
/* Empty statement. Ignore it */
|
||||||
CheckSemi (PendingToken);
|
CheckSemi (PendingToken);
|
||||||
|
|||||||
77
test/val/bug2151.c
Normal file
77
test/val/bug2151.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* Bug #2151 - #pragma causes errors when used within functions */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#pragma charmap(0x61, 0x61)
|
||||||
|
_Static_assert('A'==
|
||||||
|
#pragma charmap(0x61, 0x41)
|
||||||
|
'a'
|
||||||
|
#pragma charmap(0x61, 0x42)
|
||||||
|
,
|
||||||
|
#pragma charmap(0x61, 0x61)
|
||||||
|
"charmap failed");
|
||||||
|
|
||||||
|
char str[] =
|
||||||
|
"a"
|
||||||
|
#pragma charmap(0x61, 0x42)
|
||||||
|
"a"
|
||||||
|
#pragma charmap(0x61, 0x43)
|
||||||
|
"a"
|
||||||
|
#pragma charmap(0x61, 0x61)
|
||||||
|
;
|
||||||
|
|
||||||
|
unsigned failures;
|
||||||
|
|
||||||
|
#pragma bss-name("BSS1")
|
||||||
|
int
|
||||||
|
#pragma code-name("CODE_WUT")
|
||||||
|
main _Pragma
|
||||||
|
#pragma charmap(0x61, 0x32)
|
||||||
|
(
|
||||||
|
"message(\"_Pragma string"
|
||||||
|
/* Concatenated string literals in _Pragma is a cc65 extension */
|
||||||
|
" unaffected by charmap\")"
|
||||||
|
)
|
||||||
|
#pragma charmap(0x61, 0x61)
|
||||||
|
(
|
||||||
|
void
|
||||||
|
_Pragma _Pragma (
|
||||||
|
#pragma message("nested message 1")
|
||||||
|
"message(\"nested message 2\")"
|
||||||
|
)
|
||||||
|
(
|
||||||
|
"message(\"_Pragma in function parentheses\")")
|
||||||
|
#pragma code-name("CODE")
|
||||||
|
)
|
||||||
|
#pragma bss-name("BSS")
|
||||||
|
{
|
||||||
|
extern int y;
|
||||||
|
#pragma bss-name("BSS2")
|
||||||
|
static
|
||||||
|
#pragma zpsym ("y")
|
||||||
|
int x; // TODO: currently in "BSS", but supposed to be in "BSS2"?
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
if (memcmp(str, "aBC", 3))
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("%3s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x + y != 0)
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("%d\n", x + y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failures != 0)
|
||||||
|
{
|
||||||
|
printf("faiures: %d\n", failures);
|
||||||
|
}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
#pragma bss-name("BSS")
|
||||||
|
}
|
||||||
|
|
||||||
|
int y;
|
||||||
Reference in New Issue
Block a user