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

Dependents:   scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lexer.c Source File

lexer.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 2012-2013 Jan Breuer,
00003  *
00004  * All Rights Reserved
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are
00008  * met:
00009  * 1. Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00018  * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
00019  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00022  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00023  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00024  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 /**
00029  * @file   lexer.c
00030  * @date   Wed Mar 20 19:35:19 UTC 2013
00031  * 
00032  * @brief  SCPI Lexer
00033  * 
00034  * 
00035  */
00036 
00037 #include <ctype.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 
00041 #include "lexer_private.h"
00042 #include "scpi/error.h"
00043 
00044 /**
00045  * Is white space
00046  * @param c
00047  * @return 
00048  */
00049 static int isws(int c) {
00050     if ((c == ' ') || (c == '\t')) {
00051         return 1;
00052     }
00053     return 0;
00054 }
00055 
00056 /**
00057  * Is binary digit
00058  * @param c
00059  * @return 
00060  */
00061 static int isbdigit(int c) {
00062     if ((c == '0') || (c == '1')) {
00063         return 1;
00064     }
00065     return 0;
00066 }
00067 
00068 /**
00069  * Is hexadecimal digit
00070  * @param c
00071  * @return 
00072  */
00073 static int isqdigit(int c) {
00074     if ((c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7')) {
00075         return 1;
00076     }
00077     return 0;
00078 }
00079 
00080 /**
00081  * Is end of string
00082  * @param state
00083  * @return 
00084  */
00085 static int iseos(lex_state_t * state) {
00086     if ((state->buffer + state->len) <= (state->pos)) {
00087         return 1;
00088     } else {
00089         return 0;
00090     }
00091 }
00092 
00093 /**
00094  * Private export of iseos
00095  * @param state
00096  * @return 
00097  */
00098 int scpiLex_IsEos(lex_state_t * state) {
00099     return iseos(state);
00100 }
00101 
00102 /**
00103  * Test current character
00104  * @param state
00105  * @param chr
00106  * @return 
00107  */
00108 static int ischr(lex_state_t * state, char chr) {
00109     return (state->pos[0] == chr);
00110 }
00111 
00112 /**
00113  * Is plus or minus
00114  * @param c
00115  * @return 
00116  */
00117 static int isplusmn(int c) {
00118     return c == '+' || c == '-';
00119 }
00120 
00121 /**
00122  * Is letter H
00123  * @param c
00124  * @return 
00125  */
00126 static int isH(int c) {
00127     return c == 'h' || c == 'H';
00128 }
00129 
00130 /**
00131  * Is letter B
00132  * @param c
00133  * @return 
00134  */
00135 static int isB(int c) {
00136     return c == 'b' || c == 'B';
00137 }
00138 
00139 /**
00140  * Is letter Q
00141  * @param c
00142  * @return 
00143  */
00144 static int isQ(int c) {
00145     return c == 'q' || c == 'Q';
00146 }
00147 
00148 /**
00149  * Is letter E
00150  * @param c
00151  * @return 
00152  */
00153 static int isE(int c) {
00154     return c == 'e' || c == 'E';
00155 }
00156 
00157 #define SKIP_NONE       0
00158 #define SKIP_OK         1
00159 #define SKIP_INCOMPLETE -1
00160 
00161 /* skip characters */
00162 /* 7.4.1 <PROGRAM MESSAGE UNIT SEPARATOR>*/
00163 // TODO: static int skipProgramMessageUnitSeparator(lex_state_t * state)
00164 
00165 /**
00166  * Skip all whitespaces
00167  * @param state
00168  * @return 
00169  */
00170 static int skipWs(lex_state_t * state) {
00171     int someSpace = 0;
00172     while (!iseos(state) && isws(state->pos[0])) {
00173         state->pos++;
00174         someSpace++;
00175     }
00176 
00177     return someSpace;
00178 }
00179 
00180 /* 7.4.2 <PROGRAM DATA SEPARATOR> */
00181 // static int skipProgramDataSeparator(lex_state_t * state)
00182 
00183 /* 7.5.2 <PROGRAM MESSAGE TERMINATOR> */
00184 // static int skipProgramMessageTerminator(lex_state_t * state)
00185 
00186 /**
00187  * Skip decimal digit
00188  * @param state
00189  * @return 
00190  */
00191 static int skipDigit(lex_state_t * state) {
00192     if (!iseos(state) && isdigit(state->pos[0])) {
00193         state->pos++;
00194         return SKIP_OK;
00195     } else {
00196         return SKIP_NONE;
00197     }
00198 }
00199 
00200 /**
00201  * Skip multiple decimal digits
00202  * @param state
00203  * @return 
00204  */
00205 static int skipNumbers(lex_state_t * state) {
00206     int someNumbers = 0;
00207     while (!iseos(state) && isdigit(state->pos[0])) {
00208         state->pos++;
00209         someNumbers++;
00210     }
00211     return someNumbers;
00212 }
00213 
00214 /**
00215  * Skip plus or minus
00216  * @param state
00217  * @return 
00218  */
00219 static int skipPlusmn(lex_state_t * state) {
00220     if (!iseos(state) && isplusmn(state->pos[0])) {
00221         state->pos++;
00222         return SKIP_OK;
00223     } else {
00224         return SKIP_NONE;
00225     }
00226 }
00227 
00228 /**
00229  * Skip any character from 'a'-'Z'
00230  * @param state
00231  * @return 
00232  */
00233 static int skipAlpha(lex_state_t * state) {
00234     int someLetters = 0;
00235     while (!iseos(state) && isalpha(state->pos[0])) {
00236         state->pos++;
00237         someLetters++;
00238     }
00239     return someLetters;
00240 }
00241 
00242 /**
00243  * Skip exact character chr or nothing
00244  * @param state
00245  * @param chr
00246  * @return 
00247  */
00248 static int skipChr(lex_state_t * state, char chr) {
00249     if (!iseos(state) && ischr(state, chr)) {
00250         state->pos++;
00251         return SKIP_OK;
00252     } else {
00253         return SKIP_NONE;
00254     }
00255 }
00256 
00257 /**
00258  * Skip slash or dot
00259  * @param state
00260  * @return 
00261  */
00262 static int skipSlashDot(lex_state_t * state) {
00263     if (!iseos(state) && (ischr(state, '/') | ischr(state, '.'))) {
00264         state->pos++;
00265         return SKIP_OK;
00266     } else {
00267         return SKIP_NONE;
00268     }
00269 }
00270 
00271 /**
00272  * Skip star
00273  * @param state
00274  * @return 
00275  */
00276 static int skipStar(lex_state_t * state) {
00277     if (!iseos(state) && ischr(state, '*')) {
00278         state->pos++;
00279         return SKIP_OK;
00280     } else {
00281         return SKIP_NONE;
00282     }
00283 }
00284 
00285 /**
00286  * Skip colon
00287  * @param state
00288  * @return 
00289  */
00290 static int skipColon(lex_state_t * state) {
00291     if (!iseos(state) && ischr(state, ':')) {
00292         state->pos++;
00293         return SKIP_OK;
00294     } else {
00295         return SKIP_NONE;
00296     }
00297 }
00298 
00299 /* 7.6.1.2 <COMMAND PROGRAM HEADER> */
00300 
00301 /**
00302  * Skip program mnemonic [a-z][a-z0-9_]*
00303  * @param state
00304  * @return 
00305  */
00306 static int skipProgramMnemonic(lex_state_t * state) {
00307     const char * startPos = state->pos;
00308     if (!iseos(state) && isalpha(state->pos[0])) {
00309         state->pos++;
00310         while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) {
00311             state->pos++;
00312         }
00313     }
00314 
00315     if (iseos(state)) {
00316         return (state->pos - startPos) * SKIP_INCOMPLETE;
00317     } else {
00318         return (state->pos - startPos) * SKIP_OK;
00319     }
00320 }
00321 
00322 /* tokens */
00323 
00324 /**
00325  * Detect token white space
00326  * @param state
00327  * @param token
00328  * @return 
00329  */
00330 int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) {
00331     token->ptr = state->pos;
00332 
00333     skipWs(state);
00334 
00335     token->len = state->pos - token->ptr;
00336 
00337     if (token->len > 0) {
00338         token->type = SCPI_TOKEN_WS;
00339     } else {
00340         token->type = SCPI_TOKEN_UNKNOWN;
00341     }
00342 
00343     return token->len;
00344 }
00345 
00346 /* 7.6.1 <COMMAND PROGRAM HEADER> */
00347 
00348 /**
00349  * Skip command program header \*<PROGRAM MNEMONIC>
00350  * @param state
00351  * @return 
00352  */
00353 static int skipCommonProgramHeader(lex_state_t * state) {
00354     int res;
00355     if (skipStar(state)) {
00356         res = skipProgramMnemonic(state);
00357         if (res == SKIP_NONE && iseos(state)) {
00358             return SKIP_INCOMPLETE;
00359         } else if (res <= SKIP_INCOMPLETE) {
00360             return SKIP_OK;
00361         } else if (res >= SKIP_OK) {
00362             return SKIP_OK;
00363         } else {
00364             return SKIP_INCOMPLETE;
00365         }
00366     }
00367     return SKIP_NONE;
00368 }
00369 
00370 /**
00371  * Skip compound program header :<PROGRAM MNEMONIC>:<PROGRAM MNEMONIC>...
00372  * @param state
00373  * @return 
00374  */
00375 static int skipCompoundProgramHeader(lex_state_t * state) {
00376     int res;
00377     int firstColon = skipColon(state);
00378 
00379     res = skipProgramMnemonic(state);
00380     if (res >= SKIP_OK) {
00381         while (skipColon(state)) {
00382             res = skipProgramMnemonic(state);
00383             if (res <= SKIP_INCOMPLETE) {
00384                 return SKIP_OK;
00385             } else if (res == SKIP_NONE) {
00386                 return SKIP_INCOMPLETE;
00387             }
00388         }
00389         return SKIP_OK;
00390     } else if (res <= SKIP_INCOMPLETE) {
00391         return SKIP_OK;
00392     } else if (firstColon) {
00393         return SKIP_INCOMPLETE;
00394     } else {
00395         return SKIP_NONE;
00396     }
00397 }
00398 
00399 /**
00400  * Detect token command or compound program header
00401  * @param state
00402  * @param token
00403  * @return 
00404  */
00405 int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) {
00406     int res;
00407     token->ptr = state->pos;
00408     token->type = SCPI_TOKEN_UNKNOWN;
00409 
00410     res = skipCommonProgramHeader(state);
00411     if (res >= SKIP_OK) {
00412         if (skipChr(state, '?') >= SKIP_OK) {
00413             token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER;
00414         } else {
00415             token->type = SCPI_TOKEN_COMMON_PROGRAM_HEADER;
00416         }
00417     } else if (res <= SKIP_INCOMPLETE) {
00418         token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER;
00419     } else if (res == SKIP_NONE) {
00420         res = skipCompoundProgramHeader(state);
00421 
00422         if (res >= SKIP_OK) {
00423             if (skipChr(state, '?') >= SKIP_OK) {
00424                 token->type = SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER;
00425             } else {
00426                 token->type = SCPI_TOKEN_COMPOUND_PROGRAM_HEADER;
00427             }
00428         } else if (res <= SKIP_INCOMPLETE) {
00429             token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER;
00430         }
00431     }
00432 
00433     if (token->type != SCPI_TOKEN_UNKNOWN) {
00434         token->len = state->pos - token->ptr;
00435     } else {
00436         token->len = 0;
00437         state->pos = token->ptr;
00438     }
00439 
00440     return token->len;
00441 }
00442 
00443 /* 7.7.1 <CHARACTER PROGRAM DATA> */
00444 
00445 /**
00446  * Detect token "Character program data"
00447  * @param state
00448  * @param token
00449  * @return 
00450  */
00451 int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) {
00452     token->ptr = state->pos;
00453 
00454     if (!iseos(state) && isalpha(state->pos[0])) {
00455         state->pos++;
00456         while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) {
00457             state->pos++;
00458         }
00459     }
00460 
00461     token->len = state->pos - token->ptr;
00462     if (token->len > 0) {
00463         token->type = SCPI_TOKEN_PROGRAM_MNEMONIC;
00464     } else {
00465         token->type = SCPI_TOKEN_UNKNOWN;
00466     }
00467 
00468     return token->len;
00469 }
00470 
00471 /* 7.7.2 <DECIMAL NUMERIC PROGRAM DATA> */
00472 static int skipMantisa(lex_state_t * state) {
00473     int someNumbers = 0;
00474 
00475     skipPlusmn(state);
00476 
00477     someNumbers += skipNumbers(state);
00478 
00479     if (skipChr(state, '.')) {
00480         someNumbers += skipNumbers(state);
00481     }
00482 
00483     return someNumbers;
00484 }
00485 
00486 static int skipExponent(lex_state_t * state) {
00487     int someNumbers = 0;
00488 
00489     if (!iseos(state) && isE(state->pos[0])) {
00490         state->pos++;
00491 
00492         skipWs(state);
00493 
00494         skipPlusmn(state);
00495 
00496         someNumbers = skipNumbers(state);
00497     }
00498 
00499     return someNumbers;
00500 }
00501 
00502 /**
00503  * Detect token Decimal number
00504  * @param state
00505  * @param token
00506  * @return 
00507  */
00508 int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) {
00509     char * rollback;
00510     token->ptr = state->pos;
00511 
00512     if (skipMantisa(state)) {
00513         rollback = state->pos;
00514         skipWs(state);
00515         if (!skipExponent(state)) {
00516             state->pos = rollback;
00517         }
00518     } else {
00519         state->pos = token->ptr;
00520     }
00521 
00522     token->len = state->pos - token->ptr;
00523     if (token->len > 0) {
00524         token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA;
00525     } else {
00526         token->type = SCPI_TOKEN_UNKNOWN;
00527     }
00528 
00529     return token->len;
00530 }
00531 
00532 /* 7.7.3 <SUFFIX PROGRAM DATA> */
00533 int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) {
00534     token->ptr = state->pos;
00535 
00536     skipChr(state, '/');
00537 
00538     // TODO: strict parsing  : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))*
00539     if (skipAlpha(state)) {
00540         skipChr(state, '-');
00541         skipDigit(state);
00542 
00543         while (skipSlashDot(state)) {
00544             skipAlpha(state);
00545             skipChr(state, '-');
00546             skipDigit(state);
00547         }
00548     }
00549 
00550     token->len = state->pos - token->ptr;
00551     if ((token->len > 0)) {
00552         token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA;
00553     } else {
00554         token->type = SCPI_TOKEN_UNKNOWN;
00555         state->pos = token->ptr;
00556         token->len = 0;
00557     }
00558 
00559     return token->len;
00560 }
00561 
00562 /* 7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA> */
00563 static int skipHexNum(lex_state_t * state) {
00564     int someNumbers = 0;
00565     while (!iseos(state) && isxdigit(state->pos[0])) {
00566         state->pos++;
00567         someNumbers++;
00568     }
00569     return someNumbers;
00570 }
00571 
00572 static int skipOctNum(lex_state_t * state) {
00573     int someNumbers = 0;
00574     while (!iseos(state) && isqdigit(state->pos[0])) {
00575         state->pos++;
00576         someNumbers++;
00577     }
00578     return someNumbers;
00579 }
00580 
00581 static int skipBinNum(lex_state_t * state) {
00582     int someNumbers = 0;
00583     while (!iseos(state) && isbdigit(state->pos[0])) {
00584         state->pos++;
00585         someNumbers++;
00586     }
00587     return someNumbers;
00588 }
00589 
00590 /**
00591  * Detect token nondecimal number
00592  * @param state
00593  * @param token
00594  * @return 
00595  */
00596 int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) {
00597     int someNumbers = 0;
00598     token->ptr = state->pos;
00599     if (skipChr(state, '#')) {
00600         if (!iseos(state)) {
00601             if (isH(state->pos[0])) {
00602                 state->pos++;
00603                 someNumbers = skipHexNum(state);
00604                 token->type = SCPI_TOKEN_HEXNUM;
00605             } else if (isQ(state->pos[0])) {
00606                 state->pos++;
00607                 someNumbers = skipOctNum(state);
00608                 token->type = SCPI_TOKEN_OCTNUM;
00609             } else if (isB(state->pos[0])) {
00610                 state->pos++;
00611                 someNumbers = skipBinNum(state);
00612                 token->type = SCPI_TOKEN_BINNUM;
00613             }
00614         }
00615     }
00616 
00617     if (someNumbers) {
00618         token->ptr += 2; // ignore number prefix
00619         token->len = state->pos - token->ptr;
00620     } else {
00621         token->type = SCPI_TOKEN_UNKNOWN;
00622         state->pos = token->ptr;
00623         token->len = 0;
00624     }
00625     return token->len > 0 ? token->len + 2 : 0;
00626 }
00627 
00628 /* 7.7.5 <STRING PROGRAM DATA> */
00629 static int isascii7bit(int c) {
00630     return (c >= 0) && (c <= 0x7f);
00631 }
00632 
00633 static void skipQuoteProgramData(lex_state_t * state, char quote) {
00634     while (!iseos(state)) {
00635         if (isascii7bit(state->pos[0]) && !ischr(state, quote)) {
00636             state->pos++;
00637         } else if (ischr(state, quote)) {
00638             state->pos++;
00639             if (!iseos(state) && ischr(state, quote)) {
00640                 state->pos++;
00641             } else {
00642                 state->pos--;
00643                 break;
00644             }
00645         }
00646     }
00647 }
00648 
00649 static void skipDoubleQuoteProgramData(lex_state_t * state) {
00650     skipQuoteProgramData(state, '"');
00651 }
00652 
00653 static void skipSingleQuoteProgramData(lex_state_t * state) {
00654     skipQuoteProgramData(state, '\'');
00655 }
00656 
00657 /**
00658  * Detect token String data
00659  * @param state
00660  * @param token
00661  * @return 
00662  */
00663 int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) {
00664     token->ptr = state->pos;
00665 
00666     if (!iseos(state)) {
00667         if (ischr(state, '"')) {
00668             state->pos++;
00669             token->type = SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA;
00670             skipDoubleQuoteProgramData(state);
00671             if (!iseos(state) && ischr(state, '"')) {
00672                 state->pos++;
00673                 token->len = state->pos - token->ptr;
00674             } else {
00675                 state->pos = token->ptr;
00676             }
00677         } else if (ischr(state, '\'')) {
00678             state->pos++;
00679             token->type = SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA;
00680             skipSingleQuoteProgramData(state);
00681             if (!iseos(state) && ischr(state, '\'')) {
00682                 state->pos++;
00683                 token->len = state->pos - token->ptr;
00684             } else {
00685                 state->pos = token->ptr;
00686             }
00687         }
00688     }
00689 
00690     token->len = state->pos - token->ptr;
00691 
00692     if ((token->len > 0)) {
00693         token->ptr++;
00694         token->len -= 2;
00695     } else {
00696         token->type = SCPI_TOKEN_UNKNOWN;
00697         state->pos = token->ptr;
00698         token->len = 0;
00699     }
00700 
00701     return token->len > 0 ? token->len + 2 : 0;
00702 }
00703 
00704 /* 7.7.6 <ARBITRARY BLOCK PROGRAM DATA> */
00705 static int isNonzeroDigit(int c) {
00706     return isdigit(c) && (c != '0');
00707 }
00708 
00709 /**
00710  * Detect token Block Data
00711  * @param state
00712  * @param token
00713  * @return 
00714  */
00715 int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) {
00716     int i;
00717     int arbitraryBlockLength = 0;
00718     const char * ptr = state->pos;
00719     int validData = -1;
00720     token->ptr = state->pos;
00721 
00722     if (skipChr(state, '#')) {
00723         if (!iseos(state) && isNonzeroDigit(state->pos[0])) {
00724             /* Get number of digits */
00725             i = state->pos[0] - '0';
00726             state->pos++;
00727 
00728             for (; i > 0; i--) {
00729                 if (!iseos(state) && isdigit(state->pos[0])) {
00730                     arbitraryBlockLength *= 10;
00731                     arbitraryBlockLength += (state->pos[0] - '0');
00732                     state->pos++;
00733                 } else {
00734                     break;
00735                 }
00736             }
00737 
00738             if (i == 0) {
00739                 state->pos += arbitraryBlockLength;
00740                 if ((state->buffer + state->len) >= (state->pos)) {
00741                     token->ptr = state->pos - arbitraryBlockLength;
00742                     token->len = arbitraryBlockLength;
00743                     validData = 1;
00744                 }
00745             } else if (iseos(state)) {
00746                 validData = 0;
00747             }
00748         } else if (iseos(state)) {
00749             validData = 0;
00750         }
00751     }
00752 
00753     if (validData == 1) {
00754         // valid
00755         token->type = SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA;
00756     } else if (validData == 0) {
00757         // incomplete
00758         token->type = SCPI_TOKEN_UNKNOWN;
00759         token->len = 0;
00760         state->pos = state->buffer + state->len;
00761     } else {
00762         // invalid
00763         token->type = SCPI_TOKEN_UNKNOWN;
00764         state->pos = token->ptr;
00765         token->len = 0;
00766     }
00767 
00768     return token->len + (token->ptr - ptr);
00769 }
00770 
00771 /* 7.7.7 <EXPRESSION PROGRAM DATA> */
00772 static int isProgramExpression(int c) {
00773     if ((c >= 0x20) && (c <= 0x7e)) {
00774         if ((c != 0x22)
00775                 && (c != 0x23)
00776                 && (c != 0x27)
00777                 && (c != 0x28)
00778                 && (c != 0x29)
00779                 && (c != 0x3B)) {
00780             return 1;
00781         }
00782     }
00783 
00784     return 0;
00785 }
00786 
00787 static void skipProgramExpression(lex_state_t * state) {
00788     while (!iseos(state) && isProgramExpression(state->pos[0])) {
00789         state->pos++;
00790     }
00791 }
00792 
00793 // TODO: 7.7.7.2-2 recursive - any program data
00794 
00795 /**
00796  * Detect token Expression
00797  * @param state
00798  * @param token
00799  * @return 
00800  */
00801 int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) {
00802     token->ptr = state->pos;
00803 
00804     if (!iseos(state) && ischr(state, '(')) {
00805         state->pos++;
00806         skipProgramExpression(state);
00807 
00808         if (!iseos(state) && ischr(state, ')')) {
00809             state->pos++;
00810             token->len = state->pos - token->ptr;
00811         } else {
00812             token->len = 0;
00813         }
00814     }
00815 
00816     if ((token->len > 0)) {
00817         token->type = SCPI_TOKEN_PROGRAM_EXPRESSION;
00818     } else {
00819         token->type = SCPI_TOKEN_UNKNOWN;
00820         state->pos = token->ptr;
00821         token->len = 0;
00822     }
00823 
00824     return token->len;
00825 }
00826 
00827 /**
00828  * Detect token comma
00829  * @param state
00830  * @param token
00831  * @return 
00832  */
00833 int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) {
00834     token->ptr = state->pos;
00835 
00836     if (skipChr(state, ',')) {
00837         token->len = 1;
00838         token->type = SCPI_TOKEN_COMMA;
00839     } else {
00840         token->len = 0;
00841         token->type = SCPI_TOKEN_UNKNOWN;
00842     }
00843 
00844     return token->len;
00845 }
00846 
00847 /**
00848  * Detect token semicolon
00849  * @param state
00850  * @param token
00851  * @return 
00852  */
00853 int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) {
00854     token->ptr = state->pos;
00855 
00856     if (skipChr(state, ';')) {
00857         token->len = 1;
00858         token->type = SCPI_TOKEN_SEMICOLON;
00859     } else {
00860         token->len = 0;
00861         token->type = SCPI_TOKEN_UNKNOWN;
00862     }
00863 
00864     return token->len;
00865 }
00866 
00867 /**
00868  * Detect token New line
00869  * @param state
00870  * @param token
00871  * @return 
00872  */
00873 int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) {
00874     token->ptr = state->pos;
00875 
00876     skipChr(state, '\r');
00877     skipChr(state, '\n');
00878 
00879     token->len = state->pos - token->ptr;
00880 
00881     if ((token->len > 0)) {
00882         token->type = SCPI_TOKEN_NL;
00883     } else {
00884         token->type = SCPI_TOKEN_UNKNOWN;
00885         state->pos = token->ptr;
00886         token->len = 0;
00887     }
00888 
00889     return token->len;
00890 }