From: TimePath Date: Sat, 16 Sep 2017 03:09:39 +0000 (+1000) Subject: Stuff X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=1a1fe84ea5d1b816e15ad30a8c552f7a9cadaa40;p=xonotic%2Fgmqcc.git Stuff --- diff --git a/parser2.cpp b/parser2.cpp index 77a2695..227d775 100644 --- a/parser2.cpp +++ b/parser2.cpp @@ -1,6 +1,130 @@ #include "parser.h" #include +#include + + +/* + * have a tape stack for pushing assigning CST nodes to as they are completed + * have a templated destructor wrapper serving double duty as a destructor + union discriminant + * reset the stack on error, destroying everything as needed + * on completion of some nodes (if, while, for, etc -- probably everything but expressions) + * take all prior parameters and produce some kind of AST node + * is there a way to convert from a pointer to a destructor impl to its size? need a size for traversing the stack + * + */ + +template +void destructor(void *v) { + reinterpret_cast(v)->~T(); +} + +class stack_t { + using byte = std::uint8_t; + using destructor_t = void (&)(void *it); + + struct entry_t { + stack_t *owner; + std::size_t size; + std::size_t offset; + destructor_t dtor; + + entry_t() : entry_t(nullptr, static_cast(0), static_cast(0), destructor) {} + + entry_t(stack_t *owner, std::size_t size, std::size_t offset, destructor_t dtor) : owner(owner), + size(size), + offset(offset), + dtor(dtor) {} + + ~entry_t() { + auto self = this; + printf("%p\n", self); + auto &stack = owner->stack; + auto ptr = &stack[offset]; + printf("DELETE AT %p with %p\n", &stack[offset], dtor); + dtor(reinterpret_cast(ptr)); + } + }; + + std::vector entries; + std::vector stack; + +public: + + using size_t = struct { + size_t entries; + size_t stack; + }; + + size_t size() { + return {entries.size(), stack.size()}; + } + + std::size_t sizeat(std::size_t i) { + return entries[i].size; + } + + void resize(size_t sp) { + entries.resize(sp.entries); + stack.resize(sp.stack); + } + + template + void push(T &&it) { + auto size = sizeof(T); + auto offset = stack.size(); + stack.resize(offset + size); + new(&stack[offset]) T(std::move(it)); + auto &dtor = destructor; + printf("MADE AT %p with %p\n", &stack[offset], dtor); + entries.emplace_back(this, size, offset, dtor); + } + + void pop() { + auto size = entries.back().size; + entries.pop_back(); + stack.resize(stack.size() - size); + } + +}; + +template +T exchange(T &obj, U &&new_value) { + T old_value = std::move(obj); + obj = std::forward(new_value); + return old_value; +} + +//void never() { +// struct test { +// std::uint8_t okay; +// std::uint8_t *x; +// +// test() { +// this->x = new std::uint8_t; +// this->okay = 47; +// printf("allocated %p\n", this->x); +// } +// +// test(test &&o) : x(exchange(o.x, nullptr)), okay(o.okay) { +// printf("stole from %p into %p\n", &o, this); +// } +// +// ~test() { +// printf("bye %p\n", this); +// delete this->x; +// } +// }; +// auto d2 = destructor; +// printf("dtor %p\n", d2); +// { +//// auto it = test{}; +//// printf("pushing: %p\n", &it); +//// stack.push(std::move(it)); +//// stack.pop(); +// } +// printf("over\n"); +//} // fixme: register typedef'd types. this wouldn't matter if parameters required names // defeated by a mere for (i = 0; i < n; ++i) @@ -65,6 +189,7 @@ struct memo_t { size_t peekpos; size_t line, column; size_t idx; + stack_t::size_t sp; }; struct ctx_t { @@ -72,13 +197,17 @@ struct ctx_t { lex_file &lex; Token tok; + stack_t stack = {}; + + std::map typedefs; + explicit ctx_t(parser_t &parser) : parser(parser), lex(*parser.lex) { tok = Token::NONE; } memo_t memo() { auto idx = lex.file ? ftell(lex.file) : lex.open_string_pos; - return memo_t{lex.tok, lex.peek, lex.peekpos, lex.line, lex.column, idx}; + return memo_t{lex.tok, lex.peek, lex.peekpos, lex.line, lex.column, idx, stack.size()}; } void memo(memo_t memo) { @@ -93,6 +222,7 @@ struct ctx_t { } else if (lex.open_string) { lex.open_string_pos = memo.idx; } + stack.resize(memo.sp); } void next() { @@ -142,11 +272,40 @@ private: static bool parser_compile(ctx_t &&ctx); +using Rule = Result(ctx_t &ctx); + namespace parse { + Result dummy_result() { + return Result::OK; + } + + template + auto rule_do(ctx_t &ctx) -> decltype(R::act(ctx, {}, {}, static_cast(nullptr), 0), dummy_result()) { + auto begin = ctx.stack.size(); + ctx.rule_enter(R::name); + auto ret = R::call(ctx); + ctx.rule_leave(R::name, ret); + if (ret) { + auto end = ctx.stack.size(); + end.stack -= ctx.stack.sizeat(end.entries -= 1); + R::act(ctx, begin, end, static_cast(nullptr), 0); + } + return ret; + } + #define RULE(rule) \ -static Result rule(ctx_t &ctx) { ctx.rule_enter(#rule); auto ret = do_##rule(ctx); ctx.rule_leave(#rule, ret); return ret; } \ -static Result do_##rule(ctx_t &ctx) +struct rule##_traits { \ + static constexpr const char *name = #rule; \ + static Result call(ctx_t &ctx) { return impl_##rule##_fn(ctx); } \ + template static auto act(ctx_t &ctx, stack_t::size_t begin, stack_t::size_t end, G*, int) -> decltype(G::act_##rule(ctx, begin, end), void()) { G::act_##rule(ctx, begin, end); } \ + template static auto act(ctx_t&, stack_t::size_t, stack_t::size_t, G*, long) -> decltype(void()) { } \ +}; \ +static Result rule(ctx_t &ctx) { return parse::rule_do(ctx); } \ +static Result impl_##rule##_fn(ctx_t &ctx) + +#define ACTION(rule) \ +static void act_##rule(ctx_t &ctx, stack_t::size_t begin, stack_t::size_t end) #define TRY(...) do { \ auto ret = __VA_ARGS__; \ @@ -183,7 +342,7 @@ static Result do_##rule(ctx_t &ctx) } } -using Rule = Result(ctx_t &ctx); +namespace utils { #define BT() ERR("BT") @@ -289,6 +448,19 @@ Result leftop(ctx_t &ctx) { return sep(ctx); } +template +Result when(ctx_t &ctx) { + auto ret = rule(ctx); + if (ret) { + (*static_cast(nullptr))(ctx); + } + return ret; +} + +} + +using namespace utils; + struct grammar { static constexpr auto Void = lit; @@ -333,12 +505,19 @@ struct grammar { OK(); } + ACTION(compilationUnit) { + printf("DONE!\n"); + } + /// : externalDeclaration+ RULE(translationUnit) { TRY(CROSS(externalDeclaration)(ctx)); OK(); } + struct externalDeclaration_declaration { + }; + /// : pragma /// | functionDefinition /// | declaration @@ -355,6 +534,16 @@ struct grammar { OK(); } + ACTION(declaration) { + printf("START %d\n", begin); + ctx.stack.push(externalDeclaration_declaration{}); + } + + ACTION(externalDeclaration) { + + printf("FINISH %d\n", begin); + } + RULE(pragma) { EXPECT(Token::HASH); if (ACCEPT_IDENT("pragma")) { @@ -385,6 +574,14 @@ struct grammar { OK(); } + struct attribute_alias { + }; + + struct attribute_eraseable { + }; + + struct attribute_accumulate { + }; /// : '[[' X ']]' RULE(attribute) { @@ -393,8 +590,11 @@ struct grammar { EXPECT(Token::PAREN_OPEN); TRY(CROSS(tok)(ctx)); EXPECT(Token::PAREN_CLOSE); + ctx.stack.push(attribute_alias{}); } else if (ACCEPT_IDENT("eraseable")) { + ctx.stack.push(attribute_eraseable{}); } else if (ACCEPT_IDENT("accumulate")) { + ctx.stack.push(attribute_accumulate{}); } else { ERR("unknown attribute '" + STRING() + "'"); } @@ -402,6 +602,9 @@ struct grammar { OK(); } + struct storageClass_typedef { + }; + /// : 'typedef' /// | 'extern' /// | 'static' @@ -409,8 +612,11 @@ struct grammar { /// | 'local' # legacy /// | 'var' # legacy RULE(storageClassSpecifier) { + static auto handleTypedef = [](ctx_t &ctx) { + ctx.stack.push(storageClass_typedef{}); + }; TRY(alt< - Typedef, + when, Extern, Static, Noref, @@ -448,8 +654,18 @@ struct grammar { /// : Identifier RULE(typedefName) { - TRY(tok(ctx)); - OK(); + if (ACCEPT(Token::TYPENAME)) { + OK(); + } + if (PEEK() == Token::IDENT) { + auto typedefs = ctx.typedefs; + auto td = typedefs.find(std::string(STRING())); + if (td != typedefs.end()) { + ctx.next(); + OK(); + } + } + BT(); } /// : 'const' @@ -512,6 +728,14 @@ struct grammar { TRY(declarationSpecifiers(ctx)); TRY(OPT(initDeclaratorList)(ctx)); TRY(tok(ctx)); + + // we're done, might have to register a typedef +// auto typedefs = ctx.typedefs; +// auto td = typedefs.find(std::string(STRING())); +// if (td != typedefs.end()) { +// ctx.next(); +// OK(); +// } OK(); }