fastjson词法和语法解析

本文详细介绍了fastjson的词法和语法解析过程,包括token定义、基础类型实现和对象实现的解析。重点讲解了JSONToken成员、JSONLexerBase成员函数,以及扫描字符串、数字、Boolean、标识符和注释的方法。通过对fastjson词法分析的深入理解,为后续的反序列化奠定了基础。
摘要由CSDN通过智能技术生成

                                fastjson词法和语法解析

目录

                                fastjson词法和语法解析

一 token定义解析

JSONToken成员

(二) - 基础类型实现解析

JSON Token解析

JSONLexerBase成员函数

推断token类型

跳过注释

扫描字符串

扫描数字类型

扫描Boolean

扫描标识符

扫描十六进制数

根据期望字符扫描token

(三) - 针对对象实现解析

JSON Token解析

JSONLexerBase成员函数

Int类型字段解析

Long类型字段解析

Float类型字段解析

String类型字段解析

在这里插入图片描述


一 token定义解析

词法分析是反序列化的重要基础,在其他框架druidparsii等框架都用到了词法分析的技术,个人认为在讲反序列化之前讲词法分析更重要。

写出优秀框架之前,先理解大量优秀框架的实现对未来自己写框架非常有帮助!!!

好了,废话不多说,来看看fastjson中定义的token吧。

JSONToken成员

com.alibaba.fastjson.parser.JSONToken定义了fastjson需要的token标识符:

    /** 1 关联到 error */
    public final static int ERROR                = 1;
    /** 2 关联到 int */
    public final static int LITERAL_INT          = 2;
    /** 3 关联到 float */
    public final static int LITERAL_FLOAT        = 3;
    /** 4 关联到 string */
    public final static int LITERAL_STRING       = 4;
    /** 5 关联到 iso8601 */
    public final static int LITERAL_ISO8601_DATE = 5;
    /** 6 关联到 true */
    public final static int TRUE                 = 6;
    /** 7 关联到 false */
    public final static int FALSE                = 7;
    /** 8 关联到 null */
    public final static int NULL                 = 8;
    /** 9 关联到 new */
    public final static int NEW                  = 9;
    /** 10 关联到 ( */
    public final static int LPAREN               = 10;
    /** 11 关联到 ) */
    public final static int RPAREN               = 11;
    /** 12 关联到 { */
    public final static int LBRACE               = 12;
    /** 13 关联到 } */
    public final static int RBRACE               = 13;
    /** 14 关联到 [ */
    public final static int LBRACKET             = 14;
    /** 15 关联到 ] */
    public final static int RBRACKET             = 15;
    /** 16 关联到 , */
    public final static int COMMA                = 16;
    /** 17 关联到 : */
    public final static int COLON                = 17;
    /** 18 关联到 ident */
    public final static int IDENTIFIER           = 18;
    /** 19 关联到 fieldName */
    public final static int FIELD_NAME           = 19;
    /** 20 关联到 EOF */
    public final static int EOF                  = 20;
    /** 21 关联到 Set */
    public final static int SET                  = 21;
    /** 22 关联到 TreeSet */
    public final static int TREE_SET             = 22;
    /** 23 关联到 undefined */
    public final static int UNDEFINED            = 23; // undefined
    /** 24 关联到 ; */
    public final static int SEMI                 = 24;
    /** 25 关联到 . */
    public final static int DOT                  = 25;
    /** 26 关联到 hex */
    public final static int HEX                  = 26;

    public static String name(int value) {
        switch (value) {
            case ERROR:
                return "error";
            case LITERAL_INT:
                return "int";
            case LITERAL_FLOAT:
                return "float";
            case LITERAL_STRING:
                return "string";
            case LITERAL_ISO8601_DATE:
                return "iso8601";
            case TRUE:
                return "true";
            case FALSE:
                return "false";
            case NULL:
                return "null";
            case NEW:
                return "new";
            case LPAREN:
                return "(";
            case RPAREN:
                return ")";
            case LBRACE:
                return "{";
            case RBRACE:
                return "}";
            case LBRACKET:
                return "[";
            case RBRACKET:
                return "]";
            case COMMA:
                return ",";
            case COLON:
                return ":";
            case SEMI:
                return ";";
            case DOT:
                return ".";
            case IDENTIFIER:
                return "ident";
            case FIELD_NAME:
                return "fieldName";
            case EOF:
                return "EOF";
            case SET:
                return "Set";
            case TREE_SET:
                return "TreeSet";
            case UNDEFINED:
                return "undefined";
            case HEX:
                return "hex";
            default:
                return "Unknown";
        }
    }

(二) - 基础类型实现解析

JSON Token解析

JSONLexerBase定义并实现了json串实现解析机制的基础,在理解后面反序列化之前,我们先来看看并理解重要的属性:

    /** 当前token含义 */
    protected int                            token;
    /** 记录当前扫描字符位置 */
    protected int                            pos;
    protected int                            features;

    /** 当前有效字符 */
    protected char                           ch;
    /** 流(或者json字符串)中当前的位置,每次读取字符会递增 */
    protected int                            bp;

    protected int                            eofPos;

    /** 字符缓冲区 */
    protected char[]                         sbuf;

    /** 字符缓冲区的索引,指向下一个可写
     *  字符的位置,也代表字符缓冲区字符数量
     */
    protected int                            sp;

    /**
     * number start position
     * 可以理解为 找到token时 token的首字符位置
     * 和bp不一样,这个不会递增,会在开始token前记录一次
     */
    protected int                            np;

JSONLexerBase成员函数

在开始分析词法分析实现过程中,我发现中解析存在大量重复代码实现或极其类似实现,重复代码主要解决类似c++内联调用,极其相似代码实现我会挑选有代表性的来说明(一般实现较为复杂),没有说明的成员函数可以参考代码注释。

推断token类型

fastjson token类型推断当前json字符串是哪种类型的token, 比如是字符串、花括号和逗号等等。

    public final void nextToken() {
        /** 将字符buffer pos设置为初始0 */
        sp = 0;

        for (;;) {
            /** pos记录为流的当前位置 */
            pos = bp;

            if (ch == '/') {
                /** 如果是注释// 或者 \/* *\/ 注释,跳过注释 */
                skipComment();
                continue;
            }

            if (ch == '"') {
                /** 读取引号内的字符串 */
                scanString();
                return;
            }

            if (ch == ',') {
                /** 跳过当前,读取下一个字符 */
                next();
                token = COMMA;
                return;
            }

            if (ch >= '0' && ch <= '9') {
                /** 读取整数 */
                scanNumber();
                return;
            }

            if (ch == '-') {
                /** 读取负数 */
                scanNumber();
                return;
            }

            switch (ch) {
                /** 读取单引号后面的字符串,和scanString逻辑一致 */
                case '\'':
                    if (!isEnabled(Feature.AllowSingleQuotes)) {
                        throw new JSONException("Feature.AllowSingleQuotes is false");
                    }
                    scanStringSingleQuote();
                    return;
                case ' ':
                case '\t':
                case '\b':
                case '\f':
                case '\n':
                case '\r':
                    next();
                    break;
                case 't': // true
                    /** 读取字符true */
                    scanTrue();
                    return;
                case 'f': // false
                    /** 读取字符false */
                    scanFalse();
                    return;
                case 'n': // new,null
                    /** 读取为new或者null的token */
                    scanNullOrNew();
                    return;
                case 'T':
                case 'N': // NULL
                case 'S':
                case 'u': // undefined
                    /** 读取标识符,已经自动预读了下一个字符 */
                    scanIdent();
                    return;
                case '(':
                    /** 读取下一个字符 */
                    next();
                    token = LPAREN;
                    return;
                case ')':
                    next();
                    token = RPAREN;
                    return;
                case '[':
                    next();
                    token = LBRACKET;
                    return;
                case ']':
                    next();
                    token = RBRACKET;
                    return;
                case '{':
                    next();
                    token = LBRACE;
                    return;
                case '}':
                    next();
                    token = RBRACE;
                    return;
                case ':':
                    next();
                    token = COLON;
                    return;
                case ';':
                    next();
                    token = SEMI;
                    return;
                case '.':
                    next();
                    token = DOT;
                    return;
                case '+':
                    next();
                    scanNumber();
                    return;
                case 'x':
                    scanHex();
                    return;
                default:
                    if (isEOF()) { // JLS
                        if (token == EOF) {
                            throw new JSONException("EOF error");
                        }

                        token = EOF;
                        pos = bp = eofPos;
                    } else {
                        /** 忽略控制字符或者删除字符 */
                        if (ch <= 31 || ch == 127) {
                            next();
                            break;
                        }

                        lexError("illegal.char", String.valueOf((int) ch));
                        next();
                    }

                    return;
            }
        }

    }

跳过注释

    protected void skipComment() {
        /** 读下一个字符 */
        next();
        /** 连续遇到左反斜杠/ */
        if (ch == '/') {
            for (;;) {
                /** 读下一个字符 */
                next();
                if (ch == '\n') {
                    /** 如果遇到换行符,继续读取下一个字符并返回 */
                    next();
                    return;
                    /** 如果已经遇到流结束,返回 */
                } else if (ch == EOI) {
                    return;
                }
            }
            /** 遇到`/*` 注释的格式 */
        } else if (ch == '*') {
            /** 读下一个字符 */
            next();
            for (; ch != EOI;) {
                if (ch == '*') {
                    /** 如果遇到*,继续尝试读取下一个字符,看看是否是/字符 */
                    next();
                    if (ch == '/') {
                        /** 如果确实是/字符,提前预读下一个有效字符后终止 */
                        next();
                        return;
                    } else {
                        /** 遇到非/ 继续跳过度下一个字符 */
                        continue;
                    }
                }
                /** 如果没有遇到`*\` 注释格式, 继续读下一个字符 */
                next();
            }
        } else {
            /** 不符合// 或者 \/* *\/ 注释格式 */
            throw new JSONException("invalid comment");
        }
    }

解析注释主要分为2中,支持// 或者 /* */ 注释格式。

扫描字符串

当解析json字符串是"时,会调用扫描字符串方法。

    public final void scanString() {
        /** 记录当前流中token的开始位置, np指向引号的索引 */
        np = bp;
        hasSpecial = false;
        char ch;
        for (;;) {

            /** 读取当前字符串的字符 */
            ch = next();

            /** 如果遇到字符串结束符", 则结束 */
            if (ch == '\"') {
                break;
            }

            if (ch == EOI) {
                /** 如果遇到了结束符EOI,但是没有遇到流的结尾,添加EOI结束符 */
                if (!isEOF()) {
                    putChar((char) EOI);
                    continue;
                }
                throw new JSONException("unclosed string : " + ch);
            }

            /** 处理转译字符逻辑 */
            if (ch == '\\') {
                if (!hasSpecial) {
                    /** 第一次遇到\认为是特殊符号 */
                    hasSpecial = true;

                    /** 如果buffer空间不够,执行2倍扩容 */
                    if (sp >= sbuf.length) {
                        int newCapcity = sbuf.length * 2;
                        if (sp > newCapcity) {
                            n
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haikuotiankongdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值