Closes
This commit is contained in:
1 parent
65142fdfe3
commit
e5d818d9b2
14 files changed
+393
-39
No files matched your search
@@ -309,6 +309,7 @@ DbcStatementDispatcher::DbcStatementDispatcher() {
|
||||
RegisterType<DbcFrameHandler>("BO_");
|
||||
RegisterType<DbcSignalHandler>("SG_");
|
||||
RegisterType<DbcCommentHandler>("CM_");
|
||||
RegisterType<DbcValueDescriptionHandler>("VAL_");
|
||||
}
|
||||
|
||||
bool DbcStatementDispatcher::Dispatch(const std::string &line,
|
||||
@@ -322,3 +323,88 @@ bool DbcStatementDispatcher::Dispatch(const std::string &line,
|
||||
handler->second->Handle(line, context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DbcValueDescriptionHandler::Handle(const std::string &line, DbcParseContext &context) const {
|
||||
static const std::regex header(R"(^VAL_[ \t]+([^ \t]+)[ \t]+([^ \t;]+)[ \t]+(.*)$)");
|
||||
static const std::regex pair(R"dbc(^([^ \t]+)[ \t]+"((?:[^"\\]|\\["\\])*)")dbc");
|
||||
std::smatch fields;
|
||||
if (!std::regex_match(line, fields, header))
|
||||
throw std::runtime_error("Malformed or unsupported VAL_ statement.");
|
||||
const auto rawId = ParseDecimal(fields[1].str(), std::numeric_limits<std::uint32_t>::max(), "VAL_ CAN ID");
|
||||
if ((rawId & 0x60000000U) != 0U)
|
||||
throw std::runtime_error("VAL_ CAN ID exceeds the 29-bit identifier range.");
|
||||
PendingValueDescriptions pending;
|
||||
NormalizeCanId(rawId, pending.canId, pending.isExtended);
|
||||
pending.signalName = fields[2].str();
|
||||
pending.lineNumber = context.lineNumber;
|
||||
std::string rest = fields[3].str();
|
||||
while (rest != ";") {
|
||||
if (!std::regex_search(rest, fields, pair))
|
||||
throw std::runtime_error("Malformed VAL_ value/description pair or missing semicolon.");
|
||||
const std::string number = fields[1].str();
|
||||
RawSignalValue key;
|
||||
if (!number.empty() && number[0] == '-') {
|
||||
std::int64_t value = 0;
|
||||
const auto parsed = std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = NormalizeValueKey(RawSignalValue(value));
|
||||
} else {
|
||||
std::uint64_t value = 0;
|
||||
const auto parsed = std::from_chars(number.data(), number.data() + number.size(), value);
|
||||
if (number.empty() || parsed.ec != std::errc() || parsed.ptr != number.data() + number.size())
|
||||
throw std::runtime_error("Invalid VAL_ integer: " + number);
|
||||
key = value;
|
||||
}
|
||||
std::string description;
|
||||
const std::string quoted = fields[2].str();
|
||||
for (std::size_t i = 0; i < quoted.size(); ++i) {
|
||||
if (quoted[i] == '\\')
|
||||
++i;
|
||||
description += quoted[i];
|
||||
}
|
||||
if (!pending.descriptions.emplace(key, description).second)
|
||||
throw std::runtime_error("Duplicate VAL_ value key: " + number);
|
||||
const auto consumed = static_cast<std::size_t>(fields.length());
|
||||
rest.erase(0, consumed);
|
||||
if (!rest.empty() && rest[0] != ';' && rest[0] != ' ' && rest[0] != '\t')
|
||||
throw std::runtime_error("Missing whitespace between VAL_ pairs.");
|
||||
rest = TrimText(rest);
|
||||
}
|
||||
if (pending.descriptions.empty())
|
||||
throw std::runtime_error("VAL_ requires at least one value/description pair.");
|
||||
context.pendingValues.push_back(std::move(pending));
|
||||
}
|
||||
|
||||
void DbcParseContext::ResolveValueDescriptions(const std::string &filePath) {
|
||||
for (const auto &pending: pendingValues) {
|
||||
try {
|
||||
FrameInfo *frame = nullptr;
|
||||
for (auto &candidate: database.frames) {
|
||||
if (candidate.canId == pending.canId && candidate.isExtended == pending.isExtended) {
|
||||
if (frame)
|
||||
throw std::runtime_error("Ambiguous VAL_ frame reference.");
|
||||
frame = &candidate;
|
||||
}
|
||||
}
|
||||
if (!frame)
|
||||
throw std::runtime_error("Unresolved VAL_ frame reference.");
|
||||
SignalInfo *signal = nullptr;
|
||||
for (auto &candidate: frame->signals) {
|
||||
if (candidate.name == pending.signalName) {
|
||||
if (signal)
|
||||
throw std::runtime_error("Ambiguous VAL_ signal reference: " + pending.signalName);
|
||||
signal = &candidate;
|
||||
}
|
||||
}
|
||||
if (!signal)
|
||||
throw std::runtime_error("Unresolved VAL_ signal reference: " + pending.signalName);
|
||||
for (const auto &entry: pending.descriptions) {
|
||||
if (!signal->valueDescriptions.insert(entry).second)
|
||||
throw std::runtime_error("Duplicate VAL_ value key for signal: " + pending.signalName);
|
||||
}
|
||||
} catch (const std::exception &error) {
|
||||
throw std::runtime_error(filePath + ":" + std::to_string(pending.lineNumber) + ": " + error.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user