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

[VeriblePreProcessor][4]: Handling file inclusion in "VerilogPreprocess" class. #1375

Closed
10 changes: 10 additions & 0 deletions common/util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ cc_library(
deps = ["@com_google_absl//absl/base:core_headers"],
)

cc_library(
name = "cmd_positional_arguments",
srcs = ["cmd_positional_arguments.cc"],
hdrs = ["cmd_positional_arguments.h"],
deps = [
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
],
)

cc_library(
name = "subcommand",
srcs = ["subcommand.cc"],
Expand Down
128 changes: 128 additions & 0 deletions common/util/cmd_positional_arguments.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// 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 "common/util/cmd_positional_arguments.h"

#include <string>
#include <vector>

#include "absl/status/status.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"

namespace verible {

// Sets a file argument.
absl::Status CmdPositionalArguments::SetFile(absl::string_view file) {
files_.push_back(file);
return absl::OkStatus();
}

// Sets a define arguments.
absl::Status CmdPositionalArguments::SetDefine(
std::pair<absl::string_view, absl::string_view> define) {
defines_.push_back(define);
return absl::OkStatus();
}

// Sets a include directory argument.
absl::Status CmdPositionalArguments::SetIncludeDir(
absl::string_view include_dir) {
include_dirs_.push_back(include_dir);
return absl::OkStatus();
}

// Gets include directories arguments.
std::vector<absl::string_view> CmdPositionalArguments::GetIncludeDirs() {
return include_dirs_;
}

std::vector<std::pair<absl::string_view, absl::string_view>>

// Gets macro defines arguments.
CmdPositionalArguments::GetDefines() {
return defines_;
}

// Gets SV files arguments.
std::vector<absl::string_view> CmdPositionalArguments::GetFiles() {
return files_;
}

// Main function that parses arguments and add them to the correct data memeber.
absl::Status CmdPositionalArguments::ParseArgs() {
// Positional arguments types:
// 1) <file>
// 2) +define+<foo>[=<value>]
// 3) +incdir+<dir>

int argument_index = 0;
for (absl::string_view argument : all_args_) {
if (!argument_index) {
argument_index++;
continue;
} // all_args_[0] is the tool's name, which can be skipped.
if (argument[0] != '+') { // the argument is a SV file name.
if (auto status = SetFile(argument); !status.ok())
return status; // add it to the file arguments.
} else { // it should be either a define or incdir.
std::vector<absl::string_view> argument_plus_splitted =
absl::StrSplit(argument, absl::ByChar('+'), absl::SkipEmpty());
if (argument_plus_splitted.size() < 2) {
// Unknown argument.
return absl::InvalidArgumentError("Unkown argument.");
}
absl::string_view plus_argument_type = argument_plus_splitted[0];
if (absl::StrContains(plus_argument_type, "define")) {
// define argument.
int define_argument_index = 0;
for (absl::string_view define_argument : argument_plus_splitted) {
if (!define_argument_index) {
define_argument_index++;
continue;
}
// define_argument is something like <macro1>=<value>.
std::pair<absl::string_view, absl::string_view> macro_pair =
absl::StrSplit(
define_argument, absl::ByChar('='),
absl::SkipEmpty()); // parse the macro name and value.
if (auto status = CmdPositionalArguments::SetDefine(macro_pair);
!status.ok())
return status; // add the define argument.
define_argument_index++;
}
} else if (absl::StrContains(plus_argument_type, "incdir")) {
// incdir argument.
int incdir_argument_index = 0;
for (absl::string_view incdir_argument : argument_plus_splitted) {
if (!incdir_argument_index) {
incdir_argument_index++;
continue;
}
if (auto status =
CmdPositionalArguments::SetIncludeDir(incdir_argument);
!status.ok())
return status; // add file argument.
incdir_argument_index++;
}
} else {
return absl::InvalidArgumentError("Unkown argument.");
}
}
argument_index++;
}
return absl::OkStatus();
}

} // namespace verible
67 changes: 67 additions & 0 deletions common/util/cmd_positional_arguments.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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.

#ifndef VERIBLE_COMMON_UTIL_CMD_POSITIONAL_ARGUMENTS_H_
#define VERIBLE_COMMON_UTIL_CMD_POSITIONAL_ARGUMENTS_H_

#include <string>
#include <vector>

#include "absl/status/status.h"
#include "absl/strings/string_view.h"

namespace verible {

class CmdPositionalArguments {
public:
explicit CmdPositionalArguments(const std::vector<char *> &args)
: all_args_(args){};

// Main function that parses arguments.
absl::Status ParseArgs();

// Gets include directories arguments.
std::vector<absl::string_view> GetIncludeDirs();

// Gets macro defines arguments.
std::vector<std::pair<absl::string_view, absl::string_view>> GetDefines();

// Gets SV files arguments.
std::vector<absl::string_view> GetFiles();

private:
// Sets a include directory argument.
absl::Status SetIncludeDir(absl::string_view include_dir);

// Sets a define arguments.
absl::Status SetDefine(
std::pair<absl::string_view, absl::string_view> define);

// Sets a file argument.
absl::Status SetFile(absl::string_view file);

std::vector<char *>
all_args_; // contains all arguments (tool's name is included).
std::vector<absl::string_view>
include_dirs_; // contains all arugments that follows +incdir+<dir>.
std::vector<absl::string_view>
files_; // contains all SV files passed to the tool.
std::vector<std::pair<absl::string_view, absl::string_view>>
defines_; // contains all arguments that follow +define+<name>[=<value>]
// as a pair<name,value>.
}; // class CmdPositionalArguments

} // namespace verible

#endif // VERIBLE_COMMON_UTIL_CMD_POSITIONAL_ARGUMENTS_H_
12 changes: 12 additions & 0 deletions verilog/analysis/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ cc_library(
],
)

cc_library(
name = "flow_tree",
srcs = ["flow_tree.cc"],
hdrs = ["flow_tree.h"],
deps = [
"//common/lexer:token_stream_adapter",
"//verilog/parser:verilog_token_enum",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/status",
],
)

cc_library(
name = "lint_rule_registry",
srcs = ["lint_rule_registry.cc"],
Expand Down
147 changes: 147 additions & 0 deletions verilog/analysis/flow_tree.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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 wedge_from_iteratorh 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 wredge_from_iteratoring,
// software distributed under the License is distributed on an "AS IS" BASIS,
// Wedge_from_iteratorHOUT WARRANTIES OR CONDedge_from_iteratorIONS OF ANY KIND,
// eedge_from_iteratorher express or implied. See the License for the specific
// language governing permissions and limedge_from_iteratorations under the
// License.

#include "verilog/analysis/flow_tree.h"

#include <map>
#include <string>
#include <vector>

#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "common/lexer/token_stream_adapter.h"
#include "verilog/parser/verilog_token_enum.h"

namespace verilog {

// Constructs the control flow tree, which determines the edge from each node
// (token index) to the next possible childs, And save edge_from_iterator in
// edges_.
absl::Status FlowTree::GenerateControlFlowTree() {
// Adding edges for if blocks.
int token_index = 0;
int current_token_enum = 0;
for (auto current_token : source_sequence_) {
current_token_enum = current_token.token_enum();

if (current_token_enum == PP_ifdef || current_token_enum == PP_ifndef) {
ifs_.push_back(token_index); // add index of `ifdef and `ifndef to ifs_.
elses_[ifs_.back()].push_back(
token_index); // also add edge_from_iterator to elses_ as if will
// help marking edges later on.

} else if (current_token_enum == PP_else ||
current_token_enum == PP_elsif ||
current_token_enum == PP_endif) {
elses_[ifs_.back()].push_back(
token_index); // add index of `elsif, `else and `endif to else_ of
// the last recent if block.
if (current_token_enum ==
PP_endif) { // if the current token is an `endif, then we are ready
// to create edges for this if block.
auto& current_if_block =
elses_[ifs_.back()]; // current_if_block contains all indexes of
// ifs and elses in the latest block.

// Adding edges for each index in the if block using a nested loop.
for (auto edge_from_iterator = current_if_block.begin();
edge_from_iterator != current_if_block.end();
edge_from_iterator++) {
for (auto edge_to_iterator = edge_from_iterator + 1;
edge_to_iterator != current_if_block.end(); edge_to_iterator++) {
if (edge_from_iterator == current_if_block.begin() &&
edge_to_iterator == current_if_block.end() - 1 &&
current_if_block.size() > 2)
continue; // skip edges from `if to `endif if there is an else in
// this bloc wheneven there is an else in this block.
edges_[*edge_from_iterator].push_back(
*edge_to_iterator +
(edge_to_iterator !=
current_if_block.end() - 1)); // add the possible edge.
}
}
ifs_.pop_back(); // the if block edges were added, ready to pop it.
}
}
token_index++; // increment the token index.
}

// Adding edges for non-if blocks.
token_index = 0;
for (auto current_token : source_sequence_) {
current_token_enum = current_token.token_enum();
if (current_token_enum != PP_else && current_token_enum != PP_elsif) {
if (token_index > 0)
edges_[token_index - 1].push_back(
token_index); // edges from a token to the one coming after it
// directly.
} else {
if (token_index > 0)
edges_[token_index - 1].push_back(
edges_[token_index]
.back()); // edges from the last token in `ifdef/`ifndef body
// to `endif from the same if block.
}
token_index++; // increment the token index.
}

return absl::OkStatus();
}

// Traveses the control flow tree in a depth first manner, appending the visited
// tokens to current_sequence_, then adding current_sequence_ to variants_ upon
// completing.
absl::Status FlowTree::DepthFirstSearch(int current_node_index) {
// skips preprocessor directives so that current_sequence_ doesn't contain
// any.
const auto& current_token = source_sequence_[current_node_index];
if (current_token.token_enum() != PP_Identifier &&
current_token.token_enum() != PP_ifndef &&
current_token.token_enum() != PP_ifdef &&
current_token.token_enum() != PP_define &&
current_token.token_enum() != PP_define_body &&
current_token.token_enum() != PP_elsif &&
current_token.token_enum() != PP_else &&
current_token.token_enum() != PP_endif)
current_sequence_.push_back(current_token);

// do recursive search through every possible edge.
for (auto next_node : edges_[current_node_index]) {
if (auto status = FlowTree::DepthFirstSearch(next_node); !status.ok()) {
std::cerr << "ERROR: DepthFirstSearch fails\n";
return status;
}
}
if (current_node_index ==
int(source_sequence_.size()) -
1) { // if the current node is the last one, push the completed
// current_sequence_ to variants_.
variants_.push_back(current_sequence_);
}
if (current_token.token_enum() != PP_Identifier &&
current_token.token_enum() != PP_ifndef &&
current_token.token_enum() != PP_ifdef &&
current_token.token_enum() != PP_define &&
current_token.token_enum() != PP_define_body &&
current_token.token_enum() != PP_elsif &&
current_token.token_enum() != PP_else &&
current_token.token_enum() != PP_endif)
current_sequence_
.pop_back(); // remove tokens to back track into other variants.
return absl::OkStatus();
}

} // namespace verilog
Loading