ANTLR прямые ссылки - PullRequest
       5

ANTLR прямые ссылки

1 голос
/ 18 ноября 2010

Мне нужно создать грамматику для языка с прямыми ссылками.Я думаю, что самый простой способ добиться этого - сделать несколько проходов по сгенерированному AST, но мне нужен способ хранения символьной информации в дереве.

Сейчас мой анализатор правильно генерирует AST и вычисляет областипеременные и определения функций.Проблема в том, что я не знаю, как сохранить информацию о области действия в дереве.

Фрагмент моей грамматики:

composite_instruction
scope JScope;
@init {
    $JScope::symbols = new ArrayList();
    $JScope::name = "level "+ $JScope.size();
}
@after {
    System.out.println("code block scope " +$JScope::name + " = " + $JScope::symbols);
}
    : '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*)
    ;

Я хотел бы поместить ссылку на текущую область вдерево, что-то вроде:

    : '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction* {$JScope::symbols})

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

1 Ответ

2 голосов
/ 18 ноября 2010

Насколько мне известно, синтаксис правил перезаписи не позволяет напрямую присваивать значения, как предполагает ваш предварительный фрагмент.Отчасти это связано с тем, что синтаксический анализатор не знал, к какой части дерева / узла следует добавить значения.

Однако одна из интересных особенностей созданных ANTLR AST - эточто синтаксический анализатор не делает никаких предположений о типе узлов.Нужно просто реализовать TreeAdapator, который служит фабрикой для новых узлов и навигатором древовидной структуры.Поэтому можно добавить любую информацию, которая может потребоваться в узлах, как описано ниже.

ANTLR обеспечивает реализацию узла дерева по умолчанию, CommonTree , и в большинстве случаев (как в текущей ситуации).) нам просто нужно

  • подкласс CommonTree, добавив в него некоторые пользовательские поля
  • подкласс CommonTreeAdaptor, чтобы переопределить его метод create (), то есть способ, которым он создает новые узлы.

но можно также создать новый тип узла altogher для какой-то нечетной структуры графа или еще чего-нибудь.Для рассматриваемого случая должно быть достаточно следующего (адаптировать для конкретного целевого языка, если это не Java)

import org.antlr.runtime.tree.*;
import org.antlr.runtime.Token;

public class NodeWithScope extends CommonTree {

    /* Just declare the extra fields for the node */
    public ArrayList symbols;
    public string    name;
    public object    whatever_else;

    public NodeWithScope (Token t) {
        super(t);
    }
}

/* TreeAdaptor: we just need to override create method */
class NodeWithScopeAdaptor extends CommonTreeAdaptor {
    public Object create(Token standardPayload) {
        return new NodeWithScope(standardPayload);
    }
}

Затем необходимо немного изменить способ запуска процесса синтаксического анализа, чтобыANTLR (или, точнее, созданный ANTLR синтаксический анализатор) знает, что нужно использовать NodeWithScopeAdaptor вместо CommnTree.
(шаг 4.1 ниже, остальное, если скорее стандартная тестовая установка ANTLR)

// ***** Typical ANTLR pipe rig  *****
//  ** 1. input stream 
ANTLRInputStream input = new ANTLRInputStream(my_input_file);
//  ** 2, Lexer 
MyGrammarLexer lexer = new MyGrammarLexer(input);
//  ** 3. token stream produced by lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
//  ** 4. Parser
MyGrammarParser parser = new MyGrammarParser(tokens);

//     4.1  !!! Specify the TreeAdapter
NodeWithScopeAdaptor  adaptor = new NodeWithScopeAdaptor();
parser.setTreeAdaptor(adaptor); // use my adaptor

//  ** 5. Start process by invoking the root rule
    r = parser.MyTopRule();
//  ** 6. AST tree
NodeWithScope  t = (NodeWithScope)r.getTree();
//  ** 7.  etc. parse the tree or do whatever is needed on it.

Наконец ваша грамматика будет иметьбыть приспособленным к чему-то похожему на то, что следует
(обратите внимание, что узел [для текущего правила] доступен только в разделе @after. Однако он может ссылаться на любой атрибут токена и другую контекстную переменную на уровне грамматики, используяобычная запись $ rule.atrribute)

composite_instruction
scope JScope;
@init {
    $JScope::symbols = new ArrayList();
    $JScope::name = "level "+ $JScope.size();
}
@after {
      ($composite_instruction.tree).symbols = $JScope::symbols;
      ($composite_instruction.tree).name    = $JScope::name;
      ($composite_instruction.tree).whatever_else
            = new myFancyObject($x.Text, $y.line, whatever, blah);
}
    : '{' instruction* '}' -> ^(INSTRUCTION_LIST instruction*)
    ;
...