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