Finally, the AJ Specialty: TaskDeclaration
So, we finally reach TaskDeclaration--our very own addition to AJ.
In the discussion of ClassDeclaration above, we mentioned that the
reference to TaskDeclaration is not equipped with
any semantic action--thus relegating responsibility for code generation
to the rule itself, as described below.
The semantic action for TaskDeclaration is spread over four
locations, as described below. The first location is the rule's root node itself
(as in Figure 12), and the code here helps to define required variables.

Figure 12. Semantic action for TaskDeclaration root node
The second location is the node IDENTIFIER (as in Figure 13),
and that code helps to capture the name of the task being defined. (The
$$, used in Figures 13 and 14, translates into
a type-safe value notation for the current token.)

Figure 13. Semantic action for the IDENTIFIER node of TaskDeclaration
The third location is the node INT (as in Figure 14), and the
associated code helps to capture the priority value.

Figure 14. Semantic action for the INT node of TaskDeclaration
The fourth (and last) location is the node BlockStatement, as depicted in
Figure 15.
The code in this semantic action uses the information gathered by the preceding
sibling nodes, and uses all of it to instantiate a java.lang.Thread object
(with the task's name) to run the code in the BlockStatement within its
run() method.

Figure 15. Semantic action for the BlockStatement node of TaskDeclaration
Careful application of the principles described above (the function and use of %%,
$B$, and $Z$) will help you understand the text transformation performed by
this semantic action. The following two code snippets illustrate the transformation
of task blocks.
/*
* Sample input task code
*/
task incrAge priority 5 {
while (true) {
age += 10;
try {
Thread.sleep( 3000 );
} catch (Exception e) {}
}
}
/*
* Generated (plain Java) output code
*/
private Thread incrAge = new Thread() {
public void run() {
Thread.currentThread().setPriority( 5 );
while (true) {
age += 10;
try {
Thread.sleep( 3000 );
} catch (Exception e) {}
}
}
The underlined portions of the output text are generated using information
directly obtained from the AJ source. The line
Thread.currentThread().setPriority( 5 );
is, of course, only generated if a priority value is explicitly provided in
the TaskDeclaration.
We're Ready to Test!
All that remains now is to generate, compile, and test the AJ compiler.
Generate the compiler by selecting the File -> Write code menu choice (which
should produce a file called AJ.java in the same directory as the
grammar file). Then use the Java compiler: javac AJ.java
(and remember to keep VisualLangLab.jar on the classpath). To make
sure that all's well with the grammar, use the file AJ.lkv from the
demos/AJ directory of the distribution. Finally, to test the compiler,
try to process the following AJ program (file aj00.aj in the
distribution).
/*
* Sample AJ program (aj00.aj)
*/
public class aj00 {
task aa {
for (int i = 0; i < 5; ++i) {
++count;
try {
Thread.sleep(2000);
} catch (Exception e) {}
}
}
task b priority 7 {
for (int i = 0; i < 10; ++i) {
System.out.println( count );
try {
Thread.sleep( 2000 );
} catch (Exception e) {}
}
}
int count = 0;
public static void main( String a[] ) {
aj00 me = new aj00();
me.aa.start();
me.b.start();
}
}
To process the file, use the command line java >aj00.java AJ -f aj00.aj
(with VisualLangLab.jar on the classpath). Note that the output has been
redirected to aj00.java, so that file receives the generated Java code, and
should be compiled (as a Java program:
javac aj00.java). Finally, running the program (using java aj00)
should produce the output shown below.
1
1
2
3
4
5
5
5
5
5
Life Beyond AJ
Java, and other third-generation languages,
are used as building blocks for solutions in a wide range of domains.
Since these languages do not support many domain-specific concepts,
the resulting code sometimes looks low-level, unintuitive, or
even contrived. The approach described here can be used to augment
programming languages (or create new ones) to produce more expressive
(and therefore more elegant, compact, and supportable) code.
For many situations, a simple tool (such as VisualLangLab) may be
adequate by itself. And for situations where it isn't, this article
should have provided a firm basis on which to build the capability
to use more sophisticated tools.
References
-
Programming Language Processors in Java, David A. Watt and Deryck F. Brown, Pearson Education (2000).
-
Modern Compiler Implementation in Java, A.W. Appel, Cambridge University Press (1997).
-
Compilers: Principles, Techniques and Tools, A.V. Aho, R. Sethi, and J.D. Ullman, Addison Wesley (1986).
Sanjay Dasgupta has been using Java for telecom applications since 1996 (after many years of using many different languages in many industries).