From 1ea396b98ee06b0ec56403b70d553ccc5b379b9a Mon Sep 17 00:00:00 2001 From: Jan Breuer <jan.breuer@jaybee.cz> Date: 周三, 19 6月 2013 18:19:44 +0800 Subject: [PATCH] Parse program data --- libscpi/src/lexer.c | 15 /dev/null | 194 ------------- libscpi/Makefile | 2 libscpi/inc/scpi/types.h | 108 +++++- libscpi/src/parser.c | 115 ++++++- libscpi/test/test_lexer_parser.c | 302 +++++++++++++++++++++ libscpi/inc/scpi/lexer.h | 65 --- libscpi/inc/scpi/parser.h | 8 8 files changed, 504 insertions(+), 305 deletions(-) diff --git a/libscpi/Makefile b/libscpi/Makefile index e58cd39..75caea6 100644 --- a/libscpi/Makefile +++ b/libscpi/Makefile @@ -36,7 +36,7 @@ TESTS = $(addprefix test/, \ - test_fifo.c test_scpi_utils.c test_lexer.c \ + test_fifo.c test_scpi_utils.c test_lexer_parser.c\ ) TESTS_OBJS = $(TESTS:.c=.o) diff --git a/libscpi/inc/scpi/lexer.h b/libscpi/inc/scpi/lexer.h index 6aaeca6..c5d5a32 100644 --- a/libscpi/inc/scpi/lexer.h +++ b/libscpi/inc/scpi/lexer.h @@ -43,58 +43,19 @@ extern "C" { #endif -enum _token_type_t { - TokComma, - TokSemicolon, - TokQuiestion, - TokNewLine, - TokHexnum, - TokOctnum, - TokBinnum, - TokProgramMnemonic, - TokDecimalNumericProgramData, - TokSuffixProgramData, - TokArbitraryBlockProgramData, - TokSingleQuoteProgramData, - TokDoubleQuoteProgramData, - TokProgramExpression, - TokCompoundProgramHeader, - TokCommonProgramHeader, - TokCompoundQueryProgramHeader, - TokCommonQueryProgramHeader, - TokWhiteSpace, - TokUnknown, -}; -typedef enum _token_type_t token_type_t; - -struct _token_t { - token_type_t type; - const char * ptr; - int len; -}; -typedef struct _token_t token_t; - -struct _lex_state_t { - const char * buffer; - const char * pos; - int len; -}; -typedef struct _lex_state_t lex_state_t; - - -int SCPI_LexWhiteSpace(lex_state_t * state, token_t * token); -int SCPI_LexProgramHeader(lex_state_t * state, token_t * token); -int SCPI_LexQuestion(lex_state_t * state, token_t * token); -int SCPI_LexCharacterProgramData(lex_state_t * state, token_t * token); -int SCPI_LexDecimalNumericProgramData(lex_state_t * state, token_t * token); -int SCPI_LexSuffixProgramData(lex_state_t * state, token_t * token); -int SCPI_LexNondecimalNumericData(lex_state_t * state, token_t * token); -int SCPI_LexStringProgramData(lex_state_t * state, token_t * token); -int SCPI_LexArbitraryBlockProgramData(lex_state_t * state, token_t * token); -int SCPI_LexProgramExpression(lex_state_t * state, token_t * token); -int SCPI_LexComma(lex_state_t * state, token_t * token); -int SCPI_LexSemicolon(lex_state_t * state, token_t * token); -int SCPI_LexNewLine(lex_state_t * state, token_t * token); + int SCPI_LexWhiteSpace(lex_state_t * state, token_t * token); + int SCPI_LexProgramHeader(lex_state_t * state, token_t * token); + int SCPI_LexQuestion(lex_state_t * state, token_t * token); + int SCPI_LexCharacterProgramData(lex_state_t * state, token_t * token); + int SCPI_LexDecimalNumericProgramData(lex_state_t * state, token_t * token); + int SCPI_LexSuffixProgramData(lex_state_t * state, token_t * token); + int SCPI_LexNondecimalNumericData(lex_state_t * state, token_t * token); + int SCPI_LexStringProgramData(lex_state_t * state, token_t * token); + int SCPI_LexArbitraryBlockProgramData(lex_state_t * state, token_t * token); + int SCPI_LexProgramExpression(lex_state_t * state, token_t * token); + int SCPI_LexComma(lex_state_t * state, token_t * token); + int SCPI_LexSemicolon(lex_state_t * state, token_t * token); + int SCPI_LexNewLine(lex_state_t * state, token_t * token); #ifdef __cplusplus } diff --git a/libscpi/inc/scpi/parser.h b/libscpi/inc/scpi/parser.h index dfa5608..a8d5959 100644 --- a/libscpi/inc/scpi/parser.h +++ b/libscpi/inc/scpi/parser.h @@ -39,11 +39,11 @@ #include "scpi/types.h" #include "scpi/debug.h" +#include "scpi/lexer.h" #ifdef __cplusplus extern "C" { #endif - void SCPI_Init(scpi_t * context); int SCPI_Input(scpi_t * context, const char * data, size_t len); @@ -58,9 +58,13 @@ bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, bool_t mandatory); bool_t SCPI_ParamDouble(scpi_t * context, double * value, bool_t mandatory); bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, bool_t mandatory); - bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, bool_t mandatory); + bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, bool_t mandatory); + int SCPI_ParseProgramData(lex_state_t * state, token_t * token); + int SCPI_ParseAllProgramData(lex_state_t * state, token_t * token, int * numberOfParameters); + int SCPI_DetectProgramMessageUnit(scpi_t * context); + #ifdef __cplusplus } #endif diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h index dff7991..7dcca59 100644 --- a/libscpi/inc/scpi/types.h +++ b/libscpi/inc/scpi/types.h @@ -57,13 +57,13 @@ /* IEEE 488.2 registers */ enum _scpi_reg_name_t { SCPI_REG_STB = 0, /* Status Byte */ - SCPI_REG_SRE, /* Service Request Enable Register */ - SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */ - SCPI_REG_ESE, /* Event Status Enable Register */ - SCPI_REG_OPER, /* OPERation Status Register */ - SCPI_REG_OPERE, /* OPERation Status Enable Register */ - SCPI_REG_QUES, /* QUEStionable status register */ - SCPI_REG_QUESE, /* QUEStionable status Enable Register */ + SCPI_REG_SRE, /* Service Request Enable Register */ + SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */ + SCPI_REG_ESE, /* Event Status Enable Register */ + SCPI_REG_OPER, /* OPERation Status Register */ + SCPI_REG_OPERE, /* OPERation Status Enable Register */ + SCPI_REG_QUES, /* QUEStionable status register */ + SCPI_REG_QUESE, /* QUEStionable status Enable Register */ /* last definition - number of registers */ SCPI_REG_COUNT @@ -72,21 +72,21 @@ enum _scpi_ctrl_name_t { SCPI_CTRL_SRQ = 1, /* service request */ - SCPI_CTRL_GTL, /* Go to local */ - SCPI_CTRL_SDC, /* Selected device clear */ - SCPI_CTRL_PPC, /* Parallel poll configure */ - SCPI_CTRL_GET, /* Group execute trigger */ - SCPI_CTRL_TCT, /* Take control */ - SCPI_CTRL_LLO, /* Device clear */ - SCPI_CTRL_DCL, /* Local lockout */ - SCPI_CTRL_PPU, /* Parallel poll unconfigure */ - SCPI_CTRL_SPE, /* Serial poll enable */ - SCPI_CTRL_SPD, /* Serial poll disable */ - SCPI_CTRL_MLA, /* My local address */ - SCPI_CTRL_UNL, /* Unlisten */ - SCPI_CTRL_MTA, /* My talk address */ - SCPI_CTRL_UNT, /* Untalk */ - SCPI_CTRL_MSA /* My secondary address */ + SCPI_CTRL_GTL, /* Go to local */ + SCPI_CTRL_SDC, /* Selected device clear */ + SCPI_CTRL_PPC, /* Parallel poll configure */ + SCPI_CTRL_GET, /* Group execute trigger */ + SCPI_CTRL_TCT, /* Take control */ + SCPI_CTRL_LLO, /* Device clear */ + SCPI_CTRL_DCL, /* Local lockout */ + SCPI_CTRL_PPU, /* Parallel poll unconfigure */ + SCPI_CTRL_SPE, /* Serial poll enable */ + SCPI_CTRL_SPD, /* Serial poll disable */ + SCPI_CTRL_MLA, /* My local address */ + SCPI_CTRL_UNL, /* Unlisten */ + SCPI_CTRL_MTA, /* My talk address */ + SCPI_CTRL_UNT, /* Untalk */ + SCPI_CTRL_MSA /* My secondary address */ }; typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t; @@ -106,7 +106,7 @@ const char * parameters; size_t length; }; - #define SCPI_CMD_LIST_END {NULL, NULL, } +#define SCPI_CMD_LIST_END {NULL, NULL, } typedef struct _scpi_param_list_t scpi_param_list_t; /* scpi interface */ @@ -123,6 +123,63 @@ typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len); typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error); + + /* scpi lexer */ + enum _token_type_t { + TokComma, + TokSemicolon, + TokQuiestion, + TokNewLine, + TokHexnum, + TokOctnum, + TokBinnum, + TokProgramMnemonic, + TokDecimalNumericProgramData, + TokDecimalNumericProgramDataWithSuffix, + TokSuffixProgramData, + TokArbitraryBlockProgramData, + TokSingleQuoteProgramData, + TokDoubleQuoteProgramData, + TokProgramExpression, + TokCompoundProgramHeader, + TokCommonProgramHeader, + TokCompoundQueryProgramHeader, + TokCommonQueryProgramHeader, + TokWhiteSpace, + TokAllProgramData, + TokUnknown, + }; + typedef enum _token_type_t token_type_t; + + struct _token_t { + token_type_t type; + const char * ptr; + int len; + }; + typedef struct _token_t token_t; + + struct _lex_state_t { + const char * buffer; + const char * pos; + int len; + }; + typedef struct _lex_state_t lex_state_t; + + /* scpi parser */ + enum _message_termination_t { + PmutNone, + PmutNewLine, + PmutSemicolon, + }; + typedef enum _message_termination_t message_termination_t; + + struct _scpi_parser_state_t { + token_t programHeader; + token_t programData; + int numberOfParameters; + message_termination_t termination; + }; + typedef struct _scpi_parser_state_t scpi_parser_state_t; typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *); @@ -147,7 +204,7 @@ scpi_unit_t unit; double mult; }; - #define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} +#define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} typedef struct _scpi_unit_def_t scpi_unit_def_t; enum _scpi_special_number_t { @@ -167,7 +224,7 @@ const char * name; scpi_special_number_t type; }; - #define SCPI_SPECIAL_NUMBERS_LIST_END {NULL, SCPI_NUM_NUMBER} +#define SCPI_SPECIAL_NUMBERS_LIST_END {NULL, SCPI_NUM_NUMBER} typedef struct _scpi_special_number_def_t scpi_special_number_def_t; struct _scpi_number_t { @@ -204,6 +261,7 @@ const scpi_unit_def_t * units; const scpi_special_number_def_t * special_numbers; void * user_context; + scpi_parser_state_t parser_state; }; #ifdef __cplusplus diff --git a/libscpi/src/lexer.c b/libscpi/src/lexer.c index 1507eed..0b3bf09 100644 --- a/libscpi/src/lexer.c +++ b/libscpi/src/lexer.c @@ -437,8 +437,9 @@ } else { token->type = TokUnknown; state->pos = token->ptr; + token->len = 0; } - return token->len; + return token->len > 0 ? token->len + 2 : 0; } @@ -510,7 +511,7 @@ token->len = 0; } - return token->len; + return token->len > 0 ? token->len + 2 : 0; } /* 7.7.6 <ARBITRARY BLOCK PROGRAM DATA> */ @@ -521,7 +522,7 @@ int SCPI_LexArbitraryBlockProgramData(lex_state_t * state, token_t * token) { int i; int j = 0; - + const char * ptr = state->pos; token->ptr = state->pos; if (skipChr(state, '#')) { @@ -542,11 +543,11 @@ if(i == 0) { state->pos += j; - if (!iseos(state)) { + if ((state->buffer + state->len) < (state->pos)) { + token->len = 0; + } else { token->ptr = state->pos - j; token->len = j; - } else { - token->len = 0; } } else { token->len = 0; @@ -564,7 +565,7 @@ token->len = 0; } - return token->len; + return token->len + (token->ptr - ptr); } /* 7.7.7 <EXPRESSION PROGRAM DATA> */ diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c index d10cfe1..af66202 100644 --- a/libscpi/src/parser.c +++ b/libscpi/src/parser.c @@ -265,7 +265,7 @@ cmd_len = cmdTerminatorPos(cmdline_ptr, cmdline_end - cmdline_ptr); cmdline_len = cmdlineSeparatorPos(cmdline_ptr, cmdline_end - cmdline_ptr); if (cmd_len > 0) { - if(findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) { + if (findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) { processCommand(context); result = 1; } else { @@ -568,39 +568,106 @@ return FALSE; } +int SCPI_ParseProgramData(lex_state_t * state, token_t * token) { + token_t tmp; + int result = 0; + int wsLen; + int suffixLen; + int realLen = 0; + realLen += SCPI_LexWhiteSpace(state, &tmp); + + if (result == 0) result = SCPI_LexNondecimalNumericData(state, token); + if (result == 0) result = SCPI_LexCharacterProgramData(state, token); + if (result == 0) { + result = SCPI_LexDecimalNumericProgramData(state, token); + if (result != 0) { + wsLen = SCPI_LexWhiteSpace(state, &tmp); + suffixLen = SCPI_LexSuffixProgramData(state, &tmp); + if (suffixLen > 0) { + token->len += wsLen + suffixLen; + token->type = TokDecimalNumericProgramDataWithSuffix; + result = token->len; + } + } + } + + if (result == 0) result = SCPI_LexStringProgramData(state, token); + if (result == 0) result = SCPI_LexArbitraryBlockProgramData(state, token); + if (result == 0) result = SCPI_LexProgramExpression(state, token); + + realLen += SCPI_LexWhiteSpace(state, &tmp); + + return result + realLen; +} + +int SCPI_ParseAllProgramData(lex_state_t * state, token_t * token, int * numberOfParameters) { + + int result; + token_t tmp; + int paramCount = 0; + + token->len = -1; + token->type = TokAllProgramData; + token->ptr = state->pos; -void SCPI_ProgramMessageUnit(scpi_t * context) { + for (result = 1; result != 0; result = SCPI_LexComma(state, &tmp)) { + token->len += result; + + if (result == 0) { + token->type = TokUnknown; + token->len = 0; + break; + } + + result = SCPI_ParseProgramData(state, &tmp); + if (tmp.type != TokUnknown) { + token->len += result; + } else { + token->type = TokUnknown; + token->len = 0; + break; + } + paramCount++; + } + + if (token->len == -1) { + token->len = 0; + } + + if (numberOfParameters != NULL) { + *numberOfParameters = paramCount; + } + return token->len; +} + +int SCPI_DetectProgramMessageUnit(scpi_t * context) { lex_state_t state; token_t tmp; - token_t header; - token_t token; - + int result = 0; + state.buffer = state.pos = context->buffer.data; state.len = context->buffer.position; - + /* ignore whitespace at the begginig */ SCPI_LexWhiteSpace(&state, &tmp); - - SCPI_LexProgramHeader(&state, &header); - + + SCPI_LexProgramHeader(&state, &context->parser_state.programHeader); + SCPI_LexWhiteSpace(&state, &tmp); - - SCPI_ParseProgramDate(context, &state, &token); - - SCPI_LexWhiteSpace(&state, &tmp); - - { - SCPI_LexComma(&state, &token); - - SCPI_LexWhiteSpace(&state, &tmp); - - SCPI_ParseProgramDate(context, &state); - - SCPI_LexWhiteSpace(&state, &tmp); + + SCPI_ParseAllProgramData(&state, &context->parser_state.programData, &context->parser_state.numberOfParameters); + + if (result == 0) result = SCPI_LexNewLine(&state, &tmp); + if (result == 0) result = SCPI_LexSemicolon(&state, &tmp); + + if (TokSemicolon == tmp.type) { + context->parser_state.termination = PmutSemicolon; + } else if (TokNewLine == tmp.type) { + context->parser_state.termination = PmutNewLine; + } else { + context->parser_state.termination = PmutNone; } - - SCPI_LexNewLine(&state, &tmp); } diff --git a/libscpi/test/test_lexer.c b/libscpi/test/test_lexer.c deleted file mode 100644 index 6e593c0..0000000 --- a/libscpi/test/test_lexer.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * File: test_lexer.c - * Author: jaybee - * - * Created on Thu Mar 21 14:39:03 UTC 2013 - */ - -#include <stdio.h> -#include <stdlib.h> -#include "CUnit/Basic.h" - -#include "scpi/lexer.h" - -/* - * CUnit Test Suite - */ - -int init_suite(void) { - return 0; -} - -int clean_suite(void) { - return 0; -} - -typedef int (*lexfn_t)(lex_state_t * state, token_t * token); - - -const char * typeToStr(token_type_t type) { - switch(type) { - case TokComma: return "TokComma"; - case TokSemicolon: return "TokSemicolon"; - case TokQuiestion: return "TokQuiestion"; - case TokNewLine: return "TokNewLine"; - case TokHexnum: return "TokHexnum"; - case TokOctnum: return "TokOctnum"; - case TokBinnum: return "TokBinnum"; - case TokProgramMnemonic: return "TokProgramMnemonic"; - case TokDecimalNumericProgramData: return "TokDecimalNumericProgramData"; - case TokSuffixProgramData: return "TokSuffixProgramData"; - case TokArbitraryBlockProgramData: return "TokArbitraryBlockProgramData"; - case TokSingleQuoteProgramData: return "TokSingleQuoteProgramData"; - case TokDoubleQuoteProgramData: return "TokDoubleQuoteProgramData"; - case TokProgramExpression: return "TokProgramExpression"; - case TokCompoundProgramHeader: return "TokCompoundProgramHeader"; - case TokCommonProgramHeader: return "TokCommonProgramHeader"; - case TokCompoundQueryProgramHeader: return "TokCompoundQueryProgramHeader"; - case TokCommonQueryProgramHeader: return "TokCommonQueryProgramHeader"; - case TokWhiteSpace: return "TokWhiteSpace"; - default: return "TokUnknown"; - } -} - -void printToken(token_t * token) { - printf("Token:\r\n"); - printf("\t->type = %s\r\n", typeToStr(token->type)); - printf("\t->ptr = %p (\"%.*s\")\r\n", token->ptr, token->len, token->ptr); - printf("\t->len = %d\r\n", token->len); -} - - -#if 0 -static void TEST_TOKEN(const char * str, lexfn_t fn, int offset, int len, token_type_t tp) { - lex_state_t state; - token_t token; - - state.buffer = state.pos = str; - state.len = strlen(str); - fn(&state, &token); - CU_ASSERT_EQUAL(str + offset, token.ptr); - CU_ASSERT_EQUAL(len, token.len); - CU_ASSERT_EQUAL(tp, token.type); -} -#endif - -#define TEST_TOKEN(s, f, o, l, t) do { \ - const char * str = s; \ - lexfn_t fn = f; \ - int offset = o; \ - int len = l; \ - token_type_t tp = t; \ - lex_state_t state; \ - token_t token; \ - \ - state.buffer = state.pos = str; \ - state.len = strlen(str); \ - fn(&state, &token); \ - CU_ASSERT_EQUAL(str + offset, token.ptr); \ - CU_ASSERT_EQUAL(len, token.len); \ - CU_ASSERT_EQUAL(tp, token.type); \ - /* printToken(&token); */ \ -} while(0) - - -void testWhiteSpace(void) { - TEST_TOKEN(" \t MEAS", SCPI_LexWhiteSpace, 0, 4, TokWhiteSpace); - TEST_TOKEN("MEAS", SCPI_LexWhiteSpace, 0, 0, TokUnknown); -} - -void testNondecimal(void) { - TEST_TOKEN("#H123fe5A", SCPI_LexNondecimalNumericData, 2, 7, TokHexnum); - TEST_TOKEN("#B0111010101", SCPI_LexNondecimalNumericData, 2, 10, TokBinnum); - TEST_TOKEN("#Q125725433", SCPI_LexNondecimalNumericData, 2, 9, TokOctnum); -} - -void testCharacterProgramData(void) { - TEST_TOKEN("abc_213as564 , ", SCPI_LexCharacterProgramData, 0, 12, TokProgramMnemonic); -} - -void testDecimal(void) { - TEST_TOKEN("10 , ", SCPI_LexDecimalNumericProgramData, 0, 2, TokDecimalNumericProgramData); - TEST_TOKEN("-10.5 , ", SCPI_LexDecimalNumericProgramData, 0, 5, TokDecimalNumericProgramData); - TEST_TOKEN("+.5 , ", SCPI_LexDecimalNumericProgramData, 0, 3, TokDecimalNumericProgramData); - TEST_TOKEN("-. , ", SCPI_LexDecimalNumericProgramData, 0, 0, TokUnknown); - TEST_TOKEN("-1 e , ", SCPI_LexDecimalNumericProgramData, 0, 2, TokDecimalNumericProgramData); - TEST_TOKEN("-1 e 3, ", SCPI_LexDecimalNumericProgramData, 0, 6, TokDecimalNumericProgramData); - TEST_TOKEN("1.5E12", SCPI_LexDecimalNumericProgramData, 0, 6, TokDecimalNumericProgramData); -} - -void testSuffix(void) { - TEST_TOKEN("A/V , ", SCPI_LexSuffixProgramData, 0, 3, TokSuffixProgramData); - TEST_TOKEN("mA.h", SCPI_LexSuffixProgramData, 0, 4, TokSuffixProgramData); -} - -void testProgramHeader(void) { - TEST_TOKEN("*IDN? ", SCPI_LexProgramHeader, 0, 5, TokCommonQueryProgramHeader); - TEST_TOKEN("*RST ", SCPI_LexProgramHeader, 0, 4, TokCommonProgramHeader); - TEST_TOKEN("*?; ", SCPI_LexProgramHeader, 0, 0, TokUnknown); - TEST_TOKEN("MEAS:VOLT:DC? ", SCPI_LexProgramHeader, 0, 13, TokCompoundQueryProgramHeader); - TEST_TOKEN("CONF:VOLT:DC ", SCPI_LexProgramHeader, 0, 12, TokCompoundProgramHeader); - TEST_TOKEN(":MEAS:VOLT:DC? ", SCPI_LexProgramHeader, 0, 14, TokCompoundQueryProgramHeader); - TEST_TOKEN(":MEAS::VOLT:DC? ", SCPI_LexProgramHeader, 0, 0, TokUnknown); - TEST_TOKEN("*IDN?", SCPI_LexProgramHeader, 0, 5, TokCommonQueryProgramHeader); - TEST_TOKEN("*RST", SCPI_LexProgramHeader, 0, 4, TokCommonProgramHeader); -} - -void testArbitraryBlock(void) { - TEST_TOKEN("#12AB, ", SCPI_LexArbitraryBlockProgramData, 3, 2, TokArbitraryBlockProgramData); - TEST_TOKEN("#13AB", SCPI_LexArbitraryBlockProgramData, 0, 0, TokUnknown); - TEST_TOKEN("#12\r\n, ", SCPI_LexArbitraryBlockProgramData, 3, 2, TokArbitraryBlockProgramData); - TEST_TOKEN("#02AB, ", SCPI_LexArbitraryBlockProgramData, 0, 0, TokUnknown); -} - -void testExpression(void) { - TEST_TOKEN("( 1 + 2 ) , ", SCPI_LexProgramExpression, 0, 9, TokProgramExpression); - TEST_TOKEN("( 1 + 2 , ", SCPI_LexProgramExpression, 0, 0, TokUnknown); -} - -void testString(void) { - TEST_TOKEN("\"ahoj\" ", SCPI_LexStringProgramData, 1, 4, TokDoubleQuoteProgramData); - TEST_TOKEN("'ahoj' ", SCPI_LexStringProgramData, 1, 4, TokSingleQuoteProgramData); - TEST_TOKEN("'ahoj ", SCPI_LexStringProgramData, 0, 0, TokUnknown); - TEST_TOKEN("'ah''oj' ", SCPI_LexStringProgramData, 1, 6, TokSingleQuoteProgramData); - TEST_TOKEN("'ah\"oj' ", SCPI_LexStringProgramData, 1, 5, TokSingleQuoteProgramData); - TEST_TOKEN("\"ah\"\"oj\" ", SCPI_LexStringProgramData, 1, 6, TokDoubleQuoteProgramData); -} - - -int main() { - CU_pSuite pSuite = NULL; - - /* Initialize the CUnit test registry */ - if (CUE_SUCCESS != CU_initialize_registry()) - return CU_get_error(); - - /* Add a suite to the registry */ - pSuite = CU_add_suite("Lexer", init_suite, clean_suite); - if (NULL == pSuite) { - CU_cleanup_registry(); - return CU_get_error(); - } - - /* Add the tests to the suite */ - if ((NULL == CU_add_test(pSuite, "WhiteSpace", testWhiteSpace)) - || (NULL == CU_add_test(pSuite, "Nondecimal", testNondecimal)) - || (NULL == CU_add_test(pSuite, "CharacterProgramData", testCharacterProgramData)) - || (NULL == CU_add_test(pSuite, "Decimal", testDecimal)) - || (NULL == CU_add_test(pSuite, "Suffix", testSuffix)) - || (NULL == CU_add_test(pSuite, "ProgramHeader", testProgramHeader)) - || (NULL == CU_add_test(pSuite, "ArbitraryBlock", testArbitraryBlock)) - || (NULL == CU_add_test(pSuite, "Expression", testExpression)) - || (NULL == CU_add_test(pSuite, "String", testString)) - ) { - CU_cleanup_registry(); - return CU_get_error(); - } - - /* Run all tests using the CUnit Basic interface */ - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - CU_cleanup_registry(); - return CU_get_error(); -} - diff --git a/libscpi/test/test_lexer_parser.c b/libscpi/test/test_lexer_parser.c new file mode 100644 index 0000000..4b94e13 --- /dev/null +++ b/libscpi/test/test_lexer_parser.c @@ -0,0 +1,302 @@ +/* + * File: test_lexer.c + * Author: jaybee + * + * Created on Thu Mar 21 14:39:03 UTC 2013 + */ + +#include <stdio.h> +#include <stdlib.h> +#include "CUnit/Basic.h" + +#include "scpi/lexer.h" +#include "scpi/parser.h" + +/* + * CUnit Test Suite + */ + +int init_suite(void) { + return 0; +} + +int clean_suite(void) { + return 0; +} + +typedef int (*lexfn_t)(lex_state_t * state, token_t * token); +typedef int (*lexfn2_t)(lex_state_t * state, token_t * token, int * cnt); + +const char * typeToStr(token_type_t type) { + switch (type) { + case TokComma: return "TokComma"; + case TokSemicolon: return "TokSemicolon"; + case TokQuiestion: return "TokQuiestion"; + case TokNewLine: return "TokNewLine"; + case TokHexnum: return "TokHexnum"; + case TokOctnum: return "TokOctnum"; + case TokBinnum: return "TokBinnum"; + case TokProgramMnemonic: return "TokProgramMnemonic"; + case TokDecimalNumericProgramData: return "TokDecimalNumericProgramData"; + case TokDecimalNumericProgramDataWithSuffix: return "TokDecimalNumericProgramDataWithSuffix"; + case TokSuffixProgramData: return "TokSuffixProgramData"; + case TokArbitraryBlockProgramData: return "TokArbitraryBlockProgramData"; + case TokSingleQuoteProgramData: return "TokSingleQuoteProgramData"; + case TokDoubleQuoteProgramData: return "TokDoubleQuoteProgramData"; + case TokProgramExpression: return "TokProgramExpression"; + case TokCompoundProgramHeader: return "TokCompoundProgramHeader"; + case TokCommonProgramHeader: return "TokCommonProgramHeader"; + case TokCompoundQueryProgramHeader: return "TokCompoundQueryProgramHeader"; + case TokCommonQueryProgramHeader: return "TokCommonQueryProgramHeader"; + case TokWhiteSpace: return "TokWhiteSpace"; + case TokAllProgramData: return "TokAllProgramData"; + default: return "TokUnknown"; + } +} + +void printToken(token_t * token) { + printf("Token:\r\n"); + printf("\t->type = %s\r\n", typeToStr(token->type)); + printf("\t->ptr = %p (\"%.*s\")\r\n", token->ptr, token->len, token->ptr); + printf("\t->len = %d\r\n", token->len); +} + + +#if 0 + +static void TEST_TOKEN(const char * str, lexfn_t fn, int offset, int len, token_type_t tp) { + lex_state_t state; + token_t token; + + state.buffer = state.pos = str; + state.len = strlen(str); + fn(&state, &token); + CU_ASSERT_EQUAL(str + offset, token.ptr); + CU_ASSERT_EQUAL(len, token.len); + CU_ASSERT_EQUAL(tp, token.type); +} +#endif + +#define TEST_TOKEN(s, f, o, l, t) do { \ + const char * str = s; \ + lexfn_t fn = f; \ + int offset = o; \ + int len = l; \ + token_type_t tp = t; \ + lex_state_t state; \ + token_t token; \ + \ + state.buffer = state.pos = str; \ + state.len = strlen(str); \ + fn(&state, &token); \ + CU_ASSERT_EQUAL(str + offset, token.ptr); \ + CU_ASSERT_EQUAL(len, token.len); \ + CU_ASSERT_EQUAL(tp, token.type); \ + if (tp != token.type) printToken(&token); \ + else \ + if (len != token.len) printToken(&token); \ +} while(0) + + +void testWhiteSpace(void) { + TEST_TOKEN(" \t MEAS", SCPI_LexWhiteSpace, 0, 4, TokWhiteSpace); + TEST_TOKEN("MEAS", SCPI_LexWhiteSpace, 0, 0, TokUnknown); +} + +void testNondecimal(void) { + TEST_TOKEN("#H123fe5A", SCPI_LexNondecimalNumericData, 2, 7, TokHexnum); + TEST_TOKEN("#B0111010101", SCPI_LexNondecimalNumericData, 2, 10, TokBinnum); + TEST_TOKEN("#Q125725433", SCPI_LexNondecimalNumericData, 2, 9, TokOctnum); +} + +void testCharacterProgramData(void) { + TEST_TOKEN("abc_213as564", SCPI_LexCharacterProgramData, 0, 12, TokProgramMnemonic); + TEST_TOKEN("abc_213as564 , ", SCPI_LexCharacterProgramData, 0, 12, TokProgramMnemonic); +} + +void testDecimal(void) { + TEST_TOKEN("10", SCPI_LexDecimalNumericProgramData, 0, 2, TokDecimalNumericProgramData); + TEST_TOKEN("10 , ", SCPI_LexDecimalNumericProgramData, 0, 2, TokDecimalNumericProgramData); + TEST_TOKEN("-10.5 , ", SCPI_LexDecimalNumericProgramData, 0, 5, TokDecimalNumericProgramData); + TEST_TOKEN("+.5 , ", SCPI_LexDecimalNumericProgramData, 0, 3, TokDecimalNumericProgramData); + TEST_TOKEN("-. , ", SCPI_LexDecimalNumericProgramData, 0, 0, TokUnknown); + TEST_TOKEN("-1 e , ", SCPI_LexDecimalNumericProgramData, 0, 2, TokDecimalNumericProgramData); + TEST_TOKEN("-1 e 3, ", SCPI_LexDecimalNumericProgramData, 0, 6, TokDecimalNumericProgramData); + TEST_TOKEN("1.5E12", SCPI_LexDecimalNumericProgramData, 0, 6, TokDecimalNumericProgramData); +} + +void testSuffix(void) { + TEST_TOKEN("A/V , ", SCPI_LexSuffixProgramData, 0, 3, TokSuffixProgramData); + TEST_TOKEN("mA.h", SCPI_LexSuffixProgramData, 0, 4, TokSuffixProgramData); +} + +void testProgramHeader(void) { + TEST_TOKEN("*IDN? ", SCPI_LexProgramHeader, 0, 5, TokCommonQueryProgramHeader); + TEST_TOKEN("*RST ", SCPI_LexProgramHeader, 0, 4, TokCommonProgramHeader); + TEST_TOKEN("*?; ", SCPI_LexProgramHeader, 0, 0, TokUnknown); + TEST_TOKEN(":*IDN?; ", SCPI_LexProgramHeader, 0, 0, TokUnknown); + TEST_TOKEN("MEAS:VOLT:DC? ", SCPI_LexProgramHeader, 0, 13, TokCompoundQueryProgramHeader); + TEST_TOKEN("CONF:VOLT:DC ", SCPI_LexProgramHeader, 0, 12, TokCompoundProgramHeader); + TEST_TOKEN(":MEAS:VOLT:DC? ", SCPI_LexProgramHeader, 0, 14, TokCompoundQueryProgramHeader); + TEST_TOKEN(":MEAS::VOLT:DC? ", SCPI_LexProgramHeader, 0, 0, TokUnknown); + TEST_TOKEN("*IDN?", SCPI_LexProgramHeader, 0, 5, TokCommonQueryProgramHeader); + TEST_TOKEN("*RST", SCPI_LexProgramHeader, 0, 4, TokCommonProgramHeader); +} + +void testArbitraryBlock(void) { + TEST_TOKEN("#12AB", SCPI_LexArbitraryBlockProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#12AB, ", SCPI_LexArbitraryBlockProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#13AB", SCPI_LexArbitraryBlockProgramData, 0, 0, TokUnknown); + TEST_TOKEN("#12\r\n, ", SCPI_LexArbitraryBlockProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#02AB, ", SCPI_LexArbitraryBlockProgramData, 0, 0, TokUnknown); +} + +void testExpression(void) { + TEST_TOKEN("( 1 + 2 )", SCPI_LexProgramExpression, 0, 9, TokProgramExpression); + TEST_TOKEN("( 1 + 2 ) , ", SCPI_LexProgramExpression, 0, 9, TokProgramExpression); + TEST_TOKEN("( 1 + 2 , ", SCPI_LexProgramExpression, 0, 0, TokUnknown); +} + +void testString(void) { + TEST_TOKEN("\"ahoj\"", SCPI_LexStringProgramData, 1, 4, TokDoubleQuoteProgramData); + TEST_TOKEN("\"ahoj\" ", SCPI_LexStringProgramData, 1, 4, TokDoubleQuoteProgramData); + TEST_TOKEN("'ahoj' ", SCPI_LexStringProgramData, 1, 4, TokSingleQuoteProgramData); + TEST_TOKEN("'ahoj ", SCPI_LexStringProgramData, 0, 0, TokUnknown); + TEST_TOKEN("'ah''oj' ", SCPI_LexStringProgramData, 1, 6, TokSingleQuoteProgramData); + TEST_TOKEN("'ah\"oj' ", SCPI_LexStringProgramData, 1, 5, TokSingleQuoteProgramData); + TEST_TOKEN("\"ah\"\"oj\" ", SCPI_LexStringProgramData, 1, 6, TokDoubleQuoteProgramData); +} + +void testProgramData(void) { + TEST_TOKEN("#H123fe5A", SCPI_ParseProgramData, 2, 7, TokHexnum); + TEST_TOKEN(" #H123fe5A ", SCPI_ParseProgramData, 4, 7, TokHexnum); + TEST_TOKEN("#B0111010101", SCPI_ParseProgramData, 2, 10, TokBinnum); + TEST_TOKEN("#Q125725433", SCPI_ParseProgramData, 2, 9, TokOctnum); + + TEST_TOKEN("10", SCPI_ParseProgramData, 0, 2, TokDecimalNumericProgramData); + TEST_TOKEN("10 , ", SCPI_ParseProgramData, 0, 2, TokDecimalNumericProgramData); + TEST_TOKEN("-10.5 , ", SCPI_ParseProgramData, 0, 5, TokDecimalNumericProgramData); + TEST_TOKEN("+.5 , ", SCPI_ParseProgramData, 0, 3, TokDecimalNumericProgramData); + TEST_TOKEN("-. , ", SCPI_ParseProgramData, 0, 0, TokUnknown); + TEST_TOKEN("-1 e , ", SCPI_ParseProgramData, 0, 4, TokDecimalNumericProgramDataWithSuffix); + TEST_TOKEN("-1 e 3, ", SCPI_ParseProgramData, 0, 6, TokDecimalNumericProgramData); + TEST_TOKEN("1.5E12", SCPI_ParseProgramData, 0, 6, TokDecimalNumericProgramData); + + TEST_TOKEN("#12AB", SCPI_ParseProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#12AB, ", SCPI_ParseProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#13AB", SCPI_ParseProgramData, 0, 0, TokUnknown); + TEST_TOKEN("#12\r\n, ", SCPI_ParseProgramData, 3, 2, TokArbitraryBlockProgramData); + TEST_TOKEN("#02AB, ", SCPI_ParseProgramData, 0, 0, TokUnknown); + + TEST_TOKEN("( 1 + 2 ) , ", SCPI_ParseProgramData, 0, 9, TokProgramExpression); + TEST_TOKEN("( 1 + 2 , ", SCPI_ParseProgramData, 0, 0, TokUnknown); + + TEST_TOKEN("\"ahoj\" ", SCPI_ParseProgramData, 1, 4, TokDoubleQuoteProgramData); + TEST_TOKEN("'ahoj' ", SCPI_ParseProgramData, 1, 4, TokSingleQuoteProgramData); + TEST_TOKEN("'ahoj ", SCPI_ParseProgramData, 0, 0, TokUnknown); + TEST_TOKEN("'ah''oj' ", SCPI_ParseProgramData, 1, 6, TokSingleQuoteProgramData); + TEST_TOKEN("'ah\"oj' ", SCPI_ParseProgramData, 1, 5, TokSingleQuoteProgramData); + TEST_TOKEN("\"ah\"\"oj\" ", SCPI_ParseProgramData, 1, 6, TokDoubleQuoteProgramData); + + TEST_TOKEN("abc_213as564 , ", SCPI_LexCharacterProgramData, 0, 12, TokProgramMnemonic); + + TEST_TOKEN("1.5E12 V", SCPI_ParseProgramData, 0, 8, TokDecimalNumericProgramDataWithSuffix); +} + + +#define TEST_ALL_TOKEN(s, f, o, l, t, c) do { \ + const char * str = s; \ + lexfn2_t fn = f; \ + int offset = o; \ + int len = l; \ + token_type_t tp = t; \ + lex_state_t state; \ + token_t token; \ + int count; \ + \ + state.buffer = state.pos = str; \ + state.len = strlen(str); \ + fn(&state, &token, &count); \ + CU_ASSERT_EQUAL(str + offset, token.ptr); \ + CU_ASSERT_EQUAL(len, token.len); \ + CU_ASSERT_EQUAL(tp, token.type); \ + CU_ASSERT_EQUAL(count, c); \ + if (tp != token.type) printToken(&token); \ + else \ + if (len != token.len) printToken(&token); \ +} while(0) + + +void testAllProgramData(void) { + TEST_ALL_TOKEN("1.5E12 V", SCPI_ParseAllProgramData, 0, 8, TokAllProgramData, 1); + TEST_ALL_TOKEN("1.5E12 V, abc_213as564, 10, #H123fe5A", SCPI_ParseAllProgramData, 0, 37, TokAllProgramData, 4); + TEST_ALL_TOKEN("1.5E12 V, ", SCPI_ParseAllProgramData, 0, 0, TokUnknown, 1); + TEST_ALL_TOKEN("#12\r\n, 1.5E12 V", SCPI_ParseAllProgramData, 0, 15, TokAllProgramData, 2); + TEST_ALL_TOKEN(" ( 1 + 2 ) ,#12\r\n, 1.5E12 V", SCPI_ParseAllProgramData, 0, 27, TokAllProgramData, 3); + TEST_ALL_TOKEN("\"ahoj\" , #12AB", SCPI_ParseAllProgramData, 0, 14, TokAllProgramData, 2); +} + + +#define TEST_DETECT(s, h, ht, d, dc, t) do { \ + const char * str = s; \ + scpi_t context; \ + int result; \ + context.buffer.data = s; \ + context.buffer.length = strlen(s); \ + context.buffer.position = context.buffer.length; \ + result = SCPI_DetectProgramMessageUnit(&context); \ + CU_ASSERT_EQUAL(context.parser_state.programHeader.ptr, str+h); \ + CU_ASSERT_EQUAL(context.parser_state.programHeader.type, ht); \ + CU_ASSERT_EQUAL(context.parser_state.programData.ptr, str+d); \ + CU_ASSERT_EQUAL(context.parser_state.numberOfParameters, dc); \ + CU_ASSERT_EQUAL(context.parser_state.termination, t); \ +} while(0) + +void testDetectProgramMessageUnit(void) { + TEST_DETECT("*IDN?\r\n", 0, TokCommonQueryProgramHeader, 5, 0, PmutNewLine); + TEST_DETECT(" MEAS:VOLT:DC?\r\n", 1, TokCompoundQueryProgramHeader, 14, 0, PmutNewLine); + TEST_DETECT(" MEAS:VOLT:DC? 1.2 V\r\n", 1, TokCompoundQueryProgramHeader, 15, 1, PmutNewLine); + TEST_DETECT(" CONF:VOLT:DC 1.2 V, 100mv;", 1, TokCompoundProgramHeader, 14, 2, PmutSemicolon); + TEST_DETECT(" CONF:VOLT:DC 1.2 V, 100mv", 1, TokCompoundProgramHeader, 14, 2, PmutNone); + TEST_DETECT(" CONF:VOLT:DC 1.2 V, \r\n", 1, TokCompoundProgramHeader, 14, 1, PmutNewLine); +} + +int main() { + CU_pSuite pSuite = NULL; + + /* Initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + /* Add a suite to the registry */ + pSuite = CU_add_suite("Lexer", init_suite, clean_suite); + if (NULL == pSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Add the tests to the suite */ + if ((NULL == CU_add_test(pSuite, "WhiteSpace", testWhiteSpace)) + || (NULL == CU_add_test(pSuite, "Nondecimal", testNondecimal)) + || (NULL == CU_add_test(pSuite, "CharacterProgramData", testCharacterProgramData)) + || (NULL == CU_add_test(pSuite, "Decimal", testDecimal)) + || (NULL == CU_add_test(pSuite, "Suffix", testSuffix)) + || (NULL == CU_add_test(pSuite, "ProgramHeader", testProgramHeader)) + || (NULL == CU_add_test(pSuite, "ArbitraryBlock", testArbitraryBlock)) + || (NULL == CU_add_test(pSuite, "Expression", testExpression)) + || (NULL == CU_add_test(pSuite, "String", testString)) + || (NULL == CU_add_test(pSuite, "ProgramData", testProgramData)) + || (NULL == CU_add_test(pSuite, "AllProgramData", testAllProgramData)) + || (NULL == CU_add_test(pSuite, "DetectProgramMessageUnit", testDetectProgramMessageUnit)) + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + return CU_get_error(); +} + -- Gitblit v1.9.1