2010-11-22 2 views
2

Я написал конфигурацию JJTree (JavaCC) для типа DSL, и она успешно выполняет токенизацию заданного формата файла и сбрасывает AST по запросу.Как использовать JavaCC/JJTree для хранения токенов?

Проблема в том, что каждый из узлов в дереве пуст, так как я в настоящее время не храню токены (я не могу понять примеры).

Вот часть моего .jjt файла:

SimpleNode Start() #Root : {} { 
    (
    (Section1())? 
    (Section2())? 
    (Section3())* 
) { 
    return jjtThis; 
    } 
} 

void Section3() #Section3 : {} 
{ 
    <SECTION_3> Identifier() <LBRACE > 
    Header() 
     (Details() <SEMICOLON>)* 
    <RBRACE> 
} 

Я хотел бы корневой узел для хранения ссылок на section1, section2 и список ссылок на раздел3. Я хотел бы, чтобы узел Section3 сохранил идентификатор, блок заголовка и сохранил список блоков данных.

My fill .jjt file - это сотни строк, но я чувствую, что, если я могу понять это для этих двух разделов, тогда я могу понять, как работает JJTree. Пожалуйста, дайте мне знать, как правильно использовать JJTree.

Спасибо.

ответ

2

Если вы посмотрите на класс SimpleNode, вы заметите, что его экземпляры автоматически сохраняют ссылки на родительский и дочерний узлы (если их создание не было подавлено с помощью #void). Например, ваш корневой узел будет содержать ссылки на 0..1 узлы Section1, 0..1 узлы Section2 и 0 .. * узлы Section3, и к ним можно получить доступ с помощью метода jjtGetChild(), который возвращает объект Node. Чтобы определить, является ли этот дочерний узел узлом Section1, Section2 или Section3, вы можете вызвать его метод toString() (как это делает dump()).

В качестве альтернативы, если вы устали от этого стиля наивной итерации узла и проверки toString, вы можете определить свои собственные типы узлов вместо того, чтобы полагаться на реализацию SimpleNode. В моем примере ниже Start() теперь возвращает пользовательский RootNode вместо простого SimpleNode. RootNode содержит определенные ссылки на его дочерние узлы (определите для них подходящие по мере необходимости). Обратите внимание, что в моем кратком фрагменте предполагается, что раздел 1/2/3() возвращает возвратные пользовательские узлы, но это не имеет в зависимости от того, что вы сказали, вам нужен пользовательский узел для Section3(), но если раздел 1/2 тривиален, вы можете оставить их как SimpleNodes.

RootNode Start() : 
{ 
    Section1Node s1Node = null; 
    Section2Node s2Node = null; 

    List s3Nodes = new LinkedList(); 
    Section3Node s3Node = null; 
} 
{ 
    (
    (s1Node = Section1())? 
    (s2Node = Section2())? 
    (s3Node = Section3() {s3Nodes.add(s3Node); })* 
) { 

    return new RootNode(s1Node, s2Node, s3Nodes); 
    } 
} 

Если вы обход вашего дерева разбора и делать сложные вещи с узлами, это может быть хорошей идея, чтобы переместить его в Visitor class, так что то, что вы делаете с вашими узлами отсоединен от сами классы узлов. Возможно, вы получите несколько классов посетителей, каждый из которых выполняет функцию в дереве разбора и перегружает метод метода для каждого типа узла.

Дайте мне знать, если что-то не поняли. Я не эксперт по JavaCC (я использовал его однажды в uni), но я должен быть в состоянии помочь вам :)

+0

Спасибо за информацию. Если возможно, вы можете показать мне, как обрабатывать этот пример без определения пользовательских классов узлов (как добавить поля для сохранения пользовательских токенов в уже существующих типах узлов JJTree)? То есть - дайте пример метода, который вы объясняете в первом абзаце. – Chris 2010-11-23 17:38:12