c++ positive integer preprocessing method

  • 2020-05-26 09:51:57
  • OfStack

Although the preprocessing is also Turing complete with 1 set through the ingenuity of series 1, it is really thankless to do the calculation with the preprocessing. Because preprocessor 1 was designed with little ambition, it was originally designed to do simple text replacement work, and it was not intended to be a regular 8 programming language, even the most limited version of the scripting language could not meet the functional requirements. Only later, there was a lot of demand for automatic batch generation of code, especially before c++11 version of what to play template metaprogramming, overwhelming need for a lot of similar code. This code is generated by other tools, which is more elegant, but it's always easier to do this with native preprocessing, otherwise you'd have to run the external tool once every time you make a change. I prefer to use preprocessing to generate code. In addition, after c++11, it is true that many situations where macros are needed to generate code are no longer necessary, but since c++11 has greatly enhanced its type derivation capability, it is found that there is another large area where macros can be used to generate code. Not that macros in C++ are essential, but using macros can really cut down on a lot of repetitive code, at least on paper.

Pretreatment of native data types are only symbols and symbols and only support # feeder, at the same time, the results after pretreatment can also identify and meet (otherwise, calculate and collect is meaningless), if it is a macro function, it calls the operation, if it is a macro symbols, just replace text, if nothing, do nothing, keep symbols. But this type of weak chicken is clearly far from meeting the needs of the deviant code ape. After lots of macro-program to try, can be very sure that 1 point, pretreatment in simulated again only 1 kind of data type, that is a positive integer, negative although by complement operation simulation, but due to the inside of the preprocessing symbol cannot contain a minus sign (-) character, of course, it takes great effort also can modify negative integer, just also is not convenient also not intuitive to use, price is not high, basically, must use the macro to generate code, can don't need a negative integer.

In addition, preprocessing does not have the concept of variable type, let alone strong type, or even weak type. It is completely untyped. Positive integer type depends on the concept of code compiler to maintenance man flesh, 1 cycle of macro code generation 1 kind is back and forth and don't know how many layer of macro calls, call any one place error, sometimes is a few tons, dense in the middle of the failure code, the compiler of the pretreatment of buffer overflow, capitulated), sometimes no output, no 1 ounce of prompt, is to find a needle in a haystack. So you have to be very careful when generating code with macro loops, step by step, and you have to say, well, the types in the language are a good thing.

In fact, the data type is not important, but the set of operations that can be supported on the data and where these operations can be applied.
Ok, back to the above, we made 10 Numbers with _ZPP_INC_N, and by copying and pasting, we can increase N to 255. In practice, it's completely adequate.

#define _ZPP_INC_JOIN(_A, _B) _ZPP_INC_JOIN_IMP1(_A, _B)
#define _ZPP_INC_JOIN_IMP1(_A, _B) _ZPP_INC_JOIN_IMP2(~, _A##_B)
#define _ZPP_INC_JOIN_IMP2(p, res) res

#define PP_INC(x, ) _ZPP_INC_JOIN(_ZPP_INC_, x)
#define _ZPP_INC_0 1
#define _ZPP_INC_1 2
#define _ZPP_INC_2 3
#define _ZPP_INC_3 4
#define _ZPP_INC_4 5
#define _ZPP_INC_5 6
#define _ZPP_INC_6 7
#define _ZPP_INC_7 8
#define _ZPP_INC_8 9
#define _ZPP_INC_9 10
...
#define _ZPP_INC_255 256

In the same way, PP_DEC is brewed, starting at 256 and decreasing 1 to 0. For Numbers greater than 256, they are not supported, and they are all undefined operations. So if I go through PP_INC(n), I get n+1; PP_DEC(n) is n-1. For example, PP_INC(PP_DEC(9)), the result must be 9. Good. So, in this case, we're dealing with natural Numbers that are self-incrementing by 1 and self-subtracting by 1. In addition, for a number greater than 256, such as 512 passed to PP_INC, you only get one symbol of _ZPP_INC_512, which makes no sense at all.

And then, the judgment that two natural Numbers are equal is also very important and must be supported. However, before doing so, implement a macro function, PP_NOT, to determine whether the input parameter is 0. If it is 0, the function returns 1; otherwise, it returns 0. That is:
PP_NOT(0) == 1
PP_NOT(23) == 0, or PP_NOT(var) == 0.
Remember, preprocessing gives us native types that are nothing but symbols and ## and operations. As if the tools were too simple to accomplish the purpose? Have to admire the imagination of some code ape. So the following code works, assuming PP_NOT produces the following call form, regardless PP_ARG1, ~ as for symbols, is like this, can be as a common variable name, it is a placeholder, because pretreatment only identify the comma (,), and small brackets, as for other symbols, completely ignore, those are C/C + + compile phase is concerned with symbols.
PP_NOT(0) = PP_ARG1(~, 1, 0)
PP_NOT(n) = PP_ARG1(_ZPP_NOT_n, 0)
Then, let PP_ARG1 take the second parameter (the code ape counts from 0, that is, 0 is 1,1 is 2), and you are done. As for what _ZPP_NOT_n is, that is just a temporary symbol generated in the middle, which can be discarded. We just have to do something special with _ZPP_NOT_0. So, the code can be written like this. PP_PROBE() is used to generate two input parameters
#define PP_PROBE() ~, 1
#define _ZPP_NOT_0 PP_PROBE()
#define PP_NOT(_X, ...) PP_IS(PP_JOIN(_ZPP_NOT_, _X))
# define PP_IS(...) PP_ARG1(__VA_ARGS__, 0)

After this, it is clear that PP_NOT(n) can be changed to PP_ARG1(_ZPP_NOT_n, 0). Isn't PP_NOT only one entry? The reason for the ellipsis is purely for the purpose of pleasing the compiler with all sorts of perverted applications. Once you've written your code in macros, you don't have to follow any rules, just get the job done.

As for the implementation of PP_ARG1, it is very simple, as shown below,
#define PP_ARG0(_0, ...) _0
#define PP_ARG1(_0, _1, ...) _1
#define PP_ARG2(_0, _1, _2, ...) _2

And then you take the inverse function twice, and you fill in PP_BOOL, if you take in the parameters > 0, return 1, otherwise return 0, similar to integer to bool cast.
#define PP_BOOL(_X, ...) PP_NOT(PP_NOT(_X))

So with that in mind, it's easy to compare two natural Numbers that are equal to each other. There is nothing mysterious about this, except to repeat the following 256 #define statements from 0 to 255,
#define _ZPP_0_EQUALS_0 PP_PROBE()
#define _ZPP_1_EQUALS_1 PP_PROBE()
#define _ZPP_2_EQUALS_2 PP_PROBE()
...
#define PP_EQUALS(x, y) PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y))
PP_EQUALS is to join the arguments into the form of _ZPP_x_EQUALS_y. As long as x and y are the same, that is, they are in the above table, then the result will be 1, just like the implementation of PP_NOT. In fact, there is no such thing as judgment in preprocessing, only table, only union, only look up table. The so-called Turing complete, put simply, there is no mystery, is to build a table, and then look up the table. Take the inverse PP_NOT for the equality comparison, and you will naturally get the judgment function of inequality.
#define PP_UN_EQUALS(x, y) PP_NOT(PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y)))
Once again, you can get the function that bool operates on, or with
#define PP_OR(a,b) PP_CONCAT3(_ZPP_OR_, a, b)
#define _ZPP_OR_00 0
#define _ZPP_OR_01 1
#define _ZPP_OR_10 1
#define _ZPP_OR_11 1

#define PP_AND(a,b) PP_CONCAT3(_ZPP_AND_, a, b)
#define _ZPP_AND_00 0
#define _ZPP_AND_01 0
#define _ZPP_AND_10 0
#define _ZPP_AND_11 1

Prepare another table and map the bytes to eight base 2 bits.
#define _ZPP_BINARY_0 (0, 0, 0, 0, 0, 0, 0, 0)
#define _ZPP_BINARY_1 (0, 0, 0, 0, 0, 0, 0, 1)
#define _ZPP_BINARY_2 (0, 0, 0, 0, 0, 0, 1, 0)
#define _ZPP_BINARY_3 (0, 0, 0, 0, 0, 0, 1, 1)
#define _ZPP_BINARY_4 (0, 0, 0, 0, 0, 1, 0, 0)
...
Then by simulating the principle of addition, subtraction, multiplication and division in the principle of computer composition, we can realize 4 operations. By the way, the whole preprocessor library code is on the compressed package, which is much more powerful than the preprocessor library of boost. However, the code is much less and much easier to understand. All the code runs normally under vs, which has not been tested on other platforms. Code package: preprocessor.rar


Related articles: