Design: rewritten using parser structure

master
Serge A. Zaitsev 14 years ago
parent a2755a7595
commit 60509e2850

@ -1,4 +1,4 @@
CFLAGS=-Wall -std=c89
CFLAGS=-Wall -std=c89 -g
OBJS=jsmn.o demo.o

@ -50,7 +50,6 @@ static void jsmn_dump_obj(jsontok_t *obj, const char *js) {
int main(int argc, char *argv[]) {
int i;
int r;
int errpos;
jsontok_t tokens[NUM_TOKENS];
FILE *f;
int filesize = 0;
@ -85,14 +84,18 @@ int main(int argc, char *argv[]) {
fclose(f);
r = jsmn_parse((unsigned char *) js, tokens, NUM_TOKENS, &errpos);
jsmn_parser parser;
jsmn_init_parser(&parser, js, tokens, NUM_TOKENS);
r = jsmn_parse(&parser);
if (r < 0) {
printf("error %d at pos %d: %s\n", r, errpos, &js[errpos]);
printf("error %d at pos %d: %s\n", r, parser.pos, &js[parser.pos]);
exit(EXIT_FAILURE);
}
for (i = 0; i<NUM_TOKENS; i++) {
jsmn_dump_obj(&tokens[i], js);
jsmn_dump_obj(&parser.tokens[i], js);
}
free(js);

224
jsmn.c

@ -2,77 +2,28 @@
#include "jsmn.h"
struct jsmn_params {
jsontok_t *tokens;
size_t num_tokens;
int *errpos;
};
/**
* Read the string from JSON data. Store string
*/
static int jsmn_parse_string(const unsigned char *js, jsontok_t *token) {
const unsigned char *p;
/* Check if string begins from a quote */
if (js[token->start] != '\"') {
return -1;
}
/* Skip starting quote */
token->start++;
for (p = &js[token->start]; *p != '\0'; p++) {
/* Quote: end of string */
if (*p == '\"') {
token->end = p - js;
return 0;
}
/* Backslash: Quoted symbol expected */
if (*p == '\\') {
p++;
switch (*p) {
/* Allowed escaped symbols */
case '\"': case '/' : case '\\' : case 'b' :
case 'f' : case 'r' : case 'n' : case 't' :
break;
/* Allows escaped symbol \uXXXX */
case 'u':
/* TODO */
break;
/* Unexpected symbol */
default:
return -1;
}
}
}
return -1;
}
void jsmn_init_parser(jsmn_parser *parser, const char *js,
jsontok_t *tokens, size_t num_tokens) {
unsigned int i;
static int jsmn_parse_primitive(const unsigned char *js, jsontok_t *token) {
const unsigned char *p;
parser->js = js;
parser->pos = 0;
parser->tokens = tokens;
parser->num_tokens = num_tokens;
for (p = &js[token->start]; *p != '\0'; p++) {
switch (*p) {
case '\t' : case '\r' : case '\n' : case ' ' :
case ',' : case ']' : case '}' :
token->end = p - js;
return 0;
for (i = 0; i < parser->num_tokens; i++) {
parser->tokens[i].start = -1;
parser->tokens[i].end = -1;
parser->tokens[i].type = JSON_OTHER;
}
if (*p < 32 || *p >= 127) {
return -1;
}
}
return -1;
}
static jsontok_t *jsmn_token_start(struct jsmn_params *params, jsontype_t type, int pos) {
jsontok_t *jsmn_start_token(jsmn_parser *parser, jsontype_t type) {
unsigned int i;
jsontok_t *tokens = params->tokens;
for (i = 0; i<params->num_tokens; i++) {
jsontok_t *tokens = parser->tokens;
for (i = 0; i<parser->num_tokens; i++) {
if (tokens[i].start == -1 && tokens[i].end == -1) {
tokens[i].start = pos;
tokens[i].start = parser->pos;
tokens[i].type = type;
return &tokens[i];
}
@ -80,98 +31,121 @@ static jsontok_t *jsmn_token_start(struct jsmn_params *params, jsontype_t type,
return NULL;
}
static jsontok_t *jsmn_token_end(struct jsmn_params *params, jsontype_t type, int pos) {
jsontok_t *jsmn_end_token(jsmn_parser *parser, jsontype_t type) {
int i;
jsontok_t *tokens = params->tokens;
for (i = params->num_tokens - 1; i>= 0; i--) {
jsontok_t *tokens = parser->tokens;
for (i = parser->num_tokens - 1; i>= 0; i--) {
if (tokens[i].type == type && tokens[i].start != -1 && tokens[i].end == -1) {
tokens[i].end = pos;
tokens[i].end = parser->pos;
return &tokens[i];
}
}
return NULL;
}
int jsmn_parse(const unsigned char *js, jsontok_t *tokens, size_t num_tokens, int *errpos) {
static int jsmn_parse_primitive(jsmn_parser *parser) {
const char *js;
jsontok_t *token;
#define jsmn_return(error) \
do { \
if ((errpos) != NULL) { \
*(errpos) = (p - js); \
} \
return (error); \
} while (0)
js = parser->js;
#define jsmn_assert(cond, error) \
if (!(cond)) { \
jsmn_return(error); \
token = jsmn_start_token(parser, JSON_NUMBER);
for (; js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
case '\t' : case '\r' : case '\n' : case ' ' :
case ',' : case ']' : case '}' :
token->end = parser->pos;
parser->pos--;
return JSMN_SUCCESS;
}
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
return JSMN_ERROR_INVAL;
}
}
return JSMN_ERROR_PART;
}
struct jsmn_params params;
int r;
unsigned int i;
const unsigned char *p;
jsontype_t type;
jsontok_t *cur_token;
static int jsmn_parse_string(jsmn_parser *parser) {
const char *js;
jsontok_t *token;
js = parser->js;
params.num_tokens = num_tokens;
params.tokens = tokens;
params.errpos = errpos;
/* Check if string begins from a quote */
if (js[parser->pos] != '\"') {
return JSMN_ERROR_INVAL;
}
for (i = 0; i<num_tokens; i++) {
tokens[i].start = tokens[i].end = -1;
tokens[i].type = JSON_OTHER;
parser->pos++;
token = jsmn_start_token(parser, JSON_STRING);
/* Skip starting quote */
for (; js[parser->pos] != '\0'; parser->pos++) {
char c = js[parser->pos];
/* Quote: end of string */
if (c == '\"') {
token->end = parser->pos;
return JSMN_SUCCESS;
}
/* Backslash: Quoted symbol expected */
if (c == '\\') {
parser->pos++;
switch (js[parser->pos]) {
/* Allowed escaped symbols */
case '\"': case '/' : case '\\' : case 'b' :
case 'f' : case 'r' : case 'n' : case 't' :
break;
/* Allows escaped symbol \uXXXX */
case 'u':
/* TODO */
break;
/* Unexpected symbol */
default:
return JSMN_ERROR_INVAL;
}
}
}
return JSMN_ERROR_PART;
}
for (p = js; *p != '\0'; ) {
switch (*p) {
jsmnerr_t jsmn_parse(jsmn_parser *parser) {
const char *js;
jsontype_t type;
jsontok_t *token;
js = parser->js;
for (; js[parser->pos] != '\0'; parser->pos++) {
char c;
c = js[parser->pos];
switch (c) {
case '{': case '[':
type = (*p == '{' ? JSON_OBJECT : JSON_ARRAY);
cur_token = jsmn_token_start(&params, type, p - js);
jsmn_assert(cur_token != NULL, JSMN_ERROR_NOMEM);
type = (c == '{' ? JSON_OBJECT : JSON_ARRAY);
token = jsmn_start_token(parser, type);
break;
case '}': case ']':
type = (*p == '}' ? JSON_OBJECT : JSON_ARRAY);
cur_token = jsmn_token_end(&params, type, p - js + 1);
jsmn_assert(cur_token != NULL, JSMN_ERROR_PART);
type = (c == '}' ? JSON_OBJECT : JSON_ARRAY);
token = jsmn_end_token(parser, type);
break;
case '-': case '0': case '1' : case '2': case '3' : case '4':
case '5': case '6': case '7' : case '8': case '9':
cur_token = jsmn_token_start(&params, JSON_NUMBER, p - js);
jsmn_assert(cur_token != NULL, JSMN_ERROR_NOMEM);
r = jsmn_parse_primitive(js, cur_token);
jsmn_assert(r == 0, JSMN_ERROR_INVAL);
p = &js[cur_token->end] - 1;
break;
case 't': case 'f': case 'n' :
cur_token = jsmn_token_start(&params, JSON_OTHER, p - js);
jsmn_assert(cur_token != NULL, JSMN_ERROR_NOMEM);
r = jsmn_parse_primitive(js, cur_token);
jsmn_assert(r == 0, JSMN_ERROR_INVAL);
p = &js[cur_token->end] - 1;
jsmn_parse_primitive(parser);
break;
case '\"':
cur_token = jsmn_token_start(&params, JSON_STRING, p - js);
jsmn_assert(cur_token != NULL, JSMN_ERROR_NOMEM);
r = jsmn_parse_string(js, cur_token);
jsmn_assert(r == 0, JSMN_ERROR_INVAL);
p = &js[cur_token->end];
jsmn_parse_string(parser);
break;
case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
break;
default:
jsmn_return(JSMN_ERROR_INVAL);
return JSMN_ERROR_INVAL;
}
p++;
}
if (errpos != NULL) *errpos = 0;
return 0;
#undef jsmn_return
#undef jsmn_assert
return JSMN_SUCCESS;
}

@ -11,10 +11,10 @@
*/
typedef enum {
JSON_OTHER = 0,
JSON_OBJECT,
JSON_ARRAY,
JSON_STRING,
JSON_NUMBER
JSON_OBJECT = 1,
JSON_ARRAY = 2,
JSON_STRING = 3,
JSON_NUMBER = 4
} jsontype_t;
typedef enum {
@ -36,10 +36,27 @@ typedef struct {
int end;
} jsontok_t;
/**
* JSON parser. Contains an array of token blocks available. Also stores
* the string being parsed now and current position in that string
*/
typedef struct {
const char *js;
unsigned int pos;
size_t num_tokens;
jsontok_t *tokens;
} jsmn_parser;
/**
* Create JSON parser over an array of tokens
*/
void jsmn_init_parser(jsmn_parser *parser, const char *js,
jsontok_t *tokens, size_t num_tokens);
/**
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
* a single JSON object.
*/
int jsmn_parse(const unsigned char *js, jsontok_t *tokens, size_t num_tokens, int *errpos);
jsmnerr_t jsmn_parse(jsmn_parser *parser);
#endif /* __JSMN_H_ */

Loading…
Cancel
Save