bmp is a powerful general purpose macro processor that can be used with many languages, e.g. Pascal or C. It was developed as a part of the ZTEX EZ-USB SDK and is used to assemble the firmware for EZ-USB micro controllers.
bmp is also available as a separate package and distributed as Open Source software under GPLv3. It is written in Freepascal and is known to run on Linux and Windows, but should run an every platform that is supported by Freepascal.
The package can be downloaded from
It will contain the source files as well the binaries for Linux and Windows. The binaries are linked statically such that there are no system requirements.
term | Definition |
---|---|
Macro | Code sequence that is replaced by another code sequence. A macro may have parameters. The replacing process is called macro expansion. |
Meta macro | Code sequence for the definition of macros, conditional expansion of code, or control of the macro processor |
The usage of bmp is
bmp [<Options>] [<filename1> [<filename2> ...]] .
<filename1>
, filename2>
, … denote the input files. If none is given, bmp reads from standard input stdin.
The supported options are
Option | Description |
---|---|
-o <filename> | Output file. By default the output is written to standard output stdout. |
-p | Pascal mode (default), equal to -mm "//" -mo "[" -mc "]" -mp "#" |
-c | C mode, equal to -mm "#" -mo "[" -mc "]" -mp "$" -l '#line %2 "%1"' |
-i | Ignore upper/lower case of macros (not for meta macros) |
-l | Line info (default for C mode: '#line %2 "%1"' ). The sequence “%1 ” is replaced by the file name and “%2 ” is replaced by the line number. |
-I <directory> | Include path. May be specified several times. bmp searches for (input) files in that directories. |
-D <symbol> | Define symbol <symbol>. May be specified several times. -D DEFINE_ME is equal to //define[DEFINE_ME]] in Pascal mode |
-mm <string> | Meta macro start string |
-mo <char> | Open bracket |
-mc <char> | Close bracket |
-mp <char> | Parameter character |
-dd | Print all definitions before exiting. This is intended for debug purposes. |
-h | Help |
The syntax of the meta macros depends on four special meta sequences which can be set using the command line parameters -mm
, -mo
, -mc
and -mp
.
The meaning of these meta sequences is explained in the following example:
A typical meta macro in Pascal mode (parameter -p) looks like
//define[REPLACE_ME(][,#1);][By this: #0 #1]
This defines a macro with two parameters. The same macro in C mode (parameter -c) is defined by
#define[REPLACE_ME(][,$1);][By this: $0 $1]
This example contains all four meta sequences:
Description of the meta sequence | Command line parameter | In Pascal mode | In C Mode |
---|---|---|---|
Meta macro start string | -mm | // | # |
Open bracket character | -mo | [ | [ |
Closing bracket character | -mc | ] | ] |
Parameter character | -mp | # | $ |
Each meta macro begins with the meta macro start string at the beginning of a line. If a line begins with meta macro start string the rest of the line is only considered for meta macro expansion. Code and normal macros are skipped.
bmp is able the generate line information. Its syntax is specified using the parameter -l
.
Line information is used to translate line numbers of the output files to line numbers of the input files.
This is required for the backtracing errors in the source code, i.e. in the input files of bmp.
Without these line information errors have to be located in the output of bmp.
Line information is evaluated by the compiler/interpreter which means that the compiler has to support this feature and that the
syntax must be specified correctly using the -l
parameter. The correct setting for most C compilers is -l '#line %2 "%1"'
.
The resulting line information looks like
#line 123,"source.c"
This section will first give an overview about the meta macros. Detailed descriptions can be found below.
In this section the C mode syntax is used for meta macros.
Syntax | Short description |
---|---|
#define[m] | Define symbol m |
#define[m][r] | Define macro m with replacement r |
#define[m][p][r] | Define macro m with parameter list p and replacement r |
#udefine[m] | Revoke last definition of macro or symbol m |
#uadefine[m] | Revoke all definitions of macros and symbol m |
#include[f] | Include file f |
#ifdef[m] / ifndef[m] | Start of conditional expansion if symbol or macro m is defined / not defined |
#ifeq[s1][s2] / #ifneq[s1][s2] | Start of conditional expansion if strings s1 and s2 are equal / not equal |
#else | else statement, i.e. invert the condition of the previous if meta macro |
#endif | End of conditional expansion |
#elifdef[m] / #elifndef[m] | Similar to #else + #ifdef[s] / ifndef[s] (no additional #end is required) |
#elifeq[s1][s2] / #elifndef[s1][s2] | Similar to #else + #ifeq[s1][s2] / ifneq[s1][s2] (no additional #end is required) |
#noexpand[d] | Disable macro expansion until delimiter d is found |
#error[s] | Generates a user defined preprocessor error with the message s |
#warning[s] | Generates a user defined preprocessor warning with the message s |
#disablaeout / #enableout | Suppress / enable the preprocessor output |
#ignorecase / #exactcase | Switch to ignore/match upper/lowercase mode |
#nolf | Suppress the previous linefeed |
#disablelineinfo | Disables line information for the next macro |
This defines the symbol m
. Unlike macros, symbols are not expanded. They are used in combination with #ifdef
/ #ifndef
.
See #ifdef[m] / #ifndef[m]
for a detailed description.
This defines the macro m
. If m
occurs somewhere in the input code, it is replaced by r
. Macros and meta macros in r
are expanded.
If m
occurs in r
, m
is replaced by the previous definition, see the second example below. This allows recursive expansion of macros.
Example 1:
#define[m1][r1] #define[m2][m1] #define[m4][#define[m3][r3]] -- m1 -- m2 -- m3 -- m4 m3 --
is expanded to (bmp -c -l ””
):
-- r1 -- r1 -- m3 -- r3 --
Example of a recursive macro:
-- #define[m1][m1+1] m1 ---- #define[m1][m1+2] m1 -- #define[m1][m1+3] m1 --
is expanded to (bmp -c -l ””
):
-- m1+1 ---- m1+1+2 -- m1+1+2+3 --
This defines the parametrized macro m
with the prameterlist p
. If m
occurs somewhere in the input code, it is replaced by r
which usually depends from the parameters. Macros and meta macros in r
are expanded as in #define[m][r]
.
The syntax of the parameter list is
<d0>[$1<d2>[$2...[$9<d9>[$a<da>...[$z<dz>]...]]...]]
The parts within [
and ]
are optional. <d0>
…<d9>
,<da>
…<dz>
denote delimiters and $0
…$9
,$a
…$z
denote parameters.
A delimter can be any string. The maximum amount of parameters is 27.
If a parameterized macro is found, the input between the end of the macro name m
and first delimiter <d0>
is stored in $0
, the input between
<d0>
and <d1>
is stored in $1, and so on. Note that $0
is not specified in the paramter list p
. In r
the occurrences of $0
, $1
, … are replaced by their contents, i.e. by the argument of the respective parameter.
Example:
#define[m1(][,$1,$2)][Parameter 1: $0 Parameter 2: $1 Parameter 3: $2] #define[Example of ][ a long delimiter $1 an even longer delimiter $2.][$0+$1=$2] -- m1(a,b,c) -- Example of 1 a long delimiter 2 an even longer delimiter 3. --
is expanded to (bmp -c -l ””):
-- Parameter 1: a Parameter 2: b Parameter 3: c -- 1+2=3 --
Example of a recursive macro:
-- #define[m2][1] #define[add(][)][#define[m2][m2+$0]] m2 -- add(2) m2 -- add(3) m2 --
is expanded to (bmp -c -l ””):
-- 1 -- 1+2 -- 1+2+3 --
This meta macro revokes the last definition of a macro or a symbol m
. See also #uadefine[m] which revokes all definitions.
Example:
#define[m1][r1a] #define[m1][r1b] #define[m2] #define[m3][#ifdef[m2] m2 defined #else m2 not defined #endif] -- m1 m3 -- #udefine[m1] #udefine[m2] m1 m3 -- #udefine[m1] m1 --
is expanded to (bmp -c -l ””):
-- r1b m2 defined -- r1a m2 not defined -- m1 --
This meta macro revokes the all definitions of a macro or a symbol m
. See also #udefine[m] which revokes only the last definition.
Example:
#define[m1][r1a] #define[m1][r1b] #define[m2] #define[m3][#ifdef[m2] m2 defined #else m2 not defined #endif] -- m1 m3 -- #uadefine[m1] #uadefine[m2] m1 m3 --
is expanded to (bmp -c -l ””):
-- r1b m2 defined -- m1 m2 not defined --
This meta macro includes the file f
. f
is searched first in the directory of the
current file, and then in the directory given by the -I
parameters.
The structure of if statements is
#if<condition> <code1> #endif
or
#if<condition> <code1> #else <code2> #endif
If the condition (denoted by <condition>
) is true, <code1> is expanded, i.e. the section starting from #if
and ending with #endif
is replaced by <code1>.
In the second version (with #else
) <code2> is expanded if the condition is false. Both, macros and meta macros are expanded in <code1> and <code2>.
Valid conditions are
Condition | Short description |
---|---|
def[m] / ndef[m] | true, if macro m is defined / not defined |
eq[s1][s2] / neq[s1][s2] | true, if strings s1 and s2 are equal / not equal |
Detailed descriptions if the conditions follow below.
Expands (see #if
), if symbol or macro m is defined / not defined.
Example:
#define[m1] #define[m3][r3] -- #ifdef[m1] m2 #else m3 #endif -- #ifdef[m2] m1 #else m3 #endif -- #ifndef[m2] m1 #else m3 #endif --
is expanded to (bmp -c -l “”
):
-- m2 -- r3 -- m1 --
Expands (see #if
), if strings s1
and s2
are equal / not equal.
Macros within s1
/s2
are expanded. Except of #noexpand[d]
, meta macros are not expanded.
Example:
#define[m1][r1] #define[m2(][,$1)][$0+$1] #define[m3][m3] #define[m4(][)][#ifeq[$0][6] equal 6 #else not equal 6 #endif] -- #ifeq[abc][abc] euqal 1 #endif ---- #ifneq[abc][def] not euqal 2 #endif -- #ifeq[m1][r1] equal 3 #endif -- #ifeq[b+m2(a,b)][m2(b,a)+b] equal 4 #endif -- #ifeq[#noexpand[$]m3$][m3] equal 5 #endif -- m4(6) -- m4(7) --
is expanded to (bmp -c -l “”
):
-- euqal 1 ---- not euqal 2 -- equal 3 -- equal 4 -- equal 5 -- equal 6 -- not equal 6 --
#elif<condition>
statements are equal to #else#if<condition>
statements except that not additional #end
is required.
The valid conditons (denoted by <condition>
) are the same as for #if
.
Example:
#ifeq[m1][1] 1 #else #ifeq[m1][2] 2 #else Neither 1 nor 2 #endif #endif
is the same as
#ifeq[m1][1] 1 #elifeq[m1][2] 2 #else Neither 1 nor 2 #endif
Disables the expansion of macros and meta macro up to the delimiter sequence d
.
Example:
#define[m1][r1] #define[m2(][,$1)][$0+$1] #define[m3][m3] -- m1 -- #noexpand[!]m1! --
is expanded to (bmp -c -l “”
):
-- r1 -- m1 --
This meta macro generates a user defined preprocessor error with the message string s
. Neither macros nor meta macros within the string s
are expanded.
bmp exits after the occurrence of #error
.
An example can be found in below
This meta macro generates a user defined preprocessor warning with the message string s
. Neither macros nor meta macros within the string s
are expanded.
Example:
#define[m1][r1] #warning[#noexpand[!]m1! (macros and meta macros in the message string are not expanded)] #error[This is an error message] #error[This error message will never be printed]
is expanded to (bmp -c -l “” tmp.bmp
):
tmp.bmp(2): Warning: #noexpand[!]m1! (macros and meta macros in the message string are no expanded) tmp.bmp(3): Error: This is an error message
These meta macros are be used to skip code. After #disableout
and #enablout
occurs, bmp switches the output on and off, respectively.
Example:
#define[def][#enableout ] #define[stu][ #disableout] #disableout abcdefghijklmnopqrstuvwxyz
is expanded to (bmp -c -l “”
):
ghijklmnopqr
These meta macros switches ignore upper/lower case mode for macros on and off, respectively.
Example:
#define[m1][r1] M1 #ignorecase M1 #exactcase M1
is expanded to (bmp -c -l “”
):
M1 r1 M1
This meta macro is used to suppress a previous linefeed. This is mainly intended to pretty up the output.
Example:
#define[m1][ #nolf r1] #define[m2][ r2] #define[m3][r3] -- m1 -- m2 -- m3 --
is expanded to (bmp -c -l “”
):
-- r1 -- r2 -- r3 --
This meta macro disable line information for the next macro. This can be used to suppress macro-defined comments.
The following symbols are defined by default depending on certain conditions:
Symbol | defined if … |
---|---|
UNIX | Operating system is a Unix (including Linux) |
LINUX | Operating system is Linux |
WINDOWS | Operating system is Windows |