231 lines
9.1 KiB
Plaintext
231 lines
9.1 KiB
Plaintext
[/
|
|
(C) Copyright Edward Diener 2011-2015
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt).
|
|
]
|
|
|
|
[section:vmd_sequence Parsing sequences]
|
|
|
|
In the normal use of Boost PP data is passed as arguments to a macro in
|
|
discrete units so that each parameter expects a single data type. A typical
|
|
macro might be:
|
|
|
|
#define AMACRO(anumber,atuple,anidentifier) someoutput
|
|
|
|
where the 'atuple', having the form of ( data1, data2, data3 ), itself may
|
|
contain different data types of elements.
|
|
|
|
This is the standard macro design and internally it is the easiest way
|
|
to pass macro data back and forth. The Boost PP library has a rich set of
|
|
functionality to deal with all of its high-level data types, and variadic data,
|
|
with its own simpler functionality, also offers another alternative to
|
|
representing data.
|
|
|
|
Occasionally designers of macros, especially for the use of others programmers within
|
|
a particular library, have expressed the need for a macro parameter to allow a more
|
|
C/C++ like syntax where a single parameter might mimic a C++ function-call or a
|
|
C-like type modification syntax, or some other more complicated construct.
|
|
Something along the lines of:
|
|
|
|
areturn afunction ( aparameter1, aparameter2, aparameter3 )
|
|
|
|
or
|
|
|
|
( type ) data
|
|
|
|
etc. etc.
|
|
|
|
In other words, from a syntactical level when designing possible macro input,
|
|
is it possible to design parameter data to look more like C/C++ when macros
|
|
are used in a library and still do a certain amount of preprocessor metaprogramming
|
|
with such mixed token input ?
|
|
|
|
VMD has functionality which allows more than one type of preprocessing token,
|
|
excluding an 'empty' token which always refers to some entire input, to be part of a
|
|
single parameter of input data. These preprocessing tokens as a single parameter are
|
|
syntactically a consecutive series of data. The single limitation of this consecutive
|
|
series of data is that each top-level part of the data of this series is of some VMD data type.
|
|
What this means is that if some input consists of a series of data types it is possible
|
|
to extract the data for each data type in that series.
|
|
|
|
In practicality what this means is that, given the examples just above, if
|
|
'areturn', 'afunction', and 'data' are identifiers it would be possible to
|
|
parse either of the two inputs above so that one could identify the different
|
|
data types involved and do preprocessor metaprogramming based on those results.
|
|
|
|
[heading Sequence definition]
|
|
|
|
I will be calling such input data, which consists of all top-level data types in a series,
|
|
by the term of a 'sequence'. Each separate data type in the sequence is called an 'element'.
|
|
In this definition of a 'sequence' we can have 0 or more elements, so that a sequence
|
|
is a general name for any VMD input. A sequence is therefore
|
|
any input VMD can parse, whether it is emptiness, a single element, or more than one
|
|
element in a series. Therefore when we speak of VMD macros parsing input data we are
|
|
really speaking of VMD macros parsing a sequence. A sequence can therefore also be part of
|
|
a Boost PP composite data type, or variadic data, and VMD can still parse such an embedded
|
|
sequence if asked to do so.
|
|
|
|
[heading Sequence parsing]
|
|
|
|
Parsing a sequence means that VMD can step through each element of a sequence
|
|
sequentially, determine the type and data of each element, then move on to the
|
|
next element. Parsing is sequential and can only be done in a forward direction,
|
|
but it can be done any number of times. In C++ iterator terms parsing of a
|
|
sequence is a forward iterator.
|
|
|
|
Working with a sequence is equivalent to using VMD macros 'generically'.
|
|
|
|
Before I give an explanation of how to use a sequence using VMD generic
|
|
functionality I would like to make two points:
|
|
|
|
* The possibility of working with a sequence which contains more than one
|
|
data type can be easily abused. In general
|
|
keeping things simple is usually better than making things overly complicated
|
|
when it comes to the syntactical side of things in a computer language. A macro
|
|
parameter syntactical possibility has to be understandable to be used.
|
|
* Using VMD to parse the individual data types of a sequence takes more
|
|
preprocessing time than functionality offered with Boost PP data types,
|
|
because it is based on forward access through each top-level type of the sequence.
|
|
|
|
The one constraint in a sequence is that the top-level must
|
|
consist of VMD data types, in other words preprocessor tokens which VMD understands.
|
|
By top-level it is meant that a Boost PP composite data may have elements which
|
|
VMD cannot parse but as long as the input consists of the composite data types and
|
|
not the inner unparsable elements, VMD can parse the input.
|
|
Therefore if preprocessor data is one of the examples above, you will be successful
|
|
in using VMD. However if your preprocessor data takes the form of:
|
|
|
|
&name identifier ( param )
|
|
|
|
or
|
|
|
|
identifier "string literal"
|
|
|
|
or
|
|
|
|
identifier + number
|
|
|
|
or
|
|
|
|
identifier += 4.3
|
|
|
|
etc. etc.
|
|
|
|
you will not be able to parse the data using VMD since '&', "string literal",
|
|
'+', '+=', and "4.3" are preprocessor tokens which are not VMD top-level data types and
|
|
therefore VMD cannot handle them at the parsing level. You can still of course
|
|
pass such data as preprocessing input to macros but you cannot use VMD to recognize
|
|
the parts of such data.
|
|
|
|
This is similar to the fact that VMD cannot tell you what type preprocessor data
|
|
is as a whole, using any of the VMD identifying macros already discussed, if the
|
|
type is not one that VMD can handle.
|
|
|
|
On the other hand you can still use VMD to parse such tokens in the input if you use
|
|
Boost PP data types as top-level data types to do so. Such as:
|
|
|
|
( &name ) identifier ( param )
|
|
|
|
or
|
|
|
|
identifier ( "string literal" )
|
|
|
|
or
|
|
|
|
identifier ( + ) number
|
|
|
|
or
|
|
|
|
identifier ( += ) 4 ( . ) 3
|
|
|
|
The succeeding topics explain the VMD functionality for parsing a sequence
|
|
for each individual VMD data type in that sequence.
|
|
|
|
[heading Sequence types]
|
|
|
|
A VMD sequence can be seen as one of either three general types:
|
|
|
|
# An empty sequence
|
|
# A single element sequence
|
|
# A multi-element sequence
|
|
|
|
An empty sequence is merely input that is empty, what VMD calls "emptiness". Use the previously
|
|
explained BOOST_VMD_IS_EMPTY macro to test for an empty sequence.
|
|
|
|
#include <boost/vmd/is_empty.hpp>
|
|
|
|
#define AN_EMPTY_SEQUENCE
|
|
|
|
BOOST_VMD_IS_EMPTY(AN_EMPTY_SEQUENCE) will return 1
|
|
|
|
The type of an empty sequence is BOOST_VMD_TYPE_EMPTY.
|
|
|
|
A single element sequence is a single VMD data type. This is what
|
|
we have been previously discussing as data which VMD can parse in this
|
|
documentation with our identifying macros. You can use the
|
|
BOOST_VMD_IS_UNARY macro to test for a single element sequence.
|
|
|
|
#include <boost/vmd/is_unary.hpp>
|
|
|
|
#define A_SINGLE_ELEMENT_SEQUENCE (1,2)
|
|
|
|
BOOST_VMD_IS_UNARY(A_SINGLE_ELEMENT_SEQUENCE) will return 1
|
|
|
|
The type of a single element sequence is the type of the individual data type.
|
|
In our example above the type of A_SINGLE_ELEMENT_SEQUENCE is BOOST_VMD_TYPE_TUPLE.
|
|
|
|
A multi-element sequence consists of more than one data type. This is the
|
|
"new" type which VMD can parse. You can use the BOOST_VMD_IS_MULTI macro
|
|
to test for a multi-element sequence.
|
|
|
|
#define A_MULTI_ELEMENT_SEQUENCE (1,2) (1)(2) 45
|
|
|
|
The A_MULTI_ELEMENT_SEQUENCE consists of a tuple followed by a seq followed by a number.
|
|
|
|
#include <boost/vmd/is_multi.hpp>
|
|
|
|
BOOST_VMD_IS_MULTI(A_MULTI_ELEMENT_SEQUENCE) will return 1
|
|
|
|
The type of a multi-element sequence is always BOOST_VMD_TYPE_SEQUENCE.
|
|
|
|
The type of a sequence can be obtained generically with the BOOST_VMD_GET_TYPE
|
|
macro. We will be explaining this further in the documentation.
|
|
|
|
[heading Sequence size]
|
|
|
|
The size of any sequence can be accessed using the BOOST_VMD_SIZE macro.
|
|
For an empty sequence the size is always 0. For a single element sequence
|
|
the size is always 1. For a multi-element sequence the size is the number
|
|
of individual top-level data types in the sequence.
|
|
|
|
#include <boost/vmd/size.hpp>
|
|
|
|
BOOST_VMD_SIZE(AN_EMPTY_SEQUENCE) will return 0
|
|
BOOST_VMD_SIZE(A_SINGLE_ELEMENT_SEQUENCE) will return 1
|
|
BOOST_VMD_SIZE(A_MULTI_ELEMENT_SEQUENCE) will return 3
|
|
|
|
[heading Using VMD to parse sequence input]
|
|
|
|
For a VMD sequence essentially two ways of parsing into individual data
|
|
types are offered by the VMD library:
|
|
|
|
# The sequence can be converted to any of the Boost PP data types, or
|
|
to variadic data, where each individual data type in the sequence becomes
|
|
a separate element of the particular composite data type chosen. The
|
|
conversion to a particular Boost PP data type or variadic data is slow,
|
|
because it is based on forward access through each top-level type of the sequence,
|
|
but afterwards accessing any individual element is as fast as accessing
|
|
any element in the Boost PP data type or among variadic data.
|
|
# The sequence can be accessed directly through its individual elements.
|
|
This is slower than accessing an element of a Boost PP data type
|
|
or variadic data but offers conceptual access to the original sequence
|
|
as a series of elements.
|
|
|
|
These two techniques will be discussed in succeeding topics.
|
|
|
|
[include vmd_sequence_convert.qbk]
|
|
[include vmd_sequence_access.qbk]
|
|
|
|
[endsect]
|