PP: Report an error when a # is not the first thing on a line

According to the GLSL spec
Each number sign (#) can be preceded in its line only by spaces or horizontal tabs.
It may also be followed by spaces and horizontal tabs, preceding the directive.
This commit is contained in:
“jimihe” 2023-11-23 14:19:58 +08:00 committed by arcady-lunarg
parent 530a6266b2
commit feb5437942
3 changed files with 34 additions and 5 deletions

View file

@ -1,5 +1,7 @@
cppBad.vert
WARNING: 0:1: '#define' : missing space after macro name
ERROR: 0:1: '#' : (#) can be preceded in its line only by spaces or horizontal tabs
ERROR: 0:2: '#' : (#) can be preceded in its line only by spaces or horizontal tabs
ERROR: 0:3: 'preprocessor evaluation' : bad expression
ERROR: 0:3: '#if' : unexpected tokens following directive
ERROR: 0:6: 'string' : End of line in string
@ -7,7 +9,7 @@ ERROR: 0:6: 'string literal' : required extension not requested: Possible extens
GL_EXT_debug_printf
GL_EXT_spirv_intrinsics
ERROR: 0:6: '' : syntax error, unexpected INT, expecting COMMA or SEMICOLON
ERROR: 5 compilation errors. No code generated.
ERROR: 7 compilation errors. No code generated.
Shader version: 100

View file

@ -1,7 +1,8 @@
cppBad4.vert
ERROR: 0:2: '#' : (#) can be preceded in its line only by spaces or horizontal tabs
ERROR: 0:4: 'macro expansion' : unexpected '#' g
ERROR: 0:5: '' : syntax error, unexpected SEMICOLON, expecting LEFT_PAREN
ERROR: 2 compilation errors. No code generated.
ERROR: 3 compilation errors. No code generated.
Shader version: 100

View file

@ -215,6 +215,7 @@ public:
virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste
virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
virtual bool isMacroInput() { return false; }
virtual bool isStringInput() { return false; }
// Will be called when we start reading tokens from this instance
virtual void notifyActivated() {}
@ -355,7 +356,8 @@ protected:
// Scanner data:
int previous_token;
TParseContextBase& parseContext;
std::vector<int> lastLineTokens;
std::vector<TSourceLoc> lastLineTokenLocs;
// Get the next token from *stack* of input sources, popping input sources
// that are out of tokens, down until an input source is found that has a token.
// Return EndOfInput when there are no more tokens to be found by doing this.
@ -369,7 +371,31 @@ protected:
break;
popInput();
}
if (!inputStack.empty() && inputStack.back()->isStringInput()) {
if (token == '\n') {
bool seenNumSign = false;
for (int i = 0; i < (int)lastLineTokens.size() - 1;) {
int curPos = i;
int curToken = lastLineTokens[i++];
if (curToken == '#' && lastLineTokens[i] == '#') {
curToken = PpAtomPaste;
i++;
}
if (curToken == '#') {
if (seenNumSign) {
parseContext.ppError(lastLineTokenLocs[curPos], "(#) can be preceded in its line only by spaces or horizontal tabs", "#", "");
} else {
seenNumSign = true;
}
}
}
lastLineTokens.clear();
lastLineTokenLocs.clear();
} else {
lastLineTokens.push_back(token);
lastLineTokenLocs.push_back(ppToken->loc);
}
}
return token;
}
int getChar() { return inputStack.back()->getch(); }
@ -522,7 +548,7 @@ protected:
public:
tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { }
virtual int scan(TPpToken*) override;
bool isStringInput() override { return true; }
// Scanner used to get source stream characters.
// - Escaped newlines are handled here, invisibly to the caller.
// - All forms of newline are handled, and turned into just a '\n'.