diff --git a/.gitignore b/.gitignore index 7e4fcb7..f241371 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ !scripts !scripts/common.mak +!scripts/lsproj.mak !scripts/install.bat !scripts/uninstall.bat diff --git a/Makefile b/Makefile index c5fc586..f244a48 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -export MAKEFLAGS += --silent -r +export MAKEFLAGS += --silent -r -j export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow export ldflags=-L$(bin)/$(profile) export lib=ppc$(version-major)- @@ -51,7 +51,7 @@ build: version make -f scripts/common.mak if exist "$(subst /,\,$(bin)\$(output).exe)" del "$(subst /,\,$(bin)\$(output).exe)" mklink /H "$(subst /,\,$(bin)\$(output).exe)" "$(subst /,\,$(binary))" > NUL - + echo Done! clear: if exist $(subst /,\,$(oldbin)) rmdir /s /q $(subst /,\,$(oldbin)) diff --git a/include/compiler/treeifier/ast.hh b/include/compiler/treeifier/ast.hh index f49b59f..38f3b96 100644 --- a/include/compiler/treeifier/ast.hh +++ b/include/compiler/treeifier/ast.hh @@ -10,6 +10,7 @@ using namespace std::string_literals; using namespace ppc; +using namespace ppc::lang; using namespace ppc::messages; namespace ppc::comp::tree::ast { @@ -42,6 +43,8 @@ namespace ppc::comp::tree::ast { public: msg_stack_t &messages; std::vector &tokens; + std::set imports; + located_t nmsp; void add_parser(std::string name, parser_t &parser); void add_parser(std::string name, group_parser_t &parser); @@ -57,10 +60,7 @@ namespace ppc::comp::tree::ast { }; class parser_t { - private: - std::string _name; public: - const std::string &name() { return _name; } virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0; bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { return parse(ctx, i, out); diff --git a/include/compiler/treeifier/ast/helper.hh b/include/compiler/treeifier/ast/helper.hh index bf9e53a..e4c0193 100644 --- a/include/compiler/treeifier/ast/helper.hh +++ b/include/compiler/treeifier/ast/helper.hh @@ -5,14 +5,19 @@ namespace ppc::comp::tree::ast { private: ast_ctx_t &ctx; size_t &res_i; - size_t i; void throw_ended() { if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc()); } + void throw_ended(const std::string &reason) { + if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end: " + reason, loc()); + } public: - void submit() { + size_t i; + + bool submit() { res_i = i; + return true; } bool ended() { @@ -83,6 +88,11 @@ namespace ppc::comp::tree::ast { i++; throw_ended(); } + void advance(const std::string &reason) { + throw_ended(reason); + i++; + throw_ended(reason); + } tree_helper_t(ast_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) { this->i = i; diff --git a/include/lang/common.hh b/include/lang/common.hh index 00670ad..69a2137 100644 --- a/include/lang/common.hh +++ b/include/lang/common.hh @@ -8,10 +8,9 @@ namespace ppc::lang { struct located_t : T { location_t location; - template - located_t(location_t loc, Args ...args): T(args...), location(loc) { } - template - located_t(Args ...args): T(args...), location(location_t::NONE) { } + located_t(location_t loc, const T &val): T(val), location(loc) { } + located_t(const T &val): T(val), location(location_t::NONE) { } + located_t() { } }; struct namespace_name_t : public std::vector { diff --git a/include/utils/message.hh b/include/utils/message.hh index 4223d3a..cf3ac52 100644 --- a/include/utils/message.hh +++ b/include/utils/message.hh @@ -17,7 +17,7 @@ namespace ppc::messages { std::string content; location_t location; - message_t(level_t level, std::string content, location_t loc = location_t::NONE) : + message_t(level_t level, const std::string &content, location_t loc = location_t::NONE) : level(level), content(content), location(loc) { } @@ -25,6 +25,8 @@ namespace ppc::messages { std::string to_string() const; bool is_severe() const; + + static message_t error(const std::string &message, location_t loc = location_t::NONE) { return message_t(ERROR, message, loc); } }; struct msg_stack_t { diff --git a/scripts/common.mak b/scripts/common.mak index 3b3e241..608e459 100644 --- a/scripts/common.mak +++ b/scripts/common.mak @@ -1,14 +1,16 @@ export lsproj = $(bin)/lsproj$(exe) export flags += "-I$(inc)" -D$(OS) -DPPC_VERSION_MAJOR=$(version-major) -DPPC_VERSION_MINOR=$(version-minor) -DPPC_VERSION_BUILD=$(version-build) -rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) +rwildcard=$(foreach d, $(wildcard $(1:=/*)),\ + $(call rwildcard,$d,$2)\ + $(filter $(subst *,%,$2),$d)\ +) uniq=$(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) modoutput=$(shell ./$(lsproj) $(src) $1 output) deps=$(strip \ $(foreach dep, $(shell ./$(lsproj) $(src) $1 deps),\ - $(if $(wildcard src/$(dep)),\ - $(dep),\ + $(if $(wildcard src/$(dep)), $(dep),\ $(error The module '$(dep)' (dependency of '$1') doesn't exist)\ )\ )\ @@ -29,15 +31,14 @@ lrdeps=$(foreach dep,$(call rdeps,$1),-l$(lib)$(call modoutput,$(dep))) modules = $(patsubst $(src)/%/,$(bin)/lib$(lib)%$(so),$(filter-out $(src)/$(mainmodule)/,$(wildcard $(src)/*/))) sources = $(call rwildcard,$(src)/$1,*.cc) headers = $(call rwildcard,$(inc),*.h) -binaries = $(patsubst $(src)/%.cc,$(bin)/%.o,$(call sources,$1)) +binaries = $(patsubst $(src)/%.cc,$(bin)/tmp/%.o,$(call sources,$1)) ifneq ($(nolsproj),yes) -$(shell make -f scripts/lsproj.mak $(lsproj)) +$(shell make -f scripts/lsproj.mak lsproj=$(lsproj) src=$(src) $(lsproj)) endif - .PHONY: build -.PRECIOUS: $(bin)/%.o +.PRECIOUS: $(bin)/tmp/%.o build: $(binary) @@ -53,7 +54,7 @@ $(bin)/lib$(lib)%$(so): $$(call frdeps,$$*) $$(call binaries,$$*) echo Compiling library '$(notdir $@)'... $(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)" -$(bin)/%.o: $(src)/%.cc $(headers) +$(bin)/tmp/%.o: $(src)/%.cc $(headers) echo - Compiling '$*.cc'... $(call mkdir,$(dir $@)) $(CXX) -fPIC -c $(flags) $< -o $@ diff --git a/src/compiler/treeifier/parsers/glob.cc b/src/compiler/treeifier/parsers/glob.cc index a4627b8..e574e3e 100644 --- a/src/compiler/treeifier/parsers/glob.cc +++ b/src/compiler/treeifier/parsers/glob.cc @@ -1,9 +1,59 @@ #include "compiler/treeifier/ast.hh" +#include "compiler/treeifier/ast/helper.hh" namespace ppc::comp::tree::ast { class glob_parser_t : public parser_t { + bool parse_nmsp(ast_ctx_t &ctx, size_t &res_i, located_t &out) const { + tree_helper_t h(ctx, res_i); + located_t res; + + while (true) { + auto &curr = h.curr(); + + if (h.ended() || !curr.is_identifier()) return false; + else res.push_back(curr.identifier()); + + if (!h.try_advance() || !h.curr().is_operator(operator_t::DOUBLE_COLON)) { + out = res; + return h.submit(); + } + } + } + bool parse_nmsp_def(ast_ctx_t &ctx, size_t &res_i) const { + tree_helper_t h(ctx, res_i); + if (h.ended()) return true; + + if (h.curr().is_identifier("namespace")) { + h.advance("Expected a namespace name."); + if (!parse_nmsp(ctx, h.i, ctx.nmsp)) throw message_t::error("Expected a namespace name.", h.loc()); + return h.submit(); + } + else return false; + } + bool parse_import(ast_ctx_t &ctx, size_t &res_i) const { + tree_helper_t h(ctx, res_i); + if (h.ended()) return true; + + if (h.curr().is_identifier("import")) { + h.advance("Expected a namespace name."); + located_t name; + if (!parse_nmsp(ctx, h.i, name)) throw message_t::error("Expected a namespace name.", h.loc()); + if (!ctx.imports.emplace(name).second) { + throw message_t::error("The namespace '" + name.to_string() + "' is already imported.", h.loc()); + } + return h.submit(); + } + else return false; + } + bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const { - return false; + tree_helper_t h(ctx, res_i); + if (h.ended()) return true; + parse_nmsp_def(ctx, h.i); + + while (parse_import(ctx, h.i)); + + return true; } }; diff --git a/src/compiler/treeifier/parsers/group.cc b/src/compiler/treeifier/parsers/group.cc index 979c49d..2c4d17c 100644 --- a/src/compiler/treeifier/parsers/group.cc +++ b/src/compiler/treeifier/parsers/group.cc @@ -41,12 +41,14 @@ bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { try { return h.parse(*parser, out); } - catch (std::string) { + catch (const message_t &err) { + ctx.messages.push(err); return false; } } -} + return false; +} group_parser_t &group_parser_t::add(parser_t &parser) { parsers.push_back(&parser); diff --git a/src/compiler/treeifier/tokenizer.cc b/src/compiler/treeifier/tokenizer.cc index c91614f..2063afe 100644 --- a/src/compiler/treeifier/tokenizer.cc +++ b/src/compiler/treeifier/tokenizer.cc @@ -52,7 +52,7 @@ static std::vector parse_string(msg_stack_t &msg_stack, bool is_char, lex: if (is_char) throw message_t(message_t::ERROR, "Unterminated char literal.", token.location); else throw message_t(message_t::ERROR, "Unterminated string literal.", token.location); } -static tok::token_t parse_int(msg_stack_t &msg_stack, lex::token_t token) { +static token_t parse_int(msg_stack_t &msg_stack, lex::token_t token) { enum radix_t { BINARY, OCTAL, @@ -119,9 +119,9 @@ static tok::token_t parse_int(msg_stack_t &msg_stack, lex::token_t token) { } } - return tok::token_t(res, token.location); + return token_t(res, token.location); } -static tok::token_t parse_float(msg_stack_t &msg_stack, lex::token_t token) { +static token_t parse_float(msg_stack_t &msg_stack, lex::token_t token) { double whole = 0, fract = 0; char c; @@ -143,16 +143,16 @@ static tok::token_t parse_float(msg_stack_t &msg_stack, lex::token_t token) { } } - return tok::token_t(whole + fract, token.location); + return token_t(whole + fract, token.location); } -tok::token_t tok::token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) { +token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) { switch (in.type) { case lex::token_t::IDENTIFIER: - return tok::token_t(in.data, in.location); + return token_t(in.data, in.location); case lex::token_t::OPERATOR: try { - auto op = tok::operator_find(in.data); + auto op = operator_find(in.data); return token_t(op, in.location); } catch (std::string &err) { @@ -176,11 +176,11 @@ tok::token_t tok::token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t throw message_t(message_t::ERROR, "Token type not recognised.", in.location); } } -std::vector tok::token_t::parse_many(messages::msg_stack_t &msg_stack, std::vector tokens) { - std::vector res; +std::vector token_t::parse_many(messages::msg_stack_t &msg_stack, std::vector tokens) { + std::vector res; for (auto &tok : tokens) { - res.push_back(tok::token_t::parse(msg_stack, tok)); + res.push_back(token_t::parse(msg_stack, tok)); } return res; diff --git a/src/lang/version.cc b/src/lang/version.cc index 21c2918..a7f0642 100644 --- a/src/lang/version.cc +++ b/src/lang/version.cc @@ -4,14 +4,14 @@ using namespace ppc; bool version_t::operator==(version_t other) const { bool major_same = major == other.major; - bool minor_same = minor == -1 || other.minor == -1 || minor == other.minor; - bool revision_same = revision == -1 || other.revision == -1 || revision == other.revision; + bool minor_same = minor == -1u || other.minor == -1 || minor == other.minor; + bool revision_same = revision == -1u || other.revision == -1u || revision == other.revision; return major_same && minor_same && revision_same; } bool version_t::is_compliant(version_t other) const { bool major_compliant = major == other.major; - bool minor_compliant = minor == -1 || other.minor == -1 || minor <= other.minor; + bool minor_compliant = minor == -1u || other.minor == -1u || minor <= other.minor; return major_compliant && minor_compliant; } diff --git a/src/main/main.cc b/src/main/main.cc index fbc052e..bb637ce 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -152,11 +152,11 @@ int main(int argc, const char *argv[]) { for (const auto &file : files) { std::ifstream f { file, std::ios_base::in }; try { - auto res = tok::token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f)); + auto res = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f)); for (auto tok : res) { if (tok.is_identifier()) std::cout << "Identifier: \t" << tok.identifier(); - if (tok.is_operator()) std::cout << "Operator: \t" << tok::operator_stringify(tok._operator()); + if (tok.is_operator()) std::cout << "Operator: \t" << operator_stringify(tok._operator()); if (tok.is_float_lit()) std::cout << "Float: \t" << tok.float_lit(); if (tok.is_int_lit()) std::cout << "Int: \t" << tok.int_lit(); if (tok.is_char_lit()) std::cout << "Char: \t" << tok.char_lit();