Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/reshadefx/include/effect_preprocessor.hpp
4246 views
1
/*
2
* Copyright (C) 2014 Patrick Mours
3
* SPDX-License-Identifier: BSD-3-Clause
4
*/
5
6
#pragma once
7
8
#include "effect_token.hpp"
9
#include <cstdint>
10
#include <memory> // std::unique_ptr
11
#include <filesystem>
12
#include <unordered_map>
13
#include <unordered_set>
14
15
namespace reshadefx
16
{
17
/// <summary>
18
/// A C-style preprocessor implementation.
19
/// </summary>
20
class preprocessor
21
{
22
public:
23
struct macro
24
{
25
std::string replacement_list;
26
std::vector<std::string> parameters;
27
bool is_predefined = false;
28
bool is_variadic = false;
29
bool is_function_like = false;
30
};
31
32
// Callbacks for manual file reading.
33
using include_file_exists_callback = bool(*)(const std::string &path);
34
using include_read_file_callback = bool(*)(const std::string &path, std::string &data);
35
static bool stdfs_read_file_callback(const std::string &path, std::string& data);
36
static bool stdfs_file_exists_callback(const std::string &path);
37
38
// Define constructor explicitly because lexer class is not included here
39
preprocessor();
40
~preprocessor();
41
42
/// <summary>
43
/// Sets callbacks to use for reading files. If this is not called, std::filesystem will be used.
44
/// </summary>
45
void set_include_callbacks(include_file_exists_callback file_exists, include_read_file_callback read_file);
46
47
/// <summary>
48
/// Adds an include directory to the list of search paths used when resolving #include directives.
49
/// </summary>
50
/// <param name="path">Path to the directory to add.</param>
51
void add_include_path(const std::string &path);
52
53
/// <summary>
54
/// Adds a new macro definition. This is equal to appending '#define name macro' to this preprocessor instance.
55
/// </summary>
56
/// <param name="name">Name of the macro to define.</param>
57
/// <param name="macro">Definition of the macro function or value.</param>
58
/// <returns></returns>
59
bool add_macro_definition(const std::string &name, const macro &macro);
60
/// <summary>
61
/// Adds a new macro value definition. This is equal to appending '#define name macro' to this preprocessor instance.
62
/// </summary>
63
/// <param name="name">Name of the macro to define.</param>
64
/// <param name="value">Value to define that macro to.</param>
65
/// <returns></returns>
66
bool add_macro_definition(const std::string &name, std::string value = "1")
67
{
68
return add_macro_definition(name, macro { std::move(value), {}, true });
69
}
70
71
/// <summary>
72
/// Opens the specified file, parses its contents and appends them to the output.
73
/// </summary>
74
/// <param name="path">Path to the file to parse.</param>
75
/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
76
bool append_file(const std::string &path);
77
/// <summary>
78
/// Parses the specified string and appends it to the output.
79
/// </summary>
80
/// <param name="source_code">String to parse.</param>
81
/// <param name="path">Optional file path to identify this string with.</param>
82
/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
83
bool append_string(std::string source_code, const std::string &path = std::string());
84
85
/// <summary>
86
/// Gets the list of error messages.
87
/// </summary>
88
const std::string &errors() const { return _errors; }
89
/// <summary>
90
/// Gets the current pre-processed output string.
91
/// </summary>
92
const std::string &output() const { return _output; }
93
94
/// <summary>
95
/// Gets a list of all included files.
96
/// </summary>
97
std::vector<std::filesystem::path> included_files() const;
98
99
/// <summary>
100
/// Gets a list of all defines that were used in #ifdef and #ifndef lines.
101
/// </summary>
102
std::vector<std::pair<std::string, std::string>> used_macro_definitions() const;
103
104
/// <summary>
105
/// Gets a list of pragma directives that occured.
106
/// </summary>
107
std::vector<std::pair<std::string, std::string>> used_pragma_directives() const { return _used_pragmas; }
108
109
private:
110
struct if_level
111
{
112
bool value;
113
bool skipping;
114
token pp_token;
115
size_t input_index;
116
};
117
struct input_level
118
{
119
std::string name;
120
std::unique_ptr<class lexer> lexer;
121
token next_token;
122
std::unordered_set<std::string> hidden_macros;
123
};
124
125
void error(const location &location, const std::string &message);
126
void warning(const location &location, const std::string &message);
127
128
void push(std::string input, const std::string &name = std::string());
129
130
bool peek(tokenid tokid) const;
131
void consume();
132
void consume_until(tokenid tokid);
133
bool accept(tokenid tokid, bool ignore_whitespace = true);
134
bool expect(tokenid tokid);
135
136
void parse();
137
void parse_def();
138
void parse_undef();
139
void parse_if();
140
void parse_ifdef();
141
void parse_ifndef();
142
void parse_elif();
143
void parse_else();
144
void parse_endif();
145
void parse_error();
146
void parse_warning();
147
void parse_pragma();
148
void parse_include();
149
150
bool evaluate_expression();
151
bool evaluate_identifier_as_macro();
152
153
bool is_defined(const std::string &name) const;
154
void expand_macro(const std::string &name, const macro &macro, const std::vector<std::string> &arguments);
155
void create_macro_replacement_list(macro &macro);
156
157
include_file_exists_callback _file_exists_cb;
158
include_read_file_callback _read_file_cb;
159
std::string _output, _errors;
160
161
std::vector<input_level> _input_stack;
162
size_t _next_input_index = 0;
163
size_t _current_input_index = 0;
164
reshadefx::token _token;
165
std::string _current_token_raw_data;
166
reshadefx::location _output_location;
167
168
std::vector<if_level> _if_stack;
169
170
unsigned short _recursion_count = 0;
171
std::unordered_set<std::string> _used_macros;
172
std::unordered_map<std::string, macro> _macros;
173
174
std::vector<std::filesystem::path> _include_paths;
175
std::unordered_map<std::string, std::string> _file_cache;
176
177
std::vector<std::pair<std::string, std::string>> _used_pragmas;
178
};
179
}
180
181