diff --git a/Makefile b/Makefile index 623891a..4002055 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ export MAKEFLAGS += --silent -r -j -export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile) +export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile) -fdiagnostics-color=always export ldflags=-L$(bin)/$(profile) export lib=ppc$(version-major)- export profile=release diff --git a/include/compiler/treeifier/ast.hh b/include/compiler/treeifier/ast.hh index b83f24d..f589d37 100644 --- a/include/compiler/treeifier/ast.hh +++ b/include/compiler/treeifier/ast.hh @@ -15,111 +15,52 @@ using namespace ppc::lang; using namespace ppc::messages; namespace ppc::comp::tree::ast { - class parser_t; - class group_parser_t; struct ast_ctx_t; + using parser_func_t = bool (ast_ctx_t &ctx, size_t &res_i, data::map_t &out); + using parser_t = parser_func_t*; - using parser_adder_t = void (*)(ast_ctx_t &ctx); + class group_t { + private: + std::map named_parsers; + std::map parsers; + public: + group_t &insert(const std::string &name, parser_t parser, const std::string &relative_to, bool after); + group_t &add_last(const std::string &name, parser_t parser); + group_t &replace(const std::string &name, parser_t parser); + group_t &add_named(const std::string &name, parser_t parser, const lang::namespace_name_t &identifier); - extern const parser_adder_t glob_adder; - extern const parser_adder_t identifier_adder; - extern const parser_adder_t nmsp_adder; - extern const parser_adder_t type_adder; - extern const parser_adder_t exp_adder; - extern const parser_adder_t field_adder; - extern const parser_adder_t func_adder; - extern const parser_adder_t var_adder; + bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const; + }; struct ast_ctx_t { private: - struct parser_proxy_t { - private: - ast_ctx_t *parent; - public: - const parser_t &operator[](const std::string &name) const; - parser_proxy_t(ast_ctx_t *parent): parent(parent) { } - }; - - struct group_proxy_t { - private: - ast_ctx_t *parent; - public: - group_parser_t &operator[](const std::string &name); - group_parser_t &operator[](const std::string &name) const; - group_proxy_t(ast_ctx_t *parent): parent(parent) { } - }; - - std::unordered_map parsers; - std::set groups; + std::unordered_map groups; public: msg_stack_t &messages; std::vector &tokens; std::set imports; loc_namespace_name_t nmsp; - void add_parser(const parser_t *parser); - void add_parser(const parser_t *parser, const std::string &group); - void add_parser(const parser_t *parser, const std::string &group, const namespace_name_t &name); - - void add_parser(parser_adder_t factory) { factory(*this); } - ast_ctx_t &operator=(const ast_ctx_t &other) = delete; - const parser_proxy_t parser; - const group_proxy_t group; - - ast_ctx_t &init() { - add_parser(identifier_adder); - add_parser(nmsp_adder); - add_parser(glob_adder); - add_parser(type_adder); - add_parser(exp_adder); - add_parser(var_adder); - add_parser(field_adder); - add_parser(func_adder); - - return *this; + template + bool parse(const T &parser, size_t &i, data::map_t &out) { + return parser(*this, i, out); } - bool parse(std::string parser, size_t &pi, data::map_t &out); - static data::map_t parse(msg_stack_t &messages, std::vector &tokens); + group_t &group(const std::string &name); - ~ast_ctx_t(); - ast_ctx_t(msg_stack_t &messages, std::vector &tokens): - messages(messages), - tokens(tokens), - parser(this), - group(this) { } - }; - - class parser_t { - private: - std::string _name; - protected: - virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0; - public: - const std::string &name() const { return _name; } - bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { + template + static data::map_t parse(const T &glob, msg_stack_t &messages, std::vector &tokens) { + ast_ctx_t ctx(messages, tokens); data::map_t res; - out["$_name"] = _name; - return parse(ctx, i, out); + size_t i = 0; + + if (!ctx.parse(glob, i, res)) throw message_t::error("Failed to compile."); + return res; } - virtual ~parser_t() = default; - parser_t(const std::string &name): _name(name) { } - }; - - class group_parser_t : public parser_t { - private: - std::map named_parsers; - std::vector parsers; - public: - group_parser_t &add(const parser_t &parser); - group_parser_t &add(const parser_t &parser, const lang::namespace_name_t &name); - - bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const; - - group_parser_t(const std::string &name): parser_t(name) { } + ast_ctx_t(msg_stack_t &messages, std::vector &tokens); }; namespace conv { @@ -132,4 +73,7 @@ namespace ppc::comp::tree::ast { data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp); loc_namespace_name_t map_to_nmsp(const data::map_t &map); } + + parser_func_t parse_glob, parse_nmsp, parse_identifier, parse_type, parse_func, parse_field, parse_exp, parse_stat_exp; + parser_func_t parse_exp_var, parse_exp_str_lit, parse_exp_int_lit, parse_exp_float_lit; } \ No newline at end of file diff --git a/include/compiler/treeifier/ast/helper.hh b/include/compiler/treeifier/ast/helper.hh index 1181ce2..971c562 100644 --- a/include/compiler/treeifier/ast/helper.hh +++ b/include/compiler/treeifier/ast/helper.hh @@ -104,25 +104,28 @@ namespace ppc::comp::tree::ast { throw_ended(reason); } - bool push_parse(const std::string &name, data::array_t &out) { + template + bool push_parse(const T &parser, data::array_t &out) { data::map_t res; - if (parse(name, res)) { + if (parse(parser, res)) { out.push_back(res); return true; } else return false; } - bool parse(const std::string &name, data::map_t &out) { - return ctx.parse(name, i, out); + template + bool parse(const T &parser, data::map_t &out) { + return ctx.parse(parser, i, out); } - void force_push_parse(const std::string &name, std::string message, data::array_t &out) { + template + void force_push_parse(const T &parser, std::string message, data::array_t &out) { throw_ended(message); bool success; try { - success = push_parse(name, out); + success = push_parse(parser, out); } catch (const message_t &msg) { ctx.messages.push(msg); @@ -131,12 +134,13 @@ namespace ppc::comp::tree::ast { if (!success) err(message); } - void force_parse(const std::string &name, std::string message, data::map_t &out) { + template + void force_parse(const T &parser, std::string message, data::map_t &out) { throw_ended(message); bool success; try { - success = parse(name, out); + success = parse(parser, out); } catch (const message_t &msg) { ctx.messages.push(msg); diff --git a/include/compiler/treeifier/tokenizer.hh b/include/compiler/treeifier/tokenizer.hh index 93e1cb6..adaece9 100644 --- a/include/compiler/treeifier/tokenizer.hh +++ b/include/compiler/treeifier/tokenizer.hh @@ -79,28 +79,19 @@ namespace ppc::comp::tree { NONE, IDENTIFIER, OPERATOR, - INT, - FLOAT, - CHAR, - STRING, + LITERAL, } kind; union data_t { std::string *identifier; operator_t _operator; - std::uint64_t int_literal; - double float_literal; - char char_literal; - std::vector *string_literal; + std::vector *literal; } data; public: ppc::location_t location; bool is_identifier() const { return kind == IDENTIFIER; } bool is_operator() const { return kind == OPERATOR; } - bool is_int_lit() const { return kind == INT; } - bool is_float_lit() const { return kind == FLOAT; } - bool is_char_lit() const { return kind == CHAR; } - bool is_string_lit() const { return kind == STRING; } + bool is_literal() const { return kind == LITERAL; } const auto &identifier() const { if (!is_identifier()) throw std::string { "Token is not an identifier." }; @@ -110,21 +101,9 @@ namespace ppc::comp::tree { if (!is_operator()) throw std::string { "Token is not an operator." }; else return data._operator; } - auto int_lit() const { - if (!is_int_lit()) throw std::string { "Token is not an int literal." }; - else return data.int_literal; - } - auto float_lit() const { - if (!is_float_lit()) throw std::string { "Token is not a float literal." }; - else return data.float_literal; - } - auto char_lit() const { - if (!is_char_lit()) throw std::string { "Token is not a char literal." }; - else return data.char_literal; - } - const auto &string_lit() const { - if (!is_string_lit()) throw std::string { "Token is not a string literal." }; - else return *data.string_literal; + const auto &literal() const { + if (!is_literal()) throw std::string { "Token is not a literal." }; + else return *data.literal; } bool is_operator(operator_t op) const { return is_operator() && _operator() == op; } @@ -139,21 +118,9 @@ namespace ppc::comp::tree { kind = OPERATOR; data._operator = op; } - token_t(std::uint64_t val, location_t loc = location_t::NONE): location(loc) { - kind = INT; - data.int_literal = val; - } - token_t(double val, location_t loc = location_t::NONE): location(loc) { - kind = FLOAT; - data.float_literal = val; - } - token_t(char c, location_t loc = location_t::NONE): location(loc) { - kind = CHAR; - data.char_literal = c; - } - token_t(const std::vector &val, location_t loc = location_t::NONE): location(loc) { - kind = STRING; - data.string_literal = new std::vector { val }; + token_t(const std::vector &val, location_t loc = location_t::NONE): location(loc) { + kind = LITERAL; + data.literal = new std::vector { val }; } token_t(const token_t &tok): location(tok.location) { kind = tok.kind; @@ -161,17 +128,14 @@ namespace ppc::comp::tree { case NONE: break; case IDENTIFIER: data.identifier = new std::string { *tok.data.identifier }; break; case OPERATOR: data._operator = tok.data._operator; break; - case INT: data.int_literal = tok.data.int_literal; break; - case FLOAT: data.float_literal = tok.data.float_literal; break; - case CHAR: data.char_literal = tok.data.char_literal; break; - case STRING: data.string_literal = new std::vector { *tok.data.string_literal }; break; + case LITERAL: data.literal = new std::vector { *tok.data.literal }; break; } } ~token_t() { switch (kind) { case IDENTIFIER: delete data.identifier; break; - case STRING: delete data.string_literal; break; + case LITERAL: delete data.literal; break; default: break; } } diff --git a/src/compiler/treeifier/ast.cc b/src/compiler/treeifier/ast.cc deleted file mode 100644 index aea1723..0000000 --- a/src/compiler/treeifier/ast.cc +++ /dev/null @@ -1,59 +0,0 @@ -#include "compiler/treeifier/ast.hh" - -namespace ppc::comp::tree::ast { - std::unordered_map parsers; - - const parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const { - auto it = parent->parsers.find(name); - if (it == parent->parsers.end()) throw "The parser '" + name + "' doesn't exist."; - return *it->second; - } - group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const { - auto it = parent->parsers.find(name); - if (it == parent->parsers.end()) { - auto p = new group_parser_t(name); - parent->parsers[name] = p; - parent->groups.emplace(p); - return *p; - } - else if (parent->groups.find((group_parser_t*)it->second) == parent->groups.end()) { - throw "A parser '" + name + "' exists, but isn't a group."s; - } - else { - return *(group_parser_t*)it->second; - } - } - - ast_ctx_t::~ast_ctx_t() { - for (auto pair : parsers) { - delete pair.second; - } - } - - void ast_ctx_t::add_parser(const parser_t *parser) { - if (parsers.find(parser->name()) != parsers.end()) throw "The parser '" + parser->name() + "' already exists."; - parsers[parser->name()] = parser; - } - void ast_ctx_t::add_parser(const parser_t *parser, const std::string &group) { - add_parser(parser); - this->group[group].add(*parser); - } - void ast_ctx_t::add_parser(const parser_t *parser, const std::string &group, const namespace_name_t &name) { - add_parser(parser); - this->group[group].add(*parser, name); - } - - data::map_t ast_ctx_t::parse(msg_stack_t &messages, std::vector &tokens) { - ast_ctx_t ctx(messages, tokens); - ctx.init(); - size_t i = 0; - data::map_t res; - - if (!ctx.parse("$_glob", i, res)) throw message_t::error("Failed to compile."); - return res; - } - bool ast_ctx_t::parse(std::string parser, size_t &pi, data::map_t &out) { - return this->parser[parser] (*this, pi, out); - } -} - diff --git a/src/compiler/treeifier/ast/ast.cc b/src/compiler/treeifier/ast/ast.cc new file mode 100644 index 0000000..83abea1 --- /dev/null +++ b/src/compiler/treeifier/ast/ast.cc @@ -0,0 +1,24 @@ +#include "compiler/treeifier/ast.hh" + +using namespace ppc; +using namespace ppc::data; +using namespace ppc::lang; +using namespace ppc::comp::tree::ast; + +group_t &ast_ctx_t::group(const std::string &name) { + if (groups.find(name) == groups.end()) return groups[name] = { }; + else return groups[name]; +} + +ast_ctx_t::ast_ctx_t(msg_stack_t &messages, std::vector &tokens): messages(messages), tokens(tokens) { + group("$_exp_val") + .add_last("$_var", parse_exp_var) + .add_last("$_int", parse_exp_int_lit); + // .add_last("$_float", parse_exp_float_lit) + // .add_last("$_string", parse_exp_str_lit); + group("$_stat") + .add_last("$_exp", parse_stat_exp); + group("$_def") + .add_last("$_func", parse_func) + .add_last("$_field", parse_field); +} \ No newline at end of file diff --git a/src/compiler/treeifier/ast/parsers.cc b/src/compiler/treeifier/ast/parsers.cc new file mode 100644 index 0000000..e69de29 diff --git a/src/compiler/treeifier/ast/parsers/exp.cc b/src/compiler/treeifier/ast/parsers/exp.cc index f4ed46e..690eb50 100644 --- a/src/compiler/treeifier/ast/parsers/exp.cc +++ b/src/compiler/treeifier/ast/parsers/exp.cc @@ -51,251 +51,261 @@ std::map bin_ops { { (operator_t)-1, sizeof_data }, }; -class exp_parser_t : public parser_t { - map_t op_to_map(located_t op) const { - return { - { "$_name", "$_operator" }, - { "ops", array_t() }, - { "location", conv::loc_to_map(op.location) }, - { "op", op.name }, - }; - } +map_t op_to_map(located_t op) { + return { + { "$_name", "$_operator" }, + { "ops", array_t() }, + { "location", conv::loc_to_map(op.location) }, + { "op", op.name }, + }; +} - bool pop(std::vector> &op_stack, array_t &res) const { - if (op_stack.empty()) return false; +bool pop(std::vector> &op_stack, array_t &res) { + if (op_stack.empty()) return false; - auto map = op_to_map(op_stack.back()); - auto op_n = op_stack.back().op_n; - auto loc = op_stack.back().location; - op_stack.pop_back(); + auto map = op_to_map(op_stack.back()); + auto op_n = op_stack.back().op_n; + auto loc = op_stack.back().location; + op_stack.pop_back(); - if (res.size() < op_n) return false; + if (res.size() < op_n) return false; - auto &ops = map["ops"].array(); + auto &ops = map["ops"].array(); - for (size_t i = 0; i < op_n; i++) { - ops.push_back(res.back()); - loc = loc.intersect(conv::map_to_loc(res.back().map()["location"].string())); - res.pop_back(); - } - - map["location"] = conv::loc_to_map(loc); - - std::reverse(ops.begin(), ops.end()); - res.push_back(map); - - return true; - } - bool pop_paren(std::vector> &op_stack, array_t &res) const { - bool has_paren = false; - for (const auto &op : op_stack) { - if (op.precedence == precedence_t::PAREN) { - has_paren = true; - break; - } - } - if (!has_paren) return false; - - while (true) { - if (op_stack.back().precedence == precedence_t::PAREN) break; - if (!pop(op_stack, res)) return false; - } - - op_stack.pop_back(); - return true; - } - bool pop_call(size_t n, location_t loc, std::vector> &op_stack, array_t &res) const { - map_t call = { - { "$_name", "$_call" }, - }; - - array_t &args = call["args"].array({}); - - while (true) { - if (op_stack.back().precedence == precedence_t::CALL_START) break; - if (!pop(op_stack, res)) return false; - } - loc = loc.intersect(op_stack.back().location); - op_stack.pop_back(); - call["location"] = conv::loc_to_map(loc); - - for (size_t i = 0; i <= n; i++) { - args.push_back(res.back()); - res.pop_back(); - } - - std::reverse(args.begin(), args.end()); - - call["func"] = res.back(); + for (size_t i = 0; i < op_n; i++) { + ops.push_back(res.back()); + loc = loc.intersect(conv::map_to_loc(res.back().map()["location"].string())); res.pop_back(); - res.push_back(call); - - return true; } - bool pop_until(const op_data_t &data, tree_helper_t &h, std::vector> &op_stack, array_t &res) const { - while (!op_stack.empty()) { - auto &back_data = op_stack.back(); - if (data.assoc ? - back_data.precedence >= data.precedence : - back_data.precedence > data.precedence - ) break; - if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); + map["location"] = conv::loc_to_map(loc); + + std::reverse(ops.begin(), ops.end()); + res.push_back(map); + + return true; +} +bool pop_paren(std::vector> &op_stack, array_t &res) { + bool has_paren = false; + for (const auto &op : op_stack) { + if (op.precedence == precedence_t::PAREN) { + has_paren = true; + break; } - return true; + } + if (!has_paren) return false; + + while (true) { + if (op_stack.back().precedence == precedence_t::PAREN) break; + if (!pop(op_stack, res)) return false; } - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); + op_stack.pop_back(); + return true; +} +bool pop_call(size_t n, location_t loc, std::vector> &op_stack, array_t &res) { + map_t call = { + { "$_name", "$_call" }, + }; - bool last_val = false; - map_t val; - std::vector> op_stack; - std::vector call_args_n; - auto res = array_t(); + array_t &args = call["args"].array({}); + + while (true) { + if (op_stack.back().precedence == precedence_t::CALL_START) break; + if (!pop(op_stack, res)) return false; + } + loc = loc.intersect(op_stack.back().location); + op_stack.pop_back(); + call["location"] = conv::loc_to_map(loc); + + for (size_t i = 0; i <= n; i++) { + args.push_back(res.back()); + res.pop_back(); + } + + std::reverse(args.begin(), args.end()); + + call["func"] = res.back(); + res.pop_back(); + res.push_back(call); + + return true; +} +bool pop_until(const op_data_t &data, tree_helper_t &h, std::vector> &op_stack, array_t &res) { + while (!op_stack.empty()) { + auto &back_data = op_stack.back(); + if (data.assoc ? + back_data.precedence >= data.precedence : + back_data.precedence > data.precedence + ) break; + + if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); + } + return true; +} + +bool ast::parse_exp_var(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); + + if (h.curr().is_identifier()) { + out["content"] = h.curr().identifier(); + out["location"] = conv::loc_to_map(h.loc()); + return h.submit(true); + } + + return false; +} +bool ast::parse_exp_int_lit(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); + + if (h.curr().is_literal()) { + auto &arr = out["content"].array({}); + for (auto b : h.curr().literal()) arr.push_back((float)b); + out["location"] = conv::loc_to_map(h.loc()); + return h.submit(true); + } + + return false; +} - while (true) { - if (h.ended()) break; +bool ast::parse_exp(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (!last_val && h.curr().is_identifier("sizeof")) { - op_stack.push_back({ h.loc(), sizeof_data }); - h.advance("Expected a value on the right side of the operator."); - continue; - } - if (!last_val && h.push_parse("$_exp_val", res)) last_val = true; - if (h.curr().is_operator()) { - auto op = h.curr()._operator(); - if (last_val) { - if (op == operator_t::PAREN_OPEN) { - h.advance("Expected an argument."); - call_args_n.push_back(0); - op_stack.push_back({ h.loc(), { precedence_t::CALL_START } }); - last_val = false; - } - else if (op == operator_t::COMMA) { - if (call_args_n.size() == 0) break; - h.advance("Expected an argument."); + bool last_val = false; + map_t val; + std::vector> op_stack; + std::vector call_args_n; + auto res = array_t(); - pop_until({ precedence_t::CALL_START, .assoc = true }, h, op_stack, res); - call_args_n.back()++; - last_val = false; - } - else if (op == operator_t::PAREN_CLOSE) { - bool is_call = false, is_paren = false; - for (auto i = op_stack.rbegin(); i != op_stack.rend(); i++) { - if (i->precedence == precedence_t::PAREN) { - is_paren = true; - break; - } - else if (i->precedence == precedence_t::CALL_START) { - is_call = true; - break; - } - } + while (true) { + if (h.ended()) break; - if (is_call) pop_call(call_args_n.back(), h.loc(), op_stack, res); - else if (is_paren) pop_paren(op_stack, res); - else break; - - if (!h.try_advance()) break; - } - else if (op == operator_t::COLON) { - h.advance("Expected a type."); - pop_until({ precedence_t::PREFIX, .assoc = true }, h, op_stack, res); - map_t cast = { - { "$_name", "$_cast" }, - { "exp", res.back() }, - }; - - res.pop_back(); - h.force_parse("$_type", "Expected a type.", cast["type"].map({})); - res.push_back(cast); - } - else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) { - h.advance("Expected an identifier."); - pop_until({ precedence_t::POSTFIX, .assoc = true }, h, op_stack, res); - - map_t member_access = { - { "$_name", "$_member" }, - { "exp", res.back() }, - { "is_ptr", op == operator_t::PTR_MEMBER }, - }; - h.force_parse("$_identifier", "Expected an identifier.", member_access["name"].map({})); - member_access["location"] = conv::loc_to_map( - conv::map_to_loc(member_access["name"].map()["location"].string()).intersect( - conv::map_to_loc(res.back().map()["location"].string()) - ) - ); - res.pop_back(); - res.push_back(member_access); - } - else if (bin_ops.find(op) != bin_ops.end()) { - auto data = bin_ops[op]; - pop_until(data, h, op_stack, res); - op_stack.push_back({ h.loc(), data }); - - if (data.op_n == 1) { - last_val = true; - if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); - if (h.try_advance()) break; - } - else { - last_val = false; - h.advance("Expected a value on the right side of the operator."); - } - } - else break; + if (!last_val && h.curr().is_identifier("sizeof")) { + op_stack.push_back({ h.loc(), sizeof_data }); + h.advance("Expected a value on the right side of the operator."); + continue; + } + if (!last_val && h.push_parse(ctx.group("$_exp_val"), res)) last_val = true; + if (h.curr().is_operator()) { + auto op = h.curr()._operator(); + if (last_val) { + if (op == operator_t::PAREN_OPEN) { + h.advance("Expected an argument."); + call_args_n.push_back(0); + op_stack.push_back({ h.loc(), { precedence_t::CALL_START } }); + last_val = false; } - else { - if (op == operator_t::PAREN_OPEN) { - op_stack.push_back({ h.loc(), { precedence_t::PAREN } }); - h.advance("Expected a value."); - last_val = false; + else if (op == operator_t::COMMA) { + if (call_args_n.size() == 0) break; + h.advance("Expected an argument."); + + pop_until({ .precedence = precedence_t::CALL_START, .assoc = true }, h, op_stack, res); + call_args_n.back()++; + last_val = false; + } + else if (op == operator_t::PAREN_CLOSE) { + bool is_call = false, is_paren = false; + + for (auto i = op_stack.rbegin(); i != op_stack.rend(); i++) { + if (i->precedence == precedence_t::PAREN) { + is_paren = true; + break; + } + else if (i->precedence == precedence_t::CALL_START) { + is_call = true; + break; + } } - else if (pre_ops.find(op) != pre_ops.end()) { - op_stack.push_back({ h.loc(), pre_ops[op] }); + + if (is_call) pop_call(call_args_n.back(), h.loc(), op_stack, res); + else if (is_paren) pop_paren(op_stack, res); + else break; + + if (!h.try_advance()) break; + } + else if (op == operator_t::COLON) { + h.advance("Expected a type."); + pop_until({ .precedence = precedence_t::PREFIX, .assoc = true }, h, op_stack, res); + map_t cast = { + { "$_name", "$_cast" }, + { "exp", res.back() }, + }; + + res.pop_back(); + h.force_parse(parse_type, "Expected a type.", cast["type"].map({})); + res.push_back(cast); + } + else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) { + h.advance("Expected an identifier."); + pop_until({ .precedence = precedence_t::POSTFIX, .assoc = true }, h, op_stack, res); + + map_t member_access = { + { "exp", res.back() }, + { "is_ptr", op == operator_t::PTR_MEMBER }, + }; + h.force_parse(parse_identifier, "Expected an identifier.", member_access["name"].map({})); + member_access["location"] = conv::loc_to_map( + conv::map_to_loc(member_access["name"].map()["location"].string()).intersect( + conv::map_to_loc(res.back().map()["location"].string()) + ) + ); + res.pop_back(); + res.push_back(member_access); + } + else if (bin_ops.find(op) != bin_ops.end()) { + auto data = bin_ops[op]; + pop_until(data, h, op_stack, res); + op_stack.push_back({ h.loc(), data }); + + if (data.op_n == 1) { + last_val = true; + if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); + if (h.try_advance()) break; + } + else { + last_val = false; h.advance("Expected a value on the right side of the operator."); } - else break; } - continue; + else break; } - else break; + else { + if (op == operator_t::PAREN_OPEN) { + op_stack.push_back({ h.loc(), { precedence_t::PAREN } }); + h.advance("Expected a value."); + last_val = false; + } + else if (pre_ops.find(op) != pre_ops.end()) { + op_stack.push_back({ h.loc(), pre_ops[op] }); + h.advance("Expected a value on the right side of the operator."); + } + else break; + } + continue; } - - if (res.size() == 0) return false; - - while (!op_stack.empty()) { - if (op_stack.back().precedence == precedence_t::PAREN) throw message_t::error("Unclosed paren.", op_stack.back().location); - if (op_stack.back().precedence == precedence_t::CALL_START) throw message_t::error("Unclosed call.", op_stack.back().location); - if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); - } - - out = res.front().map(); - - return h.submit(false); + else break; } - public: exp_parser_t(): parser_t("$_exp") { } -}; + if (res.size() == 0) return false; -class exp_stat_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &i, map_t &res) const { - tree_helper_t h(ctx, i); - if (!h.parse("$_exp", res)) return false; - if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); - - ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); - return h.submit(false); + while (!op_stack.empty()) { + if (op_stack.back().precedence == precedence_t::PAREN) throw message_t::error("Unclosed paren.", op_stack.back().location); + if (op_stack.back().precedence == precedence_t::CALL_START) throw message_t::error("Unclosed call.", op_stack.back().location); + if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator."); } - public: exp_stat_parser_t() : parser_t("$_exp_stat") { } -}; + out = res.front().map(); -const parser_adder_t ppc::comp::tree::ast::exp_adder = [](ast_ctx_t &ctx) { - ctx.add_parser(new exp_parser_t()); - ctx.add_parser(new exp_stat_parser_t(), "$_stat"); -}; + return h.submit(false); +} +bool ast::parse_stat_exp(ast_ctx_t &ctx, size_t &i, map_t &res) { + tree_helper_t h(ctx, i); + if (!h.parse(parse_exp, res)) return false; + if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); + + ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); + return h.submit(false); +} diff --git a/src/compiler/treeifier/ast/parsers/field.cc b/src/compiler/treeifier/ast/parsers/field.cc index 631faac..d1f335f 100644 --- a/src/compiler/treeifier/ast/parsers/field.cc +++ b/src/compiler/treeifier/ast/parsers/field.cc @@ -1,42 +1,36 @@ #include "compiler/treeifier/ast/helper.hh" -class field_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); +bool ast::parse_field(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + if (h.ended()) return false; - if (!h.parse("$_identifier", out["name"].map({}))) return false; + if (!h.parse(parse_identifier, out["name"].map({}))) return false; - bool type, defval; + bool type, defval; - h.throw_ended("Expected a colon or an equals sign."); + h.throw_ended("Expected a colon or an equals sign."); - if (h.curr().is_operator(operator_t::COLON)) { - h.advance(); - h.force_parse("$_type", "Expected a type.", out["type"].map({})); - type = true; - } - if (h.curr().is_operator(operator_t::ASSIGN)) { - h.advance(); - h.force_parse("$_exp", "Expected an expression.", out["value"].map({})); - type = true; - } - - if (h.curr().is_operator(operator_t::SEMICOLON)) { - if (type || defval) return h.submit(); - else return h.err("A type or a default value must be specified "); - } - else if (type || defval) { - ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); - return h.submit(false); - } - else return false; - - return h.submit(true); + if (h.curr().is_operator(operator_t::COLON)) { + h.advance(); + h.force_parse(parse_type, "Expected a type.", out["type"].map({})); + type = true; + } + if (h.curr().is_operator(operator_t::ASSIGN)) { + h.advance(); + h.force_parse(parse_exp, "Expected an expression.", out["value"].map({})); + type = true; } - public: field_parser_t(): parser_t("$_field") { } -}; + if (h.curr().is_operator(operator_t::SEMICOLON)) { + if (type || defval) return h.submit(); + else return h.err("A type or a default value must be specified "); + } + else if (type || defval) { + ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); + return h.submit(false); + } + else return false; -const parser_adder_t ppc::comp::tree::ast::field_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new field_parser_t(), "$_def"); }; + return h.submit(true); +} diff --git a/src/compiler/treeifier/ast/parsers/func.cc b/src/compiler/treeifier/ast/parsers/func.cc index 1380ce3..ca588a3 100644 --- a/src/compiler/treeifier/ast/parsers/func.cc +++ b/src/compiler/treeifier/ast/parsers/func.cc @@ -1,101 +1,88 @@ #include "compiler/treeifier/ast/helper.hh" -class arg_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); +static bool parse_arg(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + if (h.ended()) return false; - if (!h.parse("$_identifier", out["name"].map({}))) return false; + if (!h.parse(parse_identifier, out["name"].map({}))) return false; - bool type, defval; + bool type, defval; - h.throw_ended("Expected a colon or an equals sign."); + h.throw_ended("Expected a colon or an equals sign."); - if (h.curr().is_operator(operator_t::COLON)) { - h.advance(); - h.force_parse("$_type", "Expected a type.", out["type"].map({})); - type = true; + if (h.curr().is_operator(operator_t::COLON)) { + h.advance(); + h.force_parse(parse_type, "Expected a type.", out["type"].map({})); + type = true; + } + if (h.curr().is_operator(operator_t::ASSIGN)) { + h.advance(); + h.force_parse(parse_exp, "Expected an expression.", out["value"].map({})); + type = true; + } + + if (!type && !defval) { + ctx.messages.push(message_t::error("Expected a type or a default value.", h.loc(1))); + } + + return h.submit(false); +} + +bool ast::parse_func(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); + + if (h.ended()) return false; + + if (!h.parse(parse_identifier, out["name"].map({}))) return false; + if (h.ended()) return false; + if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false; + h.advance("Expected a closing paren or a parameter."); + + auto ¶ms = out["params"].array({}); + auto &content = out["content"].array({}); + + while (true) { + if (h.curr().is_operator(operator_t::PAREN_CLOSE)) { + h.advance("Expected a function body."); + break; } - if (h.curr().is_operator(operator_t::ASSIGN)) { - h.advance(); - h.force_parse("$_exp", "Expected an expression.", out["value"].map({})); - type = true; + h.force_push_parse(parse_arg, "Expected a parameter.", params); + if (h.curr().is_operator(operator_t::COMMA)) { + h.advance("Expected a parameter."); } + } - if (!type && !defval) { - ctx.messages.push(message_t::error("Expected a type or a default value.", h.loc(1))); + if (h.curr().is_operator(operator_t::COLON)) { + h.advance("Expected a type."); + h.force_parse(parse_type, "Expected a type", out["type"].map({})); + } + + if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); + else if (h.curr().is_operator(operator_t::LAMBDA)) { + h.advance("Expected an expression."); + map_t exp; + h.force_parse(parse_exp, "Expected an expression.", exp); + content.push_back({ + { "$_name", "$_return" }, + { "content", exp }, + }); + return h.submit(false); + } + else if (h.curr().is_operator(operator_t::BRACE_OPEN)) { + h.advance("Expected a statement."); + while (true) { + if (h.curr().is_operator(operator_t::BRACE_CLOSE)) { + return h.submit(true); + } + + h.force_push_parse(ctx.group("$_stat"), "Expected an expression.", content); } - + } + else { + ctx.messages.push(message_t::error("Expected a semicolon, brace open or a lambda operator.", h.loc(1))); return h.submit(false); } - public: arg_parser_t(): parser_t("$_func_arg") {} -}; - -class func_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); - - if (h.ended()) return false; - - if (!h.parse("$_identifier", out["name"].map({}))) return false; - if (h.ended()) return false; - if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false; - h.advance("Expected a closing paren or a parameter."); - - auto ¶ms = out["params"].array({}); - auto &content = out["content"].array({}); - - while (true) { - if (h.curr().is_operator(operator_t::PAREN_CLOSE)) { - h.advance("Expected a function body."); - break; - } - h.force_push_parse("$_func_arg", "Expected a parameter.", params); - if (h.curr().is_operator(operator_t::COMMA)) { - h.advance("Expected a parameter."); - } - } - - if (h.curr().is_operator(operator_t::COLON)) { - h.advance("Expected a type."); - h.force_parse("$_type", "Expected a type", out["type"].map({})); - } - - if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); - else if (h.curr().is_operator(operator_t::LAMBDA)) { - h.advance("Expected an expression."); - map_t exp; - h.force_parse("$_exp", "Expected an expression.", exp); - content.push_back({ - { "$_name", "$_return" }, - { "content", exp }, - }); - return h.submit(false); - } - else if (h.curr().is_operator(operator_t::BRACE_OPEN)) { - h.advance("Expected a statement."); - while (true) { - if (h.curr().is_operator(operator_t::BRACE_CLOSE)) { - return h.submit(true); - } - - h.force_push_parse("$_stat", "Expected an expression.", content); - } - } - else { - ctx.messages.push(message_t::error("Expected a semicolon, brace open or a lambda operator.", h.loc(1))); - return h.submit(false); - } - - return h.submit(true); - } - - public: func_parser_t(): parser_t("$_func") { } -}; - -const parser_adder_t ppc::comp::tree::ast::func_adder = [](ast_ctx_t &ctx) { - ctx.add_parser(new func_parser_t(), "$_def"); - ctx.add_parser(new arg_parser_t()); -}; + return h.submit(true); +} diff --git a/src/compiler/treeifier/ast/parsers/glob.cc b/src/compiler/treeifier/ast/parsers/glob.cc index f8ec95c..2b8021a 100644 --- a/src/compiler/treeifier/ast/parsers/glob.cc +++ b/src/compiler/treeifier/ast/parsers/glob.cc @@ -1,88 +1,69 @@ #include "compiler/treeifier/ast.hh" #include "compiler/treeifier/ast/helper.hh" +// #include "./type.cc" using namespace ppc::comp::tree::ast; -class nmsp_def_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const { - tree_helper_t h(ctx, res_i); - if (h.ended()) return false; +static bool nmsp_def(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) { + tree_helper_t h(ctx, res_i); + if (h.ended()) return false; - if (!h.curr().is_identifier("namespace")) return false; - h.advance("Expected a namespace"); - h.force_parse("$_nmsp", "Expected a namespace.", res); - if (!h.curr().is_operator(operator_t::SEMICOLON)) { - ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); - return h.submit(false); - } - return h.submit(true); + if (!h.curr().is_identifier("namespace")) return false; + h.advance("Expected a namespace"); + h.force_parse(parse_nmsp, "Expected a namespace.", res); + if (!h.curr().is_operator(operator_t::SEMICOLON)) { + ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); + return h.submit(false); + } + return h.submit(true); +} +static bool import(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) { + tree_helper_t h(ctx, res_i); + if (h.ended()) return false; + + if (!h.curr().is_identifier("import")) return false; + h.advance("Expected a namespace"); + h.force_parse(parse_nmsp, "Expected a namespace.", res); + if (!h.curr().is_operator(operator_t::SEMICOLON)) { + ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); + return h.submit(false); } - public: nmsp_def_parser_t(): parser_t("$_nmsp") { } -}; -class import_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const { - tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + return h.submit(true); +} - if (!h.curr().is_identifier("import")) return false; - h.advance("Expected a namespace"); - h.force_parse("$_nmsp", "Expected a namespace.", res); - if (!h.curr().is_operator(operator_t::SEMICOLON)) { - ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); - return h.submit(false); - } +bool ast::parse_glob(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) { + tree_helper_t h(ctx, res_i); - return h.submit(true); + if (h.ended()) return true; + if (h.parse(nmsp_def, out["namespace"].map({}))) { + ctx.nmsp = conv::map_to_nmsp(out["namespace"].map()); + } + else { + out["namespace"] = data::null; } - public: import_parser_t(): parser_t("$_import") { } -}; + auto &imports = out["imports"].array({}); + auto &contents = out["content"].array({}); -auto import_parser = import_parser_t(); -auto nmsp_def_parser = nmsp_def_parser_t(); + while (true) { + map_t map; + if (!h.parse(import, map)) break; + imports.push_back(map); + auto nmsp = conv::map_to_nmsp(map); -class glob_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const { - tree_helper_t h(ctx, res_i); - - if (h.ended()) return true; - if (nmsp_def_parser(ctx, h.i, out["namespace"].map({}))) { - ctx.nmsp = conv::map_to_nmsp(out["namespace"].map()); - } - else { - out["namespace"] = data::null; - } - - auto &imports = out["imports"].array({}); - auto &contents = out["content"].array({}); - - while (true) { - map_t map; - if (!import_parser(ctx, h.i, map)) break; - imports.push_back(map); - auto nmsp = conv::map_to_nmsp(map); - - if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported."); - } - - while (true) { - if (h.ended()) break; - if (!h.push_parse("$_def", contents)) { - ctx.messages.push(message_t::error("Invalid token.", h.loc())); - h.i++; - } - } - - if (!h.ended()) h.err("Invalid token."); - - return h.submit(); + if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported."); } -public: - glob_parser_t(): parser_t("$_glob") { } -}; + while (true) { + if (h.ended()) break; + if (!h.push_parse(ctx.group("$_def"), contents)) { + ctx.messages.push(message_t::error("Invalid token.", h.loc())); + h.i++; + } + } -const parser_adder_t ppc::comp::tree::ast::glob_adder = [](ast_ctx_t &ctx) { - ctx.add_parser(new glob_parser_t()); -}; + if (!h.ended()) h.err("Invalid token."); + + return h.submit(); +} diff --git a/src/compiler/treeifier/ast/parsers/group.cc b/src/compiler/treeifier/ast/parsers/group.cc index c52d103..fa12cc2 100644 --- a/src/compiler/treeifier/ast/parsers/group.cc +++ b/src/compiler/treeifier/ast/parsers/group.cc @@ -13,7 +13,7 @@ using namespace std; static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &name) { tree_helper_t h(ctx, i); map_t res; - if (!h.parse("$_nmsp", res)) return false; + if (!h.parse(parse_nmsp, res)) return false; name = conv::map_to_nmsp(res); return true; } @@ -40,8 +40,48 @@ static bool resolve_nmsp(ast_ctx_t &ctx, const lang::namespace_name_t &name, T b return false; } +group_t &group_t::insert(const std::string &name, parser_t parser, const std::string &relative_to, bool after) { + if (parsers.find(name) != parsers.end()) { + throw "The parser '" + name + "' is already in the group."; + } -bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { + auto it = parsers.find(relative_to); + if (it == parsers.end()) { + throw "The parser '" + relative_to + "' isn't in the group."; + } + + if (after) it++; + + parsers.insert(it, { name, parser }); + + return *this; +} +group_t &group_t::replace(const std::string &name, parser_t parser) { + auto it = parsers.find(name); + + if (parsers.find(name) == parsers.end()) { + throw "The parser '" + name + "' isn't in the group."; + } + + it->second = parser; + + return *this; +} +group_t &group_t::add_last(const std::string &name, parser_t parser) { + if (parsers.find(name) != parsers.end()) { + throw "The parser '" + name + "' is already in the group."; + } + + parsers.emplace(name, parser); + + return *this; +} +group_t &group_t::add_named(const std::string &name, parser_t parser, const lang::namespace_name_t &identifier) { + add_last(name, parser); + return *this; +} + +bool group_t::operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { tree_helper_t h(ctx, i); if (h.ended()) return false; @@ -50,8 +90,9 @@ bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { if (read_nmsp(ctx, h.i, name)) { namespace_name_t actual; if (resolve_nmsp(ctx, name.strip_location(), named_parsers.begin(), named_parsers.end(), actual)) { - auto &parser = *this->named_parsers.find(actual)->second; - if (parser(ctx, i, out)) return true; + auto parser = parsers.find(this->named_parsers.find(actual)->second); + out["$_name"] = parser->first; + if (parser->second(ctx, i, out)) return true; else throw message_t::error("Unexpected construct specifier.", h.res_loc()); } } @@ -59,25 +100,11 @@ bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { unordered_map errors; for (auto parser : parsers) { - if ((*parser)(ctx, i, out)) return true; + out["$_name"] = parser.first; + if ((*parser.second)(ctx, i, out)) return true; } stringstream m; return false; } - -group_parser_t &group_parser_t::add(const parser_t &parser) { - parsers.push_back(&parser); - return *this; -} -group_parser_t &group_parser_t::add(const parser_t &parser, const lang::namespace_name_t &name) { - if (name.empty()) throw "Name can't be empty."s; - if (std::find(parsers.begin(), parsers.end(), &parser) != parsers.end()) { - throw "Parser '" + name.to_string() + "' already in group."; - } - - named_parsers[name] = &parser; - - return *this; -} diff --git a/src/compiler/treeifier/ast/parsers/identifier.cc b/src/compiler/treeifier/ast/parsers/identifier.cc index e44eaed..a1119e0 100644 --- a/src/compiler/treeifier/ast/parsers/identifier.cc +++ b/src/compiler/treeifier/ast/parsers/identifier.cc @@ -1,21 +1,15 @@ #include "compiler/treeifier/ast/helper.hh" -class identifier_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); +bool ast::parse_identifier(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + if (h.ended()) return false; - if (h.curr().is_identifier()) { - auto loc = h.loc(); - out["location"] = conv::loc_to_map(loc); - out["content"] = h.curr().identifier(); - return h.submit(); - } - else return false; + if (h.curr().is_identifier()) { + auto loc = h.loc(); + out["location"] = conv::loc_to_map(loc); + out["content"] = h.curr().identifier(); + return h.submit(); } - - public: identifier_parser_t(): parser_t("$_identifier") { } -}; - -const parser_adder_t ppc::comp::tree::ast::identifier_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new identifier_parser_t()); }; + else return false; +} diff --git a/src/compiler/treeifier/ast/parsers/nmsp.cc b/src/compiler/treeifier/ast/parsers/nmsp.cc index 576aec1..13431ad 100644 --- a/src/compiler/treeifier/ast/parsers/nmsp.cc +++ b/src/compiler/treeifier/ast/parsers/nmsp.cc @@ -1,26 +1,20 @@ #include "compiler/treeifier/ast/helper.hh" -class nmsp_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); +bool ast::parse_nmsp(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + if (h.ended()) return false; - auto &arr = (out["content"] = array_t()).array(); + auto &arr = (out["content"] = array_t()).array(); - if (!h.push_parse("$_identifier", arr)) return false; + if (!h.push_parse(parse_identifier, arr)) return false; - while (true) { - if (h.ended()) break; - if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break; - h.force_push_parse("$_identifier", "Expected an identifier.", arr); - } - - out["location"] = conv::loc_to_map(h.res_loc()); - return h.submit(false); + while (true) { + if (h.ended()) break; + if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break; + h.force_push_parse(parse_identifier, "Expected an identifier.", arr); } - public: nmsp_parser_t(): parser_t("$_nmsp") { } -}; - -const parser_adder_t ppc::comp::tree::ast::nmsp_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new nmsp_parser_t()); }; + out["location"] = conv::loc_to_map(h.res_loc()); + return h.submit(false); +} diff --git a/src/compiler/treeifier/ast/parsers/type.cc b/src/compiler/treeifier/ast/parsers/type.cc index 9cc580f..4242a05 100644 --- a/src/compiler/treeifier/ast/parsers/type.cc +++ b/src/compiler/treeifier/ast/parsers/type.cc @@ -1,51 +1,45 @@ #include "compiler/treeifier/ast/helper.hh" -class type_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); +bool ast::parse_type(ast_ctx_t &ctx, size_t &res_i, map_t &out) { + tree_helper_t h(ctx, res_i); - if (h.ended()) return false; + if (h.ended()) return false; - auto &nmsp = (out["namespace"] = map_t()).map(); - nmsp["$_name"] = "$_nmsp"; - auto &nmsp_content = (out["namespace"].map()["content"] = array_t()).array(); - size_t ptr_n = 0; + auto &nmsp = (out["namespace"] = map_t()).map(); + nmsp["$_name"] = "$_nmsp"; + auto &nmsp_content = (out["namespace"].map()["content"] = array_t()).array(); + size_t ptr_n = 0; - if (!h.push_parse("$_identifier", nmsp_content)) return false; + if (!h.push_parse(parse_identifier, nmsp_content)) return false; - while (true) { - if (h.ended()) break; - if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break; - h.advance("Expected an identifier."); - h.force_push_parse("$_identifier", "Expected an identifier.", nmsp_content); - } - - while (!h.ended() && h.curr().is_operator(operator_t::MULTIPLY)) { - ptr_n++; - if (!h.try_advance()) break; - } - - out["location"] = conv::loc_to_map(h.res_loc()); - out["name"] = nmsp_content[nmsp_content.size() - 1]; - out["ptr_n"] = (float)ptr_n; - nmsp_content.pop_back(); - - if (nmsp_content.size() == 0) { - auto loc = h.res_loc(); - loc.length = 1; - nmsp["location"] = conv::loc_to_map(loc); - } - else { - auto loc_1 = conv::map_to_loc(nmsp_content[0].map()["location"].string()); - auto loc_2 = conv::map_to_loc(nmsp_content[nmsp_content.size() - 1].map()["location"].string()); - auto loc = loc_1.intersect(loc_2); - nmsp["location"] = conv::loc_to_map(loc); - } - - return h.submit(false); + while (true) { + if (h.ended()) break; + if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break; + h.advance("Expected an identifier."); + h.force_push_parse(parse_identifier, "Expected an identifier.", nmsp_content); } - public: type_parser_t(): parser_t("$_type") { } -}; + while (!h.ended() && h.curr().is_operator(operator_t::MULTIPLY)) { + ptr_n++; + if (!h.try_advance()) break; + } -const parser_adder_t ppc::comp::tree::ast::type_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new type_parser_t()); }; + out["location"] = conv::loc_to_map(h.res_loc()); + out["name"] = nmsp_content[nmsp_content.size() - 1]; + out["ptr_n"] = (float)ptr_n; + nmsp_content.pop_back(); + + if (nmsp_content.size() == 0) { + auto loc = h.res_loc(); + loc.length = 1; + nmsp["location"] = conv::loc_to_map(loc); + } + else { + auto loc_1 = conv::map_to_loc(nmsp_content[0].map()["location"].string()); + auto loc_2 = conv::map_to_loc(nmsp_content[nmsp_content.size() - 1].map()["location"].string()); + auto loc = loc_1.intersect(loc_2); + nmsp["location"] = conv::loc_to_map(loc); + } + + return h.submit(false); +} diff --git a/src/compiler/treeifier/ast/parsers/var.cc b/src/compiler/treeifier/ast/parsers/var.cc deleted file mode 100644 index 4d3a8e0..0000000 --- a/src/compiler/treeifier/ast/parsers/var.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include "compiler/treeifier/ast/helper.hh" - -class var_parser_t : public parser_t { - bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { - tree_helper_t h(ctx, res_i); - - if (h.curr().is_identifier()) { - out["content"] = h.curr().identifier(); - out["location"] = conv::loc_to_map(h.loc()); - return h.submit(true); - } - - return false; - } - - public: var_parser_t(): parser_t("$_var") { } -}; - -const parser_adder_t ppc::comp::tree::ast::var_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new var_parser_t(), "$_exp_val"); }; diff --git a/src/compiler/treeifier/tokenizer.cc b/src/compiler/treeifier/tokenizer.cc index 763aab1..ecda2d1 100644 --- a/src/compiler/treeifier/tokenizer.cc +++ b/src/compiler/treeifier/tokenizer.cc @@ -1,4 +1,5 @@ #include +#include #include "compiler/treeifier/tokenizer.hh" #include "compiler/treeifier/lexer.hh" @@ -7,12 +8,12 @@ using namespace messages; using namespace comp::tree; using namespace std::string_literals; -static std::vector parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) { +static std::vector parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) { char literal_char = is_char ? '\'' : '"'; bool escaping = false; - std::vector res; + std::vector res; location_t curr_char_loc = token.location; curr_char_loc.length = 1; curr_char_loc.start++; @@ -52,96 +53,99 @@ static std::vector parse_string(msg_stack_t &msg_stack, bool is_char, cons 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 token_t parse_int(msg_stack_t &msg_stack, const lex::token_t &token) { - enum radix_t { - BINARY, - OCTAL, - DECIMAL, - HEXADECIMAL, - } radix; - std::size_t i = 0; +static std::vector parse_bin(msg_stack_t &msg_stack, size_t i, const std::string &data) { + std::vector res; + int last_byte = 0; + int lastbyte_n = 0; + + for (size_t j = data.length() - 1; j >= i; j--) { + if (lastbyte_n == 8) { + lastbyte_n = 0; + res.push_back(last_byte); + last_byte = 0; + } + + last_byte <<= 1; + last_byte |= data[j] - '0'; + lastbyte_n++; + } + + res.push_back(last_byte); + std::reverse(res.begin(), res.end()); + + return res; +} +static std::vector parse_hex(msg_stack_t &msg_stack, size_t i, const std::string &data) { + std::vector res; + + int last_byte = 0; + int lastbyte_n = 0; + + for (size_t j = data.length() - 1; j >= i; j--) { + if (lastbyte_n == 8) { + lastbyte_n = 0; + res.push_back(last_byte); + last_byte = 0; + } + + int digit = data[j] - '0'; + if (data[j] >= 'a' && data[j] <= 'f') digit = data[j] - 'a' + 10; + if (data[j] >= 'A' && data[j] <= 'F') digit = data[j] - 'F' + 10; + + last_byte <<= 4; + last_byte |= digit; + lastbyte_n += 4; + } + + res.push_back(last_byte); + std::reverse(res.begin(), res.end()); + + return res; +} +static std::vector parse_oct(msg_stack_t &msg_stack, size_t i, const std::string &data) { + std::vector res; + + int last_byte = 0; + int lastbyte_n = 0; + + for (size_t j = data.length() - 1; j >= i; j--) { + if (lastbyte_n >= 8) { + lastbyte_n = 0; + res.push_back(last_byte); + last_byte >>= 8; + } + + int digit = data[j] - '0'; + + last_byte <<= 3; + last_byte |= digit; + lastbyte_n += 3; + } + + res.push_back(last_byte); + std::reverse(res.begin(), res.end()); + + return res; +} + +static std::vector parse_int(msg_stack_t &msg_stack, const lex::token_t &token) { switch (token.type) { case lex::token_t::BIN_LITERAL: - i += 2; - radix = BINARY; - break; + return parse_bin(msg_stack, 2, token.data); case lex::token_t::OCT_LITERAL: - i++; - radix = OCTAL; - break; + return parse_oct(msg_stack, 1, token.data); case lex::token_t::DEC_LITERAL: - radix = DECIMAL; - break; + throw "no dec literals lol bozo."s; case lex::token_t::HEX_LITERAL: - i += 2; - radix = HEXADECIMAL; - break; + return parse_hex(msg_stack, 2, token.data); default: throw "WTF r u doing bro?"s; } - - uint64_t res = 0; - - for (; i <= token.data.length() - 1; i++) { - char c = token.data[i]; - int8_t digit; - switch (radix) { - case BINARY: - digit = c - '0'; - res <<= 1; - res |= digit; - break; - case OCTAL: - digit = c - '0'; - if (digit < 0 || digit > 7) { - throw message_t(message_t::ERROR, "Octal literals may contain numbers between 0 and 7.", token.location); - } - res <<= 3; - res |= digit; - break; - case 2: - digit = c - '0'; - res *= 10; - res += digit; - break; - case 3: - if (c >= 'a' && c <= 'f') digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10; - else if (c >= '0' && c <= '9') digit = c - '0'; - else throw message_t(message_t::ERROR, "Invalid character '"s + c + "' in hex literal.", token.location); - res <<= 4; - res |= digit; - break; - } - } - - return token_t(res, token.location); } -static token_t parse_float(msg_stack_t &msg_stack, const lex::token_t &token) { - double whole = 0, fract = 0; - - char c; - std::size_t i; - - for (i = 0; i < token.data.length() && isdigit(c = token.data[i]); i++) { - if (c == '.') break; - int digit = c - '0'; - whole *= 10; - whole += digit; - } - - if (c == '.') { - i++; - for (; i < token.data.length() && isdigit(c = token.data[i]); i++) { - int digit = c - '0'; - fract += digit; - fract /= 10; - } - } - - return token_t(whole + fract, token.location); +static std::vector parse_float(msg_stack_t &msg_stack, const lex::token_t &token) { + throw "no floats lol bozo"s; } token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) { @@ -160,16 +164,13 @@ token_t token_t::parse(messages::msg_stack_t &msg_stack, lex::token_t in) { case lex::token_t::OCT_LITERAL: case lex::token_t::DEC_LITERAL: case lex::token_t::HEX_LITERAL: - return parse_int(msg_stack, in); + return { parse_int(msg_stack, in), in.location }; case lex::token_t::FLOAT_LITERAL: - return parse_float(msg_stack, in); + return { parse_float(msg_stack, in), in.location }; case lex::token_t::STRING_LITERAL: - return { parse_string(msg_stack, false, in) }; - case lex::token_t::CHAR_LITERAL: { - auto str = parse_string(msg_stack, true, in); - if (str.size() != 1) throw message_t(message_t::ERROR, "Char literal must consist of just one character.", in.location); - return str.front(); - } + return { parse_string(msg_stack, false, in), in.location }; + case lex::token_t::CHAR_LITERAL: + return { parse_string(msg_stack, true, in), in.location }; default: throw message_t(message_t::ERROR, "Token type not recognised.", in.location); } diff --git a/src/main/main.cc b/src/main/main.cc index b7d6f08..2f4ec65 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -157,7 +157,7 @@ int main(int argc, const char *argv[]) { try { std::ifstream f { file, std::ios_base::in }; auto tokens = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f)); - auto ast = ast_ctx_t::parse(msg_stack, tokens); + auto ast = ast_ctx_t::parse(ast::parse_glob, msg_stack, tokens); std::cout << data::json::stringify(ast) << std::endl; }