mirror of
https://github.com/cc65/cc65.git
synced 2025-02-05 04:37:23 +00:00
Reused code more for macros in preprocessing directives.
This commit is contained in:
parent
36123c9c8f
commit
79f97e7714
@ -67,6 +67,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 +116,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 */
|
||||
|
||||
|
||||
|
||||
@ -545,7 +559,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;
|
||||
@ -809,122 +823,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,97 +916,19 @@ 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 ();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
/* Object-like macro */
|
||||
ExpandMacro (Target, M, 0);
|
||||
SB_AppendChar (Target, CurC);
|
||||
NextChar ();
|
||||
}
|
||||
} 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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1260,7 +1163,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);
|
||||
@ -1324,7 +1227,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);
|
||||
@ -1400,7 +1303,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 (");
|
||||
@ -1448,7 +1351,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;
|
||||
@ -1576,7 +1479,7 @@ static int ParseDirectives (int InArgList)
|
||||
|
||||
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");
|
||||
@ -1626,11 +1529,76 @@ static int ParseDirectives (int InArgList)
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preprocessor */
|
||||
/* 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 (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 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 */
|
||||
{
|
||||
@ -1641,7 +1609,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 */
|
||||
@ -1651,7 +1619,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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user