我想扩展或覆盖解析树中的 TerminalNode 对象
I would like to extend or override the TerminalNode object in a parse tree
我正在使用 ANTLR4 在 C# 中开发代码生成器。它有效,但我正在做一些比 TerminalNode 更高级别的事情,我认为应该在 TerminalNode 中处理。
现在,我有一个标识符规则,例如,它可能具有 GetText() 值 "myCollection.First.Name" 和 "myCollection"、“.”、[=25= 的子终端节点], ".", "Name" ... [请注意,我的领域语言不是 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
我一直无法找到执行此操作的方法,而且我不确定创建自定义令牌和 TokenFactory 是否是正确的方法。似乎这将放入词法分析器,应该驻留在解析器中的内容。
帮忙?
P.S。我有 "The Definitive Antlr4 Reference,",虽然目前还没有,但如果答案在那里,请提供指向它的指针?
好吧,虽然这不是我认为的最佳方式,但出于权宜之计,我通过创建自定义令牌和令牌工厂来实现这一点,如下所示:
在解析命名空间中,我创建了一个自定义令牌:
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
我正在使用 ANTLR4 在 C# 中开发代码生成器。它有效,但我正在做一些比 TerminalNode 更高级别的事情,我认为应该在 TerminalNode 中处理。
现在,我有一个标识符规则,例如,它可能具有 GetText() 值 "myCollection.First.Name" 和 "myCollection"、“.”、[=25= 的子终端节点], ".", "Name" ... [请注意,我的领域语言不是 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
我一直无法找到执行此操作的方法,而且我不确定创建自定义令牌和 TokenFactory 是否是正确的方法。似乎这将放入词法分析器,应该驻留在解析器中的内容。
帮忙?
P.S。我有 "The Definitive Antlr4 Reference,",虽然目前还没有,但如果答案在那里,请提供指向它的指针?
好吧,虽然这不是我认为的最佳方式,但出于权宜之计,我通过创建自定义令牌和令牌工厂来实现这一点,如下所示:
在解析命名空间中,我创建了一个自定义令牌:
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