Quick Links
Overview
This topic discusses how the Common Lisp Readtable is implemented in
CLforJava. The
ReadTable is used by the
TheReader to determine what character
TheReader has encountered. A
ReadTable can also contain associations between macro characters and their macro functions. In addition to these requirments, the
ReadTable must also record information about the case of a character which effects the
TheReader.
Like ANSI Lisp, the
CLforJava will allow the Lisp programmer to customize the macro characters and macro functions of the readtable. However, the Readtable is only responsible for storing these modifications during the execution of the
CLforJava. That is to say that upon startup the Readtable will initialize to the default "Standard Readtable".
Current Implementation
The current implementation defines an array containing the 128 ASCII characters in an array, more commonly refered to as the Standard Readtable. The character's numerical value will act as the indexing scheme for storage and look up within the array. The character syntax types are
constitiuent, whitespace, terminating macro, non-terminating macro, single escape, multiple escape, and invalid**. The idea is to use an enumerated type to define these as constants in a seperate Java class. Details on enumeration can be found at Topic 21 of the book
Effective Java and you can find more information about the syntax types in the Lisp Hyper Spec listing of
Syntax Types.
Here is an example of the Enumerated character syntax type described above. Defining this class in this manner gives us a type safe implementation of the Character attributes necassary to both
TheReader and
ReadTable.
public class SyntaxType {
public static final SyntaxType CONSTITUENT = new SyntaxType("CONSTITUENT");
public static final SyntaxType NON_TERMINATING = new SyntaxType("NON_TERMINATING");
public static final SyntaxType TERMINATING = new SyntaxType("TERMINATING");
public static final SyntaxType WHITESPACE = new SyntaxType("WHITESPACE");
public static final SyntaxType INVALID = new SyntaxType("INVALID");
public static final SyntaxType SINGLE_ESCAPE = new SyntaxType("SINGLE_ESCAPE");
public static final SyntaxType MUTIPLE_ESCAPE = new SyntaxType("MUTIPLE_ESCAPE");
private String name;
/**
* Creates a new instance of SyntaxType. Making it private prevents any subclassing or other
* instantiations other than the ones defined here.
*/
private SyntaxType(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
The
ReadTable also contains two objects similar to a Hashtable capable of storing function, names or values. This will be implemented using an Object known in Java as a Hashmap. This structure allows us to bind functions, values, or names to a paticular character as a pair set. There are two cases in which we will need to access these Hashmaps.
Case 1
When we encounter a syntax type equal to that of Non_Terminating character. Therefore we must look in the function hashmap for the function associated with the character returning the fucntion we found.
Case 2
In the event that the reader encounters a character not contained within the Standard Readtable array, then we must search for the character within the Unicode Block we will then store this character and its associated type in the exception hash map. The solution for this problem may be found by defining a method similar to the "of" method used in the Character.Subset class.
Combining these attributes of a
ReadTable with the necassary functionality described in the Hyperspec
Readtable we can begin to define an interface for the
ReadTable.
Interface ReadtableInterface
The following is a Readtable Interface which will define the methods available to
TheReader and Lisp Programmer for access to the readtable.
package lisp.common;
public interface Readtable extends Atom {
/**
* This is the Java definition of the Lisp type READTABLE
*/
public static final Symbol Readtable = (Symbol)lisp.common.Package.CommonLisp.intern("READTABLE").get(0);
public class Factory{
public static final Readtable newInstance(){
Readtable rtnTable = new lisp.system.reader.ReadtableImpl();
//initializes the dispatch macro functions.
rtnTable.initialize();
return rtnTable;
}
}
/**
* An inner class that defines the Syntax Types of characters
*/
public class SyntaxType {
public static final SyntaxType CONSTITUENT = new SyntaxType("CONSTITUENT");
public static final SyntaxType NON_TERMINATING = new SyntaxType("NON_TERMINATING");
public static final SyntaxType TERMINATING = new SyntaxType("TERMINATING");
public static final SyntaxType WHITESPACE = new SyntaxType("WHITESPACE");
public static final SyntaxType INVALID = new SyntaxType("INVALID");
public static final SyntaxType SINGLE_ESCAPE = new SyntaxType("SINGLE_ESCAPE");
public static final SyntaxType MULTIPLE_ESCAPE = new SyntaxType("MUTIPLE_ESCAPE");
private java.lang.String name;
/** Creates a new instance of Readtable */
private SyntaxType(java.lang.String name) {
this.name = name;
}
public java.lang.String toString() {
return name;
}
}
/**
* This method overides the Java clone method. Returns this instance of
* the Readtable. Some precautions should be taken when using this method
* to ensure that this implementation reacts appropiately. That is to say
* that it is not yet known if any unintended side-effects will occur
* until thourgh testing can be performed.
* @return Object
*
*/
public Object clone() ;
/**
* This method overides the Java equals method for comparing Readtable
* objects. The Object passed in as an argument is tested for being of
* type Readtable. If it is not of type Readtable false is returned,
* otherwise the boolean equality of the two objects attibutes are returned.
*
* @return boolean
*
*/
public boolean equals(Object obj);
/**
* This method returns the Readtable associated with its char
* arguments.
*
* @return Readtable
* @param rootChar
*
*/
public Readtable getDispatchMacroCharacter(char rootChar);
/**
* This method returns the Function2 associated with its argument.
*
* @return Function2
*/
public Function2 getMacroCharacter(char c);
/**
* This method returns the readtableCase of the current Readtable
*
*/
public Symbol getReadtableCase();
/**
* This method returns the SyntaxType associated with its argument.
*
* @return SyntaxType
* @param aChar
*
*/
public SyntaxType getSyntaxType(char aChar);
/*
* This method overides the java.lang.hashCode method.
* It is imperative and good practice to always overide hashCode when
* also overidding java.lang.equals method.
*/
public int hashCode();
public void initialize();
/** This method returns true if the char arg character value is larger than
* ARRAYLENGTH, returns false otherwise.
* @param charC
*/
public boolean isOutOfBounds(char charC);
/**
* This method makes the SyntaxType associated with its argument
* equal to TERMINATING if is a NON_TERMINATING SyntaxType or
* it makes the SyntaxType equal to NON_TERMINATING if it is a Terminating
* SyntaxType.
*
* @return boolean
*/
public boolean makeDispatchMacroCharacter(char c, boolean nonTerminatingP);
/**
* This method sets the dispatingMacroCharacter to the newFunction argument
* and executes this function when the rootchar is read followed by the
* subchar. If the subChar is lowercase it is converted to uppercase. It
* is an error for the subChar represents a decimal char between 0-9.
*
* @return lisp.common.Symbol or
* SIMPLY RETURNS NULL WHEN DECIMAL ENCOUNTERED. TBD
*
*/
public void setDispatchMacroCharacter(char rootChar, char subChar, Function2 newFunction);
/**
* This method causes char to be a macro character associated with the
* reader macro function newFunction (or the designator for newFunction)
* in readtable. If Non-Terminating SyntaxType is true, char becomes a
* Non-Terminating macro character; otherwise it becomes a Terminating
* macro character.
*
* @return lisp.common.Symbol
*/
public void setMacroCharacter(char newFunctionChar, lisp.common.Function2 func);
/**
* This method setSyntaxFromChar copies the syntax types of fromChar.
* If fromChar is a macro character, its reader macro function is copied
* also. If the character is a dispatching macro character, its entire
* dispatch table of reader macro functions is copied. The constituent
* traits of fromChar are not copied.
*
* A macro definition from a character such as " can be copied to another
* character; the standard definition for " looks for another character
* that is the same as the character that invoked it. The definition of
* ( can not be meaningfully copied to {, on the other hand. The result is
* that lists are of the form {a b c), not {a b c}, because the definition
* always looks for a closing parenthesis, not a closing brace.
*
* @return boolean
*/
public void setSyntaxFromChar(char fromChar, char toChar);
/**
* This method makes the syntax of toChar in toReadtable be the same as
* the syntax of fromChar in fromReadtable.
*
* A macro definition from a character such as " can be copied to another
* character; the standard definition for " looks for another character
* that is the same as the character that invoked it. The definition of
* ( can not be meaningfully copied to {, on the other hand. The result is
* that lists are of the form {a b c), not {a b c}, because the definition
* always looks for a closing parenthesis, not a closing brace.
*
* @return boolean
*/
public void setSyntaxFromChar(char fromChar, char toChar, Readtable fromReadtable);
/** This method sets the readtableCase of the current Readtable
* The standard Readtable will be "UPCASE".
* @param sym
*/
public void setReadtableCase(Symbol sym);
/*
* This method overides the java.lang toString method. Simply returns the
* contents of the the readtable. These contents are functions, exception
* characters, and the Standard Lisp Syntax types.
*
*
*/
public java.lang.String toString();
}
References
Implementation
Details of implementation
Discussions
Links to Blog issues
Test Suites
Links to JUnit results
--
JerryBoetje - 11 Jul 2003