Files
dbc/core/dbc_parser.cpp
T
2026-10-11 06:19:42 -04:00

111 lines
4.0 KiB
C++

/**
* @file dbc_parser.cpp
* @brief
*
* Created: 2026-03-13
* Author: Deeaitch (Dim. Himro)
*
* Licensed under the MIT License.
* See LICENSE file in the project root for full license text.
*/
#include "dbc_parser.h"
#include "dbc_statement_handler.h"
#include "text_utils.h"
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <utility>
namespace {
DbcDiagnosticCode StatementErrorCode(const std::string &keyword) {
if (keyword == "SG_MUL_VAL_")
return DbcDiagnosticCode::UnsupportedStatement;
if (keyword == "VAL_")
return DbcDiagnosticCode::InvalidValueDescription;
return DbcDiagnosticCode::InvalidStatement;
}
}
DbcDatabase DbcParser::ParseFile(const std::string &filePath) const {
DbcParseResult result = ParseFileWithDiagnostics(filePath);
for (const DbcDiagnostic &diagnostic : result.diagnostics) {
if (diagnostic.severity == DbcDiagnosticSeverity::Error) {
if (diagnostic.lineNumber == 0U)
throw std::runtime_error(diagnostic.message);
throw std::runtime_error(diagnostic.filePath + ":" +
std::to_string(diagnostic.lineNumber) + ": " + diagnostic.message);
}
}
return std::move(result.database);
}
DbcParseResult DbcParser::ParseFileWithDiagnostics(const std::string &filePath) const {
DbcParseResult result;
std::ifstream input(filePath.c_str());
if (!input.is_open()) {
result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
DbcDiagnosticCode::FileOpenError, filePath, 0U,
"Failed to open DBC file: " + filePath});
return result;
}
DbcDatabase database;
DbcParseContext context{database, nullptr};
const DbcStatementDispatcher dispatcher;
bool inNamespace = false;
std::size_t lineNumber = 0U;
std::string line;
while (std::getline(input, line)) {
++lineNumber;
line = dbc_detail::TrimText(line);
if (line.empty())
continue;
std::istringstream tokens(line);
std::string keyword;
std::string argument;
tokens >> keyword;
const bool hasArgument = static_cast<bool>(tokens >> argument);
if (inNamespace && !hasArgument && keyword != "BO_" && keyword != "SG_" &&
keyword != "BS_" && keyword != "BS_:" &&
keyword != "BU_" && keyword != "BU_:")
continue; // NS_ lists syntax symbols; BO_, SG_, BS_ and BU_ end the list.
inNamespace = keyword == "NS_" || keyword == "NS_:";
try {
context.lineNumber = lineNumber;
if (!dispatcher.Dispatch(line, context)) {
result.diagnostics.push_back({DbcDiagnosticSeverity::Warning,
DbcDiagnosticCode::UnsupportedStatement,
filePath, lineNumber,
"Unsupported statement '" + keyword +
"' is ignored; decoding or metadata may be incomplete."});
}
} catch (const std::exception &error) {
result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
StatementErrorCode(keyword), filePath,
lineNumber, error.what()});
return result;
}
}
if (input.bad() || !input.eof()) {
result.diagnostics.push_back({DbcDiagnosticSeverity::Error,
DbcDiagnosticCode::FileReadError, filePath, 0U,
"Failed to read DBC file: " + filePath});
return result;
}
try {
context.ResolveValueDescriptions(filePath);
context.ValidateMultiplexing(filePath);
} catch (const DbcDiagnosticError &error) {
result.diagnostics.push_back(error.diagnostic);
return result;
}
result.database = std::move(database);
return result;
}