├── .gitignore ├── .gitmodules ├── Makefile ├── .github └── workflows │ └── build.yaml ├── LICENSE ├── LICENSES ├── veiler.LICENSE ├── boost.LICENSE ├── linse.LICENSE └── linse.parents.LICENSE ├── README.md └── messer.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /messer 2 | /include_dir.ipp 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "linse"] 2 | path = linse 3 | url = https://github.com/messer-cpp/linse 4 | [submodule "veiler"] 5 | path = veiler 6 | url = https://github.com/messer-cpp/veiler 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX := g++ 2 | CXXFLAGS := -std=c++17 -Wall -Wextra -pedantic-errors -O3 -march=native -Ilinse -I. 3 | LDFLAGS := -lboost_context -lstdc++fs 4 | OBJS := messer include_dir.ipp 5 | 6 | 7 | all: $(OBJS) 8 | 9 | .PHONY: clean 10 | 11 | 12 | messer: messer.cpp include_dir.ipp 13 | $(CXX) $(CXXFLAGS) -o$(@) $(<) $(LDFLAGS) 14 | 15 | include_dir.ipp: 16 | echo | LC_ALL=C $(CPP) -xc++ -v - 2>&1 | awk '/<...>/,/^End/ {print}' | sed -n 's|^ \(.*\)|"\1",|p' > $(@) 17 | 18 | clean: 19 | $(RM) $(OBJS) 20 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 2 | 3 | on: 4 | push: 5 | branches: [ "**" ] 6 | tags: [ "**" ] 7 | pull_request: 8 | branches: [ "**" ] 9 | 10 | jobs: 11 | standalone: 12 | strategy: 13 | matrix: 14 | include: 15 | - image: ubuntu-24.04 16 | arch: x86_64 17 | - image: ubuntu-24.04-arm 18 | arch: aarch64 19 | runs-on: ${{ matrix.image }} 20 | steps: 21 | - name: stop update man-page 22 | run: | 23 | echo "set man-db/auto-update false" | sudo debconf-communicate 24 | sudo dpkg-reconfigure man-db 25 | - run: | 26 | sudo apt update 27 | sudo apt install libboost-all-dev 28 | - uses: actions/checkout@v4 29 | with: 30 | submodules: recursive 31 | - name: build 32 | shell: bash 33 | run: | 34 | CXX=g++-14 CPP=cpp-14 make 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016-2019 I 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /LICENSES/veiler.LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /LICENSES/boost.LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSES/linse.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, I 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of I nor the names of its contributors may be used 13 | to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Messer 2 | 3 | Messer is an interactive environment for evaluating C preprocessing macros conforming to C++17 standard with showing macro replacement steps. 4 | 5 | ## Prerequisites 6 | 7 | - You need to install below manually: 8 | - C++17 supported GNU C++ Compiler < 15 9 | - **NOTE:** `g++` >= 15 can't build messer. Please use `g++` <= 14 10 | - Boost 11 | - Boost.Coroutine2 12 | - Boost.Preprocessor 13 | - `sed` 14 | - `awk` 15 | - `make` 16 | - You can get the following prerequisites as git-submodules: 17 | - Veiler 18 | - Linse 19 | 20 | ## Build 21 | 22 | ```shell-session 23 | $ make 24 | ``` 25 | 26 | It takes **extremely** long time. 27 | For example, it takes 4 minutes to build messer on an AMD Ryzen7 2700X. 28 | It is recommended to take coffee while building. 29 | 30 | ``` 31 | ...patience... 32 | ...patience... 33 | ...patience... 34 | ``` 35 | 36 | ## Usage 37 | 38 | You can input programs following the prompt (`>>>`). 39 | `#pragma step tokens` shows macro replacement steps for `tokens`. 40 | You can exit Messer with `C-d`. 41 | 42 | ### Example 43 | 44 | ``` 45 | >>> #define CAT_I(a, b) a ## b 46 | >>> #define ID(x) x 47 | >>> CAT_I(a, ID(b)) 48 | aID(b) 49 | >>> #pragma step CAT_I(a, ID(b)) 50 | CAT_I(a, ID(b)) 51 | -> a ## ID(b) 52 | -> aID(b) 53 | >>> #define CAT(a, b) CAT_I(a, b) 54 | >>> CAT(a, ID(b)) 55 | ab 56 | >>> #pragma step CAT(a, ID(b)) 57 | CAT(a, ID(b)) 58 | -> CAT_I(a, ID(b)) 59 | -> CAT_I(a, b) 60 | -> a ## b 61 | -> ab 62 | >>> 63 | ``` 64 | 65 | ## License 66 | 67 | MIT License (see `LICENSE` file) 68 | 69 | ### License of dependent libraries 70 | 71 | see `LICENSES` directory. 72 | -------------------------------------------------------------------------------- /LICENSES/linse.parents.LICENSE: -------------------------------------------------------------------------------- 1 | /* linenoise.c -- guerrilla line editing library against the idea that a 2 | * line editing lib needs to be 20,000 lines of C code. 3 | * 4 | * Copyright (c) 2010, Salvatore Sanfilippo 5 | * Copyright (c) 2010, Pieter Noordhuis 6 | * 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * * Neither the name of Redis nor the names of its contributors may be used 18 | * to endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /* Copyright 2001-2004 Unicode, Inc. 35 | * 36 | * Disclaimer 37 | * 38 | * This source code is provided as is by Unicode, Inc. No claims are 39 | * made as to fitness for any particular purpose. No warranties of any 40 | * kind are expressed or implied. The recipient agrees to determine 41 | * applicability of information provided. If this file has been 42 | * purchased on magnetic or optical media from Unicode, Inc., the 43 | * sole remedy for any claim will be exchange of defective media 44 | * within 90 days of receipt. 45 | * 46 | * Limitations on Rights to Redistribute This Code 47 | * 48 | * Unicode, Inc. hereby grants the right to freely use the information 49 | * supplied in this file in the creation of products supporting the 50 | * Unicode Standard, and to make copies of this file in any form 51 | * for internal or external distribution as long as this notice 52 | * remains attached. 53 | */ 54 | 55 | /* Markus Kuhn -- 2007-05-26 (Unicode 5.0) 56 | * 57 | * Permission to use, copy, modify, and distribute this software 58 | * for any purpose and without fee is hereby granted. The author 59 | * disclaims all warranties with regard to this software. 60 | */ 61 | -------------------------------------------------------------------------------- /messer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace messer{ 21 | 22 | template 23 | class output_range{ 24 | Iterator be, en; 25 | public: 26 | output_range() = default; 27 | output_range(const output_range&)noexcept = default; 28 | output_range(output_range&&)noexcept = default; 29 | output_range& operator=(const output_range&)noexcept = default; 30 | output_range& operator=(output_range&&)noexcept = default; 31 | template 32 | output_range(I&& b, J&& e):be(std::forward(b)), en(std::forward(e)){} 33 | const Iterator& begin()const{return be;} 34 | const Iterator& end ()const{return en;} 35 | friend std::ostream& operator<<(std::ostream& os, const output_range& r){ 36 | for(auto&& x : r) 37 | os << x; 38 | return os; 39 | } 40 | }; 41 | 42 | namespace detail{ 43 | 44 | using has_get_raw = VEILER_HASTUR_TAG_CREATE(get_raw); 45 | 46 | templateclass pointer_iterator; 47 | templateclass pointer_iterator{ 48 | T* ptr; 49 | using self = pointer_iterator; 50 | public: 51 | pointer_iterator() = default; 52 | pointer_iterator(T* ptr):ptr(ptr){} 53 | pointer_iterator(const pointer_iterator&) = default; 54 | using value_type = T; 55 | using difference_type = std::ptrdiff_t; 56 | using pointer = value_type*; 57 | using reference = value_type&; 58 | using iterator_category = std::random_access_iterator_tag; 59 | value_type operator*()const{return *ptr;} 60 | self& operator++(){++ptr;return *this;} 61 | self operator++(int){self t = *this; ++(*this); return t;} 62 | self& operator+=(std::size_t n){ptr += n;return *this;} 63 | self& operator--(){--ptr;return *this;} 64 | self operator--(int){self t = *this;--(*this);return t;} 65 | self operator-=(std::size_t n){ptr -= n;return *this;} 66 | friend self operator+ (const self& lhs, std::size_t n){self t = lhs; t += n; return t;} 67 | friend self operator- (const self& lhs, std::size_t n){self t = lhs; t -= n; return t;} 68 | friend std::ptrdiff_t operator- (const self& lhs, const self& rhs){return lhs.ptr-rhs.ptr;} 69 | friend bool operator==(const self& lhs, const self& rhs)noexcept{return lhs.ptr == rhs.ptr;} 70 | friend bool operator!=(const self& lhs, const self& rhs)noexcept{return !(lhs == rhs);} 71 | }; 72 | 73 | template 74 | using to_inheritable_iterator = std::conditional_t::value, pointer_iterator, T>; 75 | 76 | }//namespace detail 77 | 78 | template::func{}>* = nullptr> 79 | inline auto&& get_raw(FilterIterator&& it){ 80 | return std::forward(it).get_raw(); 81 | } 82 | 83 | template::func{}>* = nullptr> 84 | inline auto&& get_raw(Iterator&& it){ 85 | return std::forward(it); 86 | } 87 | 88 | struct annotation_type{ 89 | std::string_view filename; 90 | std::size_t line; 91 | std::size_t column; 92 | }; 93 | 94 | template 95 | class annotation_range{ 96 | class annotation_iterator:public detail::to_inheritable_iterator()))>{ 97 | using self = annotation_iterator; 98 | using parent = detail::to_inheritable_iterator()))>; 99 | annotation_type data; 100 | public: 101 | annotation_iterator() = default; 102 | annotation_iterator(const parent& it, std::string_view fn, std::size_t l = 1, std::size_t c = 1):parent{it}, data{fn, l, c}{} 103 | annotation_iterator(const parent& it, const annotation_type& an):parent{it}, data{an}{} 104 | annotation_iterator(const self&) = default; 105 | std::string_view get_filename()const{return data.filename;} 106 | std::size_t get_line()const{return data.line;} 107 | std::size_t get_column()const{return data.column;} 108 | self& operator++(){ 109 | if(**this == '\n'){ 110 | ++data.line; 111 | data.column = 1; 112 | } 113 | else 114 | ++data.column; 115 | ++*static_cast(this); 116 | return *this; 117 | } 118 | self operator++(int){self t = *this; ++(*this); return t;} 119 | const annotation_type& get_annotate()const{return data;} 120 | const parent& get_inner()const{return *this;} 121 | }; 122 | annotation_type annot_data; 123 | T&& t; 124 | public: 125 | using iterator = annotation_iterator; 126 | using const_iterator = iterator; 127 | using value_type = decltype(*std::declval()))>()); 128 | annotation_range(annotation_type anno, T&& data):annot_data(std::move(anno)), t(std::forward(data)){} 129 | annotation_iterator begin()const{return annotation_iterator{t.begin(), annot_data};} 130 | annotation_iterator end()const{return annotation_iterator{t.end(), annot_data};} 131 | }; 132 | 133 | class annotation{ 134 | annotation_type data; 135 | public: 136 | annotation(const std::string_view& filename, std::size_t l = 1, std::size_t c = 1):data{filename, l, c}{} 137 | annotation(const annotation_type& anno):data{anno}{} 138 | template 139 | friend constexpr auto operator|(T&& t, annotation&& a)noexcept{ 140 | return annotation_range{std::move(a.data), std::forward(t)}; 141 | } 142 | }; 143 | 144 | template 145 | class filter_iterator : T{ 146 | using self = filter_iterator; 147 | std::optional t; 148 | public: 149 | using typename T::value_type; 150 | template 151 | explicit filter_iterator(Args&&... args):T{std::forward(args)...}{} 152 | filter_iterator(const filter_iterator& other):T{other}{} 153 | filter_iterator& operator=(const filter_iterator& other){static_cast(*this) = other; return *this;} 154 | value_type& operator*(){t = this->dereference();return *t;} 155 | value_type operator*()const{return this->dereference();} 156 | value_type* operator->(){return &**this;} 157 | self& operator++(){this->next();return *this;} 158 | self operator++(int){self t = *this; ++(*this); return t;} 159 | self& operator+=(std::size_t n){while(n-->0)++(*this);return *this;} 160 | auto&& get_raw(){return this->get_raw_iterator();} 161 | auto&& get_raw()const{return this->get_raw_iterator();} 162 | friend self operator+(const self& lhs, std::size_t n){self t = lhs; t += n; return t;} 163 | friend bool operator==(const self& lhs, const self& rhs)noexcept{return lhs.is_equal(rhs);} 164 | friend bool operator!=(const self& lhs, const self& rhs)noexcept{return !(lhs == rhs);} 165 | }; 166 | 167 | } 168 | 169 | namespace std{ 170 | 171 | templatestruct iterator_traits>{ 172 | using value_type = typename messer::filter_iterator::value_type; 173 | using iterator = messer::filter_iterator; 174 | using iterator_category = forward_iterator_tag; 175 | using reference = value_type&; 176 | using difference_type = std::ptrdiff_t; 177 | using pointer = value_type*; 178 | }; 179 | 180 | } 181 | 182 | namespace veiler{ 183 | 184 | template 185 | struct hash> : hash::value_type>{ 186 | constexpr hash() = default; 187 | constexpr hash(const hash&) = default; 188 | constexpr hash(hash&&) = default; 189 | ~hash() = default; 190 | hash& operator=(const hash&) = default; 191 | hash& operator=(hash&&) = default; 192 | using result_type = std::size_t; 193 | using argument_type = messer::filter_iterator; 194 | std::size_t operator()(const argument_type& key)const noexcept{ 195 | return veiler::hash::value_type>::operator()(*key); 196 | } 197 | }; 198 | 199 | } 200 | 201 | namespace messer{ 202 | 203 | templateclass IteratorImpl> 204 | class filter_range{ 205 | T t; 206 | public: 207 | using iterator = filter_iterator>>; 208 | using const_iterator = iterator; 209 | using value_type = typename iterator::value_type; 210 | filter_range(T&& t):t{std::forward(t)}{} 211 | iterator begin()const{using std::begin;using std::end;return iterator{begin(t), end(t)};} 212 | iterator end ()const{ using std::end;return iterator{end (t), end(t)};} 213 | friend std::ostream& operator<<(std::ostream& os, const filter_range& rhs){ 214 | for(auto&& x : rhs) 215 | os << x; 216 | return os; 217 | } 218 | }; 219 | 220 | class phase1_t{ 221 | template 222 | struct crlf_to_lf_iterator_impl{ 223 | using iterator = typename T::const_iterator; 224 | private: 225 | iterator b; 226 | iterator e; 227 | bool is_target()const noexcept{ 228 | if(*b != '\r') 229 | return false; 230 | const auto next = std::next(b); 231 | return next != e && *next == '\n'; 232 | } 233 | public: 234 | using value_type = std::enable_if_t::value, char>; 235 | crlf_to_lf_iterator_impl() = default; 236 | crlf_to_lf_iterator_impl(const iterator& b, const iterator& e):b{b}, e{e}{} 237 | crlf_to_lf_iterator_impl(const crlf_to_lf_iterator_impl&) = default; 238 | crlf_to_lf_iterator_impl& operator=(const crlf_to_lf_iterator_impl& other){b = other.b; e = other.e;return *this;} 239 | value_type dereference()const{ 240 | return *b; 241 | } 242 | 243 | void next(){ 244 | ++b; 245 | if(is_target()) 246 | ++b; 247 | } 248 | bool is_equal(const crlf_to_lf_iterator_impl& other)const noexcept{return b == other.b;} 249 | auto& get_raw_iterator() {return get_raw(b);} 250 | const auto& get_raw_iterator()const{return get_raw(b);} 251 | }; 252 | template 253 | class trigraph_iterator_impl{ 254 | static char trigraph_convert(char c){ 255 | switch(c){ 256 | case '=' : return '#'; 257 | case '(' : return '['; 258 | case '/' : return '\\'; 259 | case ')' : return ']'; 260 | case '\'': return '^'; 261 | case '<' : return '{'; 262 | case '!' : return '|'; 263 | case '>' : return '}'; 264 | case '-' : return '~'; 265 | } 266 | return -1; 267 | } 268 | public: 269 | using iterator = typename T::const_iterator; 270 | private: 271 | iterator b; 272 | iterator e; 273 | bool is_trigraph()const noexcept{ 274 | if(*b != '?') 275 | return false; 276 | auto next = std::next(b); 277 | if(next == e || *next != '?') 278 | return false; 279 | next = std::next(next); 280 | return next != e && trigraph_convert(*next) != -1; 281 | } 282 | public: 283 | using value_type = std::enable_if_t::value, char>; 284 | trigraph_iterator_impl() = default; 285 | trigraph_iterator_impl(const iterator& b, const iterator& e):b{b}, e{e}{} 286 | trigraph_iterator_impl(const trigraph_iterator_impl&) = default; 287 | trigraph_iterator_impl& operator=(const trigraph_iterator_impl& other){b = other.b;return *this;} 288 | value_type dereference()const{ 289 | if(is_trigraph()) 290 | return trigraph_convert(*std::next(b,2)); 291 | return *b; 292 | } 293 | void next(){ 294 | if(is_trigraph()) 295 | std::advance(b, 3); 296 | else 297 | ++b; 298 | } 299 | bool is_equal(const trigraph_iterator_impl& other)const noexcept{return b == other.b;} 300 | auto& get_raw_iterator() {return get_raw(b);} 301 | const auto& get_raw_iterator()const{return get_raw(b);} 302 | }; 303 | template 304 | using trigraph = filter_range; 305 | template 306 | using crlf_to_lf = filter_range; 307 | public: 308 | template 309 | friend constexpr auto operator|(T&& t, const phase1_t&)noexcept{ 310 | return /*trigraph<*/crlf_to_lf/*>*/{{std::forward(t)}}; 311 | } 312 | }; 313 | 314 | class phase2_t{ 315 | template 316 | struct backslash_eol_iterator_impl{ 317 | using iterator = typename T::const_iterator; 318 | private: 319 | iterator b; 320 | iterator e; 321 | bool is_target()const noexcept{ 322 | if(*b != '\\') 323 | return false; 324 | const auto next = std::next(b); 325 | return next != e && *next == '\n'; 326 | } 327 | void skip(){ 328 | while(is_target()) 329 | std::advance(b, 2); 330 | } 331 | public: 332 | using value_type = std::enable_if_t::value, char>; 333 | backslash_eol_iterator_impl() = default; 334 | backslash_eol_iterator_impl(const iterator& b, const iterator& e):b{b}, e{e}{skip();} 335 | backslash_eol_iterator_impl(const backslash_eol_iterator_impl&) = default; 336 | backslash_eol_iterator_impl& operator=(const backslash_eol_iterator_impl& other){b = other.b;return *this;} 337 | value_type dereference()const{ 338 | return *b; 339 | } 340 | void next(){ 341 | ++b; 342 | skip(); 343 | } 344 | bool is_equal(const backslash_eol_iterator_impl& other)const noexcept{return b == other.b;} 345 | auto& get_raw_iterator() {return get_raw(b);} 346 | const auto& get_raw_iterator()const{return get_raw(b);} 347 | }; 348 | template 349 | using backslash_eol = filter_range; 350 | public: 351 | template 352 | friend constexpr auto operator|(T&& t, const phase2_t&)noexcept{ 353 | return backslash_eol{std::forward(t)}; 354 | } 355 | }; 356 | 357 | #define MESSER_DECL_TOKEN_TYPE(sequence) \ 358 | enum class token_type{\ 359 | BOOST_PP_SEQ_ENUM(sequence)\ 360 | , END\ 361 | };\ 362 | inline std::ostream& operator<<(std::ostream& os, token_type t){\ 363 | switch(t){\ 364 | BOOST_PP_SEQ_FOR_EACH(MESSER_DECL_TOKEN_TYPE_I, _, sequence)\ 365 | default:os<<"unknown("<>(t)<<')';\ 366 | }\ 367 | return os;\ 368 | } 369 | #define MESSER_DECL_TOKEN_TYPE_I(r, _, name) case token_type::name: os << BOOST_PP_STRINGIZE(name);break; 370 | 371 | #define PUNCTUATORS \ 372 | (punctuator)(punctuator_hash)(punctuator_hashhash)(punctuator_left_parenthesis)(punctuator_comma)(punctuator_ellipsis)(punctuator_right_parenthesis)(punctuator_left_shift)(punctuator_right_shift)(punctuator_less_equal)(punctuator_greater_equal)(punctuator_less)(punctuator_greater)(punctuator_equalequal)(punctuator_not_equal)(punctuator_logical_or)(punctuator_logical_and)(punctuator_logical_not)(punctuator_ampersand)(punctuator_asterisk)(punctuator_plus)(punctuator_minus)(punctuator_division)(punctuator_modulo)(punctuator_bitwise_or)(punctuator_bitwise_xor)(punctuator_bitwise_not)(punctuator_question)(punctuator_colon) 373 | #define IDENTIFIERS \ 374 | (identifier)(identifier_include)(identifier_define)(identifier_undef)(identifier_line)(identifier_error)(identifier_pragma)(identifier_if)(identifier_ifdef)(identifier_ifndef)(identifier_elif)(identifier_else)(identifier_endif)(identifier_defined)(identifier_time_)(identifier_date_)(identifier_file_)(identifier_line_)(identifier_pragma_op)(identifier_has_include)(identifier_true)(identifier_false) 375 | MESSER_DECL_TOKEN_TYPE( 376 | (empty) 377 | (white_space) 378 | (eol) 379 | (header_name) 380 | PUNCTUATORS 381 | (character_literal) 382 | (string_literal) 383 | (pp_number) 384 | IDENTIFIERS 385 | (unclassified_character) 386 | ) 387 | #undef MESSER_DECL_TOKEN_TYPE_I 388 | #undef MESSER_DECL_TOKEN_TYPE 389 | 390 | inline bool is_white_spaces(const token_type& t)noexcept{switch(t){case token_type::white_space: case token_type::eol: return true;default:return false;}} 391 | #define MESSER_DECL_TOKEN_TYPE(r, _, name) case token_type::name: 392 | inline bool is_punctuator(const token_type& t)noexcept{switch(t){BOOST_PP_SEQ_FOR_EACH(MESSER_DECL_TOKEN_TYPE, _, PUNCTUATORS)return true; default: return false;}} 393 | inline bool is_identifier(const token_type& t)noexcept{switch(t){BOOST_PP_SEQ_FOR_EACH(MESSER_DECL_TOKEN_TYPE, _, IDENTIFIERS)return true; default: return false;}} 394 | 395 | template 396 | class token{ 397 | StrT str; 398 | token_type tt; 399 | public: 400 | template 401 | token(T&& str, token_type tok):str{std::forward(str)}, tt{tok}{} 402 | token_type type()const{return tt;} 403 | token_type& type(){return tt;} 404 | const StrT& get()const{return str;} 405 | friend std::ostream& operator<<(std::ostream& os, const token& tkn){return os << tkn.str;} 406 | }; 407 | 408 | #define RULE VEILER_PEGASUS_RULE 409 | #define AUTO_RULE VEILER_PEGASUS_AUTO_RULE 410 | #define INLINE_RULE VEILER_PEGASUS_INLINE_RULE 411 | 412 | class phase3_t{ 413 | struct lexer : veiler::pegasus::parsers{ 414 | static auto entrypoint(){ 415 | return instance().preprocessing_token; 416 | } 417 | static auto inner_include(){ 418 | return instance().rule_inner_include; 419 | } 420 | private: 421 | static constexpr auto location = veiler::pegasus::semantic_actions::location; 422 | static constexpr auto omit = veiler::pegasus::semantic_actions::omit; 423 | static constexpr auto read = veiler::pegasus::read; 424 | static constexpr auto value = veiler::pegasus::semantic_actions::value; 425 | template 426 | static constexpr auto lit(T&& t){return veiler::pegasus::lit(std::forward(t));} 427 | template 428 | static constexpr auto range(T&& t, U&& u){return veiler::pegasus::range(std::forward(t), std::forward(u));} 429 | static constexpr auto set_token(token_type t){ 430 | return [t](auto&& loc, [[maybe_unused]] auto&&... unused){return std::make_pair(loc, t);}; 431 | } 432 | AUTO_RULE(rule_inner_include, veiler::pegasus::transient( 433 | rules.header_name 434 | | rules.preprocessing_token 435 | )) 436 | AUTO_RULE(header_name, veiler::pegasus::transient( 437 | ( lit('<') >> +rules.h_char >> lit('>') 438 | | lit('"') >> +rules.q_char >> lit('"') 439 | )[location][set_token(token_type::header_name)] 440 | )) 441 | AUTO_RULE(h_char, veiler::pegasus::transient( 442 | omit[read - lit('\n') - lit('>')] 443 | )) 444 | AUTO_RULE(q_char, veiler::pegasus::transient( 445 | omit[read - lit('\n') - lit('"')] 446 | )) 447 | AUTO_RULE(preprocessing_token, veiler::pegasus::transient( 448 | rules.white_spaces[location][set_token(token_type::white_space)] 449 | | lit('\n')[location][set_token(token_type::eol)] 450 | | rules.pp_number[location][set_token(token_type::pp_number)] 451 | | rules.punctuators 452 | | rules.character_literal[location][set_token(token_type::character_literal)] 453 | | rules.string_literal 454 | | rules.directive 455 | | (lit("true") >> !rules.identifier)[location][set_token(token_type::identifier_true)] 456 | | (lit("false") >> !rules.identifier)[location][set_token(token_type::identifier_false)] 457 | | (lit("defined") >> !rules.identifier)[location][set_token(token_type::identifier_defined)] 458 | | (lit("__TIME__") >> !rules.identifier)[location][set_token(token_type::identifier_time_)] 459 | | (lit("__DATE__") >> !rules.identifier)[location][set_token(token_type::identifier_date_)] 460 | | (lit("__FILE__") >> !rules.identifier)[location][set_token(token_type::identifier_file_)] 461 | | (lit("__LINE__") >> !rules.identifier)[location][set_token(token_type::identifier_line_)] 462 | | (lit("_Pragma") >> !rules.identifier)[location][set_token(token_type::identifier_pragma_op)] 463 | | (lit("__has_include") >> !rules.identifier)[location][set_token(token_type::identifier_has_include)] 464 | | rules.identifier[location][set_token(token_type::identifier)] 465 | | read[location][set_token(token_type::unclassified_character)] 466 | )) 467 | AUTO_RULE(punctuators, veiler::pegasus::transient( 468 | lit("%:%:" )[location][set_token(token_type::punctuator_hashhash)] 469 | | lit("..." )[location][set_token(token_type::punctuator_ellipsis)] 470 | | lit("<<=" )[location][set_token(token_type::punctuator)] 471 | | lit(">>=" )[location][set_token(token_type::punctuator)] 472 | | lit("->*" )[location][set_token(token_type::punctuator)]//C++ 473 | | lit(".*" )[location][set_token(token_type::punctuator)]//C++ 474 | | lit("%:" )[location][set_token(token_type::punctuator_hash)] 475 | | lit("<:" )[location][set_token(token_type::punctuator)] 476 | | lit(":>" )[location][set_token(token_type::punctuator)] 477 | | lit("<%" )[location][set_token(token_type::punctuator)] 478 | | lit("%>" )[location][set_token(token_type::punctuator)] 479 | | lit("##" )[location][set_token(token_type::punctuator_hashhash)] 480 | | lit("<<" )[location][set_token(token_type::punctuator_left_shift)] 481 | | lit(">>" )[location][set_token(token_type::punctuator_right_shift)] 482 | | lit("->" )[location][set_token(token_type::punctuator)] 483 | | lit("++" )[location][set_token(token_type::punctuator)] 484 | | lit("--" )[location][set_token(token_type::punctuator)] 485 | | lit("<=" )[location][set_token(token_type::punctuator_less_equal)] 486 | | lit(">=" )[location][set_token(token_type::punctuator_greater_equal)] 487 | | lit("==" )[location][set_token(token_type::punctuator_equalequal)] 488 | | lit("!=" )[location][set_token(token_type::punctuator_not_equal)] 489 | | lit("&&" )[location][set_token(token_type::punctuator_logical_and)] 490 | | lit("||" )[location][set_token(token_type::punctuator_logical_or)] 491 | | lit("*=" )[location][set_token(token_type::punctuator)] 492 | | lit("/=" )[location][set_token(token_type::punctuator)] 493 | | lit("%=" )[location][set_token(token_type::punctuator)] 494 | | lit("+=" )[location][set_token(token_type::punctuator)] 495 | | lit("-=" )[location][set_token(token_type::punctuator)] 496 | | lit("&=" )[location][set_token(token_type::punctuator)] 497 | | lit("^=" )[location][set_token(token_type::punctuator)] 498 | | lit("|=" )[location][set_token(token_type::punctuator)] 499 | | lit("::" )[location][set_token(token_type::punctuator)]//C++ 500 | | lit('#' )[location][set_token(token_type::punctuator_hash)] 501 | | lit('[' )[location][set_token(token_type::punctuator)] 502 | | lit(']' )[location][set_token(token_type::punctuator)] 503 | | lit('(' )[location][set_token(token_type::punctuator_left_parenthesis)] 504 | | lit(')' )[location][set_token(token_type::punctuator_right_parenthesis)] 505 | | lit('{' )[location][set_token(token_type::punctuator)] 506 | | lit('}' )[location][set_token(token_type::punctuator)] 507 | | lit('.' )[location][set_token(token_type::punctuator)] 508 | | lit('&' )[location][set_token(token_type::punctuator_ampersand)] 509 | | lit('*' )[location][set_token(token_type::punctuator_asterisk)] 510 | | lit('+' )[location][set_token(token_type::punctuator_plus)] 511 | | lit('-' )[location][set_token(token_type::punctuator_minus)] 512 | | lit('~' )[location][set_token(token_type::punctuator_bitwise_not)] 513 | | lit('!' )[location][set_token(token_type::punctuator_logical_not)] 514 | | lit('/' )[location][set_token(token_type::punctuator_division)] 515 | | lit('%' )[location][set_token(token_type::punctuator_modulo)] 516 | | lit('<' )[location][set_token(token_type::punctuator_less)] 517 | | lit('>' )[location][set_token(token_type::punctuator_greater)] 518 | | lit('^' )[location][set_token(token_type::punctuator_bitwise_xor)] 519 | | lit('|' )[location][set_token(token_type::punctuator_bitwise_or)] 520 | | lit('?' )[location][set_token(token_type::punctuator_question)] 521 | | lit(':' )[location][set_token(token_type::punctuator_colon)] 522 | | lit(';' )[location][set_token(token_type::punctuator)] 523 | | lit('=' )[location][set_token(token_type::punctuator)] 524 | | lit(',' )[location][set_token(token_type::punctuator_comma)] 525 | | lit("bitand")[location][set_token(token_type::punctuator_ampersand)] >> omit[!rules.identifier] 526 | | lit("and_eq")[location][set_token(token_type::punctuator)] >> omit[!rules.identifier] 527 | | lit("xor_eq")[location][set_token(token_type::punctuator)] >> omit[!rules.identifier] 528 | | lit("not_eq")[location][set_token(token_type::punctuator_not_equal)] >> omit[!rules.identifier] 529 | | lit("bitor" )[location][set_token(token_type::punctuator_bitwise_or)] >> omit[!rules.identifier] 530 | | lit("compl" )[location][set_token(token_type::punctuator_bitwise_not)] >> omit[!rules.identifier] 531 | | lit("or_eq" )[location][set_token(token_type::punctuator)] >> omit[!rules.identifier] 532 | | lit("and" )[location][set_token(token_type::punctuator_logical_and)] >> omit[!rules.identifier] 533 | | lit("xor" )[location][set_token(token_type::punctuator_bitwise_xor)] >> omit[!rules.identifier] 534 | | lit("not" )[location][set_token(token_type::punctuator_logical_not)] >> omit[!rules.identifier] 535 | | lit("or" )[location][set_token(token_type::punctuator_logical_or)] >> omit[!rules.identifier] 536 | )) 537 | AUTO_RULE(pp_number, veiler::pegasus::transient( 538 | ( rules.digit 539 | | lit('.') >> rules.digit 540 | ) 541 | >> *( -lit('\'') >> rules.digit 542 | | lit('e') >> rules.sign 543 | | lit('E') >> rules.sign 544 | | lit('p') >> rules.sign 545 | | lit('P') >> rules.sign 546 | | lit('.') 547 | | -lit('\'') >> rules.ident_nondigit 548 | ) 549 | )) 550 | AUTO_RULE(character_literal, veiler::pegasus::transient( 551 | -( lit("u8") 552 | | rules.encoding_prefix 553 | ) 554 | >> lit('\'') 555 | >> +rules.c_char 556 | >> lit('\'') 557 | >> -rules.identifier//UDL 558 | )) 559 | AUTO_RULE(encoding_prefix, veiler::pegasus::transient( 560 | lit('u') 561 | | lit('U') 562 | | lit('L') 563 | )) 564 | AUTO_RULE(c_char, veiler::pegasus::transient( 565 | ( read - lit('\'') - lit('\\') - lit('\n') ) 566 | | rules.escape_sequence 567 | )) 568 | AUTO_RULE(escape_sequence, veiler::pegasus::transient( 569 | lit('\\') 570 | >> ( lit('\'') 571 | | lit('"') 572 | | lit('?') 573 | | lit('\\') 574 | | lit('a') 575 | | lit('b') 576 | | lit('f') 577 | | lit('n') 578 | | lit('r') 579 | | lit('t') 580 | | lit('v') 581 | | rules.octo >> rules.octo >> rules.octo 582 | | rules.octo >> rules.octo 583 | | rules.octo 584 | | lit('x') >> +rules.hex 585 | ) 586 | )) 587 | AUTO_RULE(string_literal, veiler::pegasus::transient( 588 | ( -( lit("u8") 589 | | rules.encoding_prefix 590 | ) 591 | >> lit('"') 592 | >> *rules.s_char 593 | >> lit('"') 594 | >> -rules.identifier 595 | )[location][set_token(token_type::string_literal)] 596 | | 597 | ( -( lit("u8") 598 | | rules.encoding_prefix 599 | ) 600 | >> lit("R\"") 601 | >> veiler::pegasus::filter([&rules](auto&& v, auto&& end, auto&&... args){ 602 | const auto raw_string_literal_parser = 603 | (*rules.d_char)[location][([](auto&& loc, auto&&, auto&& delim, [[maybe_unused]] auto&&... unused){delim.assign(loc.begin(), loc.end());return veiler::pegasus::unit{};})] 604 | >> lit('(') 605 | >> *(veiler::pegasus::read 606 | - ( lit(')') 607 | >> veiler::pegasus::loop( 608 | veiler::pegasus::eps[([](auto&&, auto&&, auto&& delim, [[maybe_unused]] auto&&... unused){return delim.size();})], 609 | rules.d_char[value])[veiler::pegasus::semantic_actions::change_container] 610 | [([](auto&& v, auto&& loc, auto&& delim, [[maybe_unused]] auto&&... unused) 611 | ->veiler::expected>{ 612 | if(v != delim)return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"raw string literal: unmatch delimiter"}); 613 | else return veiler::pegasus::unit{}; 614 | })] 615 | >> lit('"') 616 | )) 617 | >> lit(')') 618 | >> veiler::pegasus::loop( 619 | veiler::pegasus::eps[([](auto&&, auto&&, auto&& delim, [[maybe_unused]] auto&&... unused){return delim.size();})], 620 | rules.d_char) 621 | >> &lit('"'); 622 | auto it = messer::get_raw(v); 623 | auto ret = raw_string_literal_parser[omit](it, messer::get_raw(end), args...); 624 | messer::get_raw(v) = it; 625 | ++v; 626 | return ret.valid(); 627 | }) 628 | >> -rules.identifier//UDL 629 | )[location][set_token(token_type::string_literal)] 630 | )) 631 | AUTO_RULE(s_char, veiler::pegasus::transient( 632 | ( read - lit('"') - lit('\\') - lit('\n') ) 633 | | rules.escape_sequence 634 | )) 635 | AUTO_RULE(d_char, veiler::pegasus::transient( 636 | read 637 | - lit(' ') 638 | - lit('(') 639 | - lit(')') 640 | - lit('\\') 641 | - lit('\t') 642 | - lit('\v') 643 | - lit('\f') 644 | - lit('\n') 645 | )) 646 | AUTO_RULE(directive, veiler::pegasus::transient( 647 | ( lit("include") >> &( rules.white_spaces 648 | | lit('<') 649 | | lit('"') 650 | ) 651 | )[location][set_token(token_type::identifier_include)] 652 | | 653 | ( lit("define") >> & rules.white_spaces 654 | )[location][set_token(token_type::identifier_define)] 655 | | 656 | ( lit("undef") >> & rules.white_spaces 657 | )[location][set_token(token_type::identifier_undef)] 658 | | 659 | ( lit("line") >> & rules.white_spaces 660 | )[location][set_token(token_type::identifier_line)] 661 | | 662 | ( lit("error") >> &( rules.white_spaces 663 | | lit('\n') 664 | ) 665 | )[location][set_token(token_type::identifier_error)] 666 | | 667 | ( lit("pragma") >> &( rules.white_spaces 668 | | lit('\n') 669 | ) 670 | )[location][set_token(token_type::identifier_pragma)] 671 | | 672 | ( lit("if") >> &( rules.white_spaces 673 | | lit('(') 674 | ) 675 | )[location][set_token(token_type::identifier_if)] 676 | | 677 | ( lit("ifdef") >> & rules.white_spaces 678 | )[location][set_token(token_type::identifier_ifdef)] 679 | | 680 | ( lit("ifndef") >> & rules.white_spaces 681 | )[location][set_token(token_type::identifier_ifndef)] 682 | | 683 | ( lit("elif") >> &( rules.white_spaces 684 | | lit('(') 685 | ) 686 | )[location][set_token(token_type::identifier_elif)] 687 | | 688 | ( lit("else") >> &( rules.white_spaces 689 | | lit('\n') 690 | ) 691 | )[location][set_token(token_type::identifier_else)] 692 | | 693 | ( lit("endif") >> &( rules.white_spaces 694 | | lit('\n') 695 | ) 696 | )[location][set_token(token_type::identifier_endif)] 697 | )) 698 | AUTO_RULE(identifier, veiler::pegasus::transient( 699 | ( 700 | rules.ident_nondigit 701 | >> *( rules.ident_nondigit 702 | | rules.digit 703 | ) 704 | ) 705 | )) 706 | AUTO_RULE(white_spaces, veiler::pegasus::transient( 707 | +( lit(' ') 708 | | lit('\t') 709 | | lit("/*") >> *( read - lit("*/") ) >> lit("*/") 710 | | lit("//") >> *( read - lit('\n') ) 711 | | lit('\v') 712 | | lit('\f') 713 | ) 714 | )) 715 | RULE(ident_nondigit, char, veiler::pegasus::transient( 716 | rules.nondigit 717 | )) 718 | RULE(nondigit, char, veiler::pegasus::transient( 719 | range('A', 'Z')[value] 720 | | range('a', 'z')[value] 721 | | lit('_')[value] 722 | )) 723 | RULE(digit, char, veiler::pegasus::transient( 724 | range('0', '9')[value] 725 | )) 726 | RULE(hex, char, veiler::pegasus::transient( 727 | rules.digit 728 | | range('A', 'F')[value] 729 | | range('a', 'f')[value] 730 | )) 731 | RULE(octo, char, veiler::pegasus::transient( 732 | range('0', '7')[value] 733 | )) 734 | RULE(sign, char, veiler::pegasus::transient( 735 | lit('+')[value] 736 | | lit('-')[value] 737 | )) 738 | }; 739 | public: 740 | class value_type : public token{ 741 | using parent = token; 742 | annotation_type data; 743 | public: 744 | value_type(parent&& tk, const annotation_type& anno):parent{std::move(tk)}, data{anno}{} 745 | std::string_view filename()const{return data.filename;} 746 | std::size_t line()const{return data.line;} 747 | std::size_t column()const{return data.column;} 748 | const annotation_type& annotation()const{return data;} 749 | annotation_type& annotation(){return data;} 750 | value_type& filename(std::string_view sv){data.filename = std::move(sv); return *this;} 751 | value_type& line(std::size_t ln){data.line = ln; return *this;} 752 | friend std::ostream& operator<<(std::ostream& os, const value_type& v){return os << *static_cast(&v);} 753 | }; 754 | private: 755 | template 756 | class lexer_iterator_impl{ 757 | using impl = typename T::iterator; 758 | impl it; 759 | impl end; 760 | enum class status{ 761 | first, 762 | pp_directive, 763 | include, 764 | none 765 | }st = status::first; 766 | token_type tkt = token_type::eol; 767 | impl beg; 768 | bool result; 769 | public: 770 | using value_type = phase3_t::value_type; 771 | using iterator = filter_iterator>; 772 | lexer_iterator_impl(const impl& b, const impl& e):it(b), end(e), beg(b), result(b != e){} 773 | lexer_iterator_impl(const lexer_iterator_impl&) = default; 774 | lexer_iterator_impl& operator=(const lexer_iterator_impl&) = default; 775 | value_type dereference()const{ 776 | if(!result) 777 | throw std::runtime_error("can't dereference it"); 778 | const auto& i = get_raw(beg); 779 | const auto anno = annotation_type{i.get_filename(), i.get_line(), i.get_column()}; 780 | if(tkt != token_type::string_literal || *beg == '"') 781 | return value_type{token{std::string{beg, it}, tkt}, anno}; 782 | auto itt = beg; 783 | while(std::next(itt) != end && *std::next(itt) != '"') 784 | ++itt; 785 | if(*itt != 'R') 786 | return value_type{token{std::string{beg, it}, tkt}, anno}; 787 | ++itt; 788 | auto edit = itt; 789 | auto edit_raw = messer::get_raw(edit); 790 | std::string delimiter; 791 | for(auto itr = std::next(edit_raw); *itr != '('; ++itr) 792 | delimiter.push_back(*itr); 793 | std::advance(edit_raw, delimiter.size()); 794 | while(true){ 795 | while(*edit_raw++ != ')'); 796 | auto itr = edit_raw; 797 | for(auto&& x : delimiter){ 798 | if(*itr++ != x) 799 | break; 800 | } 801 | if(*itr == '"'){ 802 | messer::get_raw(edit) = itr; 803 | break; 804 | } 805 | } 806 | return value_type{token{std::string{beg, itt} + std::string{messer::get_raw(itt).get_inner(), messer::get_raw(edit).get_inner()} + std::string{edit, it} , tkt}, anno}; 807 | } 808 | void next(){ 809 | if(!result) 810 | return; 811 | beg = it; 812 | auto ret = (st == status::include ? 813 | lexer::inner_include()(it, end, std::string{}): 814 | lexer::entrypoint ()(it, end, std::string{})); 815 | result = ret && it != beg; 816 | if(!result) 817 | return; 818 | tkt = ret--->second; 819 | if(st == status::first && tkt == token_type::punctuator_hash) 820 | st = status::pp_directive; 821 | else if(st == status::pp_directive && tkt == token_type::identifier_include) 822 | st = status::include; 823 | else if(tkt == token_type::eol) 824 | st = status::first; 825 | else if(tkt != token_type::white_space) 826 | st = status::none; 827 | } 828 | bool is_equal(const lexer_iterator_impl& other)const noexcept{return result == other.result && it == other.it;} 829 | auto& get_raw_iterator() {return it;} 830 | const auto& get_raw_iterator()const{return it;} 831 | }; 832 | template 833 | using lexer_range = filter_range; 834 | public: 835 | template 836 | friend constexpr auto operator|(T&& t, const phase3_t&)noexcept{ 837 | return lexer_range{std::forward(t)}; 838 | } 839 | }; 840 | 841 | } 842 | 843 | namespace veiler{ 844 | 845 | template<> 846 | struct hash : hash>, hash, hash, hash{ 847 | constexpr hash() = default; 848 | constexpr hash(const hash&) = default; 849 | constexpr hash(hash&&) = default; 850 | ~hash() = default; 851 | hash& operator=(const hash&) = default; 852 | hash& operator=(hash&&) = default; 853 | using result_type = std::size_t; 854 | using argument_type = messer::phase3_t::value_type; 855 | std::size_t operator()(const argument_type& key)const noexcept{ 856 | return detail::fool::hash_combine(hash>::operator()(static_cast>(key.type())), hash::operator()(key.get()), hash::operator()(key.filename()), hash::operator()(key.line()), hash::operator()(key.column())); 857 | } 858 | }; 859 | 860 | } 861 | 862 | namespace veiler::pegasus{ 863 | 864 | template<> 865 | struct member_accessor{ 866 | static const std::string& access(const messer::phase3_t::value_type& t){return t.get();} 867 | }; 868 | template<> 869 | struct member_accessor{ 870 | static const std::string& access(const messer::phase3_t::value_type& t){return t.get();} 871 | }; 872 | template<> 873 | struct member_accessor{ 874 | static const std::string& access(const messer::phase3_t::value_type& t){return t.get();} 875 | }; 876 | template<> 877 | struct member_accessor{ 878 | static messer::token_type access(const messer::phase3_t::value_type& t){return t.type();} 879 | }; 880 | 881 | } 882 | 883 | #include 884 | #include 885 | #include 886 | namespace messer{ 887 | 888 | template 889 | inline bool tokens_equal(const T& t, const U& u){ 890 | if(t.size() != u.size()) 891 | return false; 892 | for(auto t_it = t.begin(), u_it = u.begin(); t_it != t.end(); ++t_it, ++u_it) 893 | if(t_it->get() != u_it->get()) 894 | return false; 895 | return true; 896 | } 897 | 898 | template 899 | inline std::vector vector_product(std::vector x, std::vector y){ 900 | std::sort(x.begin(), x.end()); 901 | std::sort(y.begin(), y.end()); 902 | std::vector product; 903 | product.reserve(x.size() + y.size()); 904 | std::set_intersection(x.begin(), x.end(), y.begin(), y.end(), std::back_inserter(product)); 905 | return product; 906 | } 907 | 908 | namespace detail{ 909 | 910 | template 911 | struct list_replace_1{ 912 | output_range::const_iterator> r; 913 | std::list data; 914 | output_range::iterator> operator()(std::list& l){ 915 | if(data.empty()){ 916 | const auto it = l.erase(r.begin(), r.end()); 917 | return output_range::iterator>{it, it}; 918 | } 919 | const auto inserted_begin = data.begin(); 920 | l.splice(r.begin(), std::move(data)); 921 | return output_range::iterator>{inserted_begin, l.erase(r.begin(), r.end())}; 922 | } 923 | friend output_range::iterator> operator|(std::list& l, list_replace_1&& rep){return std::move(rep)(l);} 924 | list_replace_1(output_range::const_iterator> r, std::list&& data):r{std::move(r)}, data{std::move(data)}{} 925 | list_replace_1(output_range::iterator> r, std::list&& data):r{r.begin(), r.end()}, data{std::move(data)}{} 926 | }; 927 | 928 | template 929 | struct list_replace_2{ 930 | output_range::iterator> r; 931 | T data; 932 | output_range::iterator> operator()(std::list& l){ 933 | const auto inserted_begin = l.insert(r.begin(), std::move(data)); 934 | return {inserted_begin, l.erase(r.begin(), r.end())}; 935 | } 936 | friend output_range::iterator> operator|(std::list& l, list_replace_2&& rep){return std::move(rep)(l);} 937 | }; 938 | 939 | template 940 | struct list_replace_3{ 941 | output_range::iterator> r; 942 | output_range data; 943 | output_range::iterator> operator()(std::list& l){ 944 | const auto inserted_begin = l.insert(r.begin(), data.begin(), data.end()); 945 | return {inserted_begin, l.erase(r.begin(), r.end())}; 946 | } 947 | friend output_range::iterator> operator|(std::list& l, list_replace_3&& rep){return std::move(rep)(l);} 948 | }; 949 | 950 | } 951 | 952 | template 953 | inline detail::list_replace_1::value_type> replacer(const T& rb, const T& re, std::list::value_type> l){return detail::list_replace_1::value_type>(output_range{rb, re}, std::move(l));} 954 | template 955 | inline detail::list_replace_2::value_type> replacer(const T& rb, const T& re, typename std::iterator_traits::value_type t){return {output_range{rb, re}, std::move(t)};} 956 | template 957 | inline detail::list_replace_3::value_type, U> replacer(const T& rb, const T& re, const output_range& r2){return {output_range{rb, re}, r2};} 958 | template 959 | inline detail::list_replace_3::value_type, std::common_type_t> replacer(const T& rb, const T& re, const U& b, const Y& e){return replacer(rb, re, output_range>{b, e});} 960 | 961 | inline std::string escape(std::string_view str){ 962 | std::string ret; 963 | for(auto&& x : str) 964 | switch(x){ 965 | case '\t':ret += "\\t";break; 966 | case '\'':ret += "\\\'";break; 967 | case '"': ret += "\\\"";break; 968 | case '\\':ret += "\\\\";break; 969 | case '\a':ret += "\\a";break; 970 | case '\b':ret += "\\b";break; 971 | case '\f':ret += "\\f";break; 972 | case '\n':ret += "\\n";break; 973 | case '\r':ret += "\\r";break; 974 | case '\v':ret += "\\v";break; 975 | default: ret += x;break; 976 | } 977 | return ret; 978 | } 979 | 980 | inline std::string unescape(std::string_view str){ 981 | static constexpr auto oct = veiler::pegasus::filter([](auto&& x, auto&&){return '0' <= *x && *x <= '8';})[([](auto&& x, [[maybe_unused]] auto&&... unused)->int{return *x - '0';})] >> veiler::pegasus::read[veiler::pegasus::semantic_actions::omit]; 982 | static constexpr auto hex = veiler::pegasus::filter([](auto&& x, auto&&){return '0' <= *x && *x <= '9';})[([](auto&& x, [[maybe_unused]] auto&&... unused)->int{return *x - '0';})] >> veiler::pegasus::read[veiler::pegasus::semantic_actions::omit] 983 | | veiler::pegasus::filter([](auto&& x, auto&&){return 'a' <= *x && *x <= 'f';})[([](auto&& x, [[maybe_unused]] auto&&... unused)->int{return *x - 'a'+10;})] >> veiler::pegasus::read[veiler::pegasus::semantic_actions::omit] 984 | | veiler::pegasus::filter([](auto&& x, auto&&){return 'A' <= *x && *x <= 'F';})[([](auto&& x, [[maybe_unused]] auto&&... unused)->int{return *x - 'A'+10;})] >> veiler::pegasus::read[veiler::pegasus::semantic_actions::omit]; 985 | std::string ret; 986 | ret.reserve(str.size()); 987 | for(auto it = str.begin(); it != str.end();) 988 | if(*it != '\\') 989 | ret += *it++; 990 | else if(it+1 != str.end())switch(*(it+1)){ 991 | case 't': ret += '\t';it += 2;break; 992 | case '\'':ret += '\'';it += 2;break; 993 | case '"':ret += '"';it += 2;break; 994 | case '\\':ret += '\\';it += 2;break; 995 | case '?': ret += '?';it += 2;break; 996 | case 'a': ret += '\a';it += 2;break; 997 | case 'b': ret += '\b';it += 2;break; 998 | case 'f': ret += '\f';it += 2;break; 999 | case 'n': ret += '\n';it += 2;break; 1000 | case 'r': ret += '\r';it += 2;break; 1001 | case 'v': ret += '\v';it += 2;break; 1002 | case 'x':{ 1003 | int t = 0; 1004 | auto itt = it+2; 1005 | if(auto h = hex(itt, str.end())) 1006 | t = t*16+*h; 1007 | else 1008 | throw std::runtime_error("unescape: invalid \\x"); 1009 | while(auto h = hex(itt, str.end())) 1010 | t = t*16+*h; 1011 | ret.push_back(static_cast(t)); 1012 | it = itt; 1013 | }break; 1014 | default:{ 1015 | int t = 0; 1016 | auto itt = it+2; 1017 | if(auto h = oct(itt, str.end())) 1018 | t = t*8+*h; 1019 | else 1020 | throw std::runtime_error("unescape: invalid \\"); 1021 | if(auto h = oct(itt, str.end())){ 1022 | t = t*8+*h; 1023 | if(auto h = oct(itt, str.end())) 1024 | t = t*8+*h; 1025 | } 1026 | ret.push_back(static_cast(t)); 1027 | it = itt; 1028 | } 1029 | } 1030 | return ret; 1031 | } 1032 | 1033 | template 1034 | inline std::string stringizer(const output_range& r){ 1035 | std::string str; 1036 | for(auto&& x : r) 1037 | if(x.type() == token_type::white_space 1038 | || x.type() == token_type::eol) 1039 | if(str.back() == ' ') 1040 | continue; 1041 | else 1042 | str += ' '; 1043 | else 1044 | if(x.type() == token_type::unclassified_character) 1045 | str += x.get(); 1046 | else 1047 | str += escape(x.get()); 1048 | return str; 1049 | } 1050 | template 1051 | inline std::string stringizer(const T& b, const T& e){ 1052 | return stringizer(output_range{b, e}); 1053 | } 1054 | 1055 | struct string_literal{ 1056 | std::string str; 1057 | std::string suffix;//for UDL 1058 | enum class prefix{none, L, u, U, u8} is; 1059 | template 1060 | static std::optional destringize(T&& token){ 1061 | assert(token.type() == token_type::string_literal); 1062 | auto it = token.get().cbegin(); 1063 | auto end = token.get().cend(); 1064 | prefix is = prefix::none; 1065 | switch(*it){ 1066 | case 'L': 1067 | is = prefix::L; 1068 | ++it; 1069 | break; 1070 | case 'u': 1071 | if(*(it+1) == '8') 1072 | is = prefix::u8, ++it; 1073 | else 1074 | is = prefix::u; 1075 | ++it; 1076 | break; 1077 | case 'U': 1078 | is = prefix::U; 1079 | ++it; 1080 | break; 1081 | default:; 1082 | } 1083 | const bool is_raw = *it == 'R'; 1084 | if(is_raw)++it; 1085 | if(*it++ != '"') 1086 | return std::nullopt; 1087 | if(!is_raw){ 1088 | while(*--end != '"'); 1089 | return string_literal{unescape(std::string_view{&*it, static_cast(end-it)}), std::string(end+1, token.get().cend()), is}; 1090 | } 1091 | std::string delim; 1092 | while(*it != '(') 1093 | delim.push_back(*it++); 1094 | ++it; 1095 | end = it; 1096 | while(end != token.get().cend()){ 1097 | if(*end == ')'){ 1098 | std::string_view str{&*(end+1), delim.size()}; 1099 | if(str == delim && *(end+1+delim.size()) == '"') 1100 | return string_literal{std::string(it, end), std::string(end+2+delim.size(), token.get().cend()), is}; 1101 | } 1102 | ++end; 1103 | } 1104 | return std::nullopt; 1105 | } 1106 | phase3_t::value_type stringize(const annotation_type& anno)const{ 1107 | std::string s; 1108 | switch(is){ 1109 | case prefix::none:break; 1110 | case prefix::L:s.push_back('L');break; 1111 | case prefix::u:s.push_back('u');break; 1112 | case prefix::U:s.push_back('U');break; 1113 | case prefix::u8:s.push_back('u');s.push_back('8');break; 1114 | } 1115 | s.push_back('"'); 1116 | s += escape(str); 1117 | s.push_back('"'); 1118 | s += suffix; 1119 | return phase3_t::value_type{{std::move(s), token_type::string_literal}, anno}; 1120 | } 1121 | string_literal& operator+=(const string_literal& rhs){ 1122 | if(is == prefix::none) 1123 | is = rhs.is; 1124 | else if(rhs.is != prefix::none && is != rhs.is) 1125 | throw std::runtime_error("concat string literals failed (unmatch prefixes)"); 1126 | if(suffix.empty()) 1127 | suffix = rhs.suffix; 1128 | else if(!rhs.suffix.empty() && suffix != rhs.suffix) 1129 | throw std::runtime_error("concat string literals failed (unmatch user-defined literals)"); 1130 | str += rhs.str; 1131 | return *this; 1132 | } 1133 | }; 1134 | 1135 | template 1136 | struct iterator_hasher : private std::hash::pointer>, std::hash::value_type>{ 1137 | iterator_hasher() = default; 1138 | iterator_hasher(const iterator_hasher&) = default; 1139 | iterator_hasher(iterator_hasher&&) = default; 1140 | ~iterator_hasher() = default; 1141 | iterator_hasher& operator=(const iterator_hasher&) = default; 1142 | iterator_hasher& operator=(iterator_hasher&&) = default; 1143 | std::size_t operator()(T key)const{return veiler::detail::fool::hash_combine(static_cast::pointer>*>(this)->operator()(std::addressof(*key)), static_cast::value_type>*>(this)->operator()(*key));} 1144 | using result_type = std::size_t; 1145 | using argument_type = T; 1146 | }; 1147 | 1148 | } 1149 | 1150 | namespace std{ 1151 | 1152 | template<> 1153 | struct hash : hash{ 1154 | using result_type = std::size_t; 1155 | using argument_type = messer::phase3_t::value_type; 1156 | std::size_t operator()(const argument_type& key)const{return static_cast*>(this)->operator()(key.get());} 1157 | }; 1158 | 1159 | } 1160 | 1161 | #include 1162 | #include 1163 | 1164 | namespace messer{ 1165 | 1166 | static std::list phase6(std::list); 1167 | 1168 | class phase4_t{ 1169 | public: 1170 | using token_t = phase3_t::value_type; 1171 | 1172 | using filepath = std::filesystem::path; 1173 | std::vector system_include_dir; 1174 | std::vector include_dir; 1175 | std::unordered_map> files; 1176 | std::unordered_map::const_iterator>> objects; 1177 | struct func_t{ 1178 | int arg_num; 1179 | std::vector arg_index; 1180 | output_range::const_iterator> dst; 1181 | }; 1182 | std::unordered_map functions; 1183 | struct pp_state{ 1184 | std::list& list; 1185 | std::unordered_map::const_iterator, std::vector, iterator_hasher::const_iterator>> replaced; 1186 | }; 1187 | template 1188 | static constexpr auto _(T&& t){return veiler::pegasus::lit(std::forward(t))[veiler::pegasus::semantic_actions::omit];} 1189 | struct passed_identity_t{ 1190 | constexpr passed_identity_t() = default; 1191 | template 1192 | constexpr bool operator()(T&&)const{return true;} 1193 | }static constexpr passed_identity = {}; 1194 | struct eval_macro_t{ 1195 | constexpr eval_macro_t() = default; 1196 | template 1197 | static auto en_us_utf8_locale_for_time(F&& f){ 1198 | struct raii{ 1199 | std::string saved_locale; 1200 | raii() : saved_locale{std::setlocale(LC_TIME, nullptr)}{ 1201 | std::setlocale(LC_TIME, "en_us.UTF-8"); 1202 | } 1203 | ~raii(){ 1204 | std::setlocale(LC_TIME, saved_locale.c_str()); 1205 | } 1206 | }_; 1207 | return f(); 1208 | } 1209 | static std::string format_time_point(const std::chrono::system_clock::time_point& time, const char* strftime_format, std::string_view expected_format){ 1210 | return en_us_utf8_locale_for_time([&]{ 1211 | auto t = std::chrono::system_clock::to_time_t(time); 1212 | std::string str{expected_format}; 1213 | str.push_back('.'); 1214 | std::strftime(str.data(), str.size(), strftime_format, std::localtime(&t)); 1215 | str.pop_back(); 1216 | return str; 1217 | }); 1218 | } 1219 | static std::string time(){ 1220 | return format_time_point(std::chrono::system_clock::now(), "%H:%M:%S", "hh:mm:ss"); 1221 | } 1222 | static std::string date(){ 1223 | return format_time_point(std::chrono::system_clock::now(), "%b %e %Y", "Mmm dd yyyy"); 1224 | } 1225 | template 1226 | static auto cat_token(T&& prev, U&& next, V&& hashhash){ 1227 | if(prev.type() == token_type::empty) 1228 | return next; 1229 | if(next.type() == token_type::empty) 1230 | return prev; 1231 | auto str = prev.get() + next.get(); 1232 | auto range = str | annotation{prev.annotation()} | phase3_t{}; 1233 | if(std::distance(std::next(range.begin()), range.end()) != 1){ 1234 | std::string message = std::string{hashhash->filename()} + ':' + std::to_string(hashhash->line()) + ':' + std::to_string(hashhash->column()) + ": error: operator ## makes invalid token"; 1235 | const auto f = [](auto t){ 1236 | std::stringstream ss; 1237 | ss << t; 1238 | return ss.str(); 1239 | }; 1240 | for(auto it = std::next(range.begin()); it != range.end(); ++it) 1241 | message += "\n " + std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": " + it->get() + '(' + f(it->type()) + ")"; 1242 | throw std::runtime_error(std::move(message)); 1243 | } 1244 | auto t = *std::next(range.begin()); 1245 | if(t.type() == token_type::punctuator_hash || t.type() == token_type::punctuator_hashhash) 1246 | return token_t{token{t.get(), token_type::punctuator}, t.annotation()}; 1247 | return t; 1248 | } 1249 | template 1250 | static auto search_(Iterator it, Iterator sentinel, F&& f){ 1251 | if(it == sentinel) 1252 | throw std::runtime_error("search_ failed"); 1253 | do{ 1254 | f(it); 1255 | if(it == sentinel) 1256 | throw std::runtime_error("search_ failed"); 1257 | }while(is_white_spaces(it->type())); 1258 | return it; 1259 | } 1260 | template 1261 | static auto apply_cat(Hash&& hashhash, pp_state& pps){ 1262 | static auto search = [](const auto& it, auto sentinel, auto&& f){ 1263 | try{ 1264 | return search_(it, std::move(sentinel), f); 1265 | }catch(std::runtime_error&){ 1266 | throw std::runtime_error(std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: operator ## can't receive parameter(search_parameter reach edge)"); 1267 | } 1268 | }; 1269 | const auto prev = search(hashhash, pps.list.begin(), [](auto&& it){--it;}); 1270 | auto next = search(hashhash, pps.list.end(), [](auto&& it){++it;}); 1271 | const auto replaced_pos = pps.list.insert(prev, cat_token(*prev, *next, hashhash)); 1272 | ++next; 1273 | for(auto it = prev; it != next; ++it) 1274 | pps.replaced.erase(it); 1275 | pps.list.erase(prev, next); 1276 | return replaced_pos; 1277 | } 1278 | template 1279 | auto object_macro_replace(const decltype(objects)::const_iterator& object_it, Passed&& passed, const phase4_t& state, pp_state& tmp_state, Iterator&& it, const End& end, Yield&& yield)const{ 1280 | auto check_recur = tmp_state.replaced.find(it); 1281 | if(check_recur != tmp_state.replaced.end()) 1282 | for(auto&& x : check_recur->second) 1283 | if(it->get() == x) 1284 | return passed(*it++); 1285 | std::list copy(object_it->second.begin(), object_it->second.end()); 1286 | for(auto&& x : copy) 1287 | x.annotation() = it->annotation(); 1288 | copy.push_front({{"", token_type::empty}, it->annotation()}); 1289 | pp_state copy_state{copy, std::move(tmp_state.replaced)}; 1290 | yield(state, copy_state, copy.begin(), {output_range::const_iterator>{copy.begin(), copy.end()}, output_range::const_iterator>{std::next(it), end}}); 1291 | for(auto it_ = std::next(copy.begin()), end_ = copy.end(); it_ != end_; ++it_) 1292 | if(it_->type() == token_type::punctuator_hashhash) 1293 | it_ = apply_cat(it_, copy_state), 1294 | yield(state, copy_state, std::next(it_), {output_range::const_iterator>{copy.begin(), copy.end()}, output_range::const_iterator>{std::next(it), end}}); 1295 | copy.pop_front(); 1296 | for(auto it_ = copy.begin(), end_ = copy.end(); it_ != end_; ++it_){ 1297 | if(check_recur != tmp_state.replaced.end()) 1298 | copy_state.replaced[it_] = check_recur->second; 1299 | copy_state.replaced[it_].emplace_back(it->get()); 1300 | } 1301 | tmp_state.replaced = std::move(copy_state.replaced); 1302 | auto replaced = (tmp_state.list|replacer(it, std::next(it), std::move(copy))); 1303 | it = replaced.begin(); 1304 | return true; 1305 | } 1306 | template 1307 | auto save_defined_argument(Passed&& passed, Iterator&& it, const End& end)const{ 1308 | static constexpr auto identifier = veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return is_identifier(veiler::pegasus::member_access(*v++));}); 1309 | static constexpr auto arg_parser = ( 1310 | veiler::pegasus::read //token_type::identifier_defined 1311 | >> ( ( _(token_type::punctuator_left_parenthesis) 1312 | >> identifier 1313 | >> _(token_type::punctuator_right_parenthesis) 1314 | ) 1315 | | identifier 1316 | ) 1317 | ).with_skipper(*veiler::pegasus::filter([](auto&& it, [[maybe_unused]] auto&&... unused){return is_white_spaces(veiler::pegasus::member_access(*it++));})); 1318 | auto parse_result = arg_parser[veiler::pegasus::semantic_actions::location](it, end); 1319 | if(!parse_result) 1320 | return false; 1321 | for(auto&& x : *parse_result) 1322 | passed(x); 1323 | return true; 1324 | } 1325 | template 1326 | auto save_has_include_argument(Passed&& passed, Iterator&& it, const End& end)const{ 1327 | static constexpr auto arg_parser = ( 1328 | veiler::pegasus::read //token_type::identifier_has_include 1329 | >> _(token_type::punctuator_left_parenthesis) 1330 | >> ( _(token_type::header_name) 1331 | | _(token_type::string_literal) 1332 | | veiler::pegasus::lexeme[_(token_type::punctuator_less) >> *(veiler::pegasus::read - _(token_type::punctuator_greater)) >> _(token_type::punctuator_greater)] 1333 | ) 1334 | >> _(token_type::punctuator_right_parenthesis) 1335 | ).with_skipper(*veiler::pegasus::filter([](auto&& it, [[maybe_unused]] auto&&... unused){return is_white_spaces(veiler::pegasus::member_access(*it++));})); 1336 | auto parse_result = arg_parser[veiler::pegasus::semantic_actions::location](it, end); 1337 | if(!parse_result) 1338 | return false; 1339 | for(auto&& x : *parse_result) 1340 | passed(x); 1341 | return true; 1342 | } 1343 | template 1344 | auto operator()(Self&& self, Passed&& passed, const phase4_t& state, pp_state& tmp_state, Iterator&& it, const End& end, Yield&& yield)const{ 1345 | if(it == end) 1346 | return false; 1347 | if(!is_identifier(it->type())) 1348 | return passed(*it++); 1349 | if constexpr(InArithmeticEvaluation){ 1350 | if(it->type() == token_type::identifier_defined) 1351 | return save_defined_argument(std::forward(passed), std::forward(it), end); 1352 | if(it->type() == token_type::identifier_has_include) 1353 | return save_has_include_argument(std::forward(passed), std::forward(it), end); 1354 | } 1355 | bool is_pragma_op = false; 1356 | { 1357 | const auto make_token_and_pass = [&](std::string&& str, token_type tt = token_type::string_literal){ 1358 | std::list list{phase3_t::value_type{{std::move(str), tt}, it->annotation()}}; 1359 | yield(state, tmp_state, it, {output_range::const_iterator>{list.begin(), list.end()}, {std::next(it), end}}); 1360 | it = (tmp_state.list|replacer(it, std::next(it), std::move(list))).begin(); 1361 | return true; 1362 | }; 1363 | switch(it->type()){ 1364 | case token_type::identifier_time_: 1365 | return make_token_and_pass('"'+time()+'"'); 1366 | case token_type::identifier_date_: 1367 | return make_token_and_pass('"'+date()+'"'); 1368 | case token_type::identifier_file_: 1369 | return make_token_and_pass('"'+escape(it->filename())+'"'); 1370 | case token_type::identifier_line_: 1371 | return make_token_and_pass(std::to_string(it->line()), token_type::pp_number); 1372 | case token_type::identifier_pragma_op: 1373 | is_pragma_op = true; 1374 | [[fallthrough]]; 1375 | default: 1376 | break; 1377 | } 1378 | } 1379 | { 1380 | auto object_it = state.objects.find(it->get()); 1381 | if(object_it != state.objects.end()) 1382 | return object_macro_replace(object_it, std::forward(passed), state, tmp_state, std::forward(it), end, std::forward(yield)); 1383 | } 1384 | constexpr auto white_spaces = veiler::pegasus::filter([](auto&& it, [[maybe_unused]] auto&&... unused){return is_white_spaces(veiler::pegasus::member_access(*it++));})[veiler::pegasus::semantic_actions::omit]; 1385 | struct arg_parser_data{ 1386 | using type = std::decay_t; 1387 | std::optional first; 1388 | std::optional last; 1389 | unsigned long nest_count; 1390 | }; 1391 | auto not_arg = _(token_type::punctuator_comma) | _(token_type::punctuator_right_parenthesis); 1392 | auto arg_parser = *white_spaces 1393 | >> ( +veiler::pegasus::freeze 1394 | ( ( _(token_type::punctuator_left_parenthesis) >> *white_spaces 1395 | >> *( _(token_type::punctuator_comma) >> *white_spaces 1396 | | veiler::pegasus::self[veiler::pegasus::semantic_actions::omit] >> *white_spaces 1397 | ) 1398 | >> _(token_type::punctuator_right_parenthesis) >> *white_spaces 1399 | ) 1400 | | 1401 | ( veiler::pegasus::read - not_arg - _(token_type::punctuator_left_parenthesis))[veiler::pegasus::semantic_actions::omit] 1402 | ) 1403 | | 1404 | ¬_arg//empty token 1405 | ) 1406 | ; 1407 | auto arg_parser_registrar = [](auto&& first, auto&& loc){ 1408 | auto ret = output_range::const_iterator>{first, loc.end()}; 1409 | return ret; 1410 | }; 1411 | auto args_parser = _(token_type::punctuator_left_parenthesis) 1412 | >> ( (*white_spaces)[([](auto&&, auto&& loc){return loc.end();})] 1413 | >> arg_parser[veiler::pegasus::semantic_actions::omit] 1414 | )[arg_parser_registrar] % _(token_type::punctuator_comma) 1415 | >> _(token_type::punctuator_right_parenthesis); 1416 | auto f = state.functions.find(it->get()); 1417 | if(f == state.functions.end() && !is_pragma_op) 1418 | return passed(*it++); 1419 | std::vector::const_iterator>> args; 1420 | auto arg_it = [&]{ 1421 | try{ 1422 | return search_(it, end,[](auto&& t){++t;}); 1423 | }catch(std::runtime_error& e){ 1424 | return end; 1425 | } 1426 | }(); 1427 | if(arg_it == end) 1428 | return passed(*it++); 1429 | if(!(&_(token_type::punctuator_left_parenthesis))(arg_it, end)) 1430 | return passed(*it++); 1431 | if(auto parsed_result = args_parser(arg_it, end)) 1432 | args = *parsed_result; 1433 | else{ 1434 | for(auto itt = it, end = std::next(arg_it); itt != end; ++itt){ 1435 | if(tmp_state.replaced.find(itt) != tmp_state.replaced.end()) 1436 | return passed(*it++); 1437 | } 1438 | throw std::runtime_error(std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: ')' does not exist"); 1439 | } 1440 | if(is_pragma_op){ 1441 | if(args.size() != 1) 1442 | return false; 1443 | { 1444 | auto it = args[0].begin(); 1445 | ++it; 1446 | if(it != args[0].end()) 1447 | return false; 1448 | } 1449 | if(args[0].begin()->type() != token_type::string_literal) 1450 | return false; 1451 | std::string scratch = "#pragma " + string_literal::destringize(*args[0].begin())->str; 1452 | auto range = scratch | annotation{""} | phase1_t{} | phase2_t{} | phase3_t{}; 1453 | std::list tokens(range.begin(), range.end()); 1454 | override_annotate oa{}; 1455 | const_cast(state).eval(tokens, output_range::const_iterator>{tokens.cbegin(), tokens.cend()}, oa, std::filesystem::current_path(), false, std::cout); 1456 | it = arg_it; 1457 | return true; 1458 | } 1459 | if(f->second.arg_num > 0 && f->second.arg_num != static_cast(args.size())) 1460 | return false; 1461 | //if argument list is (...) /*f->second.arg_num == -1*/, we can pass no arguments 1462 | //but (a, b, ...), we need 3 or more arguments(can't pass 2 arguments) 1463 | //GCC and clang can pass 2 args 1464 | static constexpr auto allow_pass_no_arg_to_variadic_param = false; 1465 | if(f->second.arg_num < -1 && -f->second.arg_num - (allow_pass_no_arg_to_variadic_param ? 1 : 0) > static_cast(args.size())) 1466 | return false; 1467 | if(allow_pass_no_arg_to_variadic_param && f->second.arg_num < -1 && -f->second.arg_num - 1 == static_cast(args.size())) 1468 | args.emplace_back(output_range::const_iterator>{args.back().end(), args.back().end()}); 1469 | if(f->second.arg_num == -1 && static_cast(args.size()) == 0) 1470 | args.emplace_back(output_range::const_iterator>{it, it}); 1471 | bool first = true; 1472 | std::vector recur; 1473 | for(auto it_ = it; it_ != arg_it && (first || !recur.empty()); ++it_){ 1474 | auto rit = tmp_state.replaced.find(it_); 1475 | if(rit != tmp_state.replaced.end()){ 1476 | if(first) 1477 | recur = rit->second, first = false; 1478 | else 1479 | recur = vector_product(std::move(recur), rit->second); 1480 | } 1481 | else 1482 | recur.clear(), first = false; 1483 | } 1484 | for(auto&& x : recur){ 1485 | if(x == it->get()){ 1486 | return passed(*it++); 1487 | } 1488 | } 1489 | { 1490 | auto rit = tmp_state.replaced.find(it); 1491 | if(rit != tmp_state.replaced.end()) 1492 | for(auto&& x : rit->second) 1493 | if(x == it->get()){ 1494 | return passed(*it++); 1495 | } 1496 | } 1497 | static auto pull_out_hash = [](auto&& list){ 1498 | for(auto _it = list.begin(); _it != list.end();++_it) 1499 | if(_it->type() == token_type::punctuator_hash || _it->type() == token_type::punctuator_hashhash) 1500 | _it->type() = token_type::punctuator; 1501 | }; 1502 | auto copy_insert = [&](auto&& list, auto&& it_, auto beg_, auto end_){ 1503 | std::list copy(beg_, end_); 1504 | { 1505 | if(!recur.empty()){ 1506 | for(auto itt = copy.begin(); itt != copy.end(); ++itt) 1507 | tmp_state.replaced[itt] = recur; 1508 | } 1509 | } 1510 | pull_out_hash(copy); 1511 | if(beg_ != end_){ 1512 | auto replaced = (list|replacer(it_, std::next(it_), std::move(copy))); 1513 | it_ = replaced.end(); 1514 | } 1515 | else{ 1516 | auto replaced = (list|replacer(it_, std::next(it_), token_t{{"", token_type::empty}, beg_->annotation()})); 1517 | it_ = replaced.end(); 1518 | } 1519 | }; 1520 | auto copy_eval_insert = [&](auto&& cei, auto&& ls, auto&& it_, auto beg_, auto end_, auto index, auto& tmp_state){ 1521 | std::list list(beg_, end_); 1522 | if(list.size() == 0){ 1523 | copy_insert(ls, it_, beg_, end_); 1524 | return; 1525 | } 1526 | pull_out_hash(list); 1527 | auto backup = list; 1528 | pp_state ps{list, tmp_state.replaced}; 1529 | for(auto itr = beg_, list_it = list.begin(); itr != end_; ++list_it, ++itr){ 1530 | const auto finded = tmp_state.replaced.find(itr); 1531 | if(finded != tmp_state.replaced.end()) 1532 | ps.replaced[list_it] = std::move(finded->second); 1533 | } 1534 | { 1535 | auto p = ps.replaced.find(it_); 1536 | if(p != ps.replaced.end()){ 1537 | if(!recur.empty()){ 1538 | for(auto itt = list.begin(); itt != list.end(); ++itt){ 1539 | if(std::any_of(ps.replaced[itt].begin(), ps.replaced[itt].end(), [&](auto&& t){return t == itt->get();})) 1540 | (ps.replaced[itt] = recur).emplace_back(itt->get()); 1541 | else 1542 | ps.replaced[itt] = recur; 1543 | } 1544 | } 1545 | } 1546 | } 1547 | auto list_it = list.begin(); 1548 | auto func_yield = [&](auto it_, auto id, auto&& ls, auto&& ret){ 1549 | if(it_ != ls.begin()){ 1550 | ret.emplace(ret.begin(), ls.begin(), it_); 1551 | } 1552 | ++it_; 1553 | ++id; 1554 | auto b = it_; 1555 | while(it_ != ls.end()){ 1556 | const auto ai = f->second.arg_index[id]; 1557 | if(ai != 0){ 1558 | if(b != it_) 1559 | ret.emplace_back(b, it_); 1560 | b = std::next(it_); 1561 | } 1562 | if(ai > 0) 1563 | ret.emplace_back(args[ai-1]); 1564 | else if(ai < 0) 1565 | ret.emplace_back(args[-ai-1].begin(), args.back().end()); 1566 | ++it_; 1567 | ++id; 1568 | } 1569 | if(b != it_) 1570 | ret.emplace_back(b, it_); 1571 | }; 1572 | while(self.template operator()(self, passed_identity, state, ps, list_it, list.end(), std::function::const_iterator, std::vector::const_iterator>>)>{[&](const phase4_t& state_, pp_state& tmp_state_, std::list::const_iterator itr, std::vector::const_iterator>> list_){ 1573 | if(list_it != list.begin()){ 1574 | list_.emplace(list_.begin(), list.begin(), list_it); 1575 | } 1576 | func_yield(it_, index, ls, list_); 1577 | list_.emplace_back(arg_it, end); 1578 | yield(state_, tmp_state_, itr, std::move(list_));}})); 1579 | { 1580 | if(!tokens_equal(list, backup)){ 1581 | cei(cei, ls, it_, list.begin(), list.end(), index, ps); 1582 | std::swap(tmp_state.replaced, ps.replaced); 1583 | return; 1584 | } 1585 | std::swap(tmp_state.replaced, ps.replaced); 1586 | tmp_state.replaced.erase(it_); 1587 | auto replaced = (ls|replacer(it_, std::next(it_), std::move(list))); 1588 | it_ = replaced.end(); 1589 | return; 1590 | } 1591 | }; 1592 | std::list copy(f->second.dst.begin(), f->second.dst.end()); 1593 | for(auto&& x : copy) 1594 | x.annotation() = it->annotation(); 1595 | { 1596 | auto p = tmp_state.replaced.find(it); 1597 | if(p != tmp_state.replaced.end()){ 1598 | if(!recur.empty()){ 1599 | for(auto itt = copy.begin(); itt != copy.end(); ++itt){ 1600 | for(auto&& x : recur) 1601 | if(x == itt->get()) 1602 | tmp_state.replaced[itt].emplace_back(x); 1603 | tmp_state.replaced[itt] = recur;//p->second; 1604 | } 1605 | } 1606 | } 1607 | } 1608 | copy.push_front({{"", token_type::empty}, it->annotation()}); 1609 | pp_state copy_state{copy, std::move(tmp_state.replaced)}; 1610 | std::size_t index = 0; 1611 | auto func_yield = [&](auto it_, std::size_t id){ 1612 | std::vector::const_iterator>> ret; 1613 | if(it_ != std::next(copy.begin())) 1614 | ret.emplace_back(std::next(copy.begin()), it_); 1615 | auto b = it_; 1616 | while(it_ != copy.end() && id < f->second.arg_index.size()){ 1617 | const auto ai = f->second.arg_index[id]; 1618 | if(ai != 0){ 1619 | if(b != it_) 1620 | ret.emplace_back(b, it_); 1621 | b = std::next(it_); 1622 | } 1623 | if(ai > 0) 1624 | ret.emplace_back(args[ai-1]); 1625 | else if(ai < 0) 1626 | ret.emplace_back(args[-ai-1].begin(), args.back().end()); 1627 | ++it_; 1628 | ++id; 1629 | } 1630 | if(b != it_) 1631 | ret.emplace_back(b, it_), 1632 | b = std::next(it_); 1633 | ret.emplace_back(arg_it, end); 1634 | yield(state, copy_state, it_, ret); 1635 | }; 1636 | func_yield(std::next(copy.begin()), index); 1637 | for(auto it_ = std::next(copy.begin()); it_ != copy.end();){ 1638 | if(it_->type() == token_type::punctuator_hash){ 1639 | static auto search = [](const auto& it, auto sentinel){ 1640 | try{ 1641 | return search_(it, std::move(sentinel), [](auto&& it){++it;}); 1642 | }catch(std::runtime_error&){ 1643 | throw std::runtime_error(std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: operator # must receive argument"); 1644 | } 1645 | }; 1646 | auto next = search(it_, copy.end()); 1647 | const auto next_i = std::distance(it_, next); 1648 | const auto next_ai = f->second.arg_index[index+next_i]; 1649 | if(next_ai == 0) 1650 | throw std::runtime_error(std::string{it_->filename()} + ':' + std::to_string(it_->line()) + ':' + std::to_string(it_->column()) + ": error: # receive invalid(not argument) parameter"); 1651 | auto replaced = (copy|replacer(it_, std::next(next), token_t{{'"' + 1652 | (next_ai < 0 ? stringizer(args[-next_ai-1].begin(), args.back().end()) 1653 | : stringizer(args[ next_ai-1]) 1654 | ) + '"', token_type::string_literal}, it_->annotation()})); 1655 | it_ = replaced.end(); 1656 | index += next_i+1; 1657 | func_yield(it_, index); 1658 | continue; 1659 | } 1660 | if(it_->type() == token_type::punctuator_hashhash){ 1661 | static auto search = [](const auto& it, auto sentinel){ 1662 | try{ 1663 | return search_(it, std::move(sentinel), [](auto&& it){++it;}); 1664 | }catch(std::runtime_error&){ 1665 | throw std::runtime_error(std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: operator ## can't receive parameter(search_parameter reach edge)"); 1666 | } 1667 | }; 1668 | auto next = search(it_, copy.end()); 1669 | const auto next_next = std::next(next); 1670 | const auto next_i = index + std::distance(it_, next); 1671 | const auto next_ai = f->second.arg_index[next_i]; 1672 | if(next_ai < 0) 1673 | copy_insert(copy, next, args[-next_ai-1].begin(), args.back().end()); 1674 | else if(next_ai > 0) 1675 | copy_insert(copy, next, args[ next_ai-1].begin(), args[next_ai-1].end()); 1676 | apply_cat(it_, copy_state); 1677 | it_ = next_next; 1678 | index = next_i+1; 1679 | func_yield(it_, index); 1680 | continue; 1681 | } 1682 | const auto ai = f->second.arg_index[index]; 1683 | static auto search = [](auto it, auto sentinel){ 1684 | try{ 1685 | return search_(std::move(it), std::move(sentinel), [](auto&& it){++it;}); 1686 | }catch(std::runtime_error&){ 1687 | return sentinel; 1688 | } 1689 | }; 1690 | const auto next = search(it_, copy.end()); 1691 | if(ai == 0){ 1692 | ++it_; 1693 | ++index; 1694 | continue; 1695 | } 1696 | else if(next != copy.end() && next->type() == token_type::punctuator_hashhash) 1697 | if(ai < 0) 1698 | copy_insert(copy, it_, args[-ai-1].begin(), args.back().end()); 1699 | else 1700 | copy_insert(copy, it_, args[ ai-1].begin(), args[ai-1].end()); 1701 | else 1702 | if(ai < 0) 1703 | copy_eval_insert(copy_eval_insert, copy, it_, args[-ai-1].begin(), args.back().end(), index, copy_state); 1704 | else 1705 | copy_eval_insert(copy_eval_insert, copy, it_, args[ ai-1].begin(), args[ai-1].end(), index, copy_state); 1706 | ++index; 1707 | } 1708 | copy.pop_front(); 1709 | tmp_state.replaced = std::move(copy_state.replaced); 1710 | for(auto it_ = copy.begin(), end_ = copy.end(); it_ != end_; ++it_){ 1711 | if(tmp_state.replaced[it_].empty()) 1712 | tmp_state.replaced[it_] = recur; 1713 | else 1714 | if(std::any_of(tmp_state.replaced[it_].begin(), tmp_state.replaced[it_].end(), [&](auto&& t){return t == it_->get();})){ 1715 | tmp_state.replaced[it_].emplace_back(it_->get()); 1716 | } 1717 | tmp_state.replaced[it_].emplace_back(it->get()); 1718 | } 1719 | for(auto i = it; i != arg_it; ++i) 1720 | tmp_state.replaced.erase(i); 1721 | auto replaced = (tmp_state.list|replacer(it, arg_it, std::move(copy))); 1722 | it = replaced.begin(); 1723 | for(auto i = tmp_state.list.begin(); i != tmp_state.list.end();) 1724 | if(i->type() == token_type::empty){ 1725 | if(auto ri = tmp_state.replaced.find(i); ri != tmp_state.replaced.end()) 1726 | tmp_state.replaced.erase(ri); 1727 | if(it == i) 1728 | it = i = tmp_state.list.erase(i); 1729 | else 1730 | i = tmp_state.list.erase(i); 1731 | } 1732 | else 1733 | ++i; 1734 | return true; 1735 | } 1736 | }static constexpr eval_macro = {}; 1737 | template 1738 | std::optional find_include_path(T&& tmp, const std::filesystem::path current_path)const{ 1739 | std::filesystem::path include_file; 1740 | bool is_angle = false; 1741 | { 1742 | if(tmp.begin()->type() == token_type::header_name){ 1743 | auto&& str = tmp.begin()->get(); 1744 | include_file = str.substr(1, str.size()-2); 1745 | is_angle = str[0] == '<'; 1746 | } 1747 | else{ 1748 | std::string str; 1749 | for(auto&& x : tmp) 1750 | if(str.empty() && x.type() == token_type::white_space) 1751 | continue; 1752 | else 1753 | str += x.get(); 1754 | const auto parser = 1755 | ( _('<') >> +(veiler::pegasus::read - _('>'))[veiler::pegasus::semantic_actions::value] >> _('>') )[veiler::pegasus::semantic_actions::change_container][([&](auto&& v, [[maybe_unused]] auto&&... unused){include_file = std::move(v); is_angle = true; return veiler::pegasus::unit{};})] 1756 | | ( _('"') >> +(veiler::pegasus::read - _('"'))[veiler::pegasus::semantic_actions::value] >> _('"') )[veiler::pegasus::semantic_actions::change_container][([&](auto&& v, [[maybe_unused]] auto&&... unused){include_file = std::move(v); is_angle = false;return veiler::pegasus::unit{};})]; 1757 | auto result = parser(str.begin(), str.end()); 1758 | if(!result) 1759 | return std::nullopt; 1760 | } 1761 | } 1762 | auto f = [&](const std::filesystem::path& path){ 1763 | if(!std::filesystem::exists(path) || std::filesystem::is_directory(path)) 1764 | return false; 1765 | return true; 1766 | }; 1767 | if(!is_angle && std::filesystem::exists(current_path/include_file)) 1768 | return std::filesystem::canonical(current_path/include_file); 1769 | for(auto&& x : include_dir) 1770 | if(f(x/include_file)) 1771 | return std::filesystem::canonical(x/include_file); 1772 | for(auto&& x : system_include_dir) 1773 | if(f(x/include_file)) 1774 | return std::filesystem::canonical(x/include_file); 1775 | return std::nullopt; 1776 | } 1777 | struct arithmetic_expression : veiler::pegasus::parsers{ 1778 | static auto entrypoint(){ 1779 | return instance().conditional_expression.with_skipper(*instance()._); 1780 | } 1781 | private: 1782 | static constexpr auto omit = veiler::pegasus::semantic_actions::omit; 1783 | template 1784 | static constexpr auto lit(T&& t){return veiler::pegasus::lit(std::forward(t));} 1785 | #define SIMPLE_RULE(name, operator_name, operator, next_rule) \ 1786 | RULE(name, std::intmax_t, veiler::pegasus::transient(\ 1787 | ( rules.next_rule\ 1788 | >> *( lit(token_type::operator_name)[omit]\ 1789 | >> rules.next_rule\ 1790 | )\ 1791 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){\ 1792 | return std::accumulate(v.begin()+1, v.end(), *v.begin(), [](auto&& lhs, auto&& rhs){return lhs operator rhs;});\ 1793 | })]\ 1794 | )) 1795 | #define TWO_OPERATOR_RULE(name, operator_name1, operator1, operator_name2, operator2, next_rule) \ 1796 | RULE(name, std::intmax_t, veiler::pegasus::transient(\ 1797 | ( rules.next_rule\ 1798 | >> *( ( lit(token_type::operator_name1)[omit][([]([[maybe_unused]]auto&&... unused){return true;})]\ 1799 | | lit(token_type::operator_name2)[omit][([]([[maybe_unused]]auto&&... unused){return false;})]\ 1800 | )\ 1801 | >> rules.next_rule\ 1802 | )\ 1803 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){\ 1804 | auto&& [first, exps] = v;\ 1805 | for(auto&& [op, val] : exps)\ 1806 | if(op)\ 1807 | first = first operator1 val;\ 1808 | else\ 1809 | first = first operator2 val;\ 1810 | return first;\ 1811 | })]\ 1812 | )) 1813 | RULE(conditional_expression, std::intmax_t, veiler::pegasus::transient( 1814 | ( rules.logical_or 1815 | >> *( lit(token_type::punctuator_question)[omit] 1816 | >> rules.logical_or 1817 | >> lit(token_type::punctuator_colon)[omit] 1818 | >> rules.logical_or 1819 | ) 1820 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){ 1821 | auto&& [first, tf] = v; 1822 | for(auto&& x : tf) 1823 | if(first == 0) 1824 | first = x[1]; 1825 | else 1826 | return x[0]; 1827 | return first; 1828 | })] 1829 | )) 1830 | SIMPLE_RULE(logical_or , punctuator_logical_or , ||, logical_and) 1831 | SIMPLE_RULE(logical_and, punctuator_logical_and, &&, bitwise_or ) 1832 | SIMPLE_RULE(bitwise_or , punctuator_bitwise_or , |, bitwise_xor) 1833 | SIMPLE_RULE(bitwise_xor, punctuator_bitwise_xor, ^, bitwise_and) 1834 | SIMPLE_RULE(bitwise_and, punctuator_ampersand , &, equal) 1835 | TWO_OPERATOR_RULE(equal, punctuator_equalequal, ==, 1836 | punctuator_not_equal, !=, compare) 1837 | AUTO_RULE(compare, veiler::pegasus::transient( 1838 | ( rules.shift 1839 | >> *( ( lit(token_type::punctuator_less) 1840 | | lit(token_type::punctuator_less_equal) 1841 | | lit(token_type::punctuator_greater) 1842 | | lit(token_type::punctuator_greater_equal) 1843 | )[([](auto&& v, [[maybe_unused]]auto&&... unused){return v->type();})] 1844 | >> rules.shift 1845 | ) 1846 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){ 1847 | auto&& [first, cmps] = v; 1848 | for(auto&& [op, val] : cmps) 1849 | switch(op){ 1850 | case token_type::punctuator_less: first = first < val; break; 1851 | case token_type::punctuator_less_equal: first = first <= val; break; 1852 | case token_type::punctuator_greater: first = first > val; break; 1853 | case token_type::punctuator_greater_equal: first = first >= val; break; 1854 | default: break; 1855 | } 1856 | return first; 1857 | })] 1858 | )) 1859 | TWO_OPERATOR_RULE(shift, punctuator_left_shift, <<, 1860 | punctuator_right_shift, >>, addsub) 1861 | TWO_OPERATOR_RULE(addsub, punctuator_plus, +, 1862 | punctuator_minus, -, muldiv) 1863 | AUTO_RULE(muldiv, veiler::pegasus::transient( 1864 | ( rules.unary 1865 | >> *( ( lit(token_type::punctuator_asterisk) 1866 | | lit(token_type::punctuator_division) 1867 | | lit(token_type::punctuator_modulo) 1868 | )[([](auto&& v, [[maybe_unused]]auto&&... unused){return v->type();})] 1869 | >> rules.unary 1870 | ) 1871 | )[([](auto&& v, auto&& loc, [[maybe_unused]] auto&&... unused)->veiler::expected>>{ 1872 | auto&& [first, muls] = v; 1873 | for(auto&& [op, val] : muls) 1874 | switch(op){ 1875 | case token_type::punctuator_asterisk: first = first * val; break; 1876 | case token_type::punctuator_division: if(val == 0)return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"div zero"}); first = first / val; break; 1877 | case token_type::punctuator_modulo: if(val == 0)return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"mod zero"}); first = first % val; break; 1878 | default: break; 1879 | } 1880 | return first; 1881 | })] 1882 | )) 1883 | AUTO_RULE(unary, veiler::pegasus::transient( 1884 | ( *( ( lit(token_type::punctuator_plus) 1885 | | lit(token_type::punctuator_minus) 1886 | | lit(token_type::punctuator_logical_not) 1887 | | lit(token_type::punctuator_bitwise_not) 1888 | )[([](auto&& v, [[maybe_unused]]auto&&... unused){return v->type();})] 1889 | ) 1890 | >> rules.primary 1891 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){ 1892 | auto&& [ops, val] = v; 1893 | for(auto&& op : ops | boost::adaptors::reversed) 1894 | switch(op){ 1895 | case token_type::punctuator_plus: break; 1896 | case token_type::punctuator_minus: val = -val; break; 1897 | case token_type::punctuator_logical_not: val = !val; break; 1898 | case token_type::punctuator_bitwise_not: val = ~val; break; 1899 | default: break; 1900 | } 1901 | return val; 1902 | })] 1903 | )) 1904 | AUTO_RULE(primary, veiler::pegasus::transient( 1905 | ( lit(token_type::pp_number)[([](auto&& v, [[maybe_unused]] auto&&... unused)->veiler::expected>>{ 1906 | std::size_t index; 1907 | auto vstr = v->get(); 1908 | vstr.erase(std::remove_if(vstr.begin(), vstr.end(), [](char c){return c == '\'';}), vstr.end()); 1909 | auto value = std::stoull(vstr, &index, 0); 1910 | { 1911 | bool is_unsigned = false; 1912 | bool is_long = false; 1913 | bool is_long_long = false; 1914 | for(;index < vstr.size(); ++index){ 1915 | switch(vstr[index]){ 1916 | case 'u':case'U': 1917 | if(std::exchange(is_unsigned, true)) 1918 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"duplicate u suffix"}); 1919 | break; 1920 | case 'l':case 'L': 1921 | if(index+1 < vstr.size() && vstr[index] == vstr[index+1]){ 1922 | ++index; 1923 | if(is_long) 1924 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"exists l suffix and ll suffix together"}); 1925 | if(std::exchange(is_long_long, true)) 1926 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"duplicate ll suffix"}); 1927 | } 1928 | else{ 1929 | if(is_long_long) 1930 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"exists l suffix and ll suffix together"}); 1931 | if(std::exchange(is_long, true)) 1932 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"duplicate l suffix"}); 1933 | } 1934 | break; 1935 | default: 1936 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{"invalid suffix"}); 1937 | } 1938 | } 1939 | } 1940 | return static_cast(value); 1941 | })] 1942 | | lit(token_type::character_literal)[([](auto&& v, [[maybe_unused]] auto&&... unused)->veiler::expected>>{ 1943 | return static_cast(0); 1944 | })] 1945 | | lit(token_type::punctuator_left_parenthesis)[omit] 1946 | >> rules.conditional_expression 1947 | >> lit(token_type::punctuator_right_parenthesis)[omit] 1948 | | lit(token_type::identifier_true)[omit][([]([[maybe_unused]]auto&&... unused){return static_cast(true);})] 1949 | | lit(token_type::identifier_false)[omit][([]([[maybe_unused]]auto&&... unused){return static_cast(false);})] 1950 | | ( lit(token_type::identifier_defined)[omit] 1951 | >> ( ( lit(token_type::punctuator_left_parenthesis)[omit] 1952 | >> rules.identifier 1953 | >> lit(token_type::punctuator_right_parenthesis)[omit] 1954 | ) 1955 | | rules.identifier 1956 | ) 1957 | )[([](auto&& v, auto&&, auto&& s, [[maybe_unused]] auto&&... unused)->std::intmax_t{ 1958 | return v->type() == token_type::identifier_has_include || s.objects.find(v->get()) != s.objects.end() || s.functions.find(v->get()) != s.functions.end() ? 1 : 0; 1959 | })] 1960 | | ( lit(token_type::identifier_has_include)[omit] 1961 | >> lit(token_type::punctuator_left_parenthesis)[omit] 1962 | >> ( lit(token_type::header_name) 1963 | | lit(token_type::string_literal) 1964 | | veiler::pegasus::lexeme[lit(token_type::punctuator_less) >> *(veiler::pegasus::read - lit(token_type::punctuator_greater)) >> lit(token_type::punctuator_greater)] 1965 | )[veiler::pegasus::semantic_actions::location] 1966 | >> lit(token_type::punctuator_right_parenthesis)[omit] 1967 | )[([](auto&& v, auto&&, auto&& s, auto&& c, [[maybe_unused]] auto&&... unused)->std::intmax_t{ 1968 | return s.find_include_path(v, c) ? 1 : 0; 1969 | })] 1970 | | rules.identifier[omit][([]([[maybe_unused]]auto&&... unused){return static_cast(0);})] 1971 | ) 1972 | )) 1973 | INLINE_RULE(identifier, veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return is_identifier((v++)->type());})) 1974 | INLINE_RULE(_, veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return (v++)->type() == token_type::white_space;})) 1975 | #undef TWO_OPERATOR_RULE 1976 | #undef SIMPLE_RULE 1977 | }; 1978 | struct preprocessing_file : veiler::pegasus::parsers{ 1979 | static auto entrypoint(){ 1980 | return instance().group.with_skipper(*instance()._); 1981 | } 1982 | struct if_section_t; 1983 | struct node{ 1984 | std::vector::const_iterator>>> data; 1985 | }; 1986 | struct if_section_t{ 1987 | std::vector::const_iterator>, node>> data; 1988 | }; 1989 | private: 1990 | static constexpr auto location = veiler::pegasus::semantic_actions::location; 1991 | static constexpr auto omit = veiler::pegasus::semantic_actions::omit; 1992 | static constexpr auto read = veiler::pegasus::read; 1993 | static constexpr auto value = veiler::pegasus::semantic_actions::value; 1994 | template 1995 | static constexpr auto lit(T&& t){return veiler::pegasus::lit(std::forward(t));} 1996 | template 1997 | static constexpr auto range(T&& t, U&& u){return veiler::pegasus::range(std::forward(t), std::forward(u));} 1998 | RULE(group, node, veiler::pegasus::transient((*rules.group_part)[([](auto&& v, [[maybe_unused]] auto&&... unused){return node{std::move(v)};})])) 1999 | AUTO_RULE(group_part, veiler::pegasus::transient( 2000 | ( rules.if_section 2001 | | rules.other_part 2002 | ) 2003 | )) 2004 | RULE(if_section, if_section_t, veiler::pegasus::transient( 2005 | ( rules.if_group 2006 | >> *( omit[ lit(token_type::eol) 2007 | >> lit(token_type::punctuator_hash) 2008 | ] 2009 | >> ( lit(token_type::identifier_elif) 2010 | >> rules.get_line 2011 | )[location] 2012 | >> rules.group 2013 | ) 2014 | >> -( omit[ lit(token_type::eol) 2015 | >> lit(token_type::punctuator_hash) 2016 | ] 2017 | >> ( lit(token_type::identifier_else) 2018 | >> &lit(token_type::eol)[omit] 2019 | )[location] 2020 | >> rules.group 2021 | ) 2022 | >> omit[ lit(token_type::eol) 2023 | >> lit(token_type::punctuator_hash) 2024 | >> lit(token_type::identifier_endif) 2025 | >> &lit(token_type::eol) 2026 | ] 2027 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){ 2028 | auto&& [xs, else_part] = v; 2029 | if(else_part) 2030 | xs.emplace_back(std::move(*else_part)); 2031 | return if_section_t{std::move(xs)}; 2032 | })] 2033 | )) 2034 | AUTO_RULE(if_group, veiler::pegasus::transient( 2035 | omit[ lit(token_type::eol) 2036 | >> lit(token_type::punctuator_hash) 2037 | ] 2038 | >> ( ( lit(token_type::identifier_if) 2039 | >> rules.get_line 2040 | >> &lit(token_type::eol) 2041 | ) 2042 | | 2043 | ( ( lit(token_type::identifier_ifdef) 2044 | | lit(token_type::identifier_ifndef) 2045 | ) 2046 | >> rules.identifier 2047 | >> &lit(token_type::eol) 2048 | ) 2049 | )[location] 2050 | >> rules.group 2051 | )) 2052 | AUTO_RULE(other_part, veiler::pegasus::transient( 2053 | ( lit(token_type::eol) 2054 | >> ( rules.get_line 2055 | - ( lit(token_type::punctuator_hash) 2056 | >> ( lit(token_type::identifier_if) 2057 | | lit(token_type::identifier_ifdef) 2058 | | lit(token_type::identifier_ifndef) 2059 | | lit(token_type::identifier_elif) 2060 | | lit(token_type::identifier_else) 2061 | | lit(token_type::identifier_endif) 2062 | ) 2063 | ) 2064 | ) % lit(token_type::eol) 2065 | )[location] 2066 | )) 2067 | INLINE_RULE(get_line, *(veiler::pegasus::read - veiler::pegasus::lit(token_type::eol)) >> &veiler::pegasus::lit(token_type::eol)) 2068 | INLINE_RULE(identifier, veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return is_identifier((v++)->type());})) 2069 | INLINE_RULE(_, veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return (v++)->type() == token_type::white_space;})) 2070 | }; 2071 | struct override_annotate{ 2072 | std::string filename; 2073 | std::size_t base_line; 2074 | std::size_t org_line; 2075 | }; 2076 | public: 2077 | template 2078 | std::list eval(std::list& ls, T&& r, override_annotate& override_annotation, const std::filesystem::path& current_path, bool step_flag = false, std::ostream& os = std::cout){ 2079 | static auto pp_directive_line = 2080 | _(token_type::eol) >> *_(token_type::white_space) 2081 | >> _(token_type::punctuator_hash) >> *_(token_type::white_space) 2082 | ; 2083 | static auto next_pp_line = [](auto it, auto&& end){ 2084 | for(;it != end; ++it) 2085 | if((&pp_directive_line)(it, end)) 2086 | break; 2087 | return it; 2088 | }; 2089 | struct include_data : veiler::pegasus::iterator_range::const_iterator>{}; 2090 | static auto rule_include = 2091 | _(token_type::identifier_include) >> *_(token_type::white_space) 2092 | >> (+(veiler::pegasus::read - _(token_type::eol)))[veiler::pegasus::semantic_actions::omit][([](auto&&, auto&& loc, [[maybe_unused]] auto&&... unused){return include_data{loc};})]; 2093 | using define_data = std::variant::const_iterator, func_t>, std::tuple::const_iterator, output_range::const_iterator>>>; 2094 | static auto identifier = veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return is_identifier((v++)->type());}); 2095 | static auto rule_define = ( 2096 | _(token_type::identifier_define) >> *_(token_type::white_space) 2097 | >> identifier 2098 | >> -( _(token_type::punctuator_left_parenthesis) >> *_(token_type::white_space) 2099 | >> ( ( identifier >> *_(token_type::white_space) ) 2100 | % ( _(token_type::punctuator_comma) >> *_(token_type::white_space) ) 2101 | >> ( -( _(token_type::punctuator_comma) >> *_(token_type::white_space) 2102 | >> _(token_type::punctuator_ellipsis) >> *_(token_type::white_space) 2103 | ) 2104 | )[([](auto&& v, [[maybe_unused]] auto&&... unused){return static_cast(v);})] 2105 | | ( -( _(token_type::punctuator_ellipsis) >> *_(token_type::white_space) ) 2106 | )[([](auto&& v, auto&& loc, [[maybe_unused]] auto&&... unused){return std::make_tuple(std::vector>{}, static_cast(v));})] 2107 | ) 2108 | //(), (ident, ident) or (...) or (ident, ...) 2109 | >> _(token_type::punctuator_right_parenthesis) 2110 | ) 2111 | >> *_(token_type::white_space) 2112 | >> (*(veiler::pegasus::read - _(token_type::eol)))[veiler::pegasus::semantic_actions::location] 2113 | )[([](auto&& t, auto&& loc, [[maybe_unused]] auto&&... args)->veiler::expected>>{ 2114 | auto&& [name, function_info, destination] = t; 2115 | if(name->type() == token_type::identifier_defined) 2116 | return veiler::make_unexpected(veiler::pegasus::error_type::semantic_check_failed{}); 2117 | output_range::const_iterator> dst{destination.begin(), destination.end()}; 2118 | if(function_info){ 2119 | auto&& [args, is_variadic] = *function_info; 2120 | std::vector arg_index; 2121 | arg_index.reserve(std::distance(dst.begin(), dst.end())); 2122 | { 2123 | std::size_t t_i = 0; 2124 | for(auto&& t : dst){ 2125 | if(is_variadic && t.get() == "__VA_ARGS__"){ 2126 | arg_index.push_back(-static_cast(args.size())-1); 2127 | ++t_i; 2128 | continue; 2129 | } 2130 | for(auto&& x : args | boost::adaptors::indexed()) 2131 | if(t.get() == x.value()->get()){ 2132 | arg_index.push_back(x.index()+1); 2133 | break; 2134 | } 2135 | if(t_i++ == arg_index.size()) 2136 | arg_index.push_back(0); 2137 | } 2138 | } 2139 | return define_data{std::make_tuple(std::move(name), func_t{is_variadic ? -static_cast(args.size())-1 : static_cast(args.size()), std::move(arg_index), dst})}; 2140 | } 2141 | else 2142 | return define_data{std::make_tuple(std::move(name), dst)}; 2143 | })]; 2144 | using undef_data = std::list::const_iterator; 2145 | static auto rule_undef = 2146 | _(token_type::identifier_undef) >> *_(token_type::white_space) 2147 | >> _(token_type::identifier)[([](auto&&, auto&& loc, [[maybe_unused]] auto&&... unused)->undef_data{return loc.begin();})]; 2148 | struct pragma_step_data : veiler::pegasus::iterator_range::const_iterator>{}; 2149 | static const auto rule_pragma_step = 2150 | _(token_type::identifier_pragma) >> *_(token_type::white_space) 2151 | >> _(std::string_view{"step"}) >> *_(token_type::white_space) 2152 | >> (*(veiler::pegasus::read - _(token_type::eol)))[([](auto&&, auto&& loc, [[maybe_unused]] auto&&... unused){return pragma_step_data{loc};})]; 2153 | static auto rule_pragma = 2154 | _(token_type::identifier_pragma) >> *_(token_type::white_space) 2155 | >> *(veiler::pegasus::read - _(token_type::eol)); 2156 | using error_data = std::tuple::const_iterator>>; 2157 | static auto rule_error = 2158 | veiler::pegasus::lit(token_type::identifier_error)[([](auto&& v, [[maybe_unused]] auto&&... unused){return std::make_tuple(v->filename(), v->line(), v->column());})] >> *_(token_type::white_space) 2159 | >> (*(veiler::pegasus::read - _(token_type::eol)))[veiler::pegasus::semantic_actions::location]; 2160 | struct line_data : veiler::pegasus::iterator_range::const_iterator>{}; 2161 | static auto rule_line = 2162 | _(token_type::identifier_line) >> *_(token_type::white_space) 2163 | >> (+(veiler::pegasus::read - _(token_type::eol)))[veiler::pegasus::semantic_actions::omit][([](auto&&, auto&& loc, [[maybe_unused]] auto&&... unused){return line_data{loc};})]; 2164 | static auto pp_directive = 2165 | pp_directive_line[veiler::pegasus::semantic_actions::omit] 2166 | >> ( rule_include 2167 | | rule_define 2168 | | rule_undef 2169 | | rule_pragma_step 2170 | | rule_pragma[veiler::pegasus::semantic_actions::omit] 2171 | | rule_error 2172 | | rule_line 2173 | | veiler::pegasus::eps[veiler::pegasus::semantic_actions::omit] 2174 | ); 2175 | pp_state preprocessing_state{ls, {}}; 2176 | std::list result; 2177 | auto passed = [&](auto&& t){result.push_back(t);return true;}; 2178 | for(auto it = r.begin(); it != r.end();) 2179 | if((&pp_directive_line)(it, r.end())){ 2180 | auto copied = it; 2181 | if(auto ret = pp_directive(it, r.end())){ 2182 | if(*ret){ 2183 | struct{ 2184 | void operator()(const include_data& i)const{ 2185 | std::list tmp; 2186 | { 2187 | auto it = i.begin(); 2188 | while(it != i.end()) 2189 | if(!eval_macro(eval_macro, [&tmp](auto&& t){tmp.push_back(t);return true;}, *s_, *pps_, it, i.end(), [](const phase4_t&, pp_state&, std::list::const_iterator, const std::vector::const_iterator>>&){})) 2190 | {return;} 2191 | } 2192 | if(tmp.empty()) 2193 | return; 2194 | auto path = s_->find_include_path(tmp, current_path); 2195 | if(path){ 2196 | auto canonicaled = path->string(); 2197 | if(s_->files.find(canonicaled) == s_->files.end()){ 2198 | std::ifstream ifs{*path}; 2199 | std::istreambuf_iterator it{ifs}; 2200 | static constexpr std::istreambuf_iterator end{}; 2201 | std::string tmp(it, end); 2202 | static constexpr phase1_t phase1; 2203 | static constexpr phase2_t phase2; 2204 | static constexpr phase3_t phase3; 2205 | auto range = tmp | annotation{canonicaled} | phase1 | phase2 | phase3; 2206 | std::list tokens(range.begin(), range.end()); 2207 | auto copied = canonicaled; 2208 | s_->files[std::move(canonicaled)] = std::move(tokens); 2209 | canonicaled = std::move(copied); 2210 | } 2211 | res_->splice(res_->end(), (*s_)(s_->files[canonicaled], path->parent_path())); 2212 | } 2213 | else{ 2214 | auto message = std::string{tmp.begin()->filename()} + ':' + std::to_string(tmp.begin()->line()) + ':' + std::to_string(tmp.begin()->column()) + ": fatal error: "; 2215 | for(auto&& x : tmp) 2216 | message += x.get(); 2217 | message += ": No such file or directory"; 2218 | throw std::runtime_error(std::move(message)); 2219 | } 2220 | return; 2221 | } 2222 | void operator()(define_data&& d)const{ 2223 | struct{ 2224 | [[noreturn]] static void throw_redefine(const std::list::const_iterator& it){ 2225 | std::string message(it->filename()); 2226 | message += ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: invalid redifinition of '"; 2227 | message += it->get() + '\''; 2228 | throw std::runtime_error(std::move(message)); 2229 | } 2230 | void operator()(std::tuple::const_iterator, func_t>&& t)const{ 2231 | auto&& [name_node, func_data] = std::move(t); 2232 | { 2233 | auto prev_defined = s_->functions.find(name_node->get()); 2234 | if(prev_defined != s_->functions.end()){ 2235 | if(prev_defined->second.arg_num != func_data.arg_num) 2236 | throw_redefine(name_node); 2237 | auto prev_it = prev_defined->second.dst.begin(); 2238 | auto current_it = func_data.dst.begin(); 2239 | std::size_t idx = 0; 2240 | while(true){ 2241 | if(prev_it == prev_defined->second.dst.end()){ 2242 | if(current_it != func_data.dst.end()) 2243 | while(current_it != func_data.dst.end()) 2244 | if(current_it++->type() != token_type::white_space) 2245 | throw_redefine(name_node); 2246 | break; 2247 | } 2248 | else if(current_it == func_data.dst.end()){ 2249 | while(prev_it != prev_defined->second.dst.end()) 2250 | if(prev_it++->type() != token_type::white_space) 2251 | throw_redefine(name_node); 2252 | break; 2253 | } 2254 | if(prev_it->type() != current_it->type() 2255 | || (prev_it->type() != token_type::white_space && prev_it->get() != current_it->get()) 2256 | || prev_defined->second.arg_index[idx] != func_data.arg_index[idx]) 2257 | throw_redefine(name_node); 2258 | ++prev_it; 2259 | ++current_it; 2260 | ++idx; 2261 | } 2262 | } 2263 | else if(s_->objects.find(name_node->get()) != s_->objects.end()) 2264 | throw_redefine(name_node); 2265 | } 2266 | s_->functions.emplace(name_node->get(), std::move(func_data)); 2267 | } 2268 | void operator()(std::tuple::const_iterator, output_range::const_iterator>>&& t)const{ 2269 | auto&& [name_node, replacement_list] = std::move(t); 2270 | { 2271 | auto prev_defined = s_->objects.find(name_node->get()); 2272 | if(prev_defined != s_->objects.end()){ 2273 | auto prev_it = prev_defined->second.begin(); 2274 | auto current_it = replacement_list.begin(); 2275 | while(true){ 2276 | if(prev_it == prev_defined->second.end()){ 2277 | if(current_it != replacement_list.end()) 2278 | while(current_it != replacement_list.end()) 2279 | if(current_it++->type() != token_type::white_space) 2280 | throw_redefine(name_node); 2281 | break; 2282 | } 2283 | else if(current_it == replacement_list.end()){ 2284 | while(prev_it != prev_defined->second.end()) 2285 | if(prev_it++->type() != token_type::white_space) 2286 | throw_redefine(name_node); 2287 | break; 2288 | } 2289 | if(prev_it->type() != current_it->type() 2290 | || (prev_it->type() != token_type::white_space && prev_it->get() != current_it->get())) 2291 | throw_redefine(name_node); 2292 | ++prev_it; 2293 | ++current_it; 2294 | } 2295 | } 2296 | else if(s_->functions.find(name_node->get()) != s_->functions.end()) 2297 | throw_redefine(name_node); 2298 | } 2299 | s_->objects.emplace(name_node->get(), std::move(replacement_list)); 2300 | } 2301 | phase4_t* s_; 2302 | }v{s_}; 2303 | std::visit(v, std::move(d)); 2304 | } 2305 | void operator()(const undef_data& u)const{ 2306 | auto& s = *s_; 2307 | auto&& x = u->get(); 2308 | auto o = s.objects.find(x); 2309 | if(o != s.objects.end()){ 2310 | s.objects.erase(o); 2311 | return; 2312 | } 2313 | auto f = s.functions.find(x); 2314 | if(f != s.functions.end()) 2315 | s.functions.erase(f); 2316 | } 2317 | void operator()(const error_data& e)const{ 2318 | std::stringstream ss; 2319 | for(auto&& x : std::get<3>(e)) 2320 | ss << x.get(); 2321 | throw std::runtime_error(std::string{std::get<0>(e)} + ':' + std::to_string(std::get<1>(e)) + ':' + std::to_string(std::get<2>(e)) + ": error: " + ss.str()); 2322 | } 2323 | void operator()(const line_data& l)const{ 2324 | std::list tmp; 2325 | { 2326 | auto it = l.begin(); 2327 | while(it != l.end()) 2328 | if(!eval_macro(eval_macro, [&tmp](auto&& t){tmp.push_back(t);return true;}, *s_, *pps_, it, l.end(), [](const phase4_t&, pp_state&, std::list::const_iterator, const std::vector::const_iterator>>&){})) 2329 | {return;} 2330 | } 2331 | if(tmp.empty()) 2332 | return; 2333 | constexpr auto parser = ( 2334 | veiler::pegasus::lit(token_type::pp_number)[([](auto&& v, [[maybe_unused]] auto&&... unused)->veiler::expected::const_iterator>>{ 2335 | std::size_t idx; 2336 | const auto ret = std::stoull(v->get(), &idx, 10); 2337 | if(idx != v->get().size()) 2338 | return veiler::make_unexpected::const_iterator>>(veiler::pegasus::error_type::semantic_check_failed{"line number is not decimal"}); 2339 | return ret; 2340 | })] 2341 | >> -veiler::pegasus::lit(token_type::string_literal)[veiler::pegasus::semantic_actions::value] 2342 | ).with_skipper(*_(token_type::white_space)); 2343 | auto cit = tmp.cbegin(); 2344 | auto result = parser(cit, tmp.cend()); 2345 | if(!result || cit != tmp.cend()) 2346 | return; 2347 | auto&& [line_num, filename] = *result; 2348 | if(filename){ 2349 | auto str_lit = string_literal::destringize(*filename); 2350 | if(str_lit) 2351 | oa_->filename = str_lit->str; 2352 | else 2353 | return; 2354 | } 2355 | oa_->base_line = line_num; 2356 | static auto next_line = [](auto it, auto end){ 2357 | while(it != end) 2358 | if(it->type() == token_type::eol) 2359 | return ++it; 2360 | else 2361 | ++it; 2362 | return it; 2363 | }; 2364 | const auto nit = next_line(l.end(), end); 2365 | oa_->org_line = nit->line(); 2366 | for(auto it = nit; it != end; ++it){ 2367 | const_cast(*it).line(oa_->base_line + it->line() - oa_->org_line); 2368 | if(!oa_->filename.empty()) 2369 | const_cast(*it).filename(oa_->filename); 2370 | } 2371 | } 2372 | void operator()(const pragma_step_data& p)const{ 2373 | res_->splice(res_->end(), 2374 | s_->eval(pps_->list, static_cast::const_iterator>&>(p), *oa_, current_path, true) ); 2375 | } 2376 | phase4_t* s_; 2377 | pp_state* pps_; 2378 | override_annotate* oa_; 2379 | decltype(std::declval().end()) end; 2380 | const std::filesystem::path& current_path; 2381 | std::list* res_; 2382 | }visitor{this, &preprocessing_state, &override_annotation, ls.end(), current_path, &result}; 2383 | std::visit(visitor, std::move(**ret)); 2384 | } 2385 | else{ 2386 | veiler::pegasus::semantic_actions::omit[pp_directive_line](copied, r.end()); 2387 | if(copied->type() != token_type::eol && !veiler::pegasus::semantic_actions::omit[&rule_pragma](copied, r.end())){ 2388 | std::string message = std::string{copied->filename()} + ':' + std::to_string(copied->line()) + ':' + std::to_string(copied->column()) + ": error: invalid preprocessing directive: "; 2389 | for(auto it = copied; it->type() != token_type::eol; ++it) 2390 | message += it->get(); 2391 | throw std::runtime_error(std::move(message)); 2392 | } 2393 | } 2394 | } 2395 | else 2396 | ++it; 2397 | } 2398 | else if(step_flag){ 2399 | boost::coroutines2::coroutine::const_iterator>>>::pull_type coroutine{[&](boost::coroutines2::coroutine::const_iterator>>>::push_type& yield){ 2400 | preprocessing_state.replaced.clear(); 2401 | const auto next_pp = next_pp_line(it, r.end()); 2402 | while(it != next_pp) 2403 | if(!eval_macro.template operator()(eval_macro, passed, *this, preprocessing_state, it, next_pp, [&](const phase4_t&, pp_state&, std::list::const_iterator, const std::vector::const_iterator>>& list){ 2404 | yield(list); 2405 | })) 2406 | {std::cout << "eval_macro_failed" << std::endl;return;} 2407 | }}; 2408 | const auto next_pp = next_pp_line(it, r.end()); 2409 | os << " "; 2410 | auto pnp = std::prev(next_pp); 2411 | while(result.front().type() == token_type::eol)result.pop_front(); 2412 | for(auto&& x : result) 2413 | if(x.type() != token_type::eol) 2414 | os << x; 2415 | else 2416 | os << "\n "; 2417 | for(auto&& x : output_range::const_iterator>{it, next_pp}) 2418 | if(x.type() != token_type::eol || (x.line() == pnp->line() && x.column() == pnp->column())) 2419 | os << x; 2420 | else 2421 | os << "\n "; 2422 | if(std::prev(next_pp)->type() != token_type::eol) 2423 | os << '\n'; 2424 | for(auto&& xss : coroutine){ 2425 | os << "-> "; 2426 | while(result.front().type() == token_type::eol)result.pop_front(); 2427 | for(auto&& x : result) 2428 | if(x.type() != token_type::eol) 2429 | os << x; 2430 | else 2431 | os << "\n "; 2432 | auto pxsse = std::prev(xss.back().end()); 2433 | for(auto&& xs : xss) 2434 | for(auto&& x : xs){ 2435 | if(x.type() != token_type::eol || (x.line() == pxsse->line() && x.column() == pxsse->column())) 2436 | os << x; 2437 | else 2438 | os << "\n "; 2439 | } 2440 | if(pxsse->type() != token_type::eol) 2441 | os << '\n'; 2442 | } 2443 | const auto p6 = phase6(result); 2444 | if(!tokens_equal(result, p6)){ 2445 | os << "-> "; 2446 | for(auto&& x : p6) 2447 | if(x.type() != token_type::eol) 2448 | os << x; 2449 | else 2450 | os << "\n "; 2451 | if(std::prev(p6.end())->type() != token_type::eol) 2452 | os << '\n'; 2453 | } 2454 | return {}; 2455 | } 2456 | else{ 2457 | const auto next_pp = next_pp_line(it, r.end()); 2458 | while(it != next_pp) 2459 | if(!eval_macro.template operator()(eval_macro, passed, *this, preprocessing_state, it, next_pp, [](const phase4_t&, pp_state&, std::list::const_iterator, const std::vector::const_iterator>>&){})) 2460 | {std::cerr << "eval_macro_failed" << std::endl; return decltype(result){};} 2461 | } 2462 | return result; 2463 | } 2464 | auto operator()(std::list& ls, const std::filesystem::path& current_path = std::filesystem::current_path()){ 2465 | auto if_group = preprocessing_file::entrypoint()(std::as_const(ls)); 2466 | if(!if_group){ 2467 | std::cerr << "parsing for file structure failed" << std::endl; 2468 | return std::list{}; 2469 | } 2470 | override_annotate override_annotation = {}; 2471 | struct{ 2472 | using list = std::list; 2473 | using iterator = list::const_iterator; 2474 | using iterator_range = veiler::pegasus::iterator_range; 2475 | static iterator next(iterator it){ 2476 | do{ 2477 | ++it; 2478 | }while(it->type() == token_type::white_space); 2479 | return it; 2480 | } 2481 | list operator()(const preprocessing_file::node& n)const{ 2482 | list l; 2483 | for(auto&& x : n.data) 2484 | l.splice(l.end(), std::visit(*this, x)); 2485 | return l; 2486 | } 2487 | list operator()(const iterator_range& other_part)const{ 2488 | using veiler::pegasus::lit; 2489 | return self->eval(*ls_p, other_part, *oa, *cp, false); 2490 | } 2491 | list operator()(const preprocessing_file::if_section_t& if_section)const{ 2492 | for(auto&& [range, node] : if_section.data) 2493 | switch(range.begin()->type()){ 2494 | case token_type::identifier_if: 2495 | case token_type::identifier_elif:{ 2496 | auto ae = arithmetic_expression::entrypoint()(self->eval(*ls_p, iterator_range{next(range.begin()), range.end()}, *oa, *cp), *self, *cp); 2497 | if(!ae){ 2498 | auto it = next(range.begin()); 2499 | std::string message = std::string{it->filename()} + ':' + std::to_string(it->line()) + ':' + std::to_string(it->column()) + ": error: invalid expression: "; 2500 | for(auto&& x : iterator_range{it, range.end()}) 2501 | message += x.get(); 2502 | throw std::runtime_error(std::move(message)); 2503 | } 2504 | else if(*ae != 0) 2505 | return (*this)(node); 2506 | }break; 2507 | case token_type::identifier_ifdef: 2508 | case token_type::identifier_ifndef:{ 2509 | const auto ident = next(range.begin()); 2510 | assert(is_identifier(ident->type())); 2511 | if(ident->type() == token_type::identifier_has_include){ 2512 | if(range.begin()->type() == token_type::identifier_ifdef) 2513 | return (*this)(node); 2514 | else 2515 | return list{}; 2516 | } 2517 | const bool function = self->functions.find(ident->get()) != self->functions.end(); 2518 | const bool object = self->objects.find(ident->get()) != self->objects.end(); 2519 | if((function || object) == (range.begin()->type() == token_type::identifier_ifdef)) 2520 | return (*this)(node); 2521 | }break; 2522 | case token_type::identifier_else: 2523 | return (*this)(node); 2524 | default:; 2525 | } 2526 | return list{}; 2527 | } 2528 | phase4_t* self; 2529 | std::list* ls_p; 2530 | override_annotate* oa; 2531 | const std::filesystem::path* cp; 2532 | }visitor{this, &ls, &override_annotation, ¤t_path}; 2533 | auto ret = visitor(*if_group); 2534 | if(!ret.empty() && ret.begin()->type() == token_type::eol) 2535 | ret.erase(ret.begin()); //first eol 2536 | return ret; 2537 | } 2538 | }; 2539 | 2540 | #undef INLINE_RULE 2541 | #undef AUTO_RULE 2542 | #undef RULE 2543 | 2544 | static std::list phase6(std::list tokens){ 2545 | static constexpr auto search = [](std::list::const_iterator it, std::list::const_iterator end)->std::optional::const_iterator>{ 2546 | while(it != end) 2547 | if(is_white_spaces(it->type())) 2548 | ++it; 2549 | else 2550 | return it; 2551 | return std::nullopt; 2552 | }; 2553 | std::list ret; 2554 | for(auto it = tokens.cbegin(); it != tokens.cend();){ 2555 | if(it->type() != token_type::string_literal){ 2556 | ret.splice(ret.end(), tokens, it++); 2557 | continue; 2558 | } 2559 | auto str = *string_literal::destringize(*it); 2560 | auto next = search(std::next(it), tokens.cend()); 2561 | if(next && (*next)->type() == token_type::string_literal){ 2562 | while(true){ 2563 | str += *string_literal::destringize(**next); 2564 | auto n = search(++*next, tokens.cend()); 2565 | if(n && (*n)->type() == token_type::string_literal) 2566 | next = n; 2567 | else 2568 | break; 2569 | } 2570 | ret.emplace_back(str.stringize(it->annotation())); 2571 | } 2572 | else 2573 | ret.splice(ret.end(), tokens, it++); 2574 | if(next) 2575 | it = *next; 2576 | else 2577 | it = tokens.cend(); 2578 | } 2579 | return ret; 2580 | } 2581 | 2582 | class split_range{ 2583 | std::string_view target; 2584 | std::string delimiters; 2585 | public: 2586 | class iterator{ 2587 | std::string_view delimiters; 2588 | std::string_view::const_iterator prev, it, end; 2589 | public: 2590 | iterator() = default; 2591 | iterator(std::string_view delim, const std::string_view::const_iterator& begin, const std::string_view::const_iterator& end):delimiters{delim}, prev{begin}, it{begin}, end{end}{++*this;} 2592 | using value_type = std::string_view; 2593 | iterator& operator++(){ 2594 | static constexpr auto f = [](auto& prev, auto it, auto end){ 2595 | if(it == end){ 2596 | prev = it; 2597 | return false; 2598 | } 2599 | return true; 2600 | }; 2601 | while(f(prev, it, end)) 2602 | if(delimiters.find(*it) == std::string_view::npos){ 2603 | prev = it; 2604 | break; 2605 | } 2606 | else 2607 | ++it; 2608 | while(it != end) 2609 | if(delimiters.find(*it) != std::string_view::npos) 2610 | break; 2611 | else 2612 | ++it; 2613 | return *this; 2614 | } 2615 | value_type operator*()const{return value_type{&*prev, static_cast(it-prev)};} 2616 | constexpr bool operator!=(const iterator& rhs){ 2617 | auto lt = prev; 2618 | while(lt != end && delimiters.find(*lt) != std::string_view::npos) 2619 | ++lt; 2620 | auto rt = rhs.prev; 2621 | while(rt != end && delimiters.find(*rt) != std::string_view::npos) 2622 | ++rt; 2623 | return lt != rt; 2624 | } 2625 | }; 2626 | split_range(std::string_view target, std::string delimiters):target{target}, delimiters{std::move(delimiters)}{} 2627 | iterator begin()const{return iterator{delimiters, target.begin(), target.end()};} 2628 | iterator end()const{return iterator{{}, target.end(), target.end()};} 2629 | }; 2630 | 2631 | } 2632 | 2633 | #include 2634 | #include 2635 | 2636 | int main(){ 2637 | using messer::annotation; 2638 | using namespace std::literals::string_view_literals; 2639 | static constexpr auto white_space = veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){ 2640 | const bool result = v->type() == messer::token_type::white_space; 2641 | if(result) 2642 | ++v; 2643 | return result; 2644 | }); 2645 | static constexpr messer::phase1_t phase1; 2646 | static constexpr messer::phase2_t phase2; 2647 | static constexpr messer::phase3_t phase3; 2648 | std::list inputed; 2649 | std::list> tokens; 2650 | messer::phase4_t preprocessor_data; 2651 | const char* additional_include_dirs[] = { 2652 | #include "include_dir.ipp" 2653 | }; 2654 | for(auto x : additional_include_dirs) 2655 | preprocessor_data.system_include_dir.emplace_back(x); 2656 | { 2657 | static constexpr const char* predefined_macros = R"code( 2658 | #define __cplusplus 201703L 2659 | #define __STDC_HOSTED__ 1 2660 | #define __STDCPP_DEFAULT_NEW_ALIGNMENT__ 16 2661 | #if __has_include() 2662 | #include 2663 | #else 2664 | #define __STDC_ISO_10646__ 199712L 2665 | #endif 2666 | #define __x86_64__ 1 // TODO: specify for the environment 2667 | #define __LP64__ 1 // TODO: ditto 2668 | )code"; 2669 | inputed.emplace_back(predefined_macros); 2670 | auto range = inputed.back() | annotation{""} | phase1 | phase2 | phase3; 2671 | tokens.emplace_back(range.begin(), range.end()); 2672 | preprocessor_data(tokens.back()); 2673 | } 2674 | linse input; 2675 | input.history.load("./.repl_history"); 2676 | auto logical_line = [&input, &preprocessor_data](const char* prompt)->std::optional{ 2677 | std::string str; 2678 | input.completion_callback = [&](std::string_view data, std::string_view::size_type pos)->linse::completions{ 2679 | using veiler::pegasus::lit; 2680 | using messer::token_type; 2681 | linse::completions comp; 2682 | const auto pref = str + std::string{data.substr(0, pos)}; 2683 | auto anno_range = pref | annotation{""}; 2684 | auto range = anno_range| phase1 | phase2 | phase3; 2685 | { 2686 | static constexpr auto include_parser = 2687 | ( veiler::pegasus::semantic_actions::omit[ 2688 | lit(token_type::eol) 2689 | >> lit(token_type::punctuator_hash) 2690 | >> lit(token_type::identifier_include)] 2691 | >> &( lit(token_type::punctuator_less)[([]([[maybe_unused]] auto&&... unused){return true;})] 2692 | | lit("\""sv)[([]([[maybe_unused]] auto&&... unused){return false;})] 2693 | ) 2694 | ).with_skipper(*white_space); 2695 | static const auto has_include_parser_impl = 2696 | veiler::pegasus::semantic_actions::omit[ 2697 | *( veiler::pegasus::read - lit(token_type::identifier_has_include) ) 2698 | >> lit(token_type::identifier_has_include) 2699 | >> lit(token_type::punctuator_left_parenthesis)] 2700 | >> &( lit(token_type::punctuator_less)[([]([[maybe_unused]] auto&&... unused){return true;})] 2701 | | lit("\""sv)[([]([[maybe_unused]] auto&&... unused){return false;})] 2702 | ); 2703 | static const auto has_include_parser = 2704 | ( veiler::pegasus::semantic_actions::omit[ 2705 | lit(token_type::eol) 2706 | >> lit(token_type::punctuator_hash) 2707 | >> lit(token_type::identifier_if) 2708 | >> *( has_include_parser_impl 2709 | >> ( lit(token_type::punctuator_less) >> *(veiler::pegasus::read - lit(token_type::punctuator_greater)) >> lit(token_type::punctuator_greater) 2710 | | lit("\""sv) >> *(veiler::pegasus::read - lit("\""sv)) >> lit("\""sv) 2711 | ) 2712 | >> lit(token_type::punctuator_right_parenthesis) 2713 | )] 2714 | >> has_include_parser_impl 2715 | ).with_skipper(*white_space); 2716 | auto it = range.begin(); 2717 | const auto include_parser_result = include_parser(it, range.end()); 2718 | const auto has_include_parser_result = include_parser_result ? include_parser_result : has_include_parser(it, range.end()); 2719 | if(include_parser_result || has_include_parser_result){ 2720 | const auto is_angled = include_parser_result ? *include_parser_result : *has_include_parser_result; 2721 | static constexpr auto find_file = [](const std::filesystem::path& include_dir, const std::filesystem::path& path, std::vector& bank){ 2722 | const auto directory_path = include_dir/path.parent_path(); 2723 | if(!std::filesystem::exists(directory_path) || !std::filesystem::is_directory(directory_path)) 2724 | return; 2725 | const veiler::pegasus::iterator_range directory{std::filesystem::directory_iterator{directory_path}, std::filesystem::directory_iterator{}}; 2726 | const auto filename = path.filename().u8string(); 2727 | for(auto&& x : directory){ 2728 | const auto filepath = x.path().filename().u8string(); 2729 | if(filepath.find(filename) != 0) 2730 | continue; 2731 | bank.emplace_back(std::string_view{filepath}.substr(filename.size())); 2732 | if(x.is_directory()) 2733 | bank.back().push_back('/'); 2734 | } 2735 | }; 2736 | std::filesystem::path path(std::string(messer::get_raw(messer::get_raw(it)).get_inner(), anno_range.end().get_inner())); 2737 | std::vector bank; 2738 | if(!is_angled) 2739 | find_file(std::filesystem::path{"."}, path, bank); 2740 | for(auto&& x : preprocessor_data.system_include_dir) 2741 | find_file(x, path, bank); 2742 | std::sort(bank.begin(), bank.end()); 2743 | const auto end = std::unique(bank.begin(), bank.end()); 2744 | for(auto it = bank.begin(); it != end; ++it) 2745 | comp.add_completion(*it); 2746 | comp.set_prefix(path.filename().u8string()); 2747 | return comp; 2748 | } 2749 | } 2750 | static constexpr auto if_parser = 2751 | veiler::pegasus::semantic_actions::omit[ 2752 | lit(token_type::eol) 2753 | >> lit(token_type::punctuator_hash) 2754 | >> veiler::pegasus::lexeme[ 2755 | lit(token_type::identifier_if) 2756 | >> white_space 2757 | ] 2758 | ].with_skipper(*white_space); 2759 | static constexpr auto ifdef_parser = 2760 | ( veiler::pegasus::semantic_actions::omit[ 2761 | lit(token_type::eol) 2762 | >> lit(token_type::punctuator_hash) 2763 | >> ( lit(token_type::identifier_ifdef) 2764 | | lit(token_type::identifier_ifndef) 2765 | )] 2766 | >> veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return messer::is_identifier(v->type());}) 2767 | ).with_skipper(*white_space); 2768 | static constexpr auto define_fm_parser = ( 2769 | veiler::pegasus::semantic_actions::omit[ 2770 | lit(token_type::eol) 2771 | >> lit(token_type::punctuator_hash) 2772 | >> lit(token_type::identifier_define) 2773 | >> veiler::pegasus::lexeme[ 2774 | veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return messer::is_identifier(v->type());}) >> veiler::pegasus::read 2775 | >> lit(token_type::punctuator_left_parenthesis) 2776 | ] 2777 | ] 2778 | >> (veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return messer::is_identifier(v->type());})[veiler::pegasus::semantic_actions::omit] >> veiler::pegasus::read) % lit(token_type::punctuator_comma) 2779 | >> ( ( lit(token_type::punctuator_comma)[veiler::pegasus::semantic_actions::omit] >> lit(token_type::punctuator_ellipsis) )[([]([[maybe_unused]] auto&&... unused){return true;})] 2780 | | veiler::pegasus::eps[([]([[maybe_unused]] auto&&... unused){return false;})] 2781 | ) 2782 | ).with_skipper(*white_space); 2783 | static constexpr auto undef_parser = 2784 | veiler::pegasus::semantic_actions::omit[ 2785 | lit(token_type::eol) 2786 | >> lit(token_type::punctuator_hash) 2787 | >> lit(token_type::identifier_undef) 2788 | >> veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return messer::is_identifier(v->type());}) 2789 | ].with_skipper(*white_space); 2790 | const auto tokens = std::list(range.begin(), range.end()); 2791 | std::string_view prefix = tokens.empty() ? "" : tokens.back().get(); 2792 | if(!tokens.empty() && tokens.back().type() == token_type::white_space) 2793 | prefix = ""; 2794 | comp.set_prefix(prefix); 2795 | std::vector bank; 2796 | if(if_parser(tokens)){ 2797 | if((prefix.size() <= 13 && "__has_include"sv.compare(0, prefix.size(), prefix) == 0) || prefix.empty()) 2798 | bank.emplace_back("__has_include("); 2799 | else if((prefix.size() <= 7 && "defined"sv.compare(0, prefix.size(), prefix) == 0) || prefix.empty()) 2800 | bank.emplace_back("defined("); 2801 | }else if(auto ifdef_directive = ifdef_parser(tokens)){ 2802 | if((*ifdef_directive)->get() != prefix) 2803 | return comp; 2804 | if((prefix.size() <= 13 && "__has_include"sv.compare(0, prefix.size(), prefix) == 0) || prefix.empty()) 2805 | bank.emplace_back("__has_include"); 2806 | }else if(auto define_directive = define_fm_parser(tokens)){ 2807 | auto&& [identifiers, is_variadic] = *define_directive; 2808 | for(auto&& x : identifiers) 2809 | if(prefix.size() <= x->get().size() && x->get().compare(0, prefix.size(), prefix) == 0) 2810 | bank.emplace_back(x->get()); 2811 | if(is_variadic 2812 | && ( (prefix.size() <= 11 && "__VA_ARGS__"sv.compare(0, prefix.size(), prefix) == 0) 2813 | || prefix.empty())) 2814 | bank.emplace_back("__VA_ARGS__"); 2815 | }else{ 2816 | auto it = tokens.cbegin(); 2817 | auto directive = 2818 | ( veiler::pegasus::semantic_actions::omit[ 2819 | lit(token_type::eol) 2820 | >> lit(token_type::punctuator_hash) 2821 | ] 2822 | >> ( veiler::pegasus::filter([](auto&& v, [[maybe_unused]] auto&&... unused){return messer::is_identifier(v->type());}) >> veiler::pegasus::read[veiler::pegasus::omit] 2823 | | veiler::pegasus::eps[veiler::pegasus::semantic_actions::omit] 2824 | ) 2825 | ).with_skipper(*white_space)(it, tokens.cend()); 2826 | if(directive && it == tokens.cend() && ((*directive && (**directive)->get() == prefix) || !*directive)){ 2827 | if(!*directive) 2828 | prefix = ""; 2829 | std::string_view directives[] = { 2830 | "define", 2831 | "elif", 2832 | "else", 2833 | "endif", 2834 | "error", 2835 | "if", 2836 | "ifdef", 2837 | "ifndef", 2838 | "include", 2839 | "line", 2840 | "pragma step", 2841 | "undef", 2842 | }; 2843 | for(auto&& x : directives) 2844 | if((prefix.size() <= x.size() && x.compare(0, prefix.size(), prefix) == 0) || prefix.empty()) 2845 | comp.add_completion(x.substr(prefix.size())); 2846 | return comp; 2847 | } 2848 | } 2849 | const bool is_undef = undef_parser(tokens).valid(); 2850 | auto search_add = [&](auto&& data, char suffix = '\0'){ 2851 | for(auto&& x : data) 2852 | if((prefix.size() <= x.first.size() && !x.first.compare(0, prefix.size(), prefix)) || prefix.empty()){ 2853 | if(suffix == '\0') 2854 | bank.emplace_back(x.first); 2855 | else 2856 | bank.emplace_back(x.first+suffix); 2857 | } 2858 | }; 2859 | search_add(preprocessor_data.objects); 2860 | search_add(preprocessor_data.functions, is_undef ? '\0' : '('); 2861 | if(!is_undef) 2862 | for(auto&& x : { 2863 | "true"sv, 2864 | "false"sv, 2865 | "__TIME__"sv, 2866 | "__DATE__"sv, 2867 | "__FILE__"sv, 2868 | "__LINE__"sv, 2869 | "_Pragma("sv, 2870 | "bitand"sv, 2871 | "and_eq"sv, 2872 | "xor_eq"sv, 2873 | "not_eq"sv, 2874 | "bitor"sv, 2875 | "compl"sv, 2876 | "or_eq"sv, 2877 | "and"sv, 2878 | "xor"sv, 2879 | "not"sv, 2880 | "or"sv 2881 | }) 2882 | if((prefix.size() <= x.size() && x.compare(0, prefix.size(), prefix) == 0) || prefix.empty()) 2883 | bank.emplace_back(x); 2884 | std::sort(bank.begin(), bank.end()); 2885 | const auto end = std::unique(bank.begin(), bank.end()); 2886 | for(auto it = bank.begin(); it != end; ++it) 2887 | comp.add_completion(std::string_view{*it}.substr(prefix.size())); 2888 | return comp; 2889 | }; 2890 | static constexpr auto check_raw_string = [](auto&& s)->std::optional{ 2891 | auto range = s | annotation{""} | phase1 | phase2 | phase3; 2892 | auto it = range.begin(); 2893 | messer::phase3_t::value_type token{{"", messer::token_type::empty}, {"", 0, 0}}; 2894 | static constexpr auto f = [](auto&& raw)->std::optional{ 2895 | std::string delimiter; 2896 | while(*++raw != '(') 2897 | if(*raw != ' ' && *raw != ')' && *raw != '\\' && *raw != '\t' && *raw != '\v' && *raw != '\f' && *raw != '\n') 2898 | delimiter.push_back(*raw); 2899 | else 2900 | return std::nullopt; 2901 | return delimiter; 2902 | }; 2903 | try{ 2904 | const auto end = range.end(); 2905 | auto prev = messer::get_raw(it); 2906 | while(it != end){ 2907 | if(messer::is_identifier(token.type()) && token.get().back() == 'R' && it->get().front() == '"') 2908 | return f(prev); 2909 | prev = messer::get_raw(it); 2910 | token = *it++; 2911 | } 2912 | }catch(...){ 2913 | auto raw = messer::get_raw(it); 2914 | if(*raw == '"' && token.type() == messer::token_type::identifier && token.get().back() == 'R') 2915 | return f(raw); 2916 | } 2917 | return std::nullopt; 2918 | }; 2919 | while(auto in = input(prompt)){ 2920 | str += std::move(*in); 2921 | if(auto raw_string = check_raw_string(str)){ 2922 | prompt = "R\"> "; 2923 | str.push_back('\n'); 2924 | continue; 2925 | } 2926 | if(str.back() == '\\'){ 2927 | prompt = " \\> "; 2928 | str.push_back('\n'); 2929 | continue; 2930 | } 2931 | return str; 2932 | } 2933 | return std::nullopt; 2934 | }; 2935 | while(auto str = logical_line(">>> ")){ 2936 | str->push_back('\n'); 2937 | const auto if_directive = [&](auto&& s){ 2938 | using veiler::pegasus::lit; 2939 | using messer::token_type; 2940 | static constexpr auto if_rule = 2941 | ( lit(token_type::eol) 2942 | >> lit(token_type::punctuator_hash) 2943 | >> ( lit(token_type::identifier_if) 2944 | | lit(token_type::identifier_ifdef) 2945 | | lit(token_type::identifier_ifndef) 2946 | ) 2947 | )[veiler::pegasus::semantic_actions::omit].with_skipper(*white_space); 2948 | return if_rule(s | annotation{""} | phase1 | phase2 | phase3); 2949 | }; 2950 | const auto endif_directive = [&](auto&& s){ 2951 | using veiler::pegasus::lit; 2952 | using messer::token_type; 2953 | static constexpr auto endif_rule = 2954 | ( lit(token_type::eol) 2955 | >> lit(token_type::punctuator_hash) 2956 | >> lit(token_type::identifier_endif) 2957 | )[veiler::pegasus::semantic_actions::omit].with_skipper(*white_space); 2958 | return endif_rule(s | annotation{""} | phase1 | phase2 | phase3); 2959 | }; 2960 | std::size_t if_nest = 0; 2961 | if(if_directive(*str)) 2962 | ++if_nest; 2963 | while(if_nest){ 2964 | if(auto add = logical_line("if> ")){ 2965 | add->push_back('\n'); 2966 | if(endif_directive(*add)) 2967 | --if_nest; 2968 | else if(if_directive(*add)) 2969 | ++if_nest; 2970 | *str += std::move(*add); 2971 | } 2972 | else 2973 | return 0; 2974 | } 2975 | inputed.emplace_back(std::move(*str)); 2976 | auto range = inputed.back() | annotation{""} | phase1 | phase2 | phase3; 2977 | tokens.emplace_back(range.begin(), range.end()); 2978 | try{ 2979 | auto result = phase6(preprocessor_data(tokens.back())); 2980 | if(!result.empty()){ 2981 | for(auto&& x : result) 2982 | std::cout << x; 2983 | std::cout << std::endl; 2984 | } 2985 | }catch(std::exception& e){ 2986 | std::cerr << e.what() << std::endl; 2987 | } 2988 | for(auto&& x : messer::split_range{inputed.back(), "\n"}) 2989 | input.history.add(x); 2990 | } 2991 | } 2992 | 2993 | --------------------------------------------------------------------------------