152 lines
6.4 KiB
C++
152 lines
6.4 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#ifndef DBC_STATEMENT_HANDLER_H
|
|
#define DBC_STATEMENT_HANDLER_H
|
|
|
|
#include "dbc_database.h"
|
|
#include "dbc_diagnostic.h"
|
|
#include "typefactory.h"
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
/** @brief Deferred raw value descriptions and their target. */
|
|
struct PendingValueDescriptions {
|
|
std::uint32_t canId; /**< Normalized target frame identifier. */
|
|
bool isExtended; /**< Target frame type. */
|
|
std::string signalName; /**< Target signal name. */
|
|
ValueDescriptions descriptions; /**< Raw integer descriptions to merge. */
|
|
std::size_t lineNumber; /**< One-based physical statement line. */
|
|
};
|
|
|
|
/** @brief Deferred frame or signal comment and its source location. */
|
|
struct PendingComment {
|
|
std::uint32_t canId; /**< Normalized target frame identifier. */
|
|
bool isExtended; /**< Target frame type. */
|
|
bool isSignal; /**< Whether the target is a signal rather than a frame. */
|
|
std::string signalName; /**< Target signal name. */
|
|
std::string comment; /**< Unescaped comment text. */
|
|
std::size_t lineNumber; /**< One-based physical statement line. */
|
|
};
|
|
|
|
/** Carries deferred validation locations without parsing exception text. */
|
|
class DbcDiagnosticError : public std::runtime_error {
|
|
public:
|
|
/** @brief Create an exception with a structured source diagnostic. */
|
|
DbcDiagnosticError(DbcDiagnosticCode code, const std::string &filePath,
|
|
std::size_t lineNumber, const std::string &message)
|
|
: std::runtime_error(filePath + ":" + std::to_string(lineNumber) + ": " + message),
|
|
diagnostic{DbcDiagnosticSeverity::Error, code, filePath, lineNumber, message} {}
|
|
|
|
DbcDiagnostic diagnostic; /**< Structured error accompanying the exception message. */
|
|
};
|
|
|
|
/** @brief Attribute statement retained for ordered resolution. */
|
|
struct PendingAttribute {
|
|
std::string statement; /**< Complete attribute statement. */
|
|
std::size_t lineNumber; /**< One-based physical statement line. */
|
|
};
|
|
|
|
/** Mutable state belonging to one file parse. Handlers do not retain it. */
|
|
struct DbcParseContext {
|
|
DbcDatabase &database; /**< Parsed metadata under construction. */
|
|
FrameInfo *currentFrame = nullptr; /**< Current frame for following signal definitions. */
|
|
bool enableJ1939 = false; /**< Explicit interpretation option for extended frames. */
|
|
std::size_t lineNumber = 0U; /**< Physical line of the current statement. */
|
|
std::vector<PendingValueDescriptions> pendingValues = {}; /**< Unresolved raw value descriptions. */
|
|
|
|
std::vector<std::vector<std::size_t>> signalLines = {}; /**< Signal definition lines grouped by frame. */
|
|
/** @brief Validate selectors, branch ranges, and signal overlap. */
|
|
void ValidateMultiplexing(const std::string &filePath) const;
|
|
|
|
std::vector<PendingComment> pendingComments = {}; /**< Unresolved comments in source order. */
|
|
/** @brief Resolve deferred comments after all definitions are known. */
|
|
void ResolveComments(const std::string &filePath);
|
|
|
|
std::vector<PendingAttribute> pendingAttributes = {}; /**< Unresolved attributes in source order. */
|
|
/** @brief Resolve definitions, defaults, then assignments; append format warnings. */
|
|
void ResolveAttributes(const std::string &filePath, std::vector<DbcDiagnostic> &diagnostics);
|
|
|
|
/** @brief Resolve deferred raw descriptions against unique targets. */
|
|
void ResolveValueDescriptions(const std::string &filePath);
|
|
};
|
|
|
|
/** @brief Interface for processing a registered DBC statement. */
|
|
class DbcStatementHandler {
|
|
public:
|
|
virtual ~DbcStatementHandler() = default;
|
|
/** @brief Process a trimmed statement using state belonging to this parse. */
|
|
virtual void Handle(const std::string &line, DbcParseContext &context) const = 0;
|
|
};
|
|
|
|
/** @brief Parse and append frame definitions. */
|
|
class DbcFrameHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
|
|
private:
|
|
static FrameInfo ParseFrameLine(const std::string &line);
|
|
};
|
|
|
|
/** @brief Parse and append signals to the current frame. */
|
|
class DbcSignalHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
|
|
private:
|
|
static SignalInfo ParseSignalLine(const std::string &line);
|
|
};
|
|
|
|
/** @brief Defer frame and signal comments for target resolution. */
|
|
class DbcCommentHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
};
|
|
|
|
/** @brief Defer typed attribute statements for resolution. */
|
|
class DbcAttributeHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
};
|
|
|
|
/** @brief Defer raw value descriptions for target resolution. */
|
|
class DbcValueDescriptionHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
};
|
|
|
|
/** @brief Reject unsupported extended multiplexing statements. */
|
|
class DbcUnsupportedMultiplexingHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
};
|
|
|
|
/** Common header metadata does not change the supported decode definitions. */
|
|
class DbcHeaderHandler : public DbcStatementHandler {
|
|
public:
|
|
void Handle(const std::string &line, DbcParseContext &context) const override;
|
|
};
|
|
|
|
/** Exact-key dispatch to handlers created once per registration via TypeFactory. */
|
|
class DbcStatementDispatcher {
|
|
public:
|
|
/** @brief Register supported statement handlers through TypeFactory. */
|
|
DbcStatementDispatcher();
|
|
|
|
/** @brief Register or replace a handler and create its reusable instance. */
|
|
template<class Handler>
|
|
void RegisterType(const std::string &keyword) {
|
|
m_factory.registerType<Handler>(keyword);
|
|
m_handlers.insert_or_assign(keyword, m_factory.create(keyword));
|
|
}
|
|
|
|
/** Returns false for an unregistered keyword; input must be trimmed. */
|
|
bool Dispatch(const std::string &line, DbcParseContext &context) const;
|
|
|
|
private:
|
|
using HandlerMap = std::unordered_map<std::string, std::shared_ptr<DbcStatementHandler>>;
|
|
TypeFactory<std::string, DbcStatementHandler> m_factory;
|
|
HandlerMap m_handlers;
|
|
};
|
|
|
|
#endif /* DBC_STATEMENT_HANDLER_H */
|