Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ jobs:
- name: Clang-format
uses: jidicula/clang-format-action@v4.13.0
with:
clang-format-version: '18'
clang-format-version: '20'
check-path: '.'
19 changes: 16 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,30 @@ add_library(qpiler_lib
src/reader.cpp
src/ast.cpp
src/grouper.cpp
src/expression.cpp
)
find_package(OpenMP)
if (OpenMP_CXX_FOUND)
target_link_libraries(qpiler_lib PUBLIC OpenMP::OpenMP_CXX)
endif()

target_include_directories(qpiler_lib PUBLIC include)

target_precompile_headers(qpiler_lib PRIVATE
include/reader.hpp
include/ast.hpp
include/grouper.hpp
include/expression.hpp
)

set_target_properties(qpiler_lib PROPERTIES UNITY_BUILD ON)

add_executable(qpiler src/main.cpp)

target_link_libraries(qpiler PRIVATE qpiler_lib)
if (OpenMP_CXX_FOUND)
target_link_libraries(qpiler PRIVATE OpenMP::OpenMP_CXX)
endif()

option(BUILD_TESTS "Build unit tests" ON)
option(COVERAGE "Enable coverage reporting" OFF)
Expand All @@ -66,18 +75,22 @@ if (BUILD_TESTS)

add_executable(unit_tests
tests/main.cpp

tests/reader_tests.cpp
tests/ast_tests.cpp
tests/grouper_tests.cpp
tests/identify_tests.cpp
tests/ast_tests.cpp
tests/arithmetic_tests.cpp
)

target_link_libraries(unit_tests
target_link_libraries(unit_tests PRIVATE
qpiler_lib
GTest::GTest
GTest::Main
Threads::Threads
)
if (OpenMP_CXX_FOUND)
target_link_libraries(unit_tests PRIVATE OpenMP::OpenMP_CXX)
endif()

enable_testing()
add_test(NAME unit_tests COMMAND unit_tests)
Expand Down
2 changes: 2 additions & 0 deletions data/test10.qc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
1-a*b+c/d-e%f;

+a*b-c/d;

++a--;
Expand Down
208 changes: 161 additions & 47 deletions include/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,86 +30,200 @@
#include <string>
#include <vector>

enum class token_kind {
eof,
open_bracket,
close_bracket,
separator,
keyword,
string,
comment,
whitespace,
integer,
floating,
special_character
};

struct token {
token_kind kind;
int line;
int column;
std::streamoff file_offset;
std::string word;

virtual ~token();

virtual void dump(std::ostream& os, const std::string& prefix, bool is_last)
const noexcept;

void dump(std::ostream& os) const noexcept;
};

using token_ptr = std::shared_ptr<token>;
#include "reader.hpp"

struct ast_node {
size_t fixed_size { 1 }, full_size { 1 };
virtual ~ast_node();

virtual ast_node const* first() const noexcept;
[[nodiscard]] virtual ast_node const* get() const noexcept;
[[nodiscard]] virtual ast_node const* first() const;
virtual const position& get_start() const;

virtual bool empty() const noexcept;
[[nodiscard]] virtual bool empty() const noexcept;

virtual void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const noexcept;
void dump(std::ostream& os, bool full) const noexcept;
void dump(std::ostream& os) const noexcept;

virtual void placeholde();
) const;
void dump(std::ostream& os, bool full) const;
void dump(std::ostream& os) const;
};

using ast_node_ptr = std::shared_ptr<ast_node>;

struct token_node : ast_node {
token value;
bool empty() const noexcept override;

[[nodiscard]] bool empty() const noexcept override;
const position& get_start() const override;
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const noexcept override;
) const override;
};

using token_node_ptr = std::shared_ptr<token_node>;

enum class group_kind { file, body, list, paren, command, item, key, halt };

[[nodiscard]] const char* group_kind_name(group_kind k) noexcept;

struct group_node : ast_node {
size_t limit;
group_kind kind { group_kind::halt };
std::vector<ast_node_ptr> nodes;
std::priority_queue<std::pair<size_t, size_t>>
weights; /// node_size -> node_index

bool placeholder { false };
void append(ast_node_ptr node);
bool empty() const noexcept override;
size_t size() const noexcept;
ast_node const* first() const noexcept override;
void append(ast_node_ptr node, const reader& src);
[[nodiscard]] bool empty() const noexcept override;
[[nodiscard]] size_t size() const noexcept;
[[nodiscard]] ast_node const* get() const noexcept override;
[[nodiscard]] ast_node const* first() const override;
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const noexcept override;
void placeholde() override;
) const override;
const position& get_start() const override;
void squeeze(size_t index, const reader& src);
void pop_back();
};

using group_ptr = std::shared_ptr<group_node>;

struct wrapped_node : group_node {
position start {};
const position& get_start() const override;
};

using wrapped_ptr = std::shared_ptr<wrapped_node>;

struct placeholder_node : wrapped_node {
reader* src { nullptr };
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using placeholder_node_ptr = std::shared_ptr<placeholder_node>;

struct callexp_node : token_node {
ast_node_ptr paren;
bool has_paren { false };

explicit callexp_node(const token& name);
void set_paren(ast_node_ptr paren);

void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using callexp_ptr = std::shared_ptr<callexp_node>;

struct fundecl_node : callexp_node {
ast_node_ptr body;
bool has_body { false };

explicit fundecl_node(const callexp_ptr& proto);
void set_body(ast_node_ptr body);

void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using fundecl_ptr = std::shared_ptr<fundecl_node>;

struct control_node : token_node {
ast_node_ptr body;
bool has_body { false };

explicit control_node(const token& name);
void set_body(ast_node_ptr body);
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using control_ptr = std::shared_ptr<control_node>;

struct condition_node : control_node {
bool is_loop { false };
ast_node_ptr paren;
bool has_paren { false };

explicit condition_node(const token& name);
void set_paren(ast_node_ptr paren);

void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using condition_ptr = std::shared_ptr<condition_node>;

struct jump_node : control_node {
explicit jump_node(const token& name);
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using jump_ptr = std::shared_ptr<jump_node>;

struct unary_node : ast_node {
token op;
ast_node_ptr expr;
bool is_prefix { true };
int priority { 0 };

unary_node(
const token& op, ast_node_ptr expr, bool is_prefix, int priority
);

const position& get_start() const override;
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using unary_ptr = std::shared_ptr<unary_node>;

struct binary_node : ast_node {
token op;
ast_node_ptr lhs;
ast_node_ptr rhs;
int priority { 0 };

binary_node(
const token& op, ast_node_ptr lhs, ast_node_ptr rhs, int priority
);

const position& get_start() const override;
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using binary_ptr = std::shared_ptr<binary_node>;

struct ternary_node : ast_node {
token qmark;
token colon;
ast_node_ptr cond;
ast_node_ptr left;
ast_node_ptr right;
int priority { 0 };

ternary_node(
const token& qmark, const token& colon, ast_node_ptr cond,
ast_node_ptr left, ast_node_ptr right, int priority
);

const position& get_start() const override;
void dump(
std::ostream& os, const std::string& prefix, bool is_last, bool full
) const override;
};

using ternary_ptr = std::shared_ptr<ternary_node>;

#endif // AST_HPP
61 changes: 61 additions & 0 deletions include/expression.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2025 Yaroslav Riabtsev <yaroslav.riabtsev@rwth-aachen.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef EXPRESSION_HPP
#define EXPRESSION_HPP

#include "ast.hpp"
#include <unordered_map>
#include <vector>

class expression {
public:
struct item {
bool is_op { false };
token tok;
ast_node_ptr node;
};

static std::vector<item> make_items(const std::vector<ast_node_ptr>& nodes);

static ast_node_ptr
parse_expression(std::vector<item>& items, size_t& idx, int min_prec);

static ast_node_ptr parse_prefix(std::vector<item>& items, size_t& idx);

private:
static token make_token(const token_node& tn, const std::string& word);

static bool match_op(
const std::vector<ast_node_ptr>& nodes, size_t pos,
const std::string& op
);

static const std::unordered_map<std::string, std::pair<int, bool>>
binary_ops;
static const std::unordered_map<std::string, int> prefix_ops;
static const std::unordered_map<std::string, int> postfix_ops;
};

#endif // EXPRESSION_HPP
Loading
Loading