关于ANTLR的通用库的需求:使用反射来构建元模型

我是一名语言工程师:我使用多种工具来定义和处理语言。 在其他工具中,我使用ANTLR:它简单,灵活,可以围绕它进行构建。

但是,我发现自己围绕ANTLR为不同的项目重建了类似的工具。 我看到两个问题:

  • ANTLR是一个非常好的构建基块,但是仅使用ANTLR并不能做很多事情:价值在于我们可以在AST上进行的处理,而且我看不到ANTLR周围的图书馆生态系统
  • ANTLR不会产生语法的元模型:没有它,就很难围绕ANTLR构建通用工具

让我解释一下:

  • 对于具有EMF经验的人:我们基本上每个语法都需要一个Ecore等效项。
  • 对于其他:请阅读下一段

为什么我们需要一个元模型

假设我想构建一个通用库,以通过ANTLR生成的AST生成XML文件或JSON文档。 我该怎么办?

好吧,给定一个ParseRuleContext,我可以获取规则索引并找到名称。 我为Python语法生成了解析器,并提供了一些示例,因此,让我们看一下如何使用实际的类:

Python3Parser.Single_inputContext astRoot = pythonParse(...my code...);
String ruleName = Python3Parser.ruleNames[astRoot.getRuleIndex()];

让我们看一下类Single_inputContext:

public static class Single_inputContext extends ParserRuleContext {
    public TerminalNode NEWLINE() { return getToken(Python3Parser.NEWLINE, 0); }
    public Simple_stmtContext simple_stmt() {
        return getRuleContext(Simple_stmtContext.class,0);
    }
    public Compound_stmtContext compound_stmt() {
        return getRuleContext(Compound_stmtContext.class,0);
    }
    public Single_inputContext(ParserRuleContext parent, int invokingState) {
        super(parent, invokingState);
    }
    @Override public int getRuleIndex() { return RULE_single_input; }
    @Override
    public void enterRule(ParseTreeListener listener) {
        if ( listener instanceof Python3Listener ) ((Python3Listener)listener).enterSingle_input(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
        if ( listener instanceof Python3Listener ) ((Python3Listener)listener).exitSingle_input(this);
    }
}

我应该得到这样的东西:

<Single_input NEWLINES="...">
   <Simple_stmt>...</Simple_stmt>
   <Compund_stmt>...</Compunt_stmt>
</root>

好。 对我来说,看课并识别这些元素非常容易,但是我如何自动做到这一点呢?

反思,显然,您会思考。

是。 那行得通。 但是,如果我们有多个元素怎么办? 参加本课:

public static class File_inputContext extends ParserRuleContext {
    public TerminalNode EOF() { return getToken(Python3Parser.EOF, 0); }
    public List NEWLINE() { return getTokens(Python3Parser.NEWLINE); }
    public TerminalNode NEWLINE(int i) {
        return getToken(Python3Parser.NEWLINE, i);
    }
    public List stmt() {
        return getRuleContexts(StmtContext.class);
    }
    public StmtContext stmt(int i) {
        return getRuleContext(StmtContext.class,i);
    }
    public File_inputContext(ParserRuleContext parent, int invokingState) {
        super(parent, invokingState);
    }
    @Override public int getRuleIndex() { return RULE_file_input; }
    @Override
    public void enterRule(ParseTreeListener listener) {
        if ( listener instanceof Python3Listener ) ((Python3Listener)listener).enterFile_input(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
        if ( listener instanceof Python3Listener ) ((Python3Listener)listener).exitFile_input(this);
    }
}

现在,方法NEWLINEstmt返回列表。 您可能还记得,一般而言,泛型在Java的反射中不能很好地工作。 在这种情况下,我们很幸运,因为有一个解决方案:

Class clazz = Python3Parser.File_inputContext.class;
Method method = clazz.getMethod("stmt");
Type listType = method.getGenericReturnType();
if (listType instanceof ParameterizedType) {
    Type elementType = ((ParameterizedType) listType).getActualTypeArguments()[0];
    System.out.println("ELEMENT TYPE "+elementType);
}

这将打印:

元素类型类me.tomassetti.antlrplus.python.Python3Parser $ StmtContext

因此,我们也可以介绍泛型。 好的,使用反射并不理想,但是我们可以从中提取一些信息。

我不是100%肯定会足够,但是我们可以开始。

元模型应该如何?

为了定义元模型,我不会尝试任何幻想。 我将使用基于EMF的经典模式,该模式类似于MPS中提供的模式。

我将添加一种名为PackageMetamodel的容器。 中将列出几个实体。 我们也可以将其中一个实体标记为实体。

每个实体将具有:

  • 一个名字
  • 可选的父实体(从其继承属性和关系)
  • 属性列表
  • 关系清单

每个属性将具有:

  • 一个名字
  • 从原始类型中选择的一种类型。 实际上,我希望只使用String和Integers。 将来可能枚举
  • 多重性(1个或多个)

每个关系将具有:

  • 一个名字
  • 种类: 包含引用 。 现在,AST只知道容器 ,但是稍后我们可以实现符号解析和模型转换,在那个阶段我们将需要引用
  • 目标类型:另一个实体
  • 多重性(1个或多个)

下一步

我将开始构建一个元模型,然后再利用该元模型来构建通用工具。

通常还需要执行其他操作:

  • 转换:我通常从ANTLR获得的AST是由我如何表达语法以获取可解析内容的方式决定的。 有时我还必须进行一些重构以提高性能。 我想在解析后转换AST,以更接近语言的逻辑结构。
  • 取消编组:我想从AST进行测试
  • 符号解析:这绝对不是一件容易的事,因为我发现为Java构建符号求解器

是的,我知道有些人在想: 只需使用Xtext即可 。 虽然我喜欢EMF(Xtext建立在它上面),但它的学习曲线陡峭,我看到很多人对此感到困惑。 我也不喜欢OSGi在非OSGi世界中的表现。 最终,Xtext带有很多依赖项。

别误会:我认为Xtext在许多情况下都是一个了不起的解决方案。 但是,有些客户更喜欢精简的方法。 对于有意义的情况,我们需要一种替代方法。 我认为它可以建立在ANTLR之上,但是还有很多工作要做。

几年前,我为.NET构建了类似的东西,并将其称为NetModelingFramework

翻译自: https://www.javacodegeeks.com/2016/05/need-generic-library-around-antlr-using-reflection-build-metamodel.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值