expander - a Perl module to perform macro expansions in ascii-files
use expander;
undef $/;
my $st= <>;
parse_scalar($st,%options);
This package provides functions in order to perform macro substitutions in ascii files. Aside from simple substitution, the calculation of complex expressions is also possible.
The module provides two parse-functions that take either a scalar variable that contains a reference to the text or the filename of the file that contains the text to parse.
Both functions scan for variables, expressions or keywords in the text. If one of these is encountered, the text printed is altered. Otherwise the input-text is printed unchanged.
Variables have the following form:
${name}
${name[index]}
or
$name
$name[index]
The first two lines above show simple variables. A variable of this type can hold numbers or strings. The third and fourth lines show the array form. In this case the variable is an array of values, each value can be accessed by an index. The index can be a number or a perl expression. Note however, that the perl expression MUST not contain the closing bracket ']'.
CAUTION: In opposition to ordinary perl-programs, scalar and array variables are in the same namespace. You cannot have for example a variable $var and @var at the same time !
An expression consists of variables and operators or functions. Almost all expressions that are valid in perl can be used. For example this expression defines and sets a variable
$myvar=1
This expression does a simple calculation:
$myvar*2
This expression initializes an array:
@my_array=("X", "Y", "Z")
Keywords always start with a dollar sign. They may be followed by an expression that is enclosed in brackets. Examples:
$if (<expression>)
$else
$endif
In this case, $if is followed by an expression, $else and $endif aren't.
A single \ at the end of a line concatenates this line with the next one. This technique can be used in order to avoid unwanted empty lines in the output.
A "\n" is always replaced with a line-feed.
If the dollar sign is preceeded by a backslash, the following sequence is not interpreted as a variable or keyword. The backslash, however, is removed. So
\$myvar
expands to $myvar.
The same applies to the "@" sign:
\@myvar
expands to @myvar.
A line ending with "\\" is not concatenated with the next line but "\\" is replaced with "\".
A "\\n" is not replaced with a linefeed but with "\n".
$set(<expression>)
The expression is evaluated, but the result is not printed.
$eval(<expression>)
The expression is evaluated and the result is printed. Note that is can also be used to calculate the name of a variable and expand it:
${$eval(<expression>)}
$perl(<statements>)
The given statements are evaluated directly by the perl-interpreter. This is a significant difference to $set or $eval since with these certain replacements are done in the given expression before it is evaluated. This can be used to include perl-modules
$perl(require modulename;)
or to define functions
$perl(sub myfunc { print "$_[0]\n"; })
Note that variables of expander cannot be used here, since they are represented internally in a perl-hash. In principle you could access the variables here by directly accessing the hash, but that would not be portable and bad style. If you define new functions here, the functions should take parameters instead of trying to access the expander-variables directly.
Note that is can also be used to calculate the name of a variable and expand it:
${$perl(<expression>)}
$func(myfunc { my($a,$b)= @; return($a+$b); })
This is a definition of a function. It is actually a shortcut for $perl(myfunc { my($a,$b)= @; return($a+$b); }). The advantage of this construct is, however, that such a function is evaluated without the need to use $eval(). Whenever "$myfunc(..)" is found in the source, it is evaluated, e.g. "$myfunc(1,2)" would return "3" in the example above. Note that the real function name (when called from within a $perl() statement) is prepended with "m_". This is in order to separate user-defined functions from the functions already defined in this module.
$if (<expression>)
The expression is evaluated. It it is logical true, the following part is further parsed until $else or $endif is encountered.
$else
This belongs to an $if statement before. It the if-expression was true, everything between else and endif is ignored. If the if-expression was false, everything between if and else was ignored, everything between else and endif is parsed.
$endif
This finishes an if-statement.
$write_to(<expression>)
This command opens a file with the name of the given expression and writes expander's output from now on to that file.
$append_to(<expression>)
This command opens a file with the name of the given expression in append mode and writes expander's output from now on to that file.
$include(<expression>)
This command includes and parses the file specified by <expression>
$comment(<comment>)
Everything between the brackets is ignored. Note however, that bracket-pairs (round, square and curly) within the comment must be matching, nested pairs.
$for(<init expression>;<condition>;<loop statement>)
This starts a loop very similar to the loop in c or perl. The text between for end endfor is printed several times. The init and loop-expression can be used to count a counter-variable up or down. The for-block implicitly contains a $begin statement so all variable definitions within $for..$endfor are local to this block. This is also the case for the variable defined and used in the init-expression, condition and loop-statement.
Here is an example:
$for($i=0; $i<5; $i++)
NAME= "Axle$i"
$endfor
Here is another example with arrays:
$set(@chars=qw(X Y Z))
$for($i=0; $i<@a; $i++)
NAME= "element: $chars[$i]"
$endfor
$for_noblock(<init expression>;<condition>;<loop statement>)
This command is similar to $for except that it doesn not implicitly start a new $begin-$end block.
$endfor
This ends a for-expression. This statement contains also an implicit $end which ends restores all variables to the state they had before the block started.
$begin
This statement opens a new block. All variable definitions and changes within a block are reversed when the block ends with $end
$end
This statement ends a block. All variable definitions are restored to the state they had before the block started.
$export($var1,$var2)
This statement can be used within a block (see $begin). It exports the local variables (given as a comma-separated list) to the variable-setting outside the block.
$list(10,",")
Prints a list of all defined variables in the form of key=value pairs. The first parameter is the width of the key column, the second parameter is the separator string that separates each key-value pair.
$list_new(10,",",$var1,$var2)
This command is similar to $list except that it prints only variables that have been new defined in the current block (see $begin and $end). The parameters after the 2nd parameter are an optional list of variables, which will also be printed although they were already defined in the previous block. This is useful, when the current block has re-defined a variable that already existed, and this variable shall be printed, too.
$silent
This option changes to mode to silent-mode. In this mode, spaces and line-feeds are not printed. This mode is useful if large parts of the input only consist of variable definitions. Usually, each empty line that is often used to separate definitions, would be printed.
$loud
This switches back from silent-mode to the normal mode of operation.
$leave
This immediately leaves the parse-function producing no more output.
$lineno
This prints the current line-number in the source file.
$column
This prints the current column in the source file.
$debug(<text>)
This statement emits arbitrary text to STDERR.
$dumphash
This dumps the internal hash %m that is used to hold all defined variables. This is only useful for debugging.
$ifstack
This dumps the internal if-stack that is used to track if-else-endif blocks. This is only useful for debugging.
parse_scalar and parse_file take an option-hash as optional second parameter. For this hash the following keys are defined:
parse_scalar($myvar, errmsg=> "my_message")
In case of a fatal parse error, this message is printed just before the error message of the module.
parse_scalar($myvar, scalarref=>\$result)
If this hash key is provided, the output written (appended) to the given scalar variable.
parse_scalar($myvar, filehandle=>\*MYFILE)
If this hash key is provided, the output is printed to the given filehandle.
parse_scalar($myvar, filename=>"output.txt")
If this hash key is provided, a file with the given name is created and the output is printed to that file. If neither "filehandle" nor "filename" is given, all ouput is printed to STDOUT.
parse_scalar($myvar, callback=> \&mycallback)
With this option, a user-defined callback function is defined that is called every time a variable is to be expanded. The callback function is given the name of the variable and (optional) the array-index. If the variable does not yet exist, the callback function must take care of setting this variable with set_var(), otherwise a run-time error is raised.
parse_scalar($myvar, silent=> 1)
With this option, the parser can be started in "silent" mode. See also description of the $silent command.
parse_scalar($myvar, includepaths=> [$dir1,$dir2])
With this option, search-paths for the $include() command can be specified.
parse_scalar($myvar, allow_not_defined_vars=> 1)
With this option, variables that are not defined just produce a warning and do not terminate the program.
parse_scalar($myvar, forbit_nobrackets=> 1)
With this option, the parser ignores (does not expand) variables of the form $var or $var[index]. Only the bracketed variants lile ${var} of (see below) $(var) and their index variants are allowed.
parse_scalar($myvar, roundbrackets=> 1)
With this option, the parser allows round brackets for variables, so $(myvar) is treated like ${myvar}.
parse_scalar($myvar, recursive=> 1)
Allow recursive variable expansion. Each variable that contains a non-quoted '$' sign is evaluated again until that condition is no longer true.
parse_scalar($myvar, no_escaped_at_chars=> 1)
When this option is not set, "\@" is changed to "@", so the at-character may be escaped. If this option is set, the expander module is backwards compatible and leaves these strings unchanged.
parse_scalar()
parse_scalar($st,%options)
This function parses a (multi-line) scalar and prints the results. See also the description of the option-hash further up.
parse_file()
parse_file($filename,%options)
This function parses given file and prints the results. See also the description of the option-hash further up.
get_var()
get_var($varname)
get_var($varname,$index)
This function returns the value of the internal variable with the name $varname. If $index is given, an index-variable is assumed.
testget_var()
testget_var($varname)
testget_var($varname,$index)
This function returns the value of the internal variable with the name $varname. If $index is given, an index-variable is assumed. If the variable does not exist, this function returns <undef>.
set_var()
set_var($varname,$value)
set_var($varname,$index,$value)
This function sets the value of the internal variable with the name $varname. If $index is given, an index-variable is assumed. Note that the 2nd example, using this function to set and index-variable is depricated. Use the new function set_indexvar() (see below) instead. The problem is, that set_var($varname,$index,undef)
kind of destroys the internal index variable while calling set_indexvar($varname,$index,undef)
works without problems.
set_indexvar()
set_indexvar($varname,$index,$value)
This function sets the value of the internal index-variable with the name $varname.
test_var()
test_var($varname,$index)
This function returns 1 if the variable (and optional with this index) is defined, otherwise it returns undef.
declare_func()
declare_func($identifier,$funcname)
Declare (make known) a function to the parser. $identifier is the name of the function in the parsed text, $funcname is the perl-name of the function that is called. The function declared this way works similar to a function defined with "$func" in the text.
lineno()
lineno()
Returns the current line number in the input file, starting with 1 for the first line. This function may be convenient to call or use from within user-defined functions (see $func statement).
column()
column()
Returns the current column number in the input file, starting with 0 for the first character in a line. This function may be convenient to call or use from within user-defined functions (see $func statement).
Goetz Pfeiffer, Goetz.Pfeiffer@helmholtz-berlin.de
perl-documentation