static struct jx_item * jx_parse_item_list( struct jx_parser *s ) { jx_token_t t = jx_scan(s); if(t==JX_TOKEN_RBRACKET) { // empty list return 0; } jx_unscan(s,t); struct jx_item *i = jx_item(0,0); i->value = jx_parse(s); if(!i->value) { // error set by deeper layer jx_item_delete(i); return 0; } t = jx_scan(s); if(t==JX_TOKEN_COMMA) { i->next = jx_parse_item_list(s); } else if(t==JX_TOKEN_RBRACKET) { i->next = 0; } else { jx_parse_error(s,"array items missing a comma or closing brace"); jx_item_delete(i); return 0; } return i; }
static struct jx_pair * jx_parse_pair_list( struct jx_parser *s ) { jx_token_t t = jx_scan(s); if(t==JX_TOKEN_RBRACE) { // empty list return 0; } jx_unscan(s,t); struct jx_pair *p = jx_pair(0,0,0); p->key = jx_parse(s); if(!p->key) { // error set by deeper layer jx_pair_delete(p); return 0; } if(s->strict_mode) { if(p->key->type!=JX_STRING) { jx_parse_error(s,"key-value pair must have a string as the key"); jx_pair_delete(p); return 0; } } t = jx_scan(s); if(t!=JX_TOKEN_COLON) { jx_parse_error(s,"key-value pair must be separated by a colon"); jx_pair_delete(p); return 0; } p->value = jx_parse(s); if(!p->value) { // error set by deeper layer jx_pair_delete(p); return 0; } t = jx_scan(s); if(t==JX_TOKEN_COMMA) { p->next = jx_parse_pair_list(s); } else if(t==JX_TOKEN_RBRACE) { p->next = 0; } else { jx_parse_error(s,"key-value pairs missing a comma or closing brace"); jx_pair_delete(p); return 0; } return p; }
struct jx * jx_parse( struct jx_parser *s ) { jx_token_t t = jx_scan(s); switch(t) { case JX_TOKEN_EOF: return 0; case JX_TOKEN_LBRACE: return jx_object(jx_parse_pair_list(s)); case JX_TOKEN_LBRACKET: return jx_array(jx_parse_item_list(s)); case JX_TOKEN_STRING: return jx_string(s->token); case JX_TOKEN_INTEGER: return jx_integer(s->integer_value); case JX_TOKEN_DOUBLE: return jx_double(s->double_value); case JX_TOKEN_TRUE: return jx_boolean(1); case JX_TOKEN_FALSE: return jx_boolean(0); case JX_TOKEN_NULL: return jx_null(); case JX_TOKEN_SYMBOL: if(s->strict_mode) { jx_parse_error(s,"symbols are not allowed in strict parsing mode"); return 0; } else { return jx_symbol(s->token); } case JX_TOKEN_RBRACE: case JX_TOKEN_RBRACKET: case JX_TOKEN_COMMA: case JX_TOKEN_COLON: case JX_TOKEN_ERROR: jx_parse_error(s,"unexpected token"); return 0; } /* We shouldn't get here, since all the token types should be handled above. But just in case... */ jx_parse_error(s,"parse error"); return 0; }
static void jx_shell_scan_input(jx_shell_scanner_state * state) { /* allocate parser */ void *jx_Parser = jx_shell_Alloc((void *(*)(size_t)) jx__shell_alloc); jx_int tok_type = 0; jx_char stack_buffer[SSCANF_BUFSIZE]; state->context.status = 0; state->n_tok_parsed = 0; while(!state->context.exhausted) { tok_type = jx_scan(state); { jx_ob token = JX_OB_NULL; jx_size st_len = state->cur - state->tok; jx_bool skip = JX_FALSE; #ifdef JX_SHELL_PARSER_DEBUG if(1) { jx_size i; jx_char *c = state->tok; if(st_len) { printf(" "); for(i = 0; i < st_len; i++) { printf("%c", *(c++)); } printf("\n"); } } #endif switch (tok_type) { case JX_SHELL_ICON: case JX_SHELL_FCON: case JX_SHELL_SCON: case JX_SHELL_IDENT: { char *buffer = stack_buffer; if(st_len >= SSCANF_BUFSIZE) { buffer = jx_malloc(st_len + 1); } if(buffer) { jx_os_strncpy(buffer, state->tok, st_len); buffer[st_len] = 0; switch (tok_type) { case JX_SHELL_ICON: { #ifdef JX_64_BIT jx_int icon; if(jx_os_sscanf(buffer, "%lli", &icon) != 1) { /* use strtol instead? */ icon = 0; } token = jx_ob_from_int(icon); #else int icon; if(jx_os_sscanf(buffer, "%i", &icon) != 1) { /* use strtol instead? */ icon = 0; } #endif token = jx_ob_from_int(icon); } break; case JX_SHELL_FCON: { #ifdef JX_64_BIT double fcon; if(jx_os_sscanf(buffer, "%lf", &fcon) != 1) { /* use strtof instead? */ fcon = 0.0; } #else float fcon; if(jx_os_sscanf(buffer, "%f", &fcon) != 1) { /* use strtof instead? */ fcon = 0.0F; } #endif token = jx_ob_from_float(fcon); } break; case JX_SHELL_SCON: buffer[st_len - 1] = 0; token = jx_ob_from_str(buffer + 1); break; case JX_SHELL_IDENT: token = jx_ob_from_ident(buffer); break; } if(buffer != stack_buffer) jx_free(buffer); } break; case JX_SHELL_TRUE: token = jx_ob_from_bool(true); break; case JX_SHELL_FALSE: token = jx_ob_from_bool(false); break; case JX_SHELL_NULL: token = jx_ob_from_null(); break; case JX_SHELL_BUILTIN: token = jx_builtin_new_from_selector(0); break; case JX_SHELL_EOL: { jx_ob ob = JX_OB_NULL; jx_shell_(jx_Parser, JX_SHELL_EOI, ob, &state->context); state->n_tok_parsed++; } break; case JX_SHELL_OPEN_RECT_BRACE: case JX_SHELL_CLOSE_RECT_BRACE: case JX_SHELL_OPEN_CURLY_BRACE: case JX_SHELL_CLOSE_CURLY_BRACE: /* do nothing */ break; case JX_SHELL_EOI: break; case JX_SHELL_ERROR: state->context.status = JX_STATUS_SYNTAX_ERROR; break; case JX_SHELL_COMMA: break; case JX_SHELL_SEMICOLON: break; } } if(!skip) { jx_shell_(jx_Parser, (int) tok_type, token, &state->context); if(!jx_ok(state->context.status)) /* something bad happened */ break; switch (tok_type) { case JX_SHELL_EOI: { /* parse a null token to enable acceptance */ jx_ob ob = JX_OB_NULL; jx_shell_(jx_Parser, 0, ob, &state->context); } break; } } if(state->context.status) /* accepted or complete */ break; else state->n_tok_parsed++; } } if(tok_type == JX_SHELL_EOI) { state->context.exhausted = JX_TRUE; } /* free the parser instance */ jx_shell_Free(jx_Parser, jx__shell_free); }