|
For Ver-10.10 or higher only! If you are using an older version, follow this tutorial instead. Beginning Ver-10.01, the title bar of the About VisualLangLab dialog box displays the version number. The latest jar file can be downloaded here: VLL4J.jar. |
The VisualLangLab API is used by client programs to load a grammar file (created in and saved by the VisualLangLab GUI), and create a parser from it. The API is written in Java, and may be used by client programs in any JVM language. The API is quite small and simple, and is best understood in the context of a real example. Using the API requires a good knowledge of the AST Structure and action-code design.
The rest of this article describes a compact example based on one of the sample grammars bundled with the VisualLangLab GUI. Another, somewhat larger, example can be found in Evaluating Expressions Using an AST.
The following example uses the API to load the PS2E-ArithExpr sample grammar (see Sample Grammars) into a client Java program. The grammar's top-level rule Expr is then fetched and applied to the string "(3 + 5) / (8 - 4)" to obtain an AST which is then interpreted to obtain the value of the expression. For better clarity, the program is organized as 4 functions with distinct roles:
main()
function loads the grammar from a file, fetches the top-level rule, and applies the
parser to the string. It checks the result, and in case of success passes the AST
to the function evalExprAST()evalExprAST() interprets the complete expression's ASTevalTermAST() interprets the AST produced by the
term ruleevalFactorAST() interprets the AST from the
factor rule
The main() function is shown first below.
The colored parts depend on the VisualLangLab API
as described after the code below.
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import vll4j.Vll4j;
public static void main(String[] args) throws
ParserConfigurationException, SAXException, IOException {
String input = "(3 + 5) * (8 - 4)";
Vll4j vll = Vll4j.fromFile(new File("PS2E-ArithExpr.vll"));
Vll4j.Parser exprParser = vll.getParserFor("Expr");
Vll4j.ParseResult parseResult = vll.parseAll(exprParser, input);
if (parseResult.successful()) {
Object ast = parseResult.get();
Float result = evalExprAST(ast);
System.out.println(result);
} else {
System.out.println(parseResult);
}
}
The colored parts are all dependent on the VisualLangLab API. The entities in red are entirely VisualLangLab specific, but those in blue follow the design of synonymous entities in the Scala parser combinator package. Although all of the API is implemented in Java, the design of a small part of the Scala API has been adapted to leverage the advantages of a proven, well-understood and documented design. The purpose and use of the entities highlighted above is explained in the table below:
| Entity | Description |
|---|---|
| Vll4j |
A class with capabilities like those of Scala's
Parsers
extended with
RegexParsers
and PackratParsers.
VisualLangLab's implementation of RegexParsers includes a simple
builtin lexical analyzer with sophisticated (although somewhat slow)
lexing capabilities far superior to those of the literal() and regex()
methods of RegexParsers. However, the API user does not have to know
anything about these Scala concepts at all. The API user will only need the features
discussed below:It also provides a set of utility ( static) methods,
like Vll4j fromFile(File) used above,
to load a grammar from various types of sources (File, String, etc.).The method Vll4j.Parser getParserFor(String) is used to fetch a parser for
a named rule. The above code uses it to fetch the parser for the rule ExprThe method Vll4j.ParseResult parseAll(Vll4j.Parser, String) is the API
user's primary workhorse.
The above code uses it to apply the parser for Expr to the string.
There are also other overloaded versions of this method that obtain input
from different types of sources (File, JTextComponent, etc.).
|
| Vll4j.Parser |
A class with capabilities like those of Scala's
Parser.
The API user may need to be aware of its Vll4j.ParseResult apply(Reader) method,
although responsibility for invoking it is usually relegated to Vll4j's
parseAll() method (as in the code above).
Most API users may never need to use any of its methods.
|
| Vll4j.ParseResult |
A class with capabilities like those of Scala's
ParseResult.
The API user only needs to be aware of the methods used in the code above The method boolean successful() tests the result of parsingThe method Object get() is used to extract the AST in case parsing succeeded.
|
Most API users will never need to use other features of the classes descrbed above.
More detailed information about the design of these classes can be obtained from
the hyperlinks (to the Scala API) given above.
The Java source-code of these classes (and other utility classes like Reader)
can be found in the vll4j.core package.
The main() function (above) passes the entire AST to another function.
The other functions shown below do not need the VisualLangLab API—they
merely process the AST (which contains standard Java/JVM data types).
The evalExprAST() function processes the entire AST (from main()).
The table below places the function's code alongside the AST structure to help you
understand the logic better.
| AST | Code |
|
|
|---|
The variable array on line-2 corresponds to the AST's outermost
layer (Array). Observe how the two elements of this array are used
in line-3 (to define the variable term), and on line-4
(within the for to iterate the contained list). The elements of the list
(each a 2-element array) are successively assigned to the variable
pair (in line-4). The first element of this array
is tested by the if (lines 5 and 7), and the second element of the
array is respectively used to add to or subtract from the running total.
As shown by the AST, this rule references rule term at two places,
so those portions of the AST must be handed off to another function
for further processing. That function evalTermAST() is described below.
The evalTermAST() function processes the AST of the rule term.
The table below places the function's code alongside the AST structure to help you
understand the logic better.
| AST | Code |
|
|
|---|
The AST of this rule (term) is structurally identical to the previous case (Expr),
so the code is also structurally identical.
The only difference is in the identity of the rule
(factor in this case) to which the sub-AST is handed off for further processing,
and the arithmetic operators (*= and /= in this case)
used for updating the cumulated value.
The evalFactorAST() function processes the AST of the rule factor.
The table below places the function's code alongside the AST structure to help you
understand the logic better.
| AST | Code |
|
|
|---|
The top-level of this AST is a Choice, meaning that one of the two array objects defined
in the Choice will be received. Line-2 of the code therefore assigns the AST as received
to pair which is an array of two Objects. It then proceeds to test the first
element of the array to help it to decide how to process the second element.
The last example above (funcion evalFactorAST()) makes it clear that
autoboxing
is at work on the API side. How else would an array of Object's carry an
integer? The API user should be aware of this and exploit Java's unboxing
capabilities appropriately.
To compile and run the code, proceed as follows.
main() function)
The program should print out 32 when run as-is. You should change the expression
parsed by the program (assigned to the variable input in the main()
function) to check out the parser completely.
It is sometimes required to completely embed all resources (including the grammar) within a program. A couple of options are available for this:
static Vll4j Vll4j.fromString(String) function. This
approach is convenient only for small grammarsgetResourceAsStream(String) method
to get an InputStream, and load the grammar by passing the
stream to the static Vll4j Vll4j.fromStream(InputStream)
function