From f56ff4879d27c3dbc085c9c72d2eb8eef4e503ac Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 18 Jun 2010 15:36:36 -0300 Subject: [PATCH 2/7] implement optional lookahead in json lexer RH-Author: Luiz Capitulino Message-id: <1276875397-26225-3-git-send-email-lcapitulino@redhat.com> Patchwork-id: 9994 O-Subject: [PATCH 2/3] implement optional lookahead in json lexer Bugzilla: 585009 RH-Acked-by: Kevin Wolf RH-Acked-by: Markus Armbruster RH-Acked-by: Paolo Bonzini From: Paolo Bonzini 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 Signed-off-by: Luiz Capitulino (cherry picked from commit f7c052747e4b139df16e1d5b7851f4729acc2bb7) --- json-lexer.c | 58 +++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 35 insertions(+), 23 deletions(-) Signed-off-by: Eduardo Habkost --- json-lexer.c | 58 +++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 35 insertions(+), 23 deletions(-) diff --git a/json-lexer.c b/json-lexer.c index 1d9b81f..5ea64a7 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) -- 1.7.0.3