Morph grammars

Skip to end of metadata
Go to start of metadata

Grammar syntax

ANTLRMorph grammar follows the format of ANTLR grammar except several definitions:

  1. There's no tokens definition in morph, instead we use labels definition to set up label reference for token or rule.
  2. Options definition has the same syntax as ANTLR, but different option setting. conforms is the only option morph accepts currently.
  3. No global scope definition in morph.
  4. No lexer header definition. Therefore, if you're using a package setting, just put it once into the header definition.

/** This is a morph script comment */
morph grammar_name;
options { name1 = value; name2 = value2; ... }
labels { label1 = token-name1; label2, label3 = token-name2; ... }
@header {...}
@members {...}

«morph-rules»

Please check Morph grammar options and actions for more detail.

Rule syntax

There are several distinct characteristics in morph rule definition:

  1. Unique grammatical context syntax.
  2. No grammar options.
  3. Morph rule has dynamic scope which is able to refer to elements with the stack of rules context.
  4. Only accept initial action block currently.
  5. No catch and finally definitions

/** morph rule comment */
grammatical-context    // the basic form is just a rule-name
scope {...}
@init {...}
    : «input-pattern-1» -> «output-pattern-1»
    | «input-pattern-2» -> «output-pattern-2»
    ...
    | «input-pattern-n» -> «output-pattern-n»
    ;

Grammatical context

ANTLRMorph allows you define rewrite alternatives in the context of the specified rule context. The context here means that which rule you're matching. Therefore, you can utilize it to do something different based on different context. For instance, you might have to rewrite something different for variable declarations matched at block level (locals) and for variable declarations matched in methods (parameters) and default rewrite for variables:

/** in context of the following rules, match left side, rewrite to right side */
[block ... variable]: // context is local
    type ID -> rewrite1

[func variable]: // context is func local
    type ID -> rewrite2

variable: // in context of variable (default, be careful of the order)
    type ID -> rewrite3

In the above example, please note that you have to put the context variable after the other two because the morph rule specified first would be given precedence over those specified later. To avoid ambiguity, morph is implemented by a simple law: winner is always the one matched first.

Grammatical context syntax

[rule-name-1 rule-name-2 ... -rule-name-n]

  • "..." here is a keyword which means anything on the rule invocation stack.
  • if you would like to match input in the context of single rule:[rule-name], just use the basic form: rule-name

Dynamic scope

ANTLRMorph implements its dynamic scope within a parse tree structure instead of a stack used in ANTLR. The syntax and the usage of dynamic scope are same as those in ANTLR grammar. However, morph provides you a 2-way reference of scope attributes in the parse tree. In other words, morph can not only search attributes downward until reaching the bottom of tree but also do searches upward until reaching the top of tree. We'll address this more in the other section.

rule-name
scope {
    type1 attribute-name1;
    type2 attribute-name2;
}
...

Remember to initialize your scope attributes in the @init block if necessary. Also note that when you're using the scope attributes in the action blocks including @init block, you must use the form $rule-name::attribute-name to access the scope attributes you've set up within the scope block.

Rule alternatives

Each rule alternative contains an input pattern and an output pattern. ANTLRMorph takes the token stream matched on the input pattern, and prepares those matched elements for the attributes of the template defined by the output pattern. Currently, morph generates text instead of a token stream; therefore, the grammar output pattern would actually be a StringTemplate.

Labels: