#ifndef CTLL__GRAMMARS__HPP #define CTLL__GRAMMARS__HPP namespace ctll { // terminal type representing symbol / character of any type template struct term { static constexpr auto value = v; }; // epsilon = nothing on input tape // also used as an command for parsing means "do nothing" struct epsilon { static constexpr auto value = '-'; }; // empty_stack_symbol = nothing on stack struct empty_stack_symbol {}; // push is alias to list template using push = list; // accept/reject type for controlling output of LL1 machine struct accept { constexpr explicit operator bool() noexcept { return true; } }; struct reject { constexpr explicit operator bool() noexcept { return false; } }; // action type, every action item in grammar must inherit from struct action { struct action_tag { }; }; // move one character forward and pop it from stack command struct pop_input { struct pop_input_tag { }; }; // additional overloads for type list template constexpr auto push_front(pop_input, list) -> list { return {}; } template constexpr auto push_front(epsilon, list) -> list { return {}; } template constexpr auto push_front(list, list) -> list { return {}; } template constexpr auto pop_front_and_push_front(T item, list l) { return push_front(item, pop_front(l)); } // SPECIAL matching types for nicer grammars // match any term struct anything { constexpr inline anything() noexcept { } template constexpr anything(term) noexcept; }; // match range of term A-B template struct range { constexpr inline range() noexcept { } //template constexpr range(term) noexcept requires (A <= V) && (V <= B); template > constexpr range(term) noexcept; }; #ifdef __EDG__ template struct contains { static constexpr bool value = ((Set == V) || ... || false); }; #endif // match terms defined in set template struct set { constexpr inline set() noexcept { } #ifdef __EDG__ template ::value>> constexpr set(term) noexcept; #else template > constexpr set(term) noexcept; #endif }; // match terms not defined in set template struct neg_set { constexpr inline neg_set() noexcept { } #ifdef __EDG__ template ::value>> constexpr neg_set(term) noexcept; #else template > constexpr neg_set(term) noexcept; #endif }; // AUGMENTED grammar which completes user-defined grammar for all other cases template struct augment_grammar: public Grammar { // start nonterminal is defined in parent type using typename Grammar::_start; // grammar rules are inherited from Grammar parent type using Grammar::rule; // term on stack and on input means pop_input; template static constexpr auto rule(term, term) -> ctll::pop_input; // if the type on stack (range, set, neg_set, anything) is constructible from the terminal => pop_input template static constexpr auto rule(Expected, term) -> std::enable_if_t>, ctll::pop_input>; // empty stack and empty input means we are accepting static constexpr auto rule(empty_stack_symbol, epsilon) -> ctll::accept; // not matching anything else => reject static constexpr auto rule(...) -> ctll::reject; // start stack is just a list; using start_stack = list; }; } #endif