AST building #2
2
Makefile
2
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
|
||||
|
@ -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<lang::namespace_name_t, std::string> named_parsers;
|
||||
std::map<std::string, parser_t> 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<std::string, const parser_t*> parsers;
|
||||
std::set<group_parser_t*> groups;
|
||||
std::unordered_map<std::string, group_t> groups;
|
||||
public:
|
||||
msg_stack_t &messages;
|
||||
std::vector<token_t> &tokens;
|
||||
std::set<loc_namespace_name_t> 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 <class T>
|
||||
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<token_t> &tokens);
|
||||
group_t &group(const std::string &name);
|
||||
|
||||
~ast_ctx_t();
|
||||
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &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 <class T>
|
||||
static data::map_t parse(const T &glob, msg_stack_t &messages, std::vector<token_t> &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<lang::namespace_name_t, const parser_t*> named_parsers;
|
||||
std::vector<const parser_t*> 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<token_t> &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;
|
||||
}
|
@ -104,25 +104,28 @@ namespace ppc::comp::tree::ast {
|
||||
throw_ended(reason);
|
||||
}
|
||||
|
||||
bool push_parse(const std::string &name, data::array_t &out) {
|
||||
template <class T>
|
||||
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 <class T>
|
||||
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 <class T>
|
||||
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 <class T>
|
||||
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);
|
||||
|
@ -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<char> *string_literal;
|
||||
std::vector<uint8_t> *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<char> &val, location_t loc = location_t::NONE): location(loc) {
|
||||
kind = STRING;
|
||||
data.string_literal = new std::vector<char> { val };
|
||||
token_t(const std::vector<uint8_t> &val, location_t loc = location_t::NONE): location(loc) {
|
||||
kind = LITERAL;
|
||||
data.literal = new std::vector<uint8_t> { 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<char> { *tok.data.string_literal }; break;
|
||||
case LITERAL: data.literal = new std::vector<uint8_t> { *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;
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
#include "compiler/treeifier/ast.hh"
|
||||
|
||||
namespace ppc::comp::tree::ast {
|
||||
std::unordered_map<std::string, group_parser_t> 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<token_t> &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);
|
||||
}
|
||||
}
|
||||
|
24
src/compiler/treeifier/ast/ast.cc
Normal file
24
src/compiler/treeifier/ast/ast.cc
Normal file
@ -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<token_t> &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);
|
||||
}
|
0
src/compiler/treeifier/ast/parsers.cc
Normal file
0
src/compiler/treeifier/ast/parsers.cc
Normal file
@ -51,251 +51,261 @@ std::map<operator_t, op_data_t> bin_ops {
|
||||
{ (operator_t)-1, sizeof_data },
|
||||
};
|
||||
|
||||
class exp_parser_t : public parser_t {
|
||||
map_t op_to_map(located_t<op_data_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_data_t> op) {
|
||||
return {
|
||||
{ "$_name", "$_operator" },
|
||||
{ "ops", array_t() },
|
||||
{ "location", conv::loc_to_map(op.location) },
|
||||
{ "op", op.name },
|
||||
};
|
||||
}
|
||||
|
||||
bool pop(std::vector<located_t<op_data_t>> &op_stack, array_t &res) const {
|
||||
if (op_stack.empty()) return false;
|
||||
bool pop(std::vector<located_t<op_data_t>> &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<located_t<op_data_t>> &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<located_t<op_data_t>> &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<located_t<op_data_t>> &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<located_t<op_data_t>> &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<located_t<op_data_t>> &op_stack, array_t &res) {
|
||||
map_t call = {
|
||||
{ "$_name", "$_call" },
|
||||
};
|
||||
|
||||
bool last_val = false;
|
||||
map_t val;
|
||||
std::vector<located_t<op_data_t>> op_stack;
|
||||
std::vector<size_t> 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<located_t<op_data_t>> &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<located_t<op_data_t>> op_stack;
|
||||
std::vector<size_t> 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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<string, message_t> 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"); };
|
@ -1,4 +1,5 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#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<char> parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) {
|
||||
static std::vector<uint8_t> 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<char> res;
|
||||
std::vector<uint8_t> res;
|
||||
location_t curr_char_loc = token.location;
|
||||
curr_char_loc.length = 1;
|
||||
curr_char_loc.start++;
|
||||
@ -52,96 +53,99 @@ static std::vector<char> 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<uint8_t> parse_bin(msg_stack_t &msg_stack, size_t i, const std::string &data) {
|
||||
std::vector<uint8_t> 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<uint8_t> parse_hex(msg_stack_t &msg_stack, size_t i, const std::string &data) {
|
||||
std::vector<uint8_t> 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<uint8_t> parse_oct(msg_stack_t &msg_stack, size_t i, const std::string &data) {
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user