1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cctype>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
/// Stores all informations necessary for implementing an FSM-based parser.
template <class Iterator, class Sentinel>
struct parser_state {
/// Current position of the parser.
Iterator i;
/// End-of-input marker.
Sentinel e;
/// Current state of the parser.
pec code;
/// Current line in the input.
int32_t line;
/// Position in the current line.
int32_t column;
parser_state() noexcept : i(), e(), code(pec::success), line(1), column(1) {
// nop
}
explicit parser_state(Iterator first) noexcept : parser_state() {
i = first;
}
parser_state(Iterator first, Sentinel last) noexcept : parser_state() {
i = first;
e = last;
}
/// Returns the null terminator when reaching the end of the string,
/// otherwise the next character.
char next() noexcept {
++i;
++column;
if (i != e) {
auto c = *i;
if (c == '\n') {
++line;
column = 1;
}
return c;
}
return '\0';
}
/// Returns the null terminator if `i == e`, otherwise the current character.
char current() const noexcept {
return i != e ? *i : '\0';
}
/// Checks whether `i == e`.
bool at_end() const noexcept {
return i == e;
}
/// Skips any whitespaces characters in the input.
void skip_whitespaces() noexcept {
auto c = current();
while (isspace(c))
c = next();
}
/// Tries to read `x` as the next character, automatically skipping leading
/// whitespaces.
bool consume(char x) noexcept {
skip_whitespaces();
if (current() == x) {
next();
return true;
}
return false;
}
/// Consumes the next character if it satisfies given predicate, automatically
/// skipping leading whitespaces.
template <class Predicate>
bool consume_if(Predicate predicate) noexcept {
skip_whitespaces();
if (predicate(current())) {
next();
return true;
}
return false;
}
/// Tries to read `x` as the next character without automatically skipping
/// leading whitespaces.
bool consume_strict(char x) noexcept {
if (current() == x) {
next();
return true;
}
return false;
}
/// Consumes the next character if it satisfies given predicate without
/// automatically skipping leading whitespaces.
template <class Predicate>
bool consume_strict_if(Predicate predicate) noexcept {
if (predicate(current())) {
next();
return true;
}
return false;
}
};
/// Returns an error object from the current code in `ps` as well as its
/// current position.
template <class Iterator, class Sentinel>
auto make_error(const parser_state<Iterator, Sentinel>& ps)
-> decltype(make_error(ps.code, ps.line, ps.column)) {
return make_error(ps.code, ps.line, ps.column);
}
/// Specialization for parsers operating on string views.
using string_parser_state = parser_state<string_view::iterator>;
} // namespace caf
|