首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 表達式語法 AST 解析器實作筆記

     編輯:Java 綜合教學

專案背景

自研表達式引擎,支援類似 new(Class).method(param).chain() 的鏈式調用語法,核心為 AstParser 將字串解析為抽象語法樹(AST)。

核心類:AstParser

package com.attilax.lang;

public class AstParser {
    private Object obj;  // 上下文物件,傳遞給各表達式
    private Object rzt;  // 最後一個表達式的結果

    public List<Object> getExprsLiAst(String code) {
        List<String> tokens = new JavaExpFsm(code).getTokens(); // 詞法分析
        List<Object> astList = new ArrayList<>();
        List<String> slice = new ArrayList<>();

        for (int i = 0; i < tokens.size(); i++) {
            String tk = tokens.get(i).trim();
            if (".".equals(tk)) { // 點號為表達式分隔符
                astList.add(buildExprs(slice));
                slice.clear();
                continue;
            }
            slice.add(tk);
            if (i == tokens.size() - 1) { // 最後一段
                astList.add(buildExprs(slice));
            }
        }
        return astList;
    }

    private Exprs buildExprs(List<String> slice) {
        Exprs e = new Exprs();
        e.method = slice.get(0); // new(...) 或 methodName
        if (slice.size() == 3) { // 無參數:method()
            e.params = new ArrayList<>();
        } else { // 有參數:method(p1, p2)
            e.params = slice.subList(2, slice.size() - 1); // 去掉 method ( )
        }
        return e;
    }

    public Object parse(List<Object> ast) {
        for (Object node : ast) {
            parseSingle(node);
        }
        return rzt;
    }

    private void parseSingle(Object node) {
        Exprs e = (Exprs) node;
        e.obj = this.obj; // 注入上下文
        this.rzt = e.calc(); // 執行表達式
        this.obj = e.obj; // 更新上下文(支援鏈式)
    }
}

關鍵設計點

  1. 有限狀態機分詞:JavaExpFsm 處理括號、引號、逗號、點號等,產出 Token 列表。
  2. 點號分割表達式:new(A).b().c(d) → 三個 Exprs 節點。
  3. 上下文傳遞:每個 Exprs 執行後更新 obj,實現 a.b().c() 鏈式調用。
  4. 參數解析:簡單按逗號分割,未處理巢狀結構,適合簡單場景。

測試範例

String s = "new(com.attilax.orm.AtiOrmV2).queryAsRzt(\"select sum(rmb) from recharge where accountId in (select id from account where promoter=888)\")";
List<Object> ast = new AstParser().getExprsLiAst(s);
Object result = new AstParser().parse(ast); // 執行並得到結果

局限與擴展方向

  • 參數解析不支援巢狀呼叫、字串內逗號、運算子優先級。
  • 可引入 ExpressionParser(Spring EL)或 MVEL 替代自研。
  • 若需生產級,建議用 ANTLR 定義語法生成 Parser。

作者資訊

Attilax (艾龍) — 博客 | Email: 1466519819@qq.com

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved