Skip to content
Open
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