REBOL/SDK - Preprocessor
Return to Contents
Contents:
1. Overview
1.1 Part of Encap
1.2 Preprocessor Source Code
1.3 Changes in 2.0
2. Running the Preprocessor Separately
3. Preprocessor Commands
3.1 Include Commands
3.2 Including Groups of Files
3.3 Include File Headers
3.4 Evaluation Commands
3.5 Conditional Includes
4. Example Usage
5. Hint for Creating Module Namespaces
6. Including Scripts Not to be Preprocessed
1. Overview
This tool allows you to combine multiple source or data files
into a single REBOL output file.
The preprocessor includes the full power of REBOL, allowing you
to evaluate any REBOL expression during processing. The program
allows merging of code, data, images, sound and other types of
files into a single output file. It also supports conditional
expressions, such as the conditional including of files.
The output is a reduced REBOL source file with extra spacing,
comments, and include file headers removed. Processing is
recursive, so included files can themselves contain commands to
process. This is very powerful.
1.1 Part of Encap
The preprocessor is now part of REBOL/Encap. Source files provided
as input to Encap will be preprocessed.
The preprocessor can also be run independently of Encap using
any recent version of REBOL. See the instructions below.
1.2 Preprocessor Source Code
The preprocessor source code is provided as part of the SDK
distribution. It includes two files:
prerebol.r - command line and interactive interfaces
prebol.r - main functions of the preprocessor
|
Under the conditions of the SDK license, any bug fixes or
modifications must be sent to REBOL Technologies (to let other
developers to take advantage of the changes).
Before adding any additional #commands to the preprocessor,
please be certain that the #DO command does not already easily
provide the same capability. We believe that it is unlikely
that such command additions are needed, but if you think so,
please contact us.
1.3 Changes in 2.0
The 2.0 version is a complete rewrite of the REBOL preprocessor
and is now smaller, faster, and adds a few new features.
2. Running the Preprocessor Separately
The preprocessor is normally run as part of REBOL/Encap
processing. No separate steps are required. However, if for
testing purposes you want to run the preprocessor separately,
the commands below will do so by calling a separate preprocessor
interface file:
From a shell command line or an icon shortcut link:
rebol -s prerebol.r input.r output.r
|
From the REBOL console or a REBOL script:
do/args %prerebol.r [%input.r %output.r]
|
3. Preprocessor Commands
All preprocessor commands begin with a # character. The
commands can appear anywhere within REBOL blocks (but not within
strings), and are not restricted to the beginning of a line. In
fact, commands can be part of expressions (see examples below).
3.1 Include Commands
The include commands are:
#include %file.r | (file-expr)
#include-string %file.txt | (file-expr)
#include-binary %file.bin | (file-expr)
#include-files %path [%file1 %file2 %file3]
|
The (file-expr) can be any valid REBOL expression that returns
a filename. For example you can write:
#include (rejoin [%file version ".r"])
|
An include file may itself contain #include commands. When this
occurs, the include files are processed relative to the
directory location of the parent include file. This is the
behavior you would expect in a preprocessor.
For example, if you include the file with the line:
#include %graphics/defines.r
|
and defines.r has:
#include %draw.r
#include %render.r
#include-binary %image1.jpg
|
all of the include files specified in defines.r are opened in
the %graphics directory.
3.2 Including Groups of Files
The #include-files command requires additional explanation. This
command returns a block of paired values: the input you provided
(a word or filename) and its contents. This lets you write
expressions such as:
foreach [word data] #include-files %graphics [
header.png
backdrop.png
button.png
arrow.png
][
set word load data
]
view layout [
image backdrop.png
btn button.png [...]
]
|
This example will create an output file that contains the
necessary images, then at run-time loads them and sets them to a
word which is identical to their file names. This technique is
useful if you require a lot of images or sounds in your program.
Note that in the VIEW LAYOUT a percent does not appear before
backdrop.png because it is actually a word (a variable) that
holds the image to be viewed.
3.3 Include File Headers
As part of preprocessing all include files will have their REBOL
headers removed. However, the main file provided to the
preprocessor will keep it's REBOL header.
For example, if your main file is:
REBOL [Title: "Main Program"]
#include %draw.r
...
|
and draw.r has:
REBOL [Title: "Drawing Functions"]
draw-box: func [...]
|
The output file will become:
REBOL [Title: "Main Program"]
draw-box: func [...]
|
This feature lets you keep your REBOL include files properly
documented with headers (for identification, version control,
authorship, etc.), but produce an optimal output file when
preprocessed. It also lets you join together multiple include
files without intervening data (such as when you want to
concatenate several smaller files into a large table in the
output file. You don't want the REBOL header being part of
the resulting table).
3.4 Evaluation Commands
The evaluation commands let you execute any REBOL expression as
part of preprocessing. They can be used to process include files
in more detail (like building tables, etc.), dynamically create
version numbers, auto-configure the output file, print status
information during preprocessing, and much more.
The evaluation commands also eliminate the need for other types
of preprocessor commands and allows an unlimited variety of
expressions and results to be processed.
The evaluation commands are:
#do [expr]
#if [expr] [then-block]
#either [expr] [then-block] [else-block]
|
The #do, #if, and #either commands let you execute any
REBOL expression within the preprocessor.
In the case of #do the result of the expression will
be placed in the output file. For example:
version: #do [1.2.3 + 0.0.1]
|
will create the output:
If you do not want the result of #do in the output file,
return NONE.
#do [vers: 1.2.3 + 0.0.1 none]
|
The expression returns NONE, so nothing will be insert into the
output. In addition, if you use an expression that returns
nothing (such as print) nothing will be added to the output:
#do [print ["Version:" version]]
#do [start: time/precise none]
...
#do [write %elapsed-time difference time/precise start]
|
The #if and #either commands will put the results of their
blocks into the output file. For example:
version: #if [new-version] [2.3.4] [1.2.3]
|
will result in:
if new-version is TRUE, or
if new-version is false.
If you use an evaluation command and you need to insert a NONE
as the result, you must return the word NONE, not the NONE
value. For example:
colors: #do [either block? data [data]['none]]
|
This line would insert a block of data or the word NONE.
3.5 Conditional Includes
You can conditionally include files by using both the evaluation
and include commands together. For example:
#if [flag] [
#include %file1.r
#include %file2.r
]
|
If FLAG is TRUE, then the block with the two include commands
will be included in the output, and they will be processed
(recursively).
Be sure to note the difference between the above expression
and this one:
if flag [
#include %file1.r
#include %file2.r
]
|
The first example only includes file1 and file2 if the flag is
set. The second will always include file1 and file2 in
the program but will only evaluate their contents if the flag is
set.
4. Example Usage
Here is an example program:
Include a couple source files:
#include %library.r
#include %actions.r
|
Compute a version number, print it during preprocessing,
save it to a file, and include the version as part of the
output file:
version: #do [
vers: load %version.r
vers: vers + 0.0.1
print ["Version:" vers]
save %version.r vers
vers
]
|
Set a flag to check later during preprocessing:
Conditionally include two files if the BIG-VERSION option
has been set.
#if [big-version] [
#include %special.r
#include %features.r
]
|
Include a file, but only if it exists:
#if [exists? %extra.r] [#include %extra.r]
|
Include one file or another, based on a condition:
#either [now/time > 12:00] [
#include %afternoon.r
][
#include %beforenoon.r
]
|
Include a string as text within the program:
text: #include-string %text.txt
|
Include a large string as compressed text within the program,
and decompress it when the program runs:
text: decompress #do [compress read %text.txt]
|
Include an image file as binary. Keep the image in its
compressed format until the program is executed:
image: load #include-binary %image.jpg
|
5. Hint for Creating Module Namespaces
If you use the preprocessor to combine a set of source code
files, you can use REBOL objects to create separate namespaces
for module-local variables. This is easily done by creating
module files that have a format such as:
REBOL [Title: "Graphics Module" Version: 1.0.0]
graphics-module: context [
data: ["Example" 123]
local-func: func [arg] [
...
]
set 'global-func func [arg] [
...
]
window: layout [
...
]
]
|
When the CONTEXT function is encountered it will be evaluated
and its contents initialized (variables and functions set,
expressions evaluated, etc.) As with any object, variables that
are set within the block (with word: syntax) will only be local
to that module.
If you need to delay the module's initialization (for example if
it needs variables that are not yet defined or uses a file in a
directory that has not been set), you can accomplish this with:
graphics-module: [
data: ["Example" 123]
local-func: func [arg] [ ... ]
set 'global-func func [arg] [... ]
window: layout [ ... ]
]
init-graphics: does [
graphics-module: context graphics-module
]
|
Within your main program, call the init-graphics function:
REBOL [Title: "Main Program"]
#include %graphics.r
#include %otherstuff.r
init-graphics
|
6. Including Scripts Not to be Preprocessed
On some occassions, you may need to include a script that contains
preprocessor commands that you do not want processed. That can
be done with a line such as:
do #include-string %script.r
|
This will embed the script as a text string within your program,
then load and evaluate the script upon execution.
This is in fact how we include the REBOL preprocessor within our
Encap products to prevent it's #include values from being
processed.
Also, if within your script you need to refer to an issue datatype
that is the same as those used by the preprocessor, you can use
code such as:
if value = to-issue "include" [...]
|
to keep the preprocessor from evaluating it.
| | REBOL/MakeDoc 2.0 | REBOL is a registered trademark of REBOL Technologies Copyright 2003 REBOL Technologies | 5-Aug-2003 |
|