Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lexer detection of translate_on/off pragmas #1157

Merged
merged 10 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/slang/parsing/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ struct SLANG_EXPORT LexerOptions {
/// If true, the preprocessor will support legacy protected envelope directives,
/// for compatibility with old Verilog tools.
bool enableLegacyProtect = false;

/// A flag to enable the interpretation of non-standard line comment pragmas
/// disabling parts of the input for synthesis.
bool enableTranslateOnOffCompat = false;
};

/// Possible encodings for encrypted text used in a pragma protect region.
Expand Down Expand Up @@ -114,6 +118,7 @@ class SLANG_EXPORT Lexer {
void scanEncodedText(ProtectEncoding encoding, uint32_t expectedBytes, bool singleLine,
bool legacyProtectedMode);
void scanProtectComment();
void scanTranslateOffSection();

template<typename... Args>
Token create(TokenKind kind, Args&&... args);
Expand Down
1 change: 1 addition & 0 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ error BadOctalDigit "expected octal digit"
error BadDecimalDigit "expected decimal digit"
error BadHexDigit "expected hexadecimal digit"
error TooManyLexerErrors "lexer has encountered too many errors (input is a binary file?)"
error UnclosedTranslateOff "translate_off pragma missing a closing counterpart"
warning unknown-escape-code UnknownEscapeCode "unknown character escape sequence '\\\\{}'"
warning nonstandard-escape-code NonstandardEscapeCode "non-standard character escape sequence '\\\\{}'"
warning invalid-source-encoding InvalidUTF8Seq "invalid UTF-8 sequence in source text"
Expand Down
99 changes: 99 additions & 0 deletions source/parsing/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,96 @@ void Lexer::scanWhitespace() {
addTrivia(TriviaKind::Whitespace);
}

bool detectTranslateOnOffPragma(std::string_view view, bool offMode) {
static std::vector<std::string_view> offCandidates = {
povik marked this conversation as resolved.
Show resolved Hide resolved
"pragma synthesis_off"sv, "pragma translate_off"sv, "synopsys synthesis_off"sv,
"synopsys translate_off"sv, "synthesis translate_off"sv, "xilinx translate_off"sv};

static std::vector<std::string_view> onCandidates = {
"pragma synthesis_on"sv, "pragma translate_on"sv, "synopsys synthesis_on"sv,
"synopsys translate_on"sv, "synthesis translate_on"sv, "xilinx translate_on"sv};

if (view.length() < 2)
return false;
const char *p = view.data() + 2, *end = view.data() + view.size();

auto skipWs = [&] {
bool seen = false;
while (p != end && isWhitespace(*p)) {
seen = true;
p++;
}
return seen;
};

int cpos = 0;
auto clower = offMode ? offCandidates.begin() : onCandidates.begin();
auto cupper = offMode ? offCandidates.end() : onCandidates.end();

skipWs();
while (p != end) {
if ((*clower)[cpos] == ' ') {
if (!skipWs())
return false;

cpos++;
}
else {
while (clower < cupper && (*clower)[cpos] < *p)
clower++;
while (cupper > clower && (*(cupper - 1))[cpos] > *p)
cupper--;

if (clower == cupper)
return false;

cpos++;
p++;
}

if (cpos == (int)clower->length()) {
// We have a complete match, check the comment line
// ends there or the match is followed by a whitespace
if (p == end || isWhitespace(*p))
return true;
return false;
}
}

return false;
}

void Lexer::scanTranslateOffSection() {
while (true) {
const char* commentStart = sourceBuffer;

switch (peek()) {
case '\0':
if (reallyAtEnd()) {
addDiag(diag::UnclosedTranslateOff, currentOffset() - lexemeLength());
return;
}
break;
case '/':
advance();
if (peek() == '/') {
advance();
while (!isNewline(peek()) && !reallyAtEnd())
advance();

std::string_view commentText = std::string_view(commentStart,
sourceBuffer - commentStart);
if (detectTranslateOnOffPragma(commentText, false))
return;
}
continue;
default:
break;
}
advance();
}
}

void Lexer::scanLineComment() {
if (options.enableLegacyProtect) {
// See if we're looking at a pragma protect comment and skip
Expand Down Expand Up @@ -1242,6 +1332,15 @@ void Lexer::scanLineComment() {
sawUTF8Error |= !scanUTF8Char(sawUTF8Error);
}
}

if (options.enableTranslateOnOffCompat) {
if (detectTranslateOnOffPragma(lexeme(), true)) {
scanTranslateOffSection();
addTrivia(TriviaKind::DisabledText);
return;
}
}

addTrivia(TriviaKind::LineComment);
}

Expand Down
Loading