Commit 59b221cb authored by Dominik Charousset's avatar Dominik Charousset

Add fsm_transition utility to DSL for FSM

parent d4cf1f7a
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <cstring> #include <cstring>
#include "caf/detail/pp.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -59,15 +61,18 @@ extern const char octal_chars[9]; ...@@ -59,15 +61,18 @@ extern const char octal_chars[9];
ps.code = mismatch_ec; \ ps.code = mismatch_ec; \
return; return;
/// Starts the definition of an FSM.
#define start() \ #define start() \
char ch = ps.current(); \ char ch = ps.current(); \
goto s_init; \ goto s_init; \
s_unexpected_eof: \ s_unexpected_eof: \
__attribute__((unused)); \
ps.code = ec::unexpected_eof; \ ps.code = ec::unexpected_eof; \
return; \ return; \
{ \ { \
static constexpr ec mismatch_ec = ec::unexpected_character static constexpr ec mismatch_ec = ec::unexpected_character
/// Defines a non-terminal state in the FSM.
#define state(name) \ #define state(name) \
CAF_FSM_EVAL_MISMATCH_EC \ CAF_FSM_EVAL_MISMATCH_EC \
} \ } \
...@@ -78,6 +83,7 @@ extern const char octal_chars[9]; ...@@ -78,6 +83,7 @@ extern const char octal_chars[9];
goto s_unexpected_eof; \ goto s_unexpected_eof; \
e_##name : __attribute__((unused)); e_##name : __attribute__((unused));
/// Defines a terminal state in the FSM.
#define term_state(name) \ #define term_state(name) \
CAF_FSM_EVAL_MISMATCH_EC \ CAF_FSM_EVAL_MISMATCH_EC \
} \ } \
...@@ -88,6 +94,7 @@ extern const char octal_chars[9]; ...@@ -88,6 +94,7 @@ extern const char octal_chars[9];
goto s_fin; \ goto s_fin; \
e_##name : __attribute__((unused)); e_##name : __attribute__((unused));
/// Ends the definition of an FSM.
#define fin() \ #define fin() \
CAF_FSM_EVAL_MISMATCH_EC \ CAF_FSM_EVAL_MISMATCH_EC \
} \ } \
...@@ -171,6 +178,44 @@ extern const char octal_chars[9]; ...@@ -171,6 +178,44 @@ extern const char octal_chars[9];
epsilon(__VA_ARGS__) \ epsilon(__VA_ARGS__) \
} }
#define CAF_FSM_TRANSITION_IMPL2(fsm_call, target) \
ps.next(); \
fsm_call; \
if (ps.code > ec::trailing_character) \
return; \
ch = ps.current(); \
goto s_##target;
#define CAF_FSM_TRANSITION_IMPL3(fsm_call, target, whitelist) \
if (::caf::detail::in_whitelist(whitelist, ch)) { \
CAF_FSM_TRANSITION_IMPL2(fsm_call, target) \
}
#define CAF_FSM_TRANSITION_IMPL4(fsm_call, target, whitelist, action) \
if (::caf::detail::in_whitelist(whitelist, ch)) { \
action; \
CAF_FSM_TRANSITION_IMPL2(fsm_call, target) \
}
#define CAF_FSM_TRANSITION_IMPL5(fsm_call, target, whitelist, action, \
error_code) \
if (::caf::detail::in_whitelist(whitelist, ch)) { \
if (!action) { \
ps.code = error_code; \
return; \
} \
CAF_FSM_TRANSITION_IMPL2(fsm_call, target) \
}
/// Makes an transition transition into another FSM, resuming at state `target`.
#define fsm_transition(...) \
CAF_PP_OVERLOAD(CAF_FSM_TRANSITION_IMPL, __VA_ARGS__)(__VA_ARGS__)
#define fsm_transition_if(statement, ...) \
if (statement) { \
fsm_transition(__VA_ARGS__) \
}
#define CAF_FSM_EPSILON_IMPL2(fsm_call, target) \ #define CAF_FSM_EPSILON_IMPL2(fsm_call, target) \
fsm_call; \ fsm_call; \
if (ps.code > ec::trailing_character) \ if (ps.code > ec::trailing_character) \
......
...@@ -54,12 +54,9 @@ namespace parser { ...@@ -54,12 +54,9 @@ namespace parser {
template <class Iterator, class Sentinel, class Consumer> template <class Iterator, class Sentinel, class Consumer>
void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&) { void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&) {
start(); start();
state(init) { term_state(init) {
transition(await_newline, ';')
}
term_state(await_newline) {
transition(done, '\n') transition(done, '\n')
transition(await_newline) transition(init)
} }
term_state(done) { term_state(done) {
// nop // nop
...@@ -71,10 +68,10 @@ template <class Iterator, class Sentinel, class Consumer> ...@@ -71,10 +68,10 @@ template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& consumer); void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& consumer);
template <class Iterator, class Sentinel, class Consumer> template <class Iterator, class Sentinel, class Consumer>
void read_ini_list(state<Iterator, Sentinel>& ps, Consumer& consumer) { void read_ini_list(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
start(); start();
state(init) { state(init) {
transition(before_value, '[', consumer.begin_list()) epsilon(before_value)
} }
state(before_value) { state(before_value) {
transition(before_value, " \t\n") transition(before_value, " \t\n")
...@@ -95,14 +92,14 @@ void read_ini_list(state<Iterator, Sentinel>& ps, Consumer& consumer) { ...@@ -95,14 +92,14 @@ void read_ini_list(state<Iterator, Sentinel>& ps, Consumer& consumer) {
} }
template <class Iterator, class Sentinel, class Consumer> template <class Iterator, class Sentinel, class Consumer>
void read_ini_map(state<Iterator, Sentinel>& ps, Consumer& consumer) { void read_ini_map(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
std::string key; std::string key;
auto alnum_or_dash = [](char x) { auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_'; return isalnum(x) || x == '-' || x == '_';
}; };
start(); start();
state(init) { state(init) {
transition(await_key_name, '{', consumer.begin_map()) epsilon(await_key_name)
} }
state(await_key_name) { state(await_key_name) {
transition(await_key_name, " \t\n") transition(await_key_name, " \t\n")
...@@ -147,8 +144,8 @@ void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& consumer) { ...@@ -147,8 +144,8 @@ void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& consumer) {
fsm_epsilon(read_number(ps, consumer), done, '.') fsm_epsilon(read_number(ps, consumer), done, '.')
fsm_epsilon(read_bool(ps, consumer), done, "ft") fsm_epsilon(read_bool(ps, consumer), done, "ft")
fsm_epsilon(read_number_or_timespan(ps, consumer), done, decimal_chars) fsm_epsilon(read_number_or_timespan(ps, consumer), done, decimal_chars)
fsm_epsilon(read_ini_list(ps, consumer), done, '[') fsm_transition(read_ini_list(ps, consumer.begin_list()), done, '[')
fsm_epsilon(read_ini_map(ps, consumer), done, '{') fsm_transition(read_ini_map(ps, consumer.begin_map()), done, '{')
} }
term_state(done) { term_state(done) {
// nop // nop
......
...@@ -35,20 +35,24 @@ using log_type = std::vector<std::string>; ...@@ -35,20 +35,24 @@ using log_type = std::vector<std::string>;
struct test_consumer { struct test_consumer {
log_type log; log_type log;
void begin_map() { test_consumer& begin_map() {
log.emplace_back("{"); log.emplace_back("{");
return *this;
} }
void end_map() { test_consumer& end_map() {
log.emplace_back("}"); log.emplace_back("}");
return *this;
} }
void begin_list() { test_consumer& begin_list() {
log.emplace_back("["); log.emplace_back("[");
return *this;
} }
void end_list() { test_consumer& end_list() {
log.emplace_back("]"); log.emplace_back("]");
return *this;
} }
void key(std::string name) { void key(std::string name) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment