From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=59042 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGTbU-0005mV-3D for qemu-devel@nongnu.org; Mon, 24 May 2010 05:05:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OGSGl-0005rF-9U for qemu-devel@nongnu.org; Mon, 24 May 2010 03:40:25 -0400 Received: from mail-ww0-f45.google.com ([74.125.82.45]:42742) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OGSGc-0005nN-ND for qemu-devel@nongnu.org; Mon, 24 May 2010 03:40:11 -0400 Received: by wwg30 with SMTP id 30so326497wwg.4 for ; Mon, 24 May 2010 00:40:04 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Mon, 24 May 2010 09:39:52 +0200 Message-Id: <1274686793-1566-3-git-send-email-pbonzini@redhat.com> In-Reply-To: <1274686793-1566-1-git-send-email-pbonzini@redhat.com> References: <1274686793-1566-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PATCH v2 2/3] implement optional lookahead in json lexer List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: lcapitulino@redhat.com 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 --- json-lexer.c | 58 +++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 35 insertions(+), 23 deletions(-) diff --git a/json-lexer.c b/json-lexer.c index d1d8033..41b37f4 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), @@ -279,35 +285,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; } @@ -329,7 +341,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.6.6.1