| # The `balicomposer` Tool

The `balicomposer` tool is a command-line application that composes `Bali` grammar files into a single `Bali` grammar file. Generally, the `composer` will automatically invoke `balicomposer` when Bali grammar files (with a `.b` extension) are specified as operands, but this document describes how `balicomposer` can be invoked directly. It briefly describes how `Bali` grammars are composed. The reader should be familiar with the Bali language documentation and the HowTo guide.

- Invoking `balicomposer`
- Generated Output
- Example (with Generated Output!)

## Invoking `balicomposer`

The `balicomposer` tool accepts one or more Bali grammar files as inputs and it produces a single Bali grammar file as output. The form of the generated output is described in the next section. For now, we describe only the command invocation.

Suppose there are two Bali input grammars to be composed named, respectively, `expression.b` and `statement.b`. The result of the composition is to be placed into `grammar.b`. This can be accomplished with the following command:

> `balicomposer expression.b statement.b -output grammar.b`

That's all there is to it! This produces a new grammar file in `grammar.b`. In general, there can be as many input grammar files as desired, but there are no other options possible. As a preferred alternative, the `composer` could also be invoked to perform the same composition. When using the `composer`, the command invocation is:

> `composer expression.b statement.b --target=grammar.b`

The two invocations are semantically equivalent.

## Generated Output

A Bali grammar defines a set of symbols, both terminal symbols and non-terminal symbols. Composing Bali grammars modifies the definitions by merging non-terminal definitions and by overriding terminal definitions.

Terminal symbols. For example, suppose we have a base grammar `base.b` that defines terminal symbol `REQUIRE` to be "`require`" and that a refinement grammar `refine.b` defines it to be "`import`". Then the composition of `base.b` and `refine.b`, in that order, outputs a definition of `REQUIRE` with value "`import`". Reversing the order of composition outputs the other definition. Notice that the order of composition is important!

Non-terminal symbols. Non-terminal symbols are rule names and composing them is a little more complex. First, we'll eliminate the easy cases: It's illegal to compose complex lists and simple lists! That leaves only named productions and sub-productions that can be composed.

A named production is a production of a non-terminal that has an assigned name. When composing productions of such a non-terminal, a later version of a named production overrides any earlier versions. For example, suppose we have the following named productions:

> In `base.b`: | `If : "if" Test ThenClause :: IfNode ;`
> In `refine.b`: | `If : "if" Test ThenClause [ElseClause]:: IfNode ;`

Then, the composition of `base.b` and `refine.b` will result in the second named production being placed into the definition of non-terminal `If` in the output grammar:

>     If : "if" Test ThenClause [ElseClause]:: IfNode ;

Finally, sub-productions of the same non-terminal symbol are simply combined with a set union. For example, suppose we have the following sub-productions:

> In `base.b`: | `Statement : If | Require ;`
> In `refine.b`: | `Statement : While ;`

Then the composition of `base.b` and `refine.b` will define `Statement` with three sub-productions as shown below:

>     Statement : While | If | Require ;

The order of the merged sub-productions is arbitrary.

## Example (with Generated Output!)

This section expands on the examples from the previous section. Again, we have two input grammar files, `base.b` and `refine.b`. These two files are shown below:

> `base.b` | `refine.b`
> --- | ---
>     TOKEN : {
>         <IDENTIFIER : <LETTER> (<LETTER> | <DIGIT>)*>
>         | <#LETTER: ["a"-"z", "A"-"Z"]>
>         | <#DIGIT: ["0"-"9"]>
>     }

>     "require" REQUIRE

>     Statement : If | Require ;
>     If : "if" Test ThenClause :: IfNode ;
>     Test : "(" IDENTIFIER ")" :: TestNode ;
>     ThenClause : "{" Statement "}" :: ThenNode ;
>     Require : REQUIRE IDENTIFIER :: RequireNode ;
>     require Statement, Test, ThenClause ;

>     "import" REQUIRE

>     Statement : While ;
>     If : "if" Test ThenClause [ElseClause] :: IfNode ;
>     ElseClause : "else" ThenClause :: ElseNode ;
>     While : "while" Test ThenClause :: WhileNode ;

Notice that those non-terminals that are referenced but not defined in `refine.b` are specified with a `require` statement! This is not strictly necessary, but can be helpful when debugging. Now, we compose these two files with the following command:

> `balicomposer base.b refine.b -output grammar.b`

The result is shown below. Notice that several empty sections are automatically inserted by `balicomposer`. This is harmless, though it does unnecessarily increase the size of the output file.

> `grammar.b`
>     // Automatically generated Bali code.  Edit at your own risk!
>     // Generated by "balicomposer" v2003.02.17.

>     //-----------------------------------//
>     // Option block:
>     //-----------------------------------//

>     // No options blocks in Bali grammar.

>     //-----------------------------------//
>     // Parser code block:
>     //-----------------------------------//

>     code {} code

>     //-----------------------------------//
>     // Token manager declarations:
>     //-----------------------------------//

>     // No TOKEN_MGR_DECLS defined in Bali grammar.

>     //-----------------------------------//
>     // Bali tokens:
>     //-----------------------------------//

>     "import"        	REQUIRE

>     //-----------------------------------//
>     // Regular expression tokens:
>     //-----------------------------------//

>     TOKEN: {
>         <IDENTIFIER : <LETTER> (<LETTER> | <DIGIT>)*>
>         |  <#LETTER: ["a"-"z", "A"-"Z"]>
>         |  <#DIGIT: ["0"-"9"]>
>     }

>     //-----------------------------------//
>     // Java code blocks:
>     //-----------------------------------//

>     // No JAVACODE blocks in Bali grammar.

>     //-----------------------------------//
>     // Bali productions:
>     //-----------------------------------//

>     Statement
>     	: While
>     	| If
>     	| Require
>     	;

>     ElseClause
>     	: "else" ThenClause :: ElseNode
>     	;

>     If
>     	: "if" Test ThenClause [ElseClause] :: IfNode
>     	;

>     Require
>     	: REQUIRE IDENTIFIER :: RequireNode
>     	;

>     Test
>     	: "(" IDENTIFIER ")" :: TestNode
>     	;

>     ThenClause
>     	: "{" Statement "}" :: ThenNode
>     	;

>     While
>     	: "while" Test ThenClause :: WhileNode
>     	;

ATS Home Page

Copyright © Software Systems Generator Research Group. All rights reserved.
Last modified: Thu May 1 13:01:00 CDT 2003