我想在解析树中扩展或覆盖TerminalNode对象

时间:2015-02-10 21:06:55

标签: c# antlr4

我正在使用ANTLR4在C#中编写代码生成器。它工作正常,但我做的事情比TerminalNode更高,我认为应该在TerminalNode中处理。

现在,我有一个标识符规则,例如,可能具有GetText()值,“myCollection.First.Name”并且子终端节点为“myCollection”,“。”,“First”,“。 “,”名称“...... [请注意,我的域语言不是C#或Java或C ++ - 这是一种自定义语法。]

我目前正在执行从IdentifierContext到代码将操作的域模型的映射,我认为如果在TerminalNode级别完成该映射将更容易实现和理解,如下所示:

"myCollection" --> An identifier for an object that lives in the top level scope.
"." --> Descend into the scope of "myCollection".
"First" --> an identifier for an object that lives in "myCollection"'s scope
"." --> Descend into the scope of "First".
"Name" --> an identifier for an object that lives in "First"'s scope 

我一直无法找到这样做的方法,而且我还不确定创建自定义Token和TokenFactory是正确的方法。看起来似乎会放入词法分析器,它应该存在于解析器中。

帮助?

P.S。我有“The Definitive Antlr4 Reference”,所以虽然它似乎没有那么远,如果答案在那里,请给我一个指向它的指针?

1 个答案:

答案 0 :(得分:0)

好吧,虽然它不是我认为最好的方式,但由于需要的权宜之计,我通过创建自定义令牌和令牌工厂来实现这一点,如下所示:

在解析命名空间中,我创建了一个自定义标记:

public class VToken : CommonToken
{

    public IModelTreeNode ModelTreeNode;
    public bool IsRecognized;
    public string[] Completions;

    public VToken(int type, String text) : base(type, text)
    {
    }

    public VToken(Tuple<ITokenSource, ICharStream> source, int type,
        int channel, int start, int stop) : base(source, type, channel, start, stop)
    {
    }

    public override string ToString()
    {
        return "VToken : " + Text;
    }
}

然后我创建了一个自定义令牌工厂(也在解析命名空间中)

public class VTokenFactory : ITokenFactory
{
    public static readonly ITokenFactory Default = (ITokenFactory)new VTokenFactory();

    protected internal readonly bool copyText;

    public VTokenFactory(bool copyText)
    {
        this.copyText = copyText;
    }

    public VTokenFactory()
        : this(false)
    {
    }

    public virtual VToken Create(Tuple<ITokenSource, ICharStream> source, int type, string text, int channel, int start, int stop, int line, int charPositionInLine)
    {
        VToken myToken = new VToken(source, type, channel, start, stop)
        {
            Line = line,
            Column = charPositionInLine
        };

        if (text != null)myToken.Text = text;
        else if (this.copyText && source.Item2 != null) myToken.Text = source.Item2.GetText(Interval.Of(start, stop));
        return myToken;
    }

    IToken ITokenFactory.Create(Tuple<ITokenSource, ICharStream> source, int type, string text, int channel, int start, int stop, int line, int charPositionInLine)
    {
        return (IToken)this.Create(source, type, text, channel, start, stop, line, charPositionInLine);
    }

    public virtual VToken Create(int type, string text)
    {
        return new VToken(type, text);
    }

    IToken ITokenFactory.Create(int type, string text)
    {
        return (IToken)this.Create(type, text);
    }
}

最后,改变了解析器的创建方式如下:

VLexer lexer = new VLexer(input);
VTokenFactory factory = new VTokenFactory(); // <-- added
lexer.TokenFactory = factory;                // <-- added
CommonTokenStream tokens = new CommonTokenStream(lexer);
VParser parser = new VParser(tokens);

当我处理规则时,我通过以下方式访问新字段:

((VToken)context.children[0].Payload).Completions
((VToken)context.children[0].Payload).IsRecognized
((VToken)context.children[0].Payload).ModelTreeNode