Почему input.TokenStream преобразуется в ноль? - PullRequest
2 голосов
/ 06 июля 2011

С помощью antlr я пытаюсь сделать TreeWalker для дерева следующим образом:

ввод: int x = 3

выход AST: ^(VARDEF int x 3)

Мой анализатор работает просто отлично и также генерирует AST, как показано выше, но всякий раз, когда я хочу разрешить что-либо из AST, например, с помощью $ variableType.text, всегда возникает исключение NullReferenceException в сгенерированном TreeWalker на C # 2.0.

Мой TreeWalker:

tree grammar SGLTreeWalker;
options {
    tokenVocab = SGL;
    language = 'CSharp2'; 
}

[...]

compilationUnit
    :   (statement)+
    ;

statement
    :   variableDefinitionList
    ;

variableDefinitionList
    :   ^(VARDEF variableType variableName expression) { Console.WriteLine($variableType.text); }
    ;
[...]

Проблемная часть, генерируемая правилом "variableDefinitionList", выглядит следующим образом:

Match(input, Token.UP, null);
Console.WriteLine(((variableType1 != null) ? input.TokenStream.ToString(
    input.TreeAdaptor.GetTokenStartIndex(variableType1.Start),
    input.TreeAdaptor.GetTokenStopIndex(variableType1.Start)) : null)); 

Оказывается, что input.TokenStream имеет значение null, поэтому он генерирует исключение NullReferenceException. Я читал, что это может произойти, если используемый TreeNodeStream не буферизован, но я использовал CommonTreeNodeStream, поэтому я думаю, что он должен быть буферизован. Вот код, который я использовал для фиксации AST:

[...]
SGLParser parser = new SGLParser(tStream);
CommonTree t = (CommonTree) parser.compilationUnit().Tree;
Console.WriteLine("; " + t.ToStringTree());
CommonTreeNodeStream  treeStream = new CommonTreeNodeStream(t);
SGLTreeWalker tw = new SGLTreeWalker(treeStream);
tw.compilationUnit();

Любая идея о том, почему input.TokenStream преобразуется в ноль, когда я просто хочу получить атрибут $variableType.text?

1 Ответ

2 голосов
/ 06 июля 2011

Это потому, что внутри грамматики дерева производственные правила возвращают TreeRuleReturnScope, у которого нет атрибута text (или метода GetText()).

Если вы хотите получить текст правила variableType, вам нужно явно вернуть string.

Демо:


SGL.g

grammar SGL;

options {
  language=CSharp2;
  output=AST;
}

tokens {
  VARDEF;
}

@parser::namespace { SGL }
@lexer::namespace { SGL }

public compilationUnit
  :  statement+ EOF
  ;

statement
  :  variableDefinitionList
  ;

variableDefinitionList
  :   variableType variableName '=' expression 
      -> ^(VARDEF variableType variableName expression)
  ;

variableType
  :  Type
  ;

variableName
  :  ID
  ;

expression
  :  Int
  ;

Type
  :  'int'
  |  'double'
  ;

Int
  :  '0'..'9'+
  ;

ID
  :  ('a'..'z' | 'A'..'Z')+
  ;

Space
  :  ' ' {Skip();}
  ;

SGLTreeWalker.g

tree grammar SGLTreeWalker;

options {
  tokenVocab=SGL;
  language=CSharp2; 
  ASTLabelType=CommonTree;
}

@namespace { SGL }

compilationUnit
  :  statement+
  ;

statement
  :  variableDefinitionList
  ;

variableDefinitionList
  :   ^(VARDEF variableType variableName expression) 
      {Console.WriteLine($variableType.txt);}
  ;

variableType returns [string txt]
  :  Type {$txt = $Type.text;} // note that `Type` is still a normal token! 
  ;

variableName
  :  ID
  ;

expression
  :  Int
  ;

И класс:

using System;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace SGL
{
  public class Test
  {
    public static void Main (string[] args)
    {
      ANTLRStringStream Input = new ANTLRStringStream("int x = 3");
      SGLLexer Lexer = new SGLLexer(Input);
      CommonTokenStream Tokens = new CommonTokenStream(Lexer);
      SGLParser parser = new SGLParser(Tokens);
      CommonTree t = (CommonTree) parser.compilationUnit().Tree;
      CommonTreeNodeStream  treeStream = new CommonTreeNodeStream(t);
      SGLTreeWalker tw = new SGLTreeWalker(treeStream);
      tw.compilationUnit();
    }
  }
}

производит следующий вывод:

int
...