com.ccg.macros
Class AtMacros

java.lang.Object
  extended by com.ccg.macros.AtMacros
All Implemented Interfaces:
Interpreter

public class AtMacros
extends Object
implements Interpreter

Implementation of a "@macro" Interpreter.

This class provides all of the building blocks for a full macro interpreter. It has all of the tools necessary to scan ASCII text files looking for "@macros" which it will then attempt to process.

A "@macro" entered in the following form will always be recognized:

 @NAME(["ARG0"][,"ARG1"][,"ARG2"]...)
 

By default, the NAME of the macro must contain only lower case characters ('a'-'z'), upper case characters ('A'-'Z'), digits ('0'-'9') and the underscore character ('_').

For example:

 @define("pkb","Paul Blankenbaker")
 

The following alternative forms can be used as well:

@NAME
If the macro takes no arguments, and is followed by white space, you can use this "short form" notation. It is a recognized "short form" of @NAME(). For example, "@pkb - programmer" is equivalent to "@pkb() - programmer".
@NAME(ARG0[,ARG1])
If your arguments do not contain any special characters (like spaces, quotes, commas, parenthesis), you can optionally omit the double quotes. For example, @define(pkb,Paul) is interpretted the same as @define("pkb","Paul").

Your best bet is to use the full form (include the parenthesis and argument quoting) as that form will always be processed as you expect.

At times, you may find that you need to escape characters in the arguments you pass to the macros (in particular the double quote character). The standard Java escape characters can be used in a quoted argument. For example, to pass the argument A "very" wet day! as a argument, one would construct the macro in the following form:

 @define("dayType","A \"very\" wet day!")
 

 

NOTE:The escape characters are only recognized within quoted parameters. The following escape sequences are supported:

Escape Seq Unicode Value Description
\b\u0008Backspace
\f\u000cForm feed
\n\u000aLine feed (new line)
\r\u000dCarriage return
\t\u0009Tab
\'\u0027Single Quote
\"\u0022Double Quote
\\\u005cBackslash
\(\u0040Begin Parenthesis
\)\u0041End Parenthesis
\uXXXX\uXXXXAny unicode character - must use 4 hex digits

Using an unrecognized escape sequence in a string will have unpredictable results. Most likely, the escape character will simply be ignored (and not appear in the output). You may find yourself hit with this when quoting DOS style file names. For example, "c:\t.txt" should be written as "c:\\t.txt" to prevent the "\t" from coming out as a tab character.

Also, the escaping of a double quote is only required (it never hurts to do it), if:

For example, the following parameters are equal "Hello \"Paul\"." and "Hello "Paul".", however the first form is preferred (support of the latter form was added later as it seemed reasonable). However, "\"Paul\", B." works where as ""Paul", B." does not (due to the comma following the double quote).

There is one issue in regards to including paranthesis in quoted strings. For example, consider the following:

 @define("FullName","@param(0) @param(1)")
 @define("PlusPhone","@FullName("@param(0)","@param(1)") (@param(2))")
 @define("UnmatchedParen","((--->")
 

The definition of "PlusPhone" above wants to pass two parameters to the "@define" macro. The first parameter is not a problem, but the second parameter contains nested quoted arguments. The interpreter is "smart" in that it detects the parenthesis following "@FullName" and ignores all quotes until the last parenthesis is found. This allows the interpreter to correctly extract the two arguments in the complex example. However, because of this rule, the "UnmatchedParen" will not be interpretted properly. When the two mismatched parathesis in "((--->" string are encountered the interpreter will ignore the ending quote until it finds two matching ending parenthesis. If you find yourself in this situation, you will need to "escape" your parenthesis and write your macro as follows:

@define("FullName","@param(0) @param(1)")
@define("PlusPhone","@FullName("@param(0)","@param(1)") (@param(2))")
@define("UnmatchedParen","\(\(--->")
@define(pkb,"@PlusPhone(Paul,"Blankenbaker","555-7676")")
@UnmatchedParen() @pkb
 

It should be noted, that this class doesn't actually provide any built in macros itself. This class just provides the parsing building blocks and methods to make the construction of custom macro sets possible. Typically other classes make use of the addMacro(String,String) method to define simple text replacement, the addMacro(String,MacroHandler) method to install more sophisticated macro handlers, and the addMacros(Object) to automatically add methods with a certain signature to the set of recognized macro handlers.

The At class is a full implementation of an interpreter which defines several built in macros and provides a means for additional macros to be defined based on the contents of the processed file.

Since:
1.0
Version:
$Revision: 1.1.1.1 $
Author:
$Author: pkb $
See Also:
At

Constructor Summary
AtMacros()
          Initializes object to the default parsing rules.
AtMacros(AtMacros from)
          A copy constructor of another AtMacros object.
 
Method Summary
 void addMacro(String name, MacroHandler mh)
          Associate a MacroHandler with a macro name.
 void addMacro(String name, String val)
          Add a simple string subsitution macro.
 void addMacros(Object macroHandler)
          Add all "macro handling methods" from a class to our defined set.
 int getDepth()
          Get the current depth of the recursion as we are processing
 char getEndParamChar()
          Get the symbol which indicates the end of the parameter list
 char getEndQuoteChar()
          Get the symbol which ends a "quoted" string
 char getEscapeChar()
          Get the "escape" character which can appear in quoted strings
 Object getMacro(String name)
          Fetch the object definition for a particular macro.
 Enumeration getMacroNames()
          Fetch the list of all macro names which are currently defined.
 String getParameter(int i)
          Fetch one of the parameters (arguments) passed to a macro.
 String getParameter(int i, boolean eval)
          Fetch one of the parameters (arguments) passed to a macro.
 int getRecursionDepth()
          Get the number of recursive calls allowed while evalutating
 char getSepParamChar()
          Get the character used to separate parameters in a parameter list
 char getStartMacroChar()
          Get the symbol which indicates the start of a macro
 char getStartParamChar()
          Get the symbol which indicates the start of the parameter list
 char getStartQuoteChar()
          Get the symbol which starts a "quoted" string
 void interpret(Input in, Output out)
          Process a input source and write the results to a output destination.
 String interpret(String in)
          Process a source string and return the resulting string.
 void interpretCheck(Input in, Output out)
          Process a input source and write the results to a output destination.
 String interpretCheck(String in)
          Process a source string and return the resulting string.
protected  Vector parseParams(Input in)
           
 void setDepth(int val)
          Set the current depth of the recursion as we are processing
 boolean setEndMacroChar(char match, boolean indicates_end)
          Set/clear individual character which indicates end of macro name.
 boolean setEndMacroChars(String val)
          Set the symbol(s) which indicate the end of a macro name
 void setEndParamChar(char val)
          Set the symbol which indicates the end of the parameter list
 void setEndQuoteChar(char val)
          Set the symbol which ends a "quoted" string
 void setEscapeChar(char val)
          Set the "escape" character which can appear in quoted strings
 void setRecursionDepth(int val)
          Set the number of recursive calls allowed while evalutating Typically one doesn't need to worry about setting a recursion depth limit (the default value should be sufficient in most cases).
 void setSepParamChar(char val)
          Set the character used to separate parameters in a parameter list
 void setStartMacroChar(char val)
          Set the symbol which indicates the start of a macro
 void setStartParamChar(char val)
          Set the symbol which indicates the start of the parameter list
 void setStartQuoteChar(char val)
          Set the symbol which starts a "quoted" string
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

AtMacros

public AtMacros()
Initializes object to the default parsing rules.

This constructor prepares the macro interpreter with the default parsing rules, but without any definitions.

After construction, one will typically use the the "add macro" methods to define macros (see addMacro(String,String), addMacro(String,MacroHandler), and addMacros(Object)).

Typically one will probably not want to change the parsing characters, HOWEVER you can with methods like setStartMacroChar(char), setEndMacroChars(String), etc.

Since:
1.0

AtMacros

public AtMacros(AtMacros from)
A copy constructor of another AtMacros object.

This constructor makes a duplicate of another AtMacros object. Initially after construction, both objects will have the same set of definitions - however any new definitions added to either the new copy or the original will only affect the object they are added to (each object will have its own definition rules after the intial construction).

Parameters:
from - The AtMacros
Since:
1.0
See Also:
AtMacros()
Method Detail

getParameter

public String getParameter(int i,
                           boolean eval)
                    throws InterpretException,
                           IOException
Fetch one of the parameters (arguments) passed to a macro.

This method is used by macro handlers to retrieve arguments which are passed to the macro. For example, if one were to write a macro handler for the "@define(NAME,TEXT)" macro, the handler would use this method to retrieve the information (see At.define(com.ccg.macros.Output, java.util.Vector) for the definition of this handler).

For example, if the following text were being processed by the "define" macro handler:

 @define("pkb","Paul Blankenbaker")
 

The "define" macro handler would get the value pkb if it invoked getParameter(0), and the value Paul Blankenbaker if it invoked getParameter(1).

Requesting a parameter that was not passed returns a zero length string (not null).

It should be noted that each parameter returned is also run through the interpreter if you set the second parameter to true. This means that if one of the arguments contains macros itself, they will be expanded in the returned result. Pass false as the second parameter to get the "raw" string value of the original parameter.

Parameters:
index - The index of the argument you want to request (0 correpsonds to the first argument, 1 to the second, and so on).
eval - Whether the raw value of the parameter should be evaluated or not.
Returns:
The interpretted results of the parameter passed - never returns null, but may return a zero length string (if the index specify is out of range or no argument was passed).
Throws:
IOException - If a I/O error is encountered when reading from a input source, or writing to a output destination.
InterpretException - If the contents of the source being interpretted violates the rules of the interpreter. Note, each interpretter is able to define its own set of rules as to what is allowed or not.
Since:
1.0

getParameter

public String getParameter(int i)
                    throws InterpretException,
                           IOException
Fetch one of the parameters (arguments) passed to a macro.

This method is used by macro handlers to retrieve arguments which are passed to the macro. For example, if one were to write a macro handler for the "@define(NAME,TEXT)" macro, the handler would use this method to retrieve the information (see At.define(com.ccg.macros.Output, java.util.Vector) for the definition of this handler).

For example, if the following text were being processed by the "define" macro handler:

 @define("pkb","Paul Blankenbaker")
 

The "define" macro handler would get the value pkb if it invoked getParameter(0), and the value Paul Blankenbaker if it invoked getParameter(1).

Requesting a parameter that was not passed returns a zero length string (not null).

It should be noted that each parameter returned is also run through the interpreter. This means that if one of the arguments contains macros itself, they will be expanded in the returned result.

Parameters:
index - The index of the argument you want to request (0 correpsonds to the first argument, 1 to the second, and so on).
Returns:
The interpretted results of the parameter passed - never returns null, but may return a zero length string (if the index specify is out of range or no argument was passed).
Throws:
IOException - If a I/O error is encountered when reading from a input source, or writing to a output destination.
InterpretException - If the contents of the source being interpretted violates the rules of the interpreter. Note, each interpretter is able to define its own set of rules as to what is allowed or not.
Since:
1.0

addMacro

public void addMacro(String name,
                     String val)
Add a simple string subsitution macro.

This command defines (or replaces an existing definition) a macro which evaluates to a simple text replacement. Hence, when the macro is encountered during processing it will be replaced with the interpretted value assigned. For example:

 public static void foo(AtMacros am) {
   am.addMacro("first","Paul");
   am.addMacro("last","Blankenbaker");
   am.addMacro("name","@first() @last()");
 }
 

After the following is run, when the macro "@first" is encountered in the text being processed, it will be replaced with "Paul". The key thing to notice here is that the replaced text is also interpretted. This means that when the "@name" macro is encountered in the text being processed, its contained text will be interpretted as well. This would result in "Paul Blankenbaker" appearing in the output in this example.

Parameters:
mname - The name of the macro to define (if you pass null or a zero length string we ignore your request).
val - The value to associate with the macro (null is treated like "")
Since:
1.0
See Also:
addMacros(java.lang.Object)

getMacro

public Object getMacro(String name)
Fetch the object definition for a particular macro.

Parameters:
mname - The name of the macro you want to lookup the associated value for. You can pass null - and get null back.
Returns:
The object associated with the macro name, or null if there isn't one associated.
Since:
1.0

getMacroNames

public Enumeration getMacroNames()
Fetch the list of all macro names which are currently defined.

Returns:
The list of all macro names which are currently defined.
Since:
1.0

addMacro

public void addMacro(String name,
                     MacroHandler mh)
Associate a MacroHandler with a macro name.

This installs any object which implements the MacroHandler interface into the defined set of macros.

Parameters:
mname - The name of the macro to define (this must NOT be null!).
val - The value to associate with the macro (null is treated like "")
Since:
1.0

addMacros

public void addMacros(Object macroHandler)
Add all "macro handling methods" from a class to our defined set.

This method can be used to install a LOT of macro handlers based upon the method signatures within the object passed. It uses Java's reflection mechanisms to inspect the methods in the object passed. For every method which matches the following signature:

 public void mName(Output out, Vector args)
   throws IOException, InterpretException
 

A new macro is added such that if the method name in its macro form ("@mName") is encountered, the associated method in the object passed will be invoked to carry out the processing.

This is the easy way to add your own specialized macro handlers, and what the At utility relies upon to add all of its "built-in" functions (like: "@define", "@include", "@param", etc).

Parameters:
o - The object to inspect and look for methods matching the rules specified above (must not be null).
Since:
1.0
See Also:
At

interpret

public void interpret(Input in,
                      Output out)
               throws IOException,
                      InterpretException
Process a input source and write the results to a output destination.

This is one of the methods used to actually do the processing of data. It reads information from the input, processes any contained macros and writes the results to the output.

This is how one typically starts to process macros. This method simply resets our current recursion depth and then invokes the recursion safe implementation to do the actual processing.

Specified by:
interpret in interface Interpreter
Parameters:
in - A input source to read and interpret
out - A output destination to write the results of the interpretation.
Throws:
InterpretException - If a internal (or macro error) is encountered while processing.
IOException - If a problem reading input or writing output is encountered.
Since:
1.0
See Also:
interpret(String), interpretCheck(Input,Output)

interpret

public String interpret(String in)
                 throws IOException,
                        InterpretException
Process a source string and return the resulting string.

This method evaluates a simple string for any contained macros. Any contained macros are expanded and the resulting string is returned.

Parameters:
in - A string to interpret - if you pass null you get null back.
Returns:
The results of processing the input string (any contained macros are evaluated)
Throws:
InterpretException - If a internal (or macro error) is encountered while processing.
IOException - If a problem reading input or writing output is encountered.
Since:
1.0
See Also:
interpret(Input,Output)

interpretCheck

public String interpretCheck(String in)
                      throws IOException,
                             InterpretException
Process a source string and return the resulting string.

This method evaluates a simple string for any contained macros. Any contained macros are expanded and the resulting string is returned.

Since macros often require recursive evaulation, this method makes sure that the recursion depth is not exceeded. If the recursion depth is exceeded, a Interpret exception is thrown indicating as much.

Parameters:
in - A string to interpret - if you pass null you get null back.
Returns:
The results of processing the input string (any contained macros are evaluated)
Throws:
InterpretException - If a internal (or macro error) is encountered while processing.
IOException - If a problem reading input or writing output is encountered.
Since:
1.0
See Also:
interpretCheck(Input,Output)

interpretCheck

public void interpretCheck(Input in,
                           Output out)
                    throws IOException,
                           InterpretException
Process a input source and write the results to a output destination.

This is one of the methods used to actually do the processing of data. It reads information from the input, processes any contained macros and writes the results to the output.

Since macros often require recursive evaulation, this method makes sure that the recursion depth is not exceeded. If the recursion depth is exceeded, a Interpret exception is thrown indicating as much.

Parameters:
in - A input source to read and interpret
out - A output destination to write the results of the interpretation.
Throws:
InterpretException - If a internal (or macro error) is encountered while processing.
IOException - If a problem reading input or writing output is encountered.
Since:
1.0
See Also:
interpret(String), interpret(Input,Output)

setDepth

public void setDepth(int val)
Set the current depth of the recursion as we are processing

Parameters:
val - New int value to assign.
See Also:
getDepth()

getDepth

public int getDepth()
Get the current depth of the recursion as we are processing

Returns:
Current int value assigned.
See Also:
setDepth(int)

setRecursionDepth

public void setRecursionDepth(int val)
Set the number of recursive calls allowed while evalutating Typically one doesn't need to worry about setting a recursion depth limit (the default value should be sufficient in most cases). However, if one anticipates that they will need to evalute heavily recursive definitions, you can call this method to increase how deep we allow the evaluations to proceed before giving up.

This value sets the maximum recursive call limit. If the interpretation of the source input requires a recursion level greater than this value, the interpreter will give up and throw an exception. This provides a "safety" from entering a infinite recursion loop that doesn't terminate until memory is exhausted.

Parameters:
val - New int value to assign.
See Also:
getRecursionDepth()

getRecursionDepth

public int getRecursionDepth()
Get the number of recursive calls allowed while evalutating

Returns:
Current int value assigned.
See Also:
setRecursionDepth(int)

setStartMacroChar

public void setStartMacroChar(char val)
Set the symbol which indicates the start of a macro

Parameters:
val - New char value to assign.
See Also:
getStartMacroChar()

getStartMacroChar

public char getStartMacroChar()
Get the symbol which indicates the start of a macro

Returns:
Current char value assigned.
See Also:
setStartMacroChar(char)

setEndMacroChars

public boolean setEndMacroChars(String val)
Set the symbol(s) which indicate the end of a macro name

Parameters:
val - String containing characters which mark the end of a token.

setEndMacroChar

public boolean setEndMacroChar(char match,
                               boolean indicates_end)
Set/clear individual character which indicates end of macro name.

This method can be used to individually add/remove characters which indicate the end of a macro name.

Parameters:
c - The character which we are trying to match against
indicates_end - Set to true if you want the character to indicate the end of a macro, or false if you don't want it to indicate the end.
Returns:
true if we allowed the addition, false if not
Since:
1.0
See Also:
setEndMacroChars(java.lang.String)

setStartQuoteChar

public void setStartQuoteChar(char val)
Set the symbol which starts a "quoted" string

Parameters:
val - New char value to assign.
See Also:
getStartQuoteChar()

getStartQuoteChar

public char getStartQuoteChar()
Get the symbol which starts a "quoted" string

Returns:
Current char value assigned.
See Also:
setStartQuoteChar(char)

setEndQuoteChar

public void setEndQuoteChar(char val)
Set the symbol which ends a "quoted" string

Parameters:
val - New char value to assign.
See Also:
getEndQuoteChar()

getEndQuoteChar

public char getEndQuoteChar()
Get the symbol which ends a "quoted" string

Returns:
Current char value assigned.
See Also:
setEndQuoteChar(char)

setEscapeChar

public void setEscapeChar(char val)
Set the "escape" character which can appear in quoted strings

Parameters:
val - New char value to assign.
See Also:
getEscapeChar()

getEscapeChar

public char getEscapeChar()
Get the "escape" character which can appear in quoted strings

Returns:
Current char value assigned.
See Also:
setEscapeChar(char)

setStartParamChar

public void setStartParamChar(char val)
Set the symbol which indicates the start of the parameter list

Parameters:
val - New char value to assign.
See Also:
getStartParamChar()

getStartParamChar

public char getStartParamChar()
Get the symbol which indicates the start of the parameter list

Returns:
Current char value assigned.
See Also:
setStartParamChar(char)

setEndParamChar

public void setEndParamChar(char val)
Set the symbol which indicates the end of the parameter list

Parameters:
val - New char value to assign.
See Also:
getEndParamChar()

getEndParamChar

public char getEndParamChar()
Get the symbol which indicates the end of the parameter list

Returns:
Current char value assigned.
See Also:
setEndParamChar(char)

setSepParamChar

public void setSepParamChar(char val)
Set the character used to separate parameters in a parameter list

Parameters:
val - New char value to assign.
See Also:
getSepParamChar()

getSepParamChar

public char getSepParamChar()
Get the character used to separate parameters in a parameter list

Returns:
Current char value assigned.
See Also:
setSepParamChar(char)

parseParams

protected Vector parseParams(Input in)
                      throws IOException,
                             InterpretException
Throws:
IOException
InterpretException


Copyright 1998-1998-2006 null. All Rights Reserved.