首页 > 解决方案 > 如何使用访客解析 ANTRL 语法树以提供自定义对象

问题描述

我目前面临这个问题:我正在使用 ANTLR 使用 ANTLR 提供的语法解析 terraform 文件,并希望为语法树的每个分支创建自定义对象。例如 : 在此处输入图像描述

我想采用 subTree 提供者并制作一个包含以下属性的对象 TerraformProvider :

对于这样的目的,我创建了一个 TerraformVisitor 类:

using Antlr4.Runtime.Misc;
using ANTLRch1.tmptest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ANTLRch1.terraformObjects;
using Antlr4.Runtime.Tree;

namespace ANTLRch1
{
    public class TerraformVisitor: terraformBaseVisitor<string>
    {

        public List<TerraformProvider> Providers = new List<TerraformProvider>();

        public override string VisitChildren([NotNull] IRuleNode node)
        {
            props.Add(node.GetText(), node.GetText()); 
            return base.VisitChildren(node);
        }

        public override string VisitProvider([NotNull] terraformParser.ProviderContext context)
        {
            string id = context.GetText();
            string value = context.PROVIDER().GetText();
            props.Add(id, value);
            var x = base.VisitChildren(context);
            Console.WriteLine(props);
            return base.VisitProvider(context);
        }

        public override string VisitResource([NotNull] terraformParser.ResourceContext context)
        {
            string id = context.GetText();
            return base.VisitResource(context);
        }

        public override string VisitVariable([NotNull] terraformParser.VariableContext context)
        {
            string id = context.GetText();
            string value = context.VARIABLE().GetText();
            return base.VisitVariable(context);
        }

        public override string VisitFile_([NotNull] terraformParser.File_Context context)
        {
            return base.VisitFile_(context);
        }

        public override string VisitBlockbody([NotNull] terraformParser.BlockbodyContext context)
        {
            string id = context.GetText();
            return base.VisitBlockbody(context);
        }

        public override string VisitArgument([NotNull] terraformParser.ArgumentContext context)
        {
            var c = context.GetType();
            string id = context.GetText();
            return base.VisitArgument(context);
        }

        public override string VisitIdentifier([NotNull] terraformParser.IdentifierContext context)
        {
            string id = context.GetText();
            return base.VisitIdentifier(context);
        }

        public override string VisitVal([NotNull] terraformParser.ValContext context)
        {
            string id = context.GetText();
            return base.VisitVal(context);
        }

        public override string VisitResourcetype([NotNull] terraformParser.ResourcetypeContext context)
        {
            string id = context.GetText();
            return base.VisitResourcetype(context);
        }



    }
}

但我不确定如何处理对象的创建,因为例如变量与提供者等具有共同的元素。

非常感谢您的帮助 谢谢

标签: c#parsingantlr4

解决方案


您可以跟踪当前正在创建的对象类型,但随后您需要检查类型并有条件地处理每个节点。

一种想法是使用多个访问者。您不必为所有树处理使用同一个访问者。

对于您的示例,也许您创建了一个TerraformVisitor处理高级构造的 a,然后您可以(使用您的示例) aProviderVisitor处理 Provider 节点的子节点,以及 aVariableVisitor处理 Variable 节点的子节点。

这种方法将保持混乱,并允许您处理不同访问者的不同上下文。

注意:这适用于访问者,因为您可以控制访问哪些孩子以及使用哪些访问者访问他们。对于Listeners,整个树都会和Listener一起走(你可以用Listener来走子树,但它会走整个子树)


推荐阅读