Skip to content

Commit

Permalink
fdt: working on more type driven parser/tokenizer
Browse files Browse the repository at this point in the history
Signed-off-by: Bartłomiej Burdukiewicz <[email protected]>
  • Loading branch information
dev-0x7C6 committed Jun 28, 2024
1 parent 2219b33 commit be9a3ee
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 21 deletions.
26 changes: 5 additions & 21 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,12 @@ configure_file(config.h.in config.h)

add_subdirectory("submodules/qhexview")

file(GLOB_RECURSE fdt-viewer-headers *.hpp)
file(GLOB_RECURSE fdt-viewer-sources *.cpp)

add_executable(fdt-viewer
dialogs.cpp
dialogs.hpp
endian-conversions.hpp
fdt/fdt-generator-qt.cpp
fdt/fdt-generator-qt.hpp
fdt/fdt-generator.hpp
fdt/fdt-header.hpp
fdt/fdt-parser.cpp
fdt/fdt-parser.hpp
fdt/fdt-property-types.hpp
fdt/fdt-view.cpp
fdt/fdt-view.hpp
main-window.cpp
main-window.hpp
main-window.ui
main.cpp
menu-manager.cpp
menu-manager.hpp
types.hpp
viewer-settings.cpp
viewer-settings.hpp
${fdt-viewer-headers}
${fdt-viewer-sources}
../resources.qrc
)

Expand Down
47 changes: 47 additions & 0 deletions src/fdt/fdt-parser-v2.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <type_traits>
#include <variant>
#include <string_view>
#include <vector>
#include <cstdint>

using u32 = std::uint32_t;

namespace fdt::tokenizer {

namespace types {
struct node_begin {
std::string_view name;
};
struct node_end {};
struct property {
std::string_view name;
std::string_view data;
};
struct nop {};
struct end {};

constexpr auto id_of(node_begin) -> u32 { return 0x01; };
constexpr auto id_of(node_end) -> u32 { return 0x02; };
constexpr auto id_of(property) -> u32 { return 0x03; };
constexpr auto id_of(nop) -> u32 { return 0x04; };
constexpr auto id_of(end) -> u32 { return 0x09; };

} // namespace types

using token = std::variant<types::node_begin, types::node_end, types::property, types::nop, types::end>;
using token_list = std::vector<token>;

struct context {
std::string_view structs;
std::string_view strings;
token_list tokens;
};

template <typename T>
concept Tokenizable = requires(T t) {
{ fdt::tokenizer::types::id_of(t) } -> std::convertible_to<u32>;
};

} // namespace fdt::tokenizer
118 changes: 118 additions & 0 deletions src/fdt/fdt-parser.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include "fdt-parser.hpp"
#include <ostream>
#include <string_view>
#include <variant>

#include <cstring>
#include <concepts>
#include <algorithm>
#include <endian-conversions.hpp>

fdt_parser::fdt_parser(const char *data, u64 size, iface_fdt_generator &generator, const QString &default_root_node, const std::vector<fdt_handle_special_property> &handle_special_properties)
Expand All @@ -24,6 +29,7 @@ fdt_parser::fdt_parser(const char *data, u64 size, iface_fdt_generator &generato
}
}

/*
void fdt_parser::parse(const fdt::header header, iface_fdt_generator &generator) {
const auto dt_struct = m_data + header.off_dt_struct;
const auto dt_strings = m_data + header.off_dt_strings;
Expand Down Expand Up @@ -75,3 +81,115 @@ void fdt_parser::parse(const fdt::header header, iface_fdt_generator &generator)
break;
}
}
*/

#include "fdt-parser-v2.hpp"
#include <iostream>
#include <algorithm>

auto align(const std::size_t size) {
const auto q = size % sizeof(u32);
const auto w = size / sizeof(u32);
return std::max<u32>(1u, w + (q ? 1u : 0u));
};

namespace fdt::parser {

using namespace fdt::tokenizer;
using namespace fdt::tokenizer::types;

auto parse(node_begin &&token, const char *data, int &skip, context &ctx) -> fdt::tokenizer::token {
const auto size = std::strlen(data);
token.name = std::string_view(data, size);
skip += align(size);
return {std::move(token)};
}

auto parse(node_end &&token, const char *data, int &skip, context &ctx) -> fdt::tokenizer::token {
return {std::move(token)};
}

auto parse(types::property &&token, const char *data, int &skip, context &ctx) -> fdt::tokenizer::token {
const auto header = read_data_32be<fdt::property>(data);
skip += align(sizeof(header)) + align(header.len);
data += sizeof(header);

token.name = std::string_view();
token.data = std::string_view(data, header.len);

return {std::move(token)};
}

auto parse(nop &&token, const char *data, int &skip, context &ctx) -> fdt::tokenizer::token {
return {std::move(token)};
}

auto parse(end &&token, const char *data, int &skip, context &ctx) -> fdt::tokenizer::token {
return {std::move(token)};
}
} // namespace fdt::parser

template <fdt::tokenizer::Tokenizable... Ts>
auto foreach_token_type(std::variant<Ts...>, const u32 token_id, const char *data, int &skip, fdt::tokenizer::context &ctx) {
auto conditional_parse = [&](auto &&token) {
if (fdt::tokenizer::types::id_of(token) == token_id) {
ctx.tokens.emplace_back(fdt::parser::parse(std::move(token), data, skip, ctx));
return true;
}
return false;
};
return (conditional_parse(Ts{}) || ...);
}

void fdt_parser::parse(const fdt::header header, iface_fdt_generator &generator) {
const auto dt_struct = m_data + header.off_dt_struct;
const auto dt_strings = m_data + header.off_dt_strings;

auto get_property_name = [&](auto offset) {
const auto ptr = dt_strings + offset;
return QString::fromUtf8(ptr, std::strlen(ptr));
};

using namespace fdt::tokenizer;
using namespace fdt::tokenizer::types;
context ctx;

auto begin = reinterpret_cast<const u32 *>(dt_struct);
auto end = reinterpret_cast<const u32 *>(dt_struct) + header.size_dt_struct / sizeof(u32);

for (auto iter = begin; iter != end;) {
const auto id = static_cast<u32>(convert(*iter));
iter++;
std::cout << id << std::endl;

auto skip = 0;
foreach_token_type(token{}, id, reinterpret_cast<const char *>(iter), skip, ctx);
iter += skip;
}

const auto node_begin_count = std::ranges::count_if(ctx.tokens, [](auto &&v) {
return std::holds_alternative<node_begin>(v);
});

const auto node_end_count = std::ranges::count_if(ctx.tokens, [](auto &&v) {
return std::holds_alternative<node_end>(v);
});

const auto property_count = std::ranges::count_if(ctx.tokens, [](auto &&v) {
return std::holds_alternative<property>(v);
});

const auto nop_count = std::ranges::count_if(ctx.tokens, [](auto &&v) {
return std::holds_alternative<nop>(v);
});

const auto end_count = std::ranges::count_if(ctx.tokens, [](auto &&v) {
return std::holds_alternative<types::end>(v);
});

std::cout << "node begin count: " << node_begin_count << std::endl;
std::cout << "node end count: " << node_end_count << std::endl;
std::cout << "property count: " << property_count << std::endl;
std::cout << "nop count: " << nop_count << std::endl;
std::cout << "end count: " << end_count << std::endl;
}

0 comments on commit be9a3ee

Please sign in to comment.