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