Just Another Macro Language v3.01

. . . . . . . . . . . . . . . . . . . . . . . . for HTML


Table of Contents


Note: this documentation is rather long to fit a normal HTML page. However I made this still a one pager to ease download, local storage and be it at hand. This documentation is linear, in other words, you can read it from start to end, or even print it, and read it in bed, unless you have something more appropriate for the location.

Examples appearing in this text are maintained in separate files included into the final html code using . Whenever the output of some macro is on display it is generated automatically and included into the html text. This was done to assure that the examples and the results do not contain errors.


1. General introduction

is a macro language that reads one or more jam files and generates one output file. The jam files are text files that contain all text content mixed with macros. The macros can be used to eliminate repetitive tasks. To simplify understanding and give a jumpstart here is a very simple HTML example:
Example
jam1.txt
{#define gen=general}\
{@define ref/x/y=<li><a href="#x">y</A><BR>{#define x=y}}\
{@define anchor/x=<hr><a name="x"><h2>{x}</h2></A>}

{ref/{gen}/General introduction}
{ref/def/Defining macros}
{ref/use/Using macros}
{ref/jamac/Built-in macros of {jamal}}

This example is actually from the jam file of this page, and is used to create the table of contents as well as to create the titles. The macro define is a built in macro of and is used to define "user defined" macros. The macros are always enclosed in some parenthesis, which are { and } by default. You can change them to any string, but that is for later. Built-in macros are preceded with a # or @ character, while user defined macros are not. The macro names are always alpha characters, which is a slight restriction. In other words you can not name a macro a1 or my_macro.

To be honest user defined macro names can also contain double colons, but that is only for extensions written in external Perl modules. See details in 18. Writing extension modules in Perl

Macros can be nested. It means that a macro can contain other macros either when it is defined, and also when it is used. Macro nesting has no limit, except physical limitation of memory and time.

Because macros may distort the formatting of the source text containing the macros lets you use new-line characters preceded with back-slash that will not appear in the output file. This lets you type short lines appropriate for your taste and the text editor you use and still have characters on the same line as needed in the output. In short, whenever sees a line having a backslash character at the end it chops off the new-line character before processing anything else.

Macros have two effects. One effect changes the behavior of . Example a {#define ...} macro defines a macro, that remembers and later this macro can be used. The other effect is that each macro results a string that is put into the output text at the place where the macro is in the original text. In some cases this text is empty. Taking the previous example, the built-in macro {#define ...} results an empty string as well as defines a "user-defined" macro. On the other hand the macro {gen} in the example results the text general.

Looking at the example above, the first three lines define three macros. The first is the simplest. This macro defines the user defined macro gen. Whenever later in the code we write {gen} it will be replaced by the text general (unless the macro is undefined or redefined later).

The next two lines define the macros ref and anchor. Both have parameters, and there is another interesting thing that differs from the first macro definition: both macro uses the @ character rather than #. This means that the macros embedded in the definition of the macro are not processed during the evaluation of the macro {#define ...}. In other words, the user-defined macro ref will have the value

  • <li><a href="#x">y</A><BR>{#define x=y}
    If the # were used instead of the @ caracter the value would be
  • <li><a href="#x">y</A><BR>
    The details of this will be discussed in the section 12. Fine points of macro evaluation order. When we call this macro it has several effects. It inserts a table-of-content line into the html code including a link to the anchor, and defines the name of the anchor as a macro containing the title of the section.

    Later in the code we can use the macro anchor giving the anchor name as the argument and it will not only insert the appropriate anchor to the text, but will also insert the section title into the html code. This way we eliminate the double typing of the section titles: they only appear in the code once, and the code therefore is easy to maintain.


    2. Command line format and options

    To use you need Perl 5.0. Under UNIX this is quite usual to have this language interpreter installed. Under Windows NT/2K/XP or Windows95/98/ME I use the interpreter from ActiveState.

    You can start as any other Perl program. The Perl source has the usual UNIX start line #!/usr/bin/perl that helps you to start , but it does not work in case the Perl interpreter is installed in a different directory. Ask for local help.

    From now on I assume that can be started using the command:

    $ jamal
    
    (The $ is the command prompt.) The most important use of is to start it with the command line:
    $ jamal -h
    
    to print out a short help screen. This will print
    jamal html preprocessor V3.01
    Usage:
    .
    jamal [-options] input [output]
    .
    Options:
    -? or -h               help
    -m file                macro definition file
    -D                     macro define
    -I                     j-SEX directory
    -i                     install j-SEX module interactive
    -0                     suppress output
    -d                     put error message into result
    -t file                trace file
    .
    Your default extension directories are:
    D:\Perl\lib\i386-win32
    D:\Perl\lib
    .
    
    This says that you should type the name of the command at the command prompt. This is jamal unless you have renamed it. This can be followed optionally by the options, the input file name and optionally the output file name. If the output file name is missing the result is going to be sent to the standard output.

    In the current implementation there are a few options. The option -m can be used to include macro files before processing the input file. The macros defined in these files are effective when the processing of the input file starts. There can be more than one such macro file specified, and they will be processed by in the order they are specified. The name of the macro file should always be a separate parameter for following the option -m, and should never be written together. Therefore

    $ jamal -m macros.jam input.jam output.htm
    
    will first read the file macros.jam, process the macros and throw away all output that macros.jam might generate. Then input.jam is processed and the output is put into output.html.

    The second option is -D that you can use to define simple macros on the command line. This can ease the use of jam files that are used to generate several output files. Example
    Example
    jam23.jam_
    ....
    The content of the file {includefile}:
    
    {#include {includefile}}
    ....
    
    and the output
    Example
    jam23.out
    ....
    The content of the file jam6.jam:
    
     1*1=1  2*2=4  3*3=9  4*4=16  5*5=25
     6*6=36  7*7=49  8*8=64  9*9=81  10*10=100 
    
    ....
    
    after the file was processed with the command

    jamal -Dincludefile=jam6.jam jam23.jam jam23.out
    
    The macros should be written exactly the same way as they are after the keyword define.

    For description of the command line option I see Using j-SEX.

    You can use the O and d options to ease debugging of erroneous jam files. Using the O option will not send the output to the screen (to stdout to be precise) even if no output file is specified.

    Using the option d inserts some of the error messages into the output. This might result a less usable output for further processing, buteasier to debug the source.

    The option t can be used to create a trace file. A trace file contains full debug output of macro evaluation. (For further information see 17. Trouble shooting macros.)


    3. Defining and using user-defined macros

    Defining and undefining macros is the most common task using . Macro definition can be done using the built-in macro {#define ...} macro. After a macro is defined, it can later be used in the file simply enclosing the name of the macro in braces or strings that are defined to be the macro brace string (See the section 14. Redefining the macro bracket strings).

    The following part is precise, hard to swallow, detailed, almost mathematical definition. Try to eat it, but don't panic if you can't: there are easy examples at the end of the section.

    The syntax of define is:

                     {#define name/par1/par2/.../parn/=text}
                     {#define? name/par1/par2/.../parn/=text}
    
    The macro keyword is define. This is followed by an optional question mark. This is followed by one or more spaces followed by the name of the macro name. These spaces are optional if the question mark is present. The macro name can only contain alpha characters from the English alphabet. The names just as anywhere in are case sensitive. Macro, define, Define are all valid, and different macro names. On the other hand Macro2, my_macro are not valid macro names, as they contain non-alpha characters, namely 2 and underscore.

    To be precise macro names can also contain double colons, but that is solely for extensions written in Perl. See 18. Writing extension modules in Perl for further details.

    The name of the macro is followed by the formal parameters of the macro. This part is optional. If there is any non-space character between the name of the macro and the equal = sign then it is treated as formal parameters of the macro.

    The formal parameters are followed by an equal sign and the text of the macro follows.

    The list of the formal parameters has the form:

                     /par1/par2/.../parn
    
    The very first character of the parameter list is taken as formal argument separator. In other words this need not be the slash / character. This can be any character. The list of the formal parameters is created taking into account this character as separator. The separator character can, but need not appear after the last formal parameter. Also, when using a defined macro the actual parameter list separator character need not be the same as the character that was used during the definition of the macro.

    Generally speaking the list of the formal parameters follow the syntax of parameter list syntax. (See 4. parameter list syntax for more details.)

    When a defined macro is going to be used it only have to be enclosed between braces. Spaces are allowed between the name of the macro and the opening brace, but are not allowed between the name of the macro and the list of the actual parameters. The name is immediately followed by the list of the actual parameters, if such list exists. (Actually if there is any space after the name of the macro it is treated as part of the actual parameter-list, and will play the role of the list separator. See 4. parameter list syntax for more details.)

    The very first character of the list of the actual parameters is the separator character.

    The parameter string is split up to a list of so many members as many formal parameters are needed. This means that the very last parameter may contain the list separator character.

    During evaluation of the macro the formal parameters appearing in the text of the macro are replaced by the actual values of the parameters from left to right.

    Note that the formal parameters can contain any characters, except equal sign, and they can appear anywhere in the text of the macro. They can even appear inside of words, in other words there is no usual lexical analysis of the text, parameters are replaced using usual string search-and-replace method.

    When a formal parameter is replaced by its actual value no further replacement takes place on the replacement result, even if a later formal parameter is matched by part or all of the actual parameter. This means that macro definition usage is safe, and does not depend on the formal parameter name.

    An already defined macro can silently be redefined. When using an undefined macro outputs a warning to the standard error, and the result of the macro is empty string. The processing continues. This is a defined behavior in case you need it intentionally.

    Since version 2.03 you can put a question mark after the opening brace. This will tell that the macro may be undefined and that you are aware of this fact and you do not need a warning. The result of the macro is not altered by the question mark. Spaces are allowed before and after the question mark.

    Let us see a complex example and discuss the above definitions:
    Example
    jam2.jam
    {#define Macro=This is the very first macro}\
    {Macro}
    {#define tt/x=<tt>x</tt>}
    {tt//etc/bin/sh}
    {#define Macro&apple&lemon=applemon apple lemon}
    {Macro  lemon apple}
    
    and the resulting text:
    Example
    jam2.out
    This is the very first macro
    
    <tt>/etc/bin/sh</tt>
    
    lemonmon lemon apple
    
    The fist two lines include a simple example: a macro definition without arguments. The second definition is what I frequently use to ease teletype display of simple words. The formal argument is x and this is replaced by the actual value of the parameter on the fourth line of the example. Note that because the tt macro requires only one argument it can contain the separator character any times. Even in the first character.

    The last macro is the most tricky. This macro has two formal parameters. These parameters are separated by & character. Another tricky point is that the first formal parameter name ends with the letter le just as well as the second argument starts with these characters. Usually such a tricky usage is discouraged, here I use them for the sake of the example only. When the actual values are used to replace the formal parameters the two appearances of apple are replaced to lemon. Now the string is:
    lemonmon lemon lemon
    After this action the appearance of lemon is replaced to apple. However:

    In other words only the last occurrence of lemon is going to be replaced, and the final string is as can be seen in the included output above.

    We have not spoken any word so far about the optional question mark after the macro keyword define. This optional sign can help you avoid macro redefinition. You may want to define a macro unless it is already defined. The example
    Example
    jam25.jam
    {@define a=3}\
    {@if|{?a}||{@define a=4}}\
    {@define? a=5}\
    {a}{?b}
    
    defines the macro a to have the value 3. The second line is a conditional macro that defines a and gives it the value 4 unless a's value is not empty and is defined. The third line defines a and gives it the value 5 unless it is defined. The last line uses the macro a and an undefined macro b.

    The output is
    Example
    jam25.out
    3
    
    You can see that nor the second neither the third line gave a new value to the macro a. The two commands are almost identical and you can use the conditional macro in case you like that, but the third line is more readable.

    You can have spaces between the keyword define and the question mark and you can have spaces between the question mark and the macro identifier. Or you can write them without spaces. However you need something between the keyword and the macro name either question mark or space.

    The use of the macro b results an empty string because this macro was not defined. You can not see on the screen now but believe me (or try to compile the documentation) did not complain about this undefined macro.

    (This feature was developed according to the request of fstafek@noise.cz)


    4. parameter list syntax

    Many times macros have one or more parameters. These parameters usually stand after the name of the macro in the form of a list. This list is actually a string that usually lasts until the end of the macro or until some special closing character like the equal sign in case of the macro define.

    There are such lists for example in the macros

    and these lists are handled exactly the same way. Therefore here we detail how treats these lists and later on we can just say parameter list to refer to a string of the syntax.

    can not work with the string without splitting up the list into members. We could easily say that the list separator character should be comma, or semicolon. However comma, semicolon, or any other character can appear in a list member.

    The solution that follows is that the list separator character should appear before the first list member. In other words: list separator precedes each list member rather than just separating them. looks at the very first character of the string representing the list, and knows that this character is the separator character.

    Therefore you should NOT write
    Example
    jam3.jam
    {#for i/1,2,3,4/a[i]=i;}\
    
    
    because in this case will think that the list separator in 1,2,3,4 is 1 and the list member is the string ",2,3,4" and the result is going to be
    Example
    jam3.out
    a[,2,3,4]=,2,3,4;
    
    Instead you should write
    Example
    jam4.jam
    {#for i/,1,2,3,4/a[i]=i;}\
    
    
    for which the output is exactly what you expect:
    Example
    jam4.out
    a[1]=1;a[2]=2;a[3]=3;a[4]=4;
    

    You can use any character as a list separator character, the only and obvious restriction is that the character should not appear in any list member. (except the trailing one, see later)

    There is also a notable special character: SPACE. When you use space as list separator character you could end up having magical bugs in your code putting double space at some locations and therefore having empty list members without being easily able to recognize it. Therefore treats this as a special case. If the very first character of a list is white space (that is usually the name for the group of characters including space, tab, linefeed, form-feed and alike) then will use one or more consecutive white space characters as list separators.

    New-line character is also a special character. If the first separator character is new-line then the list is separated by new-line characters, in other words the list members are the text lines. Also an empty line means a zero length string being list member, there is no such trick as in the case of other white spaces. On the other hand, if the first separator character is a white-space but new-line then later new-line characters are treated just as other white-space characters: one or more of them separating the list members.

    Using this feature you can write
    Example
    jam5.jam
    {#days Montag Dienstag
        Mittwoch
    Whateverthursdayiscalledingerman
    
       Freytag
    
    Sonntag
    
    Sammstag   }
    
    
    to set the names of the days for your German output.

    When splits up the string into a list it may or may not know a-priori the number of list elements. In case of macro days knows that there are seven arguments and in case of months there are 12. When a macro is used the number of actual parameters is known before splitting up the list: it is the same as the number of formal parameters that the macro was defined. On the other hand, the number of list members in a for loop, or the list of the formal arguments in a macro definition is known only after the string had been split up.

    When the number of list members is known before splitting creates a list with exactly that number of members. If the list needs n parameters then stops after it has found n-1 separators and takes the rest of the string the last member of the list. In other words the last member of the list may contain the separator character, but only when the number of list members is known before splitting.

    The lists, where the number of list members is known before splitting:

    In all other cases the number of list members is based on the number of separator characters in the string, and naturally none of the members can contain the separator character.

    5. Including files

    A strong point of is that it is possible to include files into the code. Using the include macro you can include text into the html code that appears in many web page, but you are still able to maintain a single copy of the text.

    There are several formats of the include macro to help inclusion of verbatim code, verbatim html, macro definitions and commands, text.

    The syntax of include is:

                     {#include type filename}
    
    The type keyword can be The filename parameter is obviously the name of the file. Just in case you are pervert enough wanting to include a file named pre, macro, macros or verbatim you can put before and after the file name a quote " character.

    The file name can be specified as absolute file name or as a relative file name. A file name is treated as absolute file name if it starts with one of the characters /, \, ~ or if it starts with some alpha character and the second character is a colon, like in c:\dos\command.com

    When a relative file name is specified it should be relative to the file that contains the include macro. At first glance it seems to be obvious, but it is notable when we think of included files including other files.

    File inclusion can be nested any level deep assumed that the system has enough memory, speed and file handle to handle the macros. Systems usually have.

    The file inclusion takes place, when the include macro is evaluated.

    When you include a file using the pre modifier, the macro is replaced by the content of the file and all < characters are changed to &lt; as well as all > characters are changed to &gt;. This is the easiest way to include code examples into an html page. This is actually method that is used to include the jam file examples into this page.

    When you include a file using the verbatim modifier, the macro is replaced by the content of the file as the file is. No replacements are done, no macro evaluations are done within the file.

    Using the macro or macros modifier includes the file, processes the macros, even generates the resulting text, but after it replaces the include macro with an empty string and throws the evaluation results. The only effect is that all macro definitions, time, date formatting and other "secondary" effects are alive.

    If you are already ahead a bit, you can notice that the macro modifier is surplus, as the same result can be reached nesting an ordinary include macro into a comment macro. (See details in 12. Fine points of macro evaluation order.) However that construct is not recommended to include macros.

    If the include macro is used without modification the file is included and processed for macros just as if it were typed into the code.


    6. for loop

    Looping macros are fine points of . You can insert repetitive text into html pages. for loop has two formats. One format is to repeat text for consecutive integer numbers, the other format is to repeat text for several textual parameter values.

    The first case has the format like:

                   {#for i/ 1 ... 1000 / a[i]=i; }
    
    the second has the format like:
                   {#for i/,this,that,here,there,kakukk/ a[i]=i;}
    
    In both cases the general syntax is:
                   {#for loopvariable/ loopdefinition / looptext}
    
    The macro keyword is for followed by one or more space. The next element of the syntax is the loop variable, which is a string of alpha characters. This is optionally followed by spaces and the loop definition comes. The loop definition part defines the actual values for the loop variable. The loop definition is enclosed between the terminating characters. In the example above this character is a slash / character, but it can be anything assuming that the chosen character does not appear inside the loop definition.

    When locates the loop definition part it takes the first non-space character after the loop variable and uses this character to locate the end of the loop definition.

    To ease readability characters are paired. for example knows that the pair of the ( character is ), and it knows other characters as well. The exact pairing definition is:

    When finds the first non-space character after the loop variable it takes the pair of the character and uses the pair to locate the end of the loop definition. This finally result a bit more of readability in code, example
    Example
    jam6.jam
    {@for loopV ( 1 ... 10 ) loopV*loopV=\
    {#* loopV loopV}{#if/{#= 5 loopV}/
    / }}
    
    
    resulting
    Example
    jam6.out
     1*1=1  2*2=4  3*3=9  4*4=16  5*5=25
     6*6=36  7*7=49  8*8=64  9*9=81  10*10=100 
    
    
    Going back to the for macro, the example above shows one possibility for the loop definition. This loop definition contains two integer numbers separated by two or three dots. Using two or three dots is just a matter of taste, there is no difference. The loop will go from the first number to the last incrementing or decrementing the value for the loop variable. The values can be positive or negative.

    The other for macro usage uses a parameter list in the loop definition. In this case you can list several values, numerical and textual values, and the loop variable will take all these values. For example
    Example
    jam7.jam
    {@for loopV (/1/2/3/4) loopV+loopV={#+ loopV loopV}}
    
    
    resulting
    Example
    jam7.out
     1+1=2 2+2=4 3+3=6 4+4=8
    
    

    In case you are good at programming, and followed the text carefully up to now, you can recognize that the definition of the macro for is not precise. Looking at the example from above
    Example
    jam6.jam
    {@for loopV ( 1 ... 10 ) loopV*loopV=\
    {#* loopV loopV}{#if/{#= 5 loopV}/
    / }}
    
    
    you can see that this is either a loop from 1 to 10 as well as a loop for three textual values, namely '1', '...' and '10' separated by space.

    The reality is that first tries to interpret the loop definition as a "from ... to" format and in case it fails goes for the second case which is the parameter list of textual values. If I really wanted to have the above loop for the three textual values I could wrote:
    Example
    jam8.jam
    {@for loopV (,1,...,10) loopV*loopV=\
    {#* loopV loopV}{#if/{#= 5 loopV}/
    / }}
    
    resulting
    Example
    jam8.out
     1*1=1  ...*...=0  10*10=100 
    

    The final point of the macro for is the text of the loop. This text is inserted to the output for each loop replacing each occurrence of the loop variable in the text with the actual value. You should be very aware that the loop variable is replaced at every occurrence, not only where it stands at a place where it can be viewed as a variable. Never have a loop variable named i or L or something similar or be prepared to end up debugging why can not process your {#if ...} macro (as I did, when the i from if was replaced to 0, 1, ... in the loop).

    7. select macro

    There are cases when you would like to easily extract a member of a parameter list. Such an example can be a list of week day names both in English and German, like:
    Example
    jam24.jam
    {@for X/,|Monday|Montag,|Tuesday|Dienstag,|Wednesday|Mittwoch/\
    {#select/0/X}
    {#select/1/X}
    }
    
    resulting
    Example
    jam24.out
    Monday
    Montag
    Tuesday
    Dienstag
    Wednesday
    Mittwoch
    
    
    If you think that this example is not the best one, you are right. But in many cases you will soon need the macro select.

    The formal definition of the macro is

            {#select LIST}
    
    where LIST contains two elements. The first element should be a numeric value and the second should itself be a LIST, something like:
            {select/n/LIST}
    
    The value of the macro is the nth element of the LIST. The index starts at zero as in most modern programming languages, in a way as was shown in the example above.

    8. Conditional macros

    Currently there is only one conditional macro implemented in . This is the if macro. The precise syntax of the macro is:
                   {#if/test/text if test is true/text if test is false}
    
    The most precise definition is that the keyword if is followed by a parameter list according to the syntax described in 4. parameter list syntax.

    first evaluates the first element of the list and if this value is true the resulting text of the macro is the second element of the list. If the value is false the resulting string is the third element of the list.

    A very simple example uses this macro to automatically generate a link to the previous chapter in an imagined document:
    Example
    jam16.jam
    {@define prev={#if|{#= {chap} 0}|\
    This is the first chapter|\
    <a href="chapter{#- {chap} 1}">previous chapter</A>}}\
    {#define chap=11}\
    {prev}
    {#define chap=0}\
    {prev}
    
    and the result
    Example
    jam16.out
    <a href="chapter10">previous chapter</A>
    This is the first chapter
    
    You can see that automatically calculated the serial number of the previous chapter and also noticed when there was no previous chapter.


    9. Numerical evaluating macros

    is not a language that you are going to write numerical simulation. However there are macros that support some numerical calculations. The name of these macros is usually a one or two character operation sign followed by the list of arguments. The list follows the parameter list syntax. The operators currently implemented are:

    File operators can be written lower case or upper case. When the lower case form is used the file name is treated as relative to the input file. The upper case letters treat the file name as relative to the output file. Absolute file names can be used with either upper or lower case version.

    A simple example calculates the expression (6+3)*12-5/8:
    Example
    jam17.jam
    {#- {#* {#+ 6 3} 12} {#/ 5 8}}
    
    and the result
    Example
    jam17.out
    107.375
    
    which you are obliged to check using pencil and paper!

    10. Listing files in a directory

    One of the most powerful features of its capability to automatically list files from a directory. Using the dir macro you can generate text in a loop for files in a directory.

    The macro dir is similar to the macro for in the sense that this also does a looping inserting text to the output several times.

    The format of the macro dir is

                 {dir/directory/pattern/text}
    
    The parameter directory gives the directory, pattern gives a selection option and text is repeated for each selected file.

    The directory can be absolute or relative to the file that contains the macro dir or relative to the output file in case option o is used. The pattern can contain a list of options, and a usual file pattern, like *.txt to select text files.

    The text can contain any text and macros, and will be inserted to the output for each selected file once. This text can contain so called looping macros to display name, extension, date, time, size or other feature of the actual file.

    The separator character can be slash or any other character according to the parameter list syntax definition (see 4. parameter list syntax), with the exception that text can contain the separator character any time, only the first two such characters are taken into account to get the parameters directory and pattern.

    Before going on, let us see an example:
    Example
    jam9.jam
    {#dir/./*.jam/ {$file$name}
    }
    
    and the output
    Example
    jam9.out
     example.jam
     filist.jam
     index.jam
     jam10.jam
     jam11.jam
     jam12.jam
     jam13.jam
     jam14.jam
     jam15.jam
     jam16.jam
     jam17.jam
     jam18.jam
     jam19.jam
     jam2.jam
     jam20.jam
     jam21.jam
     jam22.jam
     jam24.jam
     jam25.jam
     jam3.jam
     jam4.jam
     jam5.jam
     jam6.jam
     jam7.jam
     jam8.jam
     jam9.jam
    
    
    This is a very simple example just to give you a brief feeling what macro dir is all about. The above example says that should read the current directory, select all files that match the pattern *.jam and list them line by line.

    In the text of the macro we used the predefined loop macro {$file$name}, which is replaced by the name of the actual file for each loop. The loop macros are all starting with the dollar $ sign, and only evaluated when being in a loop. In other words there is no need to start a dir macro using the @ character only to protect the loop macros from evaluation. (But you should indeed use the @ character if you have other nested macros to be protected. For further details read 12. Fine points of macro evaluation order!)

    The list of all available loop macros, and their meaning:

    The pattern part of the macro dir can not only contain file pattern, but also options. For example:
    Example
    jam10.jam
    {#dir/./-s -Snd *.jam/ {$file$name}
    }
    
    says that the directory listing should be done for files matching the pattern *.jam, only the non-zero length files (-s) should be listed, and the files should be sorted by name in decreasing order (-Snd).

    The options are always before the pattern, and can be written together like -sSnd , or separated, as they are in the example above.

    The options can be

    If the h option is not used all references to html parameters of the files result empty string. However if the sort option says that the files should be sorted according to html title, the h options is automatically switched on.

    The macro dir can be used inside other dir and this way you can create listing of files which are in directories in a directory. For example you can list all files that are in some directory under directory doc:
    Example
    jam11.jam
    {@dir/doc/-d./ Directory: {$file$name}:
    {#dir|doc/{$file$name}|-. *|    {@null {$file$name}}
    }
    }
    
    This example is quite complex, and in case there are certain points that you do not understand, please read the section 12. Fine points of macro evaluation order and return here afterwards.

    The first dir starts with the character @, which means that the inner dir is evaluated when the outer dir is evaluated and not before. If we used the # character instead the outer dir would see an empty string in place of the inner dir. The reason for it is that in case of # the macro evaluation goes from inside to outside, and because there are no files in directory doc/{$file$name} (just as there is no such directory at all with such a weird name) the result of the inner dir is empty string.

    As the outer dir is preceded with the @ character the inner dir macro is evaluated when the outer loop have already created text for each directory under the directory doc. Assume that there are directories jamal, dummy1, dummy2 in the directory doc. Then the outer dir macro will result the text
    Example
    jam12.jam
     Directory: dummy1
    {#dir|doc/dummy1|-. *|    {$file$name}
    }
     Directory: dummy2
    {#dir|doc/dummy2|-. *|    {$file$name}
    }
     Directory: jamal
    {#dir|doc/jamal|-. *|    {$file$name}
    }
    
    
    The macro {$file$name} is resolved in the directory parameter, but is not resolved inside the texts of the macros, because the null macro have protected it. The result of the example:
    Example
    jam11.out
     Directory: dummy1:
        jam6.out
        jam7.out
        jam8.out
        jam9.out
    
     Directory: dummy2:
        jam2.out
        jam3.out
        jam4.out
        jam5.out
    
     Directory: examplepm:
        index.html
    
     Directory: jamal:
        ChopMacro.html
        days.html
        define.html
        dir.html
        DoFile.html
        DoInput.html
        EvalMacro.html
        expression.html
        for.html
        format.html
        history.html
        if.html
        include.html
        index.html
        jamalClose.html
        jamalDefineMacro.html
        jamalError.html
        jamalinput.html
        jamalOpen.html
        jamaloutput.html
        jamalrequire.html
        jamalSplit.html
        jamalverbatim.html
        jamalversion.html
        jsexinstall.html
        macbra.html
        maked.html
        months.html
        null.html
        optm.html
        packageJamal.html
        sep.html
        timedate.html
        undef.html
        usermacro.html
        verbatim.html
    
    
    
    should eventually be the same as
    Example
    jam12.out
     Directory: dummy1
        jam6.out
        jam7.out
        jam8.out
        jam9.out
    
     Directory: dummy2
        jam2.out
        jam3.out
        jam4.out
        jam5.out
    
     Directory: jamal
        ChopMacro.html
        days.html
        define.html
        dir.html
        DoFile.html
        DoInput.html
        EvalMacro.html
        expression.html
        for.html
        format.html
        history.html
        if.html
        include.html
        index.html
        jamalClose.html
        jamalDefineMacro.html
        jamalError.html
        jamalinput.html
        jamalOpen.html
        jamaloutput.html
        jamalrequire.html
        jamalSplit.html
        jamalverbatim.html
        jamalversion.html
        jsexinstall.html
        macbra.html
        maked.html
        months.html
        null.html
        optm.html
        packageJamal.html
        sep.html
        timedate.html
        undef.html
        usermacro.html
        verbatim.html
    
    
    
    created by the second, half evaluated macro.


    11. Date and time

    You can easily insert time and the date values. The macro {#time} and {#date} insert the actual time and date, like
    This document was last updated May 15, 2006 Monday 2:47:32
    The format of the representation is flexible and can be changed easily using the days, months and format macros.

    stores the names of the days and moths in an array and uses these names to display a date. The default names are English. In case the generated output is going to use some different language you can redefine the array saying:
    Example
    jam13.jam
    {#days/Hétfő/Kedd/Szerda/Csütörtök/Péntek/Szombat/Vasárnap}
    {#months/január/február/március/április/május/június\
    /július/augusztus/szeptember/október/november/december}
    
    Including the file jam13.jam here and displaying the above time example says:

    This document was last updated május 15, 2006 Hétfő 2:47:32
    Notice that the name of the day and the month is already in Hungarian. When a time or date value is displayed (like the time and date values of a file in a dir loop) the values are formatted according to the build in date and format string. There are two such strings: one for the time and one for the date values. You can set these strings using the macro format.

    The syntax of the macro format is:

                  {#format xxx=format string}
    
    where format is a keyword, xxx can be date, time, am or pm and format string is the formatting string. When displaying date or time value takes this formatting string and performs several substitutions, as follows: When am or pm is used it is actually replaced by the string which can be changed using the macro format am and format pm. Therefore you can say:
    Example
    jam14.jam
    {#format am=in the morning}
    {#format pm=afternoon or evening}
    

    After the time value is created using the substitutions above the resulting string is evaluated in case there are embedded macros. Therefore it is possible to write the following:
    Example
    jam15.jam
    {@format time=hh:mm {#if/{#< HH 8}/early night/\
    {#if/{#< HH 12}/morning/\
    {#if/{#< HH 18}/afternoon/\
    {#if/{#< HH 22}/night/late night}}}}}
    
    and including the above as a macro the time example

    This document was last updated május 15, 2006 Hétfő 2:47 afternoon
    Note that there is no significant difference between time and date. You can include formatting elements like YEAR into time formatting, and elements like hh into date formatting. Bot time and date macros are based on time values which are precise up to seconds.

    12. Fine points of macro evaluation order

    Read this section to understand the bits and pieces how macros are evaluated, how macros are recognized by and what order they are evaluated.

    This section is more definitive than explanatory. Here we describe how internally works and give only less explanation what rules to follow when writing compound and nested macros.

    When starts to process a text it first tries to locate the first macro in the text. He does it searching for the macro opening string, which is usually the character {. When it finds such a string appends all processed text to the output and starts to search the end of the macro. He does it looking for the macro closing string, which is usually the } character. While searching keeps track of the embedded macro opening and closing strings.

    When this is done has the macro in an internal buffer. If the macro starts with # character or is a user defined macro evaluates the macros that are embedded in the macro following the same steps as it followed until now. This is a recursive call and for the sake of reference we call it pre-evaluation. If the macro starts with the @ character no pre-evaluation takes place.

    The next step is to evaluate the macro itself. This is done in a separate procedure that defines the behavior of the macros. These check the syntax of the macro, look for parameters, look up user defined macros if necessary and generate some text. The final step during this calculation usually is searching again for embedded macros in the resulted text and evaluating them using recursive call. Let us call it post-evaluation.

    The process formalized:
    Example
    algorith.txt
    procedure jamal
    empty output
    
    while there are characters on input do
      search for the first macro,
    
      append the text before the first macro to the output,
         (and chop off it from input)
    
      search for the end of the macro found,
         (and chop off it from input)
    
      evaluate embedded macros calling
        procedure jamal unless the first character of the
        macro is @,      /pre-evaluation/
    
      evaluate the macro and 
        usually [ call the procedure jamal to evaluate
                  macros in the resulting text ],
                         /post-evaluation/
    
      append the final result of the macro to the output
    
    end of loop
    
    end of procedure
    
    
    There are some exceptional macros that do not evaluate the result again to resolve macros that were generated evaluating the macro. These are


    13. the null, comment and verbatim macros

    The null, comment and verbatim macros serve special purpose to alter the evaluation order of macros. Usually macros are parsed from outside to inside and evaluated from inside to outside when macros are nested.

    When a macro is evaluated first all embedded macros are evaluated before taking care of the macro itself unless the leading character of the macro is @.

    When a macro is evaluated tries to find again embedded macros in the result to assure that there remained no macros unevaluated.

    Let us look at the macro that we use in this document to include examples.
    Example
    example.jam
    {#define ExampleColor=#0000AA}
    {#define Example/file=<table border=0><tr>
    <td width=50 VALIGN=TOP><small><b>Example</B><br>file</small></td><td>
    <table border=1><tr><td width=550 border=1>
    <FONT COLOR="{ExampleColor}"><PRE>
    {@null {#include pre "file"}}
    </PRE></FONT></td></tr></table></td></tr></table>}
    {#define InlineExample/text=<PRE><FONT COLOR="{ExampleColor}">
    text
    </FONT></PRE>}
    
    
    {@comment Hey this is a comment!!}
    This doesn't appear as it is included as macro!!! Or does?
    

    null

    We did not use the @ character to start the definition of the macro Example because there are embedded macros like ExampleColor which are supposed to be evaluated before the definition takes place.

    On the other hand the macro include had to be protected from evaluation otherwise could try to open a file named file which is unlikely to exist. (And if it existed examples would tend to be boring a bit.)

    To protect the macro another macro null was used. This macro does nothing else but results the body of it without post-evaluation.

    When the body of the macro define is evaluated before the definition takes place, the macro null is evaluated and it results the string {#include pre "file"}, which is appended to the body of the macro define without further evaluation.

    When the macro define is evaluated it has got the include in it intact. The post-evaluation does not evaluate the macro include either, because this text does not get to the output of the macro define. The output of the macro define is empty string. On the other hand the macro include together with the other lines gets into the value of the defined macro: Example.

    When the macro Example is called it is evaluated, all formal/actual parameter substitutions take place and after this, the post-evaluation of the macro Example does evaluate the macro include having the actual file name as an argument due to formal/actual parameter substitutions.

    comment

    The last line of the example shows a comment. This comment is indeed a macro, but as the start character is @ the macros that might happen to be nested in it will not be evaluated in pre-evaluation and by the defined behavior of this very macro no post-evaluation will take place.

    There could be an interesting, but (warning! personal opinion follows!) perverted use of the macro comment: you can use this macro to emulate the effect of the macro include macro.
    Example
    jam21.jam
    First:  {#include example.jam}
    Second: {#include macro example.jam} includes macro
    Third:  {#comment {#include example.jam}} does the same
    Fourth: {@comment {#include example.jam} this does NOT include anything!}
    
    
    and the output
    Example
    jam21.out
    First:  
    
    
    
    
    
    This doesn't appear as it is included as macro!!! Or does?
    Second:  includes macro
    Third:   does the same
    Fourth: 
    
    

    verbatim

    The macro verbatim can be used to prevent post-evaluation of user defined macros. The macro verbatim has a special syntax:

    {#verbatim user-defined macro}
    
    The user defined macro should be written after the keyword verbatim separated by one or more space together with its arguments if any exactly the same way as if it were not verbatim. When sees the verbatim prefix it passes evaluation to the user defined macro, but also tells it not to do post-evaluation. If the macro verbatim is used with the @ character pre-evaluation is also prohibited. In case only pre-evaluation is to be prohibited the arguments of the user defined macro should be protected using the null macro. Example
    Example
    jam22.jam
    {#define tt/x=<tt>x</tt>}\
    {#define alma=szilva}\
    {#define apple=alma}\
    {tt|{#[}{apple}{#]}}
    {#verbatim tt|{#[}{apple}{#]}}
    {@verbatim tt|{#[}{apple}{#]}}
    {tt|{@null {#[}{apple}{#]}}{#define apple=jabloko}}
    
    and the output
    Example
    jam22.out
    <tt>szilva</tt>
    <tt>{alma}</tt>
    <tt>{#[}{apple}{#]}</tt>
    <tt>{jabloko}</tt>
    
    The first output line is resulted as pre-evaluation transformed apple to alma and post-evaluation transformed alma to szilva. Note that post-evaluation already sees the macro opening and closing strings around the string alma as the [ and ] macros were evaluated during pre-evaluation.

    The second version does not perform post-evaluation, and therefore alma remains alma, bracketed obviously.

    The third line does not evaluate neither before, nor after the evaluation of the macro tt.

    The last line evaluates the define macro before processing the macro tt, but protects apple from pre-evaluation using the null macro. However this macro is evaluated after the macro tt was evaluated during the post-evaluation and the result now is jabloko as the macro apple was redefined during the pre-evaluation of tt. Clear?


    14. Redefining the macro bracket strings

    The macros in jamal usually start with the character { and finish with the character }. This is a good choice for HTML crafting, but may not be appropriate for other languages. Therefore provides a macro to redefine the opening and closing string. You can use any string to start and to end a macro assumed that they are different.

    The syntax of the macro that redefines the macro bracket strings is:

                   {sep/start string/end string}
    
    The keyword sep is actually should be followed by a list of syntax "4. parameter list syntax". The first element of the list will be used as macro start string and the second as a macro end string. The simple example
    Example
    jam18.jam
    Start#timeStop{#time}
    {#sep/Start/Stop}\
    Start#timeStop{#time}
    Start#sep/}/{Stop\
    }#time{
    
    
    and the output
    Example
    jam18.out
    Start#timeStop2:47:31
    2:47:31{#time}
    2:47:31
    
    

    The first line of this example shows nothing interesting. The second line sets the macro start and stop strings are set to Start and Stop. The third line that follows already uses these separator strings and therefore result a different output than the first line. On the third line the { and } characters are appear as normal characters and just outputs them.

    The next line redefines the separators to be { and } but the reverse order. This is used on the last line.

    Care has to be paid when using the macro sep inside other macros. As macros are usually parsed from outside to inside and evaluated from inside to outside the redefined separators might have undesired effects. The thumb rule says that the macros should be terminated using the pair of the opening string. In other words, if a macro was opened using the string xxx and the pair of it is yyy then yyy should be used to close the macro even if an embedded sep macro redefines the opening and closing strings.

    To make it even more confuse here is an example:
    Example
    jam19.jam
    {#define sipsep={#sep/[/]}sepsip}\
    [@define supsup=[#sep/{/}]puspus]\
    [sipsep] [supsup] {sipsep}
    
    
    When sipsep is defined a sep macro is evaluated and it changes the separators to [ and ]. Even though the define is closed using the conventional { character as it was opened using the character }.

    The define on the next line already have to use the [ and ] characters as separators. The embedded sep macro in this case however is not evaluated when supsup is defined, because the leading macro character is @. On the other hand, when supsup is used, it results the string puspus and as a side effect resets the macro separator strings. The output file is:
    Example
    jam19.out
    sepsip puspus sepsip
    
    

    Try to imagine what happens when you extend the last line of this example with the {supsup} macro call. What will the result be and why does complain about malformed macro?


    15. Including the macro bracket strings

    Sometimes you need a quick way to include { or } to the output, but in case it happens only at a few locations it does not worth the effort to change the macro separator characters using sep to a different value and setting it back.

    For such situations introduces four macros. See the example
    Example
    jam20.jam
    {#[} {#]} {#sep [ ]}
    [#{] [#}] [#sep Start Stop]
    Start#{ Stop Start#} Stop Start#[ Stop Start#] Stop 
    
    
    will result
    Example
    jam20.out
    { } 
    [ ] 
    Start Stop Start Stop 
    
    
    The [ macro closed between macro start and end strings and preceded by # or @ character return the actual macro opening start string. ] returns the macro end string the same way. Just in case you happen to set the macro opening and ending strings to these characters { and } work the same way.


    16. Requiring version

    Since V2.0 of there is a macro require to check the version of . This macro takes one numerical argument, and in case this argument is larger than the version of the procesing it generates a fatal error.

    This macro can be used to inform on the minimal version the source file requires. Unfortunately V1.0 does not know this macro and does not stop. However even 1.0 will complain about bad macro format.

    This macro requires a certain version and has nothing to do with the versions of any j-SEX modules.

    Requiring a certain version that the file was written for is a safe operation and it allows later versions to modify their behaviour according to the requested version. Some versions of might behave different from earlier versions and may choose to retard the bahaviour if an earlier version is required by the source file. Such a feature is NOT implemented in the current version.

    There are some certain features between 2.0 and 2.01 that behave different. In version 2.0 the macros and and or have lost the first argument. This was a bug and therefore requesting version 2.0 does not produce the buggish behaviour using V2.01 or later.


    17. Trouble shooting macros

    Simple macros are simple to write and they usually work fine. However at some point of time you will meet a macro you wrote that does not work. It either does not produce the output you needed or complains about some error.

    Such an error comes from or from your source. The second case is the more likely. This is not because I wrote bug free, but much rather this is what I experience. Many times I was hunting bugs in the Perl source of and after a few minutes (or few hours if I am honest) I found out that worked well. Only the macro I wrote was wrong, or my expectation were wrong. This is especially true for nested macros with sophisticated macro evaluation order.

    Rule numero uno: If you think having found a bug in do not hesitate to send me a bug report. If this is really a internal bug, it helps me to correct. If it is not, I can help you telling what was wrong and your report can help me to improve the documentation. If you misunderstood something: the problem is with the documentation and not with your brain.

    If complains about some error it tries to be as specific as it can regarding the type of the error and the location. displays four lines for each error.

    1. The message of the error in English.
    2. The parameter of the error message if there is any such beast. This is usually the fragment of the source code that caused the error. For on-screen readability the fragment is truncated to 20 characters and if truncation was done ellipses are added to the parameter. Also the new-line characters are substituted with \n character pairs to ease readability.
    3. displays the file and the line number where it found the error. (See notes later!)
    4. displays the Perl source file, package and program line information. This is usually not interesting for you unless you are developing or using j-SEX packages.
    You can locate the error in the source file and correct it. In some cases continues processing the file even after an error and might result the wanted output. Do not be satisfied with such a result! Correct the source until processes it without error or warning messages. If you have a file that translates correct but displays error messages you have an output which is not guaranteed. Having many of such large files in a project can result deep problems when you want to upgrade to a newer version. might behave different.

    But how to debug syntactically correct but misbehaving macros? Macros do not execute, they are just replaced internally in 's memory and only the final result is sent to the output file.

    If you experience macro evaluation problems you can ask to produce a "trace" output using the option -t. The file you name with this option will be overwritten by 's trace report.

    Each line in the trace file has four columns. Columns are separated by colons. The firs column is the line number of the source file that the trace is displaying. The second column is type of the line saying that is tracing a M macro evaluation L lines without macro evaluation (also before and after macro evaluation) or some macro was D defined.

    NOTE: There is a known bug regarding the line numbers: preprocesses the input before anything else removing backslash escaped new lines. Line number calculation is done afterwards. This means that the line numbers displays should be treated escaped new-line characters removed from the source file.


    18. Writing extension modules in Perl

    After V1.0 was released there was a huge demand for several extensions. Users wanted to have macros that can not be defined using 's define macro but are too specific to include them into the language. Some user even modified the source of .

    Putting all requested macros into would have led to a huge, slow and unmaintainable macro processor.

    On the other hand user modification of would lead to several incompatible versions.

    The solution is that became extendible using Perl modules since version 2.0. These extensions can be very simple and at the same time perform useful tasks. As they are Simple EXtenson modules I call them j-SEX modules.

    To use a j-SEX module you have to install the source of the extension and be familiar with the built-in macros use and with.

    To write j-SEX modules you should be familiar with the language Perl, and should also know Perl modules.

    As j-SEX modules written in Perl are an elaborate topic, here we included two documents.

    There is a built-in macro called INC that can be used to specify the location of the extension modules. The extension modules usually are in a directory called jamal under the Perl library directory. The list of the available library directories are stored in the Perl array @INC, and is displayed by the help screen (Type perl jamal.pl -h.)

    There is a command line option to specify additional directories as well as the macro INC.

    The macro INC has one argument, the directory where the directory named jamal containing the extension modules is. The name of this directory can be absolute or relative to the input file. This will be push-ed onto the array @INC in Perl so the next time Perl looks for a module it will look for this directory as well.


    19. Installing j-SEX modules

    Since version 3.0 there is a new command line option to -i. Using this option you can easily install j-SEX module on the system you run . You should start interactive typing 'perl jamal.pl -i xxx.pm' to install install the module xxx.pm or just 'perl jamal.pl -i' to install all j-SEX modules that can be found in the current working directory.

    The option works interactive. Before doing anything it lists all the files it is going to install and it also lists the possible locations where the module can be installed. You can choose one location and will copy the module into the selected directory.

    You can specify any number of modules following the option -i. You have to have appropriate privilege so that can write the directory where the module is to be copied to. This usually means that you have to be root or Administrator on the system you run on.

    After you installed the j-SEX module you should check that the installed files have the appropriate permissions.


    20. Version history

    versionDescription
    1.0Primary version
    2.0j-SEX interface defined
    2.01Numeric file operation -t
    bug fixing numeric operation handling
    operator not was missing (this was bug not having that operator)
    errors now display source line numbers
    trace file output is available
    3.00j-SEX module installation included

    21. Planned future extensions

    tries to be powerful, easy to use, complete and perfect. On the other hand the few thousand years of human history taught us that nothing powerful is easy to use, and nothing made by men or women is either complete or perfect. I did my best.

    There are certain features that could include, but does not. There was a certain time during development, where introduction of new features was stopped, and development started to focus on bug elimination. Here I list some features that does NOT support, but I think could be useful and might be introduced in version 2.0

    current version is 3.01 and all new versions between this one and the next major version will only contain bug fixes and no major new features.

    WARNING: Some features of current version might change in future versions in a way being incompatible with current version. Such changes are tried to be predicted and listed here.

    New features will be introduced according to your response and inquiries. See section 22. Providing feedback.

    Features

    There are currently no features in my mind that I think should be implemented into . Give me ideas.

    22. Providing feedback

    You can reach me by electronic mail peter@verhas.com.

    Please note that supporting is not something that I am paid for. This imply that my answering capability is limited and has priority lower than job and family. Even though: if you have any note drop me a mail. And please, please read the documentation. (This seems to be a silly request. You are doing it, aren't you?)

    I highly appreciate bug reports, but as usually try to be specific, provide the shortest possible example demonstrating the bug.

    I appreciate modules submitted for publication. I am going to create a repository for j-SEX modules.

    Ideas, comments appreciated. Send me your tipps.

    Flames: thank you, no.

    Telling me that generally my English is not good enough does not carry information for me. I know. And on the other hand I speak English probably better than you do Hungarian. But tell me my mispellings in the documentation. I will correct.


    23. Tipps

    A short collection of tipps, how to use effectively. These are not hardwired rules to follow. Matter of taste.

    24. Author of the program

    Péter Verhás
    HOME PAGE


    25. Competing products

    There are other software products that aim the same or similar goal. Here is a partial list. If you know any other software not listed here, please let me know!

    26. Legal

    This software is provided on an "AS IS", basis, without warranty of any kind, including without limitation the warranties of merchantability, fitness for a particular purpose and non-infringement. The entire risk as to the quality and performance of the Software is borne by you. Should the Software prove defective, you and not the author assume the entire cost of any service and repair.

    Any statement, assumption expressed or implied in this document, in any attached document, program source code, or in any other information source associated with this program, belong to the author, and might not reflect the views of anyone else.

    The development of the program was sponsored by no one. I have done it in my free time at home using resources that I have legally purchased, including hardware and software.

    You are free to use and distribute as far as your actions are in line with the GNU General Public License. I would also appreciate if you could include a reference text on one or more of the pages that you create on a site using . This can be done using the predefined macro {reference}.
    This page was created using jamal v3.01