1 // (C) Copyright Vesa Karvonen 2004.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE.)
6 // \section{A Taste of Order} %*************************************
8 // The following chapters gradually introduce and formally define
9 // the elements of the Order language, but in this section we will
10 // take a brief informal look at a concrete example. The code
11 // snippets that we will show in this section may look ``funny'' and
12 // may be difficult to understand on first reading, but you
13 // shouldn't worry about it. You may want to read this section again
14 // after you've finished a few more chapters.
16 // As we said, Order is a C preprocessor metalanguage that can be
17 // used to generate sequences of preprocessing tokens. Normally, the
18 // generated preprocessing tokens would eventually be converted to C
19 // or C++ tokens and would constitute program code. To avoid
20 // motivating and defining an actual code generation problem, we
21 // will show two ways to use Order to generate the complete lyrics
22 // to the song ``99 Bottles of Beer on the Wall''. While the actual
23 // logic required to generate the lyrics is quite trivial, this
24 // example is sufficient to give an idea how Order can actually be
27 // Let's first consider the song, which can be thought of as a
28 // countdown from 99 to 1. Each phrase, between 99 and 3, looks like
31 N bottles of beer on the wall
,
32 N bottles of beer
, take one down
, pass it around
,
33 N
-1 bottles of beer on the wall
.
35 // Boring, isn't it? Well, things get a bit more interesting in the
36 // last two phrases. When there is just 1 bottle of beer we must
37 // drop the plural. When there are no more bottles, we must say so.
38 // The last two phrases look like this:
40 2 bottles of beer on the wall
,
41 2 bottles of beer
, take one down
, pass it around
,
42 1 bottle of beer on the wall
.
44 1 bottle of beer on the wall
,
45 1 bottle of beer
, take one down
, pass it around
,
46 no more bottles of beer on the wall
.
48 // So, the key is to generate the correct phrase for referring to
49 // the number of bottles. We can express the rule in Order code
50 // using a conditional expression with three clauses:
52 8cond((8greater(8N
, 1),
53 8separate(8N
, 8quote(bottles
)))
57 8quote(no more bottles
)))
59 // Undoubtedly the first thing to notice was the prefix `8'. It
60 // is a prefix of \emph{all} Order expressions and its purpose is to
61 // prevent \emph{unintended macro replacement} of Order expressions.
62 // A token that starts with a digit, like `8cond', is called a
63 // \emph{pp-number} and because it isn't an \emph{identifier} it
64 // isn't subject to macro replacement. The use of pp-numbers is
65 // admittedly an ugly detail, but it is absolutely necessary,
66 // because otherwise an Order expression might get macro replaced by
67 // a user or standard defined macro, like the \emph{abominable}
68 // macro `I' incredibly defined by the C standard\footnote{There
69 // aren't words strong enough that I could credibly use here to
70 // describe what I think about the quality of certain parts of the C
71 // standard \cite{c:1999}.}, before the Order interpreter gets to
72 // analyze the expression. Please note that unintended macro
73 // replacement isn't a novel problem introduced by the Order
74 // interpreter. It is a well known problem of the C preprocessor
75 // \cite{stroustrup:1994}. It should be noted that \emph{all} macros
76 // defined by the implementation of the Order interpreter have the
77 // prefix `ORDER_PP'. This makes it very unlikely that the Order
78 // interpreter would cause unintended macro replacements.
80 // The second thing to notice in the above expression is the
81 // conditional expression `8cond(...)'.\footnote{Borrowed from
82 // Scheme.} A conditional expression consists of a sequence of
83 // clauses. Each clause is a parenthesized list of comma separated
84 // expressions. The first expression of each clause must be a
85 // boolean expression or `8else', which can only be used in the
86 // last clause. Roughly speaking, a conditional expression is
87 // evaluated by evaluating the boolean expressions, starting at the
88 // first clause, until a boolean expression is found that evaluates
89 // to true. Then the rest of the expressions of the true clause are
92 // The `8quote' syntactic form is used to quote values that must not
93 // be evaluated by the interpreter. All values manipulated by the
94 // Order interpreter are sequences of preprocessing tokens. A value
95 // manipulated by the Order interpreter must be eligible as a single
96 // macro argument. We use the term \emph{pp-arg} to refer to such
97 // preprocessing token sequences. A \emph{pp-arg} must not contain,
98 // nor macro replace to a token sequence containing, unparenthesized
99 // commas nor unbalanced parentheses.
101 // The binary function `8separate', given two arguments, evaluates
102 // to a new token sequence that consists of the tokens of the two
103 // arguments separated by a space. The expression `8N' is a variable
104 // reference. By default, variable identifiers in the Order
105 // interpreter are limited to the tokens `8[A-Z]', meaning the digit
106 // `8' followed by a capital letter.\footnote{The interpreter can be
107 // extended to be able to use additional variable symbols by
108 // defining suitable macros.}
110 // Let's then continue with the example. To make the above
111 // conditional expression really useful, we can wrap it inside a
112 // function that we can apply to any number of bottles:
115 8cond((8greater(8N
, 1),
117 8quote(no more bottles
))))
119 // The `8fn(...)' syntactic form defines an anonymous
120 // first-class function. The above function binds the variable
121 // `8N', which is referred to in the conditional expression.
123 // Given the number of bottles bound to the variable `8N' and
124 // the above auxiliary function bound to the variable `8B', we
125 // can now output one phrase of the song using a `8print'
128 8print(8ap(8B
, 8N
) (of beer on the wall
,) 8space
129 8ap(8B
, 8N
) (of beer
,) 8space
130 (take one down
, pass it around
,) 8space
131 8ap(8B
, 8dec(8N
)) (of beer on the wall
.))
133 // A `8print' expression is evaluated by implicitly outputing the
134 // value of any unparenthesized Order expression and outputing any
135 // parenthesized sequence of tokens verbatim. The `8ap' syntactic
136 // form is the function application expression. \emph{Top-level}
137 // functions, like the prelude function `8greater', but also
138 // \emph{user-defined} top-level functions, can be applied without
139 // using `8ap', but `8ap' needs to be used otherwise. The `8space'
140 // syntactic form can only be used inside `8print' and causes a
141 // space to be output.\footnote{In other words, the keyword `8space'
142 // is part of the syntax of `8print' expressions.} Ordinarily, while
143 // generating program code, \emph{whitespace separations} in the
144 // output are insignificant, and it doesn't matter that heading and
145 // trailing whitespace is implicitly removed from the output, but in
146 // this case we'd like to have a space after each comma. The
147 // `8print' form can actually be used to output arbitrary sequences
148 // of preprocessing tokens, including unbalanced parentheses using
149 // the syntactic forms `8lparen' and `8rparen' that output a left
150 // and a right paren, respectively.
152 // To execute the above `8print' expression for all numbers from 99
153 // to 1 we can wrap it in an anonymous function and use the
154 // \emph{higher-order} function `8for_each_in_range', conveniently
155 // provided by the Order prelude, to make the function applications:
159 8print(8ap(8B
, 8N
) (of beer on the wall
,) 8space
161 8ap(8B
, 8dec(8N
)) (of beer on the wall
.))),
164 // You may wonder about the above upper bound of 100.
165 // `8for_each_in_range' always considers the upper bound open and
166 // the lower bound closed regardless of the direction, ascending or
167 // descending, in which the range is specified. This minimizes
170 // To complete the program, we use a `8let' expression to bind the
171 // auxiliary function to `8B', include the Order interpreter header,
172 // and invoke the Order interpreter using the `ORDER_PP' macro:
174 #include "order/interpreter.h"
178 8cond((8greater(8N
, 1),
179 8separate(8N
, 8quote(bottles
)))
183 8quote(no more bottles
))))),
186 8print(8ap(8B
, 8N
) (of beer on the wall
,) 8space
187 8ap(8B
, 8N
) (of beer
,) 8space
188 (take one down
, pass it around
,) 8space
189 8ap(8B
, 8dec(8N
)) (of beer on the wall
.))),
192 // The above program, when preprocessed, generates some 2773 tokens
193 // on one line containing the desired lyrics. As you can see, we
194 // didn't need to define any macros to generate the desired output.
195 // In fact, the Order intepreter is complete in the sense that it
196 // can \emph{theoretically} generate any finite sequence of
197 // preprocessing tokens without requiring the definition of
198 // additional macros. In practice, however, it usually makes sense
199 // to use additional macros in the form of \emph{ad hoc code
200 // generation macros} and Order \emph{top-level definitions} to
201 // both simplify and optimize a generator. Let's see how to do it.
203 // First we'll write an ad hoc macro for generating one phrase of
206 #define GEN_phrase(N_bottles, N_minus_1_bottles) \
207 N_bottles of beer on the wall, \
208 N_bottles of beer, take one down, pass it around, \
209 N_minus_1_bottles of beer on the wall.
211 // The above function-like macro, named `GEN_phrase', takes two
212 // arguments, `N_bottles' and `N_minus_1_bottles', and expands to a
213 // single phrase of the song. The idea is to use the above macro to
214 // generate all the phrases of the song by outputing a sequence of
215 // 99 macro invocations. In general, a viable design heuristic is to
216 // completely parameterize any ad hoc code generation macro and then
217 // use the Order interpreter to implement any non-trivial logic to
218 // compute the parameters. This minimizes the need to implement
219 // complex logic using only the low-level macro mechanism.
221 // To compute the arguments to the `GEN_phrase' macro, we give a
222 // top-level definition, named `8bottles', for the previously used
223 // auxiliary function for referring to the number of bottles:
225 #define ORDER_PP_DEF_8bottles \
226 ORDER_PP_FN(8fn(8N, \
227 8cond((8greater(8N, 1), \
228 8separate(8N, 8quote(bottles))) \
232 8quote(no more bottles)))))
234 // The above object-like macro definition is an Order top-level
235 // definition. Order top-level definition macros use the prefix
236 // `ORDER_PP_DEF_', which makes accidental macro replacement
237 // unlikely and allows the Order interpreter to deconstruct
238 // expressions using concatenation. The `ORDER_PP_FN' tagging macro
239 // effectively tells the Order interpreter that `8bottles' defines a
240 // function. Order also has other forms of top-level definitions
241 // such as constant and macro definitions.
243 // To actually output an invocation of the `GEN_phrase' macro, we
244 // use the `8emit' procedure:
246 8emit(8quote(GEN_phrase
),
250 // Given two arguments, the `8emit' procedure outputs both of the
251 // arguments separated by a space. Above, `8emit' is used to output
252 // the identifier of a function-like macro and a tuple\footnote{In
253 // Order, a tuple is a parenthesized and comma separated list of
254 // elements.} that matches the formal parameters of the
255 // function-like macro `GEN_phrase'. As one could expect, it will
256 // eventually result in expanding the function-like macro generating
257 // one phrase of the song.
259 // The complete program now looks like this:
261 #include "order/interpreter.h"
263 #define GEN_phrase(N_bottles, N_minus_1_bottles) \
264 N_bottles of beer on the wall, \
265 N_bottles of beer, take one down, pass it around, \
266 N_minus_1_bottles of beer on the wall.
268 #define ORDER_PP_DEF_8bottles \
269 ORDER_PP_FN(8fn(8N, \
270 8cond((8greater(8N, 1), \
271 8separate(8N, 8quote(bottles))) \
275 8quote(no more bottles)))))
277 ORDER_PP(8for_each_in_range
279 8emit(8quote(GEN_phrase
),
281 8bottles(8dec(8N
))))),
286 // Depending on the preprocessor, the above program can be
287 // preprocessed significantly faster than the previous program using
288 // `8print'. This is because the state of the program being
289 // evaluated is smaller and the program performs fewer steps. The C
290 // preprocessor has some interesting performance characteristics,
291 // which we will investigate later.
293 // All that is left to do is to preprocess this example, direct the
294 // output to the printer, get 99 bottles of beer and a few friends
295 // to sing the song\ldots{} On second thought, you could also just