-
Notifications
You must be signed in to change notification settings - Fork 6
/
jsonParser.e
412 lines (377 loc) · 11.5 KB
/
jsonParser.e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/*
JSON parser
IF you are saving icons you must open icon library in advance
*/
OPT OSVERSION=37
OPT MODULE
-> MODULE 'dos/dos','workbench/workbench','icon','wb','dos/dosextens'
MODULE '*miscfuncs'
CONST JSMN_PARENT_LINKS=0
CONST JSMN_STRICT=1
CONST BUFSIZ = 8192
/**
* JSON type identifier. Basic types are:
* o Object
* o Array
* o String
* o Other primitive: number, boolean (true/false) or NIL
*/
EXPORT ENUM JSMN_UNDEFINED = 0,JSMN_OBJECT = 1,JSMN_ARRAY = 2,JSMN_STRING = 3,JSMN_PRIMITIVE = 4
EXPORT ENUM
/* Not enough tokens were provided */
JSMN_ERROR_NOMEM = -1,
/* Invalid character inside JSON string */
JSMN_ERROR_INVAL = -2,
/* The string is not a full JSON packet, more bytes expected */
JSMN_ERROR_PART = -3
/**
* JSON token description.
* type type (object, array, string etc.)
* start start position in JSON data string
* end end position in JSON data string
*/
EXPORT OBJECT jsmntok_t
type
start:LONG
end:LONG
size:LONG
->#ifdef JSMN_PARENT_LINKS
parent:LONG
->#endif
ENDOBJECT
/**
* JSON parser. Contains an array of token blocks available. Also stores
* the string being parsed now and current position in that string
*/
EXPORT OBJECT jsmn_parser
pos:LONG /* offset in the JSON string */
toknext:LONG /* next token to allocate */
toksuper:LONG /* superior token node, e.g parent object or array */
ENDOBJECT
/**
* Create JSON parser over an array of tokens
*/
-> jsmn_init(jsmn_parser *parser)
/**
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
* a single JSON object.
*/
->int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
/**
* Allocates a fresh unused token from the token pool.
*/
PROC jsmn_alloc_token(parser:PTR TO jsmn_parser,tokens, num_tokens)
DEF tok:PTR TO jsmntok_t
IF (parser.toknext >= num_tokens)
RETURN NIL
ENDIF
tok:=tokens+(parser.toknext*SIZEOF jsmntok_t)
parser.toknext:=parser.toknext+1
tok.start:=-1
tok.end:=-1
tok.size:=0
IF JSMN_PARENT_LINKS
tok.parent:=-1
ENDIF
ENDPROC tok
/**
* Fills token type and boundaries.
*/
PROC jsmn_fill_token(token:PTR TO jsmntok_t, type,start, end)
token.type:=type
token.start:=start
token.end:=end
token.size:=0
ENDPROC
/**
* Fills next available token with JSON primitive.
*/
PROC jsmn_parse_primitive(parser:PTR TO jsmn_parser, js: PTR TO CHAR,len,tokens, num_tokens)
DEF token:PTR TO jsmntok_t, start,ch,found
start:=parser.pos
WHILE (parser.pos < len) AND (js[parser.pos] <> 0)
ch:=js[parser.pos]
/* In strict mode primitive must be followed by "," or "}" or "]" */
found:=FALSE
IF JSMN_STRICT AND (ch=":")
found:=TRUE
ELSEIF (ch="\t") OR (ch="\b") OR (ch="\n") OR (ch=" ") OR (ch=",") OR (ch="]") OR (ch="}")
found:=TRUE
ENDIF
EXIT found
IF ((ch < 32) OR (ch >= 127))
parser.pos:=start
RETURN JSMN_ERROR_INVAL
ENDIF
parser.pos:=parser.pos+1
ENDWHILE
IF JSMN_STRICT AND (found=FALSE)
/* In strict mode primitive must be followed by a comma/object/array */
parser.pos:=start
RETURN JSMN_ERROR_PART
ENDIF
IF (tokens = NIL)
parser.pos:=parser.pos-1
RETURN 0
ENDIF
token:=jsmn_alloc_token(parser, tokens, num_tokens)
IF (token = NIL)
parser.pos:=start
RETURN JSMN_ERROR_NOMEM
ENDIF
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser.pos)
IF JSMN_PARENT_LINKS
token.parent:=parser.toksuper
ENDIF
parser.pos:=parser.pos-1
ENDPROC 0
/**
* Fills next token with JSON string.
*/
PROC jsmn_parse_string(parser:PTR TO jsmn_parser, js:PTR TO CHAR,len, tokens, num_tokens)
DEF token:PTR TO jsmntok_t
DEF start
DEF c,i,ch
start:=parser.pos
parser.pos:=parser.pos+1
/* Skip starting quote */
WHILE ((parser.pos < len) AND (js[parser.pos] <> 0))
c:=js[parser.pos]
/* Quote: end of string */
IF (c = 34)
IF (tokens = NIL)
RETURN 0
ENDIF
token:=jsmn_alloc_token(parser, tokens, num_tokens)
IF (token = NIL)
parser.pos:=start
RETURN JSMN_ERROR_NOMEM
ENDIF
jsmn_fill_token(token, JSMN_STRING, start+1, parser.pos)
IF JSMN_PARENT_LINKS
token.parent:=parser.toksuper
ENDIF
RETURN 0
ENDIF
/* Backslash: Quoted symbol expected */
IF ((c = "\\") AND (parser.pos + 1 < len))
parser.pos:=parser.pos+1
ch:=js[parser.pos]
SELECT ch
/* Allowed escaped symbols */
CASE 34
CASE "/"
CASE "\\"
CASE "b"
CASE "f"
CASE "r"
CASE "n"
CASE "t"
/* Allows escaped symbol \uXXXX */
CASE "u"
parser.pos:=parser.pos+1
i:=0
WHILE (i < 4) AND (parser.pos < len) AND (js[parser.pos] <> 0)
/* If it isn't a hex character we have an error */
IF(Not(((js[parser.pos] >= 48) AND (js[parser.pos] <= 57)) OR /* 0-9 */
((js[parser.pos] >= 65) AND (js[parser.pos] <= 70)) OR /* A-F */
((js[parser.pos] >= 97) AND (js[parser.pos] <= 102)))) /* a-f */
parser.pos:=start
RETURN JSMN_ERROR_INVAL
ENDIF
parser.pos:=parser.pos+1
i++
ENDWHILE
parser.pos:=parser.pos-1
/* Unexpected symbol */
DEFAULT
parser.pos:=start
RETURN JSMN_ERROR_INVAL
ENDSELECT
ENDIF
parser.pos:=parser.pos+1
ENDWHILE
parser.pos:=start
ENDPROC JSMN_ERROR_PART
/**
* Parse JSON string and fill tokens.
*/
EXPORT PROC jsmn_parse(parser:PTR TO jsmn_parser, js:PTR TO CHAR, len,tokens, num_tokens)
DEF r,i
DEF token:PTR TO jsmntok_t
DEF count
DEF c,exit=FALSE
DEF type
DEF t:PTR TO jsmntok_t
DEF tok:PTR TO jsmntok_t
count:=parser.toknext
WHILE ((parser.pos < len) AND (js[parser.pos] <> 0))
c:=js[parser.pos]
IF (c="{") OR (c="[")
count++
IF (tokens <> NIL)
token:=jsmn_alloc_token(parser, tokens, num_tokens)
IF (token = NIL)
WriteF('1.JSMN_ERROR_NOMEM pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_NOMEM
ENDIF
IF (parser.toksuper <> -1)
tok:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
tok.size:=tok.size+1
IF JSMN_PARENT_LINKS THEN token.parent:=parser.toksuper
ENDIF
token.type:=(IF c ="{" THEN JSMN_OBJECT ELSE JSMN_ARRAY)
token.start:=parser.pos
parser.toksuper:= parser.toknext - 1
ENDIF
ELSEIF (c="}") OR (c="]")
IF (tokens <> NIL)
type:=(IF c = "}" THEN JSMN_OBJECT ELSE JSMN_ARRAY)
IF JSMN_PARENT_LINKS
IF (parser.toknext < 1)
WriteF('2.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
token:=tokens+((parser.toknext - 1)*SIZEOF jsmntok_t)
exit:=FALSE
WHILE exit=FALSE
IF ((token.start <> -1) AND (token.end = -1))
IF (token.type <> type)
WriteF('3.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
token.end:=parser.pos + 1
parser.toksuper:= token.parent
exit:=TRUE
ELSEIF (token.parent = -1)
IF((token.type <> type) OR (parser.toksuper = -1))
WriteF('4.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
->RETURN JSMN_ERROR_INVAL
ENDIF
exit:=TRUE
ELSE
token:=tokens+(token.parent*SIZEOF jsmntok_t)
ENDIF
ENDWHILE
ELSE
exit:=FALSE
i:=parser.toknext - 1
WHILE i>=0
token:= tokens+(i*SIZEOF jsmntok_t)
IF ((token.start <> -1) AND (token.end = -1) )
IF (token.type <> type)
WriteF('5.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
parser.toksuper:=-1
token.end:=parser.pos + 1
exit:=TRUE
ENDIF
EXIT exit
i--
ENDWHILE
/* Error if unmatched closing bracket */
IF (i = -1)
WriteF('6.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
exit:=FALSE
WHILE (i>=0) AND (exit=FALSE)
token:=tokens+(i*SIZEOF jsmntok_t)
IF ((token.start <> -1) AND (token.end = -1))
parser.toksuper:=i
exit:=TRUE
ENDIF
i--
ENDWHILE
ENDIF
ENDIF
ELSEIF c=34
r:=jsmn_parse_string(parser, js, len, tokens, num_tokens)
IF (r < 0) THEN RETURN r
count++
IF ((parser.toksuper <> -1) AND (tokens <> NIL))
tok:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
tok.size:=tok.size+1
ENDIF
->break
ELSEIF (c="\t") OR (c="\b") OR (c="\n") OR (c=" ")
->break
ELSEIF c=":"
parser.toksuper:=parser.toknext - 1
ELSEIF c=","
IF (tokens <> NIL) AND (parser.toksuper <> -1)
tok:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
IF (tok.type <> JSMN_ARRAY) AND (tok.type <> JSMN_OBJECT)
IF JSMN_PARENT_LINKS
parser.toksuper:=tok.parent
ELSE
exit:=FALSE
FOR i:= parser.toknext - 1 TO 0 STEP -1
tok:=tokens+(i*SIZEOF jsmntok_t)
IF ((tok.type = JSMN_ARRAY) OR (tok.type = JSMN_OBJECT))
IF ((tok.start <> -1) AND (tok.end = -1))
parser.toksuper:=i
exit:=TRUE
ENDIF
ENDIF
EXIT exit
ENDFOR
ENDIF
ENDIF
ENDIF
ELSEIF JSMN_STRICT
IF ((c="-") OR (c="0") OR (c="1") OR (c="2") OR (c="3") OR (c="4") OR (c="5") OR (c="6") OR (c="7") OR (c="8") OR (c="9") OR (c="t") OR (c="f") OR (c="n"))
/* In strict mode primitives are: numbers and booleans */
/* And they must not be keys of the object */
IF ((tokens <> NIL) AND (parser.toksuper <> -1))
t:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
IF ((t.type = JSMN_OBJECT) OR ((t.type = JSMN_STRING) AND (t.size <> 0)))
WriteF('7.JSMN_ERROR_INVAL pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
ENDIF
r:=jsmn_parse_primitive(parser, js, len, tokens, num_tokens)
IF (r < 0) THEN RETURN r
count++
IF ((parser.toksuper <> -1) AND (tokens <> NIL))
tok:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
tok.size:=tok.size+1
ENDIF
ELSE
/* Unexpected char in strict mode */
WriteF('8.JSMN_ERROR_INVAL c=\c, pos=\d,count=\d\n',c,parser.pos,count)
RETURN JSMN_ERROR_INVAL
ENDIF
ELSE /*JSMN_STRICT=FALSE*/
/* In non-strict mode every unquoted value is a primitive */
r:=jsmn_parse_primitive(parser, js, len, tokens, num_tokens)
IF (r < 0) THEN RETURN r
count++
IF ((parser.toksuper <> -1) AND (tokens <> NIL))
tok:=tokens+(parser.toksuper*SIZEOF jsmntok_t)
tok.size:=tok.size+1
ENDIF
ENDIF
parser.pos:=parser.pos+1
ENDWHILE
IF (tokens <> NIL)
FOR i:=parser.toknext - 1 TO 0 STEP -1
/* Unmatched opened object or array */
tok:=tokens+(i*SIZEOF jsmntok_t)
IF ((tok.start <> -1) AND (tok.end = -1))
WriteF('9.JSMN_ERROR_PART pos=\d,count=\d\n',parser.pos,count)
RETURN JSMN_ERROR_PART
ENDIF
ENDFOR
ENDIF
ENDPROC count
/**
* Creates a new parser based over a given buffer with an array of tokens
* available.
*/
EXPORT PROC jsmn_init(parser:PTR TO jsmn_parser)
parser.pos:=0
parser.toknext:=0
parser.toksuper:=-1
ENDPROC