diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2010-05-24 09:39:52 +0200 |
---|---|---|
committer | Luiz Capitulino <lcapitulino@redhat.com> | 2010-06-11 15:25:14 -0300 |
commit | f7c052747e4b139df16e1d5b7851f4729acc2bb7 (patch) | |
tree | cbdef39614a22f702ace4b66be1d38661af69400 /json-lexer.c | |
parent | 7f8fca7c8add770d6533c44d2d001c0442ed0371 (diff) |
implement optional lookahead in json lexer
Not requiring one extra character when lookahead is not necessary
ensures that clients behave properly even if they, for example,
send QMP requests without a trailing newline.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Diffstat (limited to 'json-lexer.c')
-rw-r--r-- | json-lexer.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/json-lexer.c b/json-lexer.c index 1d9b81fef4..5ea64a75a7 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -65,6 +65,12 @@ enum json_lexer_state { #define TERMINAL(state) [0 ... 0x7F] = (state) +/* 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] = { [IN_DONE_STRING] = { TERMINAL(JSON_STRING), @@ -284,35 +290,41 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func) static int json_lexer_feed_char(JSONLexer *lexer, char ch) { + int char_consumed, new_state; + lexer->x++; if (ch == '\n') { lexer->x = 0; 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; - } - - qstring_append_chr(lexer->token, ch); + 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; } @@ -334,7 +346,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) |