Path: blob/master/dep/reshadefx/include/effect_preprocessor.hpp
4246 views
/*1* Copyright (C) 2014 Patrick Mours2* SPDX-License-Identifier: BSD-3-Clause3*/45#pragma once67#include "effect_token.hpp"8#include <cstdint>9#include <memory> // std::unique_ptr10#include <filesystem>11#include <unordered_map>12#include <unordered_set>1314namespace reshadefx15{16/// <summary>17/// A C-style preprocessor implementation.18/// </summary>19class preprocessor20{21public:22struct macro23{24std::string replacement_list;25std::vector<std::string> parameters;26bool is_predefined = false;27bool is_variadic = false;28bool is_function_like = false;29};3031// Callbacks for manual file reading.32using include_file_exists_callback = bool(*)(const std::string &path);33using include_read_file_callback = bool(*)(const std::string &path, std::string &data);34static bool stdfs_read_file_callback(const std::string &path, std::string& data);35static bool stdfs_file_exists_callback(const std::string &path);3637// Define constructor explicitly because lexer class is not included here38preprocessor();39~preprocessor();4041/// <summary>42/// Sets callbacks to use for reading files. If this is not called, std::filesystem will be used.43/// </summary>44void set_include_callbacks(include_file_exists_callback file_exists, include_read_file_callback read_file);4546/// <summary>47/// Adds an include directory to the list of search paths used when resolving #include directives.48/// </summary>49/// <param name="path">Path to the directory to add.</param>50void add_include_path(const std::string &path);5152/// <summary>53/// Adds a new macro definition. This is equal to appending '#define name macro' to this preprocessor instance.54/// </summary>55/// <param name="name">Name of the macro to define.</param>56/// <param name="macro">Definition of the macro function or value.</param>57/// <returns></returns>58bool add_macro_definition(const std::string &name, const macro ¯o);59/// <summary>60/// Adds a new macro value definition. This is equal to appending '#define name macro' to this preprocessor instance.61/// </summary>62/// <param name="name">Name of the macro to define.</param>63/// <param name="value">Value to define that macro to.</param>64/// <returns></returns>65bool add_macro_definition(const std::string &name, std::string value = "1")66{67return add_macro_definition(name, macro { std::move(value), {}, true });68}6970/// <summary>71/// Opens the specified file, parses its contents and appends them to the output.72/// </summary>73/// <param name="path">Path to the file to parse.</param>74/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>75bool append_file(const std::string &path);76/// <summary>77/// Parses the specified string and appends it to the output.78/// </summary>79/// <param name="source_code">String to parse.</param>80/// <param name="path">Optional file path to identify this string with.</param>81/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>82bool append_string(std::string source_code, const std::string &path = std::string());8384/// <summary>85/// Gets the list of error messages.86/// </summary>87const std::string &errors() const { return _errors; }88/// <summary>89/// Gets the current pre-processed output string.90/// </summary>91const std::string &output() const { return _output; }9293/// <summary>94/// Gets a list of all included files.95/// </summary>96std::vector<std::filesystem::path> included_files() const;9798/// <summary>99/// Gets a list of all defines that were used in #ifdef and #ifndef lines.100/// </summary>101std::vector<std::pair<std::string, std::string>> used_macro_definitions() const;102103/// <summary>104/// Gets a list of pragma directives that occured.105/// </summary>106std::vector<std::pair<std::string, std::string>> used_pragma_directives() const { return _used_pragmas; }107108private:109struct if_level110{111bool value;112bool skipping;113token pp_token;114size_t input_index;115};116struct input_level117{118std::string name;119std::unique_ptr<class lexer> lexer;120token next_token;121std::unordered_set<std::string> hidden_macros;122};123124void error(const location &location, const std::string &message);125void warning(const location &location, const std::string &message);126127void push(std::string input, const std::string &name = std::string());128129bool peek(tokenid tokid) const;130void consume();131void consume_until(tokenid tokid);132bool accept(tokenid tokid, bool ignore_whitespace = true);133bool expect(tokenid tokid);134135void parse();136void parse_def();137void parse_undef();138void parse_if();139void parse_ifdef();140void parse_ifndef();141void parse_elif();142void parse_else();143void parse_endif();144void parse_error();145void parse_warning();146void parse_pragma();147void parse_include();148149bool evaluate_expression();150bool evaluate_identifier_as_macro();151152bool is_defined(const std::string &name) const;153void expand_macro(const std::string &name, const macro ¯o, const std::vector<std::string> &arguments);154void create_macro_replacement_list(macro ¯o);155156include_file_exists_callback _file_exists_cb;157include_read_file_callback _read_file_cb;158std::string _output, _errors;159160std::vector<input_level> _input_stack;161size_t _next_input_index = 0;162size_t _current_input_index = 0;163reshadefx::token _token;164std::string _current_token_raw_data;165reshadefx::location _output_location;166167std::vector<if_level> _if_stack;168169unsigned short _recursion_count = 0;170std::unordered_set<std::string> _used_macros;171std::unordered_map<std::string, macro> _macros;172173std::vector<std::filesystem::path> _include_paths;174std::unordered_map<std::string, std::string> _file_cache;175176std::vector<std::pair<std::string, std::string>> _used_pragmas;177};178}179180181