diff options
-rw-r--r-- | json-lexer.c | 116 | ||||
-rw-r--r-- | json-parser.c | 15 | ||||
-rw-r--r-- | json-streamer.c | 8 |
3 files changed, 71 insertions, 68 deletions
diff --git a/json-lexer.c b/json-lexer.c index e9a61db..c736f42 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -27,11 +27,8 @@ * */ -#undef ERROR - enum json_lexer_state { ERROR = 0, - IN_DONE_STRING, IN_DQ_UCODE3, IN_DQ_UCODE2, IN_DQ_UCODE1, @@ -59,19 +56,19 @@ enum json_lexer_state { IN_ESCAPE_I, IN_ESCAPE_I6, IN_ESCAPE_I64, - IN_ESCAPE_DONE, IN_WHITESPACE, - IN_OPERATOR_DONE, IN_START, }; #define TERMINAL(state) [0 ... 0x7F] = (state) -static const uint8_t json_lexer[][256] = { - [IN_DONE_STRING] = { - TERMINAL(JSON_STRING), - }, +/* Return whether TERMINAL is a terminal state and the transition to it + from OLD_STATE required lookahead. This happens whenever the table + below uses the TERMINAL macro. */ +#define TERMINAL_NEEDED_LOOKAHEAD(old_state, terminal) \ + (json_lexer[(old_state)][0] == (terminal)) +static const uint8_t json_lexer[][256] = { /* double quote string */ [IN_DQ_UCODE3] = { ['0' ... '9'] = IN_DQ_STRING, @@ -99,6 +96,8 @@ static const uint8_t json_lexer[][256] = { ['n'] = IN_DQ_STRING, ['r'] = IN_DQ_STRING, ['t'] = IN_DQ_STRING, + ['/'] = IN_DQ_STRING, + ['\\'] = IN_DQ_STRING, ['\''] = IN_DQ_STRING, ['\"'] = IN_DQ_STRING, ['u'] = IN_DQ_UCODE0, @@ -106,7 +105,7 @@ static const uint8_t json_lexer[][256] = { [IN_DQ_STRING] = { [1 ... 0xFF] = IN_DQ_STRING, ['\\'] = IN_DQ_STRING_ESCAPE, - ['"'] = IN_DONE_STRING, + ['"'] = JSON_STRING, }, /* single quote string */ @@ -136,6 +135,8 @@ static const uint8_t json_lexer[][256] = { ['n'] = IN_SQ_STRING, ['r'] = IN_SQ_STRING, ['t'] = IN_SQ_STRING, + ['/'] = IN_DQ_STRING, + ['\\'] = IN_DQ_STRING, ['\''] = IN_SQ_STRING, ['\"'] = IN_SQ_STRING, ['u'] = IN_SQ_UCODE0, @@ -143,7 +144,7 @@ static const uint8_t json_lexer[][256] = { [IN_SQ_STRING] = { [1 ... 0xFF] = IN_SQ_STRING, ['\\'] = IN_SQ_STRING_ESCAPE, - ['\''] = IN_DONE_STRING, + ['\''] = JSON_STRING, }, /* Zero */ @@ -209,27 +210,18 @@ static const uint8_t json_lexer[][256] = { ['\n'] = IN_WHITESPACE, }, - /* operator */ - [IN_OPERATOR_DONE] = { - TERMINAL(JSON_OPERATOR), - }, - /* escape */ - [IN_ESCAPE_DONE] = { - TERMINAL(JSON_ESCAPE), - }, - [IN_ESCAPE_LL] = { - ['d'] = IN_ESCAPE_DONE, + ['d'] = JSON_ESCAPE, }, [IN_ESCAPE_L] = { - ['d'] = IN_ESCAPE_DONE, + ['d'] = JSON_ESCAPE, ['l'] = IN_ESCAPE_LL, }, [IN_ESCAPE_I64] = { - ['d'] = IN_ESCAPE_DONE, + ['d'] = JSON_ESCAPE, }, [IN_ESCAPE_I6] = { @@ -241,11 +233,11 @@ static const uint8_t json_lexer[][256] = { }, [IN_ESCAPE] = { - ['d'] = IN_ESCAPE_DONE, - ['i'] = IN_ESCAPE_DONE, - ['p'] = IN_ESCAPE_DONE, - ['s'] = IN_ESCAPE_DONE, - ['f'] = IN_ESCAPE_DONE, + ['d'] = JSON_ESCAPE, + ['i'] = JSON_ESCAPE, + ['p'] = JSON_ESCAPE, + ['s'] = JSON_ESCAPE, + ['f'] = JSON_ESCAPE, ['l'] = IN_ESCAPE_L, ['I'] = IN_ESCAPE_I, }, @@ -257,12 +249,12 @@ static const uint8_t json_lexer[][256] = { ['0'] = IN_ZERO, ['1' ... '9'] = IN_NONZERO_NUMBER, ['-'] = IN_NEG_NONZERO_NUMBER, - ['{'] = IN_OPERATOR_DONE, - ['}'] = IN_OPERATOR_DONE, - ['['] = IN_OPERATOR_DONE, - [']'] = IN_OPERATOR_DONE, - [','] = IN_OPERATOR_DONE, - [':'] = IN_OPERATOR_DONE, + ['{'] = JSON_OPERATOR, + ['}'] = JSON_OPERATOR, + ['['] = JSON_OPERATOR, + [']'] = JSON_OPERATOR, + [','] = JSON_OPERATOR, + [':'] = JSON_OPERATOR, ['a' ... 'z'] = IN_KEYWORD, ['%'] = IN_ESCAPE, [' '] = IN_WHITESPACE, @@ -277,11 +269,12 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func) lexer->emit = func; lexer->state = IN_START; lexer->token = qstring_new(); + lexer->x = lexer->y = 0; } static int json_lexer_feed_char(JSONLexer *lexer, char ch) { - char buf[2]; + int char_consumed, new_state; lexer->x++; if (ch == '\n') { @@ -289,32 +282,33 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch) lexer->y++; } - lexer->state = json_lexer[lexer->state][(uint8_t)ch]; - - switch (lexer->state) { - case JSON_OPERATOR: - case JSON_ESCAPE: - case JSON_INTEGER: - case JSON_FLOAT: - case JSON_KEYWORD: - case JSON_STRING: - lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y); - case JSON_SKIP: - lexer->state = json_lexer[IN_START][(uint8_t)ch]; - QDECREF(lexer->token); - lexer->token = qstring_new(); - break; - case ERROR: - return -EINVAL; - default: - break; - } - - buf[0] = ch; - buf[1] = 0; - - qstring_append(lexer->token, buf); + do { + new_state = json_lexer[lexer->state][(uint8_t)ch]; + char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state); + if (char_consumed) { + qstring_append_chr(lexer->token, ch); + } + switch (new_state) { + case JSON_OPERATOR: + case JSON_ESCAPE: + case JSON_INTEGER: + case JSON_FLOAT: + case JSON_KEYWORD: + case JSON_STRING: + lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y); + case JSON_SKIP: + QDECREF(lexer->token); + lexer->token = qstring_new(); + new_state = IN_START; + break; + case ERROR: + return -EINVAL; + default: + break; + } + lexer->state = new_state; + } while (!char_consumed); return 0; } @@ -336,7 +330,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size) int json_lexer_flush(JSONLexer *lexer) { - return json_lexer_feed_char(lexer, 0); + return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0); } void json_lexer_destroy(JSONLexer *lexer) diff --git a/json-parser.c b/json-parser.c index f3debcb..70b9b6f 100644 --- a/json-parser.c +++ b/json-parser.c @@ -11,7 +11,7 @@ * */ -#include <stdbool.h> +#include <stdarg.h> #include "qemu-common.h" #include "qstring.h" @@ -93,7 +93,12 @@ static int token_is_escape(QObject *obj, const char *value) */ static void parse_error(JSONParserContext *ctxt, QObject *token, const char *msg, ...) { - fprintf(stderr, "parse error: %s\n", msg); + va_list ap; + va_start(ap, msg); + fprintf(stderr, "parse error: "); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + va_end(ap); } /** @@ -200,6 +205,10 @@ static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token qstring_append(str, "\b"); ptr++; break; + case 'f': + qstring_append(str, "\f"); + ptr++; + break; case 'n': qstring_append(str, "\n"); ptr++; @@ -264,7 +273,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l peek = qlist_peek(working); key = parse_value(ctxt, &working, ap); - if (qobject_type(key) != QTYPE_QSTRING) { + if (!key || qobject_type(key) != QTYPE_QSTRING) { parse_error(ctxt, peek, "key is not a string in object"); goto out; } diff --git a/json-streamer.c b/json-streamer.c index 610ffea..f7e7a68 100644 --- a/json-streamer.c +++ b/json-streamer.c @@ -43,11 +43,11 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok } dict = qdict_new(); - qdict_put_obj(dict, "type", QOBJECT(qint_from_int(type))); + qdict_put(dict, "type", qint_from_int(type)); QINCREF(token); - qdict_put_obj(dict, "token", QOBJECT(token)); - qdict_put_obj(dict, "x", QOBJECT(qint_from_int(x))); - qdict_put_obj(dict, "y", QOBJECT(qint_from_int(y))); + qdict_put(dict, "token", token); + qdict_put(dict, "x", qint_from_int(x)); + qdict_put(dict, "y", qint_from_int(y)); qlist_append(parser->tokens, dict); |