| // Copyright 2017-2020 The Verible Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "verilog/transform/strip_comments.h" |
| |
| #include <iostream> |
| #include <vector> |
| |
| #include "common/strings/comment_utils.h" |
| #include "common/strings/range.h" |
| #include "common/strings/split.h" |
| #include "common/text/token_info.h" |
| #include "common/util/iterator_range.h" |
| #include "common/util/spacer.h" |
| #include "verilog/parser/verilog_lexer.h" |
| #include "verilog/parser/verilog_parser.h" |
| #include "verilog/parser/verilog_token_enum.h" |
| |
| namespace verilog { |
| |
| using verible::make_string_view_range; |
| using verible::Spacer; |
| using verible::StripComment; |
| using verible::TokenInfo; |
| |
| // Replace non-newline characters with a single char, like <space>. |
| // Tabs are considered non-newline characters. |
| static void ReplaceNonNewlines(absl::string_view text, std::ostream* output, |
| char replacement) { |
| const std::vector<absl::string_view> lines(verible::SplitLines(text)); |
| if (lines.empty()) return; |
| // no newline before first element |
| *output << Spacer(lines.front().size(), replacement); |
| for (const auto& line : verible::make_range(lines.begin() + 1, lines.end())) { |
| *output << '\n' << Spacer(line.size(), replacement); |
| } |
| } |
| |
| void StripVerilogComments(absl::string_view content, std::ostream* output, |
| char replacement) { |
| VLOG(1) << __FUNCTION__; |
| verilog::VerilogLexer lexer(content); |
| |
| const TokenInfo::Context context(content, [](std::ostream& stream, int e) { |
| stream << verilog_symbol_name(e); |
| }); |
| |
| while (true) { |
| const verible::TokenInfo& token(lexer.DoNextToken()); |
| if (token.isEOF()) break; |
| |
| VLOG(2) << "token: " << verible::TokenWithContext{token, context}; |
| const absl::string_view text = token.text(); |
| switch (token.token_enum()) { |
| case verilog_tokentype::TK_EOL_COMMENT: |
| switch (replacement) { |
| case '\0': |
| // There is always a '\n' that follows, so there is no risk of |
| // accidentally fusing tokens by deleting these comments. |
| break; |
| case ' ': |
| // The lexer guarantees the text does not contain '\n'. |
| *output << Spacer(text.length()); |
| break; |
| default: { |
| // Retain the "//" but erase everything thereafter. |
| const absl::string_view body(StripComment(text)); |
| const absl::string_view head( |
| make_string_view_range(text.begin(), body.begin())); |
| *output << head << Spacer(body.length(), replacement); |
| break; |
| } |
| } |
| break; |
| |
| case verilog_tokentype::TK_COMMENT_BLOCK: |
| switch (replacement) { |
| case '\0': |
| // Print one space to prevent accidental token fusion in |
| // cases like: "a/**/b". |
| *output << ' '; |
| break; |
| case ' ': |
| // Preserve newlines, but replace everything else with space. |
| ReplaceNonNewlines(text, output, replacement); |
| break; |
| default: { |
| // Retain the "/*" and "*/" but erase everything in between. |
| const absl::string_view body(StripComment(text)); |
| const absl::string_view head( |
| make_string_view_range(text.begin(), body.begin())); |
| const absl::string_view tail( |
| make_string_view_range(body.end(), text.end())); |
| |
| *output << head; |
| ReplaceNonNewlines(body, output, replacement); |
| *output << tail; |
| break; |
| } |
| } |
| break; |
| // The following tokens are un-lexed, so they need to be lexed |
| // recursively. |
| case verilog_tokentype::MacroArg: |
| case verilog_tokentype::PP_define_body: |
| StripVerilogComments(text, output, replacement); |
| break; |
| default: |
| // Preserve all other text, including lexical error tokens. |
| *output << text; |
| } // switch |
| } |
| VLOG(1) << "end of " << __FUNCTION__; |
| } |
| |
| } // namespace verilog |