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
|
// license:GPL-2.0+
// copyright-holders:Couriersud
#ifndef PPREPROCESSOR_H_
#define PPREPROCESSOR_H_
///
/// \file ppreprocessor.h
///
#include "pstream.h"
#include "pstring.h"
#include "psource.h"
#include "putil.h"
#include <istream>
#include <unordered_map>
#include <vector>
namespace plib {
class ppreprocessor
{
public:
using string_list = std::vector<pstring>;
struct define_t
{
define_t(const pstring &name, const pstring &replace)
: m_name(name), m_replace(replace), m_has_params(false)
{}
explicit define_t(const pstring &name)
: m_name(name), m_replace(""), m_has_params(false)
{}
pstring m_name;
pstring m_replace;
bool m_has_params;
string_list m_params;
};
using defines_map_type = std::unordered_map<pstring, define_t>;
explicit ppreprocessor(psource_collection_t &sources, defines_map_type *defines = nullptr);
PCOPYASSIGNMOVE(ppreprocessor, delete)
~ppreprocessor() = default;
/// \brief process stream
///
/// \param filename a filename or identifier identifying the stream.
///
/// FIXME: this is sub-optimal. Refactor input_context into pinput_context
/// and pass this to ppreprocessor.
///
template <typename T>
pstring process(T &&istrm, const pstring &filename)
{
m_outbuf.clear();
m_stack.emplace_back(input_context(istrm.release_stream(),plib::util::path(filename), filename));
process_stack();
return m_outbuf;
}
[[noreturn]] void error(const pstring &err) noexcept(false);
define_t *get_define(const pstring &name);
pstring replace_macros(const pstring &line);
private:
enum state_e
{
PROCESS,
LINE_CONTINUATION
};
void push_out(const pstring &s);
void process_stack();
string_list tokenize(const pstring &str, const string_list &sep, bool remove_ws, bool concat);
static bool is_valid_token(const pstring &str);
std::pair<pstring,bool> process_line(const pstring &line_in);
pstring process_comments(const pstring &line);
defines_map_type m_defines;
psource_collection_t &m_sources;
string_list m_expr_sep;
std::uint_least64_t m_if_flag; // 63 if levels
std::uint_least64_t m_if_seen; // 63 if levels
std::uint_least64_t m_elif; // 63 if levels - for #elif
int m_if_level;
struct input_context
{
template <typename T>
input_context(T &&istrm, const pstring &local_path, const pstring &name)
: m_reader(std::forward<T>(istrm))
, m_lineno(0)
, m_local_path(local_path)
, m_name(name)
{}
putf8_reader m_reader;
int m_lineno;
pstring m_local_path;
pstring m_name;
};
// vector used as stack because we need to loop through stack
std::vector<input_context> m_stack;
pstring m_outbuf;
state_e m_state;
pstring m_line;
bool m_comment;
bool m_debug_out;
};
} // namespace plib
#endif // PPREPROCESSOR_H_
|