prev | next | contents


Part X: THE PREPROCESSOR

   OpenEuphoria has an integrated preprocessor which handles all aspects in the language that concern text maniplation only. The avanages of using a separate piece pof software to do the processing are:

1 Macros.

   Macros are parametrized text. When some text in the source file is almost repetitive up to a few places, it is natural to think of making the text into a routine. This routine is then called using the changing parts are the parameters of each call.

   In order to handle the chaning parts better, macros use a limited subset of OpenEuphoria statements in order to have a slightly more sophisticated text processing.

   As a first very simple example, assume the following is a quite customay piece of code:

	function get_thewhatever(integer i)
	return someSequence[i]
	end function
with various instances of whatever and someSequence. It seem quite intuitive then to define a macro that takes only the two variable parts and generates all the text above. We will learn how to do so, but suffice to say that it is enough to:
  1. Define a macro as follows:
    	%macro defgetThe(fname,rtseq)
    	function get_the%fname(integer i)
    	return %rtseq[i]
    	end function
    	%mend
    
    Don't worry for the parentheses, they will get explained later.
  2. Whenever the code snippet comes again, just issue %getThe(whatever,someSequence) and the text of the example will be generated. As the opportunitties to use the macro increase, you spare some more typing, eye strain and time.

   Note that string undergo a minimal amount of processing only, so perccent signs in strings will not be considered by the preprocessor.

1.1 Macro definition.

   A macro is any text that starts with the keyword %macro and ends with the keyword %mend. More precisely, it goes as follows:

	%macro macroname({parameters})
	... macro body ...
	%mend

   It looks like a routine, except there is no parameter type to be seen. It even looks more like a routine as you cannot start another macro definition inside a macro definition.

1.2 Macro variables and parameters.

   Macro parameters are instances of macro variables, and macro variables are alwys strings. This makes sense as macros are not general-purpose programs, but just text generators. Also, macro variables don't have metadata.

1.2.1 Scope of a variable.

   Each macro has its own scope. On top of this, here is also a global namespace where can exist variable that can be seen by several macros. There are only two sorts of variables: local (private to macro) and global. Maco parameters are always local.

   In order to make variable(s) global, just issue the call

%global {varnam}
and each variable name in the list becomes global.

1.2.2 Declaring and using variables.

   There is no need to declare variables. Variables start their existence as soon as they get a value, which is done by issuing:

%let varname[%][operator]=value
where the optional operator is in the same list as for ordinary OpenEuphoria programming.

   As macro variables are strings, the behaviour of operator is somewhat ambiguous: does it apply to the string or to the quantity represented by the string? The answer is: it depends. Use the optional % to have the operator behave on the string, and use the normal operator to work on the value represented by the string. For example, if %v1 is "253", then

1.2.3 Using a variable.

   The value of a macro variable is plugged into text by preceding it witn a percent sign, as in

return %fixedvalue
where the contents ofthe variable %fixedvalue are substituted for the string "%fixedvalue".

   A problem may appear if the macro variable name is followed by text that could as well be part of the variable name. In this case, you have to enclose the variable name inside parentheses, like in

return tax%(year)final
If the parentheses are not there, the value of %yearfinal will be requested and an error will mos likely occur as that variable probably does not exist.

1.3 Flow control.

   As some pieces of code are made of repetitive, sequential or nearly so, statements, some constructs are available to handle this case.

1.3.1 The %for loop.

   Text depending on asequential value can be swiftly generated as follows:

%for index=start value %to end value [%by increment] %do ... text and macro commands %end for

   index is a macro vriable that mmay or may not be defined beforehand. start value, end value and optionally increment must evaluate to strings representing numbers. If no %by clause is present, increment is assumed to be "1". Each iteration of the %for loop generates text with index evaluated to its current value. Otherwise, the %for loop behaves exactly as the for loop.

   Thus:

%for %ind=%to %maxindex %do control%ind=GenCtrl(%ind+1) %end for
with Mmaxindex being "5" at the first iteration, will generate:
control1=GenCtrl(1)
control2=GenCtrl(2)
control3=GenCtrl(3)
control4=GenCtrl(4)
control5=GenCtrl(5)

1.3.2 The %if block.

   The %if block behaves exactly as an OpenEuphoria if block does:

%if condition %then text [%elsif condition %then text] [%else text] %end if

   If the condition of the %if statement is true, the corresponding text is evaluated and inserted; the text extends until the next %elsif, %else or %end if macro statement of the block. Then the block is exited, and processing resumes right after the %end if closing mark..

   Oterwise, the conditions of optional %elsif branches are evaluated, until ont of them is true or all of them are false. In the former case, the corresponding branch is processed as if it were the original %if statement.

   If no %if or %elsif branch was rtaken, and if there is an %else statement, the text following it is processed.

   Then the block is exited.

1.4 Macro scoping.

   As the same macro could be defined in several places, some areas of code may need to shelter the macro you intend to use from unwanted ambiguity. You do this by using the markers %scope and %end scope. Global macxro variables defined in this scope are not visible outside it, and get undefined when the end marker is reached.

2 Macros and files.

2.1 Using a file as a macro.

   A whole file can be used as a macro, even though the text it contains may or may not contain macro statements. Coding:

%include filenme %({name=value})
Will replace the statement by the contents of the file, parsed as if some macro text with some macro variables %name that are defined in the file only, and have value on entering the file's text..

   Thus, issuing %include the.txt %(n="3",k="1.5") with the file the.txt as follows:

for i=1 to %n do
?power(i,%k)
end for
will insert the following: for i=1 to 3 do ?power(i,1.5) end for

3 Other typing assistance.

3.1 Shorthand used in noonatom manipulation.

3.1.1 Referring to a whole (tail of) snonatom.

   The shorthand [index..] can be used to refer to all elements of a nonatom whose index is at least index. This amounts to omitting the -1 before the closing square bracket.

3.1.2 Rferring to a whoe sequence.

   An entire nonatom can be referred to by the slice [1..-1]. The following shorthands for this are supported:

[1..] [..] []
The preprocessor normalizes all these to [1..-1].

3.1.3 Referring to the end element of a nonatom.

   The higher admissible index for a sequence can be represented as end or $. Both are translated to -1 by the preprocessor.

3.2 Type repetition.

   When several contiguous formal parameters in a routine declaration share the same type, you don't need to repeat the type: the preprocessor remembers the last explicit type and plugs it in when it is missing.

   Thus,

function f(integer i,j,k)
is equivakebt to
function f(integer i,integer j,iinteger k)
Of course, there must be one explicit type in the formal parameter list at least.

prev | next | contents