NAME

expander - a Perl module to perform macro expansions in ascii-files

SYNOPSIS

use expander;
undef $/;

my $st= <>;

parse_scalar($st,%options);

DESCRIPTION

Preface

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.

Basic concepts

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

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 !

expressions

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

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.

line concatenation

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.

forced linefeed

A "\n" is always replaced with a line-feed.

escapes
variable escapes

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.

line concatenation escape

A line ending with "\\" is not concatenated with the next line but "\\" is replaced with "\".

linefeed escape

A "\\n" is not replaced with a linefeed but with "\n".

The following keywords are recognized:

set
$set(<expression>)

The expression is evaluated, but the result is not printed.

eval
$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
$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
$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
$if (<expression>)

The expression is evaluated. It it is logical true, the following part is further parsed until $else or $endif is encountered.

else
$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
$endif

This finishes an if-statement.

write_to
$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
$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
$include(<expression>)

This command includes and parses the file specified by <expression>

comment
$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
$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
$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
$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
$begin

This statement opens a new block. All variable definitions and changes within a block are reversed when the block ends with $end

end
$end

This statement ends a block. All variable definitions are restored to the state they had before the block started.

export
$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
$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
$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
$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
$loud

This switches back from silent-mode to the normal mode of operation.

leave
$leave

This immediately leaves the parse-function producing no more output.

lineno
$lineno

This prints the current line-number in the source file.

column
$column

This prints the current column in the source file.

debug
$debug(<text>)

This statement emits arbitrary text to STDERR.

dumphash
$dumphash

This dumps the internal hash %m that is used to hold all defined variables. This is only useful for debugging.

ifstack
$ifstack

This dumps the internal if-stack that is used to track if-else-endif blocks. This is only useful for debugging.

The option hash

parse_scalar and parse_file take an option-hash as optional second parameter. For this hash the following keys are defined:

errmsg
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.

scalarref
parse_scalar($myvar, scalarref=>\$result)

If this hash key is provided, the output written (appended) to the given scalar variable.

filehandle
parse_scalar($myvar, filehandle=>\*MYFILE)

If this hash key is provided, the output is printed to the given filehandle.

filename
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.

callback
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.

silent
parse_scalar($myvar, silent=> 1)

With this option, the parser can be started in "silent" mode. See also description of the $silent command.

includepaths
parse_scalar($myvar, includepaths=> [$dir1,$dir2])

With this option, search-paths for the $include() command can be specified.

allow_not_defined_vars
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.

forbit_nobrackets
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.

roundbrackets
parse_scalar($myvar, roundbrackets=> 1)

With this option, the parser allows round brackets for variables, so $(myvar) is treated like ${myvar}.

recursive
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.

no_escaped_at_chars
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.

Implemented Functions:

AUTHOR

Goetz Pfeiffer, Goetz.Pfeiffer@helmholtz-berlin.de

SEE ALSO

perl-documentation