diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02c3bd8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +node_modules +refs diff --git a/fastjson.js b/fastjson.js new file mode 100644 index 0000000..30bd7f8 --- /dev/null +++ b/fastjson.js @@ -0,0 +1,19 @@ +(function(global){ + + var parser = fastparser; + var JSONFast = { + parse: function(str){ + if(parser.parse(str)){ + return parser.$$; + }else{ + return {}; + } + }, + stringify: function(){ + } + }; + + global.JSONFast = JSONFast; + + +})(this); diff --git a/generate-parser.js b/generate-parser.js new file mode 100644 index 0000000..325c6fc --- /dev/null +++ b/generate-parser.js @@ -0,0 +1,22 @@ + +var fs = require('fs'); + +var Generator = require('jsbison'); + +Generator.lexParser.parse(fs.readFileSync('./json.l').toString()); + + +Generator.bnfParser.parse(fs.readFileSync('./json.y').toString()); + +var bnfcfg = Generator.bnfParser.$$; +bnfcfg.lex = Generator.lexParser.$$; +bnfcfg.type = 'LR(1)'; + + +debugger +var generator = new Generator(bnfcfg); + +var code = generator.generate(); + + +fs.writeFileSync('./parser.js', code); diff --git a/json.l b/json.l new file mode 100644 index 0000000..d62b153 --- /dev/null +++ b/json.l @@ -0,0 +1,21 @@ + +%% + +\/\/[^\n]* /* skip singleline comment */ +\/\*(.|\n|\r)*?\*\/ /* skip multiline comment */ +"(?:\\[bfnrt\/"]|\\u[a-fA-F0-9]{4}|[^"\\])*" this.yytext=this.yytext.slice(1, this.yyleng-1);return "STRING"; +\s+ +\r\n +((0|[1-9][0-9]*)(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?|[0][xX][0-9a-fA-F]+ return "NUMBER" +null return "NULL"; +true return "TRUE"; +false return "FALSE"; +: return ":"; +, return ","; +\[ return "["; +\] return "]"; +\{ return "{"; +\} return "}"; +\s+ /* skip whitespace */ +\n /* skip lineterminal */ +. return "INVALID"; diff --git a/json.y b/json.y new file mode 100644 index 0000000..3575ab4 --- /dev/null +++ b/json.y @@ -0,0 +1,105 @@ +%start Json +%% + +Json : + JsonValue $end + { + this.$$ = $1; + } +; + +JsonValue : + NULL + { + this.$$ = null; + } + | BooleanLiteral + { + this.$$ = $1; + } + | STRING + { + this.$$ = $1; + } + | NUMBER + { + this.$$ = parseFloat($1); + } + | JSONObject + { + this.$$ = $1; + } + | JSONArray + { + this.$$ = $1; + } +; + +BooleanLiteral : + TRUE + { + this.$$ = true; + } + | FALSE + { + this.$$ = false; + } +; + +JSONObject : + { } + { + this.$$ = {}; + } + | { JSONMemberList } + { + this.$$ = $2; + } +; + +JSONMemberList : + JSONMemberList , JSONMember + { + this.$$ = $1; + this.$$ = _.merge(this.$$, $3); + } + | JSONMember + { + this.$$ = $1; + } +; +JSONMember : + STRING : JsonValue + { + this.$$ = {}; + this.$$[$1] = $3; + } +; + +JSONArray : + [ ] + { + this.$$ = []; + } + | [ JSONElementList ] + { + this.$$ = $2; + } +; +JSONElementList: + JSONElementList , JsonValue + { + this.$$ = $1; + this.$$.push($3); + } + | JsonValue + { + this.$$ = [$1]; + } +; + + + +%% + +global.fastparser = parser; diff --git a/nodes.js b/nodes.js new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json new file mode 100644 index 0000000..70bbf52 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "JSONFast", + "description": "基于jsbison生成的JSON的快速解析器。", + "version": "0.1.0", + "homepage": "https://github.com/takumi4ichi/JSONFast", + "author": { + "name": "takumi4ichi", + "email": "takumi4ichi@gmail.com" + }, + "repository": { + "type": "git", + "url": "git@github.com:takumi4ichi/jsonfast.git" + }, + "licenses": [ + { + "type": "MIT", + "url": "/blob/master/LICENSE" + } + ], + "engines": { + "node": ">= 0.8.0" + }, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-watch": "~0.4.0", + "grunt-contrib-jshint": "~0.10.0", + "jsbison": "~0.1.8" + }, + "dependencies": { + "lodash": "^2.4.1" + }, + "keywords": [ + "lib", + "parser", + "javascript", + "json" + ] +} diff --git a/parser.js b/parser.js new file mode 100644 index 0000000..3b8c1ed --- /dev/null +++ b/parser.js @@ -0,0 +1,215 @@ +(function(global, undef){ +if(typeof require === "function"){ _ = require("lodash");} +var parser = { +EOF:"$end", +reset:function (){ + var self = this; + self.lexer.reset(); + }, +lexer: (function(){ +return { +CONST:{"INITIAL":"INITIAL","EOF":"$end"}, +states:{"exclusive":{}}, +rules: [{regex:/^\/\/[^\n]*/,action:' /* skip singleline comment */'},{regex:/^\/\*(.|\n|\r)*?\*\//,action:' /* skip multiline comment */ '},{regex:/^"(?:\\[bfnrt\/"]|\\u[a-fA-F0-9]{4}|[^"\\])*"/,action:' this.yytext=this.yytext.slice(1, this.yyleng-1);return "STRING";'},{regex:/^\s+/,action:''},{regex:/^\r\n/,action:''},{regex:/^((0|[1-9][0-9]*)(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?|[0][xX][0-9a-fA-F]+/,action:' return "NUMBER"'},{regex:/^null/,action:' return "NULL";'},{regex:/^true/,action:' return "TRUE";'},{regex:/^false/,action:' return "FALSE";'},{regex:/^:/,action:' return ":";'},{regex:/^,/,action:' return ",";'},{regex:/^\[/,action:' return "[";'},{regex:/^\]/,action:' return "]";'},{regex:/^\{/,action:' return "{";'},{regex:/^\}/,action:' return "}";'},{regex:/^\s+/,action:' /* skip whitespace */'},{regex:/^\n/,action:' /* skip lineterminal */'},{regex:/^./,action:' return "INVALID";'}], +yymore:function (){ + this._more = true; + }, +stateStack:["INITIAL"], +pushState:function (state){ + this.stateStack.push(state); + }, +popState:function (){ + return this.stateStack.pop(); + }, +getCurrentRules:function (){ + var self = this, + rules = self.rules, + curState = self.stateStack[self.stateStack.length-1], + activeRules = [], + isInclusiveState = true; //是否为包容状态 + + if(self.states.exclusive[curState]){ + isInclusiveState = false; + } + + + for(var i=0, len=rules.length; i -1)){ + activeRules.push(rules[i]); + } + } + + return activeRules; + }, +setInput:function (input){ + _.merge(this, { + input: input, + position: 0, + matched: '', + text: '', + yytext: '', + lineno: 1, + firstline: 1, + lastline: 1, + firstcolumn: 1, + lastcolumn: 1, + _more: false + }); + }, +getToken:function (isDebug){ + var self = this, + token = self.getToken_(isDebug); + + if(!token){ + token = self.getToken(isDebug); + } + + return token; + }, +unToken:function (charsNum){ + this.position -= charsNum; + }, +getToken_:function (isDebug){ + var self = this, + input = self.input.slice(self.position), + regex, + activeRules = self.getCurrentRules(), + matches; + + if(!input){ + return self.CONST.EOF; + } + + if(!activeRules.length && isDebug){ + debugger + //这个断点的原因是,这是编写lex文法时常见的错误,就是自动机陷入一个没有任何规则激活的状态中了 + } + + for(var i=0,len=activeRules.length; i + + + + + + + + + + + diff --git a/test/basic.js b/test/basic.js new file mode 100644 index 0000000..464a946 --- /dev/null +++ b/test/basic.js @@ -0,0 +1,186 @@ +var BASIC = [ + "abc", + null, + true, + false, + 123, + 123.123, + { + }, + { + "image": [ + {"shape": "rect", "fill": "#333", "stroke": "#999", "x": 0.5, "y": 0.5, "width": 47, "height": 47} + ], + "jumpable": 3, + "solid": { + "1": [2,4], + "2": [], + "3": [2,6], + "4": [], + "5": [2,8,1,3,7,9,4,6], + "6": [], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": true,"3": true,"7": true,"9": true} + }, + { + "image": [ + {"shape": "polygon", "fill": "#248", "stroke": "#48f", "points": [[0.5,47.5],[47.5,47.5],[47.5,0.5]]} + ], + "solid": { + "1": [2,4], + "2": [1], + "3": [2], + "4": [], + "5": [2,8,1,3,7,9,4,6], + "6": [], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": true,"3": true,"7": false,"9": true} + }, + { + "image": [ + {"shape": "polygon", "fill": "#248", "stroke": "#48f", "points": [[0.5,0.5],[47.5,47.5],[0.5,47.5]]} + ], + "solid": { + "1": [2], + "2": [3], + "3": [2,6], + "4": [], + "5": [2,8,1,3,7,9,4,6], + "6": [], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": true,"3": true,"7": true,"9": false} + }, + { + "image": [ + {"shape": "polygon", "fill": "#333", "stroke": "#999", "points": [[0.5,0.5],[47.5,47.5],[47.5,0.5]]} + ], + "jumpable": 3, + "solid": { + "1": [2,4], + "2": [], + "3": [2,6], + "4": [], + "5": [2,8,1,3,7,9,4,6], + "6": [3], + "7": [4,8], + "8": [7], + "9": [6,8] + }, + "corners": {"1": false,"3": true,"7": true,"9": true} + }, + { + "image": [ + {"shape": "polygon", "fill": "#333", "stroke": "#999", "points": [[0.5,0.5],[0.5,47.5],[47.5,0.5]]} + ], + "jumpable": 3, + "solid": { + "1": [2,4], + "2": [], + "3": [2,6], + "4": [1], + "5": [2,8,1,3,7,9,4,6], + "6": [], + "7": [4,8], + "8": [9], + "9": [6,8] + }, + "corners": {"1": true,"3": false,"7": true,"9": true} + }, + { + "image": [ + {"shape": "polygon", "fill": "#482", "stroke": "#8f4", "points": [[0.5,47.5],[0.5,23.5],[24.5,23.5],[24.5,0.5],[47.5,0.5],[47.5,47.5]]} + ], + "jumpable": 3, + "solid": { + "1": [2,4], + "2": [], + "3": [6,2], + "4": [], + "5": [2,8,1,3,7,9,4,6], + "6": [9], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": true,"3": true,"7": false,"9": true} + }, + { + "image": [ + {"shape": "polygon", "fill": "#482", "stroke": "#8f4", "points": [[0.5,0.5],[23.5,0.5],[23.5,24.5],[47.5,24.5],[47.5,47.5],[0.5,47.5]]} + ], + "jumpable": 3, + "solid": { + "1": [4,2], + "2": [], + "3": [2,6], + "4": [7], + "5": [2,8,1,3,7,9,4,6], + "6": [], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": true,"3": true,"7": true,"9": false} + }, + { + "image": [ + {"shape": "circle", "fill": "#ff0", "stroke": "#ff8", "cx": 24, "cy": 24, "r": 18} + ], + "item": true + }, + { + "image": [ + {"shape": "polygon", "fill": "#842", "stroke": "#f84", "points": [[4.5,0.5],[14.5,0.5],[14.5,17.5],[34,17.5],[33.5,0.5],[43.5,0.5],[43.5,47.5],[33.5,47.5],[33.5,30.5],[14.5,30.5],[14.5,47.5],[4.5,47.5]]} + ], + "jumpable": 3 + }, + { + "image": [ + {"shape": "polygon", "fill": "#333", "stroke": "#999", "points": [[0.5,0.5],[47.5,0.5],[24,47.5]]} + ], + "jumpable": 3, + "solid": { + "1": [2,4], + "2": [], + "3": [2,6], + "4": [1], + "5": [2,8,1,3,7,9,4,6], + "6": [3], + "7": [4,8], + "8": [], + "9": [6,8] + }, + "corners": {"1": false,"3": false,"7": true,"9": true} + }, + { + "image": [ + {"shape": "rect", "fill": "#114acb", "x": 0.5, "y": 0.5, "width": 47, "height": 47}, + {"shape": "polygon", "fill": "rgba(255,255,255,0.30)", "points": [[0.5,0.5],[47.5,0.5],[40,8],[8,8],[8,40],[0.5,47.5]]}, + {"shape": "polygon", "fill": "rgba(0,0,0,0.30)", "points": [[47.5,0.5],[48,48],[0.5,47.5],[8,40],[40,40],[40,8]]}, + {"shape": "polygon", "fill": "rgb(255,255,0)", "stroke": "rgba(255,255,0,0.5)", "points": [[24,9],[35,20],[26,29],[26,33],[22,33],[22,27],[29,20],[24,15],[16,23],[13,20]]}, + {"shape": "rect", "fill": "rgb(255,255,0)", "stroke": "rgba(255,255,0,0.5)", "x": 22, "y":35, "width": 4, "height": 4} + ], + "item": true + }, + { + "image": [ + {"shape": "circle", "fill": "#80f", "stroke": "#88f", "cx": 24, "cy": 24, "r": 18} + ], + "item": true + }, + { + "image": [ + {"shape": "circle", "fill": "#4f4", "stroke": "#8f8", "cx": 24, "cy": 24, "r": 18} + ], + "item": true + } +];