This commit is contained in:
deeaitch committed 2026-10-06 17:04:13 -04:00
1 parent 65142fdfe3
commit e5d818d9b2
14 files changed
+393 -39

No files matched your search

+86
View File
@@ -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());
}
}
}