blob: 474ca58646c1f8eae9d4a370ea1f7493e95f2ff7 [file] [log] [blame]
#include <sstream>
#include "read_xml_util.h"
#include "vtr_util.h"
#include "arch_error.h"
using namespace pugiutil;
/* Convert bool to ReqOpt enum */
extern ReqOpt BoolToReqOpt(bool b) {
if (b) {
return REQUIRED;
}
return OPTIONAL;
}
InstPort::InstPort(std::string str) {
std::vector<std::string> inst_port = vtr::split(str, ".");
if(inst_port.size() == 1) {
instance_ = {"", -1, -1};
port_ = parse_name_index(inst_port[0]);
} else if(inst_port.size() == 2) {
instance_ = parse_name_index(inst_port[0]);
port_ = parse_name_index(inst_port[1]);
} else {
throw ArchFpgaError("Failed to parse instance port specification '%s'");
}
}
InstPort::InstPort(std::string str, pugi::xml_node node, const pugiutil::loc_data& loc_data) {
try {
*this = InstPort(str);
} catch (const ArchFpgaError& e) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(node),
"Failed to parse instance port specification '%s' for"
" on <%s> tag, %s",
str.c_str(), node.name(), e.what());
}
}
InstPort::InstPort(pugi::xml_attribute attr, pugi::xml_node node, const pugiutil::loc_data& loc_data) {
try {
*this = InstPort(attr.value());
} catch (const ArchFpgaError& e) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(node),
"Failed to parse instance port specification '%s' for"
" attribute '%s' on <%s> tag, %s",
attr.value(), attr.name(), node.name(), e.what());
}
}
InstPort::name_index InstPort::parse_name_index(std::string str) {
auto open_bracket_pos = str.find("[");
auto close_bracket_pos = str.find("]");
auto colon_pos = str.find(":");
//Parse checks
if(open_bracket_pos == std::string::npos && close_bracket_pos != std::string::npos) {
//Close brace only
std::string msg = "near '" + str + "', missing '['";
throw ArchFpgaError(msg);
}
if(open_bracket_pos != std::string::npos && close_bracket_pos == std::string::npos) {
//Open brace only
std::string msg = "near '" + str + "', missing ']'";
throw ArchFpgaError(msg);
}
if(open_bracket_pos != std::string::npos && close_bracket_pos != std::string::npos) {
//Have open and close braces, close must be after open
if(open_bracket_pos > close_bracket_pos) {
std::string msg = "near '" + str + "', '[' after ']'";
throw ArchFpgaError(msg);
}
}
if(colon_pos != std::string::npos) {
//Have a colon, it must be between open/close braces
if(colon_pos > close_bracket_pos || colon_pos < open_bracket_pos) {
std::string msg = "near '" + str + "', found ':' but not between '[' and ']'";
throw ArchFpgaError(msg);
}
}
//Extract the name and index info
std::string name = str.substr(0,open_bracket_pos);
std::string first_idx_str;
std::string second_idx_str;
if(colon_pos == std::string::npos && open_bracket_pos == std::string::npos && close_bracket_pos == std::string::npos) {
} else if(colon_pos == std::string::npos) {
//No colon, implies a single element
first_idx_str = str.substr(open_bracket_pos + 1, close_bracket_pos);
second_idx_str = first_idx_str;
} else {
//Colon, implies a range
first_idx_str = str.substr(open_bracket_pos + 1, colon_pos);
second_idx_str = str.substr(colon_pos + 1, close_bracket_pos);
}
int first_idx = UNSPECIFIED;
if(!first_idx_str.empty()) {
std::stringstream ss(first_idx_str);
size_t idx;
ss >> idx;
if(!ss.good()) {
std::string msg = "near '" + str + "', expected positive integer";
throw ArchFpgaError(msg);
}
first_idx = idx;
}
int second_idx = UNSPECIFIED;
if(!second_idx_str.empty()) {
std::stringstream ss(second_idx_str);
size_t idx;
ss >> idx;
if(!ss.good()) {
std::string msg = "near '" + str + "', expected positive integer";
throw ArchFpgaError(msg);
}
second_idx = idx;
}
return {name, std::min(first_idx, second_idx), std::max(first_idx, second_idx)};
}
void archfpga_throw(const char* filename, int line, const char* fmt, ...) {
va_list va_args;
va_start(va_args, fmt);
auto msg = vtr::vstring_fmt(fmt, va_args);
va_end(va_args);
throw ArchFpgaError(msg, filename, line);
}
void bad_tag(const pugi::xml_node node,
const pugiutil::loc_data& loc_data,
const pugi::xml_node parent_node,
const std::vector<std::string> expected_tags) {
std::string msg = "Unexpected tag ";
msg += "<";
msg += node.name();
msg += ">";
if(parent_node) {
msg += " in section <";
msg += parent_node.name();
msg += ">";
}
if(!expected_tags.empty()) {
msg += ", expected ";
for(auto iter = expected_tags.begin(); iter != expected_tags.end(); ++iter) {
msg += "<";
msg += *iter;
msg += ">";
if(iter < expected_tags.end() - 2) {
msg += ", ";
} else if(iter == expected_tags.end() - 2) {
msg += " or ";
}
}
}
throw ArchFpgaError(msg, loc_data.filename(), loc_data.line(node));
}
void bad_attribute(const pugi::xml_attribute attr,
const pugi::xml_node node,
const pugiutil::loc_data& loc_data,
const std::vector<std::string> expected_attributes) {
std::string msg = "Unexpected attribute ";
msg += "'";
msg += attr.name();
msg += "'";
if(node) {
msg += " on <";
msg += node.name();
msg += "> tag";
}
if(!expected_attributes.empty()) {
msg += ", expected ";
for(auto iter = expected_attributes.begin(); iter != expected_attributes.end(); ++iter) {
msg += "'";
msg += *iter;
msg += "'";
if(iter < expected_attributes.end() - 2) {
msg += ", ";
} else if(iter == expected_attributes.end() - 2) {
msg += " or ";
}
}
}
throw ArchFpgaError(msg, loc_data.filename(), loc_data.line(node));
}
void bad_attribute_value(const pugi::xml_attribute attr,
const pugi::xml_node node,
const pugiutil::loc_data& loc_data,
const std::vector<std::string> expected_values) {
std::string msg = "Invalid value '";
msg += attr.value();
msg += "'";
msg += " for attribute '";
msg += attr.name();
msg += "'";
if(node) {
msg += " on <";
msg += node.name();
msg += "> tag";
}
if(!expected_values.empty()) {
msg += ", expected value ";
for(auto iter = expected_values.begin(); iter != expected_values.end(); ++iter) {
msg += "'";
msg += *iter;
msg += "'";
if(iter < expected_values.end() - 2) {
msg += ", ";
} else if(iter == expected_values.end() - 2) {
msg += " or ";
}
}
}
throw ArchFpgaError(msg, loc_data.filename(), loc_data.line(node));
}