一个 JavaScript 实现的表达式语法解析器

一个 JavaScript 实现的表达式语法解析器

const TokenType = {
   
    /**
     * 表达式中词的类型
     * @type {string}
     */
    OR: "or",   // 只支持布尔值或者表达式进行逻辑运算
    AND: "and",
    GT: ">",    // greater than 只支持数值比较大小
    GE: ">:",   // greater equal than
    LT: "<=",    // less than
    LE: "<=:",   // less equal than
    EQUAL: ":", // 支持数值、字符串、布尔值 比较是否相等
    PLUS: "+",  // 只支持数值进行+-*/运算
    MINUS: "-",
    MULTIPLY: "*",
    DIVIDE: "/",
    INDEX: "index",  // 指标,相当于字面量,index 中的值可以是数值类型和字符串类型,字符串类型必须使用 '' 引起来
    FIELD: "field",  // 字段,相当于变量
    LEFT_PARENTHESIS: "(",
    RIGHT_PARENTHESIS: ")",
}

const ASTNodeType = {
   
    /**
     * 抽象语法树节点代表的表达式值的类型
     * @type {string}
     */
    NUMERIC: "numeric",   // 数值类型
    LOGICAL: "logical",     // 布尔类型
    STRING: "string",     // 字符串类型
}

let parser = {
   
    /**
     * 表达式语法分析器的 CFG
     * 表达式运算符优先级 or < and < 关系运算符 < 加减法 < 乘除法 < 小括号
     * orExpr -> andExpr (or andExpr)*
     * andExpr -> relExpr (and relExpr)*
     * relExpr -> addExpr (> addExpr)* | addExpr (>= addExpr)* | addExpr (< addExpr)*
     *                                 | addExpr (<= addExpr)* | addExpr (= addExpr)*
     * addExpr -> mulExpr (+ mulExpr)* | mulExpr (- mulExpr)*
     * mulExpr -> priExpr (* priExpr)* | priExpr (/ priExpr)*
     * priExpr -> index | field | (exp)
     *
     * 语法检查方面:
     * 1. 双元运算符两侧 node 不能为 null
     * 2. 运算符两侧 node 的数据类型必须严格和运算符匹配
     * 3. () 必须配对
     * @param tokens
     */
    tokens: {
   
        cursor: 0,
        arrToken: [],
        getCursor() {
   
            return this.cursor;
        }, peek() {
   
            /**
             * 预读下一个 token,cursor 不变
             */
            return this.arrToken[this.cursor] === undefined ? null : this.arrToken[this.cursor];
        }, read() {
   
            /**
             * 读取下一个 token,cursor 加 1
             * @type {number}
             */
            return this.arrToken[this.cursor] === undefined ? null : this.arrToken[this.cursor++];
        }
    },
    hasLeftBrackets: 0,
    nodeTree: null,
    orExpr: function () {
   
        /**
         * 解析 or 表达式
         * or 表达式 CFG 如下:orExpr -> andExpr (or andExpr)*
         * 表示 or 运算符表达式由 1 个或者多个 and 表达式组成,多个 and 表达式之间由 or 运算符连接
         */
        let child1 = this.andExpr();
        let node = child1;

        if (child1 != null) {
   
            let token = this.tokens.peek();
            while (token != null && token.type === TokenType.OR) {
   
                token = this.tokens.read();                 // 读出 or 运算符
                let child2 = this.andExpr();                // 计算下级节点
                this.checkNodeType(child1, child2, token.text, ASTNodeType.LOGICAL)

                node = {
   
                    type: ASTNodeType.LOGICAL,
                    text: token.text,
                    children: [],
                };
                node.children.push(child1);
                node.children.push(child2);
                child1 = node;
                token = this.tokens.peek();
            }
        }
        return node;
    },
    andExpr: function () {
   
        /**
         * 解析 and 表达式
         * and 表达式 CFG 如下:andExpr -> relExpr (and relExpr)*
         * 表示 and 运算符表达式由 1 个或者多个 关系表达式组成,多个 关系表达式之间由 and 运算符连接
         */
        let child1 = this.relExpr();
        let node = child1;
        if (child1 != null) {
   
            let token = this.tokens.peek();
            while (token != null && token.type === TokenType.AND) {
   
                token = this.tokens.read();         //读出 and 运算符
                let child2 = this.relExpr();        //计算下级节点
                this.checkNodeType(child1
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值