/*
 * Internal buffer looks like this.
 *   num[0] op[0] num[1] op[1] num[2]
 * If priority of op[0] is higher than op[1], (num[0] op[0] num[1]) is computed,
 * otherwise (num[1] op[1] num[2]) is computed.
 * Then, the next op and num is read from the script.
 * Num is an immediate value, a variable or a bracketed expression.
 */
void ScriptHandler::readNextOp(const char** buf, int* op, int* num)
{
    bool minus_flag = false;
    SKIP_SPACE(*buf);
    const char* buf_start = *buf;

    if (op) {
        if ((*buf)[0] == '+') *op = OP_PLUS;
        else if ((*buf)[0] == '-') *op = OP_MINUS;
        else if ((*buf)[0] == '*') *op = OP_MULT;
        else if ((*buf)[0] == '/') *op = OP_DIV;
        else if ((*buf)[0] == 'm'
                 && (*buf)[1] == 'o'
                 && (*buf)[2] == 'd'
                 && ((*buf)[3] == ' '
                     || (*buf)[3] == '\t'
                     || (*buf)[3] == '$'
                     || (*buf)[3] == '%'
                     || (*buf)[3] == '?'
                     || ((*buf)[3] >= '0' && (*buf)[3] <= '9')))
            *op = OP_MOD;
        else {
            *op = OP_INVALID;
            return;
        }

        if (*op == OP_MOD) *buf += 3;
        else (*buf)++;

        SKIP_SPACE(*buf);
    }
    else {
        if ((*buf)[0] == '-') {
            minus_flag = true;
            (*buf)++;
            SKIP_SPACE(*buf);
        }
    }

    if ((*buf)[0] == '(') {
        (*buf)++;
        *num = parseIntExpression(buf);
        if (minus_flag) *num = -*num;

        SKIP_SPACE(*buf);
        if ((*buf)[0] != ')') errorAndExit(") is not found.");

        (*buf)++;
    }
    else {
        *num = parseInt(buf);
        if (minus_flag) *num = -*num;

        if (current_variable.type == VAR_NONE) {
            if (op) *op = OP_INVALID;

            *buf = buf_start;
        }
    }
}
int ScriptHandler::readInt()
{
    string_buffer.trunc(0);

    end_status = END_NONE;
    current_variable.type = VAR_NONE;

    current_script = next_script;
    SKIP_SPACE(current_script);
    const char* buf = current_script;

    int ret = parseIntExpression(&buf);

    next_script = checkComma(buf);

    return ret;
}
int StereotypeDefinitionParser::parseIntExpression()
{
    Token token;
    token = d->m_scanner->read();
    if (token.type() == Token::TokenOperator && token.subtype() == OPERATOR_MINUS) {
        return -parseIntExpression();
    } else {
        bool ok = false;
        if (token.type() == Token::TokenInteger) {
            int value = token.text().toInt(&ok);
            QMT_CHECK(ok);
            return value;
        } else {
            throw StereotypeDefinitionParserError(QStringLiteral("Expected integer constant."), token.sourcePos());
        }
    }
}
ScriptHandler::array_ref ScriptHandler::parseArray(const char** buf)
{
    SKIP_SPACE(*buf);

    (*buf)++; // skip '?'
    int no = parseInt(buf);

    SKIP_SPACE(*buf);
    
    h_index_t indices;
    
    while (**buf == '[') {
        (*buf)++;
	indices.push_back(parseIntExpression(buf));
        SKIP_SPACE(*buf);
        if (**buf != ']') errorAndExit("parseArray: no ']' is found.");
        (*buf)++;
    }
    return std::make_pair(no, indices);
}
int ScriptHandler::parseArray( char **buf, struct ArrayVariable &array )
{
    SKIP_SPACE( *buf );
    
    (*buf)++; // skip '?'
    int no = parseInt( buf );

    SKIP_SPACE( *buf );
    array.num_dim = 0;
    while ( **buf == '[' ){
        (*buf)++;
        array.dim[array.num_dim] = parseIntExpression(buf);
        array.num_dim++;
        SKIP_SPACE( *buf );
        if ( **buf != ']' ) errorAndExit( "parseArray: missing ']'." );
        (*buf)++;
    }
    for ( int i=array.num_dim ; i<20 ; i++ ) array.dim[i] = 0;

    return no;
}
int StereotypeDefinitionParser::parseIntProperty()
{
    expectColon();
    return parseIntExpression();
}