关于ANTLR的通用库的需求:使用反射来构建元模型
我是一名語言工程師:我使用多種工具來定義和處理語言。 在其他工具中,我使用ANTLR:它簡單,靈活,可以圍繞它進(jìn)行構(gòu)建。
但是,我發(fā)現(xiàn)自己圍繞ANTLR為不同的項(xiàng)目重建了類似的工具。 我看到兩個(gè)問題:
- ANTLR是一個(gè)非常好的構(gòu)建基塊,但是僅使用ANTLR并不能做很多事情:價(jià)值在于我們可以在AST上進(jìn)行的處理,而且我看不到ANTLR周圍的圖書館生態(tài)系統(tǒng)
- ANTLR不會(huì)產(chǎn)生語法的元模型:沒有它,就很難圍繞ANTLR構(gòu)建通用工具
讓我解釋一下:
- 對于具有EMF經(jīng)驗(yàn)的人:我們基本上每個(gè)語法都需要一個(gè)Ecore等效項(xiàng)。
- 對于其他:請閱讀下一段
為什么我們需要一個(gè)元模型
假設(shè)我想構(gòu)建一個(gè)通用庫,以通過ANTLR生成的AST生成XML文件或JSON文檔。 我該怎么辦?
好吧,給定一個(gè)ParseRuleContext,我可以獲取規(guī)則索引并找到名稱。 我為Python語法生成了解析器,并提供了一些示例,因此,讓我們看一下如何使用實(shí)際的類:
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);} }我應(yīng)該得到這樣的東西:
<Single_input NEWLINES="..."><Simple_stmt>...</Simple_stmt><Compund_stmt>...</Compunt_stmt> </root>好。 對我來說,看課并識(shí)別這些元素非常容易,但是我如何自動(dòng)做到這一點(diǎn)呢?
反思,顯然,您會(huì)思考。
是。 那行得通。 但是,如果我們有多個(gè)元素怎么辦? 參加本課:
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);} }現(xiàn)在,方法NEWLINE和stmt返回列表。 您可能還記得,一般而言,泛型在Java的反射中不能很好地工作。 在這種情況下,我們很幸運(yùn),因?yàn)橛幸粋€(gè)解決方案:
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%肯定會(huì)足夠,但是我們可以開始。
元模型應(yīng)該如何?
為了定義元模型,我不會(huì)嘗試任何幻想。 我將使用基于EMF的經(jīng)典模式,該模式類似于MPS中提供的模式。
我將添加一種名為Package或Metamodel的容器。 包中將列出幾個(gè)實(shí)體。 我們也可以將其中一個(gè)實(shí)體標(biāo)記為根實(shí)體。
每個(gè)實(shí)體將具有:
- 一個(gè)名字
- 可選的父實(shí)體(從其繼承屬性和關(guān)系)
- 屬性列表
- 關(guān)系清單
每個(gè)屬性將具有:
- 一個(gè)名字
- 從原始類型中選擇的一種類型。 實(shí)際上,我希望只使用String和Integers。 將來可能枚舉
- 多重性(1個(gè)或多個(gè))
每個(gè)關(guān)系將具有:
- 一個(gè)名字
- 種類: 包含或引用 。 現(xiàn)在,AST只知道容器 ,但是稍后我們可以實(shí)現(xiàn)符號(hào)解析和模型轉(zhuǎn)換,在那個(gè)階段我們將需要引用
- 目標(biāo)類型:另一個(gè)實(shí)體
- 多重性(1個(gè)或多個(gè))
下一步
我將開始構(gòu)建一個(gè)元模型,然后再利用該元模型來構(gòu)建通用工具。
通常還需要執(zhí)行其他操作:
- 轉(zhuǎn)換:我通常從ANTLR獲得的AST是由我如何表達(dá)語法以獲取可解析內(nèi)容的方式?jīng)Q定的。 有時(shí)我還必須進(jìn)行一些重構(gòu)以提高性能。 我想在解析后轉(zhuǎn)換AST,以更接近語言的邏輯結(jié)構(gòu)。
- 取消編組:我想從AST進(jìn)行測試
- 符號(hào)解析:這絕對不是一件容易的事,因?yàn)槲野l(fā)現(xiàn)為Java構(gòu)建符號(hào)求解器
是的,我知道有些人在想: 只需使用Xtext即可 。 雖然我喜歡EMF(Xtext建立在它上面),但它的學(xué)習(xí)曲線陡峭,我看到很多人對此感到困惑。 我也不喜歡OSGi在非OSGi世界中的表現(xiàn)。 最終,Xtext帶有很多依賴項(xiàng)。
別誤會(huì):我認(rèn)為Xtext在許多情況下都是一個(gè)了不起的解決方案。 但是,有些客戶更喜歡精簡的方法。 對于有意義的情況,我們需要一種替代方法。 我認(rèn)為它可以建立在ANTLR之上,但是還有很多工作要做。
幾年前,我為.NET構(gòu)建了類似的東西,并將其稱為NetModelingFramework 。
翻譯自: https://www.javacodegeeks.com/2016/05/need-generic-library-around-antlr-using-reflection-build-metamodel.html
總結(jié)
以上是生活随笔為你收集整理的关于ANTLR的通用库的需求:使用反射来构建元模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首孝悌是什么意思 首孝悌是啥意思
- 下一篇: soa学习路线_Web服务安全性和SOA