<?xml version="1.0" encoding="utf-8"?>
<ManualTopic ID="/baanerp/tt/onlinemanual/100031" xml:lang="en">
	<Header>
		<Title xmlns:HTML="http://www.w3.org/TR/REC-html40">To use the preprocessor</Title>
		<Keyword ContextSensitive="No"><Level1>Preprocessor</Level1>
		</Keyword>
	</Header>
	<GeneralSection><List><ListIntro>The compiler bic6.2 for 3GL program scripts has a built in preprocessor which has the following functions:</ListIntro>
			<ListItem>Include files</ListItem>
			<ListItem>Define macros</ListItem>
			<ListItem>1 Variable Macro Arguments</ListItem>
			<ListItem>2 Token Pasting</ListItem>
			<ListItem>Set an identification in the object</ListItem>
			<ListItem>Pragma codes</ListItem>
			<ListItem>Conditional compiling</ListItem>
		</List>
		<Paragraph class="Default">All preprocessor directives starts with a #. A preprocessor directive must be the first word on a source line, possibly with leading spaces or tabs.</Paragraph>
		<GeneralSection><SectionTitle>1. Include Files</SectionTitle>
			<Paragraph class="Default">To include files the following statement is used: #include filename or #include &lt;filename&gt;</Paragraph>
			<Paragraph class="Default">Files included between &lt; and &gt; are searched in the $BSE/include&lt;rel.number&gt; directory. This directory is reserved for system headers and cannot be used for applications.</Paragraph>
			<Paragraph class="Default">Normally the filename between quotes is searched by using the standard file redirection method. Suppose the following entry in $BSE/lib/fd.6.2&lt;package_comb&gt; occurs:</Paragraph>
			<Paragraph class="Default"><Code>ippmmm:/usr/bse/standard6.2</Code>
			</Paragraph>
			<Paragraph class="Default">and there is an include statement like:</Paragraph>
			<Paragraph class="Default">#include ippmmmheader</Paragraph>
			<Paragraph class="Default">The file /usr/bse/standard6.2/ippmmm/immmheader0 is included.</Paragraph>
			<Paragraph class="Default">If a / occurs in the filename, the file is searched using the specified path name.</Paragraph>
			<Paragraph class="Default">When a file is included twice, the second include is ignored.</Paragraph>
			<Paragraph class="Default">Note that the preprocessor only works during compilation of a 3GL source because the standard generator std_gen6.2 does not have a preprocessor pass. So you cannot use 4GL events in an included file.</Paragraph>
		</GeneralSection>
		<GeneralSection><SectionTitle>2. Macro Definition</SectionTitle>
			<Paragraph class="Default">To define macros the following statement can be used:</Paragraph>
			<Paragraph class="Default">#define macroname[(arguments)] macro definition</Paragraph>
			<Paragraph class="Default">macro definition</Paragraph>
			<Paragraph class="Default">To undefine macros the following statement can be used:</Paragraph>
			<Paragraph class="Default"><Code>#undef macroname[(arguments)]</Code>
			</Paragraph>
			<Paragraph class="Default">The macro names in the source are expanded to the macro definition. If a macro definition does not fit on one line, you can continue the definition on the next line(s) using the caret symbol ^ at the beginning of the next line. You can use arguments in the macro.</Paragraph>
			<Paragraph class="Default">Example:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">#define a(x, y, z) 	     for i = x to y 
^                              z() 
^                        and for | The definition 
a(1, 100, func)                  | The invocation </Paragraph>
			</Formula>
			<Paragraph class="Default">Macro definitions with the same name but with different number of arguments are different, like the following example:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">#define x					        definition without arguments 
#define x()					      definition with 0 arguments
#define x(arg1)       definition with 1 argument arg1
#define x(arg1,arg2)  definition with 2 arguments
#define x(...)        definition with ellipsis ... (see below) 

		   </Paragraph>
			</Formula>
			<Paragraph class="Default">Note that there is a difference between a macro without arguments x and a macro with zero arguments x(). In the first case you must use x in the program script and in the second case you must use x() in the program script to call the macro.</Paragraph>
			<Paragraph class="Default">The #undef statement causes the macro definition to be forgotten. The number of arguments in the #undef call must match the number of arguments in the definition.</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default"> #define MAXLENGTH			 1000 
#define INCR 1 
#define INCR(i) i=i+INCR 
..... 
#undef MAXLENGTH 
#define			 INCR 2 | Redefines INCR 
..... 
#undef INCR(i) </Paragraph>
			</Formula>
			<Paragraph class="Default">If you apply #undef to an unknown macro, an error occurs. To be sure that the macro is defined, use the following construction:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">#ifdef INCR        | without arguments 
#undef INCR(i)
#endif |  of #ifdef / #endif calls </Paragraph>
			</Formula>
			<Paragraph class="Default">see <Link href="#5" role="internal">Conditional Compiling)</Link> for a detailed description</Paragraph>
		</GeneralSection>
		<GeneralSection><SectionTitle>2.1. Variable Macro Arguments</SectionTitle>
			<Paragraph class="Default">To define a macro, you can also use the ellipsis notation ( , ... ) to give the macro a varying number of arguments.</Paragraph>
			<Paragraph class="Default">Example:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">#define  fillbuf(buf1, format, ...) buf1 = sprintf$(format,...) 
| macro call string buffer(100) long l_val double d_val fillbuf(buffer,
 %d. %s = %d %5.2f, 1, Value, l_val, d_val) </Paragraph>
			</Formula>
			<Paragraph class="Default">The macro definition can contain a number of arguments, but the ellipsis notation must be the last argument. This notation can be used with functions that also use the ellipsis notation, such as the <Code>sprintf()</Code>, <Code>message()</Code> and <Code>mess()</Code> functions.</Paragraph>
		</GeneralSection>
		<GeneralSection><SectionTitle>2.2. Token Pasting</SectionTitle>
			<Paragraph class="Default">In the macro you can enter a part of a variable as macro argument. The symbol ## is used to distinguish macro arguments and the rest of the macro, but is omitted in the macro call. You can paste more macro arguments together as one identifier. This principle is called token pasting.</Paragraph>
			<Paragraph class="Default">
                                 Example
                              </Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
#define p(x) 			   message("%d", var##x)
#define q(x,y)     message("%d", x##y) 
#define r(x,y,z)		 message("%d", x##y##z)

long var1a, var1b

p(1a)          | becomes: message("%d", var1a)
p(1b)          | becomes: message("%d", var1b) 
q(var, 1a)     | becomes: message("%d", var1a) 
q(var, 1b)     | becomes: message("%d", var1b) 
r(var, 1, a)   | becomes: message("%d", var1a) 
r(var, 1, b)   | becomes: message("%d", var1b) </Paragraph>
			</Formula>
			<Paragraph class="Default">This method is used to reuse parts of source code, where using functions is impossible or difficult to use functions. See also the following example.</Paragraph>
			<Paragraph class="Default"> 
                                 Example
                              </Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
#define VRC(table,v,r,c)
^                  tt##table##.vers = v 
^                  tt##table##.rele = r 
^               	  tt##table##.cust = c 

VRC(adv100, "6.2", "a", "")
VRC(adv200, "6.2", "a", "")
VRC(adv300, "6.2", "a", "") 

</Paragraph>
			</Formula>
			<GeneralSection><SectionTitle>Object Identifications</SectionTitle>
			</GeneralSection>
			<Paragraph class="Default">To set an identification in the object, use the following statement:</Paragraph>
			<Paragraph class="Default"><Code>#ident "@(#)Identification of object"</Code>
			</Paragraph>
			<Paragraph class="Default">Example</Paragraph>
			<Paragraph class="Default"><Code>#ident "@(#)&lt;progname&gt;, YY/MM/DD [HH/MM], version, author"</Code>
			</Paragraph>
			<Paragraph class="Default">A default identification is always placed in the object by the compiler with the following contents:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default"> #ident "@(#)&lt;source name&gt;, YY/MM/DD, [HH/MM],                             
                          From ${logname}"</Paragraph>
			</Formula>
			<Paragraph class="Default">The UNIX <GUIRef href="" role="manual">what</GUIRef> command writes all object lines beginning with '@(#)' on standard output.</Paragraph>
			<Paragraph class="Default">Besides this default identification the programmer can use his own identification which is also placed in the object.</Paragraph>
		</GeneralSection>
		<GeneralSection><SectionTitle>4. Pragma Codes</SectionTitle>
			<Paragraph class="Default">Pragma codes are a kind of compiler options. The following pragma codes can be used:</Paragraph>
			<TABLE border="1" borderstyle="default" space-and-orientation="indented-estimated"><TBODY><TR><TD rowspan="1" colspan="1">#pragma nodebug</TD>
						<TD rowspan="1" colspan="1">Do not show the source while debugging.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma debug</TD>
						<TD rowspan="1" colspan="1">Show the source while debugging.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma nowarnings</TD>
						<TD rowspan="1" colspan="1">Do not give warnings about the source.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma warnings</TD>
						<TD rowspan="1" colspan="1">Give warnings about the source.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma notransactions</TD>
						<TD rowspan="1" colspan="1">The source only contains read actions. There are no transactions in the source. So, it is sufficient to start one database server.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma warning &lt;text&gt;</TD>
						<TD rowspan="1" colspan="1">The programmer generates his own warning. (Warning level 15). See example.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma fatal &lt;text&gt;</TD>
						<TD rowspan="1" colspan="1">The programmer generates his own error.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma sticky</TD>
						<TD rowspan="1" colspan="1">Do not remove the object out of memory when the process ends.</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used &lt;component&gt; &lt;code&gt;</TD>
						<TD rowspan="1" colspan="1">See below.</TD>
					</TR>
				</TBODY>
			</TABLE>
			<Paragraph class="Default">Example:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">  
#pragma warning This is not a fine solution !

| After compilation the following warning appears:
| &lt;Source(line)&gt;: Warning(15): This is not a fine solution !
			 </Paragraph>
			</Formula>
			<Paragraph class="Default">In some cases the where-used list will not be updated automatically. For example, when a session code is entered but not expected.</Paragraph>
			<Paragraph class="Default">For example,</Paragraph>
			<Paragraph class="Default"><Code>message("ttadv2130s000") or bms.send("command", event, "ttaad3100s000", pr.id)</Code>
			</Paragraph>
			<Paragraph class="Default">To put this session code into the where-used list, enter the following command line:</Paragraph>
			<Paragraph class="Default"><Code>#pragma used session ttadv2130s000</Code>
			</Paragraph>
			<Paragraph class="Default">Following is an overall picture of the pragma codes to update the where-used list:</Paragraph>
			<TABLE border="1" borderstyle="default" space-and-orientation="indented-estimated"><TBODY><TR><TD rowspan="1" colspan="1">#pragma used include</TD>
						<TD rowspan="1" colspan="1">&lt;file&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used table</TD>
						<TD rowspan="1" colspan="1">&lt;table code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used field</TD>
						<TD rowspan="1" colspan="1">&lt;field code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used domain</TD>
						<TD rowspan="1" colspan="1">&lt;domain code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used message</TD>
						<TD rowspan="1" colspan="1">&lt;message code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used question</TD>
						<TD rowspan="1" colspan="1">&lt;question code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used session</TD>
						<TD rowspan="1" colspan="1">&lt;session code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used menu</TD>
						<TD rowspan="1" colspan="1">&lt;menu code&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used dll</TD>
						<TD rowspan="1" colspan="1">&lt;dll objectname&gt;</TD>
					</TR>
					<TR><TD rowspan="1" colspan="1">#pragma used chart</TD>
						<TD rowspan="1" colspan="1">&lt;chart code&gt;</TD>
					</TR>
				</TBODY>
			</TABLE>
			<Paragraph class="Default">Usually the where-used list will be updated. In case of functions, the where-used list is updated if the function call contains the string value. (see example)</Paragraph>
			<Paragraph class="Default">
                                 Example
                              </Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
mess("ttadvs0000", 1)  | Where-used list will be updated

str = "ttadvs0000"
mess(str, 1)           | Where-used list will not be updated 

#pragma used message ttadvs0000 </Paragraph>
			</Formula>
			<Paragraph class="Default">Pragma codes can be placed everywhere in the source.</Paragraph>
			<Paragraph class="Default">For instance, you have set the following pragma on top of the source:</Paragraph>
			<Paragraph class="Default"><Code>#pragma nowarnings</Code>
			</Paragraph>
			<Paragraph class="Default">After a number of warnings, you can enter the following pragma:</Paragraph>
			<Paragraph class="Default"><Code>#pragma warnings</Code>
			</Paragraph>
		</GeneralSection>
		<GeneralSection ID="5"><SectionTitle>5. Conditional Compiling</SectionTitle>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
#ifdef &lt;macro&gt;
			 The source after #ifdef up to #else/#elif/#endif will be compiled if
			 &lt;macro&gt; is defined. Otherwise this source is ignored.

#ifndef &lt;macro&gt;
    The source after #ifndef up to #else/#elif/#endif will be
			 compiled if &lt;macro&gt; is not defined. Otherwise this source is ignored.

#if &lt;constant expression&gt;
    The source after #if up to #else/#elif/#endif will
			 be compiled if &lt;constant expression&gt; is TRUE. Otherwise this source is
			 ignored.

#else
    If the condition belonging to #if/#ifdef/#ifndef/#elif is FALSE,
			 the source after #else up to #endif will be compiled. If the condition
			 belonging to #if/#ifdef/#ifndef/#elif is TRUE, the source after #else up to
			 #endif will be ignored.

#elif &lt;constant expression&gt;
    #elif is a
			 combination of #else and #if.

Example 
#if &lt;constant expression&gt; 
     ... 
#else
			 #if &lt;constant expression&gt; 
     ...
#else 
     ... 
#endif 
#endif 

Is equal to: 
#if
			 &lt;constant expression&gt; 
     ... 
#elif &lt;constant expression&gt; 
     ... 
#else 
     ...
			 #endif 


#endif
    To finish a part of the source started with #ifdef/#ifndef/#if
			 
#undef &lt;macro&gt;
    To delete a macro definition, which means that this macro
			 is not known on a next #ifdef call. </Paragraph>
			</Formula>
			<Paragraph class="Default">The &lt;constant expression&gt; in a #if, #elif is a numeric expression. In this expression you can only use macros of long type and operators like +, -, *, /, =, &lt;, &gt;, &lt;=, &gt;=, &lt;&gt;, and, or, not, ?:, ().</Paragraph>
			<Paragraph class="Default">You can use nested #if structures.</Paragraph>
			<Paragraph class="Default">You can define a macro while starting the compiler by using the -D option.</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
    bic6.2 -D&lt;macro&gt;     | no value means default 1 
    bic6.2 -D&lt;macro&gt;=&lt;value&gt;
			 bic6.2 -D&lt;macro&gt;='any token string' </Paragraph>
			</Formula>
			<Paragraph class="Default">These macros can also be used in the #if conditions like the following examples:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
 bic6.2 -DDEBUG -DMYTEST &lt;source&gt; 

|source 
#if DEBUG and MYTEST 
       message(Some debug information) 
       ... 
#endif 
bic6.2 -DCUSTOMER_X -DCUSTOMER_Y &lt;source&gt; 
bic6.2 -DSTANDARD &lt;source&gt; 

#if STANDARD 
       ....
#elif ( CUSTOMER_X and (not CUSTOMER_Y) )
       .... 
#endif 

</Paragraph>
			</Formula>
			<Paragraph class="Default">You can inactivate a file with #ifdef:</Paragraph>
			<Paragraph class="Default">Example:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">

#ifdef OLD 
.... 
.... 
.... 
#endif 
</Paragraph>
			</Formula>
			<Paragraph class="Default">Note that the preprocessor only works during compilation of a 3GL source because the standard generator std_gen6.2 does not have a preprocessor pass. So you cannot use 4GL events in a #if, #ifdef or #ifndef.</Paragraph>
			<Paragraph class="Default">You cannot use a #ifdef statement in an embedded SQL query. So,</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
select * 
#ifdef STANDARD 
    ...
		  from x 
#else 
    ... 
    from y 
#endif 
    where ... 
selectdo 
    ... 
endselect</Paragraph>
			</Formula>
			<Paragraph class="Default">is not allowed, but the following construction is possible:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
#ifdef STANDARD
select * from x where ...
selectdo 
... 
endselect 
#else select * from y where ... 
selectdo
...
endselect
#endif </Paragraph>
			</Formula>
			<Paragraph class="Default">Two keywords are implemented to give debug information in 3GL sources:</Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
__FILE__     : contains the name of the current source
__LINE__     : contains the line number of the current source</Paragraph>
			</Formula>
			<Paragraph class="Default">
                                 Example
                              </Paragraph>
			<Formula space-and-orientation="indented-estimated"><Paragraph class="Default">
message(This is at line %d in the source %s, __LINE__, __FILE__) </Paragraph>
			</Formula>
		</GeneralSection>
	</GeneralSection>
</ManualTopic>
