Jan Breuer
2014-09-24 7755a1c3bfca65316d0d7ff6648d4ef8e08e1856
libscpi/src/parser.c
@@ -39,9 +39,10 @@
#include "scpi/config.h"
#include "scpi/parser.h"
#include "scpi/lexer.h"
#include "utils.h"
#include "parser_private.h"
#include "lexer_private.h"
#include "scpi/error.h"
#include "scpi/constants.h"
/**
 * Write data to SCPI output
@@ -74,7 +75,7 @@
 */
static size_t writeDelimiter(scpi_t * context) {
    if (context->output_count > 0) {
        return writeData(context, ", ", 2);
        return writeData(context, ",", 2);
    } else {
        return 0;
    }
@@ -130,7 +131,7 @@
 * @param context
 * @result TRUE if context->paramlist is filled with correct values
 */
static bool_t findCommandHeader(scpi_t * context, const char * header, int len) {
static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) {
    int32_t i;
    const scpi_command_t * cmd;
@@ -165,14 +166,19 @@
    while (1) {
        result = 0;
        r = SCPI_DetectProgramMessageUnit(state, data, len);
        r = detectProgramMessageUnit(state, data, len);
        if (state->programHeader.len > 0) {
        if (state->programHeader.type == TokInvalid) {
            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER);
        } else if (state->programHeader.len > 0) {
            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);
@@ -201,6 +207,19 @@
 * @param interface
 */
void SCPI_Init(scpi_t * context) {
    if (context->idn[0] == NULL) {
        context->idn[0] = SCPI_DEFAULT_1_MANUFACTURE;
    }
    if (context->idn[1] == NULL) {
        context->idn[1] = SCPI_DEFAULT_2_MODEL;
    }
    if (context->idn[2] == NULL) {
        context->idn[2] = SCPI_DEFAULT_3;
    }
    if (context->idn[3] == NULL) {
        context->idn[3] = SCPI_DEFAULT_4_REVISION;
    }
    context->buffer.position = 0;
    SCPI_ErrorInit(context);
}
@@ -237,7 +256,7 @@
        while (1) {
            cmdlen = SCPI_DetectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
            cmdlen = detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
            totcmdlen += cmdlen;
            if (context->parser_state.termination == PmutNewLine) break;
            if (context->parser_state.programHeader.type == TokUnknown) break;
@@ -340,9 +359,20 @@
    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_ResultIntBase(context, val ? 1 : 0, 10);
}
/* parsing parameters */
bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, bool_t mandatory) {
scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) {
    token_t token;
    lex_state_t * state;
    int32_t value;
@@ -367,7 +397,7 @@
        return FALSE;
    }
    if (context->input_count != 0) {
        SCPI_LexComma(state, &token);
        lexComma(state, &token);
        if (token.type != TokComma) {
            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR);
            return FALSE;
@@ -376,7 +406,7 @@
    context->input_count++;
    SCPI_ParseProgramData(&context->param_list.lex_state, &token);
    parseProgramData(&context->param_list.lex_state, &token);
    parameter->type = token.type;
    parameter->data.ptr = token.ptr;
@@ -420,7 +450,7 @@
            parameter->type = TokUnknown;
            parameter->data.ptr = NULL;
            parameter->data.len = 0;
            SCPI_ErrorPush(context, SCPI_ERROR_UNKNOWN_PARAMETER);
            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_STRING_DATA);
            return FALSE;
    }
}
@@ -434,7 +464,7 @@
        case TokDecimalNumericProgramDataWithSuffix:
            return parameter->number.value;
        default:
            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_PARAMETER);
            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
            return 0;
    }
}
@@ -448,21 +478,67 @@
    *len = parameter->data.len;
}
int SCPI_ParseProgramData(lex_state_t * state, token_t * token) {
/* SCPI-99 7.3 Boolean Program Data */
scpi_bool_t SCPI_ParamGetBoolVal(scpi_t * context, scpi_parameter_t * parameter) {
    switch (parameter->type) {
        case TokDecimalNumericProgramData:
            return parameter->number.value ? 1 : 0;
        case TokProgramMnemonic:
            if (compareStr("ON", 2, parameter->data.ptr, parameter->data.len)) {
                return TRUE;
            } else if (compareStr("OFF", 3, parameter->data.ptr, parameter->data.len)) {
                return FALSE;
            } else {
                SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
                return FALSE;
            }
        default:
            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
            return FALSE;
    }
}
/**
 * Get choice parameter
 */
int32_t SCPI_ParamGetChoiceVal(scpi_t * context, scpi_parameter_t * parameter, const char * options[]) {
    size_t res;
    if (!options) {
        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
        return -1;
    }
    switch(parameter->type) {
        case TokProgramMnemonic:
            for (res = 0; options[res]; ++res) {
                if (matchPattern(options[res], strlen(options[res]), parameter->data.ptr, parameter->data.len)) {
                    return res;
                }
            }
            SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
            return -1;
        default:
            SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
            return -1;
    }
}
int parseProgramData(lex_state_t * state, token_t * token) {
    token_t tmp;
    int result = 0;
    int wsLen;
    int suffixLen;
    int realLen = 0;
    realLen += SCPI_LexWhiteSpace(state, &tmp);
    realLen += lexWhiteSpace(state, &tmp);
    if (result == 0) result = SCPI_LexNondecimalNumericData(state, token);
    if (result == 0) result = SCPI_LexCharacterProgramData(state, token);
    if (result == 0) result = lexNondecimalNumericData(state, token);
    if (result == 0) result = lexCharacterProgramData(state, token);
    if (result == 0) {
        result = SCPI_LexDecimalNumericProgramData(state, token);
        result = lexDecimalNumericProgramData(state, token);
        if (result != 0) {
            wsLen = SCPI_LexWhiteSpace(state, &tmp);
            suffixLen = SCPI_LexSuffixProgramData(state, &tmp);
            wsLen = lexWhiteSpace(state, &tmp);
            suffixLen = lexSuffixProgramData(state, &tmp);
            if (suffixLen > 0) {
                token->len += wsLen + suffixLen;
                token->type = TokDecimalNumericProgramDataWithSuffix;
@@ -471,16 +547,16 @@
        }
    }
    if (result == 0) result = SCPI_LexStringProgramData(state, token);
    if (result == 0) result = SCPI_LexArbitraryBlockProgramData(state, token);
    if (result == 0) result = SCPI_LexProgramExpression(state, token);
    if (result == 0) result = lexStringProgramData(state, token);
    if (result == 0) result = lexArbitraryBlockProgramData(state, token);
    if (result == 0) result = lexProgramExpression(state, token);
    realLen += SCPI_LexWhiteSpace(state, &tmp);
    realLen += lexWhiteSpace(state, &tmp);
    return result + realLen;
}
int SCPI_ParseAllProgramData(lex_state_t * state, token_t * token, int * numberOfParameters) {
int parseAllProgramData(lex_state_t * state, token_t * token, int * numberOfParameters) {
    int result;
    token_t tmp;
@@ -491,7 +567,7 @@
    token->ptr = state->pos;
    for (result = 1; result != 0; result = SCPI_LexComma(state, &tmp)) {
    for (result = 1; result != 0; result = lexComma(state, &tmp)) {
        token->len += result;
        if (result == 0) {
@@ -501,7 +577,7 @@
            break;
        }
        result = SCPI_ParseProgramData(state, &tmp);
        result = parseProgramData(state, &tmp);
        if (tmp.type != TokUnknown) {
            token->len += result;
        } else {
@@ -523,39 +599,46 @@
    return token->len;
}
int SCPI_DetectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) {
static void invalidateToken(token_t * token, const char * ptr) {
    token->len = 0;
    token->ptr = ptr;
    token->type = TokUnknown;
}
int detectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) {
    lex_state_t lex_state;
    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 */
    SCPI_LexWhiteSpace(&lex_state, &tmp);
    lexWhiteSpace(&lex_state, &tmp);
    if (SCPI_LexProgramHeader(&lex_state, &state->programHeader) >= 0) {
        if (SCPI_LexWhiteSpace(&lex_state, &tmp) > 0) {
            SCPI_ParseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters);
    if (lexProgramHeader(&lex_state, &state->programHeader) >= 0) {
        if (lexWhiteSpace(&lex_state, &tmp) > 0) {
            parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters);
        } else {
            state->programData.len = 0;
            state->programData.ptr = lex_state.pos;
            state->programData.type = TokUnknown;
            state->numberOfParameters = 0;
            invalidateToken(&state->programData, lex_state.pos);
        }
    } else {
        state->programHeader.len = 0;
        state->programData.ptr = lex_state.buffer;
        state->programHeader.type = TokUnknown;
        state->programData.len = 0;
        state->programData.ptr = lex_state.buffer;
        state->programData.type = TokUnknown;
        state->numberOfParameters = 0;
        invalidateToken(&state->programHeader, lex_state.buffer);
        invalidateToken(&state->programData, lex_state.buffer);
    }
    if (result == 0) result = SCPI_LexNewLine(&lex_state, &tmp);
    if (result == 0) result = SCPI_LexSemicolon(&lex_state, &tmp);
    if (result == 0) result = lexNewLine(&lex_state, &tmp);
    if (result == 0) result = lexSemicolon(&lex_state, &tmp);
    if (!lexIsEos(&lex_state) && (result == 0)) {
        lex_state.pos++;
        state->programHeader.len = 1;
        state->programHeader.type = TokInvalid;
        invalidateToken(&state->programData, lex_state.buffer);
    }
    if (TokSemicolon == tmp.type) {
        state->termination = PmutSemicolon;