mirror of
https://github.com/cc65/cc65.git
synced 2024-06-16 09:29:32 +00:00
Merge branch 'master' into silversurfer
This commit is contained in:
commit
7ff6d244c5
|
@ -396,6 +396,11 @@ void Compile (const char* FileName)
|
|||
DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
|
||||
}
|
||||
|
||||
/* Placeholders for __FILE__, __LINE__ and __COUNTER__ macros */
|
||||
DefineTextMacro ("__FILE__", "");
|
||||
DefineTextMacro ("__LINE__", "");
|
||||
DefineTextMacro ("__COUNTER__", "");
|
||||
|
||||
/* __TIME__ and __DATE__ macros */
|
||||
Time = time (0);
|
||||
TM = localtime (&Time);
|
||||
|
|
|
@ -1133,10 +1133,6 @@ static void Primary (ExprDesc* E)
|
|||
/* Enum or some other numeric constant */
|
||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
||||
E->IVal = Sym->V.ConstVal;
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
/* Function */
|
||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
|
||||
/* Local variable. If this is a parameter for a variadic
|
||||
** function, we have to add some address calculations, and the
|
||||
|
@ -1151,6 +1147,10 @@ static void Primary (ExprDesc* E)
|
|||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
||||
E->IVal = Sym->V.Offs;
|
||||
}
|
||||
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
||||
/* Function */
|
||||
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
||||
E->Name = (uintptr_t) Sym->Name;
|
||||
} else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
|
||||
/* Register variable, zero page based */
|
||||
E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL;
|
||||
|
|
|
@ -92,6 +92,7 @@ struct AFile {
|
|||
FILE* F; /* Input file stream */
|
||||
IFile* Input; /* Points to corresponding IFile */
|
||||
int SearchPath; /* True if we've added a path for this file */
|
||||
char* PName; /* Presumed name of the file */
|
||||
PPIfStack IfStack; /* PP #if stack */
|
||||
int MissingNL; /* Last input line was missing a newline */
|
||||
};
|
||||
|
@ -105,6 +106,9 @@ static Collection AFiles = STATIC_COLLECTION_INITIALIZER;
|
|||
/* Input stack used when preprocessing. */
|
||||
static Collection InputStack = STATIC_COLLECTION_INITIALIZER;
|
||||
|
||||
/* Counter for the __COUNTER__ macro */
|
||||
static unsigned MainFileCounter;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -159,6 +163,7 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
|||
AF->Line = 0;
|
||||
AF->F = F;
|
||||
AF->Input = IF;
|
||||
AF->PName = 0;
|
||||
AF->IfStack.Index = -1;
|
||||
AF->MissingNL = 0;
|
||||
|
||||
|
@ -209,6 +214,9 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
|||
static void FreeAFile (AFile* AF)
|
||||
/* Free an AFile structure */
|
||||
{
|
||||
if (AF->PName != 0) {
|
||||
xfree (AF->PName);
|
||||
}
|
||||
xfree (AF);
|
||||
}
|
||||
|
||||
|
@ -275,6 +283,9 @@ void OpenMainFile (const char* Name)
|
|||
** the main file before the first line is read.
|
||||
*/
|
||||
UpdateLineInfo (MainFile->Input, MainFile->Line, Line);
|
||||
|
||||
/* Initialize the __COUNTER__ counter */
|
||||
MainFileCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -599,8 +610,8 @@ const char* GetCurrentFile (void)
|
|||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
||||
return AF->Input->Name;
|
||||
const AFile* AF = CollLast (&AFiles);
|
||||
return AF->PName == 0 ? AF->Input->Name : AF->PName;
|
||||
} else {
|
||||
/* No open file */
|
||||
return "(outside file scope)";
|
||||
|
@ -614,7 +625,7 @@ unsigned GetCurrentLine (void)
|
|||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
||||
const AFile* AF = CollLast (&AFiles);
|
||||
return AF->Line;
|
||||
} else {
|
||||
/* No open file */
|
||||
|
@ -624,6 +635,43 @@ unsigned GetCurrentLine (void)
|
|||
|
||||
|
||||
|
||||
void SetCurrentLine (unsigned LineNum)
|
||||
/* Set the line number in the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
AFile* AF = CollLast (&AFiles);
|
||||
AF->Line = LineNum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetCurrentFilename (const char* Name)
|
||||
/* Set the presumed name of the current input file */
|
||||
{
|
||||
unsigned AFileCount = CollCount (&AFiles);
|
||||
if (AFileCount > 0) {
|
||||
size_t Len = strlen (Name);
|
||||
AFile* AF = CollLast (&AFiles);
|
||||
if (AF->PName != 0) {
|
||||
xfree (AF->PName);
|
||||
}
|
||||
AF->PName = xmalloc (Len + 1);
|
||||
memcpy (AF->PName, Name, Len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned GetCurrentCounter (void)
|
||||
/* Return the counter number in the current input file */
|
||||
{
|
||||
return MainFileCounter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void WriteEscaped (FILE* F, const char* Name)
|
||||
/* Write a file name to a dependency file escaping spaces */
|
||||
{
|
||||
|
|
|
@ -122,6 +122,15 @@ const char* GetCurrentFile (void);
|
|||
unsigned GetCurrentLine (void);
|
||||
/* Return the line number in the current input file */
|
||||
|
||||
void SetCurrentLine (unsigned LineNum);
|
||||
/* Set the line number in the current input file */
|
||||
|
||||
void SetCurrentFilename (const char* Name);
|
||||
/* Set the presumed name of the current input file */
|
||||
|
||||
unsigned GetCurrentCounter (void);
|
||||
/* Return the counter number in the current input file */
|
||||
|
||||
void CreateDependencies (void);
|
||||
/* Create dependency files requested by the user */
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
/* cc65 */
|
||||
#include "error.h"
|
||||
#include "preproc.h"
|
||||
#include "macrotab.h"
|
||||
|
||||
|
||||
|
@ -246,6 +247,10 @@ Macro* FindMacro (const char* Name)
|
|||
Macro* M = MacroTab[Hash];
|
||||
while (M) {
|
||||
if (strcmp (M->Name, Name) == 0) {
|
||||
/* Check for some special macro names */
|
||||
if (Name[0] == '_') {
|
||||
HandleSpecialMacro (M, Name);
|
||||
}
|
||||
/* Found it */
|
||||
return M;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "ppexpr.h"
|
||||
#include "preproc.h"
|
||||
#include "scanner.h"
|
||||
#include "scanstrbuf.h"
|
||||
#include "standard.h"
|
||||
|
||||
|
||||
|
@ -67,6 +68,17 @@
|
|||
|
||||
|
||||
|
||||
/* Macro scanner mode flags */
|
||||
#define MSM_NONE 0x00U /* Default */
|
||||
#define MSM_MULTILINE 0x01U /* Read from multiple lines */
|
||||
#define MSM_IN_DIRECTIVE 0x02U /* In PP directives scan */
|
||||
#define MSM_IN_ARG_LIST 0x04U /* In macro argument scan */
|
||||
#define MSM_IN_ARG_EXPANSION 0x08U /* In expansion on arguments */
|
||||
#define MSM_OP_DEFINED 0x10U /* Handle the defined operator */
|
||||
#define MSM_OP_HAS_INCLUDE 0x20U /* Handle the __has_include operator */
|
||||
#define MSM_OP_HAS_C_ATTRIBUTE 0x40U /* Handle the __has_c_attribute operator */
|
||||
#define MSM_TOK_HEADER 0x80U /* Support header tokens */
|
||||
|
||||
/* Management data for #if */
|
||||
#define IFCOND_NONE 0x00U
|
||||
#define IFCOND_SKIP 0x01U
|
||||
|
@ -105,13 +117,16 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target);
|
|||
** non-newline whitespace sequences.
|
||||
*/
|
||||
|
||||
static int ParseDirectives (int InArgList);
|
||||
/* Handle directives. Return 1 if there are directives parsed, -1 if new lines
|
||||
** are read, otherwise 0.
|
||||
static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags);
|
||||
/* Preprocess a single line. Handle specified tokens and operators, remove
|
||||
** whitespace and comments, then do macro replacement.
|
||||
*/
|
||||
|
||||
static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine);
|
||||
/* Perform macro replacement. */
|
||||
static int ParseDirectives (unsigned ModeFlags);
|
||||
/* Handle directives. Return 1 if any whitespace or newlines are parsed. */
|
||||
|
||||
static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags);
|
||||
/* Scan for and perform macro replacement */
|
||||
|
||||
|
||||
|
||||
|
@ -121,67 +136,67 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine);
|
|||
|
||||
|
||||
|
||||
/* Types of preprocessor tokens */
|
||||
/* Types of preprocessor directives */
|
||||
typedef enum {
|
||||
PP_ILLEGAL = -1,
|
||||
PP_DEFINE,
|
||||
PP_ELIF,
|
||||
PP_ELSE,
|
||||
PP_ENDIF,
|
||||
PP_ERROR,
|
||||
PP_IF,
|
||||
PP_IFDEF,
|
||||
PP_IFNDEF,
|
||||
PP_INCLUDE,
|
||||
PP_LINE,
|
||||
PP_PRAGMA,
|
||||
PP_UNDEF,
|
||||
PP_WARNING,
|
||||
} pptoken_t;
|
||||
PPD_ILLEGAL = -1,
|
||||
PPD_DEFINE,
|
||||
PPD_ELIF,
|
||||
PPD_ELSE,
|
||||
PPD_ENDIF,
|
||||
PPD_ERROR,
|
||||
PPD_IF,
|
||||
PPD_IFDEF,
|
||||
PPD_IFNDEF,
|
||||
PPD_INCLUDE,
|
||||
PPD_LINE,
|
||||
PPD_PRAGMA,
|
||||
PPD_UNDEF,
|
||||
PPD_WARNING,
|
||||
} ppdirective_t;
|
||||
|
||||
|
||||
|
||||
/* Preprocessor keyword to token mapping table */
|
||||
static const struct PPToken {
|
||||
const char* Key; /* Keyword */
|
||||
pptoken_t Tok; /* Token */
|
||||
} PPTokens[] = {
|
||||
{ "define", PP_DEFINE },
|
||||
{ "elif", PP_ELIF },
|
||||
{ "else", PP_ELSE },
|
||||
{ "endif", PP_ENDIF },
|
||||
{ "error", PP_ERROR },
|
||||
{ "if", PP_IF },
|
||||
{ "ifdef", PP_IFDEF },
|
||||
{ "ifndef", PP_IFNDEF },
|
||||
{ "include", PP_INCLUDE },
|
||||
{ "line", PP_LINE },
|
||||
{ "pragma", PP_PRAGMA },
|
||||
{ "undef", PP_UNDEF },
|
||||
{ "warning", PP_WARNING },
|
||||
/* Preprocessor directive tokens mapping table */
|
||||
static const struct PPDType {
|
||||
const char* Tok; /* Token */
|
||||
ppdirective_t Type; /* Type */
|
||||
} PPDTypes[] = {
|
||||
{ "define", PPD_DEFINE },
|
||||
{ "elif", PPD_ELIF },
|
||||
{ "else", PPD_ELSE },
|
||||
{ "endif", PPD_ENDIF },
|
||||
{ "error", PPD_ERROR },
|
||||
{ "if", PPD_IF },
|
||||
{ "ifdef", PPD_IFDEF },
|
||||
{ "ifndef", PPD_IFNDEF },
|
||||
{ "include", PPD_INCLUDE },
|
||||
{ "line", PPD_LINE },
|
||||
{ "pragma", PPD_PRAGMA },
|
||||
{ "undef", PPD_UNDEF },
|
||||
{ "warning", PPD_WARNING },
|
||||
};
|
||||
|
||||
/* Number of preprocessor tokens */
|
||||
#define PPTOKEN_COUNT (sizeof(PPTokens) / sizeof(PPTokens[0]))
|
||||
/* Number of preprocessor directive types */
|
||||
#define PPDTOKEN_COUNT (sizeof(PPDTypes) / sizeof(PPDTypes[0]))
|
||||
|
||||
|
||||
|
||||
static int CmpToken (const void* Key, const void* Elem)
|
||||
/* Compare function for bsearch */
|
||||
{
|
||||
return strcmp ((const char*) Key, ((const struct PPToken*) Elem)->Key);
|
||||
return strcmp ((const char*) Key, ((const struct PPDType*) Elem)->Tok);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static pptoken_t FindPPToken (const char* Ident)
|
||||
/* Find a preprocessor token and return it. Return PP_ILLEGAL if the identifier
|
||||
** is not a valid preprocessor token.
|
||||
static ppdirective_t FindPPDirectiveType (const char* Ident)
|
||||
/* Find a preprocessor directive type and return it. Return PPD_ILLEGAL if the
|
||||
** identifier is not a valid preprocessor directive token.
|
||||
*/
|
||||
{
|
||||
struct PPToken* P;
|
||||
P = bsearch (Ident, PPTokens, PPTOKEN_COUNT, sizeof (PPTokens[0]), CmpToken);
|
||||
return P? P->Tok : PP_ILLEGAL;
|
||||
struct PPDType* P;
|
||||
P = bsearch (Ident, PPDTypes, PPDTOKEN_COUNT, sizeof (PPDTypes[0]), CmpToken);
|
||||
return P? P->Type : PPD_ILLEGAL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -257,6 +272,26 @@ static int ME_ArgIsVariadic (const MacroExp* E, const Macro* M)
|
|||
|
||||
|
||||
|
||||
static int MacName (char* Ident)
|
||||
/* Get a macro symbol name into Ident. If we have an error, print a
|
||||
** diagnostic message and clear the line.
|
||||
*/
|
||||
{
|
||||
if (IsSym (Ident) == 0) {
|
||||
if (CurC != '\0') {
|
||||
PPError ("Macro name must be an identifier");
|
||||
} else {
|
||||
PPError ("Missing macro name");
|
||||
}
|
||||
ClearLine ();
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void AddPreLine (StrBuf* Str)
|
||||
/* Add newlines to the string buffer */
|
||||
{
|
||||
|
@ -265,7 +300,7 @@ static void AddPreLine (StrBuf* Str)
|
|||
return;
|
||||
}
|
||||
|
||||
if (FileChanged || PendingNewLines > 4) {
|
||||
if (FileChanged || PendingNewLines > 6) {
|
||||
/* Output #line directives as source info */
|
||||
StrBuf Comment = AUTO_STRBUF_INITIALIZER;
|
||||
if (SB_NotEmpty (Str) && SB_LookAtLast (Str) != '\n') {
|
||||
|
@ -366,6 +401,11 @@ static void OldStyleComment (void)
|
|||
static void NewStyleComment (void)
|
||||
/* Remove a new style C comment from line. */
|
||||
{
|
||||
/* Diagnose if this is unsupported */
|
||||
if (IS_Get (&Standard) < STD_C99) {
|
||||
PPError ("C++ style comments are not allowed in C89");
|
||||
}
|
||||
|
||||
/* Beware: Because line continuation chars are handled when reading
|
||||
** lines, we may only skip until the end of the source line, which
|
||||
** may not be the same as the end of the input line. The end of the
|
||||
|
@ -398,7 +438,7 @@ static int SkipWhitespace (int SkipLines)
|
|||
} else if (CurC == '/' && NextC == '*') {
|
||||
OldStyleComment ();
|
||||
Skipped = 1;
|
||||
} else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
|
||||
} else if (CurC == '/' && NextC == '/') {
|
||||
NewStyleComment ();
|
||||
Skipped = 1;
|
||||
} else if (CurC == '\0' && SkipLines) {
|
||||
|
@ -502,26 +542,6 @@ static int CheckExtraTokens (const char* Name)
|
|||
|
||||
|
||||
|
||||
static int MacName (char* Ident)
|
||||
/* Get a macro symbol name into Ident. If we have an error, print a
|
||||
** diagnostic message and clear the line.
|
||||
*/
|
||||
{
|
||||
if (IsSym (Ident) == 0) {
|
||||
if (CurC != '\0') {
|
||||
PPError ("Macro name must be an identifier");
|
||||
} else {
|
||||
PPError ("Missing macro name");
|
||||
}
|
||||
ClearLine ();
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine)
|
||||
/* Identify the arguments to a macro call as-is */
|
||||
{
|
||||
|
@ -545,7 +565,7 @@ static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine)
|
|||
Newlines += PendingNewLines - OldPendingNewLines;
|
||||
PendingNewLines = OldPendingNewLines;
|
||||
OldPendingNewLines = 0;
|
||||
Skipped = ParseDirectives (1) || Skipped;
|
||||
Skipped = ParseDirectives (MSM_IN_ARG_LIST) || Skipped;
|
||||
Skipped = SkipWhitespace (MultiLine) || Skipped;
|
||||
}
|
||||
PendingNewLines += Newlines;
|
||||
|
@ -637,7 +657,7 @@ static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine)
|
|||
|
||||
|
||||
|
||||
static void MacroArgSubst (MacroExp* E, Macro* M)
|
||||
static void SubstMacroArgs (MacroExp* E, Macro* M)
|
||||
/* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */
|
||||
{
|
||||
ident Ident;
|
||||
|
@ -792,7 +812,7 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine)
|
|||
}
|
||||
|
||||
/* Replace macro arguments handling the # and ## operators */
|
||||
MacroArgSubst (&E, M);
|
||||
SubstMacroArgs (&E, M);
|
||||
|
||||
/* Forbide repeated expansion of the same macro in use */
|
||||
M->Expanding = 1;
|
||||
|
@ -809,122 +829,89 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine)
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preprocessing */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
|
||||
/* Mimic Translation Phase 3. Handle old and new style comments. Collapse
|
||||
** non-newline whitespace sequences.
|
||||
*/
|
||||
static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags)
|
||||
/* Scan for and perform macro replacement */
|
||||
{
|
||||
/* Switch to the new input source */
|
||||
StrBuf* OldSource = InitLine (Source);
|
||||
|
||||
/* Loop removing ws and comments */
|
||||
while (CurC != '\0') {
|
||||
int HasWhiteSpace = 0;
|
||||
while (1) {
|
||||
/* Squeeze runs of blanks */
|
||||
if (IsSpace (CurC)) {
|
||||
NextChar ();
|
||||
HasWhiteSpace = 1;
|
||||
} else if (CurC == '/' && NextC == '*') {
|
||||
OldStyleComment ();
|
||||
HasWhiteSpace = 1;
|
||||
} else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
|
||||
NewStyleComment ();
|
||||
HasWhiteSpace = 1;
|
||||
} else {
|
||||
/* No more white space */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (HasWhiteSpace) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
} else if (IsQuote (CurC)) {
|
||||
CopyQuotedString (Target);
|
||||
} else {
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate the new input line */
|
||||
SB_Terminate (Target);
|
||||
|
||||
/* Switch back to the old source */
|
||||
InitLine (OldSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ProcessSingleLine (StrBuf* Source,
|
||||
StrBuf* Target,
|
||||
int HandleDefined,
|
||||
int HandleHeader)
|
||||
/* Process a single line. Remove whitespace, old and new style comments.
|
||||
** Recognize and handle the "defined" operator if HandleDefined is true.
|
||||
** Recognize and handle header name tokens if HandleHeader is true.
|
||||
*/
|
||||
{
|
||||
int OldIndex = SB_GetIndex (Source);
|
||||
ident Ident;
|
||||
int HaveParen;
|
||||
|
||||
/* Operate on the new input source */
|
||||
/* Remember the current input and switch to Source */
|
||||
StrBuf* OldSource = InitLine (Source);
|
||||
|
||||
SkipWhitespace (0);
|
||||
|
||||
/* Loop removing ws and comments */
|
||||
/* Loop substituting macros */
|
||||
while (CurC != '\0') {
|
||||
if (SkipWhitespace (0)) {
|
||||
/* Squeeze runs of blanks */
|
||||
if (!IsSpace (SB_LookAtLast (Target))) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
}
|
||||
} else if (IsSym (Ident)) {
|
||||
if (HandleDefined && strcmp (Ident, "defined") == 0) {
|
||||
/* If we have an identifier, check if it's a macro */
|
||||
if (IsSym (Ident)) {
|
||||
if ((ModeFlags & MSM_OP_DEFINED) != 0 && strcmp (Ident, "defined") == 0) {
|
||||
/* Handle the "defined" operator */
|
||||
int HaveParen = 0;
|
||||
|
||||
SkipWhitespace (0);
|
||||
HaveParen = 0;
|
||||
if (CurC == '(') {
|
||||
HaveParen = 1;
|
||||
NextChar ();
|
||||
SkipWhitespace (0);
|
||||
}
|
||||
if (IsSym (Ident)) {
|
||||
SB_AppendChar (Target, IsMacro (Ident)? '1' : '0');
|
||||
/* Eat the identifier */
|
||||
SB_AppendChar (Target, IsMacro (Ident) ? '1' : '0');
|
||||
if (HaveParen) {
|
||||
SkipWhitespace (0);
|
||||
if (CurC != ')') {
|
||||
PPError ("')' expected");
|
||||
ClearLine ();
|
||||
} else {
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PPError ("Identifier expected");
|
||||
PPError ("Macro name must be an identifier");
|
||||
ClearLine ();
|
||||
SB_AppendChar (Target, '0');
|
||||
}
|
||||
} else {
|
||||
/* Check if it's an expandable macro */
|
||||
Macro* M = FindMacro (Ident);
|
||||
if (M != 0 && !M->Expanding) {
|
||||
/* Check if this is a function-like macro */
|
||||
if (M->ArgCount >= 0) {
|
||||
int Whitespace = SkipWhitespace (0);
|
||||
int MultiLine = (ModeFlags & MSM_MULTILINE) != 0;
|
||||
int Whitespace = SkipWhitespace (MultiLine);
|
||||
if (CurC != '(') {
|
||||
/* Function-like macro without an argument list is not replaced */
|
||||
SB_AppendStr (Target, M->Name);
|
||||
if (Whitespace) {
|
||||
if (Whitespace > 0) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
}
|
||||
|
||||
/* Directives can only be found in an argument list
|
||||
** that spans multiple lines.
|
||||
*/
|
||||
if (MultiLine) {
|
||||
if (CurC == '#') {
|
||||
/* If we were going to support #pragma in
|
||||
** macro argument list, it would be output
|
||||
** to OLine.
|
||||
*/
|
||||
if (OLine == 0) {
|
||||
OLine = Target;
|
||||
ParseDirectives (ModeFlags);
|
||||
OLine = 0;
|
||||
} else {
|
||||
ParseDirectives (ModeFlags);
|
||||
}
|
||||
}
|
||||
/* Add the source info to preprocessor output if needed */
|
||||
AddPreLine (Target);
|
||||
}
|
||||
} else {
|
||||
/* Function-like macro */
|
||||
ExpandMacro (Target, M, 0);
|
||||
if (OLine == 0) {
|
||||
OLine = Target;
|
||||
ExpandMacro (Target, M, MultiLine);
|
||||
OLine = 0;
|
||||
} else {
|
||||
ExpandMacro (Target, M, MultiLine);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Object-like macro */
|
||||
|
@ -935,99 +922,26 @@ static void ProcessSingleLine (StrBuf* Source,
|
|||
SB_AppendStr (Target, Ident);
|
||||
}
|
||||
}
|
||||
} else if (HandleHeader && (CurC == '<' || CurC == '\"')) {
|
||||
CopyHeaderNameToken (Target);
|
||||
} else if (IsQuote (CurC)) {
|
||||
CopyQuotedString (Target);
|
||||
} else {
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
if ((ModeFlags & MSM_TOK_HEADER) != 0 && (CurC == '<' || CurC == '\"')) {
|
||||
CopyHeaderNameToken (Target);
|
||||
} else if (IsQuote (CurC)) {
|
||||
CopyQuotedString (Target);
|
||||
} else {
|
||||
int Whitespace = SkipWhitespace (0);
|
||||
if (Whitespace) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
} else {
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch back to the old source */
|
||||
InitLine (OldSource);
|
||||
|
||||
/* Restore the source input index */
|
||||
SB_SetIndex (Source, OldIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine)
|
||||
/* Perform macro replacement. */
|
||||
{
|
||||
ident Ident;
|
||||
Macro* M;
|
||||
|
||||
/* Remember the current input and switch to Source */
|
||||
StrBuf* OldSource = InitLine (Source);
|
||||
|
||||
/* Loop substituting macros */
|
||||
while (CurC != '\0') {
|
||||
/* If we have an identifier, check if it's a macro */
|
||||
if (IsSym (Ident)) {
|
||||
/* Check if it's a macro */
|
||||
if ((M = FindMacro (Ident)) != 0 && !M->Expanding) {
|
||||
/* Check if this is a function-like macro */
|
||||
if (M->ArgCount >= 0) {
|
||||
int Whitespace = SkipWhitespace (MultiLine);
|
||||
if (CurC != '(') {
|
||||
/* Function-like macro without an argument list is not replaced */
|
||||
SB_AppendStr (Target, M->Name);
|
||||
if (Whitespace > 0) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
}
|
||||
|
||||
/* Directives can only be found in an argument list
|
||||
** that spans multiple lines.
|
||||
*/
|
||||
if (MultiLine) {
|
||||
if (CurC == '#') {
|
||||
/* If we were going to support #pragma in
|
||||
** macro argument list, it would be output
|
||||
** to OLine.
|
||||
*/
|
||||
if (OLine == 0) {
|
||||
OLine = Target;
|
||||
ParseDirectives (0);
|
||||
OLine = 0;
|
||||
} else {
|
||||
ParseDirectives (0);
|
||||
}
|
||||
}
|
||||
/* Add the source info to preprocessor output if needed */
|
||||
AddPreLine (Target);
|
||||
}
|
||||
} else {
|
||||
/* Function-like macro */
|
||||
if (OLine == 0) {
|
||||
OLine = Target;
|
||||
ExpandMacro (Target, M, MultiLine);
|
||||
OLine = 0;
|
||||
} else {
|
||||
ExpandMacro (Target, M, MultiLine);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Object-like macro */
|
||||
ExpandMacro (Target, M, 0);
|
||||
}
|
||||
} else {
|
||||
/* An identifier, keep it */
|
||||
SB_AppendStr (Target, Ident);
|
||||
}
|
||||
} else if (IsQuote (CurC)) {
|
||||
CopyQuotedString (Target);
|
||||
} else {
|
||||
int Whitespace = SkipWhitespace (0);
|
||||
if (Whitespace) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
} else {
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
/* Drop whitespace at the end */
|
||||
if (IsBlank (SB_LookAtLast (Target))) {
|
||||
SB_Drop (Target, 1);
|
||||
}
|
||||
|
||||
/* Switch back the input */
|
||||
|
@ -1036,6 +950,12 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine)
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Directives */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void DoDefine (void)
|
||||
/* Process #define directive */
|
||||
{
|
||||
|
@ -1090,6 +1010,7 @@ static void DoDefine (void)
|
|||
if (CurC != '.' || NextC != '.') {
|
||||
PPError ("'...' expected");
|
||||
ClearLine ();
|
||||
FreeMacro (M);
|
||||
return;
|
||||
}
|
||||
NextChar ();
|
||||
|
@ -1129,8 +1050,9 @@ static void DoDefine (void)
|
|||
|
||||
/* Check for a right paren and eat it if we find one */
|
||||
if (CurC != ')') {
|
||||
PPError ("')' expected");
|
||||
PPError ("')' expected for macro definition");
|
||||
ClearLine ();
|
||||
FreeMacro (M);
|
||||
return;
|
||||
}
|
||||
NextChar ();
|
||||
|
@ -1254,7 +1176,7 @@ static int DoIf (int Skip)
|
|||
|
||||
/* Macro-replace a single line with support for the "defined" operator */
|
||||
SB_Clear (MLine);
|
||||
ProcessSingleLine (Line, MLine, 1, 0);
|
||||
PreprocessDirective (Line, MLine, MSM_OP_DEFINED);
|
||||
|
||||
/* Read from the processed line */
|
||||
SB_Reset (MLine);
|
||||
|
@ -1318,7 +1240,7 @@ static void DoInclude (void)
|
|||
|
||||
/* Macro-replace a single line with special support for <filename> */
|
||||
SB_Clear (MLine);
|
||||
ProcessSingleLine (Line, MLine, 0, 1);
|
||||
PreprocessDirective (Line, MLine, MSM_TOK_HEADER);
|
||||
|
||||
/* Read from the processed line */
|
||||
SB_Reset (MLine);
|
||||
|
@ -1340,7 +1262,7 @@ static void DoInclude (void)
|
|||
break;
|
||||
|
||||
default:
|
||||
PPError ("'\"' or '<' expected");
|
||||
PPError ("#include expects \"FILENAME\" or <FILENAME>");
|
||||
goto Done;
|
||||
}
|
||||
NextChar ();
|
||||
|
@ -1360,7 +1282,7 @@ static void DoInclude (void)
|
|||
CheckExtraTokens ("include");
|
||||
/* Open the include file */
|
||||
OpenIncludeFile (SB_GetConstBuf (&Filename), IT);
|
||||
} else if (CurC == '\0') {
|
||||
} else {
|
||||
/* No terminator found */
|
||||
PPError ("#include expects \"FILENAME\" or <FILENAME>");
|
||||
}
|
||||
|
@ -1380,6 +1302,95 @@ Done:
|
|||
|
||||
|
||||
|
||||
static unsigned GetLineDirectiveNum (void)
|
||||
/* Get a decimal digit-sequence from the input. Return 0 on errors. */
|
||||
{
|
||||
unsigned long Num = 0;
|
||||
StrBuf Buf = AUTO_STRBUF_INITIALIZER;
|
||||
|
||||
/* The only non-decimal-numeric character allowed in the digit-sequence is
|
||||
** the digit separator '\'' as of C23, but we haven't supported it yet.
|
||||
*/
|
||||
SkipWhitespace (0);
|
||||
while (IsDigit (CurC))
|
||||
{
|
||||
SB_AppendChar (&Buf, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
|
||||
/* Ensure the buffer is terminated with a '\0' */
|
||||
SB_Terminate (&Buf);
|
||||
if (SkipWhitespace (0) != 0 || CurC == '\0') {
|
||||
const char* Str = SB_GetConstBuf (&Buf);
|
||||
if (Str[0] == '\0') {
|
||||
PPWarning ("#line directive interprets number as decimal, not octal");
|
||||
} else {
|
||||
Num = strtoul (Str, 0, 10);
|
||||
if (Num > 2147483647) {
|
||||
PPError ("#line directive requires an integer argument not greater than 2147483647");
|
||||
ClearLine ();
|
||||
Num = 0;
|
||||
} else if (Num == 0) {
|
||||
PPError ("#line directive requires a positive integer argument");
|
||||
ClearLine ();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PPError ("#line directive requires a simple decimal digit sequence");
|
||||
ClearLine ();
|
||||
}
|
||||
|
||||
/* Done with the buffer */
|
||||
SB_Done (&Buf);
|
||||
|
||||
return (unsigned)Num;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DoLine (void)
|
||||
/* Process #line directive */
|
||||
{
|
||||
unsigned LineNum;
|
||||
|
||||
/* Macro-replace a single line with support for the "defined" operator */
|
||||
SB_Clear (MLine);
|
||||
PreprocessDirective (Line, MLine, MSM_NONE);
|
||||
|
||||
/* Read from the processed line */
|
||||
SB_Reset (MLine);
|
||||
MLine = InitLine (MLine);
|
||||
|
||||
/* Parse and check the specified line number */
|
||||
LineNum = GetLineDirectiveNum ();
|
||||
if (LineNum != 0) {
|
||||
/* Parse and check the optional filename argument */
|
||||
if (SB_GetIndex (Line) < SB_GetLen (Line)) {
|
||||
StrBuf Filename = AUTO_STRBUF_INITIALIZER;
|
||||
if (SB_GetString (Line, &Filename)) {
|
||||
SB_Terminate (&Filename);
|
||||
SetCurrentFilename (SB_GetConstBuf (&Filename));
|
||||
} else {
|
||||
PPError ("Invalid filename for #line directive");
|
||||
LineNum = 0;
|
||||
}
|
||||
SB_Done (&Filename);
|
||||
}
|
||||
|
||||
/* #line actually sets the line number of the next line */
|
||||
if (LineNum > 0) {
|
||||
SetCurrentLine (LineNum - 1);
|
||||
/* Check for extra tokens at the end */
|
||||
CheckExtraTokens ("line");
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore input source */
|
||||
MLine = InitLine (MLine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DoPragma (void)
|
||||
/* Handle a #pragma line by converting the #pragma preprocessor directive into
|
||||
** the _Pragma() compiler operator.
|
||||
|
@ -1394,7 +1405,7 @@ static void DoPragma (void)
|
|||
|
||||
/* Macro-replace a single line */
|
||||
SB_Clear (MLine);
|
||||
ProcessSingleLine (Line, MLine, 0, 0);
|
||||
PreprocessDirective (Line, MLine, MSM_NONE);
|
||||
|
||||
/* Convert #pragma to _Pragma () */
|
||||
SB_AppendStr (PragmaLine, "_Pragma (");
|
||||
|
@ -1442,7 +1453,7 @@ static void DoWarning (void)
|
|||
|
||||
|
||||
|
||||
static int ParseDirectives (int InArgList)
|
||||
static int ParseDirectives (unsigned ModeFlags)
|
||||
/* Handle directives. Return 1 if any whitespace or newlines are parsed. */
|
||||
{
|
||||
int PPSkip = 0;
|
||||
|
@ -1468,15 +1479,15 @@ static int ParseDirectives (int InArgList)
|
|||
}
|
||||
ClearLine ();
|
||||
} else {
|
||||
switch (FindPPToken (Directive)) {
|
||||
switch (FindPPDirectiveType (Directive)) {
|
||||
|
||||
case PP_DEFINE:
|
||||
case PPD_DEFINE:
|
||||
if (!PPSkip) {
|
||||
DoDefine ();
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_ELIF:
|
||||
case PPD_ELIF:
|
||||
if (PPStack->Index >= 0) {
|
||||
if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) {
|
||||
/* Handle as #else/#if combination */
|
||||
|
@ -1496,7 +1507,7 @@ static int ParseDirectives (int InArgList)
|
|||
}
|
||||
break;
|
||||
|
||||
case PP_ELSE:
|
||||
case PPD_ELSE:
|
||||
if (PPStack->Index >= 0) {
|
||||
if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) {
|
||||
if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) {
|
||||
|
@ -1514,7 +1525,7 @@ static int ParseDirectives (int InArgList)
|
|||
}
|
||||
break;
|
||||
|
||||
case PP_ENDIF:
|
||||
case PPD_ENDIF:
|
||||
if (PPStack->Index >= 0) {
|
||||
/* Remove any clauses on top of stack that do not
|
||||
** need a terminating #endif.
|
||||
|
@ -1537,40 +1548,39 @@ static int ParseDirectives (int InArgList)
|
|||
}
|
||||
break;
|
||||
|
||||
case PP_ERROR:
|
||||
case PPD_ERROR:
|
||||
if (!PPSkip) {
|
||||
DoError ();
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_IF:
|
||||
case PPD_IF:
|
||||
PPSkip = DoIf (PPSkip);
|
||||
break;
|
||||
|
||||
case PP_IFDEF:
|
||||
case PPD_IFDEF:
|
||||
PPSkip = DoIfDef (PPSkip, 1);
|
||||
break;
|
||||
|
||||
case PP_IFNDEF:
|
||||
case PPD_IFNDEF:
|
||||
PPSkip = DoIfDef (PPSkip, 0);
|
||||
break;
|
||||
|
||||
case PP_INCLUDE:
|
||||
case PPD_INCLUDE:
|
||||
if (!PPSkip) {
|
||||
DoInclude ();
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_LINE:
|
||||
/* Should do something in C99 at least, but we ignore it */
|
||||
case PPD_LINE:
|
||||
if (!PPSkip) {
|
||||
ClearLine ();
|
||||
DoLine ();
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_PRAGMA:
|
||||
case PPD_PRAGMA:
|
||||
if (!PPSkip) {
|
||||
if (!InArgList) {
|
||||
if ((ModeFlags & MSM_IN_ARG_LIST) == 0) {
|
||||
DoPragma ();
|
||||
} else {
|
||||
PPError ("Embedded #pragma directive within macro arguments is unsupported");
|
||||
|
@ -1578,13 +1588,13 @@ static int ParseDirectives (int InArgList)
|
|||
}
|
||||
break;
|
||||
|
||||
case PP_UNDEF:
|
||||
case PPD_UNDEF:
|
||||
if (!PPSkip) {
|
||||
DoUndef ();
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_WARNING:
|
||||
case PPD_WARNING:
|
||||
/* #warning is a non standard extension */
|
||||
if (IS_Get (&Standard) > STD_C99) {
|
||||
if (!PPSkip) {
|
||||
|
@ -1619,6 +1629,101 @@ static int ParseDirectives (int InArgList)
|
|||
|
||||
|
||||
|
||||
void HandleSpecialMacro (Macro* M, const char* Name)
|
||||
/* Handle special "magic" macros that may change */
|
||||
{
|
||||
if (strcmp (Name, "__COUNTER__") == 0) {
|
||||
/* Replace __COUNTER__ with the current counter number */
|
||||
if (IS_Get (&Standard) < STD_CC65) {
|
||||
PPWarning ("__COUNTER__ is a cc65 extension");
|
||||
}
|
||||
SB_Printf (&M->Replacement, "%u", GetCurrentCounter ());
|
||||
} else if (strcmp (Name, "__LINE__") == 0) {
|
||||
/* Replace __LINE__ with the current line number */
|
||||
SB_Printf (&M->Replacement, "%u", GetCurrentLine ());
|
||||
} else if (strcmp (Name, "__FILE__") == 0) {
|
||||
/* Replace __FILE__ with the current filename */
|
||||
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
||||
SB_InitFromString (&B, GetCurrentFile ());
|
||||
SB_Clear (&M->Replacement);
|
||||
Stringize (&B, &M->Replacement);
|
||||
SB_Done (&B);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preprocessing */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
|
||||
/* Mimic Translation Phase 3. Handle old and new style comments. Collapse
|
||||
** non-newline whitespace sequences.
|
||||
*/
|
||||
{
|
||||
/* Switch to the new input source */
|
||||
StrBuf* OldSource = InitLine (Source);
|
||||
|
||||
/* Loop removing ws and comments */
|
||||
while (CurC != '\0') {
|
||||
int HasWhiteSpace = 0;
|
||||
while (1) {
|
||||
/* Squeeze runs of blanks */
|
||||
if (IsSpace (CurC)) {
|
||||
NextChar ();
|
||||
HasWhiteSpace = 1;
|
||||
} else if (CurC == '/' && NextC == '*') {
|
||||
OldStyleComment ();
|
||||
HasWhiteSpace = 1;
|
||||
} else if (CurC == '/' && NextC == '/') {
|
||||
NewStyleComment ();
|
||||
HasWhiteSpace = 1;
|
||||
} else {
|
||||
/* No more white space */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (HasWhiteSpace) {
|
||||
SB_AppendChar (Target, ' ');
|
||||
} else if (IsQuote (CurC)) {
|
||||
CopyQuotedString (Target);
|
||||
} else {
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate the new input line */
|
||||
SB_Terminate (Target);
|
||||
|
||||
/* Switch back to the old source */
|
||||
InitLine (OldSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags)
|
||||
/* Preprocess a single line. Handle specified tokens and operators, remove
|
||||
** whitespace and comments, then do macro replacement.
|
||||
*/
|
||||
{
|
||||
int OldIndex = SB_GetIndex (Source);
|
||||
MacroExp E;
|
||||
|
||||
SkipWhitespace (0);
|
||||
InitMacroExp (&E);
|
||||
MacroReplacement (Source, Target, ModeFlags | MSM_IN_DIRECTIVE);
|
||||
DoneMacroExp (&E);
|
||||
|
||||
/* Restore the source input index */
|
||||
SB_SetIndex (Source, OldIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Preprocess (void)
|
||||
/* Preprocess lines count of which is affected by directives */
|
||||
{
|
||||
|
@ -1629,7 +1734,7 @@ void Preprocess (void)
|
|||
|
||||
/* Parse any directives */
|
||||
OLine = PLine;
|
||||
ParseDirectives (0);
|
||||
ParseDirectives (MSM_MULTILINE);
|
||||
OLine = 0;
|
||||
|
||||
/* Add the source info to preprocessor output if needed */
|
||||
|
@ -1639,7 +1744,7 @@ void Preprocess (void)
|
|||
AppendIndent (PLine, SB_GetIndex (Line));
|
||||
|
||||
/* Expand macros if any */
|
||||
MacroReplacement (Line, PLine, 1);
|
||||
MacroReplacement (Line, PLine, MSM_MULTILINE);
|
||||
|
||||
/* Add the source info to preprocessor output if needed */
|
||||
AddPreLine (PLine);
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
typedef struct Macro Macro;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
@ -80,6 +90,9 @@ void InitPreprocess (void);
|
|||
void DonePreprocess (void);
|
||||
/* Done with preprocessor */
|
||||
|
||||
void HandleSpecialMacro (Macro* M, const char* Name);
|
||||
/* Handle special "magic" macros that may change */
|
||||
|
||||
|
||||
|
||||
/* End of preproc.h */
|
||||
|
|
|
@ -835,16 +835,7 @@ void NextToken (void)
|
|||
/* No reserved word, check for special symbols */
|
||||
if (token[0] == '_' && token[1] == '_') {
|
||||
/* Special symbols */
|
||||
if (strcmp (token+2, "FILE__") == 0) {
|
||||
NextTok.SVal = AddLiteral (GetCurrentFile());
|
||||
NextTok.Tok = TOK_SCONST;
|
||||
return;
|
||||
} else if (strcmp (token+2, "LINE__") == 0) {
|
||||
NextTok.Tok = TOK_ICONST;
|
||||
NextTok.IVal = GetCurrentLine();
|
||||
NextTok.Type = type_int;
|
||||
return;
|
||||
} else if (strcmp (token+2, "func__") == 0) {
|
||||
if (strcmp (token+2, "func__") == 0) {
|
||||
/* __func__ is only defined in functions */
|
||||
if (CurrentFunc) {
|
||||
NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
|
||||
|
|
|
@ -58,6 +58,20 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR)
|
|||
|
||||
define PRG_template
|
||||
|
||||
# should compile, but gives an error
|
||||
$(WORKDIR)/bug1252.$1.$2.prg: bug1252.c | $(WORKDIR)
|
||||
@echo "FIXME: " $$@ "currently does not compile."
|
||||
$(if $(QUIET),echo misc/bug1252.$1.$2.prg)
|
||||
$(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
||||
$(NOT) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR)
|
||||
# $(NOT) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
|
||||
|
||||
# should compile, but gives an error
|
||||
$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR)
|
||||
@echo "FIXME: " $$@ "currently does not compile."
|
||||
$(if $(QUIET),echo misc/bug1768.$1.$2.prg)
|
||||
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
||||
|
||||
# should compile, but gives an error
|
||||
$(WORKDIR)/bug760.$1.$2.prg: bug760.c | $(WORKDIR)
|
||||
@echo "FIXME: " $$@ "currently does not compile."
|
||||
|
|
19
test/misc/bug1252.c
Normal file
19
test/misc/bug1252.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// this works
|
||||
c_label:
|
||||
asm("inx\n"
|
||||
"bne %g\n",
|
||||
c_label);
|
||||
|
||||
// this does not work
|
||||
c_label2:
|
||||
asm("inx\n"
|
||||
"bne %g \n",
|
||||
c_label2);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
14
test/misc/bug1768.c
Normal file
14
test/misc/bug1768.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
int a = 1 || (8 / 0);
|
||||
int b = 0 && (8 % 0);
|
||||
int c = 1 ? 42 : (0 % 0);
|
||||
int d = 1 || a / 0;
|
||||
int e = 0 && b % 0;
|
||||
int f = 1 ? 42 : (a %= 0, b /= 0);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -9,11 +9,13 @@ ifdef CMD_EXE
|
|||
NULLDEV = nul:
|
||||
MKDIR = mkdir $(subst /,\,$1)
|
||||
RMDIR = -rmdir /s /q $(subst /,\,$1)
|
||||
CATRES =
|
||||
else
|
||||
S = /
|
||||
NULLDEV = /dev/null
|
||||
MKDIR = mkdir -p $1
|
||||
RMDIR = $(RM) -r $1
|
||||
CATRES = || (cat $(WORKDIR)/$$@.out && false)
|
||||
endif
|
||||
|
||||
ifdef QUIET
|
||||
|
@ -51,7 +53,7 @@ $(WORKDIR)/%.$1.$2.prg: %.c | $(WORKDIR)
|
|||
$(CC65) -t sim$2 $$(CC65FLAGS) --add-source -$1 -o $$(@:.prg=.s) $$< $(NULLERR)
|
||||
$(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR)
|
||||
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
|
||||
$(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$@.out
|
||||
$(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$@.out $(CATRES)
|
||||
|
||||
endef # PRG_template
|
||||
|
||||
|
|
81
test/val/bug1573.c
Normal file
81
test/val/bug1573.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/* Tests for predefined macros __LINE__ and __FILE__ as well as #line control */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#if !defined __LINE__
|
||||
#error __LINE__ is not predefined!
|
||||
#endif
|
||||
|
||||
#if !defined __FILE__
|
||||
#error __FILE__ is not predefined!
|
||||
#endif
|
||||
|
||||
#define CONCAT(a,b) CONCAT_impl_(a,b)
|
||||
#define CONCAT_impl_(a,b) a##b
|
||||
#define MKSTR(a) MKSTR_impl_(a)
|
||||
#define MKSTR_impl_(a) #a
|
||||
char CONCAT(ident,__LINE__)[0+__LINE__];
|
||||
char CONCAT(ident,__LINE__)[0+__LINE__];
|
||||
|
||||
#define GET_FILE() __FILE__
|
||||
#define THIS_FILENAME_1 "bug1573.c"
|
||||
#define THIS_FILENAME_2 "<<bar>>"
|
||||
#define INC_FILENAME_1 "bug1573.h"
|
||||
#define INC_FILENAME_2 "<<foo>>"
|
||||
|
||||
#line __LINE__ THIS_FILENAME_1 /* Note: #line sets the line number of the NEXT line */
|
||||
void foo(void)
|
||||
{
|
||||
if (strcmp (GET_FILE(), THIS_FILENAME_1) != 0) {
|
||||
printf("Expected: %s, got: %s\n", THIS_FILENAME_1, GET_FILE());
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
#line __LINE__ THIS_FILENAME_2 /* Note: #line sets the line number of the NEXT line */
|
||||
#include INC_FILENAME_1
|
||||
long line2 = __LINE__;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (strcmp (filename1, INC_FILENAME_1) != 0) {
|
||||
printf("Expected filename1: %s, got: %s\n", INC_FILENAME_1, filename1);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (strcmp (filename2, INC_FILENAME_2) != 0) {
|
||||
printf("Expected filename2: %s, got: %s\n", INC_FILENAME_2, filename2);
|
||||
++failures;
|
||||
}
|
||||
|
||||
foo();
|
||||
|
||||
#line 65535
|
||||
if (strcmp (GET_FILE(), THIS_FILENAME_2) != 0) {
|
||||
printf("Expected: %s, got: %s\n", THIS_FILENAME_2, GET_FILE());
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (line1 != 5L) {
|
||||
printf("Expected line1: %ld, got: %ld\n", 5L, line1);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (line2 != 38L) {
|
||||
printf("Expected line2: %ld, got: %ld\n", 38L, line2);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (strcmp (ans1, ans2) != 0 || strcmp (ans1, "42") != 0) {
|
||||
++failures;
|
||||
printf("Expected: 42, ans1: %s, ans2: %s\n", ans1, ans2);
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
return failures;
|
||||
}
|
14
test/val/bug1573.h
Normal file
14
test/val/bug1573.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* Tests for predefined macros __LINE__ and __FILE__ as well as #line control */
|
||||
|
||||
#line __LINE__ INC_FILENAME_1
|
||||
#define GET_LINE() __LINE__
|
||||
char filename1[] = GET_FILE();
|
||||
long line1 = GET_LINE();
|
||||
|
||||
#line 42
|
||||
const char ans1[] = MKSTR(GET_LINE());
|
||||
|
||||
#line 40 INC_FILENAME_2
|
||||
char filename2[] = GET_FILE();
|
||||
const char ans2[] = \
|
||||
MKSTR(GET_LINE());
|
35
test/val/bug1838.c
Normal file
35
test/val/bug1838.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* Bug 1838 - function parameters declared as function types rather than function pointers */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
typedef int fn_t(int);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void foo(fn_t*);
|
||||
fn_t bar;
|
||||
|
||||
foo(bar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo(int func(int))
|
||||
{
|
||||
int n = func(42);
|
||||
|
||||
if (n != 12) {
|
||||
printf("n = %d, expected: 12\n", n);
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
int bar(int a)
|
||||
{
|
||||
if (a != 42) {
|
||||
printf("a = %d, expected: 42\n", a);
|
||||
++failures;
|
||||
}
|
||||
return 12;
|
||||
}
|
60
test/val/counter.c
Normal file
60
test/val/counter.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#if __COUNTER__ /* 0 */
|
||||
# error __COUNTER__ should begin at 0!
|
||||
#elif __COUNTER__ == 1 /* 1 */
|
||||
# define CONCAT(a,b) CONCAT_impl_(a,b)
|
||||
# define CONCAT_impl_(a,b) a##b
|
||||
#endif
|
||||
|
||||
#line 42 "What is the answer?"
|
||||
int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */
|
||||
|
||||
#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */
|
||||
_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */
|
||||
# define GET_COUNTER() __COUNTER__
|
||||
# define GET_LINE() __LINE__
|
||||
# warning __COUNTER__ in #warning is just output as text and will never increase!
|
||||
#else
|
||||
# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */
|
||||
# endif
|
||||
# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */
|
||||
#endif
|
||||
|
||||
#include "counter.h"
|
||||
#include "counter.h"
|
||||
|
||||
_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (ident2[0] != 42) {
|
||||
printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident3[0] != 42) {
|
||||
printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident8 != 8) {
|
||||
printf("Expected ident8: %s, got: %s\n", 8, ident8);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (ident9 != 9) {
|
||||
printf("Expected ident9: %s, got: %s\n", 9, ident9);
|
||||
++failures;
|
||||
}
|
||||
|
||||
if (failures != 0) {
|
||||
printf("Failures: %d\n", failures);
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
4
test/val/counter.h
Normal file
4
test/val/counter.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
/* Tests for predefined macro __COUNTER__ */
|
||||
|
||||
#line GET_COUNTER() /* 1st: 8; 2nd: 9 */
|
||||
int CONCAT(ident,GET_LINE()) = GET_LINE();
|
Loading…
Reference in New Issue
Block a user