https://github.com/j123b567/scpi-parser

Dependents:   scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master

Files at this revision

API Documentation at this revision

Comitter:
dudmuck
Date:
Fri Aug 07 21:54:11 2015 +0000
Parent:
0:aad43948c45c
Commit message:
update from github commit 6e5e3e0e3fc450eaf53feee059824ad85c4f270d

Changed in this revision

inc/scpi/config.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/constants.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/debug.h Show diff for this revision Revisions of this file
inc/scpi/error.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/fifo.h Show diff for this revision Revisions of this file
inc/scpi/ieee488.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/minimal.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/parser.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/scpi.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/types.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/units.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/utils.h Show annotated file Show diff for this revision Revisions of this file
inc/scpi/utils_private.h Show diff for this revision Revisions of this file
src/error.c Show annotated file Show diff for this revision Revisions of this file
src/fifo.c Show annotated file Show diff for this revision Revisions of this file
src/fifo_private.h Show annotated file Show diff for this revision Revisions of this file
src/ieee488.c Show annotated file Show diff for this revision Revisions of this file
src/lexer.c Show annotated file Show diff for this revision Revisions of this file
src/lexer_private.h Show annotated file Show diff for this revision Revisions of this file
src/minimal.c Show annotated file Show diff for this revision Revisions of this file
src/parser.c Show annotated file Show diff for this revision Revisions of this file
src/parser_private.h Show annotated file Show diff for this revision Revisions of this file
src/units.c Show annotated file Show diff for this revision Revisions of this file
src/utils.c Show annotated file Show diff for this revision Revisions of this file
src/utils_private.h Show annotated file Show diff for this revision Revisions of this file
diff -r aad43948c45c -r b497f235115a inc/scpi/config.h
--- a/inc/scpi/config.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/config.h	Fri Aug 07 21:54:11 2015 +0000
@@ -2,7 +2,7 @@
  * Copyright (c) 2012-2013 Jan Breuer,
  *
  * All Rights Reserved
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
@@ -11,7 +11,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -28,10 +28,10 @@
 /**
  * @file   config.h
  * @date   Wed Mar 20 12:21:26 UTC 2013
- * 
+ *
  * @brief  SCPI Configuration
- * 
- * 
+ *
+ *
  */
 
 #ifndef __SCPI_CONFIG_H_
@@ -41,7 +41,54 @@
 extern "C" {
 #endif
 
+#ifdef SCPI_USER_CONFIG
+#include "scpi_user_config.h"
+#endif
+
+/* set the termination character(s)   */
+#define LINE_ENDING_CR          "\r"    /*   use a <CR> carriage return as termination charcter */
+#define LINE_ENDING_LF          "\n"    /*   use a <LF> line feed as termination charcter */
+#define LINE_ENDING_CRLF        "\r\n"  /*   use <CR><LF> carriage return + line feed as termination charcters */
+
+#ifndef SCPI_LINE_ENDING
+#define SCPI_LINE_ENDING        LINE_ENDING_CRLF
+#endif
+
+/* Enable full error list
+ * 0 = Minimal set of errors
+ * 1 = Full set of errors
+ *
+ * For small systems, full set of errors will occupy large ammount of data
+ */
+#ifndef USE_FULL_ERROR_LIST
+#define USE_FULL_ERROR_LIST 0
+#endif
+
+/**
+ * Enable also LIST_OF_USER_ERRORS to be included
+ * 0 = Use only library defined errors
+ * 1 = Use also LIST_OF_USER_ERRORS
+ */
+#ifndef USE_USER_ERROR_LIST
+#define USE_USER_ERROR_LIST 0
+#endif
+
 /* Compiler specific */
+/* RealView/Keil ARM Compiler, e.g. Cortex-M CPUs */
+#if defined(__CC_ARM)
+#define HAVE_STRNLEN            0
+#define HAVE_STRNCASECMP        1
+#define HAVE_STRNICMP           0
+#endif
+
+/* National Instruments (R) CVI x86/x64 PC platform */
+#if defined(_CVI_)
+#define HAVE_STRNLEN            0
+#define HAVE_STRNCASECMP        0
+#define HAVE_STRNICMP           1
+#define HAVE_STDBOOL            0
+#endif
+
 /* 8bit PIC - PIC16, etc */
 #if defined(_MPC_)
 #define HAVE_STRNLEN            0
@@ -63,6 +110,12 @@
 #define HAVE_STRNICMP           0
 #endif
 
+/* AVR libc */
+#if defined(__AVR__)
+#include <stdlib.h>
+#define HAVE_DTOSTRE            1
+#endif
+
 /* ======== test strnlen ======== */
 #ifndef HAVE_STRNLEN
 #define HAVE_STRNLEN            1
@@ -76,22 +129,33 @@
 #define HAVE_STRNICMP           0
 #endif
 
+#ifndef HAVE_STDBOOL
+#define HAVE_STDBOOL            1
+#endif
+
 /* define local macros depending on existance of strnlen */
 #if HAVE_STRNLEN
-#define SCPI_strnlen(s, l)  strnlen((s), (l))
+#define SCPIDEFINE_strnlen(s, l)    strnlen((s), (l))
 #else
-#define SCPI_strnlen(s, l)  BSD_strnlen((s), (l))
+#define SCPIDEFINE_strnlen(s, l)    BSD_strnlen((s), (l))
 #endif
 
 /* define local macros depending on existance of strncasecmp and strnicmp */
 #if HAVE_STRNCASECMP
-#define SCPI_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l))
+#define SCPIDEFINE_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l))
 #elif HAVE_STRNICMP
-#define SCPI_strncasecmp(s1, s2, l)     strnicmp((s1), (s2), (l))
+#define SCPIDEFINE_strncasecmp(s1, s2, l) strnicmp((s1), (s2), (l))
 #else
-#define SCPI_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l))
+#define SCPIDEFINE_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l))
 #endif
 
+#if HAVE_DTOSTRE
+#define SCPIDEFINE_doubleToStr(v, s, l) strlen(dtostre((v), (s), 6, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE))
+#else
+#define SCPIDEFINE_doubleToStr(v, s, l) snprintf((s), (l), "%lg", (v))
+#endif
+
+
 #ifdef  __cplusplus
 }
 #endif
diff -r aad43948c45c -r b497f235115a inc/scpi/constants.h
--- a/inc/scpi/constants.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/constants.h	Fri Aug 07 21:54:11 2015 +0000
@@ -61,4 +61,3 @@
 #endif
 
 #endif  /* SCPI_CONSTANTS_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/debug.h
--- a/inc/scpi/debug.h	Thu Apr 09 22:42:15 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*-
- * Copyright (c) 2012-2013 Jan Breuer,
- *
- * All Rights Reserved
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file   scpi_debug.h
- * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
- * @brief  SCPI debug function
- * 
- * 
- */
-
-#ifndef SCPI_DEBUG_H
-#define SCPI_DEBUG_H
-
-#include "scpi/types.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-
-    /* #define SCPI_DEBUG_COMMAND(a)   scpi_debug_command(a) */
-    #define SCPI_DEBUG_COMMAND(a)
-
-
-    scpi_bool_t SCPI_DebugCommand(scpi_t * context);
-
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif  /* SCPI_DEBUG_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/error.h
--- a/inc/scpi/error.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/error.h	Fri Aug 07 21:54:11 2015 +0000
@@ -37,9 +37,10 @@
 #ifndef SCPI_ERROR_H
 #define SCPI_ERROR_H
 
+#include "scpi/config.h"
 #include "scpi/types.h"
 
-#ifdef  __cplusplus
+#ifdef __cplusplus
 extern "C" {
 #endif
 
@@ -50,28 +51,153 @@
     int32_t SCPI_ErrorCount(scpi_t * context);
     const char * SCPI_ErrorTranslate(int16_t err);
 
-/* http://en.wikipedia.org/wiki/X_Macro */
+
+/* Using X-Macro technique to define everything once
+ * http://en.wikipedia.org/wiki/X_Macro
+ *
+ * X macro is for minimal set of errors for library itself
+ * XE macro is for full set of SCPI errors available to user application
+ */
 #define LIST_OF_ERRORS \
-    X(SCPI_ERROR_SYNTAX,               -102, "Syntax error")                   \
-    X(SCPI_ERROR_INVALID_SEPARATOR,    -103, "Invalid separator")              \
-    X(SCPI_ERROR_UNDEFINED_HEADER,     -113, "Undefined header")               \
-    X(SCPI_ERROR_PARAMETER_NOT_ALLOWED,-108, "Parameter not allowed")          \
-    X(SCPI_ERROR_MISSING_PARAMETER,    -109, "Missing parameter")              \
-    X(SCPI_ERROR_INVALID_SUFFIX,       -131, "Invalid suffix")                 \
-    X(SCPI_ERROR_SUFFIX_NOT_ALLOWED,   -138, "Suffix not allowed")             \
-    X(SCPI_ERROR_EXECUTION_ERROR,      -200, "Execution error")                \
-    X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE,-224,"Illegal parameter value")       \
-
+    XE(SCPI_ERROR_COMMAND,                      -100, "Command error")                                \
+    X(SCPI_ERROR_INVALID_CHARACTER,             -101, "Invalid character")                            \
+    XE(SCPI_ERROR_SYNTAX,                       -102, "Syntax error")                                 \
+    X(SCPI_ERROR_INVALID_SEPARATOR,             -103, "Invalid separator")                            \
+    X(SCPI_ERROR_DATA_TYPE_ERROR,               -104, "Data type error")                              \
+    XE(SCPI_ERROR_GET_NOT_ALLOWED,              -105, "GET not allowed")                              \
+    X(SCPI_ERROR_PARAMETER_NOT_ALLOWED,         -108, "Parameter not allowed")                        \
+    X(SCPI_ERROR_MISSING_PARAMETER,             -109, "Missing parameter")                            \
+    XE(SCPI_ERROR_COMMAND_HEADER,               -110, "Command header error")                         \
+    XE(SCPI_ERROR_HEADER_SEPARATOR,             -111, "Header separator error")                       \
+    XE(SCPI_ERROR_PRG_MNEMONIC_TOO_LONG,        -112, "Program mnemonic too long")                    \
+    X(SCPI_ERROR_UNDEFINED_HEADER,              -113, "Undefined header")                             \
+    XE(SCPI_ERROR_HEADER_SUFFIX_OUTOFRANGE,     -114, "Header suffix out of range")                   \
+    XE(SCPI_ERROR_UNEXP_NUM_OF_PARAMETER,       -115, "Unexpected number of parameters")              \
+    XE(SCPI_ERROR_NUMERIC_DATA_ERROR,           -120, "Numeric data error")                           \
+    XE(SCPI_ERROR_INVAL_CHAR_IN_NUMBER,         -121, "Invalid character in number")                  \
+    XE(SCPI_ERROR_EXPONENT_TOO_LONG,            -123, "Exponent too large")                           \
+    XE(SCPI_ERROR_TOO_MANY_DIGITS,              -124, "Too many digits")                              \
+    XE(SCPI_ERROR_NUMERIC_DATA_NOT_ALLOWED,     -128, "Numeric data not allowed")                     \
+    XE(SCPI_ERROR_SUFFIX_ERROR,                 -130, "Suffix error")                                 \
+    X(SCPI_ERROR_INVALID_SUFFIX,                -131, "Invalid suffix")                               \
+    XE(SCPI_ERROR_SUFFIX_TOO_LONG,              -134, "Suffix too long")                              \
+    X(SCPI_ERROR_SUFFIX_NOT_ALLOWED,            -138, "Suffix not allowed")                           \
+    XE(SCPI_ERROR_CHARACTER_DATA_ERROR,         -140, "Character data error")                         \
+    XE(SCPI_ERROR_INVAL_CHARACTER_DATA,         -141, "Invalid character data")                       \
+    XE(SCPI_ERROR_CHARACTER_DATA_TOO_LONG,      -144, "Character data too long")                      \
+    XE(SCPI_ERROR_CHARACTER_DATA_NOT_ALLOWED,   -148, "Character data not allowed")                   \
+    XE(SCPI_ERROR_STRING_DATA_ERROR,            -150, "String data error")                            \
+    X(SCPI_ERROR_INVALID_STRING_DATA,           -151, "Invalid string data")                          \
+    XE(SCPI_ERROR_STRING_DATA_NOT_ALLOWED,      -158, "String data not allowed")                      \
+    XE(SCPI_ERROR_BLOCK_DATA_ERROR,             -160, "Block data error")                             \
+    XE(SCPI_ERROR_INVALID_BLOCK_DATA,           -161, "Invalid block data")                           \
+    XE(SCPI_ERROR_BLOCK_DATA_NOT_ALLOWED,       -168, "Block data not allowed")                       \
+    XE(SCPI_ERROR_EXPRESSION_PARSING_ERROR,     -170, "Expression error")                             \
+    XE(SCPI_ERROR_INVAL_EXPRESSION,             -171, "Invalid expression")                           \
+    XE(SCPI_ERROR_EXPRESSION_DATA_NOT_ALLOWED,  -178, "Expression data not allowed")                  \
+    XE(SCPI_ERROR_MACRO_DEFINITION_ERROR,       -180, "Macro error")                                  \
+    XE(SCPI_ERROR_INVAL_OUTSIDE_MACRO_DEF,      -181, "Invalid outside macro definition")             \
+    XE(SCPI_ERROR_INVAL_INSIDE_MACRO_DEF,       -183, "Invalid inside macro definition")              \
+    XE(SCPI_ERROR_MACRO_PARAMETER_ERROR,        -184, "Macro parameter error")                        \
+    X(SCPI_ERROR_EXECUTION_ERROR,               -200, "Execution error")                              \
+    XE(SCPI_ERROR_INVAL_WHILE_IN_LOCAL,         -201, "Invalid while in local")                       \
+    XE(SCPI_ERROR_SETTINGS_LOST_DUE_TO_RTL,     -202, "Settings lost due to rtl")                     \
+    XE(SCPI_ERROR_COMMAND_PROTECTED,            -203, "Command protected TK024")                      \
+    XE(SCPI_ERROR_TRIGGER_ERROR,                -210, "Trigger error")                                \
+    XE(SCPI_ERROR_TRIGGER_IGNORED,              -211, "Trigger ignored")                              \
+    XE(SCPI_ERROR_ARM_IGNORED,                  -212, "Arm ignored")                                  \
+    XE(SCPI_ERROR_INIT_IGNORED,                 -213, "Init ignored")                                 \
+    XE(SCPI_ERROR_TRIGGER_DEADLOCK,             -214, "Trigger deadlock")                             \
+    XE(SCPI_ERROR_ARM_DEADLOCK,                 -215, "Arm deadlock")                                 \
+    XE(SCPI_ERROR_PARAMETER_ERROR,              -220, "Parameter error")                              \
+    XE(SCPI_ERROR_SETTINGS_CONFLICT,            -221, "Settings conflict")                            \
+    XE(SCPI_ERROR_DATA_OUT_OF_RANGE,            -222, "Data out of range")                            \
+    XE(SCPI_ERROR_TOO_MUCH_DATA,                -223, "Too much data")                                \
+    X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE,       -224, "Illegal parameter value")                      \
+    XE(SCPI_ERROR_OUT_OF_MEMORY_FOR_REQ_OP,     -225, "Out of memory")                                \
+    XE(SCPI_ERROR_LISTS_NOT_SAME_LENGTH,        -226, "Lists not same length")                        \
+    XE(SCPI_ERROR_DATA_CORRUPT,                 -230, "Data corrupt or stale")                        \
+    XE(SCPI_ERROR_DATA_QUESTIONABLE,            -231, "Data questionable")                            \
+    XE(SCPI_ERROR_INVAL_VERSION,                -233, "Invalid version")                              \
+    XE(SCPI_ERROR_HARDWARE_ERROR,               -240, "Hardware error")                               \
+    XE(SCPI_ERROR_HARDWARE_MISSING,             -241, "Hardware missing")                             \
+    XE(SCPI_ERROR_MASS_STORAGE_ERROR,           -250, "Mass storage error")                           \
+    XE(SCPI_ERROR_MISSING_MASS_STORAGE,         -251, "Missing mass storage")                         \
+    XE(SCPI_ERROR_MISSING_MASS_MEDIA,           -252, "Missing media")                                \
+    XE(SCPI_ERROR_CORRUPT_MEDIA,                -253, "Corrupt media")                                \
+    XE(SCPI_ERROR_MEDIA_FULL,                   -254, "Media full")                                   \
+    XE(SCPI_ERROR_DIRECTORY_FULL,               -255, "Directory full")                               \
+    XE(SCPI_ERROR_FILE_NAME_NOT_FOUND,          -256, "File name not found")                          \
+    XE(SCPI_ERROR_FILE_NAME_ERROR,              -257, "File name error")                              \
+    XE(SCPI_ERROR_MEDIA_PROTECTED,              -258, "Media protected")                              \
+    XE(SCPI_ERROR_EXPRESSION_EXECUTING_ERROR,   -260, "Expression error")                             \
+    XE(SCPI_ERROR_MATH_ERROR_IN_EXPRESSION,     -261, "Math error in expression")                     \
+    XE(SCPI_ERROR_MACRO_UNDEF_EXEC_ERROR,       -270, "Macro error")                                  \
+    XE(SCPI_ERROR_MACRO_SYNTAX_ERROR,           -271, "Macro syntax error")                           \
+    XE(SCPI_ERROR_MACRO_EXECUTION_ERROR,        -272, "Macro execution error")                        \
+    XE(SCPI_ERROR_ILLEGAL_MACRO_LABEL,          -273, "Illegal macro label")                          \
+    XE(SCPI_ERROR_IMPROPER_USED_MACRO_PARAM,    -274, "Macro parameter error")                        \
+    XE(SCPI_ERROR_MACRO_DEFINITION_TOO_LONG,    -275, "Macro definition too long")                    \
+    XE(SCPI_ERROR_MACRO_RECURSION_ERROR,        -276, "Macro recursion error")                        \
+    XE(SCPI_ERROR_MACRO_REDEF_NOT_ALLOWED,      -277, "Macro redefinition not allowed")               \
+    XE(SCPI_ERROR_MACRO_HEADER_NOT_FOUND,       -278, "Macro header not found")                       \
+    XE(SCPI_ERROR_PROGRAM_ERROR,                -280, "Program error")                                \
+    XE(SCPI_ERROR_CANNOT_CREATE_PROGRAM,        -281, "Cannot create program")                        \
+    XE(SCPI_ERROR_ILLEGAL_PROGRAM_NAME,         -282, "Illegal program name")                         \
+    XE(SCPI_ERROR_ILLEGAL_VARIABLE_NAME,        -283, "Illegal variable name")                        \
+    XE(SCPI_ERROR_PROGRAM_CURRENTLY_RUNNING,    -284, "Program currently running")                    \
+    XE(SCPI_ERROR_PROGRAM_SYNTAX_ERROR,         -285, "Program syntax error")                         \
+    XE(SCPI_ERROR_PROGRAM_RUNTIME_ERROR,        -286, "Program runtime error")                        \
+    XE(SCPI_ERROR_MEMORY_USE_ERROR,             -290, "Memory use error")                             \
+    XE(SCPI_ERROR_OUT_OF_MEMORY,                -291, "Out of memory")                                \
+    XE(SCPI_ERROR_REF_NAME_DOES_NOT_EXIST,      -292, "Referenced name does not exist")               \
+    XE(SCPI_ERROR_REF_NAME_ALREADY_EXISTS,      -293, "Referenced name already exists")               \
+    XE(SCPI_ERROR_INCOMPATIBLE_TYPE,            -294, "Incompatible type")                            \
+    XE(SCPI_ERROR_DEVICE_ERROR,                 -300, "Device specific error")                        \
+    X(SCPI_ERROR_SYSTEM_ERROR,                  -310, "System error")                                 \
+    XE(SCPI_ERROR_MEMORY_ERROR,                 -311, "Memory error")                                 \
+    XE(SCPI_ERROR_PUD_MEMORY_LOST,              -312, "PUD memory lost")                              \
+    XE(SCPI_ERROR_CALIBRATION_MEMORY_LOST,      -313, "Calibration memory lost")                      \
+    XE(SCPI_ERROR_SAVE_RECALL_MEMORY_LOST,      -314, "Save/recall memory lost")                      \
+    XE(SCPI_ERROR_CONFIGURATION_MEMORY_LOST,    -315, "Configuration memory lost")                    \
+    XE(SCPI_ERROR_STORAGE_FAULT,                -320, "Storage fault")                                \
+    XE(SCPI_ERROR_OUT_OF_DEVICE_MEMORY,         -321, "Out of memory")                                \
+    XE(SCPI_ERROR_SELF_TEST_FAILED,             -330, "Self-test failed")                             \
+    XE(SCPI_ERROR_CALIBRATION_FAILED,           -340, "Calibration failed")                           \
+    XE(SCPI_ERROR_QUEUE_OVERFLOW,               -350, "Queue overflow")                               \
+    XE(SCPI_ERROR_COMMUNICATION_ERROR,          -360, "Communication error")                          \
+    XE(SCPI_ERROR_PARITY_ERROR_IN_CMD_MSG,      -361, "Parity error in program message")              \
+    XE(SCPI_ERROR_FRAMING_ERROR_IN_CMD_MSG,     -362, "Framing error in program message")             \
+    XE(SCPI_ERROR_INPUT_BUFFER_OVERRUN,         -363, "Input buffer overrun")                         \
+    XE(SCPI_ERROR_TIME_OUT,                     -365, "Time out error")                               \
+    XE(SCPI_ERROR_QUERY_ERROR,                  -400, "Query error")                                  \
+    XE(SCPI_ERROR_QUERY_INTERRUPTED,            -410, "Query INTERRUPTED")                            \
+    XE(SCPI_ERROR_QUERY_UNTERMINATED,           -420, "Query UNTERMINATED")                           \
+    XE(SCPI_ERROR_QUERY_DEADLOCKED,             -430, "Query DEADLOCKED")                             \
+    XE(SCPI_ERROR_QUERY_UNTERM_INDEF_RESP,      -440, "Query UNTERMINATED after indefinite response") \
+    XE(SCPI_ERROR_POWER_ON,                     -500, "Power on")                                     \
+    XE(SCPI_ERROR_USER_REQUEST,                 -600, "User request")                                 \
+    XE(SCPI_ERROR_REQUEST_CONTROL,              -700, "Request control")                              \
+    XE(SCPI_ERROR_OPERATION_COMPLETE,           -800, "Operation complete")                           \
 
 enum {
 #define X(def, val, str) def = val,
+#if USE_FULL_ERROR_LIST
+#define XE X
+#else
+#define XE(def, val, str)
+#endif
 LIST_OF_ERRORS
+
+#if USE_USER_ERROR_LIST
+LIST_OF_USER_ERRORS
+#endif
 #undef X
+#undef XE
 };
 
-#ifdef  __cplusplus
+#ifdef __cplusplus
 }
 #endif
 
-#endif  /* SCPI_ERROR_H */
-
+#endif /* SCPI_ERROR_H */
diff -r aad43948c45c -r b497f235115a inc/scpi/fifo.h
--- a/inc/scpi/fifo.h	Thu Apr 09 22:42:15 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*-
- * Copyright (c) 2012-2013 Jan Breuer,
- *
- * All Rights Reserved
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file   scpi_fifo.h
- * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
- * @brief  basic FIFO implementation
- * 
- * 
- */
-
-#ifndef SCPI_FIFO_H
-#define SCPI_FIFO_H
-
-#include "scpi/types.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-
-#define FIFO_SIZE 16
-
-    struct _fifo_t {
-        int16_t wr;
-        int16_t rd;
-        int16_t size;
-        int16_t data[FIFO_SIZE];
-    };
-    typedef struct _fifo_t fifo_t;
-
-    void fifo_init(fifo_t * fifo);
-    void fifo_clear(fifo_t * fifo);
-    scpi_bool_t fifo_add(fifo_t * fifo, int16_t value);
-    scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value);
-    scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value);
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif  /* SCPI_FIFO_H */
diff -r aad43948c45c -r b497f235115a inc/scpi/ieee488.h
--- a/inc/scpi/ieee488.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/ieee488.h	Fri Aug 07 21:54:11 2015 +0000
@@ -82,6 +82,7 @@
 void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val);
 void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
 void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
+
 void SCPI_EventClear(scpi_t * context);
 
 #ifdef  __cplusplus
diff -r aad43948c45c -r b497f235115a inc/scpi/minimal.h
--- a/inc/scpi/minimal.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/minimal.h	Fri Aug 07 21:54:11 2015 +0000
@@ -60,4 +60,3 @@
 #endif
 
 #endif  /* SCPI_MINIMAL_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/parser.h
--- a/inc/scpi/parser.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/parser.h	Fri Aug 07 21:54:11 2015 +0000
@@ -37,37 +37,51 @@
 #ifndef SCPI_PARSER_H
 #define SCPI_PARSER_H
 
+#include <string.h>
 #include "scpi/types.h"
-#include "scpi/debug.h"
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
-
     void SCPI_Init(scpi_t * context);
 
-    int SCPI_Input(scpi_t * context, const char * data, size_t len);
-    int SCPI_Parse(scpi_t * context, char * data, size_t len);
+    int SCPI_Input(scpi_t * context, const char * data, int len);
+    int SCPI_Parse(scpi_t * context, char * data, int len);
+
 
-    scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd);
-
-    size_t SCPI_ResultString(scpi_t * context, const char * data);
+    size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len);
+#define SCPI_ResultMnemonic(context, data) SCPI_ResultCharacters((context), (data), strlen(data))
     size_t SCPI_ResultInt(scpi_t * context, int32_t val);
+    size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base);
     size_t SCPI_ResultDouble(scpi_t * context, double val);
     size_t SCPI_ResultText(scpi_t * context, const char * data);
+    size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len);
     size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val);
+   
+    scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed);
+    scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value);
+    scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value);
+    scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value);
+    scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text);
+
 
     scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory);
     scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory);
-    scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
-    scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);    
+    scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory);
+
     scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory);
-    scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory);
+    scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory);
 
+    scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd);
+    int32_t SCPI_CmdTag(scpi_t * context);
+    scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len);
+    scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len);
 
 #ifdef  __cplusplus
 }
 #endif
 
 #endif  /* SCPI_PARSER_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/scpi.h
--- a/inc/scpi/scpi.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/scpi.h	Fri Aug 07 21:54:11 2015 +0000
@@ -43,8 +43,8 @@
 #include "scpi/constants.h"
 #include "scpi/minimal.h"
 #include "scpi/units.h"
+#include "scpi/utils.h"
 
 
 
 #endif  /* SCPI_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/types.h
--- a/inc/scpi/types.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/types.h	Fri Aug 07 21:54:11 2015 +0000
@@ -4,7 +4,7 @@
  * Copyright (c) 2012 Jan Breuer
  *
  * All Rights Reserved
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
@@ -13,7 +13,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -30,10 +30,10 @@
 /**
  * @file   scpi_types.h
  * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
+ *
  * @brief  SCPI data types
- * 
- * 
+ *
+ *
  */
 
 #ifndef SCPI_TYPES_H
@@ -41,12 +41,20 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include "scpi/config.h"
+
+#if HAVE_STDBOOL
 #include <stdbool.h>
+#endif
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
+#if !HAVE_STDBOOL
+   typedef unsigned char bool;
+#endif
+
 #ifndef FALSE
     #define FALSE 0
 #endif
@@ -61,13 +69,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
@@ -76,21 +84,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;
 
@@ -105,37 +113,90 @@
 
     typedef struct _scpi_command_t scpi_command_t;
 
+#define SCPI_CMD_LIST_END       {NULL, NULL, 0}
+
+    /* scpi interface */
+    typedef struct _scpi_t scpi_t;
+    typedef struct _scpi_interface_t scpi_interface_t;
+
     struct _scpi_buffer_t {
         size_t length;
         size_t position;
         char * data;
     };
     typedef struct _scpi_buffer_t scpi_buffer_t;
-    
+
     struct _scpi_const_buffer_t {
         size_t length;
         size_t position;
         const char * data;
     };
-    typedef struct _scpi_const_buffer_t scpi_const_buffer_t;    
-
-    struct _scpi_param_list_t {
-        const scpi_command_t * cmd;
-        const char * parameters;
-        size_t length;
-        scpi_const_buffer_t cmd_raw;
-    };
-    #define SCPI_CMD_LIST_END       {NULL, NULL, }
-    typedef struct _scpi_param_list_t scpi_param_list_t;
-
-    /* scpi interface */
-    typedef struct _scpi_t scpi_t;
-    typedef struct _scpi_interface_t scpi_interface_t;
+    typedef struct _scpi_const_buffer_t scpi_const_buffer_t;
 
     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 _scpi_token_type_t {
+        SCPI_TOKEN_COMMA,
+        SCPI_TOKEN_SEMICOLON,
+        SCPI_TOKEN_QUESTION,
+        SCPI_TOKEN_NL,
+        SCPI_TOKEN_HEXNUM,
+        SCPI_TOKEN_OCTNUM,
+        SCPI_TOKEN_BINNUM,
+        SCPI_TOKEN_PROGRAM_MNEMONIC,
+        SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA,
+        SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX,
+        SCPI_TOKEN_SUFFIX_PROGRAM_DATA,
+        SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA,
+        SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA,
+        SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA,
+        SCPI_TOKEN_PROGRAM_EXPRESSION,
+        SCPI_TOKEN_COMPOUND_PROGRAM_HEADER,
+        SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER,
+        SCPI_TOKEN_COMMON_PROGRAM_HEADER,
+        SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER,
+        SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER,
+        SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER,
+        SCPI_TOKEN_WS,
+        SCPI_TOKEN_ALL_PROGRAM_DATA,
+        SCPI_TOKEN_INVALID,
+        SCPI_TOKEN_UNKNOWN,
+    };
+    typedef enum _scpi_token_type_t scpi_token_type_t;
+
+    struct _scpi_token_t {
+        scpi_token_type_t type;
+        char * ptr;
+        int len;
+    };
+    typedef struct _scpi_token_t scpi_token_t;
+
+    struct _lex_state_t {
+        char * buffer;
+        char * pos;
+        int len;
+    };
+    typedef struct _lex_state_t lex_state_t;
+
+    /* scpi parser */
+    enum _message_termination_t {
+        SCPI_MESSAGE_TERMINATION_NONE,
+        SCPI_MESSAGE_TERMINATION_NL,
+        SCPI_MESSAGE_TERMINATION_SEMICOLON,
+    };
+    typedef enum _message_termination_t message_termination_t;
+
+    struct _scpi_parser_state_t {
+        scpi_token_t programHeader;
+        scpi_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 *);
 
     /* scpi error queue */
@@ -159,7 +220,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 {
@@ -176,23 +237,43 @@
     };
     typedef enum _scpi_special_number_t scpi_special_number_t;
 
-    struct _scpi_special_number_def_t {
+    struct _scpi_choice_def_t {
         const char * name;
-        scpi_special_number_t type;
+        int32_t tag;
     };
-    #define SCPI_SPECIAL_NUMBERS_LIST_END   {NULL, SCPI_NUM_NUMBER}    
-    typedef struct _scpi_special_number_def_t scpi_special_number_def_t;
+#define SCPI_CHOICE_LIST_END   {NULL, -1}
+    typedef struct _scpi_choice_def_t scpi_choice_def_t;
+
+    struct _scpi_param_list_t {
+        const scpi_command_t * cmd;
+        lex_state_t lex_state;
+        scpi_const_buffer_t cmd_raw;
+    };
+    typedef struct _scpi_param_list_t scpi_param_list_t;
 
-    struct _scpi_number_t {
-        double value;
+    struct _scpi_number_parameter_t {
+        scpi_bool_t special;
+        union {
+            double value;
+            int32_t tag;
+        };
         scpi_unit_t unit;
-        scpi_special_number_t type;
+        int8_t base;
     };
-    typedef struct _scpi_number_t scpi_number_t;
+    typedef struct _scpi_number_parameter_t scpi_number_t;
+
+    struct _scpi_data_parameter_t {
+        const char * ptr;
+        int32_t len;
+    };
+    typedef struct _scpi_data_parameter_t scpi_data_parameter_t;
+
+    typedef scpi_token_t scpi_parameter_t;
 
     struct _scpi_command_t {
         const char * pattern;
         scpi_command_callback_t callback;
+        int32_t tag;
     };
 
     struct _scpi_interface_t {
@@ -201,13 +282,12 @@
         scpi_write_control_t control;
         scpi_command_callback_t flush;
         scpi_command_callback_t reset;
-        scpi_command_callback_t test;
     };
 
     struct _scpi_t {
         const scpi_command_t * cmdlist;
         scpi_buffer_t buffer;
-        scpi_param_list_t paramlist;
+        scpi_param_list_t param_list;
         scpi_interface_t * interface;
         int_fast16_t output_count;
         int_fast16_t input_count;
@@ -215,8 +295,8 @@
         scpi_error_queue_t error_queue;
         scpi_reg_val_t * registers;
         const scpi_unit_def_t * units;
-        const scpi_special_number_def_t * special_numbers;
         void * user_context;
+        scpi_parser_state_t parser_state;
         const char * idn[4];
     };
 
@@ -225,4 +305,3 @@
 #endif
 
 #endif  /* SCPI_TYPES_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/units.h
--- a/inc/scpi/units.h	Thu Apr 09 22:42:15 2015 +0000
+++ b/inc/scpi/units.h	Fri Aug 07 21:54:11 2015 +0000
@@ -44,14 +44,15 @@
 #endif
 
     extern const scpi_unit_def_t scpi_units_def[];
-    extern const scpi_special_number_def_t scpi_special_numbers_def[];
-    
-    scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory);
-    size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len);
+    extern const scpi_choice_def_t scpi_special_numbers_def[];
+
+    scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory);
+
+    scpi_bool_t SCPI_ParamTranslateNumberVal(scpi_t * context, scpi_parameter_t * parameter);
+    size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len);
 
 #ifdef  __cplusplus
 }
 #endif
 
 #endif  /* SCPI_UNITS_H */
-
diff -r aad43948c45c -r b497f235115a inc/scpi/utils.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/scpi/utils.h	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2012-2015 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   utils.h
+ * 
+ * @brief  Conversion routines and string manipulation routines
+ * 
+ * 
+ */
+
+#ifndef SCPI_UTILS_H
+#define SCPI_UTILS_H
+
+#include <stdint.h>
+#include "scpi/types.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+    size_t SCPI_LongToStr(int32_t val, char * str, size_t len, int8_t base);
+    size_t SCPI_DoubleToStr(double val, char * str, size_t len);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_UTILS_H */
diff -r aad43948c45c -r b497f235115a inc/scpi/utils_private.h
--- a/inc/scpi/utils_private.h	Thu Apr 09 22:42:15 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*-
- * Copyright (c) 2012-2013 Jan Breuer,
- *
- * All Rights Reserved
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file   scpi_utils.h
- * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
- * @brief  Conversion routines and string manipulation routines
- * 
- * 
- */
-
-#ifndef SCPI_UTILS_H
-#define SCPI_UTILS_H
-
-#include <stdint.h>
-#include "scpi/config.h"
-#include "scpi/types.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#if defined(__GNUC__) && (__GNUC__ >= 4)
-    #define LOCAL __attribute__((visibility ("hidden")))
-#else
-    #define LOCAL
-#endif
-
-    const char * strnpbrk(const char *str, size_t size, const char *set) LOCAL;
-    scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
-    scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
-    size_t longToStr(int32_t val, char * str, size_t len) LOCAL;
-    size_t doubleToStr(double val, char * str, size_t len) LOCAL;
-    size_t strToLong(const char * str, int32_t * val) LOCAL;
-    size_t strToDouble(const char * str, double * val) LOCAL;
-    scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
-    scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
-    size_t skipWhitespace(const char * cmd, size_t len) LOCAL;
-    size_t skipColon(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(char * ptr_prev, size_t len_prev, char ** pptr, size_t * plen);
-
-#if !HAVE_STRNLEN
-    size_t BSD_strnlen(const char *s, size_t maxlen);
-#endif
-
-#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
-    int OUR_strncasecmp(const char *s1, const char *s2, size_t n);
-#endif
-
-#define min(a, b)  (((a) < (b)) ? (a) : (b))
-#define max(a, b)  (((a) > (b)) ? (a) : (b))
-
-#if 0
-#define max(a,b) \
-   ({ __typeof__ (a) _a = (a); \
-       __typeof__ (b) _b = (b); \
-     _a > _b ? _a : _b; })
-
-#define min(a,b) \
-   ({ __typeof__ (a) _a = (a); \
-       __typeof__ (b) _b = (b); \
-     _a < _b ? _a : _b; })
-
-#endif
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif  /* SCPI_UTILS_H */
-
diff -r aad43948c45c -r b497f235115a src/error.c
--- a/src/error.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/error.c	Fri Aug 07 21:54:11 2015 +0000
@@ -2,7 +2,7 @@
  * Copyright (c) 2012-2013 Jan Breuer,
  *
  * All Rights Reserved
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
@@ -11,7 +11,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -28,10 +28,10 @@
 /**
  * @file   scpi_error.c
  * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
+ *
  * @brief  Error handling and storing routines
- * 
- * 
+ *
+ *
  */
 
 #include <stdint.h>
@@ -39,13 +39,16 @@
 #include "scpi/parser.h"
 #include "scpi/ieee488.h"
 #include "scpi/error.h"
-#include "scpi/fifo.h"
+#include "fifo_private.h"
 
 /* basic FIFO */
-static fifo_t local_error_queue;
+static scpi_fifo_t local_error_queue;
 
 
-
+/**
+ * Initialize error queue
+ * @param context - scpi context
+ */
 void SCPI_ErrorInit(scpi_t * context) {
     /*
      * // FreeRTOS
@@ -54,7 +57,34 @@
 
     /* basic FIFO */
     context->error_queue = (scpi_error_queue_t)&local_error_queue;
-    fifo_init((fifo_t *)context->error_queue);
+    fifo_init((scpi_fifo_t *)context->error_queue);
+}
+
+/**
+ * Emit no error
+ * @param context scpi context
+ */
+static void SCPI_ErrorEmitEmpty(scpi_t * context) {
+    if ((SCPI_ErrorCount(context) == 0) && (SCPI_RegGet(context, SCPI_REG_STB) & STB_QMA)) {
+        SCPI_RegClearBits(context, SCPI_REG_STB, STB_QMA);
+
+        if (context->interface && context->interface->error) {
+            context->interface->error(context, 0);
+        }
+    }
+}
+
+/**
+ * Emit error
+ * @param context scpi context
+ * @param err Error to emit
+ */
+static void SCPI_ErrorEmit(scpi_t * context, int16_t err) {
+    SCPI_RegSetBits(context, SCPI_REG_STB, STB_QMA);
+
+    if (context->interface && context->interface->error) {
+        context->interface->error(context, err);
+    }
 }
 
 /**
@@ -68,7 +98,9 @@
      */
 
     /* basic FIFO */
-    fifo_clear((fifo_t *)context->error_queue);
+    fifo_clear((scpi_fifo_t *)context->error_queue);
+
+    SCPI_ErrorEmitEmpty(context);
 }
 
 /**
@@ -87,7 +119,9 @@
      */
 
     /* basic FIFO */
-    fifo_remove((fifo_t *)context->error_queue, &result);
+    fifo_remove((scpi_fifo_t *)context->error_queue, &result);
+
+    SCPI_ErrorEmitEmpty(context);
 
     return result;
 }
@@ -95,7 +129,7 @@
 /**
  * Return number of errors/events in the queue
  * @param context
- * @return 
+ * @return
  */
 int32_t SCPI_ErrorCount(scpi_t * context) {
     int16_t result = 0;
@@ -106,7 +140,7 @@
      */
 
     /* basic FIFO */
-    fifo_count((fifo_t *)context->error_queue, &result);
+    fifo_count((scpi_fifo_t *)context->error_queue, &result);
 
     return result;
 }
@@ -118,7 +152,7 @@
      */
 
     /* basic FIFO */
-    fifo_add((fifo_t *)context->error_queue, err);
+    fifo_add((scpi_fifo_t *)context->error_queue, err);
 }
 
 struct error_reg {
@@ -127,12 +161,13 @@
     scpi_reg_val_t bit;
 };
 
-#define ERROR_DEFS_N    8
+#define ERROR_DEFS_N    9
 
 static const struct error_reg errs[ERROR_DEFS_N] = {
     {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9    */
     {-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10  */
     {-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11    */
+    {   1,32767, ESR_DER}, /* Device designer provided specific error 1, 32767 ch 21.8.11    */
     {-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12              */
     {-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13           */
     {-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14       */
@@ -157,11 +192,9 @@
         }
     }
 
+    SCPI_ErrorEmit(context, err);
+
     if (context) {
-        if (context->interface && context->interface->error) {
-            context->interface->error(context, err);
-        }
-
         context->cmd_error = TRUE;
     }
 }
@@ -174,11 +207,19 @@
 const char * SCPI_ErrorTranslate(int16_t err) {
     switch (err) {
         case 0: return "No error";
-        #define X(def, val, str) case def: return str;
-        LIST_OF_ERRORS
-        #undef X        
+#define X(def, val, str) case def: return str;
+#if USE_FULL_ERROR_LIST
+#define XE X
+#else
+#define XE(def, val, str)
+#endif
+LIST_OF_ERRORS
+
+#if USE_USER_ERROR_LIST
+LIST_OF_USER_ERRORS
+#endif
+#undef X
+#undef XE
         default: return "Unknown error";
     }
 }
-
-
diff -r aad43948c45c -r b497f235115a src/fifo.c
--- a/src/fifo.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/fifo.c	Fri Aug 07 21:54:11 2015 +0000
@@ -1,18 +1,32 @@
 
-#include "scpi/fifo.h"
+#include "fifo_private.h"
 
-void fifo_init(fifo_t * fifo) {
+/**
+ * Initialize fifo
+ * @param fifo
+ */
+void fifo_init(scpi_fifo_t * fifo) {
     fifo->wr = 0;
     fifo->rd = 0;
     fifo->size = FIFO_SIZE;
 }
 
-void fifo_clear(fifo_t * fifo) {
+/**
+ * Empty fifo
+ * @param fifo
+ */
+void fifo_clear(scpi_fifo_t * fifo) {
     fifo->wr = 0;
     fifo->rd = 0;
 }
 
-scpi_bool_t fifo_add(fifo_t * fifo, int16_t value) {
+/**
+ * Add element to fifo. If fifo is full, remove last element.
+ * @param fifo
+ * @param value
+ * @return 
+ */
+scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) {
     /* FIFO full? */
     if (fifo->wr == ((fifo->rd + fifo->size) % (fifo->size + 1))) {
         fifo_remove(fifo, NULL);
@@ -24,7 +38,13 @@
     return TRUE;
 }
 
-scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value) {
+/**
+ * Remove element form fifo
+ * @param fifo
+ * @param value
+ * @return FALSE - fifo is empty
+ */
+scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) {
     /* FIFO empty? */
     if (fifo->wr == fifo->rd) {
         return FALSE;
@@ -39,7 +59,13 @@
     return TRUE;
 }
 
-scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value) {
+/**
+ * Retrive number of elements in fifo
+ * @param fifo
+ * @param value
+ * @return 
+ */
+scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) {
     *value = fifo->wr - fifo->rd;
     if (*value < 0) {
         *value += (fifo->size + 1);
diff -r aad43948c45c -r b497f235115a src/fifo_private.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fifo_private.h	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2012-2013 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   scpi_fifo.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  basic FIFO implementation
+ * 
+ * 
+ */
+
+#ifndef SCPI_FIFO_H
+#define SCPI_FIFO_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#define FIFO_SIZE 16
+
+    struct _scpi_fifo_t {
+        int16_t wr;
+        int16_t rd;
+        int16_t size;
+        int16_t data[FIFO_SIZE];
+    };
+    typedef struct _scpi_fifo_t scpi_fifo_t;
+
+    void fifo_init(scpi_fifo_t * fifo) LOCAL;
+    void fifo_clear(scpi_fifo_t * fifo) LOCAL;
+    scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) LOCAL;
+    scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) LOCAL;
+    scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) LOCAL;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_FIFO_H */
diff -r aad43948c45c -r b497f235115a src/ieee488.c
--- a/src/ieee488.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/ieee488.c	Fri Aug 07 21:54:11 2015 +0000
@@ -212,7 +212,7 @@
 scpi_result_t SCPI_CoreEse(scpi_t * context) {
     int32_t new_ESE;
     if (SCPI_ParamInt(context, &new_ESE, TRUE)) {
-        SCPI_RegSet(context, SCPI_REG_ESE, new_ESE);
+        SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t)new_ESE);
     }
     return SCPI_RES_OK;
 }
@@ -250,10 +250,14 @@
  * @return 
  */
 scpi_result_t SCPI_CoreIdnQ(scpi_t * context) {
-    SCPI_ResultString(context, context->idn[0]);
-    SCPI_ResultString(context, context->idn[1]);
-    SCPI_ResultString(context, context->idn[2]);
-    SCPI_ResultString(context, context->idn[3]);
+    int i;
+    for (i = 0; i<4; i++) {
+        if (context->idn[i]) {
+            SCPI_ResultMnemonic(context, context->idn[i]);
+        } else {
+            SCPI_ResultMnemonic(context, "0");
+        }
+    }
     return SCPI_RES_OK;
 }
 
@@ -298,7 +302,7 @@
 scpi_result_t SCPI_CoreSre(scpi_t * context) {
     int32_t new_SRE;
     if (SCPI_ParamInt(context, &new_SRE, TRUE)) {
-        SCPI_RegSet(context, SCPI_REG_SRE, new_SRE);
+        SCPI_RegSet(context, SCPI_REG_SRE, (scpi_reg_val_t)new_SRE);
     }
     return SCPI_RES_OK;
 }
@@ -329,11 +333,8 @@
  * @return 
  */
 scpi_result_t SCPI_CoreTstQ(scpi_t * context) {
-    int result = 0;
-    if (context && context->interface && context->interface->test) {
-        result = context->interface->test(context);
-    }
-    SCPI_ResultInt(context, result);
+    (void) context;
+    SCPI_ResultInt(context, 0);
     return SCPI_RES_OK;
 }
 
@@ -347,4 +348,3 @@
     /* NOP */
     return SCPI_RES_OK;
 }
-
diff -r aad43948c45c -r b497f235115a src/lexer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lexer.c	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,890 @@
+/*-
+ * Copyright (c) 2012-2013 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   lexer.c
+ * @date   Wed Mar 20 19:35:19 UTC 2013
+ * 
+ * @brief  SCPI Lexer
+ * 
+ * 
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "lexer_private.h"
+#include "scpi/error.h"
+
+/**
+ * Is white space
+ * @param c
+ * @return 
+ */
+static int isws(int c) {
+    if ((c == ' ') || (c == '\t')) {
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * Is binary digit
+ * @param c
+ * @return 
+ */
+static int isbdigit(int c) {
+    if ((c == '0') || (c == '1')) {
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * Is hexadecimal digit
+ * @param c
+ * @return 
+ */
+static int isqdigit(int c) {
+    if ((c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7')) {
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * Is end of string
+ * @param state
+ * @return 
+ */
+static int iseos(lex_state_t * state) {
+    if ((state->buffer + state->len) <= (state->pos)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * Private export of iseos
+ * @param state
+ * @return 
+ */
+int scpiLex_IsEos(lex_state_t * state) {
+    return iseos(state);
+}
+
+/**
+ * Test current character
+ * @param state
+ * @param chr
+ * @return 
+ */
+static int ischr(lex_state_t * state, char chr) {
+    return (state->pos[0] == chr);
+}
+
+/**
+ * Is plus or minus
+ * @param c
+ * @return 
+ */
+static int isplusmn(int c) {
+    return c == '+' || c == '-';
+}
+
+/**
+ * Is letter H
+ * @param c
+ * @return 
+ */
+static int isH(int c) {
+    return c == 'h' || c == 'H';
+}
+
+/**
+ * Is letter B
+ * @param c
+ * @return 
+ */
+static int isB(int c) {
+    return c == 'b' || c == 'B';
+}
+
+/**
+ * Is letter Q
+ * @param c
+ * @return 
+ */
+static int isQ(int c) {
+    return c == 'q' || c == 'Q';
+}
+
+/**
+ * Is letter E
+ * @param c
+ * @return 
+ */
+static int isE(int c) {
+    return c == 'e' || c == 'E';
+}
+
+#define SKIP_NONE       0
+#define SKIP_OK         1
+#define SKIP_INCOMPLETE -1
+
+/* skip characters */
+/* 7.4.1 <PROGRAM MESSAGE UNIT SEPARATOR>*/
+// TODO: static int skipProgramMessageUnitSeparator(lex_state_t * state)
+
+/**
+ * Skip all whitespaces
+ * @param state
+ * @return 
+ */
+static int skipWs(lex_state_t * state) {
+    int someSpace = 0;
+    while (!iseos(state) && isws(state->pos[0])) {
+        state->pos++;
+        someSpace++;
+    }
+
+    return someSpace;
+}
+
+/* 7.4.2 <PROGRAM DATA SEPARATOR> */
+// static int skipProgramDataSeparator(lex_state_t * state)
+
+/* 7.5.2 <PROGRAM MESSAGE TERMINATOR> */
+// static int skipProgramMessageTerminator(lex_state_t * state)
+
+/**
+ * Skip decimal digit
+ * @param state
+ * @return 
+ */
+static int skipDigit(lex_state_t * state) {
+    if (!iseos(state) && isdigit(state->pos[0])) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Skip multiple decimal digits
+ * @param state
+ * @return 
+ */
+static int skipNumbers(lex_state_t * state) {
+    int someNumbers = 0;
+    while (!iseos(state) && isdigit(state->pos[0])) {
+        state->pos++;
+        someNumbers++;
+    }
+    return someNumbers;
+}
+
+/**
+ * Skip plus or minus
+ * @param state
+ * @return 
+ */
+static int skipPlusmn(lex_state_t * state) {
+    if (!iseos(state) && isplusmn(state->pos[0])) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Skip any character from 'a'-'Z'
+ * @param state
+ * @return 
+ */
+static int skipAlpha(lex_state_t * state) {
+    int someLetters = 0;
+    while (!iseos(state) && isalpha(state->pos[0])) {
+        state->pos++;
+        someLetters++;
+    }
+    return someLetters;
+}
+
+/**
+ * Skip exact character chr or nothing
+ * @param state
+ * @param chr
+ * @return 
+ */
+static int skipChr(lex_state_t * state, char chr) {
+    if (!iseos(state) && ischr(state, chr)) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Skip slash or dot
+ * @param state
+ * @return 
+ */
+static int skipSlashDot(lex_state_t * state) {
+    if (!iseos(state) && (ischr(state, '/') | ischr(state, '.'))) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Skip star
+ * @param state
+ * @return 
+ */
+static int skipStar(lex_state_t * state) {
+    if (!iseos(state) && ischr(state, '*')) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Skip colon
+ * @param state
+ * @return 
+ */
+static int skipColon(lex_state_t * state) {
+    if (!iseos(state) && ischr(state, ':')) {
+        state->pos++;
+        return SKIP_OK;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/* 7.6.1.2 <COMMAND PROGRAM HEADER> */
+
+/**
+ * Skip program mnemonic [a-z][a-z0-9_]*
+ * @param state
+ * @return 
+ */
+static int skipProgramMnemonic(lex_state_t * state) {
+    const char * startPos = state->pos;
+    if (!iseos(state) && isalpha(state->pos[0])) {
+        state->pos++;
+        while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) {
+            state->pos++;
+        }
+    }
+
+    if (iseos(state)) {
+        return (state->pos - startPos) * SKIP_INCOMPLETE;
+    } else {
+        return (state->pos - startPos) * SKIP_OK;
+    }
+}
+
+/* tokens */
+
+/**
+ * Detect token white space
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    skipWs(state);
+
+    token->len = state->pos - token->ptr;
+
+    if (token->len > 0) {
+        token->type = SCPI_TOKEN_WS;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+    }
+
+    return token->len;
+}
+
+/* 7.6.1 <COMMAND PROGRAM HEADER> */
+
+/**
+ * Skip command program header \*<PROGRAM MNEMONIC>
+ * @param state
+ * @return 
+ */
+static int skipCommonProgramHeader(lex_state_t * state) {
+    int res;
+    if (skipStar(state)) {
+        res = skipProgramMnemonic(state);
+        if (res == SKIP_NONE && iseos(state)) {
+            return SKIP_INCOMPLETE;
+        } else if (res <= SKIP_INCOMPLETE) {
+            return SKIP_OK;
+        } else if (res >= SKIP_OK) {
+            return SKIP_OK;
+        } else {
+            return SKIP_INCOMPLETE;
+        }
+    }
+    return SKIP_NONE;
+}
+
+/**
+ * Skip compound program header :<PROGRAM MNEMONIC>:<PROGRAM MNEMONIC>...
+ * @param state
+ * @return 
+ */
+static int skipCompoundProgramHeader(lex_state_t * state) {
+    int res;
+    int firstColon = skipColon(state);
+
+    res = skipProgramMnemonic(state);
+    if (res >= SKIP_OK) {
+        while (skipColon(state)) {
+            res = skipProgramMnemonic(state);
+            if (res <= SKIP_INCOMPLETE) {
+                return SKIP_OK;
+            } else if (res == SKIP_NONE) {
+                return SKIP_INCOMPLETE;
+            }
+        }
+        return SKIP_OK;
+    } else if (res <= SKIP_INCOMPLETE) {
+        return SKIP_OK;
+    } else if (firstColon) {
+        return SKIP_INCOMPLETE;
+    } else {
+        return SKIP_NONE;
+    }
+}
+
+/**
+ * Detect token command or compound program header
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) {
+    int res;
+    token->ptr = state->pos;
+    token->type = SCPI_TOKEN_UNKNOWN;
+
+    res = skipCommonProgramHeader(state);
+    if (res >= SKIP_OK) {
+        if (skipChr(state, '?') >= SKIP_OK) {
+            token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER;
+        } else {
+            token->type = SCPI_TOKEN_COMMON_PROGRAM_HEADER;
+        }
+    } else if (res <= SKIP_INCOMPLETE) {
+        token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER;
+    } else if (res == SKIP_NONE) {
+        res = skipCompoundProgramHeader(state);
+
+        if (res >= SKIP_OK) {
+            if (skipChr(state, '?') >= SKIP_OK) {
+                token->type = SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER;
+            } else {
+                token->type = SCPI_TOKEN_COMPOUND_PROGRAM_HEADER;
+            }
+        } else if (res <= SKIP_INCOMPLETE) {
+            token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER;
+        }
+    }
+
+    if (token->type != SCPI_TOKEN_UNKNOWN) {
+        token->len = state->pos - token->ptr;
+    } else {
+        token->len = 0;
+        state->pos = token->ptr;
+    }
+
+    return token->len;
+}
+
+/* 7.7.1 <CHARACTER PROGRAM DATA> */
+
+/**
+ * Detect token "Character program data"
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    if (!iseos(state) && isalpha(state->pos[0])) {
+        state->pos++;
+        while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) {
+            state->pos++;
+        }
+    }
+
+    token->len = state->pos - token->ptr;
+    if (token->len > 0) {
+        token->type = SCPI_TOKEN_PROGRAM_MNEMONIC;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+    }
+
+    return token->len;
+}
+
+/* 7.7.2 <DECIMAL NUMERIC PROGRAM DATA> */
+static int skipMantisa(lex_state_t * state) {
+    int someNumbers = 0;
+
+    skipPlusmn(state);
+
+    someNumbers += skipNumbers(state);
+
+    if (skipChr(state, '.')) {
+        someNumbers += skipNumbers(state);
+    }
+
+    return someNumbers;
+}
+
+static int skipExponent(lex_state_t * state) {
+    int someNumbers = 0;
+
+    if (!iseos(state) && isE(state->pos[0])) {
+        state->pos++;
+
+        skipWs(state);
+
+        skipPlusmn(state);
+
+        someNumbers = skipNumbers(state);
+    }
+
+    return someNumbers;
+}
+
+/**
+ * Detect token Decimal number
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) {
+    char * rollback;
+    token->ptr = state->pos;
+
+    if (skipMantisa(state)) {
+        rollback = state->pos;
+        skipWs(state);
+        if (!skipExponent(state)) {
+            state->pos = rollback;
+        }
+    } else {
+        state->pos = token->ptr;
+    }
+
+    token->len = state->pos - token->ptr;
+    if (token->len > 0) {
+        token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+    }
+
+    return token->len;
+}
+
+/* 7.7.3 <SUFFIX PROGRAM DATA> */
+int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    skipChr(state, '/');
+
+    // TODO: strict parsing  : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))*
+    if (skipAlpha(state)) {
+        skipChr(state, '-');
+        skipDigit(state);
+
+        while (skipSlashDot(state)) {
+            skipAlpha(state);
+            skipChr(state, '-');
+            skipDigit(state);
+        }
+    }
+
+    token->len = state->pos - token->ptr;
+    if ((token->len > 0)) {
+        token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+
+    return token->len;
+}
+
+/* 7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA> */
+static int skipHexNum(lex_state_t * state) {
+    int someNumbers = 0;
+    while (!iseos(state) && isxdigit(state->pos[0])) {
+        state->pos++;
+        someNumbers++;
+    }
+    return someNumbers;
+}
+
+static int skipOctNum(lex_state_t * state) {
+    int someNumbers = 0;
+    while (!iseos(state) && isqdigit(state->pos[0])) {
+        state->pos++;
+        someNumbers++;
+    }
+    return someNumbers;
+}
+
+static int skipBinNum(lex_state_t * state) {
+    int someNumbers = 0;
+    while (!iseos(state) && isbdigit(state->pos[0])) {
+        state->pos++;
+        someNumbers++;
+    }
+    return someNumbers;
+}
+
+/**
+ * Detect token nondecimal number
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) {
+    int someNumbers = 0;
+    token->ptr = state->pos;
+    if (skipChr(state, '#')) {
+        if (!iseos(state)) {
+            if (isH(state->pos[0])) {
+                state->pos++;
+                someNumbers = skipHexNum(state);
+                token->type = SCPI_TOKEN_HEXNUM;
+            } else if (isQ(state->pos[0])) {
+                state->pos++;
+                someNumbers = skipOctNum(state);
+                token->type = SCPI_TOKEN_OCTNUM;
+            } else if (isB(state->pos[0])) {
+                state->pos++;
+                someNumbers = skipBinNum(state);
+                token->type = SCPI_TOKEN_BINNUM;
+            }
+        }
+    }
+
+    if (someNumbers) {
+        token->ptr += 2; // ignore number prefix
+        token->len = state->pos - token->ptr;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+    return token->len > 0 ? token->len + 2 : 0;
+}
+
+/* 7.7.5 <STRING PROGRAM DATA> */
+static int isascii7bit(int c) {
+    return (c >= 0) && (c <= 0x7f);
+}
+
+static void skipQuoteProgramData(lex_state_t * state, char quote) {
+    while (!iseos(state)) {
+        if (isascii7bit(state->pos[0]) && !ischr(state, quote)) {
+            state->pos++;
+        } else if (ischr(state, quote)) {
+            state->pos++;
+            if (!iseos(state) && ischr(state, quote)) {
+                state->pos++;
+            } else {
+                state->pos--;
+                break;
+            }
+        }
+    }
+}
+
+static void skipDoubleQuoteProgramData(lex_state_t * state) {
+    skipQuoteProgramData(state, '"');
+}
+
+static void skipSingleQuoteProgramData(lex_state_t * state) {
+    skipQuoteProgramData(state, '\'');
+}
+
+/**
+ * Detect token String data
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    if (!iseos(state)) {
+        if (ischr(state, '"')) {
+            state->pos++;
+            token->type = SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA;
+            skipDoubleQuoteProgramData(state);
+            if (!iseos(state) && ischr(state, '"')) {
+                state->pos++;
+                token->len = state->pos - token->ptr;
+            } else {
+                state->pos = token->ptr;
+            }
+        } else if (ischr(state, '\'')) {
+            state->pos++;
+            token->type = SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA;
+            skipSingleQuoteProgramData(state);
+            if (!iseos(state) && ischr(state, '\'')) {
+                state->pos++;
+                token->len = state->pos - token->ptr;
+            } else {
+                state->pos = token->ptr;
+            }
+        }
+    }
+
+    token->len = state->pos - token->ptr;
+
+    if ((token->len > 0)) {
+        token->ptr++;
+        token->len -= 2;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+
+    return token->len > 0 ? token->len + 2 : 0;
+}
+
+/* 7.7.6 <ARBITRARY BLOCK PROGRAM DATA> */
+static int isNonzeroDigit(int c) {
+    return isdigit(c) && (c != '0');
+}
+
+/**
+ * Detect token Block Data
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) {
+    int i;
+    int arbitraryBlockLength = 0;
+    const char * ptr = state->pos;
+    int validData = -1;
+    token->ptr = state->pos;
+
+    if (skipChr(state, '#')) {
+        if (!iseos(state) && isNonzeroDigit(state->pos[0])) {
+            /* Get number of digits */
+            i = state->pos[0] - '0';
+            state->pos++;
+
+            for (; i > 0; i--) {
+                if (!iseos(state) && isdigit(state->pos[0])) {
+                    arbitraryBlockLength *= 10;
+                    arbitraryBlockLength += (state->pos[0] - '0');
+                    state->pos++;
+                } else {
+                    break;
+                }
+            }
+
+            if (i == 0) {
+                state->pos += arbitraryBlockLength;
+                if ((state->buffer + state->len) >= (state->pos)) {
+                    token->ptr = state->pos - arbitraryBlockLength;
+                    token->len = arbitraryBlockLength;
+                    validData = 1;
+                }
+            } else if (iseos(state)) {
+                validData = 0;
+            }
+        } else if (iseos(state)) {
+            validData = 0;
+        }
+    }
+
+    if (validData == 1) {
+        // valid
+        token->type = SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA;
+    } else if (validData == 0) {
+        // incomplete
+        token->type = SCPI_TOKEN_UNKNOWN;
+        token->len = 0;
+        state->pos = state->buffer + state->len;
+    } else {
+        // invalid
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+
+    return token->len + (token->ptr - ptr);
+}
+
+/* 7.7.7 <EXPRESSION PROGRAM DATA> */
+static int isProgramExpression(int c) {
+    if ((c >= 0x20) && (c <= 0x7e)) {
+        if ((c != 0x22)
+                && (c != 0x23)
+                && (c != 0x27)
+                && (c != 0x28)
+                && (c != 0x29)
+                && (c != 0x3B)) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void skipProgramExpression(lex_state_t * state) {
+    while (!iseos(state) && isProgramExpression(state->pos[0])) {
+        state->pos++;
+    }
+}
+
+// TODO: 7.7.7.2-2 recursive - any program data
+
+/**
+ * Detect token Expression
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    if (!iseos(state) && ischr(state, '(')) {
+        state->pos++;
+        skipProgramExpression(state);
+
+        if (!iseos(state) && ischr(state, ')')) {
+            state->pos++;
+            token->len = state->pos - token->ptr;
+        } else {
+            token->len = 0;
+        }
+    }
+
+    if ((token->len > 0)) {
+        token->type = SCPI_TOKEN_PROGRAM_EXPRESSION;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+
+    return token->len;
+}
+
+/**
+ * Detect token comma
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    if (skipChr(state, ',')) {
+        token->len = 1;
+        token->type = SCPI_TOKEN_COMMA;
+    } else {
+        token->len = 0;
+        token->type = SCPI_TOKEN_UNKNOWN;
+    }
+
+    return token->len;
+}
+
+/**
+ * Detect token semicolon
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    if (skipChr(state, ';')) {
+        token->len = 1;
+        token->type = SCPI_TOKEN_SEMICOLON;
+    } else {
+        token->len = 0;
+        token->type = SCPI_TOKEN_UNKNOWN;
+    }
+
+    return token->len;
+}
+
+/**
+ * Detect token New line
+ * @param state
+ * @param token
+ * @return 
+ */
+int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) {
+    token->ptr = state->pos;
+
+    skipChr(state, '\r');
+    skipChr(state, '\n');
+
+    token->len = state->pos - token->ptr;
+
+    if ((token->len > 0)) {
+        token->type = SCPI_TOKEN_NL;
+    } else {
+        token->type = SCPI_TOKEN_UNKNOWN;
+        state->pos = token->ptr;
+        token->len = 0;
+    }
+
+    return token->len;
+}
diff -r aad43948c45c -r b497f235115a src/lexer_private.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lexer_private.h	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2012-2013 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   lexer.h
+ * @date   Thu Mar 21 15:00:58 UTC 2013
+ * 
+ * @brief  SCPI Lexer
+ * 
+ * 
+ */
+
+#ifndef SCPI_LEXER_H
+#define SCPI_LEXER_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+    int scpiLex_IsEos(lex_state_t * state) LOCAL;
+    int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) LOCAL;
+    int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) LOCAL;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_LEXER_H */
diff -r aad43948c45c -r b497f235115a src/minimal.c
--- a/src/minimal.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/minimal.c	Fri Aug 07 21:54:11 2015 +0000
@@ -57,7 +57,7 @@
  * @return 
  */
 scpi_result_t SCPI_StubQ(scpi_t * context) {
-    SCPI_ResultString(context, "");
+    SCPI_ResultInt(context, 0);
     return SCPI_RES_OK;
 }
 
@@ -67,7 +67,7 @@
  * @return 
  */
 scpi_result_t SCPI_SystemVersionQ(scpi_t * context) {
-    SCPI_ResultString(context, SCPI_STD_VERSION_REVISION);
+    SCPI_ResultMnemonic(context, SCPI_STD_VERSION_REVISION);
     return SCPI_RES_OK;
 }
 
@@ -131,7 +131,7 @@
 scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) {
     int32_t new_QUESE;
     if (SCPI_ParamInt(context, &new_QUESE, TRUE)) {
-        SCPI_RegSet(context, SCPI_REG_QUESE, new_QUESE);
+        SCPI_RegSet(context, SCPI_REG_QUESE, (scpi_reg_val_t)new_QUESE);
     }
     return SCPI_RES_OK;
 }
diff -r aad43948c45c -r b497f235115a src/parser.c
--- a/src/parser.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/parser.c	Fri Aug 07 21:54:11 2015 +0000
@@ -2,7 +2,7 @@
  * Copyright (c) 2012-2013 Jan Breuer,
  *
  * All Rights Reserved
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
@@ -11,7 +11,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -28,10 +28,10 @@
 /**
  * @file   scpi_parser.c
  * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
+ *
  * @brief  SCPI parser implementation
- * 
- * 
+ *
+ *
  */
 
 #include <ctype.h>
@@ -39,103 +39,11 @@
 
 #include "scpi/config.h"
 #include "scpi/parser.h"
-#include "scpi/utils_private.h"
+#include "parser_private.h"
+#include "lexer_private.h"
 #include "scpi/error.h"
 #include "scpi/constants.h"
-
-
-static size_t cmdTerminatorPos(const char * cmd, size_t len);
-static size_t cmdlineSeparatorPos(const char * cmd, size_t len);
-static const char * cmdlineSeparator(const char * cmd, size_t len);
-static const char * cmdlineTerminator(const char * cmd, size_t len);
-static size_t skipCmdLine(const char * cmd, size_t len);
-
-static void paramSkipBytes(scpi_t * context, size_t num);
-static void paramSkipWhitespace(scpi_t * context);
-static scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory);
-
-/*
-int _strnicmp(const char* s1, const char* s2, size_t len) {
-    int result = 0;
-    int i;
-
-    for (i = 0; i < len && s1[i] && s2[i]; i++) {
-        char c1 = tolower(s1[i]);
-        char c2 = tolower(s2[i]);
-        if (c1 != c2) {
-            result = (int) c1 - (int) c2;
-            break;
-        }
-    }
-
-    return result;
-}
- */
-
-/**
- * Find command termination character
- * @param cmd - input command
- * @param len - max search length
- * @return position of terminator or len
- */
-size_t cmdTerminatorPos(const char * cmd, size_t len) {
-    const char * terminator = strnpbrk(cmd, len, "; \r\n\t");
-    if (terminator == NULL) {
-        return len;
-    } else {
-        return terminator - cmd;
-    }
-}
-
-/**
- * Find command line separator
- * @param cmd - input command
- * @param len - max search length
- * @return pointer to line separator or NULL
- */
-const char * cmdlineSeparator(const char * cmd, size_t len) {
-    return strnpbrk(cmd, len, ";\r\n");
-}
-
-/**
- * Find command line terminator
- * @param cmd - input command
- * @param len - max search length
- * @return pointer to command line terminator or NULL
- */
-const char * cmdlineTerminator(const char * cmd, size_t len) {
-    return strnpbrk(cmd, len, "\r\n");
-}
-
-/**
- * Find command line separator position
- * @param cmd - input command
- * @param len - max search length
- * @return position of line separator or len
- */
-size_t cmdlineSeparatorPos(const char * cmd, size_t len) {
-    const char * separator = cmdlineSeparator(cmd, len);
-    if (separator == NULL) {
-        return len;
-    } else {
-        return separator - cmd;
-    }
-}
-
-/**
- * Find next part of command
- * @param cmd - input command
- * @param len - max search length
- * @return number of characters to be skipped
- */
-size_t skipCmdLine(const char * cmd, size_t len) {
-    const char * separator = cmdlineSeparator(cmd, len);
-    if (separator == NULL) {
-        return len;
-    } else {
-        return separator + 1 - cmd;
-    }
-}
+#include "scpi/utils.h"
 
 /**
  * Write data to SCPI output
@@ -168,7 +76,7 @@
  */
 static size_t writeDelimiter(scpi_t * context) {
     if (context->output_count > 0) {
-        return writeData(context, ", ", 2);
+        return writeData(context, ",", 1);
     } else {
         return 0;
     }
@@ -182,7 +90,10 @@
 static size_t writeNewLine(scpi_t * context) {
     if (context->output_count > 0) {
         size_t len;
-        len = writeData(context, "\r\n", 2);
+#ifndef SCPI_LINE_ENDING
+#error no termination character defined
+#endif
+        len = writeData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING));
         flushData(context);
         return len;
     } else {
@@ -191,17 +102,33 @@
 }
 
 /**
+ * Conditionaly write ";"
+ * @param context
+ * @return number of characters written
+ */
+static size_t writeSemicolon(scpi_t * context) {
+    if (context->output_count > 0) {
+        return writeData(context, ";", 1);
+    } else {
+        return 0;
+    }
+}
+
+/**
  * Process command
  * @param context
  */
 static void processCommand(scpi_t * context) {
-    const scpi_command_t * cmd = context->paramlist.cmd;
+    const scpi_command_t * cmd = context->param_list.cmd;
+    lex_state_t * state = &context->param_list.lex_state;
+
+    /* conditionaly write ; */
+    writeSemicolon(context);
 
     context->cmd_error = FALSE;
     context->output_count = 0;
     context->input_count = 0;
 
-    SCPI_DEBUG_COMMAND(context);
     /* if callback exists - call command callback */
     if (cmd->callback != NULL) {
         if ((cmd->callback(context) != SCPI_RES_OK) && !context->cmd_error) {
@@ -209,14 +136,8 @@
         }
     }
 
-    /* conditionaly write new line */
-    writeNewLine(context);
-
-    /* skip all whitespaces */
-    paramSkipWhitespace(context);
-
     /* set error if command callback did not read all parameters */
-    if (context->paramlist.length != 0 && !context->cmd_error) {
+    if (state->pos < (state->buffer + state->len) && !context->cmd_error) {
         SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED);
     }
 }
@@ -226,19 +147,14 @@
  * @param context
  * @result TRUE if context->paramlist is filled with correct values
  */
-static scpi_bool_t findCommand(scpi_t * context, const char * cmdline_ptr, size_t cmdline_len, size_t cmd_len) {
+static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) {
     int32_t i;
     const scpi_command_t * cmd;
 
     for (i = 0; context->cmdlist[i].pattern != NULL; i++) {
         cmd = &context->cmdlist[i];
-        if (matchCommand(cmd->pattern, cmdline_ptr, cmd_len)) {
-            context->paramlist.cmd = cmd;
-            context->paramlist.parameters = cmdline_ptr + cmd_len;
-            context->paramlist.length = cmdline_len - cmd_len;
-            context->paramlist.cmd_raw.data = cmdline_ptr;
-            context->paramlist.cmd_raw.length = cmd_len;
-            context->paramlist.cmd_raw.position = 0;
+        if (matchCommand(cmd->pattern, header, len, NULL, 0)) {
+            context->param_list.cmd = cmd;
             return TRUE;
         }
     }
@@ -252,38 +168,60 @@
  * @param len - command line length
  * @return 1 if the last evaluated command was found
  */
-int SCPI_Parse(scpi_t * context, char * data, size_t len) {
+int SCPI_Parse(scpi_t * context, char * data, int len) {
     int result = 0;
-    const char * cmdline_end = data + len;
-    char * cmdline_ptr = data;
-    size_t cmd_len;
-    size_t cmdline_len;
-    char * cmdline_ptr_prev = NULL;
-    size_t cmd_len_prev = 0;
+    scpi_parser_state_t * state;
+    int r;
+    scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0};
 
     if (context == NULL) {
         return -1;
     }
 
-    while (cmdline_ptr < cmdline_end) {
+    state = &context->parser_state;
+    context->output_count = 0;
+
+    while (1) {
         result = 0;
-        cmd_len = cmdTerminatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
-        if (cmd_len > 0) {
-            composeCompoundCommand(cmdline_ptr_prev, cmd_len_prev,
-                                    &cmdline_ptr, &cmd_len);
-            cmdline_len = cmdlineSeparatorPos(cmdline_ptr, cmdline_end - cmdline_ptr);
-            if(findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) {
+
+        r = scpiParser_detectProgramMessageUnit(state, data, len);
+
+        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;
+                context->param_list.lex_state.pos = context->param_list.lex_state.buffer;
+                context->param_list.lex_state.len = state->programData.len;
+                context->param_list.cmd_raw.data = state->programHeader.ptr;
+                context->param_list.cmd_raw.position = 0;
+                context->param_list.cmd_raw.length = state->programHeader.len;
+
                 processCommand(context);
+
                 result = 1;
-                cmdline_ptr_prev = cmdline_ptr;
-                cmd_len_prev = cmd_len;
+                cmd_prev = state->programHeader;
             } else {
                 SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
             }
         }
-        cmdline_ptr += skipCmdLine(cmdline_ptr, cmdline_end - cmdline_ptr);
-        cmdline_ptr += skipWhitespace(cmdline_ptr, cmdline_end - cmdline_ptr);
+
+        if (r < len) {
+            data += r;
+            len -= r;
+        } else {
+            break;
+        }
+
     }
+
+    /* conditionaly write new line */
+    writeNewLine(context);
+
     return result;
 }
 
@@ -307,7 +245,7 @@
     if (context->idn[3] == NULL) {
         context->idn[3] = SCPI_DEFAULT_4_REVISION;
     }
-    
+
     context->buffer.position = 0;
     SCPI_ErrorInit(context);
 }
@@ -316,22 +254,24 @@
  * Interface to the application. Adds data to system buffer and try to search
  * command line termination. If the termination is found or if len=0, command
  * parser is called.
- * 
+ *
  * @param context
  * @param data - data to process
  * @param len - length of data
- * @return 
+ * @return
  */
-int SCPI_Input(scpi_t * context, const char * data, size_t len) {
+int SCPI_Input(scpi_t * context, const char * data, int len) {
     int result = 0;
-    const char * cmd_term;
+    size_t totcmdlen = 0;
+    int cmdlen = 0;
+
     if (len == 0) {
         context->buffer.data[context->buffer.position] = 0;
         result = SCPI_Parse(context, context->buffer.data, context->buffer.position);
         context->buffer.position = 0;
     } else {
-        size_t buffer_free;
-        int ws;
+        int buffer_free;
+
         buffer_free = context->buffer.length - context->buffer.position;
         if (len > (buffer_free - 1)) {
             return -1;
@@ -340,16 +280,20 @@
         context->buffer.position += len;
         context->buffer.data[context->buffer.position] = 0;
 
-        ws = skipWhitespace(context->buffer.data, context->buffer.position);
-        cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
-        while (cmd_term != NULL) {
-            int curr_len = cmd_term - context->buffer.data;
-            result = SCPI_Parse(context, context->buffer.data + ws, curr_len - ws);
-            memmove(context->buffer.data, cmd_term, context->buffer.position - curr_len);
-            context->buffer.position -= curr_len;
-    
-            ws = skipWhitespace(context->buffer.data, context->buffer.position);
-            cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws);
+
+        while (1) {
+            cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
+            totcmdlen += cmdlen;
+
+            if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) {
+                result = SCPI_Parse(context, context->buffer.data, totcmdlen);
+                memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
+                context->buffer.position -= totcmdlen;
+                totcmdlen = 0;
+            } else {
+                if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN) break;
+                if (totcmdlen >= context->buffer.position) break;
+            }
         }
     }
 
@@ -362,10 +306,9 @@
  * Write raw string result to the output
  * @param context
  * @param data
- * @return 
+ * @return
  */
-size_t SCPI_ResultString(scpi_t * context, const char * data) {
-    size_t len = strlen(data);
+size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len) {
     size_t result = 0;
     result += writeDelimiter(context);
     result += writeData(context, data, len);
@@ -377,38 +320,61 @@
  * Write integer value to the result
  * @param context
  * @param val
- * @return 
+ * @return
  */
 size_t SCPI_ResultInt(scpi_t * context, int32_t val) {
-    char buffer[12];
+    return SCPI_ResultIntBase(context, val, 10);
+}
+
+/**
+ * Return prefix of nondecimal base
+ * @param base
+ * @return
+ */
+static const char * getBasePrefix(int8_t base) {
+    switch (base) {
+        case 2: return "#B";
+        case 8: return "#Q";
+        case 16: return "#H";
+        default: return NULL;
+    }
+}
+
+/**
+ * Write integer value in specific base to the result
+ * @param context
+ * @param val
+ * @param base
+ * @return
+ */
+size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base) {
+    char buffer[33];
+    const char * basePrefix;
     size_t result = 0;
-    size_t len = longToStr(val, buffer, sizeof (buffer));
+    size_t len;
+
+    len = SCPI_LongToStr(val, buffer, sizeof (buffer), base);
+    basePrefix = getBasePrefix(base);
+
     result += writeDelimiter(context);
+    if (basePrefix != NULL) {
+        result += writeData(context, basePrefix, 2);
+    }
     result += writeData(context, buffer, len);
     context->output_count++;
     return result;
 }
 
 /**
- * Write boolean value to the result
- * @param context
- * @param val
- * @return 
- */
-size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) {
-    return SCPI_ResultInt(context, val ? 1 : 0);
-}
-
-/**
  * Write double walue to the result
  * @param context
  * @param val
- * @return 
+ * @return
  */
 size_t SCPI_ResultDouble(scpi_t * context, double val) {
     char buffer[32];
     size_t result = 0;
-    size_t len = doubleToStr(val, buffer, sizeof (buffer));
+    size_t len = SCPI_DoubleToStr(val, buffer, sizeof (buffer));
     result += writeDelimiter(context);
     result += writeData(context, buffer, len);
     context->output_count++;
@@ -420,266 +386,661 @@
  * Write string withn " to the result
  * @param context
  * @param data
- * @return 
+ * @return
  */
 size_t SCPI_ResultText(scpi_t * context, const char * data) {
     size_t result = 0;
     result += writeDelimiter(context);
     result += writeData(context, "\"", 1);
+    // TODO: convert " to ""
     result += writeData(context, data, strlen(data));
     result += writeData(context, "\"", 1);
     context->output_count++;
     return result;
 }
 
-/* parsing parameters */
-
 /**
- * Skip num bytes from the begginig of parameters
+ * Write arbitrary block program data to the result
  * @param context
- * @param num
+ * @param data
+ * @param len
+ * @return
  */
-void paramSkipBytes(scpi_t * context, size_t num) {
-    if (context->paramlist.length < num) {
-        num = context->paramlist.length;
-    }
-    context->paramlist.parameters += num;
-    context->paramlist.length -= num;
+size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len) {
+    size_t result = 0;
+    char block_header[12];
+    size_t header_len;
+    block_header[0] = '#';
+    SCPI_LongToStr(len, block_header + 2, 10, 10);
+
+    header_len = strlen(block_header + 2);
+    block_header[1] = (char)(header_len + '0');
+
+    result += writeData(context, block_header, header_len + 2);
+    result += writeData(context, data, len);
+
+    context->output_count++;
+    return result;
 }
 
 /**
- * Skip white spaces from the beggining of parameters
+ * Write boolean value to the result
  * @param context
+ * @param val
+ * @return
  */
-void paramSkipWhitespace(scpi_t * context) {
-    size_t ws = skipWhitespace(context->paramlist.parameters, context->paramlist.length);
-    paramSkipBytes(context, ws);
+size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) {
+    return SCPI_ResultIntBase(context, val ? 1 : 0, 10);
+}
+
+/* parsing parameters */
+
+/**
+ * Invalidate token
+ * @param token
+ * @param ptr
+ */
+static void invalidateToken(scpi_token_t * token, char * ptr) {
+    token->len = 0;
+    token->ptr = ptr;
+    token->type = SCPI_TOKEN_UNKNOWN;
 }
 
 /**
- * Find next parameter
+ * Get one parameter from command line
  * @param context
+ * @param parameter
  * @param mandatory
- * @return 
+ * @return
  */
-scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory) {
-    paramSkipWhitespace(context);
-    if (context->paramlist.length == 0) {
+scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) {
+    lex_state_t * state;
+
+    if (!parameter) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+        return FALSE;
+    }
+
+    invalidateToken(parameter, NULL);
+
+    state = &context->param_list.lex_state;
+
+    if (state->pos >= (state->buffer + state->len)) {
         if (mandatory) {
             SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER);
+        } else {
+            parameter->type = SCPI_TOKEN_PROGRAM_MNEMONIC; // TODO: select something different
         }
         return FALSE;
     }
     if (context->input_count != 0) {
-        if (context->paramlist.parameters[0] == ',') {
-            paramSkipBytes(context, 1);
-            paramSkipWhitespace(context);
-        } else {
+        scpiLex_Comma(state, parameter);
+        if (parameter->type != SCPI_TOKEN_COMMA) {
+            invalidateToken(parameter, NULL);
             SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR);
             return FALSE;
         }
     }
+
     context->input_count++;
-    return TRUE;
+
+    scpiParser_parseProgramData(&context->param_list.lex_state, parameter);
+
+    switch (parameter->type) {
+        case SCPI_TOKEN_HEXNUM:
+        case SCPI_TOKEN_OCTNUM:
+        case SCPI_TOKEN_BINNUM:
+        case SCPI_TOKEN_PROGRAM_MNEMONIC:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+        case SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA:
+        case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA:
+        case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA:
+        case SCPI_TOKEN_PROGRAM_EXPRESSION:
+            return TRUE;
+        default:
+            invalidateToken(parameter, NULL);
+            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_STRING_DATA);
+            return FALSE;
+    }
+}
+
+/**
+ * Detect if parameter is number
+ * @param parameter
+ * @param suffixAllowed
+ * @return
+ */
+scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed) {
+    switch (parameter->type) {
+        case SCPI_TOKEN_HEXNUM:
+        case SCPI_TOKEN_OCTNUM:
+        case SCPI_TOKEN_BINNUM:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+            return TRUE;
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+            return suffixAllowed;
+        default:
+            return FALSE;
+    }
 }
 
 /**
- * Parse integer parameter
+ * Convert parameter to integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value) {
+
+    if (!value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+        return FALSE;
+    }
+
+    switch (parameter->type) {
+        case SCPI_TOKEN_HEXNUM:
+            return strToLong(parameter->ptr, value, 16) > 0 ? TRUE : FALSE;
+        case SCPI_TOKEN_OCTNUM:
+            return strToLong(parameter->ptr, value, 8) > 0 ? TRUE : FALSE;
+        case SCPI_TOKEN_BINNUM:
+            return strToLong(parameter->ptr, value, 2) > 0 ? TRUE : FALSE;
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+            return strToLong(parameter->ptr, value, 10) > 0 ? TRUE : FALSE;
+    }
+    return FALSE;
+}
+
+/**
+ * Convert parameter to double
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value) {
+    scpi_bool_t result = FALSE;
+    int32_t valint;
+
+    if (!value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+        return FALSE;
+    }
+
+    switch (parameter->type) {
+        case SCPI_TOKEN_HEXNUM:
+        case SCPI_TOKEN_OCTNUM:
+        case SCPI_TOKEN_BINNUM:
+            result = SCPI_ParamToInt(context, parameter, &valint);
+            *value = valint;
+            break;
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+            result = strToDouble(parameter->ptr, value) > 0 ? TRUE : FALSE;
+            break;
+    }
+    return result;
+}
+
+/**
+ * Read floating point parameter
  * @param context
  * @param value
  * @param mandatory
- * @return 
+ * @return
  */
-scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
-    const char * param;
-    size_t param_len;
-    size_t num_len;
+scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
 
     if (!value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
-        return FALSE;
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+        if (SCPI_ParamIsNumber(&param, FALSE)) {
+            SCPI_ParamToDouble(context, &param, value);
+        } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+            SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+            result = FALSE;
+        } else {
+            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+            result = FALSE;
+        }
     }
-
-    num_len = strToLong(param, value);
-
-    if (num_len != param_len) {
-        SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
-        return FALSE;
-    }
-
-    return TRUE;
+    return result;
 }
 
 /**
- * Parse double parameter
+ * Read integer parameter
  * @param context
  * @param value
  * @param mandatory
- * @return 
+ * @return
  */
-scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
-    const char * param;
-    size_t param_len;
-    size_t num_len;
+scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
 
     if (!value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+        if (SCPI_ParamIsNumber(&param, FALSE)) {
+            SCPI_ParamToInt(context, &param, value);
+        } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+            SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+            result = FALSE;
+        } else {
+            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+            result = FALSE;
+        }
+    }
+    return result;
+}
+
+/**
+ * Read character parameter
+ * @param context
+ * @param value
+ * @param len
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
+
+    if (!value || !len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    num_len = strToDouble(param, value);
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+        *value = param.ptr;
+        *len = param.len;
 
-    if (num_len != param_len) {
-        SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
-        return FALSE;
+        // TODO: return also parameter type (ProgramMnemonic, ArbitraryBlockProgramData, SingleQuoteProgramData, DoubleQuoteProgramData
     }
 
-    return TRUE;
+    return result;
 }
 
 /**
- * Parse string parameter
+ * Get arbitrary block program data and returns pointer to data
  * @param context
- * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
- * @param len Length of returned non-null terminated string
+ * @param value result pointer to data
+ * @param len result length of data
  * @param mandatory
- * @return 
+ * @return
  */
-scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
-    size_t length;
+scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
 
     if (!value || !len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+        return FALSE;
+    }
+
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+        if (param.type == SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA) {
+            *value = param.ptr;
+            *len = param.len;
+        } else {
+            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+            result = FALSE;
+        }
+    }
+
+    return result;
+}
+
+scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
+    size_t i_from;
+    size_t i_to;
+    char quote;
+
+    if (!buffer || !copy_len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    if (!paramNext(context, mandatory)) {
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+
+        switch (param.type) {
+            case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA:
+            case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA:
+                quote = param.type == SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA ? '\'' : '"';
+                for (i_from = 0, i_to = 0; i_from < (size_t) param.len; i_from++) {
+                    if (i_from >= buffer_len) {
+                        break;
+                    }
+                    buffer[i_to] = param.ptr[i_from];
+                    i_to++;
+                    if (param.ptr[i_from] == quote) {
+                        i_from++;
+                    }
+                }
+                break;
+            default:
+                SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+                result = FALSE;
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Convert parameter to choice
+ * @param context
+ * @param parameter - should be PROGRAM_MNEMONIC
+ * @param options - NULL terminated list of choices
+ * @param value - index to options
+ * @return
+ */
+scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value) {
+    size_t res;
+    scpi_bool_t result = FALSE;
+
+    if (!options || !value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    if (locateStr(context->paramlist.parameters, context->paramlist.length, value, &length)) {
-        paramSkipBytes(context, length);
-        paramSkipWhitespace(context);
-        if (len) {
-            *len = length;
+    if (parameter->type == SCPI_TOKEN_PROGRAM_MNEMONIC) {
+        for (res = 0; options[res].name; ++res) {
+            if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len, NULL)) {
+                *value = options[res].tag;
+                result = TRUE;
+                break;
+            }
+        }
+
+        if (!result) {
+            SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
         }
-        return TRUE;
+    } else {
+        SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+    }
+
+    return result;
+}
+
+/**
+ * Find tag in choices and returns its first textual representation
+ * @param options specifications of choices numbers (patterns)
+ * @param tag numerical representatio of choice
+ * @param text result text
+ * @return TRUE if succesfule, else FALSE
+ */
+scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text) {
+    int i;
+
+    for (i = 0; options[i].name != NULL; i++) {
+        if (options[i].tag == tag) {
+            *text = options[i].name;
+            return TRUE;
+        }
     }
 
     return FALSE;
 }
 
 /**
- * Parse text parameter (can be inside "")
- * @param context
- * @param value Pointer to string buffer where pointer to non-null terminated string will be returned
- * @param len Length of returned non-null terminated string
- * @param mandatory
- * @return 
- */
-scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
-    size_t length;
-
-    if (!value || !len) {
-        return FALSE;
-    }
-
-    if (!paramNext(context, mandatory)) {
-        return FALSE;
-    }
-
-    if (locateText(context->paramlist.parameters, context->paramlist.length, value, &length)) {
-        paramSkipBytes(context, length);
-        if (len) {
-            *len = length;
-        }
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-/**
- * Parse boolean parameter as described in the spec SCPI-99 7.3 Boolean Program Data
+ * Read BOOL parameter (0,1,ON,OFF)
  * @param context
  * @param value
  * @param mandatory
- * @return 
+ * @return
  */
 scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) {
-    const char * param;
-    size_t param_len;
-    size_t num_len;
-    int32_t i;
+    scpi_bool_t result;
+    scpi_parameter_t param;
+    int32_t intval;
+
+    scpi_choice_def_t bool_options[] = {
+        {"OFF", 0},
+        {"ON", 1},
+        SCPI_CHOICE_LIST_END /* termination of option list */
+    };
 
     if (!value) {
-        return FALSE;
-    }
-
-    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    if (matchPattern("ON", 2, param, param_len)) {
-        *value = TRUE;
-    } else if (matchPattern("OFF", 3, param, param_len)) {
-        *value = FALSE;
-    } else {
-        num_len = strToLong(param, &i);
+    result = SCPI_Parameter(context, &param, mandatory);
 
-        if (num_len != param_len) {
-            SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
-            return FALSE;
+    if (result) {
+        if (param.type == SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA) {
+            SCPI_ParamToInt(context, &param, &intval);
+            *value = intval ? TRUE : FALSE;
+        } else {
+            result = SCPI_ParamToChoice(context, &param, bool_options, &intval);
+            if (result) {
+                *value = intval ? TRUE : FALSE;
+            }
         }
-
-        *value = i ? TRUE : FALSE;
     }
 
-    return TRUE;
+    return result;
 }
 
 /**
- * Parse choice parameter
+ * Read value from list of options
  * @param context
  * @param options
  * @param value
  * @param mandatory
- * @return 
+ * @return
  */
-scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory) {
-    const char * param;
-    size_t param_len;
-    size_t res;
+scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory) {
+    scpi_bool_t result;
+    scpi_parameter_t param;
 
     if (!options || !value) {
-        return FALSE;
-    }
-
-    if (!SCPI_ParamString(context, &param, &param_len, mandatory)) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    for (res = 0; options[res]; ++res) {
-        if (matchPattern(options[res], strlen(options[res]), param, param_len)) {
-            *value = res;
-            return TRUE;
+    result = SCPI_Parameter(context, &param, mandatory);
+    if (result) {
+        result = SCPI_ParamToChoice(context, &param, options, value);
+    }
+
+    return result;
+}
+
+/**
+ * Parse one parameter and detect type
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) {
+    scpi_token_t tmp;
+    int result = 0;
+    int wsLen;
+    int suffixLen;
+    int realLen = 0;
+    realLen += scpiLex_WhiteSpace(state, &tmp);
+
+    if (result == 0) result = scpiLex_NondecimalNumericData(state, token);
+    if (result == 0) result = scpiLex_CharacterProgramData(state, token);
+    if (result == 0) {
+        result = scpiLex_DecimalNumericProgramData(state, token);
+        if (result != 0) {
+            wsLen = scpiLex_WhiteSpace(state, &tmp);
+            suffixLen = scpiLex_SuffixProgramData(state, &tmp);
+            if (suffixLen > 0) {
+                token->len += wsLen + suffixLen;
+                token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX;
+                result = token->len;
+            }
         }
     }
 
-    SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
-    return FALSE;
+    if (result == 0) result = scpiLex_StringProgramData(state, token);
+    if (result == 0) result = scpiLex_ArbitraryBlockProgramData(state, token);
+    if (result == 0) result = scpiLex_ProgramExpression(state, token);
+
+    realLen += scpiLex_WhiteSpace(state, &tmp);
+
+    return result + realLen;
+}
+
+/**
+ * Skip all parameters to correctly detect end of command line.
+ * @param state
+ * @param token
+ * @param numberOfParameters
+ * @return
+ */
+int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) {
+
+    int result;
+    scpi_token_t tmp;
+    int paramCount = 0;
+
+    token->len = -1;
+    token->type = SCPI_TOKEN_ALL_PROGRAM_DATA;
+    token->ptr = state->pos;
+
+
+    for (result = 1; result != 0; result = scpiLex_Comma(state, &tmp)) {
+        token->len += result;
+
+        if (result == 0) {
+            token->type = SCPI_TOKEN_UNKNOWN;
+            token->len = 0;
+            paramCount = -1;
+            break;
+        }
+
+        result = scpiParser_parseProgramData(state, &tmp);
+        if (tmp.type != SCPI_TOKEN_UNKNOWN) {
+            token->len += result;
+        } else {
+            token->type = SCPI_TOKEN_UNKNOWN;
+            token->len = 0;
+            paramCount = -1;
+            break;
+        }
+        paramCount++;
+    }
+
+    if (token->len == -1) {
+        token->len = 0;
+    }
+
+    if (numberOfParameters != NULL) {
+        *numberOfParameters = paramCount;
+    }
+    return token->len;
 }
 
+/**
+ * Skip complete command line - program header and parameters
+ * @param state
+ * @param buffer
+ * @param len
+ * @return
+ */
+int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) {
+    lex_state_t lex_state;
+    scpi_token_t tmp;
+    int result = 0;
+
+    lex_state.buffer = lex_state.pos = buffer;
+    lex_state.len = len;
+    state->numberOfParameters = 0;
+
+    /* ignore whitespace at the begginig */
+    scpiLex_WhiteSpace(&lex_state, &tmp);
+
+    if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) {
+        if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) {
+            scpiParser_parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters);
+        } else {
+            invalidateToken(&state->programData, lex_state.pos);
+        }
+    } else {
+        invalidateToken(&state->programHeader, lex_state.buffer);
+        invalidateToken(&state->programData, lex_state.buffer);
+    }
+
+    if (result == 0) result = scpiLex_NewLine(&lex_state, &tmp);
+    if (result == 0) result = scpiLex_Semicolon(&lex_state, &tmp);
+
+    if (!scpiLex_IsEos(&lex_state) && (result == 0)) {
+        lex_state.pos++;
+
+        state->programHeader.len = 1;
+        state->programHeader.type = SCPI_TOKEN_INVALID;
+
+        invalidateToken(&state->programData, lex_state.buffer);
+    }
+
+    if (SCPI_TOKEN_SEMICOLON == tmp.type) {
+        state->termination = SCPI_MESSAGE_TERMINATION_SEMICOLON;
+    } else if (SCPI_TOKEN_NL == tmp.type) {
+        state->termination = SCPI_MESSAGE_TERMINATION_NL;
+    } else {
+        state->termination = SCPI_MESSAGE_TERMINATION_NONE;
+    }
+
+    return lex_state.pos - lex_state.buffer;
+}
+
+/**
+ * Check current command
+ *  - suitable for one handle to multiple commands
+ * @param context
+ * @param cmd
+ * @return
+ */
 scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) {
-    if (! context->paramlist.cmd) {
+    const char * pattern;
+
+    if (!context->param_list.cmd) {
         return FALSE;
     }
 
-    const char * pattern = context->paramlist.cmd->pattern;
-    return matchCommand (pattern, cmd, strlen (cmd));
+    pattern = context->param_list.cmd->pattern;
+    return matchCommand (pattern, cmd, strlen (cmd), NULL, 0);
 }
+
+/**
+ * Return the .tag field of the matching scpi_command_t
+ * @param context
+ * @return
+ */
+int32_t SCPI_CmdTag(scpi_t * context) {
+    if (context->param_list.cmd) {
+        return context->param_list.cmd->tag;
+    } else {
+        return 0;
+    }
+}
+
+scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len) {
+    return matchCommand (pattern, value, len, NULL, 0);
+}
+
+scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len) {
+    return matchCommand (context->param_list.cmd->pattern,  context->param_list.cmd_raw.data, context->param_list.cmd_raw.length, numbers, len);
+}
diff -r aad43948c45c -r b497f235115a src/parser_private.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parser_private.h	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2012-2013 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   parser_private.h
+ * 
+ * @brief  SCPI Parser private definitions
+ * 
+ * 
+ */
+
+#ifndef SCPI_PARSER_PRIVATE_H
+#define SCPI_PARSER_PRIVATE_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+    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, char * buffer, int len) LOCAL;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_PARSER_PRIVATE_H */
diff -r aad43948c45c -r b497f235115a src/units.c
--- a/src/units.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/units.c	Fri Aug 07 21:54:11 2015 +0000
@@ -37,8 +37,10 @@
 #include <string.h>
 #include "scpi/parser.h"
 #include "scpi/units.h"
-#include "scpi/utils_private.h"
+#include "utils_private.h"
+#include "scpi/utils.h"
 #include "scpi/error.h"
+#include "lexer_private.h"
 
 
 /*
@@ -62,39 +64,39 @@
  */
 const scpi_unit_def_t scpi_units_def[] = {
     /* voltage */
-    {/* name */ "UV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e-6},
-    {/* name */ "MV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e-3},
-    {/* name */ "V",    /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1},
-    {/* name */ "KV",   /* unit */ SCPI_UNIT_VOLT,      /* mult */ 1e3},
+    {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6},
+    {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3},
+    {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1},
+    {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3},
 
     /* current */
-    {/* name */ "UA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e-6},
-    {/* name */ "MA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e-3},
-    {/* name */ "A",    /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1},
-    {/* name */ "KA",   /* unit */ SCPI_UNIT_AMPER,     /* mult */ 1e3},
+    {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6},
+    {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3},
+    {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1},
+    {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3},
 
     /* resistance */
-    {/* name */ "OHM",  /* unit */ SCPI_UNIT_OHM,       /* mult */ 1},
-    {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM,       /* mult */ 1e3},
-    {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM,       /* mult */ 1e6},
+    {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1},
+    {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3},
+    {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6},
 
     /* frequency */
-    {/* name */ "HZ",   /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1},
-    {/* name */ "KHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e3},
-    {/* name */ "MHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e6},
-    {/* name */ "GHZ",  /* unit */ SCPI_UNIT_HERTZ,     /* mult */ 1e9},
+    {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1},
+    {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3},
+    {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6},
+    {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9},
 
     /* temperature */
-    {/* name */ "CEL",  /* unit */ SCPI_UNIT_CELSIUS,   /* mult */ 1},
+    {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1},
 
     /* time */
-    {/* name */ "PS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-12},
-    {/* name */ "NS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-9},
-    {/* name */ "US",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-6},
-    {/* name */ "MS",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1e-3},
-    {/* name */ "S",    /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 1},
-    {/* name */ "MIN",  /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 60},
-    {/* name */ "HR",   /* unit */ SCPI_UNIT_SECONDS,   /* mult */ 3600},
+    {/* name */ "PS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-12},
+    {/* name */ "NS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-9},
+    {/* name */ "US", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-6},
+    {/* name */ "MS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-3},
+    {/* name */ "S", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1},
+    {/* name */ "MIN", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 60},
+    {/* name */ "HR", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 3600},
 
     SCPI_UNITS_LIST_END,
 };
@@ -102,71 +104,20 @@
 /*
  * Special number values definition
  */
-const scpi_special_number_def_t scpi_special_numbers_def[] = {
-    {/* name */ "MINimum",      /* type */ SCPI_NUM_MIN},
-    {/* name */ "MAXimum",      /* type */ SCPI_NUM_MAX},
-    {/* name */ "DEFault",      /* type */ SCPI_NUM_DEF},
-    {/* name */ "UP",           /* type */ SCPI_NUM_UP},
-    {/* name */ "DOWN",         /* type */ SCPI_NUM_DOWN},
-    {/* name */ "NAN",          /* type */ SCPI_NUM_NAN},
-    {/* name */ "INFinity",     /* type */ SCPI_NUM_INF},
-    {/* name */ "NINF",         /* type */ SCPI_NUM_NINF},
-    {/* name */ "AUTO",         /* type */ SCPI_NUM_AUTO},
-    SCPI_SPECIAL_NUMBERS_LIST_END,
+const scpi_choice_def_t scpi_special_numbers_def[] = {
+    {/* name */ "MINimum", /* type */ SCPI_NUM_MIN},
+    {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX},
+    {/* name */ "DEFault", /* type */ SCPI_NUM_DEF},
+    {/* name */ "UP", /* type */ SCPI_NUM_UP},
+    {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN},
+    {/* name */ "NAN", /* type */ SCPI_NUM_NAN},
+    {/* name */ "INFinity", /* type */ SCPI_NUM_INF},
+    {/* name */ "NINF", /* type */ SCPI_NUM_NINF},
+    {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO},
+    SCPI_CHOICE_LIST_END,
 };
 
 /**
- * Match string constant to one of special number values
- * @param specs specifications of special numbers (patterns)
- * @param str string to be recognised
- * @param len length of string
- * @param value resultin value
- * @return TRUE if str matches one of specs patterns
- */
-static scpi_bool_t translateSpecialNumber(const scpi_special_number_def_t * specs, const char * str, size_t len, scpi_number_t * value) {
-    int i;
-
-    value->value = 0.0;
-    value->unit = SCPI_UNIT_NONE;
-    value->type = SCPI_NUM_NUMBER;
-
-    if (specs == NULL) {
-        return FALSE;
-    }
-
-    for (i = 0; specs[i].name != NULL; i++) {
-        if (matchPattern(specs[i].name, strlen(specs[i].name), str, len)) {
-            value->type = specs[i].type;
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-/**
- * Convert special number type to its string representation
- * @param specs specifications of special numbers (patterns)
- * @param type type of special number
- * @return String representing special number or NULL
- */
-static const char * translateSpecialNumberInverse(const scpi_special_number_def_t * specs, scpi_special_number_t type) {
-    int i;
-
-    if (specs == NULL) {
-        return NULL;
-    }
-    
-    for (i = 0; specs[i].name != NULL; i++) {
-        if (specs[i].type == type) {
-            return specs[i].name;
-        }
-    }
-
-    return NULL;
-}
-
-/**
  * Convert string describing unit to its representation
  * @param units units patterns
  * @param unit text representation of unknown unit
@@ -175,11 +126,11 @@
  */
 static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) {
     int i;
-    
+
     if (units == NULL) {
         return NULL;
     }
-    
+
     for (i = 0; units[i].name != NULL; i++) {
         if (compareStr(unit, len, units[i].name, strlen(units[i].name))) {
             return &units[i];
@@ -197,11 +148,11 @@
  */
 static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) {
     int i;
-    
+
     if (units == NULL) {
         return NULL;
     }
-    
+
     for (i = 0; units[i].name != NULL; i++) {
         if ((units[i].unit == unit) && (units[i].mult == 1)) {
             return units[i].name;
@@ -249,43 +200,97 @@
  * @param mandatory if the parameter is mandatory
  * @return 
  */
-scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory) {
+scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory)
+{
+    scpi_token_t token;
+    lex_state_t state;
+    scpi_parameter_t param;
     scpi_bool_t result;
-    const char * param;
-    size_t len;
-    size_t numlen;
+    int32_t tag;
 
-    /* read parameter and shift to the next one */
-    result = SCPI_ParamString(context, &param, &len, mandatory);
-
-    /* value not initializes */
     if (!value) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
         return FALSE;
     }
 
-    value->type = SCPI_NUM_DEF;
+    result = SCPI_Parameter(context, &param, mandatory);
+
+    if (!result) {
+        return result;
+    }
+
+    state.buffer = param.ptr;
+    state.pos = state.buffer;
+    state.len = param.len;
 
-    /* if parameter was not found, return TRUE or FALSE according
-     * to fact that parameter was mandatory or not */
-    if (!result) {
-        return mandatory ? FALSE : TRUE;
+    switch(param.type) {
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+        case SCPI_TOKEN_HEXNUM:
+        case SCPI_TOKEN_OCTNUM:
+        case SCPI_TOKEN_BINNUM:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+        case SCPI_TOKEN_PROGRAM_MNEMONIC:
+            value->unit = SCPI_UNIT_NONE;
+            value->special = FALSE;
+            result = TRUE;
+            break;
     }
 
-    /* convert string to special number type */
-    if (translateSpecialNumber(context->special_numbers, param, len, value)) {
-        /* found special type */
-        return TRUE;
+    switch(param.type) {
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+        case SCPI_TOKEN_PROGRAM_MNEMONIC:
+            value->base = 10;
+            break;
+        case SCPI_TOKEN_BINNUM:
+            value->base = 2;
+            break;
+        case SCPI_TOKEN_HEXNUM:
+            value->base = 16;
+            break;
+        case SCPI_TOKEN_OCTNUM:
+            value->base = 8;
+            break;
     }
 
-    /* convert text from double - no special type */
-    numlen = strToDouble(param, &value->value);
+    switch(param.type) {
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+            SCPI_ParamToDouble(context, &param, &(value->value));
+            break;
+        case SCPI_TOKEN_HEXNUM:
+            SCPI_ParamToDouble(context, &param, &(value->value));
+            break;
+        case SCPI_TOKEN_OCTNUM:
+            SCPI_ParamToDouble(context, &param, &(value->value));
+            break;
+        case SCPI_TOKEN_BINNUM:
+            SCPI_ParamToDouble(context, &param, &(value->value));
+            break;
+        case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+            scpiLex_DecimalNumericProgramData(&state, &token);
+            scpiLex_WhiteSpace(&state, &token);
+            scpiLex_SuffixProgramData(&state, &token);
 
-    /* transform units of value */
-    if (numlen <= len) {
-        return transformNumber(context, param + numlen, len - numlen, value);
+            SCPI_ParamToDouble(context, &param, &(value->value));
+
+            result = transformNumber(context, token.ptr, token.len, value);
+            break;
+        case SCPI_TOKEN_PROGRAM_MNEMONIC:
+            scpiLex_WhiteSpace(&state, &token);
+            scpiLex_CharacterProgramData(&state, &token);
+
+            /* convert string to special number type */
+            SCPI_ParamToChoice(context, &token, special, &tag);
+
+            value->special = TRUE;
+            value->tag = tag;
+
+            break;
+        default:
+            result = FALSE;
     }
-    return FALSE;
 
+    return result;
 }
 
 /**
@@ -296,7 +301,7 @@
  * @param len max length of string
  * @return number of chars written to string
  */
-size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len) {
+size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len) {
     const char * type;
     const char * unit;
     size_t result;
@@ -305,14 +310,17 @@
         return 0;
     }
 
-    type = translateSpecialNumberInverse(context->special_numbers, value->type);
-
-    if (type) {
-        strncpy(str, type, len);
-        return min(strlen(type), len);
+    if (value->special) {
+        if (SCPI_ChoiceToName(special, value->tag, &type)) {
+            strncpy(str, type, len);
+            return min(strlen(type), len);
+        } else {
+            str[0] = 0;
+            return 0;
+        }
     }
 
-    result = doubleToStr(value->value, str, len);
+    result = SCPI_DoubleToStr(value->value, str, len);
 
     unit = translateUnitInverse(context->units, value->unit);
 
diff -r aad43948c45c -r b497f235115a src/utils.c
--- a/src/utils.c	Thu Apr 09 22:42:15 2015 +0000
+++ b/src/utils.c	Fri Aug 07 21:54:11 2015 +0000
@@ -1,4 +1,3 @@
-#define HAVE_STRNLEN    0
 /*-
  * Copyright (c) 2013 Jan Breuer
  *                    Richard.hmm
@@ -42,7 +41,8 @@
 #include <string.h>
 #include <ctype.h>
 
-#include "scpi/utils_private.h"
+#include "utils_private.h"
+#include "scpi/utils.h"
 
 static size_t patternSeparatorShortPos(const char * pattern, size_t len);
 static size_t patternSeparatorPos(const char * pattern, size_t len);
@@ -55,7 +55,7 @@
  * @param set
  * @return 
  */
-const char * strnpbrk(const char *str, size_t size, const char *set) {
+char * strnpbrk(const char *str, size_t size, const char *set) {
     const char *scanp;
     long c, sc;
     const char * strend = str + size;
@@ -63,7 +63,7 @@
     while ((strend != str) && ((c = *str++) != 0)) {
         for (scanp = set; (sc = *scanp++) != '\0';)
             if (sc == c)
-                return str - 1;
+                return ((char *) (str - 1));
     }
     return (NULL);
 }
@@ -73,35 +73,63 @@
  * @param val   integer value
  * @param str   converted textual representation
  * @param len   string buffer length
+ * @param base  output base
  * @return number of bytes written to str (without '\0')
  */
-size_t longToStr(int32_t val, char * str, size_t len) {
-    uint32_t x = 1000000000L;
+size_t SCPI_LongToStr(int32_t val, char * str, size_t len, int8_t base) {
+    const char digits[] = "0123456789ABCDEF";
+
+#define ADD_CHAR(c) if (pos < len) str[pos++] = (c)
+    uint32_t x = 0;
     int_fast8_t digit;
     size_t pos = 0;
+    uint32_t uval = val;
 
-    if (val == 0) {
-        if (pos < len) str[pos++] = '0';
+    if (uval == 0) {
+        ADD_CHAR('0');
     } else {
-        if (val < 0) {
-            val = -val;
-            if (pos < len) str[pos++] = '-';
+
+        switch (base) {
+            case 2: 
+                x = 0x80000000L;
+                break;
+            case 8:
+                x = 0x40000000L;
+                break;
+            case 10:
+                x = 1000000000L;
+                break;
+            case 0x10:
+                x = 0x10000000L;
+                break;
+            default:
+                x = 1000000000L;
+                base = 10;
+                break;
         }
 
-        while ((val / x) == 0) {
-            x /= 10;
+        // add sign for numbers in base 10
+        if ((val < 0) && (base == 10)) {
+            uval = -val;
+            ADD_CHAR('-');
+        }
+
+        // remove leading zeros
+        while ((uval / x) == 0) {
+            x /= base;
         }
 
         do {
-            digit = (uint8_t) (val / x);
-            if (pos < len) str[pos++] = digit + '0';
-            val -= digit * x;
-            x /= 10;
+            digit = (uint8_t) (uval / x);
+            ADD_CHAR(digits[digit]);
+            uval -= digit * x;
+            x /= base;
         } while (x && (pos < len));
     }
 
     if (pos < len) str[pos] = 0;
     return pos;
+#undef ADD_CHAR
 }
 
 /**
@@ -111,8 +139,8 @@
  * @param len   string buffer length
  * @return number of bytes written to str (without '\0')
  */
-size_t doubleToStr(double val, char * str, size_t len) {
-    return snprintf(str, len, "%lg", val);
+size_t SCPI_DoubleToStr(double val, char * str, size_t len) {
+    return SCPIDEFINE_doubleToStr(val, str, len);
 }
 
 /**
@@ -121,9 +149,9 @@
  * @param val   32bit integer result
  * @return      number of bytes used in string
  */
-size_t strToLong(const char * str, int32_t * val) {
+size_t strToLong(const char * str, int32_t * val, int8_t base) {
     char * endptr;
-    *val = strtol(str, &endptr, 0);
+    *val = strtol(str, &endptr, base);
     return endptr - str;
 }
 
@@ -152,7 +180,7 @@
         return FALSE;
     }
 
-    if (SCPI_strncasecmp(str1, str2, len2) == 0) {
+    if (SCPIDEFINE_strncasecmp(str1, str2, len2) == 0) {
         return TRUE;
     }
 
@@ -167,7 +195,7 @@
  * @param len2
  * @return TRUE if strings match
  */
-scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) {
+scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) {
     scpi_bool_t result = FALSE;
     size_t i;
 
@@ -175,222 +203,34 @@
         return FALSE;
     }
 
-    if (SCPI_strncasecmp(str1, str2, len1) == 0) {
+    if (SCPIDEFINE_strncasecmp(str1, str2, len1) == 0) {
         result = TRUE;
-    }
 
-    for (i = len1; i<len2; i++) {
-        if (!isdigit((int) str2[i])) {
-            result = FALSE;
-            break;
+        if (num) {
+            if (len1 == len2) {
+                *num = 1;
+            } else {
+                int32_t tmpNum;
+                i = len1 + strToLong(str2 + len1, &tmpNum, 10);
+                if (i != len2) {
+                    result = FALSE;
+                } else {
+                    *num = tmpNum;
+                }
+            }
+        } else {
+            for (i = len1; i<len2; i++) {
+                if (!isdigit((int) str2[i])) {
+                    result = FALSE;
+                    break;
+                }
+            }
         }
     }
 
     return result;
 }
 
-enum _locate_text_states {
-    STATE_FIRST_WHITESPACE,
-    STATE_TEXT_QUOTED,
-    STATE_TEXT,
-    STATE_LAST_WHITESPACE,
-    STATE_COMMA,
-    STATE_ERROR
-};
-typedef enum _locate_text_states locate_text_states;
-
-struct _locate_text_nfa {
-    locate_text_states state;
-    int32_t startIdx;
-    int32_t stopIdx;
-    size_t i;
-};
-typedef struct _locate_text_nfa locate_text_nfa;
-
-/**
- * Test locate text state, if it is correct final state
- */
-static scpi_bool_t isFinalState(locate_text_states state) {
-    return (
-        ((state) == STATE_COMMA)
-        || ((state) == STATE_LAST_WHITESPACE)
-        || ((state) == STATE_TEXT) ||
-        ((state) == STATE_FIRST_WHITESPACE)
-    );
-}
-
-/**
- * Perform locateText automaton to search string pattern
- * @param nfa stores automaton state
- * @param c current char processed
- */
-static scpi_bool_t locateTextAutomaton(locate_text_nfa * nfa, unsigned char c) {
-    switch(nfa->state) {
-        /* first state locating only white spaces */
-        case STATE_FIRST_WHITESPACE:
-            if(isspace(c)) {
-                nfa->startIdx = nfa->stopIdx = nfa->i + 1;
-            } else if (c == ',') {
-                nfa->state = STATE_COMMA;
-            } else if (c == '"') {
-                nfa->startIdx = nfa->i + 1;
-                nfa->state = STATE_TEXT_QUOTED;
-            } else {
-                nfa->startIdx = nfa->i;
-                nfa->stopIdx = nfa->i + 1;
-                nfa->state = STATE_TEXT;
-            }
-            break;
-        /* state locating any text inside "" */
-        case STATE_TEXT_QUOTED:
-            if(c == '"') {
-                nfa->state = STATE_LAST_WHITESPACE;
-                nfa->stopIdx = nfa->i;
-            }
-            break;
-        /* locate text ignoring quotes */
-        case STATE_TEXT:
-            if (c == ',') {
-                nfa->state = STATE_COMMA;
-            } else if (!isspace(c)) {
-                nfa->stopIdx = nfa->i + 1;
-            }
-            break;
-        /* locating text after last quote */
-        case STATE_LAST_WHITESPACE:
-            if (c == ',') {
-                nfa->state = STATE_COMMA;
-            } else if (!isspace(c)) {
-                nfa->state = STATE_ERROR;
-            }
-            break;
-
-        default:
-            break;
-    }
-
-    /* if it is terminating state, break from for loop */
-    if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) {
-        return FALSE;
-    } else {
-        return TRUE;
-    }
-}
-
-/**
- * Locate text in string. Text is separated by two ""
- *   example: "text", next parameter
- *   regexp: ^[ \t\r\n]*"([^"]*)"[ \t\r\n]*,?
- *   regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,?
- * @param str1 string to be searched
- * @param len1 length of string
- * @param str2 result
- * @param len2 length of result
- * @return string str1 contains text and str2 was set
- */
-scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) {
-    locate_text_nfa nfa;
-    nfa.state = STATE_FIRST_WHITESPACE;
-    nfa.startIdx = 0;
-    nfa.stopIdx = 0;
-
-    for (nfa.i = 0; nfa.i < len1; nfa.i++) {
-        if(FALSE == locateTextAutomaton(&nfa, str1[nfa.i])) {
-            break;
-        }
-    }
-
-    if (isFinalState(nfa.state)) {
-
-        if (str2) {
-            *str2 = &str1[nfa.startIdx];
-        }
-
-        if (len2) {
-            *len2 = nfa.stopIdx - nfa.startIdx;
-        }
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/**
- * Perform locateStr automaton to search string pattern
- * @param nfa stores automaton state
- * @param c current char processed
- */
-static scpi_bool_t locateStrAutomaton(locate_text_nfa * nfa, unsigned char c) {
-    switch(nfa->state) {
-        /* first state locating only white spaces */
-        case STATE_FIRST_WHITESPACE:
-            if(isspace(c)) {
-                nfa->startIdx = nfa->stopIdx = nfa->i + 1;
-            } else if (c == ',') {
-                nfa->state = STATE_COMMA;
-            } else {
-                nfa->startIdx = nfa->i;
-                nfa->stopIdx = nfa->i + 1;
-                nfa->state = STATE_TEXT;
-            }
-            break;
-        /* locate text ignoring quotes */
-        case STATE_TEXT:
-            if (c == ',') {
-                nfa->state = STATE_COMMA;
-            } else if (!isspace(c)) {
-                nfa->stopIdx = nfa->i + 1;
-            }
-            break;
-
-        default:
-            break;            
-    }
-
-    /* if it is terminating state, break from for loop */
-    if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) {
-        return FALSE;
-    } else {
-        return TRUE;
-    }
-}
-
-/**
- * Locate string in string.
- *   regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,?
- * @param str1 string to be searched
- * @param len1 length of string
- * @param str2 result
- * @param len2 length of result
- * @return string str1 contains text and str2 was set
- */
-scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) {
-    locate_text_nfa nfa;
-    nfa.state = STATE_FIRST_WHITESPACE;
-    nfa.startIdx = 0;
-    nfa.stopIdx = 0;
-
-
-    for (nfa.i = 0; nfa.i < len1; nfa.i++) {
-        if(FALSE == locateStrAutomaton(&nfa, str1[nfa.i])) {
-            break;
-        }
-    }
-
-    if (isFinalState(nfa.state)) {
-
-        if (str2) {
-            *str2 = &str1[nfa.startIdx];
-        }
-
-        if (len2) {
-            *len2 = nfa.stopIdx - nfa.startIdx;
-        }
-        return TRUE;
-    }
-    return FALSE;
-}
-
-
 /**
  * Count white spaces from the beggining
  * @param cmd - command
@@ -414,7 +254,7 @@
  * @param len - max search length
  * @return position of separator or len
  */
-size_t patternSeparatorShortPos(const char * pattern, size_t len) {
+static size_t patternSeparatorShortPos(const char * pattern, size_t len) {
     size_t i;
     for (i = 0; (i < len) && pattern[i]; i++) {
         if (islower((unsigned char) pattern[i])) {
@@ -430,9 +270,9 @@
  * @param len - max search length
  * @return position of separator or len
  */
-size_t patternSeparatorPos(const char * pattern, size_t len) {
+static size_t patternSeparatorPos(const char * pattern, size_t len) {
 
-    const char * separator = strnpbrk(pattern, len, "?:[]");
+    char * separator = strnpbrk(pattern, len, "?:[]");
     if (separator == NULL) {
         return len;
     } else {
@@ -446,8 +286,8 @@
  * @param len - max search length
  * @return position of separator or len
  */
-size_t cmdSeparatorPos(const char * cmd, size_t len) {
-    const char * separator = strnpbrk(cmd, len, ":?");
+static size_t cmdSeparatorPos(const char * cmd, size_t len) {
+    char * separator = strnpbrk(cmd, len, ":?");
     size_t result;
     if (separator == NULL) {
         result = len;
@@ -466,7 +306,7 @@
  * @param str_len
  * @return 
  */
-scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) {
+scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) {
     int pattern_sep_pos_short;
 
     if (pattern[pattern_len - 1] == '#') {
@@ -474,8 +314,8 @@
 
         pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len);
 
-        return compareStrAndNum(pattern, new_pattern_len, str, str_len) ||
-                compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len);
+        return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) ||
+                compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num);
     } else {
 
         pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len);
@@ -492,18 +332,21 @@
  * @param len - max search length
  * @return TRUE if pattern matches, FALSE otherwise
  */
-scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) {
+scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len) {
     scpi_bool_t result = FALSE;
     int leftFlag = 0; // flag for '[' on left
     int rightFlag = 0; // flag for ']' on right
     int cmd_sep_pos = 0;
 
+    size_t numbers_idx = 0;
+    int32_t *number_ptr = NULL;
+
     const char * pattern_ptr = pattern;
     int pattern_len = strlen(pattern);
     const char * pattern_end = pattern + pattern_len;
 
     const char * cmd_ptr = cmd;
-    size_t cmd_len = SCPI_strnlen(cmd, len);
+    size_t cmd_len = SCPIDEFINE_strnlen(cmd, len);
     const char * cmd_end = cmd + cmd_len;
 
     /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */
@@ -519,7 +362,7 @@
 
     if (cmd_ptr[0] == ':') {
         /* handle errornouse ":*IDN?" */
-        if((cmd_len >= 2) && (cmd_ptr[1] != '*')) {
+        if ((cmd_len >= 2) && (cmd_ptr[1] != '*')) {
             cmd_len--;
             cmd_ptr++;
         }
@@ -535,7 +378,19 @@
             cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr);
         }
 
-        if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos)) {
+        if (pattern_ptr[pattern_sep_pos - 1] == '#') {
+            if (numbers && (numbers_idx < numbers_len)) {
+                number_ptr = numbers + numbers_idx;
+                *number_ptr = 1; // default value
+            } else {
+                number_ptr = NULL;
+            }
+            numbers_idx++;
+        } else {
+            number_ptr = NULL;
+        }
+
+        if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos, number_ptr)) {
             pattern_ptr = pattern_ptr + pattern_sep_pos;
             cmd_ptr = cmd_ptr + cmd_sep_pos;
             result = TRUE;
@@ -619,74 +474,45 @@
 
 /**
  * Compose command from previsou command anc current command
- * 
- * @param ptr_prev pointer to previous command
- * @param len_prev length of previous command
- * @param pptr pointer to pointer of current command
- * @param plen pointer to length of current command
- * 
- * ptr_prev and ptr should be in the same memory buffer
- * 
- * Function will add part of previous command prior to ptr_prev
- * 
- * char * cmd = "meas:volt:dc?;ac?"
- * char * ptr_prev = cmd;
- * size_t len_prev = 13;
- * char * ptr = cmd + 14;
- * size_t len = 3;
- * 
- * composeCompoundCommand(ptr_prev, len_prev, &ptr, &len);
- * 
- * after calling this
- * 
- * 
- * 
+ *
+ * @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(char * ptr_prev, size_t len_prev,
-                              char ** pptr, size_t * plen) {
-    char * ptr;
-    size_t len;
+scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) {
     size_t i;
 
     /* Invalid input */
-    if (pptr == NULL || plen == NULL)
+    if (current == NULL || current->ptr == NULL || current->len == 0)
         return FALSE;
 
     /* no previous command - nothing to do*/
-    if (ptr_prev == NULL || len_prev == 0)
+    if (prev->ptr == NULL || prev->len == 0)
         return TRUE;
-       
-    ptr = *pptr;
-    len = *plen;
-    
-    /* No current command */
-    if (len == 0 || ptr == NULL)
-        return FALSE;
-    
+
     /* Common command or command root - nothing to do */
-    if (ptr[0] == '*' || ptr[0] == ':')
+    if (current->ptr[0] == '*' || current->ptr[0] == ':')
         return TRUE;
-        
+
     /* Previsou command was common command - nothing to do */
-    if (ptr_prev[0] == '*')
+    if (prev->ptr[0] == '*')
         return TRUE;
-        
+
     /* Find last occurence of ':' */
-    for (i = len_prev; i > 0; i--) {
-        if (ptr_prev[i-1] == ':') {
+    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;
-    
-    ptr -= i;
-    len += i;
-    memmove(ptr, ptr_prev, i);
-    *plen = len;
-    *pptr = ptr;
+
+    current->ptr -= i;
+    current->len += i;
+    memmove(current->ptr, prev->ptr, i);
     return TRUE;
 }
 
@@ -712,20 +538,20 @@
 #endif
 
 #if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+
 int OUR_strncasecmp(const char *s1, const char *s2, size_t n) {
     unsigned char c1, c2;
 
-    for(; n != 0; n--) {
-        c1 = tolower((unsigned char)*s1++);
-        c2 = tolower((unsigned char)*s2++);
+    for (; n != 0; n--) {
+        c1 = tolower((unsigned char) *s1++);
+        c2 = tolower((unsigned char) *s2++);
         if (c1 != c2) {
             return c1 - c2;
         }
-        if (c1 = '\0') {
+        if (c1 == '\0') {
             return 0;
         }
     }
     return 0;
 }
 #endif
-
diff -r aad43948c45c -r b497f235115a src/utils_private.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/utils_private.h	Fri Aug 07 21:54:11 2015 +0000
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2012-2013 Jan Breuer,
+ *
+ * All Rights Reserved
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file   scpi_utils.h
+ * @date   Thu Nov 15 10:58:45 UTC 2012
+ * 
+ * @brief  Conversion routines and string manipulation routines
+ * 
+ * 
+ */
+
+#ifndef SCPI_UTILS_PRIVATE_H
+#define SCPI_UTILS_PRIVATE_H
+
+#include <stdint.h>
+#include "scpi/config.h"
+#include "scpi/types.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+    #define LOCAL __attribute__((visibility ("hidden")))
+#else
+    #define LOCAL
+#endif
+
+    char * strnpbrk(const char *str, size_t size, const char *set) LOCAL;
+    scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
+    scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) LOCAL;
+    size_t strToLong(const char * str, int32_t * val, int8_t base) LOCAL;
+    size_t strToDouble(const char * str, double * val) LOCAL;
+    scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+    scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+    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, int32_t * num) LOCAL;
+    scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len) LOCAL;
+    scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL;
+
+#if !HAVE_STRNLEN
+    size_t BSD_strnlen(const char *s, size_t maxlen) LOCAL;
+#endif
+
+#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+    int OUR_strncasecmp(const char *s1, const char *s2, size_t n) LOCAL;
+#endif
+
+#ifndef min
+    #define min(a, b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+    #define max(a, b)  (((a) > (b)) ? (a) : (b))
+#endif
+
+#if 0
+#define max(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* SCPI_UTILS_PRIVATE_H */