├── .gitignore ├── gil ├── std.hpp ├── gil.hpp ├── ops.inc ├── std.str.hpp ├── std.io.hpp ├── std.base.hpp ├── gil.impl.hpp └── std.impl.hpp ├── README.md ├── calculator.cpp ├── hello_world_vmi.cpp ├── hello_world.cpp ├── mergesort.cpp └── ased ├── cc1plus └── ld /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Binaries 5 | *.out 6 | *.exe 7 | 8 | # Vim 9 | *.swp 10 | -------------------------------------------------------------------------------- /gil/std.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GIL Standard Library 3 | * 4 | * This header collects all functionality provided by the standard library. 5 | */ 6 | 7 | #ifndef GIL_STD_HPP_ 8 | #define GIL_STD_HPP_ 9 | 10 | #include "std.base.hpp" 11 | #include "std.io.hpp" 12 | #include "std.str.hpp" 13 | 14 | #endif // GIL_STD_HPP_ 15 | -------------------------------------------------------------------------------- /gil/gil.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GNU Interface Layer 3 | * 4 | * This header file exposes the instruction set architecture 5 | * for the C++ abstract machine. 6 | */ 7 | 8 | #ifndef GIL_HPP_ 9 | #define GIL_HPP_ 10 | 11 | #include "gil.impl.hpp" 12 | 13 | namespace gil { 14 | 15 | using detail::expr::expr; 16 | using detail::expr::len; 17 | using detail::expr::none; 18 | using detail::expr::peek; 19 | using detail::expr::str; 20 | using detail::expr::tuple; 21 | using detail::expr::val; 22 | using detail::expr::var; 23 | using detail::expr::vec; 24 | 25 | using detail::exec::Advance; 26 | using detail::exec::Put; 27 | using detail::exec::Set; 28 | 29 | using detail::exec::Block; 30 | using detail::exec::If; 31 | using detail::exec::While; 32 | 33 | using detail::runtime::debug; 34 | using detail::runtime::start; 35 | 36 | } // namespace gil 37 | 38 | #endif // GIL_HPP_ 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Based C++ 2 | 3 | This repo provides an implementation of the GNU Interface Layer (GIL) and standard library for `g++`. 4 | 5 | ### C++ is the best interpreted language 6 | 7 | [![C++ is the best interpreted language!](https://img.youtube.com/vi/cFtymODJEjs/0.jpg)](https://youtu.be/cFtymODJEjs) 8 | 9 | ## Usage 10 | 11 | Here is a simple "Hello, world!" in C++. 12 | 13 | ```cpp 14 | #include "gil/std.hpp" 15 | using namespace gil::std; 16 | 17 | volatile auto run = main<{ 18 | str::puts(str::literal("Hello, world!\n")) 19 | }>; 20 | ``` 21 | 22 | To run the program, run 23 | 24 | ```sh 25 | g++ -std=c++23 -Based hello_world.cpp -o - 26 | ``` 27 | 28 | > [!NOTE] 29 | > The above command only works if you invoke `g++` from the root of this repo; otherwise, you will have to provide the full path to the required abstract system emulator drivers (`ased`) folder. 30 | 31 | ## Examples 32 | 33 | - `hello_world.cpp` 34 | > Be greeted in all of the languages supported by YVR! 35 | - `hello_world_vmi.cpp` 36 | > Same as above, but without using the standard library. 37 | - `calculator.cpp` 38 | > Perform a single binary operation on a pair of 64-bit signed integers. 39 | - `mergesort.cpp` 40 | > Merge sort a comma-separated list of 64-bit signed integers. 41 | 42 | 43 | -------------------------------------------------------------------------------- /calculator.cpp: -------------------------------------------------------------------------------- 1 | //usr/bin/env g++ -Based -std=c++23 -O2 -o - "${@:0}"; exit 2 | 3 | #include "gil/std.hpp" 4 | 5 | using namespace gil::std; 6 | 7 | enum { 8 | LHS, 9 | RHS, 10 | OP, 11 | RES, 12 | }; 13 | 14 | using Num = long long int; 15 | 16 | volatile auto run = main<{ 17 | // divine punishment for not entering reasonable input 18 | var_(LHS) = io::read(), 19 | var_(OP) = io::read(), 20 | var_(RHS) = io::read(), 21 | 22 | switch_(var_(OP))( 23 | case_('+')( 24 | var_(RES) = var_(LHS) + var_(RHS) 25 | ), 26 | case_('-')( 27 | var_(RES) = var_(LHS) - var_(RHS) 28 | ), 29 | case_('*')( 30 | var_(RES) = var_(LHS) * var_(RHS) 31 | ), 32 | case_('/')( 33 | if_(var_(RHS) != 0)( 34 | var_(RES) = var_(LHS) / var_(RHS) 35 | )->else_( 36 | str::puts(str::literal("Division by zero!\n")) 37 | ) 38 | ), 39 | case_('%')( 40 | if_(var_(RHS) != 0)( 41 | var_(RES) = var_(LHS) % var_(RHS) 42 | )->else_( 43 | str::puts(str::literal("Modulo zero!\n")) 44 | ) 45 | ), 46 | default_( 47 | str::puts(str::literal("Invalid OP: ")), 48 | putc_(var_(OP)), 49 | putc_('\n') 50 | ) 51 | ), 52 | if_(var_(RES) != none_)( 53 | io::write(var_(RES)), 54 | putc_('\n') 55 | ) 56 | }>; 57 | -------------------------------------------------------------------------------- /hello_world_vmi.cpp: -------------------------------------------------------------------------------- 1 | //usr/bin/env g++ -Based -std=c++23 -O2 -o - "$0" -DLANGUAGE="$1" "${@:2}"; exit 2 | 3 | #include "gil/gil.hpp" 4 | using namespace gil; 5 | 6 | enum Language { 7 | English, 8 | Français, 9 | 中文, 10 | }; 11 | 12 | enum { 13 | name, 14 | index, 15 | }; 16 | 17 | template 18 | using Puts = Block< 19 | Set>, 20 | While<(var < len), 21 | Block]>, Set + val<1>>>>>; 22 | 23 | template struct SayGreeting; 24 | 25 | template <> struct SayGreeting { 26 | template using To = Puts + name + str<"!">>; 27 | }; 28 | 29 | template <> struct SayGreeting { 30 | template using To = Puts + name + str<" !">>; 31 | }; 32 | 33 | template <> struct SayGreeting<中文> { 34 | template using To = Puts>; 35 | }; 36 | 37 | using SkipWhitespace = 38 | While == val<' '> || peek<> == val<'\n'> || peek<> == val<'\t'>, 39 | Advance<>>; 40 | 41 | template 42 | using Reads = Block>, 43 | While != val<'\n'> && peek<> != none, 44 | Block + peek<>>, Advance<>>>>; 45 | 46 | auto run = start, 47 | SayGreeting::template To>, Put>>; 48 | -------------------------------------------------------------------------------- /hello_world.cpp: -------------------------------------------------------------------------------- 1 | //usr/bin/env g++ -Based -std=c++23 -O2 -o - "$0" -DLANGUAGE="$1" "${@:2}"; exit 2 | 3 | #include "gil/std.hpp" 4 | using namespace gil::std; 5 | 6 | enum { 7 | NAME, 8 | INDEX, 9 | IS_WHITESPACE, 10 | CH, 11 | }; 12 | 13 | enum Language { 14 | English, 15 | Français, 16 | 中文, 17 | }; 18 | 19 | template 20 | static constexpr auto greet(auto name) noexcept { 21 | if constexpr (language == English) { 22 | return block_( 23 | str::puts(str::literal("Hello, ")), 24 | str::puts(name), 25 | str::puts(str::literal("!\n")) 26 | ); 27 | } else if constexpr (language == Français) { 28 | return block_( 29 | str::puts(str::literal("Bonjour, ")), 30 | str::puts(name), 31 | str::puts(str::literal(" !\n")) 32 | ); 33 | } else if constexpr (language == 中文) { 34 | return block_( 35 | str::puts(name), 36 | str::puts(str::literal("好。\n")) 37 | ); 38 | } 39 | } 40 | 41 | volatile auto run = main<{ 42 | var_(IS_WHITESPACE) = fn_(CH)( 43 | break_(var_(CH) == ' ' || var_(CH) == '\t' || var_(CH) == '\n') 44 | ), 45 | while_((*var_(IS_WHITESPACE))(var_(NAME)[0] = getc_()))(), 46 | var_(INDEX) = 1, 47 | while_((var_(NAME)[*var_(INDEX)] = getc_()) != none_)( 48 | ++var_(INDEX) 49 | ), 50 | for_(--var_(INDEX), 51 | var_(INDEX) >= 0 && (*var_(IS_WHITESPACE))(var_(NAME)[*var_(INDEX)]), 52 | --var_(INDEX))( 53 | var_(NAME)[*var_(INDEX)] = none_ 54 | ), 55 | greet(var_(NAME)) 56 | }>; 57 | -------------------------------------------------------------------------------- /gil/ops.inc: -------------------------------------------------------------------------------- 1 | #ifdef UN_OP 2 | #define PURE_UN_OP(O) UN_OP(O) 3 | #define MOD_UN_OP(O) UN_OP(O##O) 4 | #endif 5 | 6 | #ifdef PURE_UN_OP 7 | PURE_UN_OP(+) 8 | PURE_UN_OP(-) 9 | PURE_UN_OP(*) 10 | PURE_UN_OP(~) 11 | PURE_UN_OP(&) 12 | PURE_UN_OP(!) 13 | #undef PURE_UN_OP 14 | #endif 15 | 16 | #ifdef MOD_UN_OP 17 | MOD_UN_OP(+) 18 | MOD_UN_OP(-) 19 | #undef MOD_UN_OP 20 | #endif 21 | 22 | #ifdef POST_UN_OP 23 | POST_UN_OP(+) 24 | POST_UN_OP(-) 25 | #undef POST_UN_OP 26 | #endif 27 | 28 | #ifdef UN_OP 29 | #undef UN_OP 30 | #endif 31 | 32 | #ifdef BIN_OP 33 | #define PURE_BIN_OP(O) BIN_OP(O) 34 | #define ASSIGN_OP() BIN_OP(=) 35 | #define ASSIGN_BIN_OP(O) BIN_OP(O## =) 36 | #endif 37 | 38 | #ifdef PURE_BIN_OP 39 | PURE_BIN_OP(+) 40 | PURE_BIN_OP(-) 41 | PURE_BIN_OP(*) 42 | PURE_BIN_OP(/) 43 | PURE_BIN_OP(%) 44 | PURE_BIN_OP(^) 45 | PURE_BIN_OP(&) 46 | PURE_BIN_OP(|) 47 | PURE_BIN_OP(<) 48 | PURE_BIN_OP(>) 49 | PURE_BIN_OP(<<) 50 | PURE_BIN_OP(>>) 51 | PURE_BIN_OP(==) 52 | PURE_BIN_OP(!=) 53 | PURE_BIN_OP(<=) 54 | PURE_BIN_OP(>=) 55 | PURE_BIN_OP(->*) 56 | #ifndef NO_SHORTCIRCUIT_OPS 57 | PURE_BIN_OP(&&) 58 | PURE_BIN_OP(||) 59 | #else 60 | #undef NO_SHORTCIRCUIT_OPS 61 | #endif 62 | #undef PURE_BIN_OP 63 | #endif 64 | 65 | #ifdef ASSIGN_OP 66 | ASSIGN_OP() 67 | #undef ASSIGN_OP 68 | #endif 69 | 70 | #ifdef ASSIGN_BIN_OP 71 | ASSIGN_BIN_OP(+) 72 | ASSIGN_BIN_OP(-) 73 | ASSIGN_BIN_OP(*) 74 | ASSIGN_BIN_OP(/) 75 | ASSIGN_BIN_OP(%) 76 | ASSIGN_BIN_OP(^) 77 | ASSIGN_BIN_OP(&) 78 | ASSIGN_BIN_OP(|) 79 | ASSIGN_BIN_OP(<<) 80 | ASSIGN_BIN_OP(>>) 81 | #undef ASSIGN_BIN_OP 82 | #endif 83 | 84 | #ifdef BIN_OP 85 | #undef BIN_OP 86 | #endif 87 | 88 | #ifdef POLY_OP 89 | POLY_OP(()) 90 | POLY_OP([]) 91 | #undef POLY_OP 92 | #endif 93 | -------------------------------------------------------------------------------- /gil/std.str.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GIL Standard Library - Strings 3 | * 4 | * This header provides support for string literals and 5 | * string manipulation. 6 | */ 7 | 8 | #ifndef GIL_STD_STR_HPP_ 9 | #define GIL_STD_STR_HPP_ 10 | 11 | #include "std.base.hpp" 12 | 13 | namespace gil { 14 | namespace std { 15 | namespace str { 16 | 17 | namespace _impl_ { 18 | 19 | constexpr struct : local { 20 | } _str_idx_; 21 | static constexpr auto idx = global_(_str_idx_); 22 | 23 | constexpr struct : local { 24 | } _str_tmp_; 25 | static constexpr auto tmp = global_(_str_tmp_); 26 | 27 | } // namespace _impl_ 28 | 29 | template static constexpr auto literal(char const (&str)[n]) { 30 | detail::string::StringLiteral literal = str; 31 | return lib::ir::IR{literal}; 32 | } 33 | 34 | static constexpr auto memcpy(auto dst, auto src, auto size) noexcept { 35 | using _impl_::idx; 36 | 37 | return for_(idx = 0, idx < size, ++idx)(dst[*idx] = src[*idx]); 38 | } 39 | 40 | static constexpr auto end(auto ch) noexcept { 41 | return ch == none_ || ch == '\0'; 42 | } 43 | 44 | static constexpr auto strlen(auto str) noexcept { 45 | using _impl_::idx; 46 | using _impl_::tmp; 47 | return for_(block_(idx = 0, tmp = str), true, 48 | ++idx)(if_(end(*tmp[*idx]))(break_(*idx))); 49 | } 50 | 51 | static constexpr auto strcpy(auto dst, auto src) noexcept { 52 | using _impl_::idx; 53 | return for_(idx = 0, true, ++idx)(dst[*idx] = *src[*idx], 54 | if_(end(src[*idx]))(break_)); 55 | } 56 | 57 | static constexpr auto puts(auto str) noexcept { 58 | using _impl_::idx; 59 | return for_(idx = 0, !end(str[*idx]), ++idx)(putc_(str[*idx])); 60 | } 61 | 62 | } // namespace str 63 | } // namespace std 64 | } // namespace gil 65 | 66 | #endif // GIL_STD_STR_HPP_ 67 | -------------------------------------------------------------------------------- /mergesort.cpp: -------------------------------------------------------------------------------- 1 | //usr/bin/env g++ -Based -std=c++23 -O2 -o - "${@:0}"; exit 2 | 3 | #include "gil/std.hpp" 4 | using namespace gil::std; 5 | 6 | using Num = long long int; 7 | 8 | static constexpr auto read_array(auto array, auto len) noexcept { 9 | return block_( 10 | array[0] = io::read(), 11 | if_(array[0] == none_)( 12 | len = 0 13 | )->else_( 14 | for_(len = 1, io::read() == ',', ++len)( 15 | array[*len] = io::read() 16 | ) 17 | ) 18 | ); 19 | } 20 | 21 | static constexpr auto write_array(auto array, auto len) noexcept { 22 | constexpr struct : local {} stack; 23 | constexpr auto i = var_(stack)[0]; 24 | return block_( 25 | putc_('['), 26 | for_(i = 0, i < len, ++i)( 27 | if_(i > 0)( 28 | str::puts(str::literal(", ")) 29 | ), 30 | io::write(array[*i]) 31 | ), 32 | putc_(']'), 33 | putc_('\n') 34 | ); 35 | } 36 | 37 | enum { 38 | MERGESORT, 39 | LO, 40 | HI, 41 | MID, 42 | TMP, 43 | I, 44 | J, 45 | K, 46 | ARRAY, 47 | LEN, 48 | }; 49 | 50 | volatile auto run = main<{ 51 | global_(MERGESORT) = fn_(ARRAY, LO, HI)( 52 | if_(var_(LO) + 1 < var_(HI))( 53 | var_(MID) = (var_(LO) + var_(HI)) / 2, 54 | (*global_(MERGESORT))(*var_(ARRAY), *var_(LO), *var_(MID)), 55 | (*global_(MERGESORT))(*var_(ARRAY), *var_(MID), *var_(HI)), 56 | var_(I) = *var_(LO), 57 | var_(J) = *var_(MID), 58 | for_(var_(K) = 0, var_(I) < var_(MID) && var_(J) < var_(HI), ++var_(K))( 59 | if_((**var_(ARRAY))[*var_(I)] < (**var_(ARRAY))[*var_(J)])( 60 | var_(TMP)[*var_(K)] = *(**var_(ARRAY))[var_(I)++] 61 | )->else_( 62 | var_(TMP)[*var_(K)] = *(**var_(ARRAY))[var_(J)++] 63 | ) 64 | ), 65 | while_(var_(I) < var_(MID))( 66 | var_(TMP)[var_(K)++] = *(**var_(ARRAY))[var_(I)++] 67 | ), 68 | while_(var_(J) < var_(HI))( 69 | var_(TMP)[var_(K)++] = *(**var_(ARRAY))[var_(J)++] 70 | ), 71 | for_(block_(var_(K) = 0, var_(I) = *var_(LO)), 72 | var_(I) < var_(HI), 73 | block_(++var_(K), ++var_(I)))( 74 | (**var_(ARRAY))[*var_(I)] = *var_(TMP)[*var_(K)] 75 | ) 76 | ) 77 | ), 78 | 79 | read_array(var_(ARRAY), var_(LEN)), 80 | (*global_(MERGESORT))(&var_(ARRAY), 0, *var_(LEN)), 81 | write_array(var_(ARRAY), var_(LEN)) 82 | }>; 83 | -------------------------------------------------------------------------------- /gil/std.io.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GIL Standard Library - I/O 3 | * 4 | * This header implements the standard I/O functions for reading 5 | * and writing elementary data types in C++. 6 | */ 7 | 8 | #ifndef GIL_STD_IO_HPP_ 9 | #define GIL_STD_IO_HPP_ 10 | 11 | #include "std.base.hpp" 12 | 13 | namespace gil { 14 | namespace std { 15 | namespace io { 16 | 17 | namespace _impl_ { 18 | 19 | constexpr struct : local { 20 | } _io_idx_; 21 | static constexpr auto idx = global_(_io_idx_); 22 | 23 | constexpr struct : local { 24 | } _io_tmp_; 25 | static constexpr auto tmp = global_(_io_tmp_); 26 | 27 | } // namespace _impl_ 28 | 29 | static constexpr auto isspace(auto ch) noexcept { 30 | using _impl_::tmp; 31 | return block_(tmp = ch, break_(tmp == ' ' || tmp == '\t' || tmp == '\n' || 32 | tmp == '\v' || tmp == '\f' || tmp == '\r')); 33 | } 34 | 35 | static constexpr auto skip_whitespace() noexcept { 36 | return loop_(if_(isspace(peek_()))(advance_())->else_(break_)); 37 | } 38 | 39 | template static constexpr auto read() noexcept; 40 | 41 | template static constexpr auto write = [](auto...) {}; 42 | 43 | template <> constexpr auto read() noexcept { 44 | return block_(skip_whitespace(), break_(getc_())); 45 | } 46 | 47 | template <> constexpr auto write = [](auto expr) { return putc_(expr); }; 48 | 49 | namespace integral { 50 | 51 | template static constexpr auto read_int() noexcept { 52 | using _impl_::tmp; 53 | constexpr auto is_neg = tmp[0]; 54 | constexpr auto succ = tmp[1]; 55 | return block_(skip_whitespace(), is_neg = peek_() == '-', succ = false, 56 | tmp = static_cast(0), 57 | loop_(if_(peek_(*is_neg) != none_ && peek_(*is_neg) <= '9' && 58 | peek_(*is_neg) >= '0')( 59 | tmp = tmp * 10 + cast_(peek_(*is_neg) - '0'), 60 | advance_(), succ = true) 61 | ->else_(break_)), 62 | if_(succ)(if_(is_neg)(advance_(), tmp *= static_cast(-1)), 63 | break_(*tmp))); 64 | } 65 | 66 | template static constexpr auto write_int(auto var) noexcept { 67 | using _impl_::tmp; 68 | constexpr auto digit = tmp[0]; 69 | constexpr auto magnitude = tmp[1]; 70 | constexpr auto ten = static_cast(10); 71 | constexpr auto zero = static_cast(0); 72 | 73 | return block_(tmp = var, if_(tmp == zero)(putc_('0'), break_), 74 | if_(tmp < zero)(putc_('-'), tmp *= static_cast(-1)), 75 | for_(magnitude = static_cast(1), magnitude <= tmp, 76 | magnitude *= ten)(), 77 | while_((magnitude /= ten) > 78 | zero)(putc_(cast_(tmp / magnitude) + '0'), 79 | tmp %= magnitude)); 80 | } 81 | 82 | } // namespace integral 83 | 84 | #define INTIO(signed, int) \ 85 | template <> constexpr auto read() noexcept { \ 86 | return integral::read_int(); \ 87 | } \ 88 | template <> \ 89 | constexpr auto write = \ 90 | [](auto expr) { return integral::write_int(expr); }; 91 | #define INTIO_PAIR(int) \ 92 | INTIO(signed, int) \ 93 | INTIO(unsigned, int) 94 | 95 | INTIO_PAIR(char) 96 | INTIO_PAIR(short) 97 | INTIO_PAIR(int) 98 | INTIO_PAIR(long) 99 | INTIO_PAIR(long long) 100 | 101 | #undef INTIO_PAIR 102 | #undef INTIO 103 | 104 | } // namespace io 105 | } // namespace std 106 | } // namespace gil 107 | 108 | #endif // GIL_STD_IO_HPP_ 109 | -------------------------------------------------------------------------------- /gil/std.base.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GIL Standard Library - Base Language 3 | * 4 | * This header implements the C++ language (variables, blocks, keywords). 5 | */ 6 | 7 | #ifndef GIL_STD_BASE_HPP_ 8 | #define GIL_STD_BASE_HPP_ 9 | 10 | #include "std.impl.hpp" 11 | 12 | namespace gil { 13 | namespace std { 14 | 15 | struct local { 16 | template constexpr bool operator==(this This &&, This &&) { 17 | return true; 18 | } 19 | }; 20 | 21 | static constexpr auto peek_(auto offset) noexcept { 22 | return lib::ir::IR{lib::code::Peek{offset}}; 23 | } 24 | 25 | static constexpr auto peek_() noexcept { return peek_(0u); } 26 | 27 | static constexpr auto advance_(auto offset) noexcept { 28 | return lib::ir::IR{lib::code::Advance{offset}}; 29 | } 30 | 31 | static constexpr auto advance_() noexcept { return advance_(1u); } 32 | 33 | template static constexpr auto cast_(auto expr) noexcept { 34 | return lib::ir::IR{lib::code::Cast{expr}}; 35 | } 36 | 37 | static constexpr auto getc_() noexcept { 38 | return lib::ir::IR{lib::code::GetC{}}; 39 | } 40 | 41 | static constexpr auto putc_(auto code) noexcept { 42 | return lib::ir::IR{lib::code::PutC{lib::ir::get_code(code)}}; 43 | } 44 | 45 | static constexpr struct : local { 46 | } _stack_local_scope_; 47 | 48 | static constexpr auto global_(auto name) noexcept { 49 | return lib::ir::IR{lib::code::Var{lib::ir::get_code(name)}}; 50 | } 51 | 52 | static constexpr auto var_(auto name) noexcept { 53 | return global_(name)[*global_(_stack_local_scope_)]; 54 | } 55 | 56 | static constexpr auto bundle(auto... parts) { 57 | return lib::ir::IR{lib::bundle::Bundle{parts...}}; 58 | } 59 | 60 | static constexpr auto if_(auto cond) noexcept { 61 | return [=](auto... code) { 62 | return lib::ir::IR{lib::code::ctrl::IfBlock< 63 | decltype(cond), lib::code::ctrl::Block, void>{ 64 | cond, {{code...}}}}; 65 | }; 66 | } 67 | 68 | static constexpr auto loop_(auto... code) noexcept { 69 | return lib::ir::IR{lib::code::ctrl::LoopBlock{ 70 | lib::code::ctrl::Block{{code...}}}}; 71 | } 72 | 73 | static constexpr auto continue_ = lib::code::ctrl::Continue{}; 74 | static constexpr auto break_ = lib::code::ctrl::Break{}; 75 | 76 | static constexpr auto block_(auto... code) { return loop_(code..., break_); } 77 | 78 | static constexpr auto while_(auto cond) noexcept { 79 | return [=](auto... code) { return loop_(if_(cond)(code...)->else_(break_)); }; 80 | } 81 | 82 | static constexpr auto for_(auto init, auto cond, auto post) noexcept { 83 | return [=](auto... code) { 84 | return loop_(init, break_(while_(cond)(code..., post))); 85 | }; 86 | } 87 | 88 | namespace _impl_ { 89 | 90 | static constexpr struct : local { 91 | } switcher; 92 | 93 | template struct Case { 94 | Expr expr; 95 | Body body; 96 | }; 97 | 98 | template struct Default { 99 | Body body; 100 | }; 101 | 102 | static constexpr auto switch_impl(auto expr) noexcept { return block_(); } 103 | 104 | template 105 | static constexpr auto switch_impl(auto expr, Case case_, 106 | auto... cases) noexcept { 107 | return if_(expr == case_.expr)(case_.body) 108 | ->else_(switch_impl(expr, cases...)); 109 | } 110 | 111 | template 112 | static constexpr auto switch_impl(auto expr, Default default_, 113 | auto... cases) noexcept { 114 | if constexpr (sizeof...(cases) > 0) 115 | return switch_impl(cases..., default_); 116 | else 117 | return default_.body; 118 | } 119 | 120 | } // namespace _impl_ 121 | 122 | static constexpr auto case_(auto expr) noexcept { 123 | return [=](auto... body) { 124 | return _impl_::Case{expr, 125 | lib::code::ctrl::Block{{body...}}}; 126 | }; 127 | } 128 | 129 | static constexpr auto default_(auto... body) noexcept { 130 | return _impl_::Default{lib::code::ctrl::Block{{body...}}}; 131 | } 132 | 133 | static constexpr auto switch_(auto expr) noexcept { 134 | return [=](auto... cases) { 135 | constexpr auto switcher = global_(_impl_::switcher); 136 | return block_(switcher = expr, _impl_::switch_impl(*switcher, cases...)); 137 | }; 138 | } 139 | 140 | static constexpr auto none_ = lib::ir::IR{lib::none::None{}}; 141 | 142 | namespace _impl_ { 143 | 144 | static constexpr struct : local { 145 | } _lambda_return_; 146 | 147 | template struct Lambda { 148 | Args args; 149 | Body body; 150 | 151 | constexpr auto operator()(auto... vars) const noexcept { 152 | lib::bundle::Bundle varbundle{vars...}; 153 | return lib::ir::IR{loop_( 154 | ++global_(_stack_local_scope_), 155 | lib::bundle::fold([](auto arg, auto var) { return var_(arg) = var; }, 156 | args, varbundle), 157 | global_(_lambda_return_) = body, --global_(_stack_local_scope_), 158 | break_(*global_(_lambda_return_)))}; 159 | } 160 | }; 161 | 162 | } // namespace _impl_ 163 | 164 | static constexpr auto fn_(auto... args) { 165 | return [=](auto... code) { 166 | return _impl_::Lambda{lib::bundle::Bundle{args...}, loop_(code..., break_)}; 167 | }; 168 | } 169 | 170 | namespace _impl_ { 171 | 172 | template 173 | using Main = lib::interpret::Interpret; 178 | 179 | } // namespace _impl_ 180 | 181 | #if DEBUG == 0 182 | template 183 | static constexpr auto main = 184 | detail::string::as_literal::Effect::Stdout>; 185 | #else 186 | template 187 | static constexpr auto main = 188 | detail::runtime::_impl_::Debug 189 | #if DEBUG == 1 190 | ::Effect 191 | #endif 192 | >{}; 193 | #endif 194 | 195 | } // namespace std 196 | } // namespace gil 197 | 198 | #endif // GIL_STD_BASE_HPP_ 199 | -------------------------------------------------------------------------------- /ased/cc1plus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | This abstract system emulator driver is responsible for 4 | sending terminal console input to the C++ program standard 5 | input stream. 6 | """ 7 | 8 | from dataclasses import dataclass 9 | import re 10 | import subprocess 11 | import sys 12 | import typing 13 | 14 | 15 | def find_cc1plus(gcc): 16 | cmd = (gcc, "-xc++", "-E", "-", "-wrapper", "echo") 17 | 18 | mime = subprocess.run( 19 | cmd, 20 | stdout=subprocess.PIPE, 21 | text=True, 22 | check=True, 23 | ) 24 | 25 | return mime.stdout.split()[0] 26 | 27 | 28 | def yesify(s: str): 29 | return s.strip().lower() in ("1", "yes", "true", "indeed") 30 | 31 | 32 | def run_cc1plus(cmd: tuple[str, ...], debug: int): 33 | if not debug: 34 | return subprocess.call(cmd) 35 | 36 | run = subprocess.run( 37 | (*cmd, "-D", f"DEBUG={debug}"), stderr=subprocess.PIPE, text=True 38 | ) 39 | if run.returncode == 0: 40 | print("cc1plus failed unsuccessfully", file=sys.stderr) 41 | return 101 42 | 43 | note_pat = re.compile( 44 | r"(?P.*?):(?P\d+):(?P\d+): (?P\w+): (?P.*?) ‘(?P.*?)’" 45 | ) 46 | aka_pat = re.compile(r"\s*\{aka ‘(?P.*?)’\}") 47 | debug_pat = re.compile( 48 | r"struct gil::detail::runtime::_impl_::Debug<(?P.*)>" 49 | ) 50 | last_note = None 51 | last_aka = None 52 | for line in run.stderr.splitlines(): 53 | note = note_pat.match(line) 54 | if note is None: 55 | continue 56 | last_note = note 57 | last_aka = aka_pat.match(line, note.end()) 58 | if note["severity"] == "error": 59 | break 60 | 61 | if last_note is None: 62 | sys.stderr.write(run.stderr) 63 | return 202 64 | 65 | if debug_struct := debug_pat.match(last_note["line"]): 66 | dump_struct(debug_struct["content"]) 67 | return 68 | 69 | print( 70 | "{what!r} {severity} at {file}:{row}:{col}:".format( 71 | what=last_note["what"].title(), 72 | severity=last_note["severity"], 73 | file=last_note["file"], 74 | row=last_note["row"], 75 | col=last_note["col"], 76 | ) 77 | ) 78 | dump_struct(last_note["line"]) 79 | if last_aka is not None: 80 | print("~~~ aka ~~~") 81 | dump_struct(last_aka["aka"]) 82 | 83 | return run.returncode 84 | 85 | 86 | def dump_struct(s: str, *, bufsize: int = 1): 87 | CHUNK = re.compile(r"[^<>(){}'\",]*") 88 | STRING = { 89 | '"': re.compile(r"[^\"\\]*"), 90 | "'": re.compile(r"[^'\\]*"), 91 | } 92 | depth = 0 93 | buf = "" 94 | index = 0 95 | 96 | def take(): 97 | nonlocal s, index 98 | if index < len(s): 99 | c = s[index] 100 | index += 1 101 | return c 102 | return "" 103 | 104 | def read_str(delim: typing.Literal['"', "'"]): 105 | nonlocal STRING, s, index 106 | tot = "" 107 | while True: 108 | chunk = STRING[delim].match(s, index) 109 | if chunk is None: 110 | break 111 | tot += chunk[0] 112 | index = chunk.end() 113 | 114 | ch = take() 115 | tot += ch 116 | if ch == delim: 117 | break 118 | if ch == "\\": 119 | tot += take() 120 | 121 | return tot 122 | 123 | def read_chunk(): 124 | nonlocal CHUNK, s, index 125 | tot = "" 126 | while index < len(s): 127 | chunk = CHUNK.match(s, index) 128 | if chunk is None: 129 | break 130 | tot += chunk[0] 131 | index = chunk.end() 132 | 133 | ch = take() 134 | tot += ch 135 | 136 | if ch == ",": 137 | yield tot, 0 138 | tot = "" 139 | continue 140 | if ch in ("<", "(", "{", "["): 141 | yield tot, 1 142 | tot = "" 143 | continue 144 | if ch in (">", ")", "}", "]"): 145 | yield tot[:-1], None 146 | yield tot[-1], -1 147 | tot = "" 148 | continue 149 | if ch in ("'", '"'): 150 | tot += read_str(ch) 151 | continue 152 | 153 | yield tot, None 154 | 155 | def combine_chunk(chunk: str, act: typing.Literal[1, 0, -1] | None): 156 | nonlocal buf, bufsize, depth 157 | match act: 158 | case None: 159 | buf += chunk 160 | case 0: 161 | yield depth, buf + chunk 162 | buf = "" 163 | case 1: 164 | yield depth, buf + chunk 165 | depth += 1 166 | buf = "" 167 | case -1: 168 | yield depth, buf 169 | depth -= 1 170 | buf = chunk 171 | 172 | if sys.stdout.isatty() and ( 173 | sys.platform != "win32" or yesify(os.environ.get("ANSICON", "0")) 174 | ): 175 | 176 | def print_chunk(depth: int, line: str): 177 | line = line.strip() 178 | col = (depth % 7) + 1 179 | bold = "1;" if (depth // 7) & 1 == 0 else "" 180 | dim = "2;" if (depth // 14) & 1 else "" 181 | print(f"\x1b[{bold}{dim}3{col}m{line}\x1b[m", end=" ") 182 | 183 | elif yesify(os.environ.get("CC1PLUS_DEBUG_ONELINE", "0")): 184 | 185 | def print_chunk(depth: int, line: str): 186 | print(line.strip(), end=" ") 187 | 188 | else: 189 | 190 | def print_chunk(depth: int, line: str): 191 | line = line.strip() 192 | if line: 193 | print(" " * depth + line) 194 | 195 | for chunk, act in read_chunk(): 196 | for pad, line in combine_chunk(chunk, act): 197 | print_chunk(pad, line) 198 | print_chunk(depth, buf) 199 | print() 200 | 201 | 202 | if __name__ == "__main__": 203 | from json import dumps 204 | import os 205 | import shutil 206 | 207 | verbose = yesify(os.environ.get("CC1PLUS_VERBOSE", "0")) 208 | try: 209 | debug = int(os.environ.get("CC1PLUS_DEBUG", "0")) 210 | except ValueError: 211 | print(f"Error: CC1PLUS_DEBUG expects an integer.", file=sys.stderr) 212 | exit(1) 213 | 214 | try: 215 | cc1plus = os.environ.get("CC1PLUS") 216 | 217 | if cc1plus is None: 218 | gcc = os.environ.get("GCC") or shutil.which("g++") or "g++" 219 | if verbose: 220 | print(f"GCC={gcc}", file=sys.stderr) 221 | 222 | cc1plus = find_cc1plus(gcc) 223 | 224 | if verbose: 225 | print(f"CC1PLUS={cc1plus}", file=sys.stderr) 226 | 227 | args = sys.argv[1:] 228 | stdin = dumps(sys.stdin.read()) 229 | 230 | cmd = (cc1plus, *args, "-D", f"__STDIN__={stdin}") 231 | if verbose: 232 | print(" ".join(map(dumps, cmd))) 233 | exit(run_cc1plus(cmd, debug)) 234 | 235 | except Exception as exc: 236 | print(f"cc1plus failed: {exc}", file=sys.stderr) 237 | exit(1) 238 | except KeyboardInterrupt: 239 | exit(1) 240 | -------------------------------------------------------------------------------- /ased/ld: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | GIL standard linking script. 4 | 5 | This abstract system emulator driver is responsible for linking 6 | C++ program output stream with the terminal console output. 7 | """ 8 | 9 | from dataclasses import dataclass 10 | import io 11 | import os 12 | import shutil 13 | import subprocess 14 | import sys 15 | import typing as T 16 | 17 | 18 | def is_obj_file(arg: str): 19 | return arg.endswith(".o") and os.path.isfile(arg) 20 | 21 | 22 | @dataclass(frozen=True) 23 | class Config: 24 | 25 | out: str 26 | files: tuple[str, ...] 27 | cxxfilt: str | None 28 | verbose: bool 29 | print_bytes: bool 30 | run: bytes 31 | 32 | @classmethod 33 | def from_args(cls, argv: list[str]): 34 | argi = iter(argv) 35 | 36 | out = "a.out" 37 | files = list[str]() 38 | verbose = False 39 | print_bytes = False 40 | run = None 41 | 42 | while arg := next(argi, None): 43 | match arg: 44 | case "--verbose": 45 | verbose = True 46 | case "--print-bytes": 47 | print_bytes = True 48 | case "-o" | "--output": 49 | out = next(argi, out) 50 | case output if output.startswith("--output="): 51 | out = arg.split("=", 1)[-1] or next(argi, out) 52 | case "-r" | "--run": 53 | run = next(argi, run) 54 | case symbol if symbol.startswith("--run="): 55 | run = arg.split("=", 1)[-1] or next(argi, run) 56 | case file if os.path.isfile(file): 57 | files.append(file) 58 | case _: 59 | pass 60 | 61 | if out == "-": 62 | out = "/dev/stdout" 63 | 64 | cxxfilt = ( 65 | os.environ.get("CXXFILT") 66 | or shutil.which("cxxfilt") 67 | or shutil.which("c++filt") 68 | if verbose 69 | else None 70 | ) 71 | 72 | if run is None: 73 | run = os.environ.get("CXXRUN", "run") 74 | 75 | return cls(out, tuple(files), cxxfilt, verbose, print_bytes, run.encode()) 76 | 77 | def log(self, *args, **kwargs): 78 | if self.verbose: 79 | print(*args, **kwargs) 80 | 81 | 82 | class InvalidObjFile(Exception): ... 83 | 84 | 85 | @dataclass(frozen=True) 86 | class Named[T]: 87 | entry: T 88 | name: bytes 89 | 90 | def __str__(self): 91 | return repr("".join(map(chr, self.name)))[1:-1] 92 | 93 | 94 | type Table[T] = tuple[Named[T], ...] 95 | 96 | 97 | class ELF: 98 | 99 | @staticmethod 100 | def expect(cond: bool): 101 | if not cond: 102 | raise InvalidObjFile 103 | 104 | class Cursor: 105 | def __init__(self, bin: T.IO[bytes]): 106 | self.__bin = bin 107 | self.addrsize: T.Literal[4, 8] | None = None 108 | self.byteorder: T.Literal["big", "little"] | None = None 109 | 110 | def seek(self, pos: int): 111 | return self.__bin.seek(pos) 112 | 113 | def read(self, nbytes: int) -> bytes: 114 | b = self.__bin.read(nbytes) 115 | if len(b) != nbytes: 116 | raise InvalidObjFile 117 | return b 118 | 119 | def readwhile(self, cond: T.Callable[[bytes], bool]): 120 | b = b"" 121 | while cond(n := self.read(1)): 122 | b += n 123 | return b 124 | 125 | def readstr(self): 126 | return self.readwhile(lambda b: b != b"\x00") 127 | 128 | def readint(self, nbytes: int) -> int: 129 | assert self.byteorder is not None 130 | return int.from_bytes(self.read(nbytes), self.byteorder) 131 | 132 | def readhalfword(self) -> int: 133 | return self.readint(2) 134 | 135 | def readword(self) -> int: 136 | return self.readint(4) 137 | 138 | def readoffset(self) -> int: 139 | assert self.addrsize is not None 140 | return self.readint(self.addrsize) 141 | 142 | def select[R](self, nbytes: int, opts: dict[bytes, R]) -> R: 143 | res = opts.get(self.read(nbytes), InvalidObjFile()) 144 | if isinstance(res, InvalidObjFile): 145 | raise InvalidObjFile 146 | return res 147 | 148 | @dataclass(frozen=True) 149 | class Header: 150 | shoffset: int 151 | shentsize: int 152 | shnum: int 153 | strtabidx: int 154 | 155 | @classmethod 156 | def read(cls, cursor: "ELF.Cursor"): 157 | 158 | cursor.seek(0) 159 | ELF.expect(cursor.read(4) == b"\x7fELF") # magic 160 | cursor.addrsize = cursor.select(1, {b"\x01": 4, b"\x02": 8}) 161 | cursor.byteorder = cursor.select(1, {b"\x01": "little", b"\x02": "big"}) 162 | ELF.expect(cursor.read(1) == b"\x01") # version 163 | 164 | # skip to header 165 | cursor.seek(16) 166 | 167 | ELF.expect(cursor.readhalfword() == 0x01) # type == ET_REL 168 | cursor.readhalfword() # machine 169 | ELF.expect(cursor.readword() == 1) # version 170 | cursor.readoffset() # entrypoint 171 | cursor.readoffset() # PH offset 172 | shoffset = cursor.readoffset() # SH offset 173 | cursor.readword() # flags 174 | cursor.readhalfword() # elf header size 175 | cursor.readhalfword() # PH entry size 176 | cursor.readhalfword() # PH entry count 177 | shentsize = cursor.readhalfword() # SH entry size 178 | shnum = cursor.readhalfword() # SH entry count 179 | strtaboff = cursor.readhalfword() # SH string table index 180 | 181 | return cls(shoffset, shentsize, shnum, strtaboff) 182 | 183 | def section_headers(self, cursor: "ELF.Cursor"): 184 | cursor.seek(self.shoffset) 185 | section_headers = tuple( 186 | ELF.SectionHeader.read(cursor) for _ in range(self.shnum) 187 | ) 188 | shstrtab = section_headers[self.strtabidx] 189 | 190 | def named(sh: ELF.SectionHeader): 191 | cursor.seek(shstrtab.offset + sh.name) 192 | return Named(sh, cursor.readstr()) 193 | 194 | return tuple(map(named, section_headers)) 195 | 196 | @dataclass(frozen=True) 197 | class SectionHeader: 198 | name: int 199 | type: int 200 | flags: int 201 | addr: int 202 | offset: int 203 | size: int 204 | link: int 205 | info: int 206 | align: int 207 | entsize: int 208 | 209 | @classmethod 210 | def read(cls, cursor: "ELF.Cursor"): 211 | return cls( 212 | name=cursor.readword(), 213 | type=cursor.readword(), 214 | flags=cursor.readoffset(), 215 | addr=cursor.readoffset(), 216 | offset=cursor.readoffset(), 217 | size=cursor.readoffset(), 218 | link=cursor.readword(), 219 | info=cursor.readword(), 220 | align=cursor.readoffset(), 221 | entsize=cursor.readoffset(), 222 | ) 223 | 224 | def symtab(self, cursor: "ELF.Cursor", shtab: Table["ELF.SectionHeader"]): 225 | if self.type != 2: # SHT_SYMTAB = 2 226 | return None 227 | if self.entsize == 0: 228 | return None 229 | cursor.seek(self.offset) 230 | symbols = tuple( 231 | ELF.Symbol.read(cursor) for _ in range(0, self.size, self.entsize) 232 | ) 233 | strtab = shtab[self.link].entry 234 | 235 | def named(sym: ELF.Symbol): 236 | cursor.seek(strtab.offset + sym.name) 237 | return Named(sym, cursor.readstr()) 238 | 239 | return tuple(map(named, symbols)) 240 | 241 | @dataclass(frozen=True) 242 | class Symbol: 243 | name: int 244 | value: int 245 | size: int 246 | info: int 247 | other: int 248 | section_idx: int 249 | 250 | @classmethod 251 | def read32(cls, cursor: "ELF.Cursor"): 252 | assert cursor.addrsize == 4 253 | return cls( 254 | name=cursor.readword(), 255 | value=cursor.readword(), 256 | size=cursor.readoffset(), 257 | info=cursor.readint(1), 258 | other=cursor.readint(1), 259 | section_idx=cursor.readhalfword(), 260 | ) 261 | 262 | @classmethod 263 | def read64(cls, cursor: "ELF.Cursor"): 264 | assert cursor.addrsize == 8 265 | return cls( 266 | name=cursor.readword(), 267 | info=cursor.readint(1), 268 | other=cursor.readint(1), 269 | section_idx=cursor.readhalfword(), 270 | value=cursor.readoffset(), 271 | size=cursor.readoffset(), 272 | ) 273 | 274 | @classmethod 275 | def read(cls, cursor: "ELF.Cursor"): 276 | match cursor.addrsize: 277 | case 4: 278 | return cls.read32(cursor) 279 | case 8: 280 | return cls.read64(cursor) 281 | case _: 282 | raise InvalidObjFile 283 | 284 | @property 285 | def st_type(self): 286 | return self.info >> 4 287 | 288 | @property 289 | def st_bind(self): 290 | return self.info & 0x0F 291 | 292 | def content(self, cursor: "ELF.Cursor", shtab: Table["ELF.SectionHeader"]): 293 | if self.st_type != 1: # STT_OBJECT = 1 294 | return None 295 | 296 | section = shtab[self.section_idx].entry 297 | cursor.seek(section.offset + self.value) 298 | return cursor.read(self.size) 299 | 300 | @dataclass(frozen=True) 301 | class Table: 302 | entry: tuple["ELF.Symbol.Table.Entry", ...] 303 | 304 | def __iter__(self): 305 | return iter(self.entry) 306 | 307 | @dataclass(frozen=True) 308 | class Entry: 309 | symbol: "ELF.Symbol" 310 | name: bytes 311 | 312 | @classmethod 313 | def read( 314 | cls, 315 | cursor: "ELF.Cursor", 316 | symbol: "ELF.Symbol", 317 | strtab: "ELF.SectionHeader", 318 | ): 319 | cursor.seek(strtab.offset + symbol.name) 320 | return cls(symbol, cursor.readstr()) 321 | 322 | def __init__(self, bin: T.IO[bytes]): 323 | try: 324 | bin.seek(0) 325 | except io.UnsupportedOperation: 326 | bin = io.BytesIO(bin.read()) 327 | 328 | self.cursor = ELF.Cursor(bin) 329 | self.header = ELF.Header.read(self.cursor) 330 | 331 | 332 | def read_output(ld_cfg: Config, bin: T.IO[bytes]): 333 | LD_LOG_WIDTH = "LD_LOG_WIDTH" 334 | log_width = 24 335 | log_min_width = 24 336 | try: 337 | log_width = int(os.environ.get(LD_LOG_WIDTH, log_width)) 338 | except ValueError: 339 | ld_cfg.log( 340 | f"Invalid integer value for {LD_LOG_WIDTH}", os.environ.get(LD_LOG_WIDTH) 341 | ) 342 | 343 | def log_kv(key: object, value: object, *, depth: int = 0): 344 | nonlocal log_width, log_min_width 345 | PAD = "[...]" 346 | kstr = str(key) 347 | 348 | tab = depth * 2 349 | max_width = max(log_width - tab, 0) 350 | width = max_width or max(log_min_width - tab, 0) 351 | lhs = ( 352 | f"{kstr}:" 353 | if max_width <= 0 or len(kstr) <= max_width 354 | else ( 355 | f"{kstr[:max_width-len(PAD)]}{PAD}" 356 | if max_width > len(PAD) 357 | else f"{kstr[:max_width - 1]}~" 358 | ) 359 | ) 360 | ld_cfg.log(f"{' '*tab}{lhs:{width}} {value}") 361 | 362 | elf = ELF(bin) 363 | ld_cfg.log("~~~~~") 364 | log_kv("ELF object file", bin.name) 365 | log_kv( 366 | "Address size", 367 | str("??" if elf.cursor.addrsize is None else elf.cursor.addrsize * 8) + "-bit", 368 | ) 369 | log_kv("Endianness", elf.cursor.byteorder) 370 | 371 | shtab = elf.header.section_headers(elf.cursor) 372 | log_kv("Section headers", len(shtab)) 373 | log_kv("SH string table", f"{shtab[elf.header.strtabidx]} [{elf.header.strtabidx}]") 374 | 375 | for idx, sh in enumerate(shtab): 376 | symtab = sh.entry.symtab(elf.cursor, shtab) 377 | if symtab is None: 378 | continue 379 | log_kv("Symbol table", f"{sh} [{idx}]") 380 | for sym in symtab: 381 | 382 | symname = str(sym) 383 | if ld_cfg.verbose and ld_cfg.cxxfilt: 384 | filt = subprocess.run( 385 | (ld_cfg.cxxfilt, symname), stdout=subprocess.PIPE, text=True 386 | ) 387 | if filt.returncode == 0: 388 | symname = filt.stdout.strip() 389 | 390 | if content := sym.entry.content(elf.cursor, shtab): 391 | bytestr = " ".join(map(lambda b: f"{b:02x}", content[:32])) 392 | if len(content) > 32: 393 | bytestr += " ..." 394 | 395 | if not ld_cfg.verbose and sym.name == ld_cfg.run: 396 | if ld_cfg.print_bytes: 397 | with open(ld_cfg.out, "a") as out: 398 | out.write(f"{bin.name}: {content!r}\n") 399 | else: 400 | with open(ld_cfg.out, "ab") as out: 401 | out.write(content) 402 | bytestr = f"[{bytestr}]" 403 | else: 404 | bytestr = None 405 | 406 | log_kv(symname, bytestr, depth=1) 407 | 408 | 409 | if __name__ == "__main__": 410 | ld_cfg = Config.from_args(sys.argv) 411 | ld_cfg.log("cmd:", *sys.argv) 412 | ld_cfg.log("output symbol:", ld_cfg.run) 413 | 414 | # clear file contents 415 | open(ld_cfg.out, "w").close() 416 | 417 | for file in ld_cfg.files: 418 | with open(file, "rb") as bin: 419 | try: 420 | read_output(ld_cfg, bin) 421 | except InvalidObjFile: 422 | ld_cfg.log("skipping file:", file) 423 | -------------------------------------------------------------------------------- /gil/gil.impl.hpp: -------------------------------------------------------------------------------- 1 | /** ******** 2 | * GNU Interface Layer - Implementation 3 | * 4 | * This header implements the C++ abstract machine and the behaviour 5 | * of its instruction set. 6 | */ 7 | 8 | #ifndef GIL_IMPL_HPP_ 9 | #define GIL_IMPL_HPP_ 10 | 11 | namespace gil { 12 | 13 | namespace detail { 14 | 15 | namespace type { 16 | struct None; 17 | struct Undefined; 18 | template struct Value; 19 | } // namespace type 20 | 21 | namespace tfunc { 22 | 23 | namespace _impl_ { 24 | 25 | template struct Len; 26 | 27 | template