Хорошо, возвращаясь к моему обычному примеру грамматики калькулятора:)
Так вы бы объявили свой класс Tree Walker
class CalcTreeShaker extends TreeParser;
expr returns [float r]
{
float a,b;
r=0;
}
: #(PLUS a=expr b=expr) {r = a+b;}
| #(STAR a=expr b=expr) {r = a*b;}
| i:INT {r = Convert.ToSingle(i.getText());}
;
Здесь у нас есть правило дерева под названием expr
. Ходоки деревьев очень похожи на грамматики синтаксического анализатора.
Большая разница в том, что хотя грамматика синтаксического анализатора должна точно соответствовать грамматике дерева, она должна соответствовать только части дерева.
В правиле expr
мы видим, что оно соответствует любому дереву с токенами PLUS
или STAR
или INT
.
Мы можем видеть, что мы сопоставляем деревья, потому что мы используем синтаксис Antlr Tree #(...)
.
Дерево PLUS
и STAR
также соответствует 2 правилам expr. Каждому правилу expr присваивается имя, поэтому мы можем использовать его для оценки выражения. Подобно грамматикам синтаксического анализатора, мы можем поместить код C # в блоки defiend на {...}
.
Также обратите внимание, что в этом примере мы показываем, как вернуть значение из правила TreeWalker, мы используем синтаксис return [...]
.
Чтобы вызвать дерево, вы создаете его, а затем называете его правилом верхнего уровня. Я скопирую это из примера Antlr:)
// Get the ast from your parser.
CommonAST t = (CommonAST)parser.getAST();
// Create the Tree Shaker
CalcTreeWalker walker = new CalcTreeWalker();
CalcParser.initializeASTFactory(walker.getASTFactory());
// pass the ast to the walker and call the top level rule.
float r = walker.expr(t);