The EEL Compiler Using Adaptive Object
Oriented Programming and Demeter/Java

Luis Blando

April 1997

Motivation

The Secure Internet Gateway System (SIGS) project at GTE Laboratories (now Verizon) has a component whose purpose is to perform validation of incoming requests from customers. These validations are generally simple, and have the form of: "field name must be always present", "field date must be a valid date type", "if field name is present, then field telephone_no must be also present", "field customer-id must be in the list of valid customer ids", etc. Traditionally, these 'edit rules' are buried in different parts of a COBOL, C, or C++ application, which make maintenance costs extremely high.

The case was made, therefore, to abstract the concept of "editing" and define a very simple, high-level language in which these validation rules can be expressed. In this way, business-analysts can write/debug the rules themselves, at a conceptual level.

In order for these 'high-level rules' to be performed, they need to be translated into some form the computer can understand. Therefore, the Edit Engine was built as a framework where these rules can be 'plugged-in'. In other words, the interfaces of the Rule objects (and all other objects in the system, for that matter), were defined at abstract layers so that specialization by subclassing can take place at a later stage. Still, a compiler from 'Edit Engine Language' to C++ was necessary.

The first such compiler was developed using the traditional lex/yacc tools, as well as C++. It took about 4 man-months to finish. Because of the way the code-generation phase works, this compiler generates inefficient code (and possibly incorrect code). For example, for a rule like:

    if (notempty(field1)) then (field1[1] == "A");     // EEL v1.0 used

the generated code will be of the form (C++ used):
        ...
        bool a = notempty(field1);
        bool b = field1[1] == 'A';
        if (a) return b;
        ...

Succinctly, the compiler makes a in-order traversal of the parse tree and generates code at every node, generating temporaries as it goes along, with the decision being made last in the process. Besides the performance penalties, this approach might generate incorrect code. For instance, the above piece of code would crash if field1 is indeed empty! (note: the compiler-support functions would thus have to take care of checking for validity of arguments to solve this problem)

Inception

After playing with Demeter/Java for a little while, and realizing the potential applicability of Demeter/Java's built-in parsing capabilities to this problem, I decided to rewrite the compiler from scratch. Management approval was obtained at this phase.

Elaboration

The following risks, separated in risk categories, were identified:

Planning

Because of the peculiar characteristics of this project, planning was based mostly in incremental acceptance of the EEL specification, followed by incremental code-generation, instead of the most common use-case based approach. A point can be made in that each micro-step can be considered a scenario into a generic use-case, but it's immaterial to this report.

The different phases I anticipated were:

With regards to schedule estimates, I really could not make any, since I had not seen/used the technology before. Nevertheless, if the project could be finished in the same or less time than what the first version took, it could be considered a success.
 

Construction

The Edit Engine Language

The EEL is tailored for doing field validations. Instead of presenting here a full version of a BNF grammar for it, Figure 1 shows an example of an actual validation file.

Each validation file contains one or more issue{...} blocks. For each issue, first a meta{...} set is presented and then a number of rulesets (set blah{...}) are described. Within a set, a number of rules are described. Metarules differ from simple rules in that they contain a do( <ruleset_list> ) statement at the end. Furthermore, metarules are always "if" commands. A rule definition is as follows:

Expressions can have a number of representations. There are several 'functions', such as in(...), notin(...), length(...), required(...), isdate(...), istime(...), etc, that make rule-writing simple. Data elements (i.e. form fields) are represented by a qualified pathname with the pattern: form[.form][.field]. Parts of fields are extracted using an index notation [a] or [a..b], where a is the first char and b the last to be taken into account (one-based).

The Edit Engine Framework

In order to understand the function of the EEL compiler, it is useful to review the Edit Engine framework, shown in Figure 2. The objects met001, met002, fld001, fld002, etc are those that have been instantiated from classes defined by the EEL compiler. The Rule class is an abstract superclass of all these generated classes which defines the interfaces they should support. There are two 'types' of rules in the system: meta rules (which direct the validation flow) and simple rules (which validate data on a form). Each class generated by the EEL compiler must support:

Edit Engine framework (runtime snapshot)

 Figure 2: Runtime snapshot of the Edit Engine framework.

The objects met001, met002, fld001, fld002, etc are the ones generated by the EEL compiler.

 

The Target Generated Code

In terms of the rules, we need both the .h and .cpp files that contain the classes declarations and definitions, respectively.

For rules E01METH00101 and E01FLDH00012 above, for instance, we would expect the following code generated in the header file.

For the .cpp file, we would want the following for the above rules:

Parsing EEL using Demeter/Java

In order to parse EEL using Demeter/Java, I created a class dictionary annotated with syntax. There were a number of problem points since EEL does not lend itself to LL(k) parsing very nicely. Nevertheless, the task was relatively simple. One important point was parsing of the low-level identifiers. Demeter/Java uses Ident as an identifier class. Unfortunately, Demeter/Java Idents do not allow dots in them, while EEL identifiers do. For this reason, I had to define a complete class structure to parse each 'piece' of an EEL identifier. While this was an annoyance, Demeter/Java's support for automatic traversals made it easier.

The complete class dictionary, heavily commented, follows:

Specifying the Behavior

In order to come up with the behavior, we create a .beh file in Demeter/Java language (a superset of Java). The eelc.beh file used in the EEL compiler follows. It is heavily commented and you can find different approaches to programming with traversals and visitors.