|
|||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Class Summary | |
Ignorespaces | This class provides an implementation for the primitive
\ignorespaces . |
Relax | This class provides an implementation for the primitive \relax . |
This package contains classes for the primitives which are mapped to Java code. Those primitives are implemented directly opposed to the implementation as macros.
The binding to the appropriate names is performed during initialization of the interpreter. The information may come from a configuration file or a format file.
The core primitives of
Executable primitives are those primitives which can be invoked in a left-hand-side context of the expansion. This is the case whenever the next top-level macro is treated. You can consider for example the treatment of the macro \def as such a case:
\def\abc{123}In this example \def is an executable primitive.
Executable code has to implement the interface Code
. Doing this directly is not
hard. Nevertheless the abstract base class AbstractCode
is provided
which contains default implementations for all methods already.
Thus only the interesting methods have to be overwritten.
In the simplest case only a constructor with one String argument and the method execute() has to be defined. Such an empty frame can be seen in the following example:
package my.package; import de.dante.extex.interpreter.context.Context; import de.dante.extex.interpreter.Flags; import de.dante.extex.interpreter.TokenSource; import de.dante.extex.interpreter.exception.InterpreterException; import de.dante.extex.interpreter.type.AbstractCode; import de.dante.extex.typesetter.Typesetter; class MyPrimitive extends AbstractCode { public MyPrimitive(final String name) { super(name); // initialization code -- if required } public boolean execute(final Flags prefix, final Context context, final TokenSource source, final Typesetter typesetter ) throws InterpreterException { // implement the execution behaviour here return true; } }
In the method execute() you have access to other components. This can be utilized to implement the desired functionality. The following parameters are provided:
Flags
prefixYou can even modify the flags passed to the method. Usually you should invoke prefix.clear() somewhere in your implementation when the prefix is not needed any more. If this method is omitted then the prefix is passed on to the next execution. This can be desirable if you want to implement a prefix primitive yourself.
Context
contextTokenSource
sourceThe token source can also be used to push tokens to the input stream to be read back in later. This feature is used when implementing expandable primitives.
Typesetter
typesetterThe return value indicates how to deal with prefix flags. The usual behaviour is to return true. This indicates that the flags should be cleared afterwards. For those primitives which modify the prefix flags the return value false must be used.
The primary way to register new macros is in the configuration file
used by
<define name="def" class="de.dante.extex.interpreter.primitives.macro.Def"/>
To add another primitive to
<define name="myPrim" class="my.package.MyPrimitive"/>Now you can invoke
extex -configuration config/myExTeX.xmlThis is enough. In the instance of
One extension provided with \javadef
is defined in one of the configuration files provided and
consult the documentation.
The implementing Java code for new primitives can signal abnormal
situations with the help of exceptions. The exceptions used should
be derived from InterpreterException
. RuntimeExceptions and Errors
or derived classes should not be used.
Localizer
is provided. See the documentation of this
class for details.
Assignments are a special kind of executable code. AbstractAssignment
is
provided. This class defines the method execute()
appropriately. The only task left is to overwrite the method
assign() to perform the assignment.
package my.package; import de.dante.extex.interpreter.contect.Context; import de.dante.extex.interpreter.Flags; import de.dante.extex.interpreter.TokenSource; import de.dante.extex.interpreter.exception.InterpreterException; import de.dante.extex.interpreter.type.AbstractAssignment; import de.dante.extex.typesetter.Typesetter; class MyAssign extends AbstractAssignment { public MyAssign(final String name) { super(name); // initialization code -- if required } public void assign(final Flags prefix, final Context context, final TokenSource source, final Typesetter typesetter ) throws InterpreterException { // implement the assignment here } }
The arguments of the method assign() are the same as the arguments of execute() described above. In contrast to the remarks made there it is not necessary to return something. The clearing of the flags is done in the abstract class automatically.
Some macros are expandable. This means that they can be used on the
right-hand-side of an invocation as well. This feature is expressed
by the interface ExpandableCode
. Since Java does not allow multiple inheritance
no abstract base class is provided.
To implement an expandable primitive it is sufficient to declare the interface for the class and implement the method expand(). This is sketched in the following example:
package my.package; import de.dante.extex.interpreter.contect.Context; import de.dante.extex.interpreter.Flags; import de.dante.extex.interpreter.TokenSource; import de.dante.extex.interpreter.exception.InterpreterException; import de.dante.extex.interpreter.type.AbstractCode; import de.dante.extex.interpreter.type.ExpandableCode; import de.dante.extex.typesetter.Typesetter; class MyExpandable extends AbstractCode implements ExpandableCode { public MyExpandable(final String name) { super(name); // initialization code -- if required } public boolean execute(final Flags prefix, final Context context, final TokenSource source, final Typesetter typesetter ) throws InterpreterException { // implement the execution behaviour here return true; } public void evaluate(final Flags prefix, final Context context, final TokenSource source, final Typesetter typesetter ) throws InterpreterException { // implement the evaluation behaviour here } }The parameters of evaluate() are ikdentical to those of execute(). But note, that the expected behaviour of evaluate() is that it does
Conditionals are special because they modify the flow of control.
In the macro programming language of
All neccesary actions are performed by the abstract base class
AbstractIf
. The only thing to do is to implement the method
conditional() which computes whether the then or the else
branch should be considered relevant. This is shown in the
following example:
package my.package; import de.dante.extex.interpreter.primitives.conditional.AbstractIf; import de.dante.extex.interpreter.contect.Context; import de.dante.extex.interpreter.Flags; import de.dante.extex.interpreter.TokenSource; import de.dante.extex.interpreter.exception.InterpreterException; import de.dante.extex.typesetter.Typesetter; class MyIf extends AbstractIf { public MyIf(final String name) { super(name); // initialization code -- if required } public boolean conditional(final Flags prefix, final Context context, final TokenSource source, final Typesetter typesetter ) throws InterpreterException { // implement the evaluation of the conditional here return result; } }The parameters are the same as the parameters for execute() described above.
Note that any conditional is expandable automatically. Thus it should not modify the context or the typesetter.
Several primitives of
The ability to be usable after \the is expressed with the
help of the interface Theable
. Thus it is enough for a primitive to implement this
interface if it needs to be usable after \the.
The following list contains some macros of
\advance | Advanceable |
\box | Boxable |
\count | CountConvertible |
\dimen | DimenConvertible |
\divide | Dividable |
\font | FontConvertible |
\multiply | Multiplyable |
\show | Showable |
\showthe | Theable |
\the | Theable |
|
|||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |