001 0000 ; MSX BASIC JSON Parser 002 0000 ; by Ricardo Bittencourt 2017 003 0000 004 0000 output json.bin 005 0000 006 0000 org 0D000h - 7 007 CFF9 008 CFF9 ; ---------------------------------------------------------------- 009 CFF9 ; MSX bios 010 CFF9 011 CFF9 usrtab equ 0F39Ah ; Callbacks for USR functions 012 CFF9 valtyp equ 0F663h ; Type of argument in DAC 013 CFF9 dac equ 0F7F6h ; Accumulator for MSX BASIC 014 CFF9 dsctmp equ 0F698h ; Temporary string descriptor 015 CFF9 type_mismatch equ 0406Dh ; Type mismatch error handler 016 CFF9 error_handler equ 0406Fh ; Generic BASIC error handler 017 CFF9 illegal_fcall equ 00005h ; Error code for Illegal function call 018 CFF9 019 CFF9 ; ---------------------------------------------------------------- 020 CFF9 ; BIN header 021 CFF9 022 CFF9 FE db 0FEh 023 CFFA 00 D0 dw start_bin 024 CFFC F8 D2 dw end_bin - 1 025 CFFE 00 D0 dw start_bin 026 D000 027 D000 ; ---------------------------------------------------------------- 028 D000 ; Initialization. 029 D000 030 D000 start_bin: 031 D000 21 11 D0 ld hl, set_json_start 032 D003 22 9A F3 ld (usrtab + 0), hl 033 D006 21 2F D0 ld hl, get_json_type 034 D009 22 9C F3 ld (usrtab + 2), hl 035 D00C 23 inc hl 036 D00D 22 9E F3 ld (usrtab + 4), hl 037 D010 C9 ret 038 D011 039 D011 assert (get_json_type == get_json_value + 1) 040 D011 041 D011 ; ---------------------------------------------------------------- 042 D011 ; Set json start 043 D011 044 D011 set_json_start: 045 D011 ; Check for integer argument 046 D011 3A 63 F6 ld a, (valtyp) 047 D014 FE 02 cp 2 048 D016 C2 6D 40 jp nz, type_mismatch 049 D019 ; Set json start 050 D019 2A F8 F7 ld hl, (dac + 2) 051 D01C 22 F3 D2 ld (json_start), hl 052 D01F ; Check for valid json. 053 D01F CD CD D1 call check_json 054 D022 ; Return 0=error, -1=success 055 D022 3F ccf 056 D023 ED 62 sbc hl, hl 057 D025 38 03 jr c, return_integer 058 D027 22 F3 D2 ld (json_start), hl 059 D02A return_integer: 060 D02A 22 F8 F7 ld (dac + 2), hl 061 D02D C9 ret 062 D02E 063 D02E ; ---------------------------------------------------------------- 064 D02E ; Get json token type 065 D02E 066 D02E get_json_value: 067 D02E ; Alternate entry point, set token type as non-zero. 068 D02E 3E db 03Eh 069 D02F get_json_type: 070 D02F ; Set token type as zero. 071 D02F AF xor a 072 D030 get_json_action: 073 D030 32 F8 D2 ld (get_action), a 074 D033 ; Check for string argument 075 D033 3A 63 F6 ld a, (valtyp) 076 D036 FE 03 cp 3 077 D038 C2 6D 40 jp nz, type_mismatch 078 D03B ; Check if json start was set 079 D03B 2A F3 D2 ld hl, (json_start) 080 D03E 7C ld a, h 081 D03F B5 or l 082 D040 28 6A jr z, ifc_error 083 D042 ; Save sentinel 084 D042 E5 push hl 085 D043 DD 2A F8 F7 ld ix, (dac + 2) 086 D047 DD 4E 00 ld c, (ix) 087 D04A DD 6E 01 ld l, (ix + 1) 088 D04D DD 66 02 ld h, (ix + 2) 089 D050 54 ld d, h 090 D051 5D ld e, l 091 D052 06 00 ld b, 0 092 D054 09 add hl, bc 093 D055 7E ld a, (hl) 094 D056 22 F6 D2 ld (sentinel_pos), hl 095 D059 32 F5 D2 ld (sentinel), a 096 D05C 70 ld (hl), b 097 D05D ; Start parsing 098 D05D D9 exx 099 D05E E1 pop hl 100 D05F D9 exx 101 D060 EB ex de, hl 102 D061 CD 94 D0 call parse_token_main 103 D064 47 ld b, a 104 D065 ; Restore sentinel 105 D065 2A F6 D2 ld hl, (sentinel_pos) 106 D068 3A F5 D2 ld a, (sentinel) 107 D06B 77 ld (hl), a 108 D06C ; Check for error 109 D06C CB 78 bit 7, b 110 D06E 20 3C jr nz, ifc_error 111 D070 ; Check for string action 112 D070 3A F8 D2 ld a, (get_action) 113 D073 B7 or a 114 D074 3E 02 ld a, 2 115 D076 20 08 jr nz, get_string 116 D078 ; Return an integer 117 D078 26 00 ld h, 0 118 D07A 68 ld l, b 119 D07B return_valtyp: 120 D07B 32 63 F6 ld (valtyp), a 121 D07E 18 AA jr return_integer 122 D080 123 D080 ; ---------------------------------------------------------------- 124 D080 ; Get json value as a string 125 D080 126 D080 get_string: 127 D080 ; Return a string 128 D080 B8 cp b 129 D081 30 29 jr nc, ifc_error 130 D083 3C inc a 131 D084 21 98 F6 ld hl, dsctmp 132 D087 18 F2 jr return_valtyp 133 D089 134 D089 ; ---------------------------------------------------------------- 135 D089 136 D089 parse_end_collection: 137 D089 23 inc hl 138 D08A D9 exx 139 D08B 7B ld a, e 140 D08C B2 or d 141 D08D 1B dec de 142 D08E C2 B9 D1 jp nz, skip_whitespace_exx 143 D091 C1 pop bc 144 D092 D9 exx 145 D093 ; Fall through to parse_token_main_exx 146 D093 147 D093 ; ---------------------------------------------------------------- 148 D093 149 D093 parse_token_main_exx: 150 D093 D9 exx 151 D094 parse_token_main: 152 D094 CD BA D1 call skip_whitespace 153 D097 B7 or a 154 D098 23 inc hl 155 D099 28 16 jr z, parse_identify 156 D09B FE 23 cp '#' 157 D09D 28 39 jr z, parse_position 158 D09F FE 24 cp '$' 159 D0A1 CA 33 D1 jp z, parse_value 160 D0A4 FE 26 cp '&' 161 D0A6 CA 3E D1 jp z, parse_key 162 D0A9 parse_return_error: 163 D0A9 3E FF ld a, 255 164 D0AB C9 ret 165 D0AC ifc_error: 166 D0AC 1E 05 ld e, illegal_fcall 167 D0AE C3 6F 40 jp error_handler 168 D0B1 169 D0B1 ; ---------------------------------------------------------------- 170 D0B1 171 D0B1 parse_identify: 172 D0B1 D9 exx 173 D0B2 3A F8 D2 ld a, (get_action) 174 D0B5 B7 or a 175 D0B6 C2 87 D1 jp nz, parse_string 176 D0B9 CD BA D1 call skip_whitespace 177 D0BC 01 01 07 ld bc, 7 * 256 + 1 178 D0BF 11 D7 D2 ld de, identifiers 179 D0C2 EB ex de, hl 180 D0C3 1: 181 D0C3 BE cp (hl) 182 D0C4 28 0F jr z, 2f 183 D0C6 0C inc c 184 D0C7 23 inc hl 185 D0C8 10 F9 djnz 1b 186 D0CA EB ex de, hl 187 D0CB E5 push hl 188 D0CC CD 28 D2 call check_number 189 D0CF E1 pop hl 190 D0D0 3F ccf 191 D0D1 9F sbc a, a 192 D0D2 E6 04 and 4 193 D0D4 C9 ret 194 D0D5 2: 195 D0D5 EB ex de, hl 196 D0D6 79 ld a, c 197 D0D7 C9 ret 198 D0D8 199 D0D8 ; ---------------------------------------------------------------- 200 D0D8 201 D0D8 parse_position: 202 D0D8 11 00 00 ld de, 0 203 D0DB CD BA D1 call skip_whitespace 204 D0DE CD CF D2 call check_digit 205 D0E1 30 C6 jr nc, parse_return_error 206 D0E3 1: 207 D0E3 CD CF D2 call check_digit 208 D0E6 30 11 jr nc, parse_fetch 209 D0E8 D6 30 sub '0' 210 D0EA 4B ld c, e 211 D0EB 42 ld b, d 212 D0EC EB ex de, hl 213 D0ED 29 add hl, hl 214 D0EE 29 add hl, hl 215 D0EF 09 add hl, bc 216 D0F0 29 add hl, hl 217 D0F1 4F ld c, a 218 D0F2 06 00 ld b, 0 219 D0F4 09 add hl, bc 220 D0F5 EB ex de, hl 221 D0F6 23 inc hl 222 D0F7 18 EA jr 1b 223 D0F9 224 D0F9 ; ---------------------------------------------------------------- 225 D0F9 226 D0F9 parse_fetch: 227 D0F9 CD B9 D1 call skip_whitespace_exx 228 D0FC FE 7B cp '{' 229 D0FE 28 19 jr z, parse_object 230 D100 FE 5B cp '[' 231 D102 20 A5 jr nz, parse_return_error 232 D104 1: 233 D104 CD 89 D0 call parse_end_collection 234 D107 CD 06 D2 call check_anything 235 D10A 38 0B jr c, parse_fail 236 D10C CD BA D1 call skip_whitespace 237 D10F FE 5D cp ']' 238 D111 28 04 jr z, parse_fail 239 D113 FE 2C cp ',' 240 D115 28 ED jr z, 1b 241 D117 parse_fail: 242 D117 AF xor a 243 D118 C9 ret 244 D119 245 D119 ; ---------------------------------------------------------------- 246 D119 247 D119 parse_object: 248 D119 CD 89 D0 call parse_end_collection 249 D11C CD 21 D1 call parse_next_item 250 D11F 18 F8 jr parse_object 251 D121 252 D121 ; ---------------------------------------------------------------- 253 D121 254 D121 parse_next_item: 255 D121 CD 02 D2 call check_key_value 256 D124 38 0A jr c, parse_not_found 257 D126 CD BA D1 call skip_whitespace 258 D129 FE 7D cp '}' 259 D12B 28 03 jr z, parse_not_found 260 D12D FE 2C cp ',' 261 D12F C8 ret z 262 D130 parse_not_found: 263 D130 E1 pop hl 264 D131 AF xor a 265 D132 C9 ret 266 D133 267 D133 ; ---------------------------------------------------------------- 268 D133 269 D133 compare_fail equ parse_not_found 270 D133 271 D133 ; ---------------------------------------------------------------- 272 D133 273 D133 parse_value: 274 D133 CD B9 D1 call skip_whitespace_exx 275 D136 CD F4 D1 call check_key 276 D139 38 DC jr c, parse_fail 277 D13B C3 93 D0 jp parse_token_main_exx 278 D13E 279 D13E ; ---------------------------------------------------------------- 280 D13E 281 D13E parse_key: 282 D13E CD B9 D1 call skip_whitespace_exx 283 D141 FE 7B cp '{' 284 D143 C2 93 D0 jp nz, parse_token_main_exx 285 D146 CD CA D1 call skip_whitespace_next 286 D149 D9 exx 287 D14A 1: 288 D14A CD 59 D1 call compare_key 289 D14D 38 E4 jr c, parse_value 290 D14F CD B9 D1 call skip_whitespace_exx 291 D152 CD 21 D1 call parse_next_item 292 D155 23 inc hl 293 D156 D9 exx 294 D157 18 F1 jr 1b 295 D159 296 D159 ; ---------------------------------------------------------------- 297 D159 298 D159 compare_key: 299 D159 ; Returns CF=key found, NC=key not found 300 D159 E5 push hl 301 D15A CD B9 D1 call skip_whitespace_exx 302 D15D E5 push hl 303 D15E D9 exx 304 D15F D1 pop de 305 D160 1A ld a, (de) 306 D161 FE 22 cp '"' 307 D163 20 CB jr nz, compare_fail 308 D165 13 inc de 309 D166 1: 310 D166 7E ld a, (hl) 311 D167 B7 or a 312 D168 28 15 jr z, 2f 313 D16A FE 23 cp '#' 314 D16C 28 11 jr z, 2f 315 D16E FE 26 cp '&' 316 D170 28 0D jr z, 2f 317 D172 FE 24 cp '$' 318 D174 28 09 jr z, 2f 319 D176 EB ex de, hl 320 D177 BE cp (hl) 321 D178 EB ex de, hl 322 D179 20 B5 jr nz, compare_fail 323 D17B 23 inc hl 324 D17C 13 inc de 325 D17D 18 E7 jr 1b 326 D17F 2: 327 D17F 1A ld a, (de) 328 D180 FE 22 cp '"' 329 D182 20 AC jr nz, compare_fail 330 D184 C1 pop bc 331 D185 compare_success: 332 D185 37 scf 333 D186 C9 ret 334 D187 335 D187 ; ---------------------------------------------------------------- 336 D187 337 D187 json_error equ compare_success 338 D187 339 D187 ; ---------------------------------------------------------------- 340 D187 341 D187 parse_string: 342 D187 CD BA D1 call skip_whitespace 343 D18A FE 7B cp '{' 344 D18C CA 17 D1 jp z, parse_fail 345 D18F FE 5B cp '[' 346 D191 CA 17 D1 jp z, parse_fail 347 D194 FE 22 cp '"' 348 D196 28 16 jr z, parse_string_literal 349 D198 22 99 F6 ld (dsctmp + 1), hl 350 D19B E5 push hl 351 D19C CD 06 D2 call check_anything 352 D19F parse_string_common: 353 D19F B7 or a 354 D1A0 D1 pop de 355 D1A1 ED 52 sbc hl, de 356 D1A3 7C ld a, h 357 D1A4 C6 FF add a, 255 358 D1A6 9F sbc a, a 359 D1A7 B5 or l 360 D1A8 32 98 F6 ld (dsctmp), a 361 D1AB 3E 03 ld a, 3 362 D1AD C9 ret 363 D1AE 364 D1AE ; ---------------------------------------------------------------- 365 D1AE 366 D1AE parse_string_literal: 367 D1AE 23 inc hl 368 D1AF 22 99 F6 ld (dsctmp + 1), hl 369 D1B2 E5 push hl 370 D1B3 CD 97 D2 call check_contents_no_inc 371 D1B6 2B dec hl 372 D1B7 18 E6 jr parse_string_common 373 D1B9 374 D1B9 ; ---------------------------------------------------------------- 375 D1B9 376 D1B9 skip_whitespace_exx: 377 D1B9 D9 exx 378 D1BA skip_whitespace: 379 D1BA 7E ld a, (hl) 380 D1BB FE 20 cp 32 381 D1BD 28 0B jr z, skip_whitespace_next 382 D1BF FE 0A cp 10 383 D1C1 28 07 jr z, skip_whitespace_next 384 D1C3 FE 0D cp 13 385 D1C5 28 03 jr z, skip_whitespace_next 386 D1C7 FE 09 cp 9 387 D1C9 C0 ret nz 388 D1CA skip_whitespace_next: 389 D1CA 23 inc hl 390 D1CB 18 ED jr skip_whitespace 391 D1CD 392 D1CD ; ---------------------------------------------------------------- 393 D1CD 394 D1CD check_json: 395 D1CD CD BA D1 call skip_whitespace 396 D1D0 FE 5B cp '[' 397 D1D2 CA 73 D2 jp z, check_array 398 D1D5 FE 7B cp '{' 399 D1D7 20 AC jr nz, json_error 400 D1D9 ; Fall through to check_object 401 D1D9 402 D1D9 ; ---------------------------------------------------------------- 403 D1D9 404 D1D9 check_object: 405 D1D9 ; HL must be pointing to '{' 406 D1D9 CD CA D1 call skip_whitespace_next 407 D1DC FE 7D cp '}' 408 D1DE 28 20 jr z, check_success 409 D1E0 check_object_key: 410 D1E0 CD 02 D2 call check_key_value 411 D1E3 D8 ret c 412 D1E4 CD BA D1 call skip_whitespace 413 D1E7 FE 7D cp '}' 414 D1E9 28 15 jr z, check_success 415 D1EB FE 2C cp ',' 416 D1ED 20 96 jr nz, json_error 417 D1EF CD CA D1 call skip_whitespace_next 418 D1F2 18 EC jr check_object_key 419 D1F4 420 D1F4 ; ---------------------------------------------------------------- 421 D1F4 422 D1F4 check_key: 423 D1F4 CD 91 D2 call check_string 424 D1F7 D8 ret c 425 D1F8 CD BA D1 call skip_whitespace 426 D1FB FE 3A cp ':' 427 D1FD 28 01 jr z, check_success 428 D1FF 37 scf 429 D200 check_success: 430 D200 23 inc hl 431 D201 C9 ret 432 D202 433 D202 ; ---------------------------------------------------------------- 434 D202 435 D202 check_key_value: 436 D202 CD F4 D1 call check_key 437 D205 D8 ret c 438 D206 ; Fall through to check_anything 439 D206 440 D206 ; ---------------------------------------------------------------- 441 D206 442 D206 check_anything: 443 D206 CD BA D1 call skip_whitespace 444 D209 FE 7B cp '{' 445 D20B 28 CC jr z, check_object 446 D20D FE 5B cp '[' 447 D20F 28 62 jr z, check_array 448 D211 FE 22 cp '"' 449 D213 CA 91 D2 jp z, check_string 450 D216 FE 74 cp 't' 451 D218 11 E3 D2 ld de, token_true 452 D21B 28 4B jr z, check_string_literal 453 D21D FE 66 cp 'f' 454 D21F 11 E8 D2 ld de, token_false 455 D222 28 44 jr z, check_string_literal 456 D224 FE 6E cp 'n' 457 D226 28 3D jr z, check_null 458 D228 ; Fall through to check_number 459 D228 460 D228 ; ---------------------------------------------------------------- 461 D228 462 D228 check_number: 463 D228 FE 2D cp '-' 464 D22A 20 02 jr nz, 2f 465 D22C 23 inc hl 466 D22D 7E ld a, (hl) 467 D22E 2: 468 D22E FE 30 cp '0' 469 D230 20 04 jr nz, 3f 470 D232 23 inc hl 471 D233 7E ld a, (hl) 472 D234 18 04 jr check_fraction 473 D236 3: 474 D236 CD 58 D2 call check_digit_sequence 475 D239 D8 ret c 476 D23A ; Fall through to check_fraction 477 D23A 478 D23A ; ---------------------------------------------------------------- 479 D23A 480 D23A check_fraction: 481 D23A FE 2E cp '.' 482 D23C 20 05 jr nz, check_scientific 483 D23E 23 inc hl 484 D23F CD 58 D2 call check_digit_sequence 485 D242 D8 ret c 486 D243 ; Fall through to check_scientific 487 D243 488 D243 ; ---------------------------------------------------------------- 489 D243 490 D243 check_scientific: 491 D243 F6 20 or 32 492 D245 FE 65 cp 'e' 493 D247 28 02 jr z, 1f 494 D249 B7 or a 495 D24A C9 ret 496 D24B 1: 497 D24B 23 inc hl 498 D24C 7E ld a, (hl) 499 D24D FE 2B cp '+' 500 D24F 20 02 jr nz, 2f 501 D251 EE 06 xor 6 502 D253 2: 503 D253 FE 2D cp '-' 504 D255 20 01 jr nz, check_digit_sequence 505 D257 23 inc hl 506 D258 ; Fall through to check_digit_sequence 507 D258 508 D258 ; ---------------------------------------------------------------- 509 D258 510 D258 check_digit_sequence: 511 D258 ; Returns CF=not a digit sequence, NC=digit sequence 512 D258 CD CF D2 call check_digit 513 D25B D2 85 D1 jp nc, json_error 514 D25E 1: 515 D25E 23 inc hl 516 D25F CD CF D2 call check_digit 517 D262 38 FA jr c, 1b 518 D264 C9 ret 519 D265 520 D265 ; ---------------------------------------------------------------- 521 D265 522 D265 check_null: 523 D265 11 EE D2 ld de, token_null 524 D268 check_string_literal: 525 D268 1A ld a, (de) 526 D269 B7 or a 527 D26A C8 ret z 528 D26B BE cp (hl) 529 D26C C2 85 D1 jp nz, json_error 530 D26F 23 inc hl 531 D270 13 inc de 532 D271 18 F5 jr check_string_literal 533 D273 534 D273 ; ---------------------------------------------------------------- 535 D273 536 D273 check_array: 537 D273 ; HL must be pointing to '[' 538 D273 CD CA D1 call skip_whitespace_next 539 D276 FE 5D cp ']' 540 D278 CA 00 D2 jp z, check_success 541 D27B check_array_next: 542 D27B CD 06 D2 call check_anything 543 D27E D8 ret c 544 D27F CD BA D1 call skip_whitespace 545 D282 FE 5D cp ']' 546 D284 CA 00 D2 jp z, check_success 547 D287 FE 2C cp ',' 548 D289 C2 85 D1 jp nz, json_error 549 D28C CD CA D1 call skip_whitespace_next 550 D28F 18 EA jr check_array_next 551 D291 552 D291 ; ---------------------------------------------------------------- 553 D291 554 D291 check_string: 555 D291 FE 22 cp '"' 556 D293 C2 85 D1 jp nz, json_error 557 D296 ; Fall through to check_contents 558 D296 559 D296 ; ---------------------------------------------------------------- 560 D296 561 D296 check_contents: 562 D296 23 inc hl 563 D297 check_contents_no_inc: 564 D297 7E ld a, (hl) 565 D298 FE 22 cp '"' 566 D29A CA 00 D2 jp z, check_success 567 D29D FE 5C cp '\\' 568 D29F 28 02 jr z, check_escape 569 D2A1 18 F3 jr check_contents 570 D2A3 571 D2A3 ; ---------------------------------------------------------------- 572 D2A3 573 D2A3 check_escape: 574 D2A3 23 inc hl 575 D2A4 7E ld a, (hl) 576 D2A5 EB ex de, hl 577 D2A6 01 08 00 ld bc, 8 578 D2A9 21 DB D2 ld hl, string_escapes 579 D2AC ED B1 cpir 580 D2AE EB ex de, hl 581 D2AF 28 E5 jr z, check_contents 582 D2B1 FE 75 cp 'u' 583 D2B3 C2 85 D1 jp nz, json_error 584 D2B6 06 04 ld b, 4 585 D2B8 1: 586 D2B8 23 inc hl 587 D2B9 CD C3 D2 call check_hex_digit 588 D2BC D2 85 D1 jp nc, json_error 589 D2BF 10 F7 djnz 1b 590 D2C1 18 D3 jr check_contents 591 D2C3 592 D2C3 ; ---------------------------------------------------------------- 593 D2C3 594 D2C3 check_hex_digit: 595 D2C3 CD CF D2 call check_digit 596 D2C6 D8 ret c 597 D2C7 F6 20 or 32 598 D2C9 ; Fall through to check_hex_lower 599 D2C9 600 D2C9 check_hex_lower: 601 D2C9 ; Returns CF=digit, NC=non-digit 602 D2C9 FE 67 cp 'f' + 1 603 D2CB D0 ret nc 604 D2CC C6 9F add a, 256 - 'a' 605 D2CE C9 ret 606 D2CF 607 D2CF check_digit: 608 D2CF 7E ld a, (hl) 609 D2D0 ; Returns CF=digit, NC=non-digit 610 D2D0 FE 3A cp '9' + 1 611 D2D2 D0 ret nc 612 D2D3 FE 30 cp '0' 613 D2D5 3F ccf 614 D2D6 C9 ret 615 D2D7 616 D2D7 ; ---------------------------------------------------------------- 617 D2D7 ; Constants 618 D2D7 619 D2D7 identifiers: db '{["0tfn' 619 D2D7 7B5B223074666E 620 D2DE 225C2F6272 escapes_cont: db '"\/br' 621 D2E3 7472756500 token_true: db 'true', 0 622 D2E8 token_false: db 'false', 0 622 D2E8 66616C736500 623 D2EE 6E756C6C00 token_null: db 'null', 0 624 D2F3 string_escapes equ escapes_cont - 3 625 D2F3 626 D2F3 ; ---------------------------------------------------------------- 627 D2F3 ; Variables 628 D2F3 629 D2F3 00 00 json_start: dw 0 630 D2F5 00 sentinel: db 0 631 D2F6 00 00 sentinel_pos: dw 0 632 D2F8 00 get_action: db 0 633 D2F9 634 D2F9 ; ---------------------------------------------------------------- 635 D2F9 636 D2F9 end_bin: 637 D2F9 638 D2F9 end 639 D2F9 640 D2F9