aoc24: day03a complete
This commit is contained in:
@@ -76,7 +76,7 @@ if (NOT MSVC)
|
|||||||
# fmt warnings
|
# fmt warnings
|
||||||
"-Wno-unknown-attributes"
|
"-Wno-unknown-attributes"
|
||||||
# ctre warning
|
# ctre warning
|
||||||
"-Wno-missing-template-arg-list-after-template-kw"
|
# "-Wno-missing-template-arg-list-after-template-kw"
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
set(BASE_OPTIONS
|
set(BASE_OPTIONS
|
||||||
@@ -115,4 +115,18 @@ target_link_libraries(aoc
|
|||||||
)
|
)
|
||||||
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
||||||
|
|
||||||
add_subdirectory(sol/24)
|
set(HEADERS "")
|
||||||
|
set(SOURCES sol/24/day03.cpp)
|
||||||
|
add_executable(app ${HEADERS} ${SOURCES})
|
||||||
|
target_include_directories(app PRIVATE ${PROJECT_SOURCE_DIR})
|
||||||
|
target_compile_features(app PRIVATE cxx_std_23)
|
||||||
|
target_compile_options(app PRIVATE ${BASE_OPTIONS})
|
||||||
|
target_compile_definitions(app PRIVATE ${BASE_DEFINITIONS})
|
||||||
|
target_link_libraries(app
|
||||||
|
PRIVATE
|
||||||
|
aoc
|
||||||
|
)
|
||||||
|
set_target_properties(app PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||||
|
)
|
||||||
|
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
set(HEADERS "")
|
|
||||||
set(SOURCES entry.cpp)
|
|
||||||
add_executable(sol2401 ${HEADERS} ${SOURCES})
|
|
||||||
target_include_directories(sol2401 PRIVATE ${PROJECT_SOURCE_DIR})
|
|
||||||
target_compile_features(sol2401 PRIVATE cxx_std_23)
|
|
||||||
target_compile_options(sol2401 PRIVATE ${BASE_OPTIONS})
|
|
||||||
target_compile_definitions(sol2401 PRIVATE ${BASE_DEFINITIONS})
|
|
||||||
target_link_libraries(sol2401
|
|
||||||
PRIVATE
|
|
||||||
aoc
|
|
||||||
)
|
|
||||||
set_target_properties(sol2401 PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
||||||
)
|
|
||||||
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#include "aoc/aoc.hpp"
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
// auto aoc::entry([[maybe_unused]]std::vector<std::string_view> const& args) -> void {
|
|
||||||
// constexpr auto filename = "./dat/24/re/01.txt";
|
|
||||||
// std::ifstream strm{filename, std::ios::in};
|
|
||||||
// if (!strm.is_open()) {
|
|
||||||
// fmt::print("Error opening file: {}\n", filename);
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// std::vector<std::uint32_t> a{};
|
|
||||||
// std::vector<std::uint32_t> b{};
|
|
||||||
//
|
|
||||||
// std::string str{};
|
|
||||||
// while (strm) {
|
|
||||||
// auto const c = char(strm.peek());
|
|
||||||
// if (std::isdigit(c)) {
|
|
||||||
// str += char(strm.get());
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (c == ' ') {
|
|
||||||
// if (!str.empty()) {
|
|
||||||
// a.emplace_back(std::stoi(str));
|
|
||||||
// str.clear();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (c == '\n') {
|
|
||||||
// if (!str.empty()) {
|
|
||||||
// b.emplace_back(std::stoi(str));
|
|
||||||
// str.clear();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// [[discard]]strm.get();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fmt::print("a: {}, b: {}\n", a.size(), b.size());
|
|
||||||
//
|
|
||||||
// std::sort(std::begin(a), std::end(a));
|
|
||||||
// std::sort(std::begin(b), std::end(b));
|
|
||||||
//
|
|
||||||
// auto diff_view = std::views::zip(a, b) | std::views::transform([](auto const& p) {
|
|
||||||
// auto const [x, y] = p;
|
|
||||||
// return x > y ? x - y : y - x;
|
|
||||||
// });
|
|
||||||
// auto const sum = std::accumulate(std::begin(diff_view), std::end(diff_view), 0);
|
|
||||||
//
|
|
||||||
// fmt::print("Part A: {}\n", std::abs(sum));
|
|
||||||
//
|
|
||||||
// auto values = a | std::views::transform([&b](auto v) {
|
|
||||||
// return std::pair{v, b | std::views::filter([v](auto c) {
|
|
||||||
// return v == c; // Filter elements in `b` equal to `v`
|
|
||||||
// }) | std::ranges::to<std::vector>()};
|
|
||||||
// }) | std::ranges::to<std::vector>();
|
|
||||||
//
|
|
||||||
// auto const meow = std::accumulate(std::begin(values), std::end(values), 0, [](auto const acc, auto const& pair) {
|
|
||||||
// return acc + std::int32_t(pair.first * pair.second.size());
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// fmt::print("Part B: {}\n", meow);
|
|
||||||
// }
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
set(HEADERS "")
|
|
||||||
set(SOURCES entry.cpp)
|
|
||||||
add_executable(sol2402 ${HEADERS} ${SOURCES})
|
|
||||||
target_include_directories(sol2402 PRIVATE ${PROJECT_SOURCE_DIR})
|
|
||||||
target_compile_features(sol2402 PRIVATE cxx_std_23)
|
|
||||||
target_compile_options(sol2402 PRIVATE ${BASE_OPTIONS})
|
|
||||||
target_compile_definitions(sol2402 PRIVATE ${BASE_DEFINITIONS})
|
|
||||||
target_link_libraries(sol2402
|
|
||||||
PRIVATE
|
|
||||||
aoc
|
|
||||||
)
|
|
||||||
set_target_properties(sol2402 PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
||||||
)
|
|
||||||
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include "aoc/aoc.hpp"
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
auto aoc::entry([[maybe_unused]]std::vector<std::string_view> const& args) -> void {
|
|
||||||
fmt::print("Hello, World!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
set(HEADERS "")
|
|
||||||
set(SOURCES entry.cpp)
|
|
||||||
add_executable(sol2403 ${HEADERS} ${SOURCES})
|
|
||||||
target_include_directories(sol2403 PRIVATE ${PROJECT_SOURCE_DIR})
|
|
||||||
target_compile_features(sol2403 PRIVATE cxx_std_23)
|
|
||||||
target_compile_options(sol2403 PRIVATE ${BASE_OPTIONS})
|
|
||||||
target_compile_definitions(sol2403 PRIVATE ${BASE_DEFINITIONS})
|
|
||||||
target_link_libraries(sol2403
|
|
||||||
PRIVATE
|
|
||||||
aoc
|
|
||||||
)
|
|
||||||
set_target_properties(sol2403 PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
||||||
)
|
|
||||||
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES})
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
#include <fstream>
|
|
||||||
#include <expected>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "aoc/aoc.hpp"
|
|
||||||
#include "fmt/format.h"
|
|
||||||
#include "ctre.hpp"
|
|
||||||
|
|
||||||
#define ENUMERATOR_AOC_TOKENS \
|
|
||||||
ENUMERATOR_AOC_TOKEN(mul , operator_ ) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(invalid , invalid ) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(numeric_literal, number ) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(newline , punctuation) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(paren_open , punctuation) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(paren_close , punctuation) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(comma , punctuation) \
|
|
||||||
ENUMERATOR_AOC_TOKEN(identifier , identifier )
|
|
||||||
|
|
||||||
enum class token_type : std::uint32_t {
|
|
||||||
#define ENUMERATOR_AOC_TOKEN(type, category) type,
|
|
||||||
ENUMERATOR_AOC_TOKENS
|
|
||||||
#undef ENUMERATOR_AOC_TOKEN
|
|
||||||
_count
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class token_category : std::uint32_t {
|
|
||||||
operator_,
|
|
||||||
invalid,
|
|
||||||
number,
|
|
||||||
punctuation,
|
|
||||||
identifier,
|
|
||||||
_count
|
|
||||||
};
|
|
||||||
|
|
||||||
auto token_type_str(token_type type) -> char const* {
|
|
||||||
switch (type) {
|
|
||||||
using enum token_type;
|
|
||||||
#define ENUMERATOR_AOC_TOKEN(type, category) case type: return #type;
|
|
||||||
ENUMERATOR_AOC_TOKENS
|
|
||||||
#undef ENUMERATOR_AOC_TOKEN
|
|
||||||
default: return "invalid";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto token_type_category(token_type type) -> token_category {
|
|
||||||
switch (type) {
|
|
||||||
using enum token_category;
|
|
||||||
#define ENUMERATOR_AOC_TOKEN(type, category) case token_type::type: return category;
|
|
||||||
ENUMERATOR_AOC_TOKENS
|
|
||||||
#undef ENUMERATOR_AOC_TOKEN
|
|
||||||
default: return token_category::invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class token {
|
|
||||||
public:
|
|
||||||
token(std::string const& str, token_type type, token_category category, std::size_t row, std::size_t col)
|
|
||||||
: m_type(type)
|
|
||||||
, m_category(category)
|
|
||||||
, m_value(str)
|
|
||||||
, m_row(row)
|
|
||||||
, m_column(col) { }
|
|
||||||
|
|
||||||
auto type() const -> token_type { return m_type; }
|
|
||||||
auto category() const -> token_category { return m_category; }
|
|
||||||
auto value() const -> std::string const& { return m_value; }
|
|
||||||
|
|
||||||
auto row() const -> std::size_t { return m_row; }
|
|
||||||
auto col() const -> std::size_t { return m_column; }
|
|
||||||
|
|
||||||
auto str() const -> std::string {
|
|
||||||
using namespace std::string_literals;
|
|
||||||
std::string str{"token {"};
|
|
||||||
str += " type: "s + token_type_str(m_type) + ","s;
|
|
||||||
str += " value: \""s + m_value + "\","s;
|
|
||||||
str += " row: "s + std::to_string(m_row) + ","s;
|
|
||||||
str += " col: "s + std::to_string(m_column);
|
|
||||||
str += " }";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
inline static auto is_identifier(std::string_view const& str) -> bool {
|
|
||||||
return ctre::match<"^[a-z]+$">(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
token_type m_type;
|
|
||||||
token_category m_category;
|
|
||||||
std::string m_value;
|
|
||||||
std::size_t m_row;
|
|
||||||
std::size_t m_column;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class lexer_error {
|
|
||||||
eof,
|
|
||||||
unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
class lexer {
|
|
||||||
public:
|
|
||||||
lexer(std::filesystem::path const& source)
|
|
||||||
: m_strm(source, std::ios::in | std::ios::binary)
|
|
||||||
, m_line(1), m_col(1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tokenize() -> std::vector<token> {
|
|
||||||
std::vector<token> tokens{};
|
|
||||||
auto tk = next_token();
|
|
||||||
while (tk) {
|
|
||||||
tokens.emplace_back(std::move(tk.value()));
|
|
||||||
tk = next_token();
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
auto next_token() -> std::optional<token> {
|
|
||||||
if (!has_next()) return {};
|
|
||||||
if (peek() == '\n') {
|
|
||||||
peek_consume();
|
|
||||||
m_line = m_line + 1;
|
|
||||||
m_col = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string str{};
|
|
||||||
if (peek() == 'm') {
|
|
||||||
auto const col = m_col;
|
|
||||||
auto const is_valid_identifier_char = [](auto const c) {
|
|
||||||
return c >= 'a' && c <= 'z';
|
|
||||||
};
|
|
||||||
while (is_valid_identifier_char(peek())) str += peek_consume();
|
|
||||||
auto const& type = token::is_identifier(str) ? token_type::identifier : token_type::invalid;
|
|
||||||
return token(str, type, token_type_category(type), m_line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peek() == '(') {
|
|
||||||
auto const col = m_col;
|
|
||||||
str += peek_consume();
|
|
||||||
return token(str, token_type::paren_open, token_type_category(token_type::paren_open), m_line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peek() == ')') {
|
|
||||||
auto const col = m_col;
|
|
||||||
str += peek_consume();
|
|
||||||
return token(str, token_type::paren_close, token_type_category(token_type::paren_close), m_line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peek() == ',') {
|
|
||||||
auto const col = m_col;
|
|
||||||
str += peek_consume();
|
|
||||||
return token(str, token_type::comma, token_type_category(token_type::comma), m_line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const col = m_col;
|
|
||||||
str += peek_consume();
|
|
||||||
return token(str, token_type::invalid, token_type_category(token_type::invalid), m_line, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto peek() -> char {
|
|
||||||
return static_cast<char>(m_strm.peek());
|
|
||||||
}
|
|
||||||
auto peek_consume() -> char {
|
|
||||||
++m_col;
|
|
||||||
return static_cast<char>(m_strm.get());
|
|
||||||
}
|
|
||||||
auto has_next() const -> bool {
|
|
||||||
return !m_strm.eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::fstream m_strm;
|
|
||||||
std::size_t m_line;
|
|
||||||
std::size_t m_col;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto aoc::entry([[maybe_unused]]std::vector<std::string_view> const& args) -> void {
|
|
||||||
lexer lexer{"./dat/24/ex/03.txt"};
|
|
||||||
|
|
||||||
auto const tokens = lexer.tokenize();
|
|
||||||
|
|
||||||
for (auto const& tk : tokens) {
|
|
||||||
fmt::print("{}\n", tk.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# add_subdirectory(01)
|
|
||||||
# add_subdirectory(02)
|
|
||||||
add_subdirectory(03)
|
|
||||||
0
sol/24/day01.cpp
Normal file
0
sol/24/day01.cpp
Normal file
0
sol/24/day02.cpp
Normal file
0
sol/24/day02.cpp
Normal file
405
sol/24/day03.cpp
Normal file
405
sol/24/day03.cpp
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
#include <fstream>
|
||||||
|
#include <expected>
|
||||||
|
#include <string>
|
||||||
|
#include <ranges>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "aoc/aoc.hpp"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "ctre.hpp"
|
||||||
|
|
||||||
|
namespace npr {
|
||||||
|
#define ENUMERATOR_AOC_TOKENS \
|
||||||
|
ENUMERATOR_AOC_TOKEN(mul , operator_ ) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(invalid , invalid ) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(numeric_literal, number ) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(newline , punctuation) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(paren_open , punctuation) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(paren_close , punctuation) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(comma , punctuation) \
|
||||||
|
ENUMERATOR_AOC_TOKEN(identifier , identifier )
|
||||||
|
|
||||||
|
#define ENUMERATOR_AOC_CATEGORIES \
|
||||||
|
ENUMERATOR_AOC_CATEGORY(operator_) \
|
||||||
|
ENUMERATOR_AOC_CATEGORY(invalid) \
|
||||||
|
ENUMERATOR_AOC_CATEGORY(number) \
|
||||||
|
ENUMERATOR_AOC_CATEGORY(punctuation) \
|
||||||
|
ENUMERATOR_AOC_CATEGORY(identifier)
|
||||||
|
|
||||||
|
#define ENUMERATOR_AOC_NODE_TYPES \
|
||||||
|
ENUMERATOR_AOC_NODE_TYPE(numeric_literal) \
|
||||||
|
ENUMERATOR_AOC_NODE_TYPE(call_expression) \
|
||||||
|
ENUMERATOR_AOC_NODE_TYPE(binary_expression)
|
||||||
|
|
||||||
|
enum class token_type : std::uint32_t {
|
||||||
|
#define ENUMERATOR_AOC_TOKEN(type, category) type,
|
||||||
|
ENUMERATOR_AOC_TOKENS
|
||||||
|
#undef ENUMERATOR_AOC_TOKEN
|
||||||
|
_count
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class token_category : std::uint32_t {
|
||||||
|
#define ENUMERATOR_AOC_CATEGORY(type) type,
|
||||||
|
ENUMERATOR_AOC_CATEGORIES
|
||||||
|
#undef ENUMERATOR_AOC_CATEGORY
|
||||||
|
_count
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class node_type : std::uint32_t {
|
||||||
|
#define ENUMERATOR_AOC_NODE_TYPE(type) type,
|
||||||
|
ENUMERATOR_AOC_NODE_TYPES
|
||||||
|
#undef ENUMERATOR_AOC_NODE_TYPE
|
||||||
|
_count
|
||||||
|
};
|
||||||
|
|
||||||
|
auto token_type_str(token_type type) -> char const* {
|
||||||
|
switch (type) {
|
||||||
|
using enum token_type;
|
||||||
|
#define ENUMERATOR_AOC_TOKEN(type, category) case type: return #type;
|
||||||
|
ENUMERATOR_AOC_TOKENS
|
||||||
|
#undef ENUMERATOR_AOC_TOKEN
|
||||||
|
default: return "invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto token_type_category(token_type type) -> token_category {
|
||||||
|
switch (type) {
|
||||||
|
using enum token_category;
|
||||||
|
#define ENUMERATOR_AOC_TOKEN(type, category) case token_type::type: return category;
|
||||||
|
ENUMERATOR_AOC_TOKENS
|
||||||
|
#undef ENUMERATOR_AOC_TOKEN
|
||||||
|
default: return token_category::invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node_type_str(node_type type) -> char const* {
|
||||||
|
switch (type) {
|
||||||
|
using enum node_type;
|
||||||
|
#define ENUMERATOR_AOC_NODE_TYPE(type) case type: return #type;
|
||||||
|
ENUMERATOR_AOC_NODE_TYPES
|
||||||
|
#undef ENUMERATOR_AOC_NODE_TYPE
|
||||||
|
default: return "invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class token {
|
||||||
|
public:
|
||||||
|
token(std::string const& str, token_type type, token_category category, std::size_t row, std::size_t col)
|
||||||
|
: m_type(type)
|
||||||
|
, m_category(category)
|
||||||
|
, m_value(str)
|
||||||
|
, m_row(row)
|
||||||
|
, m_column(col) { }
|
||||||
|
|
||||||
|
auto type() const -> token_type { return m_type; }
|
||||||
|
auto category() const -> token_category { return m_category; }
|
||||||
|
auto value() const -> std::string const& { return m_value; }
|
||||||
|
|
||||||
|
auto row() const -> std::size_t { return m_row; }
|
||||||
|
auto col() const -> std::size_t { return m_column; }
|
||||||
|
|
||||||
|
auto str() const -> std::string {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
std::string str{"token {"};
|
||||||
|
str += " value: \""s + m_value + "\","s;
|
||||||
|
str += " type: "s + token_type_str(m_type) + ","s;
|
||||||
|
str += " row: "s + std::to_string(m_row) + ","s;
|
||||||
|
str += " col: "s + std::to_string(m_column);
|
||||||
|
str += " }";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline static auto is_identifier(std::string_view const& str) -> bool {
|
||||||
|
return ctre::match<"^[a-z]+$">(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static auto is_numeric_literal(std::string_view const& str) -> bool {
|
||||||
|
return ctre::match<"^[0-9]+$">(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
token_type m_type;
|
||||||
|
token_category m_category;
|
||||||
|
std::string m_value;
|
||||||
|
std::size_t m_row;
|
||||||
|
std::size_t m_column;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class lexer_error {
|
||||||
|
eof,
|
||||||
|
unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
class lexer {
|
||||||
|
public:
|
||||||
|
lexer(std::string const& source)
|
||||||
|
: m_strm(source, std::ios::in | std::ios::binary)
|
||||||
|
, m_line(1), m_col(1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tokenize() -> std::vector<token> {
|
||||||
|
std::vector<token> tokens{};
|
||||||
|
auto tk = next_token();
|
||||||
|
while (tk) {
|
||||||
|
tokens.emplace_back(std::move(tk.value()));
|
||||||
|
tk = next_token();
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto next_token() -> std::optional<token> {
|
||||||
|
if (!has_next()) return {};
|
||||||
|
std::string str{};
|
||||||
|
auto const col = m_col;
|
||||||
|
|
||||||
|
if (peek() == '\n') {
|
||||||
|
peek_consume();
|
||||||
|
m_line = m_line + 1;
|
||||||
|
m_col = 1;
|
||||||
|
str += "\\n";
|
||||||
|
auto const& type = token_type::invalid;
|
||||||
|
return token(str, type, token_type_category(type), m_line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() == 'm') {
|
||||||
|
auto const is_valid_identifier_char = [](auto const c) {
|
||||||
|
return c >= 'a' && c <= 'z';
|
||||||
|
};
|
||||||
|
while (is_valid_identifier_char(peek())) str += peek_consume();
|
||||||
|
auto const check_type = [](auto const str) {
|
||||||
|
if (!token::is_identifier(str)) return token_type::invalid;
|
||||||
|
if (str == "mul") return token_type::identifier;
|
||||||
|
return token_type::invalid;
|
||||||
|
};
|
||||||
|
auto const& type = check_type(str);
|
||||||
|
return token(str, type, token_type_category(type), m_line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() == '(') {
|
||||||
|
str += peek_consume();
|
||||||
|
return token{
|
||||||
|
str,
|
||||||
|
token_type::paren_open,
|
||||||
|
token_type_category(token_type::paren_open),
|
||||||
|
m_line,
|
||||||
|
col
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() == ')') {
|
||||||
|
str += peek_consume();
|
||||||
|
return token{
|
||||||
|
str,
|
||||||
|
token_type::paren_close,
|
||||||
|
token_type_category(token_type::paren_close),
|
||||||
|
m_line,
|
||||||
|
col
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() == ',') {
|
||||||
|
str += peek_consume();
|
||||||
|
return token{
|
||||||
|
str,
|
||||||
|
token_type::comma,
|
||||||
|
token_type_category(token_type::comma),
|
||||||
|
m_line,
|
||||||
|
col
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::isdigit(peek())) {
|
||||||
|
while(std::isdigit(peek())) str += peek_consume();
|
||||||
|
auto const& type = token::is_numeric_literal(str) ? token_type::numeric_literal : token_type::invalid;
|
||||||
|
return token(str, type, token_type_category(type), m_line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_next()) return {};
|
||||||
|
|
||||||
|
str += peek_consume();
|
||||||
|
return token{
|
||||||
|
str,
|
||||||
|
token_type::invalid,
|
||||||
|
token_type_category(token_type::invalid),
|
||||||
|
m_line,
|
||||||
|
col
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto peek() -> char {
|
||||||
|
return static_cast<char>(m_strm.peek());
|
||||||
|
}
|
||||||
|
auto peek_consume() -> char {
|
||||||
|
++m_col;
|
||||||
|
return static_cast<char>(m_strm.get());
|
||||||
|
}
|
||||||
|
auto has_next() const -> bool {
|
||||||
|
return !m_strm.eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::fstream m_strm;
|
||||||
|
std::size_t m_line;
|
||||||
|
std::size_t m_col;
|
||||||
|
};
|
||||||
|
|
||||||
|
class node {
|
||||||
|
public:
|
||||||
|
node(node_type type,
|
||||||
|
token const& token,
|
||||||
|
std::vector<node> const& nodes = {})
|
||||||
|
: m_type(type)
|
||||||
|
, m_token(token)
|
||||||
|
, m_nodes(nodes) { }
|
||||||
|
|
||||||
|
auto type() const -> node_type { return m_type; }
|
||||||
|
auto token() const -> npr::token const& { return m_token; }
|
||||||
|
auto nodes() const -> std::vector<node> const& { return m_nodes; }
|
||||||
|
auto value() const -> std::string const& { return m_token.value(); }
|
||||||
|
|
||||||
|
auto add_node(npr::node const& node) -> void {
|
||||||
|
m_nodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto str() const -> std::string {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
std::string str{node_type_str(m_type) + " {"s};
|
||||||
|
str += " value: "s + m_token.value();
|
||||||
|
switch (m_type) {
|
||||||
|
case node_type::call_expression:
|
||||||
|
str += call_expression_str();
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
str += " }";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto call_expression_str() const -> std::string {
|
||||||
|
using namespace std::string_literals;
|
||||||
|
std::string str{", ["};
|
||||||
|
for (std::size_t i = 0; i < m_nodes.size(); ++i) {
|
||||||
|
str += " "s + std::to_string(i) + ": "s + m_nodes[i].str();
|
||||||
|
if (i < m_nodes.size() - 1) str += ",";
|
||||||
|
}
|
||||||
|
str += " ]";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_type m_type;
|
||||||
|
npr::token m_token;
|
||||||
|
std::vector<node> m_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class parser {
|
||||||
|
public:
|
||||||
|
parser() : m_cursor(0), m_tokens() { }
|
||||||
|
|
||||||
|
auto parse(std::vector<token> const& tokens) -> std::vector<node> {
|
||||||
|
m_cursor = 0;
|
||||||
|
m_tokens = tokens;
|
||||||
|
|
||||||
|
std::vector<node> nodes{};
|
||||||
|
do {
|
||||||
|
auto n = parse_statement();
|
||||||
|
if (n.has_value()) nodes.push_back(n.value());
|
||||||
|
} while(has_next());
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto parse_statement() -> std::optional<node> {
|
||||||
|
auto const type = peek().type();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case token_type::identifier: {
|
||||||
|
if (!has_next()) return {};
|
||||||
|
auto next = peek_next();
|
||||||
|
if (next.type() == token_type::paren_open) {
|
||||||
|
return parse_call_expression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
consume();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parse_call_expression() -> std::optional<node> {
|
||||||
|
auto const& token_callee = peek();
|
||||||
|
node callee{node_type::call_expression, token_callee};
|
||||||
|
consume();
|
||||||
|
return parse_args(callee);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parse_args(npr::node callee) -> std::optional<node> {
|
||||||
|
if (peek().type() != token_type::paren_open) return {};
|
||||||
|
consume();
|
||||||
|
while (has_next()) {
|
||||||
|
auto const& arg_token = peek();
|
||||||
|
if (arg_token.type() == token_type::numeric_literal) {
|
||||||
|
callee.add_node({node_type::numeric_literal, arg_token});
|
||||||
|
consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg_token.type() == token_type::comma) {
|
||||||
|
consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg_token.type() == token_type::paren_close) {
|
||||||
|
consume();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return callee;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto peek() const -> token const& {
|
||||||
|
return m_tokens[m_cursor];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto peek_next() const -> token const& {
|
||||||
|
return m_tokens[m_cursor + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto consume() -> void {
|
||||||
|
if (m_cursor >= m_tokens.size()) return;
|
||||||
|
++m_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto has_next(std::size_t i = 0) const -> bool {
|
||||||
|
return m_cursor + i < m_tokens.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t m_cursor;
|
||||||
|
std::vector<token> m_tokens;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto aoc::entry([[maybe_unused]]std::vector<std::string_view> const& args) -> void {
|
||||||
|
npr::lexer lexer{"./dat/24/re/03.txt"};
|
||||||
|
npr::parser parser{};
|
||||||
|
auto const tokens = lexer.tokenize();
|
||||||
|
auto const nodes = parser.parse(tokens);
|
||||||
|
|
||||||
|
auto op = nodes | std::views::transform([](auto const& node) {
|
||||||
|
auto const a = std::stoi(node.nodes()[0].value());
|
||||||
|
auto const b = std::stoi(node.nodes()[1].value());
|
||||||
|
return a * b;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto const sum = std::accumulate(std::begin(op), std::end(op), 0);
|
||||||
|
|
||||||
|
fmt::print("Part A: {}\n", sum);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user