55#include " list.hpp"
66#include " grammars.hpp"
77#include " actions.hpp"
8+
89#include < limits>
910
1011namespace ctll {
@@ -16,19 +17,47 @@ enum class decision {
1617 undecided
1718};
1819
19- template <typename T> void id (T);
20-
2120struct placeholder { };
2221
22+ template <size_t > using index_placeholder = placeholder;
23+
24+ #ifdef EXPERIMENTAL_GCC_9
25+ template <size_t , typename , typename Subject, decision Decision> struct results {
26+ constexpr operator bool () const noexcept {
27+ return Decision == decision::accept;
28+ }
29+ using output_type = Subject;
30+ };
31+ #endif
32+
33+
2334#if !__cpp_nontype_template_parameter_class
2435template <typename Grammar, const auto & input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false > struct parser {
2536#else
26- template <typename Grammar, basic_fixed_string input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = true > struct parser { // in c++20
37+ template <typename Grammar, ctll:: basic_fixed_string input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false > struct parser { // in c++20
2738#endif
2839 using Actions = ctll::conditional<IgnoreUnknownActions, ignore_unknown<ActionSelector>, identity<ActionSelector>>;
29- static inline constexpr auto grammar = augment_grammar<Grammar>() ;
40+ using grammar = augment_grammar<Grammar>;
3041
31- template <size_t Pos, typename Stack = void , typename Subject = void , decision Decision = decision::undecided> struct seed ;
42+ #ifndef EXPERIMENTAL_GCC_9
43+ template <size_t Pos, typename Stack, typename Subject, decision Decision> struct results {
44+ constexpr inline CTLL_FORCE_INLINE operator bool () const noexcept {
45+ return Decision == decision::accept;
46+ }
47+
48+ using output_type = Subject;
49+
50+ constexpr auto operator +(placeholder) const noexcept {
51+ if constexpr (Decision == decision::undecided) {
52+ // parse for current char (RPos) with previous stack and subject :)
53+ return decide<Pos, Stack, Subject>({}, {});
54+ } else {
55+ // if there is decision already => just push it to the end of fold expression
56+ return *this ;
57+ }
58+ }
59+ };
60+ #endif
3261
3362 template <size_t Pos> static constexpr auto get_current_term () noexcept {
3463 if constexpr (Pos < input.size ()) {
@@ -38,6 +67,7 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
3867 } else {
3968 return term<input[Pos]>{};
4069 }
70+
4171 } else {
4272 // return epsilon if we are past the input
4373 return epsilon{};
@@ -48,29 +78,38 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
4878 // there is no previous character on input if we are on start
4979 return epsilon{};
5080 } else if constexpr ((Pos-1 ) < input.size ()) {
51- return term<input[Pos-1 ]>{};
81+ constexpr auto value = input[Pos-1 ];
82+ if constexpr (value <= std::numeric_limits<char >::max ()) {
83+ return term<static_cast <char >(value)>{};
84+ } else {
85+ return term<input[Pos]>{};
86+ }
5287 } else {
5388 return epsilon{};
5489 }
5590 }
5691 // if rule is accept => return true and subject
5792 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
5893 static constexpr auto move (ctll::accept, Terminal, Stack, Subject) noexcept {
59- return seed <Pos, Stack, Subject, decision::accept>();
94+ return results <Pos, Stack, Subject, decision::accept>();
6095 }
6196 // if rule is reject => return false and subject
6297 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
6398 static constexpr auto move (ctll::reject, Terminal, Stack, Subject) noexcept {
64- return seed <Pos, Stack, Subject, decision::reject>();
99+ return results <Pos, Stack, Subject, decision::reject>();
65100 }
66101 // if rule is pop_input => move to next character
67102 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
68103 static constexpr auto move (ctll::pop_input, Terminal, Stack, Subject) noexcept {
69- return seed<Pos+1 , Stack, Subject, decision::undecided>();
104+ #ifdef EXPERIMENTAL_GCC_9
105+ return decide<Pos+1 >(Stack (), Subject ());
106+ #else
107+ return results<Pos+1 , Stack, Subject, decision::undecided>();
108+ #endif
70109 }
71110 // if rule is string => push it to the front of stack
72111 template <size_t Pos, typename ... Content, typename Terminal, typename Stack, typename Subject>
73- static constexpr auto move (ctll:: push<Content...> string, Terminal, Stack stack, Subject subject) noexcept {
112+ static constexpr auto move (push<Content...> string, Terminal, Stack stack, Subject subject) noexcept {
74113 return decide<Pos>(push_front (string, stack), subject);
75114 }
76115 // if rule is epsilon (empty string) => continue
@@ -81,14 +120,22 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
81120 // if rule is string with current character at the beginning (term<V>) => move to next character
82121 // and push string without the character (quick LL(1))
83122 template <size_t Pos, auto V, typename ... Content, typename Stack, typename Subject>
84- static constexpr auto move (ctll::push<term<V>, Content...>, term<V>, Stack stack, Subject) noexcept {
85- return seed<Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>();
123+ static constexpr auto move (push<term<V>, Content...>, term<V>, Stack stack, Subject) noexcept {
124+ #ifdef EXPERIMENTAL_GCC_9
125+ return decide<Pos+1 >(push_front (list<Content...>(), stack), Subject ());
126+ #else
127+ return results<Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>();
128+ #endif
86129 }
87130 // if rule is string with any character at the beginning (compatible with current term<T>) => move to next character
88131 // and push string without the character (quick LL(1))
89132 template <size_t Pos, auto V, typename ... Content, auto T, typename Stack, typename Subject>
90- static constexpr auto move (ctll::push<anything, Content...>, term<T>, Stack stack, Subject) noexcept {
91- return seed<Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>();
133+ static constexpr auto move (push<anything, Content...>, term<T>, Stack stack, Subject) noexcept {
134+ #ifdef EXPERIMENTAL_GCC_9
135+ return decide<Pos+1 >(push_front (list<Content...>(), stack), Subject ());
136+ #else
137+ return results<Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>();
138+ #endif
92139 }
93140 // decide if we need to take action or move
94141 template <size_t Pos, typename Stack, typename Subject> static constexpr auto decide (Stack previous_stack, Subject previous_subject) noexcept {
@@ -103,50 +150,28 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
103150
104151 // in case that semantic action is error => reject input
105152 if constexpr (std::is_same_v<ctll::reject, decltype (subject)>) {
106- return seed<Pos, Stack, Subject, decision::reject>();
153+ #ifndef EXPERIMENTAL_GCC_9
154+ return results<Pos, Stack, Subject, decision::reject>();
155+ #else
156+ return results<Pos, Stack, Subject, decision::reject>();
157+ #endif
107158 } else {
108159 return decide<Pos>(stack, subject);
109160 }
110161 } else {
111162 // all other cases are ordinary for LL(1) parser
112163 auto current_term = get_current_term<Pos>();
113- auto rule = decltype (grammar. rule (top_symbol,current_term))();
164+ auto rule = decltype (grammar:: rule (top_symbol,current_term))();
114165 return move<Pos>(rule, current_term, stack, previous_subject);
115166 }
116167 }
117- // helper type for trampoline
118-
119- template <size_t Pos, typename Stack, typename Subject, decision Decision> struct seed {
120- constexpr inline CTLL_FORCE_INLINE operator bool () const noexcept {
121- return Decision == decision::accept;
122- }
123-
124- using output_type = Subject;
125-
126- static constexpr auto parse () noexcept {
127- // push current position to decide function with current stack and subject
128- return decide<Pos>(Stack{}, Subject{});
129- }
130-
131- constexpr auto operator +(placeholder) const noexcept {
132- if constexpr (Decision == decision::undecided) {
133- // parse for current char (RPos) with previous stack and subject :)
134- return decltype (seed<Pos, Stack, Subject, Decision>::parse ()){};
135- } else {
136- // if there is decision already => just push it to the end of fold expression
137- return *this ;
138- }
139- }
140- };
141-
142- template <size_t > using index_placeholder = placeholder;
143168
169+ #ifndef EXPERIMENTAL_GCC_9
144170 // trampolines with folded expression
145171 template <typename Subject, size_t ... Pos> static constexpr auto trampoline_decide (Subject, std::index_sequence<Pos...>) noexcept {
146172 // parse everything for first char and than for next and next ...
147173 // Pos+1 is needed as we want to finish calculation with epsilons on stack
148- auto v = (seed<0 , decltype (grammar.start_stack ), Subject, decision::undecided>::parse () + ... + index_placeholder<Pos+1 >());
149- // id(v);
174+ auto v = (decide<0 , typename grammar::start_stack, Subject>({}, {}) + ... + index_placeholder<Pos+1 >());
150175 return v;
151176 }
152177
@@ -156,8 +181,14 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
156181 }
157182
158183 template <typename Subject = empty_subject> using output = decltype (trampoline_decide<Subject>());
159- static inline constexpr bool correct = trampoline_decide( empty_subject() );
184+ static inline constexpr bool correct = trampoline_decide< empty_subject>( );
160185 template <typename Subject = empty_subject> static inline constexpr bool correct_with = trampoline_decide<Subject>();
186+ #else
187+ template <typename Subject = empty_subject> using output = decltype (decide<0 , typename grammar::start_stack, Subject>({}, {}));
188+ static inline constexpr bool correct = decide<0 , typename grammar::start_stack, empty_subject>({}, {});
189+ template <typename Subject = empty_subject> static inline constexpr bool correct_with = decide<0 , typename grammar::start_stack, Subject>({}, {});
190+ #endif
191+
161192};
162193
163194} // end of ctll namespace
0 commit comments