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

Add fsm_transition utility to DSL for FSM

parent d4cf1f7a
......@@ -20,6 +20,8 @@
#include <cstring>
#include "caf/detail/pp.hpp"
namespace caf {
namespace detail {
......@@ -59,15 +61,18 @@ extern const char octal_chars[9];
ps.code = mismatch_ec; \
return;
/// Starts the definition of an FSM.
#define start() \
char ch = ps.current(); \
goto s_init; \
s_unexpected_eof: \
__attribute__((unused)); \
ps.code = ec::unexpected_eof; \
return; \
{ \
static constexpr ec mismatch_ec = ec::unexpected_character
/// Defines a non-terminal state in the FSM.
#define state(name) \
CAF_FSM_EVAL_MISMATCH_EC \
} \
......@@ -78,6 +83,7 @@ extern const char octal_chars[9];
goto s_unexpected_eof; \
e_##name : __attribute__((unused));
/// Defines a terminal state in the FSM.
#define term_state(name) \
CAF_FSM_EVAL_MISMATCH_EC \
} \
......@@ -88,6 +94,7 @@ extern const char octal_chars[9];
goto s_fin; \
e_##name : __attribute__((unused));
/// Ends the definition of an FSM.
#define fin() \
CAF_FSM_EVAL_MISMATCH_EC \
} \
......@@ -171,6 +178,44 @@ extern const char octal_chars[9];
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) \
fsm_call; \
if (ps.code > ec::trailing_character) \
......
......@@ -54,12 +54,9 @@ namespace parser {
template <class Iterator, class Sentinel, class Consumer>
void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&) {
start();
state(init) {
transition(await_newline, ';')
}
term_state(await_newline) {
term_state(init) {
transition(done, '\n')
transition(await_newline)
transition(init)
}
term_state(done) {
// nop
......@@ -71,10 +68,10 @@ template <class Iterator, class Sentinel, class Consumer>
void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& 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();
state(init) {
transition(before_value, '[', consumer.begin_list())
epsilon(before_value)
}
state(before_value) {
transition(before_value, " \t\n")
......@@ -95,14 +92,14 @@ void read_ini_list(state<Iterator, Sentinel>& ps, Consumer& 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;
auto alnum_or_dash = [](char x) {
return isalnum(x) || x == '-' || x == '_';
};
start();
state(init) {
transition(await_key_name, '{', consumer.begin_map())
epsilon(await_key_name)
}
state(await_key_name) {
transition(await_key_name, " \t\n")
......@@ -147,8 +144,8 @@ void read_ini_value(state<Iterator, Sentinel>& ps, Consumer& consumer) {
fsm_epsilon(read_number(ps, consumer), done, '.')
fsm_epsilon(read_bool(ps, consumer), done, "ft")
fsm_epsilon(read_number_or_timespan(ps, consumer), done, decimal_chars)
fsm_epsilon(read_ini_list(ps, consumer), done, '[')
fsm_epsilon(read_ini_map(ps, consumer), done, '{')
fsm_transition(read_ini_list(ps, consumer.begin_list()), done, '[')
fsm_transition(read_ini_map(ps, consumer.begin_map()), done, '{')
}
term_state(done) {
// nop
......
......@@ -35,20 +35,24 @@ using log_type = std::vector<std::string>;
struct test_consumer {
log_type log;
void begin_map() {
test_consumer& begin_map() {
log.emplace_back("{");
return *this;
}
void end_map() {
test_consumer& end_map() {
log.emplace_back("}");
return *this;
}
void begin_list() {
test_consumer& begin_list() {
log.emplace_back("[");
return *this;
}
void end_list() {
test_consumer& end_list() {
log.emplace_back("]");
return *this;
}
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