This commit is contained in:
deeaitch committed 2026-10-23 20:48:21 -04:00
1 parent e44529007a
commit f60faea2e7
35 files changed
+2361 -2145

No files matched your search

+79 -48
View File
@@ -33,9 +33,8 @@ namespace {
}
double ParsePhysicalValue(const std::string &text, const char *field) {
static const std::regex number(
R"(^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$)");
if (!std::regex_match(text, number))
if (text.empty() || (text[0] == '+' &&
(text.size() == 1U || text[1] == '+' || text[1] == '-')))
throw std::runtime_error(std::string("Invalid ") + field + ": " + text);
// Floating-point from_chars is locale-independent and does not accept
// a leading '+', which the DBC numeric grammar permits.
@@ -53,6 +52,58 @@ namespace {
return value;
}
// Iterative scanning keeps stack use independent of the statement length.
class SignalTokens {
public:
SignalTokens(const std::string &text, std::size_t position) : text(text), position(position) {}
void SkipSpaces() {
while (position < text.size() && (text[position] == ' ' || text[position] == '\t'))
++position;
}
char Character() {
if (position == text.size())
throw std::runtime_error("Incomplete SG_ signal definition.");
return text[position++];
}
void Expect(char expected) {
SkipSpaces();
if (Character() != expected)
throw std::runtime_error("Malformed SG_ signal definition.");
}
std::string Until(char delimiter) {
const std::size_t end = text.find(delimiter, position);
if (end == std::string::npos)
throw std::runtime_error("Missing delimiter in SG_ signal definition.");
const std::string value = text.substr(position, end - position);
position = end + 1U;
return value;
}
std::vector<std::string> Receivers() {
if (position == text.size() || (text[position] != ' ' && text[position] != '\t'))
throw std::runtime_error("Missing receiver separator in SG_ signal definition.");
std::vector<std::string> receivers;
for (;;) {
const std::size_t end = text.find(',', position);
const std::string receiver = dbc_detail::TrimText(text.substr(position, end - position));
if (receiver.empty() || receiver.find_first_of(" \t\r\n") != std::string::npos)
throw std::runtime_error("Invalid SG_ receiver list.");
receivers.push_back(receiver);
if (end == std::string::npos)
return receivers;
position = end + 1U;
}
}
private:
const std::string &text;
std::size_t position = 0U;
};
Multiplexing ParseMultiplexingMarker(const std::string &marker) {
Multiplexing result;
if (marker == "M")
@@ -142,20 +193,6 @@ namespace {
} // namespace
namespace {
std::vector<std::string> SplitReceivers(const std::string &text) {
std::vector<std::string> receivers;
std::string token;
std::istringstream stream(text);
while (std::getline(stream, token, ',')) {
token = dbc_detail::TrimText(token);
if (!token.empty())
receivers.push_back(token);
}
return receivers;
}
void NormalizeCanId(std::uint32_t rawCanId, std::uint32_t &normalizedCanId, bool &isExtended) {
/*
* DBC commonly stores extended identifiers with bit 31 set.
@@ -206,28 +243,12 @@ FrameInfo DbcFrameHandler::ParseFrameLine(const std::string &line) {
}
SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
// Match the complete statement before converting any numeric fields.
enum Field {
NameAndMarker = 1, StartBit, BitLength, ByteOrder, Signedness,
Factor, Offset, Minimum, Maximum, Unit, Receivers
};
static const std::regex syntax(
// Name and optional multiplexing marker.
R"dbc(^SG_[ \t]+([^:]+):[ \t]*)dbc"
// Bit position, length, byte order and signedness.
R"dbc(([^| \t]+)[ \t]*\|[ \t]*([^@ \t]+)[ \t]*@[ \t]*([01])([+-])[ \t]*)dbc"
// Scaling factor and offset.
R"dbc(\([ \t]*([^, \t]+)[ \t]*,[ \t]*([^ )\t]+)[ \t]*\)[ \t]*)dbc"
// Physical range.
R"dbc(\[[ \t]*([^| \t]+)[ \t]*\|[ \t]*([^\] \t]+)[ \t]*\][ \t]*)dbc"
// Unit and receivers.
R"dbc("([^"\r\n]*)"[ \t]+([^ \t,]+(?:[ \t]*,[ \t]*[^ \t,]+)*)[ \t]*$)dbc");
std::smatch fields;
if (!std::regex_match(line, fields, syntax))
throw std::runtime_error("Malformed or unsupported SG_ signal definition.");
if (line.size() < 4U || line.compare(0U, 3U, "SG_") != 0 ||
(line[3] != ' ' && line[3] != '\t'))
throw std::runtime_error("Malformed SG_ signal definition.");
SignalTokens tokens(line, 3U);
SignalInfo signal;
std::istringstream nameFields(fields[NameAndMarker].str());
std::istringstream nameFields(tokens.Until(':'));
std::string marker;
std::string extra;
nameFields >> signal.name >> marker;
@@ -235,22 +256,32 @@ SignalInfo DbcSignalHandler::ParseSignalLine(const std::string &line) {
throw std::runtime_error("Invalid signal name or multiplexing marker.");
signal.multiplexing = ParseMultiplexingMarker(marker);
signal.startBit = ParseDecimal(fields[StartBit].str(),
signal.startBit = ParseDecimal(dbc_detail::TrimText(tokens.Until('|')),
std::numeric_limits<std::uint32_t>::max(), "signal start bit");
signal.length = ParseDecimal(fields[BitLength].str(), 64U, "signal length");
signal.length = ParseDecimal(dbc_detail::TrimText(tokens.Until('@')), 64U, "signal length");
if (signal.length == 0U)
throw std::runtime_error("Signal length must be within 1..64 bits.");
signal.isLittleEndian = fields[ByteOrder].str() == "1";
signal.isSigned = fields[Signedness].str() == "-";
tokens.SkipSpaces();
const char byteOrder = tokens.Character();
const char signedness = tokens.Character();
if ((byteOrder != '0' && byteOrder != '1') || (signedness != '+' && signedness != '-'))
throw std::runtime_error("Invalid SG_ byte order or signedness.");
signal.isLittleEndian = byteOrder == '1';
signal.isSigned = signedness == '-';
signal.factor = ParsePhysicalValue(fields[Factor].str(), "signal factor");
signal.offset = ParsePhysicalValue(fields[Offset].str(), "signal offset");
signal.minimum = ParsePhysicalValue(fields[Minimum].str(), "signal minimum");
signal.maximum = ParsePhysicalValue(fields[Maximum].str(), "signal maximum");
tokens.Expect('(');
signal.factor = ParsePhysicalValue(dbc_detail::TrimText(tokens.Until(',')), "signal factor");
signal.offset = ParsePhysicalValue(dbc_detail::TrimText(tokens.Until(')')), "signal offset");
tokens.Expect('[');
signal.minimum = ParsePhysicalValue(dbc_detail::TrimText(tokens.Until('|')), "signal minimum");
signal.maximum = ParsePhysicalValue(dbc_detail::TrimText(tokens.Until(']')), "signal maximum");
if (signal.minimum > signal.maximum)
throw std::runtime_error("Signal minimum exceeds maximum.");
signal.unit = fields[Unit].str();
signal.receivers = SplitReceivers(fields[Receivers].str());
tokens.Expect('"');
signal.unit = tokens.Until('"');
if (signal.unit.find_first_of("\r\n") != std::string::npos)
throw std::runtime_error("Invalid newline in SG_ unit.");
signal.receivers = tokens.Receivers();
return signal;
}