关于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; }@Overridepublic void enterRule(ParseTreeListener listener) {if ( listener instanceof Python3Listener ) ((Python3Listener)listener).enterSingle_input(this);}@Overridepublic 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; }@Overridepublic void enterRule(ParseTreeListener listener) {if ( listener instanceof Python3Listener ) ((Python3Listener)listener).enterFile_input(this);}@Overridepublic void exitRule(ParseTreeListener listener) {if ( listener instanceof Python3Listener ) ((Python3Listener)listener).exitFile_input(this);} }現在,方法NEWLINE和stmt返回列表。 您可能還記得,一般而言,泛型在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中提供的模式。
我將添加一種名為Package或Metamodel的容器。 包中將列出幾個實體。 我們也可以將其中一個實體標記為根實體。
每個實體將具有:
- 一個名字
- 可選的父實體(從其繼承屬性和關系)
- 屬性列表
- 關系清單
每個屬性將具有:
- 一個名字
- 從原始類型中選擇的一種類型。 實際上,我希望只使用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
總結
以上是生活随笔為你收集整理的关于ANTLR的通用库的需求:使用反射来构建元模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首孝悌是什么意思 首孝悌是啥意思
- 下一篇: 何伤乎翻译 何伤乎出处介绍