├── .gitignore ├── README.md ├── build.xml └── java └── com └── simplemain └── kit └── json ├── Main.java ├── element ├── IllegalElement.java ├── JsonArray.java ├── JsonBoolean.java ├── JsonElement.java ├── JsonNull.java ├── JsonNumber.java ├── JsonObject.java ├── JsonString.java └── Token.java ├── error ├── SyntaxError.java ├── SyntaxException.java └── SyntaxWarning.java ├── format ├── JsonFormatter.java ├── MetaFormatter.java └── TextJsonFormatter.java └── parser ├── ArrayParser.java ├── BooleanParser.java ├── ElementParser.java ├── JsonParser.java ├── NullParser.java ├── NumberParser.java ├── ObjectParser.java ├── StringParser.java ├── Symbol.java └── ValueParser.java /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /.settings 3 | /.project 4 | /.classpath 5 | /logs 6 | /jar 7 | /.DS_Store 8 | /data 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON Parser & Formatter 2 | 3 | 前一段时间在用JSON的时候,发现格式化JSON很有意思,于是乎老王就用空闲时间写了一个JSON的解析和格式化器。
4 | 这个解析的状态机严格按照JSON规范来编写,详细见: [http://www.json.org/](http://www.json.org/) 5 | 6 | 7 | ## 代码组织 8 | 9 | ### Java代码: 在项目的/java目录下, 包名com.simplemain.kit.json 10 | * element: 存放的是Json的实体对象 11 | * error: 错误相关的类,分为错误和警告 12 | * format: 做格式化的类,都从JsonFormatter继承。可以自己继承实现想要的效果 13 | * parser: 解析类。对外接口为JsonParser类。 14 | * Main.java: 入口main函数类 15 | 16 | ### JavaScript代码: 待开发 17 | 18 | ### C代码: 待开发 19 | 20 | ## 编译 & 运行 21 | * 下载相关代码 22 | * 切换到项目目录 23 | * 编译: ant 24 | * 运行: java -jar jar/json-formatter-1.0.0.jar 25 | * 版本号有可能发生变化,请根据编译后的文件执行相应的命令 26 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | build done! 24 | 25 | 26 | 27 | 28 | clean 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/Main.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import com.simplemain.kit.json.element.JsonElement; 6 | import com.simplemain.kit.json.format.TextJsonFormatter; 7 | import com.simplemain.kit.json.parser.JsonParser; 8 | 9 | /** 10 | * @author zgwangbo@simplemain.com 11 | */ 12 | public class Main 13 | { 14 | public static void main(String[] args) 15 | { 16 | final String json = "{'number':123, \"hello\":\"\\ux343\\u0041bCd\\uD83D\\uDE03\\r\\b\\f\\p\", \"111\":22,\"aa\": {'a':'b'}, 'array':['asdf', 123, null, true, false, 0.00003e-17, {'ddd':123,'hahah':[{}]},true]}aa"; 17 | 18 | System.out.println("==== origin json string ===="); 19 | System.out.println(json); 20 | System.out.println(); 21 | 22 | final JsonParser jp = new JsonParser(); 23 | final JsonElement je = jp.parse(json); 24 | 25 | System.out.println("==== formatted json string ===="); 26 | try (PrintWriter pw = new PrintWriter(System.out)) 27 | { 28 | new TextJsonFormatter(true, true, true).format(je, pw); 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/IllegalElement.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.Iterator; 4 | 5 | import com.simplemain.kit.json.error.SyntaxException; 6 | 7 | /** 8 | * @author zgwangbo@simplemain.com 9 | */ 10 | public class IllegalElement extends JsonElement 11 | { 12 | private String string; 13 | 14 | public IllegalElement(String s, SyntaxException e) 15 | { 16 | string = s; 17 | addException(e); 18 | } 19 | 20 | public String toString() 21 | { 22 | return string; 23 | } 24 | 25 | @Override 26 | public Iterator iterator() 27 | { 28 | return new SimpleIterator(new Token(toString(), Token.TYPE_STRING, level)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonArray.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | /** 8 | * @author zgwangbo@simplemain.com 9 | */ 10 | public class JsonArray extends JsonElement 11 | { 12 | public static final char BEGIN_SYMBOL = '['; 13 | public static final char END_SYMBOL = ']'; 14 | public static final char NEXT_SEPARATOR = ','; 15 | 16 | private List elements = new ArrayList<>(); 17 | 18 | private String beginSymbol = ""; 19 | private String endSymbol = ""; 20 | 21 | public void fillBeginSymbol() 22 | { 23 | beginSymbol = "" + BEGIN_SYMBOL; 24 | } 25 | 26 | public void fillEndSymbol() 27 | { 28 | endSymbol = "" + END_SYMBOL; 29 | } 30 | 31 | public void add(JsonElement e) 32 | { 33 | elements.add(e); 34 | } 35 | 36 | @Override 37 | public String toString() 38 | { 39 | StringBuffer sb = new StringBuffer(); 40 | sb.append(beginSymbol); 41 | 42 | boolean first = true; 43 | for (JsonElement e : elements) 44 | { 45 | if (!first) sb.append(NEXT_SEPARATOR + " "); 46 | else first = false; 47 | 48 | sb.append(e.toString()); 49 | } 50 | sb.append(endSymbol); 51 | 52 | return sb.toString(); 53 | } 54 | 55 | @Override 56 | public Iterator iterator() 57 | { 58 | return new DefaultIterator(); 59 | } 60 | 61 | private class DefaultIterator implements Iterator 62 | { 63 | protected List> iters = new ArrayList<>(); 64 | protected int elementIdx = 0; 65 | 66 | DefaultIterator() 67 | { 68 | iters.add(new SimpleIterator(new Token(beginSymbol, Token.TYPE_AREA_SEPARATOR, level))); 69 | 70 | boolean first = true; 71 | for (JsonElement e : elements) 72 | { 73 | if (!first) 74 | { 75 | iters.add(new SimpleIterator(new Token("" + NEXT_SEPARATOR, Token.TYPE_SEG_SEPARATOR, level + 1))); 76 | } 77 | else 78 | { 79 | first = false; 80 | } 81 | 82 | e.setLevel(level + 1); 83 | iters.add(e.iterator()); 84 | } 85 | 86 | iters.add(new SimpleIterator(new Token(endSymbol, Token.TYPE_AREA_SEPARATOR, level))); 87 | } 88 | 89 | @Override 90 | public boolean hasNext() 91 | { 92 | while (elementIdx < iters.size()) 93 | { 94 | if (iters.get(elementIdx).hasNext()) 95 | { 96 | return true; 97 | } 98 | elementIdx++; 99 | } 100 | 101 | return false; 102 | } 103 | 104 | @Override 105 | public Token next() 106 | { 107 | while (elementIdx < iters.size()) 108 | { 109 | Token t = iters.get(elementIdx).next(); 110 | if (t != null) 111 | { 112 | return t; 113 | } 114 | elementIdx++; 115 | } 116 | 117 | return null; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonBoolean.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.Iterator; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class JsonBoolean extends JsonElement 9 | { 10 | public static final String TRUE = "true"; 11 | public static final String FALSE = "false"; 12 | 13 | private final String string; 14 | 15 | public static JsonBoolean createTrue() 16 | { 17 | return new JsonBoolean("true"); 18 | } 19 | 20 | public static JsonBoolean createFalse() 21 | { 22 | return new JsonBoolean("false"); 23 | } 24 | 25 | private JsonBoolean(String s) 26 | { 27 | this.string = s; 28 | } 29 | 30 | public String toString() 31 | { 32 | return string; 33 | } 34 | 35 | @Override 36 | public Iterator iterator() 37 | { 38 | return new SimpleIterator(new Token(string, Token.TYPE_KEYWORD, level)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonElement.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import com.simplemain.kit.json.error.SyntaxException; 8 | 9 | /** 10 | * @author zgwangbo@simplemain.com 11 | */ 12 | public abstract class JsonElement implements Iterable 13 | { 14 | protected int level; 15 | protected List exceptions = new ArrayList<>(); 16 | 17 | public abstract Iterator iterator(); 18 | 19 | protected class SimpleIterator implements Iterator 20 | { 21 | private Token token; 22 | 23 | SimpleIterator(Token token) 24 | { 25 | this.token = token; 26 | if (token != null) 27 | { 28 | token.exceptions = exceptions; 29 | } 30 | } 31 | 32 | @Override 33 | public boolean hasNext() 34 | { 35 | return token != null; 36 | } 37 | 38 | @Override 39 | public Token next() 40 | { 41 | Token ret = token; 42 | token = null; 43 | return ret; 44 | } 45 | } 46 | 47 | public int getLevel() 48 | { 49 | return level; 50 | } 51 | 52 | public void setLevel(int level) 53 | { 54 | this.level = level; 55 | } 56 | 57 | public void addException(SyntaxException e) 58 | { 59 | exceptions.add(e); 60 | } 61 | 62 | public List getExceptions() 63 | { 64 | return exceptions; 65 | } 66 | 67 | public boolean hasExceptions() 68 | { 69 | return !exceptions.isEmpty(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonNull.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.Iterator; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class JsonNull extends JsonElement 9 | { 10 | public static final String NULL = "null"; 11 | 12 | public String toString() 13 | { 14 | return NULL; 15 | } 16 | 17 | @Override 18 | public Iterator iterator() 19 | { 20 | return new SimpleIterator(new Token(toString(), Token.TYPE_KEYWORD, level)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonNumber.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.Iterator; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class JsonNumber extends JsonElement 9 | { 10 | private String string; 11 | 12 | public JsonNumber(String s) 13 | { 14 | string = s; 15 | } 16 | 17 | public String toString() 18 | { 19 | return string; 20 | } 21 | 22 | @Override 23 | public Iterator iterator() 24 | { 25 | return new SimpleIterator(new Token(string, Token.TYPE_NUMBER, level)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonObject.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | /** 8 | * @author zgwangbo@simplemain.com 9 | */ 10 | public class JsonObject extends JsonElement 11 | { 12 | public static final char BEGIN_SYMBOL = '{'; 13 | public static final char END_SYMBOL = '}'; 14 | public static final char KV_SEPARATOR = ':'; 15 | public static final char NEXT_SEPARATOR = ','; 16 | 17 | private static class Pair 18 | { 19 | JsonString key; 20 | String sep; 21 | JsonElement value; 22 | 23 | Pair(JsonString key, String sep, JsonElement value) 24 | { 25 | this.key = key; 26 | this.sep = sep; 27 | this.value = value; 28 | } 29 | } 30 | 31 | private List list = new ArrayList<>(); 32 | 33 | private String beginSymbol = ""; 34 | private String endSymbol = ""; 35 | 36 | public void fillBeginSymbol() 37 | { 38 | beginSymbol = "" + BEGIN_SYMBOL; 39 | } 40 | 41 | public void fillEndSymbol() 42 | { 43 | endSymbol = "" + END_SYMBOL; 44 | } 45 | 46 | public void add(JsonString key, String sep, JsonElement value) 47 | { 48 | list.add(new Pair(key, sep, value)); 49 | } 50 | 51 | public void add(IllegalElement ie) 52 | { 53 | list.add(new Pair(null, null, ie)); 54 | } 55 | 56 | @Override 57 | public String toString() 58 | { 59 | StringBuffer sb = new StringBuffer(); 60 | boolean first = true; 61 | for (Pair p : list) 62 | { 63 | if (!first) 64 | { 65 | sb.append(NEXT_SEPARATOR + " "); 66 | } 67 | else 68 | { 69 | first = false; 70 | } 71 | sb.append(p.key + " " + KV_SEPARATOR + " " + p.value); 72 | } 73 | return beginSymbol + sb.toString() + endSymbol; 74 | } 75 | 76 | @Override 77 | public Iterator iterator() 78 | { 79 | return new DefaultIterator(); 80 | } 81 | 82 | private class DefaultIterator implements Iterator 83 | { 84 | protected List> iters = new ArrayList<>(); 85 | 86 | protected int elementIdx = 0; 87 | 88 | DefaultIterator() 89 | { 90 | iters.add(new SimpleIterator(new Token("" + beginSymbol, Token.TYPE_AREA_SEPARATOR, level))); 91 | 92 | boolean first = true; 93 | for (Pair p : list) 94 | { 95 | if (!first) 96 | { 97 | if (p.key != null && p.value != null) 98 | { 99 | iters.add(new SimpleIterator(new Token("" + NEXT_SEPARATOR, Token.TYPE_SEG_SEPARATOR, level + 1))); 100 | } 101 | } 102 | else 103 | { 104 | first = false; 105 | } 106 | 107 | if (p.key != null) 108 | { 109 | p.key.setLevel(level + 1); 110 | iters.add(p.key.iterator()); 111 | } 112 | 113 | if (p.sep != null) 114 | { 115 | iters.add(new SimpleIterator(new Token(p.sep, Token.TYPE_KV_SEPARATOR, level + 1))); 116 | } 117 | 118 | if (p.value != null) 119 | { 120 | p.value.setLevel(level + 1); 121 | iters.add(p.value.iterator()); 122 | } 123 | } 124 | 125 | iters.add(new SimpleIterator(new Token("" + endSymbol, Token.TYPE_AREA_SEPARATOR, level))); 126 | } 127 | 128 | @Override 129 | public boolean hasNext() 130 | { 131 | while (elementIdx < iters.size()) 132 | { 133 | if (iters.get(elementIdx).hasNext()) 134 | { 135 | return true; 136 | } 137 | elementIdx++; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | @Override 144 | public Token next() 145 | { 146 | while (elementIdx < iters.size()) 147 | { 148 | Token t = iters.get(elementIdx).next(); 149 | if (t != null) 150 | { 151 | return t; 152 | } 153 | elementIdx++; 154 | } 155 | 156 | return null; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/JsonString.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.Iterator; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class JsonString extends JsonElement 9 | { 10 | public static final char SIGN = '"'; 11 | public static final char POSSIBLE_SIGN = '\''; 12 | 13 | private String string; 14 | 15 | private String beginSymbol = ""; 16 | private String endSymbol = ""; 17 | 18 | public JsonString() 19 | { 20 | } 21 | 22 | public JsonString(String s) 23 | { 24 | string = s; 25 | } 26 | 27 | public void fillBeginSymbol() 28 | { 29 | beginSymbol = "" + SIGN; 30 | } 31 | 32 | public void fillEndSymbol() 33 | { 34 | endSymbol = "" + SIGN; 35 | } 36 | 37 | public String toString() 38 | { 39 | return beginSymbol + string + endSymbol; 40 | } 41 | 42 | @Override 43 | public Iterator iterator() 44 | { 45 | return new SimpleIterator(new Token(toString(), Token.TYPE_STRING, level)); 46 | } 47 | 48 | public String getString() 49 | { 50 | return string; 51 | } 52 | 53 | public void setString(String string) 54 | { 55 | this.string = string; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/element/Token.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.element; 2 | 3 | import java.util.List; 4 | 5 | import com.simplemain.kit.json.error.SyntaxException; 6 | 7 | /** 8 | * @author zgwangbo@simplemain.com 9 | */ 10 | public class Token 11 | { 12 | private static int idx = 0; 13 | 14 | public static final int TYPE_NORAML = idx++; 15 | public static final int TYPE_KEYWORD = idx++; 16 | public static final int TYPE_AREA_SEPARATOR = idx++; 17 | public static final int TYPE_KV_SEPARATOR = idx++; 18 | public static final int TYPE_SEG_SEPARATOR = idx++; 19 | public static final int TYPE_NUMBER = idx++; 20 | public static final int TYPE_STRING = idx++; 21 | 22 | public static final int TYPE_ILLEGAL = idx++; 23 | 24 | private String value; 25 | private int type; 26 | private int level; 27 | List exceptions; 28 | 29 | public Token() {} 30 | 31 | public Token(String value, int type, int level) 32 | { 33 | this.value = value; 34 | this.type = type; 35 | this.level = level; 36 | } 37 | 38 | public String getValue() 39 | { 40 | return value; 41 | } 42 | 43 | public void setValue(String value) 44 | { 45 | this.value = value; 46 | } 47 | 48 | public int getType() 49 | { 50 | return type; 51 | } 52 | 53 | public void setType(int type) 54 | { 55 | this.type = type; 56 | } 57 | 58 | public int getLevel() 59 | { 60 | return level; 61 | } 62 | 63 | public void setLevel(int level) 64 | { 65 | this.level = level; 66 | } 67 | 68 | public List getExceptions() 69 | { 70 | return exceptions; 71 | } 72 | 73 | public boolean hasExceptions() 74 | { 75 | return !exceptions.isEmpty(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/error/SyntaxError.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.error; 2 | 3 | /** 4 | * @author zgwangbo@simplemain.com 5 | */ 6 | public class SyntaxError extends SyntaxException 7 | { 8 | private static final long serialVersionUID = -4674194378872598782L; 9 | 10 | public SyntaxError(String msg) 11 | { 12 | super(msg, TYPE_ERROR); 13 | } 14 | 15 | public SyntaxError(int lineNo, int rowNo, String nearByString, String msg) 16 | { 17 | super(lineNo, rowNo, nearByString, msg, TYPE_ERROR); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/error/SyntaxException.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.error; 2 | 3 | /** 4 | * @author zgwangbo@simplemain.com 5 | */ 6 | public abstract class SyntaxException extends RuntimeException 7 | { 8 | private static final long serialVersionUID = 1230377296133173902L; 9 | 10 | protected static final String TYPE_WARN = "warning"; 11 | protected static final String TYPE_ERROR = "error"; 12 | 13 | protected int lineNo; 14 | protected int rowNo; 15 | protected String nearByString; 16 | protected String type; 17 | 18 | public SyntaxException(String msg, String type) 19 | { 20 | this(0, 0, null, msg, type); 21 | } 22 | 23 | public SyntaxException(int lineNo, int rowNo, String nearByString, String msg, String type) 24 | { 25 | super(msg); 26 | this.lineNo = lineNo; 27 | this.rowNo = rowNo; 28 | this.nearByString = nearByString; 29 | this.type = type; 30 | } 31 | 32 | public int getLineNo() 33 | { 34 | return lineNo; 35 | } 36 | 37 | public int getRowNo() 38 | { 39 | return rowNo; 40 | } 41 | 42 | public String toString() 43 | { 44 | return String.format("syntax %s at [%d:%d] near [%s] caused by [%s]", 45 | type, lineNo, rowNo, nearByString, super.getMessage()); 46 | } 47 | 48 | public String getNearByString() 49 | { 50 | return nearByString; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/error/SyntaxWarning.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.error; 2 | 3 | /** 4 | * @author zgwangbo@simplemain.com 5 | */ 6 | public class SyntaxWarning extends SyntaxException 7 | { 8 | private static final long serialVersionUID = -4674194398872598782L; 9 | 10 | public SyntaxWarning(String msg) 11 | { 12 | super(msg, TYPE_WARN); 13 | } 14 | 15 | public SyntaxWarning(int lineNo, int rowNo, String nearByString, String msg) 16 | { 17 | super(lineNo, rowNo, nearByString, msg, TYPE_WARN); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/format/JsonFormatter.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.format; 2 | 3 | /** 4 | * @author zgwangbo@simplemain.com 5 | */ 6 | import java.io.PrintWriter; 7 | 8 | import com.simplemain.kit.json.element.JsonElement; 9 | 10 | public interface JsonFormatter 11 | { 12 | public void format(JsonElement element, PrintWriter pw); 13 | } 14 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/format/MetaFormatter.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.format; 2 | 3 | import java.io.PrintWriter; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import com.simplemain.kit.json.element.JsonElement; 8 | import com.simplemain.kit.json.element.Token; 9 | import com.simplemain.kit.json.error.SyntaxException; 10 | 11 | public class MetaFormatter implements JsonFormatter 12 | { 13 | private List lines = new ArrayList<>(); 14 | private List exceptions = new ArrayList<>(); 15 | 16 | @Override 17 | public void format(JsonElement element, PrintWriter pw) 18 | { 19 | if (element == null) 20 | { 21 | return; 22 | } 23 | 24 | Line currentLine = newLine(); 25 | 26 | int lastLevel = 0; 27 | 28 | for (Token token : element) 29 | { 30 | int level = token.getLevel(); 31 | 32 | if (level != lastLevel) 33 | { 34 | currentLine = newLine(); 35 | lastLevel = level; 36 | 37 | currentLine.setTabCount(level); 38 | currentLine.getTokens().add(token); 39 | } 40 | else if (token.getType() == Token.TYPE_SEG_SEPARATOR) 41 | { 42 | currentLine.getTokens().add(token); 43 | currentLine = newLine(); 44 | currentLine.setTabCount(level); 45 | } 46 | else 47 | { 48 | currentLine.getTokens().add(token); 49 | } 50 | 51 | if (token.hasExceptions()) 52 | { 53 | for (SyntaxException e : token.getExceptions()) 54 | { 55 | if (!currentLine.getExceptions().contains(e)) 56 | { 57 | currentLine.getExceptions().add(e); 58 | } 59 | 60 | if (!exceptions.contains(e)) 61 | { 62 | exceptions.add(e); 63 | } 64 | } 65 | } 66 | } 67 | 68 | } 69 | 70 | private Line newLine() 71 | { 72 | final Line line = new Line(); 73 | lines.add(line); 74 | return line; 75 | } 76 | 77 | public static class Line 78 | { 79 | private int tabCount = 0; 80 | private List exceptions = new ArrayList<>(); 81 | private List tokens = new ArrayList<>(); 82 | 83 | public int getTabCount() 84 | { 85 | return tabCount; 86 | } 87 | public void setTabCount(int tabCount) 88 | { 89 | this.tabCount = tabCount; 90 | } 91 | public List getTokens() 92 | { 93 | return tokens; 94 | } 95 | public List getExceptions() 96 | { 97 | return exceptions; 98 | } 99 | } 100 | 101 | public List getLines() 102 | { 103 | return lines; 104 | } 105 | 106 | public List getExceptions() 107 | { 108 | return exceptions; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/format/TextJsonFormatter.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.format; 2 | 3 | import java.io.PrintWriter; 4 | import java.util.List; 5 | 6 | import com.simplemain.kit.json.element.JsonElement; 7 | import com.simplemain.kit.json.element.Token; 8 | import com.simplemain.kit.json.error.SyntaxException; 9 | import com.simplemain.kit.json.format.MetaFormatter.Line; 10 | 11 | public class TextJsonFormatter implements JsonFormatter 12 | { 13 | private static final String TAB = " "; 14 | 15 | private boolean withLineNo = false; // 是否输出行号 16 | private boolean withErrorInline = false; // 是否在行内输出错误指示 17 | private boolean withErrorDetail = false; // 是否输出详细错误信息 18 | 19 | public TextJsonFormatter() 20 | { 21 | this(false, false, false); 22 | } 23 | 24 | public TextJsonFormatter(boolean withLineNo, boolean withErrorInline, boolean withErrorDetail) 25 | { 26 | this.withLineNo = withLineNo; 27 | this.withErrorInline = withErrorInline; 28 | this.withErrorDetail = withErrorDetail; 29 | } 30 | 31 | @Override 32 | public void format(JsonElement element, PrintWriter pw) 33 | { 34 | final MetaFormatter format = new MetaFormatter(); 35 | format.format(element, pw); 36 | 37 | final List lines = format.getLines(); 38 | final List exceptions = format.getExceptions(); 39 | 40 | final int lineNoWidth = getLineNoWidth(lines.size()); 41 | int lineNo = 0; 42 | 43 | for (Line line : lines) 44 | { 45 | lineNo++; 46 | 47 | // 打印行号 48 | if (withLineNo) 49 | { 50 | if (lineNoWidth > 0) 51 | { 52 | pw.print(String.format("%" + lineNoWidth + "d.", lineNo)); 53 | } 54 | else 55 | { 56 | pw.print(lineNo + "."); 57 | } 58 | } 59 | 60 | // 行内打印出错 61 | if (withErrorInline && !line.getExceptions().isEmpty()) 62 | { 63 | pw.print("=>"); 64 | } 65 | else if (withLineNo || (withErrorInline && !exceptions.isEmpty())) 66 | { 67 | pw.print(" "); 68 | } 69 | 70 | // 打印前导空格 71 | for (int i = 0; i < line.getTabCount(); i++) 72 | { 73 | pw.print(TAB); 74 | } 75 | 76 | // 打印内容 77 | for (Token token : line.getTokens()) 78 | { 79 | final String s = token.getValue(); 80 | if (token.getType() == Token.TYPE_KV_SEPARATOR) 81 | { 82 | pw.print(" " + s + " "); 83 | } 84 | else 85 | { 86 | pw.print(s); 87 | } 88 | } 89 | 90 | pw.println(); 91 | } 92 | 93 | // 打印完整错误信息 94 | if (withErrorDetail && !exceptions.isEmpty()) 95 | { 96 | pw.println(); 97 | pw.println("==== syntax warnings & errors ===="); 98 | for (SyntaxException e : exceptions) 99 | { 100 | pw.println(e.toString()); 101 | } 102 | } 103 | } 104 | 105 | private int getLineNoWidth(int totalLineNo) 106 | { 107 | int ret = 0; 108 | for (; totalLineNo > 0; totalLineNo /= 10) 109 | { 110 | ret++; 111 | } 112 | return ret; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/ArrayParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.IllegalElement; 4 | import com.simplemain.kit.json.element.JsonArray; 5 | import com.simplemain.kit.json.element.JsonElement; 6 | import com.simplemain.kit.json.error.SyntaxError; 7 | 8 | /** 9 | * @author zgwangbo@simplemain.com 10 | */ 11 | public class ArrayParser implements ElementParser 12 | { 13 | @Override 14 | public JsonArray parse(Symbol symbol) 15 | { 16 | symbol.mark(); 17 | 18 | final JsonArray ret = new JsonArray(); 19 | 20 | final char begin = symbol.nextWithoutSpace(); 21 | if (JsonArray.BEGIN_SYMBOL != begin) 22 | { 23 | symbol.reset(); 24 | return null; 25 | } 26 | ret.fillBeginSymbol(); 27 | 28 | for (boolean force = false; symbol.hasNext(); force = true) 29 | { 30 | symbol.mark(); 31 | 32 | final ValueParser vp = new ValueParser(); 33 | final JsonElement value = vp.parse(symbol); 34 | if (value == null) 35 | { 36 | if (force) // error 37 | { 38 | SyntaxError error = new SyntaxError(symbol.getLineNo(), 39 | symbol.getRowNo(), 40 | symbol.getNearByChars(), 41 | "in ARRAY, a valid value is needed after comma(,)"); 42 | 43 | String remaining = symbol.getRemaining(); 44 | IllegalElement ie = new IllegalElement(remaining, error); 45 | ret.add(ie); 46 | return ret; 47 | } 48 | else 49 | { 50 | symbol.reset(); 51 | break; 52 | } 53 | } 54 | 55 | ret.add(value); 56 | 57 | symbol.mark(); 58 | char next = symbol.nextWithoutSpace(); 59 | 60 | if (JsonArray.NEXT_SEPARATOR != next) 61 | { 62 | symbol.reset(); 63 | break; 64 | } 65 | } 66 | 67 | final char end = symbol.nextWithoutSpace(); 68 | if (JsonArray.END_SYMBOL == end) 69 | { 70 | ret.fillEndSymbol(); 71 | return ret; 72 | } 73 | else 74 | { 75 | symbol.reset(); 76 | 77 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 78 | symbol.getNearByChars(), "in ARRAY, a right-bracket(]) is needed at the end"); 79 | 80 | String remaining = symbol.getRemaining(); 81 | IllegalElement ie = new IllegalElement(remaining, error); 82 | ret.add(ie); 83 | return ret; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/BooleanParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.JsonBoolean; 4 | import com.simplemain.kit.json.element.JsonElement; 5 | 6 | /** 7 | * @author zgwangbo@simplemain.com 8 | */ 9 | public class BooleanParser implements ElementParser 10 | { 11 | @Override 12 | public JsonElement parse(Symbol symbol) 13 | { 14 | symbol.mark(); 15 | 16 | StringBuffer sb = new StringBuffer(); 17 | for (int i = 0; i < JsonBoolean.TRUE.length() && symbol.hasNext(); i++) 18 | { 19 | char ch = i == 0 ? symbol.nextWithoutSpace() : symbol.next(); 20 | sb.append(ch); 21 | } 22 | String s = sb.toString(); 23 | if (JsonBoolean.TRUE.compareToIgnoreCase(s) == 0) 24 | { 25 | return JsonBoolean.createTrue(); 26 | } 27 | 28 | sb.append(symbol.next()); 29 | s = sb.toString(); 30 | if (JsonBoolean.FALSE.compareToIgnoreCase(s) == 0) 31 | { 32 | return JsonBoolean.createFalse(); 33 | } 34 | 35 | symbol.reset(); 36 | 37 | return null; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/ElementParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.JsonElement; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public interface ElementParser 9 | { 10 | public JsonElement parse(Symbol symbol); 11 | } 12 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/JsonParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.IllegalElement; 4 | import com.simplemain.kit.json.element.JsonElement; 5 | import com.simplemain.kit.json.element.Token; 6 | import com.simplemain.kit.json.error.SyntaxError; 7 | 8 | /** 9 | * @author zgwangbo@simplemain.com 10 | */ 11 | public class JsonParser 12 | { 13 | private static final ElementParser[] PARSERS = {new ObjectParser(), new ArrayParser()}; 14 | 15 | public JsonElement parse(String string) 16 | { 17 | return parse(string, false); 18 | } 19 | 20 | public JsonElement parse(String string, boolean throwsExceptions) 21 | { 22 | if (string == null || string.trim().equals("")) 23 | { 24 | return null; 25 | } 26 | 27 | final Symbol symbol = new Symbol(string); 28 | 29 | for (ElementParser parser : PARSERS) 30 | { 31 | final JsonElement je = parser.parse(symbol); 32 | if (je != null) 33 | { 34 | symbol.mark(); 35 | if (symbol.nextWithoutSpace() != 0) // 结束符后不应该再出现内容 36 | { 37 | symbol.reset(); 38 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 39 | symbol.getRemaining(), "unexpected characters!"); 40 | 41 | je.addException(error); 42 | } 43 | 44 | if (throwsExceptions) 45 | { 46 | for (Token token : je) 47 | { 48 | if (token.hasExceptions()) 49 | { 50 | throw token.getExceptions().get(0); 51 | } 52 | } 53 | } 54 | 55 | return je; 56 | } 57 | } 58 | 59 | SyntaxError error = new SyntaxError(1, 1, string, "parse error"); 60 | if (throwsExceptions) 61 | { 62 | throw error; 63 | } 64 | 65 | String remaining = symbol.getRemaining(); 66 | IllegalElement ie = new IllegalElement(remaining, error); 67 | 68 | return ie; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/NullParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.JsonElement; 4 | import com.simplemain.kit.json.element.JsonNull; 5 | 6 | /** 7 | * @author zgwangbo@simplemain.com 8 | */ 9 | public class NullParser implements ElementParser 10 | { 11 | @Override 12 | public JsonElement parse(Symbol symbol) 13 | { 14 | symbol.mark(); 15 | 16 | StringBuffer sb = new StringBuffer(); 17 | for (int i = 0; i < JsonNull.NULL.length() && symbol.hasNext(); i++) 18 | { 19 | char ch = i == 0 ? symbol.nextWithoutSpace() : symbol.next(); 20 | sb.append(ch); 21 | } 22 | 23 | String s = sb.toString(); 24 | if (JsonNull.NULL.compareToIgnoreCase(s) == 0) 25 | { 26 | return new JsonNull(); 27 | } 28 | 29 | symbol.reset(); 30 | 31 | return null; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/NumberParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.IllegalElement; 4 | import com.simplemain.kit.json.element.JsonElement; 5 | import com.simplemain.kit.json.element.JsonNumber; 6 | import com.simplemain.kit.json.error.SyntaxError; 7 | 8 | /** 9 | * @author zgwangbo@simplemain.com 10 | */ 11 | public class NumberParser implements ElementParser 12 | { 13 | @Override 14 | public JsonElement parse(Symbol symbol) 15 | { 16 | StringBuffer sb = new StringBuffer(); 17 | 18 | // 符号 19 | final String sign = getSign(symbol); 20 | if (sign != null) 21 | { 22 | sb.append(sign); 23 | } 24 | boolean hasSign = sign != null; 25 | 26 | // 整数部分 27 | final String intPart = getIntegerPart(symbol, hasSign); 28 | if (intPart != null) 29 | { 30 | sb.append(intPart); 31 | } 32 | else 33 | { 34 | if (hasSign) // 出错 35 | { 36 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 37 | symbol.getNearByChars(), "in NUMBER, expect DIGIT after minus(-)"); 38 | 39 | IllegalElement ie = new IllegalElement(sb.toString(), error); 40 | return ie; 41 | 42 | // return null; 43 | } 44 | else 45 | { 46 | symbol.reset(); 47 | return null; 48 | } 49 | } 50 | 51 | // 小数部分 52 | final String decimalPart = getDecimalPart(symbol); 53 | if (decimalPart != null) 54 | { 55 | sb.append(decimalPart); 56 | } 57 | 58 | // 指数部分 59 | final String exponentPart = getExponentPart(symbol); 60 | if (exponentPart != null) 61 | { 62 | sb.append(exponentPart); 63 | } 64 | 65 | if (sb.length() == 0) 66 | { 67 | return null; 68 | } 69 | 70 | JsonNumber ret = new JsonNumber(sb.toString()); 71 | 72 | return ret; 73 | } 74 | 75 | private String getExponentPart(Symbol symbol) 76 | { 77 | StringBuffer sb = new StringBuffer(); 78 | 79 | symbol.mark(); 80 | char ch = symbol.next(); 81 | 82 | if ('e' == Character.toLowerCase(ch)) 83 | { 84 | sb.append(ch); 85 | symbol.mark(); 86 | ch = symbol.next(); 87 | if ('+' == ch || '-' == ch) 88 | { 89 | sb.append(ch); 90 | } 91 | else 92 | { 93 | symbol.reset(); 94 | } 95 | 96 | ch = symbol.next(); 97 | if (!Character.isDigit(ch)) 98 | { 99 | throw new RuntimeException(); 100 | } 101 | sb.append(ch); 102 | 103 | while (symbol.hasNext()) 104 | { 105 | symbol.mark(); 106 | ch = symbol.next(); 107 | if (!Character.isDigit(ch)) 108 | { 109 | symbol.reset(); 110 | break; 111 | } 112 | sb.append(ch); 113 | } 114 | 115 | return sb.toString(); 116 | } 117 | else 118 | { 119 | symbol.reset(); 120 | return null; 121 | } 122 | } 123 | 124 | private String getSign(Symbol symbol) 125 | { 126 | symbol.mark(); 127 | char ch = symbol.nextWithoutSpace(); 128 | if (ch == '-') 129 | { 130 | return "" + ch; 131 | } 132 | symbol.reset(); 133 | return null; 134 | } 135 | 136 | private String getIntegerPart(Symbol symbol, boolean hasSign) 137 | { 138 | StringBuffer sb = new StringBuffer(); 139 | 140 | symbol.mark(); 141 | char ch = hasSign ? symbol.next() : symbol.nextWithoutSpace(); 142 | 143 | if (ch == '0') 144 | { 145 | sb.append(ch); 146 | } 147 | else if (ch >= '1' && ch <= '9') 148 | { 149 | sb.append(ch); 150 | while (symbol.hasNext()) 151 | { 152 | symbol.mark(); 153 | ch = symbol.next(); 154 | if (!Character.isDigit(ch)) 155 | { 156 | symbol.reset(); 157 | break; 158 | } 159 | sb.append(ch); 160 | } 161 | } 162 | else 163 | { 164 | symbol.reset(); 165 | return null; 166 | } 167 | 168 | return sb.toString(); 169 | } 170 | 171 | private String getDecimalPart(Symbol symbol) 172 | { 173 | StringBuffer sb = new StringBuffer(); 174 | 175 | symbol.mark(); 176 | char ch = symbol.next(); 177 | if ('.' == ch) 178 | { 179 | sb.append(ch); 180 | ch = symbol.next(); 181 | if (!Character.isDigit(ch)) 182 | { 183 | throw new RuntimeException(); 184 | } 185 | sb.append(ch); 186 | 187 | while (symbol.hasNext()) 188 | { 189 | symbol.mark(); 190 | ch = symbol.next(); 191 | if (!Character.isDigit(ch)) 192 | { 193 | symbol.reset(); 194 | break; 195 | } 196 | sb.append(ch); 197 | } 198 | return sb.toString(); 199 | } 200 | else 201 | { 202 | symbol.reset(); 203 | return null; 204 | } 205 | } 206 | 207 | public static void main(String[] args) 208 | { 209 | String[] numbers = {"12345", "-123", "123.4", "123.456", "0.123", "0.012", "123E12", "123.23e10"}; 210 | 211 | NumberParser p = new NumberParser(); 212 | for (String num : numbers) 213 | { 214 | JsonElement jn = p.parse(new Symbol(num)); 215 | System.out.println(num.equalsIgnoreCase(jn.toString()) + " : " + num + " ==> " + jn); 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/ObjectParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.IllegalElement; 4 | import com.simplemain.kit.json.element.JsonElement; 5 | import com.simplemain.kit.json.element.JsonObject; 6 | import com.simplemain.kit.json.element.JsonString; 7 | import com.simplemain.kit.json.error.SyntaxError; 8 | 9 | /** 10 | * @author zgwangbo@simplemain.com 11 | */ 12 | public class ObjectParser implements ElementParser 13 | { 14 | @Override 15 | public JsonObject parse(Symbol symbol) 16 | { 17 | symbol.mark(); 18 | 19 | final JsonObject ret = new JsonObject(); 20 | 21 | final char begin = symbol.nextWithoutSpace(); 22 | if (JsonObject.BEGIN_SYMBOL != begin) 23 | { 24 | symbol.reset(); 25 | return null; 26 | } 27 | ret.fillBeginSymbol(); 28 | 29 | for (boolean force = false; symbol.hasNext(); force = true) 30 | { 31 | symbol.mark(); 32 | 33 | final StringParser sp = new StringParser(); 34 | final JsonString key = sp.parse(symbol); 35 | if (key == null) 36 | { 37 | if (force) // error 38 | { 39 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 40 | symbol.getNearByChars(), "in OBJECT, a STRING key is needed"); 41 | 42 | String remaining = symbol.getRemaining(); 43 | IllegalElement ie = new IllegalElement(remaining, error); 44 | ret.add(ie); 45 | return ret; 46 | } 47 | else 48 | { 49 | symbol.reset(); 50 | break; 51 | } 52 | } 53 | 54 | symbol.mark(); 55 | char next = symbol.nextWithoutSpace(); 56 | 57 | if (JsonObject.KV_SEPARATOR != next) // error 58 | { 59 | symbol.reset(); 60 | 61 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 62 | symbol.getNearByChars(), "in OBJECT, a colon(:) is needed after key"); 63 | 64 | String remaining = symbol.getRemaining(); 65 | IllegalElement ie = new IllegalElement(remaining, error); 66 | ret.add(key, null, ie); 67 | return ret; 68 | } 69 | 70 | final ValueParser vp = new ValueParser(); 71 | final JsonElement value = vp.parse(symbol); 72 | if (value == null) // error 73 | { 74 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 75 | symbol.getNearByChars(), "in OBJECT, a valid value is needed after the colon"); 76 | 77 | String remaining = symbol.getRemaining(); 78 | IllegalElement ie = new IllegalElement(remaining, error); 79 | ret.add(key, "" + JsonObject.KV_SEPARATOR, ie); 80 | return ret; 81 | } 82 | 83 | ret.add(key, "" + JsonObject.KV_SEPARATOR, value); 84 | 85 | symbol.mark(); 86 | next = symbol.nextWithoutSpace(); 87 | 88 | if (JsonObject.NEXT_SEPARATOR != next) 89 | { 90 | symbol.reset(); 91 | break; 92 | } 93 | } 94 | 95 | final char end = symbol.nextWithoutSpace(); 96 | if (JsonObject.END_SYMBOL == end) 97 | { 98 | ret.fillEndSymbol(); 99 | return ret; 100 | } 101 | else 102 | { 103 | symbol.reset(); 104 | 105 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 106 | symbol.getNearByChars(), "in OBJECT, a right-brace(}) is needed at the end"); 107 | 108 | String remaining = symbol.getRemaining(); 109 | IllegalElement ie = new IllegalElement(remaining, error); 110 | ret.add(ie); 111 | return ret; 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/StringParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.JsonString; 4 | import com.simplemain.kit.json.error.SyntaxError; 5 | import com.simplemain.kit.json.error.SyntaxWarning; 6 | 7 | /** 8 | * @author zgwangbo@simplemain.com 9 | */ 10 | public class StringParser implements ElementParser 11 | { 12 | @Override 13 | public JsonString parse(Symbol symbol) 14 | { 15 | final JsonString ret = new JsonString(); 16 | 17 | char ch = 0; 18 | 19 | symbol.mark(); 20 | 21 | ch = symbol.nextWithoutSpace(); 22 | 23 | char END = JsonString.SIGN; 24 | if (JsonString.SIGN == ch) 25 | { 26 | 27 | } 28 | else if (JsonString.POSSIBLE_SIGN == ch) 29 | { 30 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(), 31 | symbol.getNearByChars(), "in STRING, \"'\" is NOT permitted"); 32 | 33 | ret.addException(warn); 34 | 35 | END = JsonString.POSSIBLE_SIGN; 36 | } 37 | else 38 | { 39 | symbol.reset(); 40 | return null; 41 | } 42 | ret.fillBeginSymbol(); 43 | 44 | 45 | StringBuffer sb = new StringBuffer(); 46 | while (symbol.hasNext()) 47 | { 48 | ch = symbol.next(); 49 | if (END == ch) 50 | { 51 | ret.setString(sb.toString()); 52 | ret.fillEndSymbol(); 53 | return ret; 54 | } 55 | else if ('\\' == ch) 56 | { 57 | // check : " \ / b f n r t uxxxx 58 | // sb.append(next); 59 | char next = symbol.next(); 60 | 61 | if (next != 'u') 62 | { 63 | sb.append(ch); 64 | sb.append(next); 65 | } 66 | 67 | if (next == '"' || next == '\\' || next == 'b' || next == 'f' || 68 | next == 'n' || next == 'r' || next == 't') 69 | { 70 | // permit 71 | } 72 | else if (next == 'u') 73 | { 74 | int num = 0; 75 | boolean hasError = false; 76 | String tmp = "" + ch + next; 77 | for (int i = 0; i < 4; i++) 78 | { 79 | next = symbol.next(); 80 | next = Character.toLowerCase(next); 81 | tmp += next; 82 | 83 | if (next >= '0' && next <= '9' || 84 | next >= 'a' && next <= 'f') 85 | { 86 | num *= 16; 87 | num += Integer.valueOf("" + next, 16); 88 | } 89 | else // error 90 | { 91 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(), 92 | symbol.getNearByChars(), "in STRING, only [0-9a-fA-F] are permitted after \\u"); 93 | 94 | ret.addException(warn); 95 | hasError = true; 96 | } 97 | } 98 | 99 | if (!hasError) 100 | { 101 | char c = (char)num; 102 | sb.append(c); 103 | } 104 | else 105 | { 106 | sb.append(tmp); 107 | } 108 | } 109 | else 110 | { 111 | SyntaxWarning warn = new SyntaxWarning(symbol.getLineNo(), symbol.getRowNo(), 112 | symbol.getNearByChars(), "in STRING, only [\\/bfnrtu] are permitted after \\"); 113 | 114 | ret.addException(warn); 115 | } 116 | } 117 | else 118 | { 119 | sb.append(ch); 120 | } 121 | } 122 | 123 | ret.setString(sb.toString()); 124 | SyntaxError error = new SyntaxError(symbol.getLineNo(), symbol.getRowNo(), 125 | symbol.getNearByChars(), "in STRING, a quote(\") is need at the end"); 126 | 127 | ret.addException(error); 128 | return ret; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/Symbol.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import java.nio.CharBuffer; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class Symbol 9 | { 10 | private static final int NEAR_BY_MAX_LEN = 10; 11 | 12 | private final String string; 13 | private final CharBuffer buffer; 14 | 15 | private int lineNo = 1; 16 | private int rowNo = 0; 17 | private int position = 0; 18 | 19 | private int markedLineNo = 0; 20 | private int markedRowNo = 0; 21 | 22 | public Symbol(String string) 23 | { 24 | this.string = string; 25 | this.buffer = CharBuffer.wrap(this.string); 26 | } 27 | 28 | public void mark() 29 | { 30 | buffer.mark(); 31 | markedLineNo = lineNo; 32 | markedRowNo = rowNo; 33 | } 34 | 35 | public void reset() 36 | { 37 | buffer.reset(); 38 | 39 | lineNo = markedLineNo; 40 | rowNo = markedRowNo; 41 | position = buffer.position(); 42 | } 43 | 44 | public boolean hasNext() 45 | { 46 | return buffer.hasRemaining(); 47 | } 48 | 49 | private boolean isNewLine(char ch) 50 | { 51 | return ch == '\n'; 52 | } 53 | 54 | public char next() 55 | { 56 | char ret = buffer.hasRemaining() ? buffer.get() : 0; 57 | if (isNewLine(ret)) 58 | { 59 | lineNo++; 60 | rowNo = 0; 61 | } 62 | else 63 | { 64 | rowNo++; 65 | } 66 | position = buffer.position(); 67 | 68 | return ret; 69 | } 70 | 71 | public String getRemaining() 72 | { 73 | StringBuffer sb = new StringBuffer(); 74 | while (hasNext()) 75 | { 76 | sb.append(next()); 77 | } 78 | return sb.toString(); 79 | } 80 | 81 | public char nextWithoutSpace() 82 | { 83 | while (true) 84 | { 85 | if (!buffer.hasRemaining()) 86 | { 87 | return 0; 88 | } 89 | char ch = buffer.get(); 90 | 91 | if (isNewLine(ch)) 92 | { 93 | lineNo++; 94 | rowNo = 0; 95 | } 96 | else 97 | { 98 | rowNo++; 99 | } 100 | position = buffer.position(); 101 | 102 | if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') 103 | { 104 | continue; 105 | } 106 | 107 | return ch; 108 | } 109 | } 110 | 111 | public int getLineNo() 112 | { 113 | return lineNo; 114 | } 115 | 116 | public int getRowNo() 117 | { 118 | return rowNo; 119 | } 120 | 121 | public String getNearByChars() 122 | { 123 | final int start = Math.max(position - NEAR_BY_MAX_LEN, 0); 124 | final int end = Math.min(position + NEAR_BY_MAX_LEN, string.length()); 125 | 126 | if (start >= end) 127 | { 128 | return null; 129 | } 130 | 131 | return string.substring(start, end); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /java/com/simplemain/kit/json/parser/ValueParser.java: -------------------------------------------------------------------------------- 1 | package com.simplemain.kit.json.parser; 2 | 3 | import com.simplemain.kit.json.element.JsonElement; 4 | 5 | /** 6 | * @author zgwangbo@simplemain.com 7 | */ 8 | public class ValueParser implements ElementParser 9 | { 10 | private static final ElementParser[] PARSERS = 11 | { 12 | new StringParser(), 13 | new NumberParser(), 14 | new BooleanParser(), 15 | new NullParser(), 16 | new ObjectParser(), 17 | new ArrayParser(), 18 | }; 19 | 20 | @Override 21 | public JsonElement parse(Symbol symbol) 22 | { 23 | for (ElementParser parser : PARSERS) 24 | { 25 | JsonElement je = parser.parse(symbol); 26 | if (je != null) 27 | { 28 | return je; 29 | } 30 | } 31 | return null; 32 | } 33 | 34 | } 35 | --------------------------------------------------------------------------------