From f1cd7de018b623d19a8f42ac47f0271a28eedcce Mon Sep 17 00:00:00 2001 From: Jan Breuer <jan.breuer@jaybee.cz> Date: 周日, 19 4月 2015 06:43:16 +0800 Subject: [PATCH] Implement Traversal of the Header Tree. Solve #22 --- libscpi/src/lexer.c | 2 libscpi/inc/scpi/types.h | 6 +- libscpi/src/parser_private.h | 2 libscpi/src/parser.c | 11 ++++- libscpi/test/test_lexer_parser.c | 8 ++-- libscpi/src/utils_private.h | 1 libscpi/inc/scpi/parser.h | 2 libscpi/test/test_parser.c | 30 +++++++++++++-- libscpi/src/utils.c | 45 ++++++++++++++++++++++ 9 files changed, 90 insertions(+), 17 deletions(-) diff --git a/libscpi/inc/scpi/parser.h b/libscpi/inc/scpi/parser.h index 7940ea6..2cb4f73 100644 --- a/libscpi/inc/scpi/parser.h +++ b/libscpi/inc/scpi/parser.h @@ -47,7 +47,7 @@ void SCPI_Init(scpi_t * context); int SCPI_Input(scpi_t * context, const char * data, int len); - int SCPI_Parse(scpi_t * context, const char * data, int len); + int SCPI_Parse(scpi_t * context, char * data, int len); size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len); diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h index 4851d9e..8f829b3 100644 --- a/libscpi/inc/scpi/types.h +++ b/libscpi/inc/scpi/types.h @@ -161,14 +161,14 @@ struct _scpi_token_t { scpi_token_type_t type; - const char * ptr; + char * ptr; int len; }; typedef struct _scpi_token_t scpi_token_t; struct _lex_state_t { - const char * buffer; - const char * pos; + char * buffer; + char * pos; int len; }; typedef struct _lex_state_t lex_state_t; diff --git a/libscpi/src/lexer.c b/libscpi/src/lexer.c index e7dc48d..c0505cc 100644 --- a/libscpi/src/lexer.c +++ b/libscpi/src/lexer.c @@ -506,7 +506,7 @@ * @return */ int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) { - const char * rollback; + char * rollback; token->ptr = state->pos; if (skipMantisa(state)) { diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c index 80a4a00..9017bca 100644 --- a/libscpi/src/parser.c +++ b/libscpi/src/parser.c @@ -152,10 +152,11 @@ * @param len - command line length * @return 1 if the last evaluated command was found */ -int SCPI_Parse(scpi_t * context, const char * data, int len) { +int SCPI_Parse(scpi_t * context, char * data, int len) { int result = 0; scpi_parser_state_t * state; int r; + scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0}; if (context == NULL) { return -1; @@ -171,6 +172,9 @@ if (state->programHeader.type == SCPI_TOKEN_INVALID) { SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER); } else if (state->programHeader.len > 0) { + + composeCompoundCommand(&cmd_prev, &state->programHeader); + if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) { context->param_list.lex_state.buffer = state->programData.ptr; @@ -183,6 +187,7 @@ processCommand(context); result = 1; + cmd_prev = state->programHeader; } else { SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER); } @@ -414,7 +419,7 @@ * @param token * @param ptr */ -static void invalidateToken(scpi_token_t * token, const char * ptr) { +static void invalidateToken(scpi_token_t * token, char * ptr) { token->len = 0; token->ptr = ptr; token->type = SCPI_TOKEN_UNKNOWN; @@ -934,7 +939,7 @@ * @param len * @return */ -int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) { +int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) { lex_state_t lex_state; scpi_token_t tmp; int result = 0; diff --git a/libscpi/src/parser_private.h b/libscpi/src/parser_private.h index b34c15d..de95865 100644 --- a/libscpi/src/parser_private.h +++ b/libscpi/src/parser_private.h @@ -45,7 +45,7 @@ int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) LOCAL; - int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) LOCAL; + int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) LOCAL; #ifdef __cplusplus } diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c index c40ddb6..710d8e0 100644 --- a/libscpi/src/utils.c +++ b/libscpi/src/utils.c @@ -441,6 +441,51 @@ return result; } +/** + * Compose command from previsou command anc current command + * + * @param prev pointer to previous command + * @param current pointer of current command + * + * prev and current should be in the same memory buffer + */ +scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { + size_t i; + + /* Invalid input */ + if (current == NULL || current->ptr == NULL || current->len == 0) + return FALSE; + + /* no previous command - nothing to do*/ + if (prev->ptr == NULL || prev->len == 0) + return TRUE; + + /* Common command or command root - nothing to do */ + if (current->ptr[0] == '*' || current->ptr[0] == ':') + return TRUE; + + /* Previsou command was common command - nothing to do */ + if (prev->ptr[0] == '*') + return TRUE; + + /* Find last occurence of ':' */ + for (i = prev->len; i > 0; i--) { + if (prev->ptr[i - 1] == ':') { + break; + } + } + + /* Previous command was simple command - nothing to do*/ + if (i == 0) + return TRUE; + + current->ptr -= i; + current->len += i; + memmove(current->ptr, prev->ptr, i); + return TRUE; +} + + #if !HAVE_STRNLEN /* use FreeBSD strnlen */ diff --git a/libscpi/src/utils_private.h b/libscpi/src/utils_private.h index ed624f3..255136b 100644 --- a/libscpi/src/utils_private.h +++ b/libscpi/src/utils_private.h @@ -63,6 +63,7 @@ size_t skipWhitespace(const char * cmd, size_t len) LOCAL; scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) LOCAL; scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) LOCAL; + scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current); #if !HAVE_STRNLEN size_t BSD_strnlen(const char *s, size_t maxlen); diff --git a/libscpi/test/test_lexer_parser.c b/libscpi/test/test_lexer_parser.c index d11496c..9ea883f 100644 --- a/libscpi/test/test_lexer_parser.c +++ b/libscpi/test/test_lexer_parser.c @@ -82,7 +82,7 @@ #endif #define TEST_TOKEN(s, f, o, l, t) do { \ - const char * str = s; \ + char * str = s; \ lexfn_t fn = f; \ int offset = o; \ int len = l; \ @@ -211,7 +211,7 @@ #define TEST_ALL_TOKEN(s, f, o, l, t, c) do { \ - const char * str = s; \ + char * str = s; \ lexfn2_t fn = f; \ int offset = o; \ int len = l; \ @@ -244,10 +244,10 @@ #define TEST_DETECT(s, h, hl, ht, d, dc, t) do { \ - const char * str = s; \ + char * str = s; \ scpi_parser_state_t state; \ int result; \ - result = scpiParser_detectProgramMessageUnit(&state, str, strlen(str)); \ + result = scpiParser_detectProgramMessageUnit(&state, str, strlen(str)); \ CU_ASSERT_EQUAL(state.programHeader.ptr, str + h); \ CU_ASSERT_EQUAL(state.programHeader.len, hl); \ CU_ASSERT_EQUAL(state.programHeader.type, ht); \ diff --git a/libscpi/test/test_parser.c b/libscpi/test/test_parser.c index f747271..cee918f 100644 --- a/libscpi/test/test_parser.c +++ b/libscpi/test/test_parser.c @@ -30,6 +30,20 @@ return SCPI_RES_OK; } +scpi_result_t test_treeA(scpi_t* context) { + + SCPI_ResultInt(context, 10); + + return SCPI_RES_OK; +} + +scpi_result_t test_treeB(scpi_t* context) { + + SCPI_ResultInt(context, 20); + + return SCPI_RES_OK; +} + static const scpi_command_t scpi_commands[] = { /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ { .pattern = "*CLS", .callback = SCPI_CoreCls,}, @@ -57,7 +71,10 @@ { .pattern = "STATus:PRESet", .callback = SCPI_StatusPreset,}, - { .pattern = "TEXTfunction", .callback = text_function,}, + { .pattern = "TEXTfunction?", .callback = text_function,}, + + { .pattern = "TEST:TREEA?", .callback = test_treeA,}, + { .pattern = "TEST:TREEB?", .callback = test_treeB,}, SCPI_CMD_LIST_END }; @@ -193,10 +210,15 @@ TEST_INPUT("", "MA,IN,0,VER\r\n"); output_buffer_clear(); + /* Test ctree traversal */ + TEST_INPUT("TEST:TREEA?;TREEB?\r\n", "10\r\n20\r\n"); + output_buffer_clear(); + + TEST_INPUT("TEST:TREEA?;:TEXT? \"PARAM1\", \"PARAM2\"\r\n", "10\r\n\"PARAM2\"\r\n"); + output_buffer_clear(); + CU_ASSERT_EQUAL(err_buffer_pos, 0); error_buffer_clear(); - - // TODO: Compound commands A:B;C -> A:B; A:C } void testErrorHandling(void) { @@ -215,7 +237,7 @@ TEST_ERROR("IDN?\r\n", "", SCPI_ERROR_UNDEFINED_HEADER); TEST_ERROR("*ESE\r\n", "", SCPI_ERROR_MISSING_PARAMETER); TEST_ERROR("*IDN? 12\r\n", "MA,IN,0,VER\r\n", SCPI_ERROR_PARAMETER_NOT_ALLOWED); - TEST_ERROR("TEXT \"PARAM1\", \"PARAM2\"\r\n", "\"PARAM2\"\r\n", 0); + TEST_ERROR("TEXT? \"PARAM1\", \"PARAM2\"\r\n", "\"PARAM2\"\r\n", 0); // TODO: SCPI_ERROR_INVALID_SEPARATOR // TODO: SCPI_ERROR_INVALID_SUFFIX -- Gitblit v1.9.1