mirror of
https://github.com/cc65/cc65.git
synced 2025-08-09 13:25:06 +00:00
Merge pull request #1837 from acqn/PPLineFix
[cc65] Fixed predefined __FILE__, __LINE__ and added missing preprocessing directive #line
This commit is contained in:
@@ -396,6 +396,10 @@ void Compile (const char* FileName)
|
|||||||
DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
|
DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Placeholders for __FILE__ and __LINE__ macros */
|
||||||
|
DefineTextMacro ("__FILE__", "");
|
||||||
|
DefineTextMacro ("__LINE__", "");
|
||||||
|
|
||||||
/* __TIME__ and __DATE__ macros */
|
/* __TIME__ and __DATE__ macros */
|
||||||
Time = time (0);
|
Time = time (0);
|
||||||
TM = localtime (&Time);
|
TM = localtime (&Time);
|
||||||
|
@@ -92,6 +92,7 @@ struct AFile {
|
|||||||
FILE* F; /* Input file stream */
|
FILE* F; /* Input file stream */
|
||||||
IFile* Input; /* Points to corresponding IFile */
|
IFile* Input; /* Points to corresponding IFile */
|
||||||
int SearchPath; /* True if we've added a path for this file */
|
int SearchPath; /* True if we've added a path for this file */
|
||||||
|
char* PName; /* Presumed name of the file */
|
||||||
PPIfStack IfStack; /* PP #if stack */
|
PPIfStack IfStack; /* PP #if stack */
|
||||||
int MissingNL; /* Last input line was missing a newline */
|
int MissingNL; /* Last input line was missing a newline */
|
||||||
};
|
};
|
||||||
@@ -159,6 +160,7 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
|||||||
AF->Line = 0;
|
AF->Line = 0;
|
||||||
AF->F = F;
|
AF->F = F;
|
||||||
AF->Input = IF;
|
AF->Input = IF;
|
||||||
|
AF->PName = 0;
|
||||||
AF->IfStack.Index = -1;
|
AF->IfStack.Index = -1;
|
||||||
AF->MissingNL = 0;
|
AF->MissingNL = 0;
|
||||||
|
|
||||||
@@ -209,6 +211,9 @@ static AFile* NewAFile (IFile* IF, FILE* F)
|
|||||||
static void FreeAFile (AFile* AF)
|
static void FreeAFile (AFile* AF)
|
||||||
/* Free an AFile structure */
|
/* Free an AFile structure */
|
||||||
{
|
{
|
||||||
|
if (AF->PName != 0) {
|
||||||
|
xfree (AF->PName);
|
||||||
|
}
|
||||||
xfree (AF);
|
xfree (AF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,8 +604,8 @@ const char* GetCurrentFile (void)
|
|||||||
{
|
{
|
||||||
unsigned AFileCount = CollCount (&AFiles);
|
unsigned AFileCount = CollCount (&AFiles);
|
||||||
if (AFileCount > 0) {
|
if (AFileCount > 0) {
|
||||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
const AFile* AF = CollLast (&AFiles);
|
||||||
return AF->Input->Name;
|
return AF->PName == 0 ? AF->Input->Name : AF->PName;
|
||||||
} else {
|
} else {
|
||||||
/* No open file */
|
/* No open file */
|
||||||
return "(outside file scope)";
|
return "(outside file scope)";
|
||||||
@@ -614,7 +619,7 @@ unsigned GetCurrentLine (void)
|
|||||||
{
|
{
|
||||||
unsigned AFileCount = CollCount (&AFiles);
|
unsigned AFileCount = CollCount (&AFiles);
|
||||||
if (AFileCount > 0) {
|
if (AFileCount > 0) {
|
||||||
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
|
const AFile* AF = CollLast (&AFiles);
|
||||||
return AF->Line;
|
return AF->Line;
|
||||||
} else {
|
} else {
|
||||||
/* No open file */
|
/* No open file */
|
||||||
@@ -624,6 +629,35 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void WriteEscaped (FILE* F, const char* Name)
|
static void WriteEscaped (FILE* F, const char* Name)
|
||||||
/* Write a file name to a dependency file escaping spaces */
|
/* Write a file name to a dependency file escaping spaces */
|
||||||
{
|
{
|
||||||
|
@@ -122,6 +122,12 @@ const char* GetCurrentFile (void);
|
|||||||
unsigned GetCurrentLine (void);
|
unsigned GetCurrentLine (void);
|
||||||
/* Return the line number in the current input file */
|
/* 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 */
|
||||||
|
|
||||||
void CreateDependencies (void);
|
void CreateDependencies (void);
|
||||||
/* Create dependency files requested by the user */
|
/* Create dependency files requested by the user */
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "preproc.h"
|
||||||
#include "macrotab.h"
|
#include "macrotab.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -246,6 +247,10 @@ Macro* FindMacro (const char* Name)
|
|||||||
Macro* M = MacroTab[Hash];
|
Macro* M = MacroTab[Hash];
|
||||||
while (M) {
|
while (M) {
|
||||||
if (strcmp (M->Name, Name) == 0) {
|
if (strcmp (M->Name, Name) == 0) {
|
||||||
|
/* Check for some special macro names */
|
||||||
|
if (Name[0] == '_') {
|
||||||
|
HandleSpecialMacro (M, Name);
|
||||||
|
}
|
||||||
/* Found it */
|
/* Found it */
|
||||||
return M;
|
return M;
|
||||||
}
|
}
|
||||||
|
@@ -57,6 +57,7 @@
|
|||||||
#include "ppexpr.h"
|
#include "ppexpr.h"
|
||||||
#include "preproc.h"
|
#include "preproc.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
#include "scanstrbuf.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -1301,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)
|
static void DoPragma (void)
|
||||||
/* Handle a #pragma line by converting the #pragma preprocessor directive into
|
/* Handle a #pragma line by converting the #pragma preprocessor directive into
|
||||||
** the _Pragma() compiler operator.
|
** the _Pragma() compiler operator.
|
||||||
@@ -1483,9 +1573,8 @@ static int ParseDirectives (unsigned ModeFlags)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PPD_LINE:
|
case PPD_LINE:
|
||||||
/* Should do something in C99 at least, but we ignore it */
|
|
||||||
if (!PPSkip) {
|
if (!PPSkip) {
|
||||||
ClearLine ();
|
DoLine ();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1540,6 +1629,24 @@ static int ParseDirectives (unsigned ModeFlags)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void HandleSpecialMacro (Macro* M, const char* Name)
|
||||||
|
/* Handle special mandatory macros */
|
||||||
|
{
|
||||||
|
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 */
|
/* Preprocessing */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@@ -38,6 +38,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Forwards */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Macro Macro;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -80,6 +90,9 @@ void InitPreprocess (void);
|
|||||||
void DonePreprocess (void);
|
void DonePreprocess (void);
|
||||||
/* Done with preprocessor */
|
/* Done with preprocessor */
|
||||||
|
|
||||||
|
void HandleSpecialMacro (Macro* M, const char* Name);
|
||||||
|
/* Handle special mandatory macros */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of preproc.h */
|
/* End of preproc.h */
|
||||||
|
@@ -835,16 +835,7 @@ void NextToken (void)
|
|||||||
/* No reserved word, check for special symbols */
|
/* No reserved word, check for special symbols */
|
||||||
if (token[0] == '_' && token[1] == '_') {
|
if (token[0] == '_' && token[1] == '_') {
|
||||||
/* Special symbols */
|
/* Special symbols */
|
||||||
if (strcmp (token+2, "FILE__") == 0) {
|
if (strcmp (token+2, "func__") == 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) {
|
|
||||||
/* __func__ is only defined in functions */
|
/* __func__ is only defined in functions */
|
||||||
if (CurrentFunc) {
|
if (CurrentFunc) {
|
||||||
NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
|
NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
|
||||||
|
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());
|
Reference in New Issue
Block a user