#ifndef WIN
#pragma warning (disable: 4786) // disable warning for STL maps
#include <unistd.h>
#else
#include <platform.h>
#endif /* WIN */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
//#if WIN
//#define _TIMEVAL_DEFINED
//#endif
#include <time.h>

#ifdef DPQT
#include <QWriteLocker>
#include "events.h"
#include "QFitsMainWindow.h"
#include "QFitsGlobal.h"
#endif /* DPQT */

#include "dpstring.h"
#include "dpstringlist.h"
#include "dpComplex.h"
#include "fits.h"
#include "dpuser.h"
#include "dpuser.yacchelper.h"
#include "dpuser.procs.h"
#include "dpuser.pgplot.h"
#include "dpuser_funcs.h"
#include "dpuser_utils.h"
#include "dpuser2c/dpuserType.h"
#include "dpuser2c/utils.h"
#include "gsl/gsl_math.h"
#include "JulianDay.h"
#include "y.tab.h"

extern conValue *oldVars;
extern char **sOldVars;
extern int nOldVars;

int looplock = 0;

bool checkFITSsize(conValue *arg1, conValue *arg2) {
    int n[4] = {0, 0, 0, 0}, m[4] = {0, 0, 0, 0}, i;
    bool rv = TRUE;

    if (((arg1->type == typeFits) || (arg1->type == typeFitsFile)) && ((arg2->type == typeFits) || (arg2->type == typeFitsFile))) {
        if (arg1->type == typeFits) {
            n[0] = arg1->fvalue->Naxis(0);
            n[1] = arg1->fvalue->Naxis(1);
            n[2] = arg1->fvalue->Naxis(2);
            n[3] = arg1->fvalue->Naxis(3);
        } else {
            int retint;
            Fits fvalue;

            rv = fvalue.OpenFITS(arg1->ffvalue->c_str());
            if (rv) {
                rv = (fvalue.hdr = fvalue.ReadFitsHeader() >= 0);
                fvalue.CloseFITS();
            }
            if (rv) {
                if (fvalue.GetIntKey("NAXIS", &retint)) {
                    n[0] = retint;
                }
                if (fvalue.GetIntKey("NAXIS1", &retint)) {
                    n[1] = retint;
                }
                if (fvalue.GetIntKey("NAXIS2", &retint)) {
                    n[2] = retint;
                }
                if (fvalue.GetIntKey("NAXIS3", &retint)) {
                    n[3] = retint;
                }
            }
        }
        if (arg2->type == typeFits) {
            m[0] = arg2->fvalue->Naxis(0);
            m[1] = arg2->fvalue->Naxis(1);
            m[2] = arg2->fvalue->Naxis(2);
            m[3] = arg2->fvalue->Naxis(3);
        } else {
            int retint;
            Fits fvalue;

            rv = fvalue.OpenFITS(arg2->ffvalue->c_str());
            if (rv) {
                rv = (fvalue.hdr = fvalue.ReadFitsHeader() >= 0);
                fvalue.CloseFITS();
            }
            if (rv) {
                if (fvalue.GetIntKey("NAXIS", &retint)) {
                    m[0] = retint;
                }
                if (fvalue.GetIntKey("NAXIS1", &retint)) {
                    m[1] = retint;
                }
                if (fvalue.GetIntKey("NAXIS2", &retint)) {
                    m[2] = retint;
                }
                if (fvalue.GetIntKey("NAXIS3", &retint)) {
                    m[3] = retint;
                }
            }
        }
        if (n[0] != m[0]) rv = FALSE;
        if (rv) for (i = 1; i <= n[0]; i++) {
            if (n[i] != m[i]) rv = FALSE;
        }
    }
    if (!rv) dp_output("The two arrays do not match in size\n");
    return rv;
}

conValue doArithmetic(conValue *arg1, int operation, conValue *arg2) {
    conValue result;
    result.type = typeUnknown;
    dpint64 n;

    if (operation == '+' || operation == '-' || operation == '*' || operation == '/') {
//        if (!checkFITSsize(arg1, arg2)) return result;
    }

    switch (operation) {
        case '+': switch (arg1->type) {
            case typeCon: switch(arg2->type) {
                case typeCon:
                    result.type = typeCon;
                    result.lvalue = arg1->lvalue + arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->lvalue + arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue += arg1->lvalue;
                    break;
                case typeStr:
                    result.type = typeStr;
                    result.svalue = CreateString(arg1->lvalue);
                    *result.svalue += *arg2->svalue;
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue += (double)arg1->lvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += (double)arg1->lvalue;
                    break;
                case typeStrarr:
                    dp_output("Cannot add a string array to an integer number\n");
                    break;
                default:
                    dp_output("Cannot add this type to an integer number\n");
                    break;
            }
                break;
            case typeDbl: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue + arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue + arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue += arg1->dvalue;
                    break;
                case typeStr:
                    result.type = typeStr;
                    result.svalue = CreateString(arg1->dvalue);
                    *result.svalue += *arg2->svalue;
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue += arg1->dvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += arg1->dvalue;
                    break;
                case typeStrarr:
                    dp_output("Cannot add a string array to a real number\n");
                    break;
                default:
                    dp_output("Cannot add this type to a real number\n");
                    break;
            }
                break;
            case typeCom: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.cvalue += arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.cvalue += arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.cvalue += *arg2->cvalue;
                    break;
                case typeStr:
                    result.type = typeStr;
                    result.svalue = CreateString(*arg1->cvalue);
                    *result.svalue += *arg2->svalue;
                    break;
                case typeFits:
            CloneValue(*arg2, &result);
            *result.fvalue += *arg1->cvalue;
                    break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue += *arg1->cvalue;
                    dp_output("Cannot add a FITS file to a complex number\n");
                    break;
                case typeStrarr:
                    dp_output("Cannot add a string array to a complex number\n");
                    break;
                default:
                    dp_output("Cannot add this type to a complex number\n");
                    break;
            }
                break;
            case typeStr: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.svalue += *CreateString(arg2->lvalue);
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.svalue += *CreateString(arg2->dvalue);
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.svalue += FormatComplexQString(*arg2->cvalue);
                    break;
                case typeStr:
                    CloneValue(*arg1, &result);
                    *result.svalue += *arg2->svalue;
                    break;
                case typeFits:
//                    CloneValue(*arg2, result);
//                    *result.fvalue += *arg1->cvalue;
                    dp_output("Cannot add a matrix to a string\n");
                    break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue += *arg1->cvalue;
                    dp_output("Cannot add a FITS file to a string\n");
                    break;
                case typeStrarr:
                    CloneValue(*arg2, &result);
                    result.arrvalue->prepend(*arg1->svalue);
                    break;
                default:
                    dp_output("Cannot add this type to a string\n");
                    break;
            }
                break;
            case typeFits: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.fvalue += (double)arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.fvalue += arg2->dvalue;
                    break;
                case typeCom:
            CloneValue(*arg1, &result);
            *result.fvalue += *arg2->cvalue;
            break;
                case typeStr:
                    dp_output("Cannot add a string to a matrix\n");
                    break;
                case typeFits:
                    if (arg1->fvalue->matches(*arg2->fvalue)) {
                        if (isVariable(arg1->fvalue) == 0) {
                            CloneValue(*arg1, &result);
                            *result.fvalue += *arg2->fvalue;
                        } else if (isVariable(arg2->fvalue) == 0) {
                            CloneValue(*arg2, &result);
                            *result.fvalue += *arg1->fvalue;
                        } else {
                            CloneValue(*arg1, &result);
                            *result.fvalue += *arg2->fvalue;
                        }
                    } else {
                        CloneValue(*arg1, &result);
                        *result.fvalue += *arg2->fvalue;
                    }
                    break;
                case typeFitsFile: {
                    Fits a;
                    result.type = typeFits;
                    CloneValue(*arg1, &result);
                    result.fvalue = CreateFits();
                    if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += a;
                }
                    break;
                case typeStrarr:
                    dp_output("Cannot add a string array to a matrix\n");
                    break;
                default:
                    dp_output("Cannot add this type to a matrix\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot add a complex number to a FITS file\n");
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//                    else *result.fvalue += *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot add a string to a FITS file\n");
                    break;
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue += *arg2->fvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else *result.fvalue += a;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot add a string array to a FITS file\n");
                    break;
                default:
                    dp_output("Cannot add this type to a FITS file\n");
                    break;
            }
                break;
            case typeStrarr: switch(arg2->type) {
                case typeCon:
                    dp_output("Cannot add an integer number to a string array\n");
                    break;
                case typeDbl:
                    dp_output("Cannot add a real number to a string array\n");
                    break;
                case typeCom:
                    dp_output("Cannot add a complex number to a string array\n");
                    break;
                case typeStr:
                    CloneValue(*arg1, &result);
                    result.arrvalue->append(*arg2->svalue);
                    break;
                case typeFits:
                    dp_output("Cannot add a matrix to a string array\n");
                    break;
                case typeFitsFile:
                    dp_output("Cannot add a FITS file to a string array\n");
                    break;
                case typeStrarr:
                    CloneValue(*arg1, &result);
                    for (n = 0; n < arg2->arrvalue->count(); n++) result.arrvalue->append((*arg2->arrvalue)[n]);
                    break;
                default:
                    dp_output("Cannot add this type to a string array\n");
                    break;
            }
                break;
            default:
                dp_output("Invalid arguments to operator '+'\n");
                break;
        }
            break;
        case '-': switch (arg1->type) {
            case typeCon: switch(arg2->type) {
                case typeCon:
                    result.type = typeCon;
                    result.lvalue = arg1->lvalue - arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->lvalue - arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue *= -1.;
                    *result.cvalue += arg1->lvalue;
                    break;
                case typeStr:
                    dp_output("Cannot subtract a string from an integer number\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue *= -1.;
                    *result.fvalue += (double)arg1->lvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        *result.fvalue *= -1.;
                        *result.fvalue += (double)arg1->lvalue;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot subtract a string array from an integer number\n");
                    break;
                default:
                    dp_output("Cannot subtract this type from an integer number\n");
                    break;
            }
                break;
            case typeDbl: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue - arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue - arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue *= -1.;
                    *result.cvalue += arg1->dvalue;
                    break;
                case typeStr:
                    dp_output("Cannot subtract a string from a real number\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue *= -1.;
                    *result.fvalue += arg1->dvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        *result.fvalue *= -1.;
                        *result.fvalue += arg1->dvalue;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot subtract a string array from a real number\n");
                    break;
                default:
                    dp_output("Cannot subtract this type from a real number\n");
                    break;
            }
                break;
            case typeCom: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.cvalue -= arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.cvalue -= arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.cvalue -= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot subtract a string from a complex number\n");
                    break;
                case typeFits:
            CloneValue(*arg2, &result);
            result.fvalue->setType(C16);
            for (n = 0; n < result.fvalue->Nelements(); n++) {
                result.fvalue->cdata[n].r = arg1->cvalue->real() - result.fvalue->cdata[n].r;
                result.fvalue->cdata[n].i = arg1->cvalue->imag() - result.fvalue->cdata[n].i;
            }
                    break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue += -*arg1->cvalue;
                    dp_output("Cannot subtract a FITS file from a complex number\n");
                    break;
                case typeStrarr:
                    dp_output("Cannot subtract a string array from a complex number\n");
                    break;
                default:
                    dp_output("Cannot subtract this type from a complex number\n");
                    break;
            }
                break;
            case typeStr:
                dp_output("Cannot subtract anything from a string\n");
                break;
            case typeFits: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.fvalue -= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.fvalue -= arg2->dvalue;
                    break;
                case typeCom:
            CloneValue(*arg1, &result);
            *result.fvalue -= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot subtract a string from a matrix\n");
                    break;
                case typeFits:
                    if (arg1->fvalue->matches(*arg2->fvalue)) {
                        if (isVariable(arg1->fvalue) == 0) {
                            CloneValue(*arg1, &result);
                            *result.fvalue -= *arg2->fvalue;
                        } else if (isVariable(arg2->fvalue) == 0) {
                            CloneValue(*arg2, &result);
                            *result.fvalue *= -1.;
                            *result.fvalue += *arg1->fvalue;
                        } else {
                            CloneValue(*arg1, &result);
                            *result.fvalue -= *arg2->fvalue;
                        }
                    } else {
                        CloneValue(*arg1, &result);
                        *result.fvalue -= *arg2->fvalue;
                    }
                    break;
                case typeFitsFile: {
                    Fits a;
                    result.type = typeFits;
                    CloneValue(*arg1, &result);
                    if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue -= a;
                }
                    break;
                case typeStrarr:
                    dp_output("Cannot subtract a string array from a matrix\n");
                    break;
                default:
                    dp_output("Cannot subtract this type from a matrix\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue -= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue -= arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot subtract a complex number from a FITS file\n");
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//                    else *result.fvalue -= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot subtract a string from a FITS file\n");
                    break;
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue -= *arg2->fvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else *result.fvalue -= a;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot subtract a string array from a FITS file\n");
                    break;
                default:
                    dp_output("Cannot subtract this type from a FITS file\n");
                    break;
            }
                break;
            case typeStrarr:
                dp_output("Cannot subtract anything from a string array\n");
                break;
            default:
                dp_output("Invalid arguments to operator '-'\n");
                break;
        }
            break;

        case '*': switch (arg1->type) {
            case typeCon: switch(arg2->type) {
                case typeCon:
                    result.type = typeCon;
                    result.lvalue = arg1->lvalue * arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->lvalue * arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue *= arg1->lvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to an integer number\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue *= (double)arg1->lvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= (double)arg1->lvalue;
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to an integer number\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to an integer number\n");
                    break;
            }
                break;
            case typeDbl: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue * arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue * arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue *= arg1->dvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a real number\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    *result.fvalue *= arg1->dvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= arg1->dvalue;
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a real number\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a real number\n");
                    break;
            }
                break;
            case typeCom: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a complex number\n");
                    break;
                case typeFits:
            CloneValue(*arg2, &result);
            *result.fvalue *= *arg1->cvalue;
                    break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue *= *arg1->cvalue;
                    dp_output("Cannot multiply a FITS file to a complex number\n");
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a complex number\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a complex number\n");
                    break;
            }
                break;
            case typeStr:
                dp_output("Cannot multiply anything to a string\n");
                break;
            case typeFits: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.fvalue *= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.fvalue *= arg2->dvalue;
                    break;
                case typeCom:
            CloneValue(*arg1, &result);
            *result.fvalue *= *arg2->cvalue;
            break;
                case typeStr:
                    dp_output("Cannot multiply a string to a matrix\n");
                    break;
                case typeFits:
                    if (arg1->fvalue->matches(*arg2->fvalue)) {
                        if (isVariable(arg1->fvalue) == 0) {
                            CloneValue(*arg1, &result);
                            *result.fvalue *= *arg2->fvalue;
                        } else if (isVariable(arg2->fvalue) == 0) {
                            CloneValue(*arg2, &result);
                            *result.fvalue *= *arg1->fvalue;
                        } else {
                            CloneValue(*arg1, &result);
                            *result.fvalue *= *arg2->fvalue;
                        }
                    } else {
                        CloneValue(*arg1, &result);
                        *result.fvalue *= *arg2->fvalue;
                    }
                    break;
                case typeFitsFile: {
                    Fits a;
                    result.type = typeFits;
                    CloneValue(*arg1, &result);
                    if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= a;
                }
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a matrix\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a matrix\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot multiply a complex number to a FITS file\n");
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//                    else *result.fvalue *= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a FITS file\n");
                    break;
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= *arg2->fvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else *result.fvalue *= a;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a FITS file\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a FITS file\n");
                    break;
            }
                break;
            case typeStrarr:
                dp_output("Cannot multiply anything to a string array\n");
                break;
            default:
                dp_output("Invalid arguments to operator '*'\n");
                break;
        }
            break;

        case '/': switch (arg1->type) {
            case typeCon: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = (double)arg1->lvalue / (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->lvalue / arg2->dvalue;
                    break;
                case typeCom:
                    result.type = typeCom;
                    result.cvalue = CreateComplex();
                    *result.cvalue = arg1->lvalue / *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot divide an integer number by a string\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    result.fvalue->invert();
                    *result.fvalue *= (double)arg1->lvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        result.fvalue->invert();
                        *result.fvalue *= (double)arg1->lvalue;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot divide an integer number by a string array\n");
                    break;
                default:
                    dp_output("Cannot divide an integer number by this type\n");
                    break;
            }
                break;
            case typeDbl: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue / arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = arg1->dvalue / arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg2, &result);
                    *result.cvalue = arg1->dvalue / *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot divide a real number by a string\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    result.fvalue->invert();
                    *result.fvalue *= arg1->dvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        result.fvalue->invert();
                        *result.fvalue *= arg1->dvalue;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot divide a real number by a string array\n");
                    break;
                default:
                    dp_output("Cannot divide a real number by this type\n");
                    break;
            }
                break;
            case typeCom: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.cvalue /= arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.cvalue /= arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.cvalue /= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot divide a complex number by a string\n");
                    break;
                case typeFits:
            CloneValue(*arg2, &result);
            result.fvalue->setType(C16);
            double rr, ii, div;
            for (n = 0; n < result.fvalue->Nelements(); n++) {
                rr = result.fvalue->cdata[n].r;
                ii = result.fvalue->cdata[n].i;
                div = pow(rr, 2) + pow(ii,2);

                result.fvalue->cdata[n].r = (rr * arg1->cvalue->real() + ii * arg1->cvalue->imag()) / div;
                result.fvalue->cdata[n].i = (rr * arg1->cvalue->imag() - ii * arg1->cvalue->real()) / div;
            }
            break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue += -*arg1->cvalue;
                    dp_output("Cannot divide a complex number by a FITS file\n");
                    break;
                case typeStrarr:
                    dp_output("Cannot divide a complex number by a string array\n");
                    break;
                default:
                    dp_output("Cannot divide a complex number by this type\n");
                    break;
            }
                break;
            case typeStr:
                dp_output("Cannot divide a string by anything\n");
                break;
            case typeFits: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.fvalue /= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.fvalue /= arg2->dvalue;
                    break;
                case typeCom:
            CloneValue(*arg1, &result);
            *result.fvalue /= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot divide a matrix by a string\n");
                    break;
                case typeFits:
                    if (arg1->fvalue->matches(*arg2->fvalue)) {
                        if (isVariable(arg1->fvalue) == 0) {
                            CloneValue(*arg1, &result);
                            *result.fvalue /= *arg2->fvalue;
                        } else if (isVariable(arg2->fvalue) == 0) {
                            CloneValue(*arg2, &result);
                            result.fvalue->invert();
                            *result.fvalue *= *arg1->fvalue;
                        } else {
                            CloneValue(*arg1, &result);
                            *result.fvalue /= *arg2->fvalue;
                        }
                    } else {
                        CloneValue(*arg1, &result);
                                                *result.fvalue /= *arg2->fvalue;
                    }
                    break;
                case typeFitsFile: {
                    Fits a;
                    result.type = typeFits;
                    CloneValue(*arg1, &result);
                    if (a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue /= a;
                }
                    break;
                case typeStrarr:
                    dp_output("Cannot divide a matrix by a string array\n");
                    break;
                default:
                    dp_output("Cannot divide a matrix by this type\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue /= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue /= arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot divide a FITS file by a complex number\n");
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//                    else *result.fvalue /= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot divide a FITS file by a string\n");
                    break;
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue /= *arg2->fvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else *result.fvalue /= a;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot divide a FITS file by a string array\n");
                    break;
                default:
                    dp_output("Cannot divide a FITS file by this type\n");
                    break;
            }
                break;
            case typeStrarr:
                dp_output("Cannot divide a string array by anything\n");
                break;
            default:
                dp_output("Invalid arguments to operator '/'\n");
                break;
        }
            break;
/* START: dead code */
        case '^': switch (arg1->type) {
            case typeCon: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = pow((double)arg1->lvalue, (double)arg2->lvalue);
                    if (!gsl_finite(result.dvalue)) {
                        result.type = typeCom;
                        result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->lvalue), dpComplex(arg2->lvalue)));
                    }
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = pow(arg1->lvalue, arg2->dvalue);
                    if (!gsl_finite(result.dvalue)) {
                        result.type = typeCom;
                        result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->lvalue), dpComplex(arg2->dvalue)));
                    }
                    break;
                case typeCom:
                    result.type = typeCom;
                    result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->lvalue), *arg2->cvalue));
                    break;
                case typeStr:
                    dp_output("Cannot raise an integer number to the power of a string\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    result.fvalue->ipower(arg1->lvalue);
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else result.fvalue->ipower(arg1->lvalue);
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to an integer number\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to an integer number\n");
                    break;
            }
                break;
            case typeDbl: switch(arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    result.dvalue = pow(arg1->dvalue, (double)arg2->lvalue);
                    if (!gsl_finite(result.dvalue)) {
                        result.type = typeCom;
                        result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->dvalue), dpComplex(arg2->lvalue)));
                    }
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    result.dvalue = pow(arg1->dvalue, arg2->dvalue);
                    if (!gsl_finite(result.dvalue)) {
                        result.type = typeCom;
                        result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->dvalue), dpComplex(arg2->dvalue)));
                    }
                    break;
                case typeCom:
                    result.type = typeCom;
                    result.cvalue = CreateComplex(complex_pow(dpComplex(arg1->dvalue), *arg2->cvalue));
                    break;
                case typeStr:
                    dp_output("Cannot raise a real number to the power of a string\n");
                    break;
                case typeFits:
                    CloneValue(*arg2, &result);
                    result.fvalue->ipower(arg1->dvalue);
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else result.fvalue->ipower(arg1->dvalue);
                    break;
                case typeStrarr:
                    dp_output("Cannot raise a real number to the power of a string array\n");
                    break;
                default:
                    dp_output("Cannot raise a real number to the power of this type\n");
                    break;
            }
                break;
            case typeCom: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= arg2->dvalue;
                    break;
                case typeCom:
                    CloneValue(*arg1, &result);
                    *result.cvalue *= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a complex number\n");
                    break;
                case typeFits:
//                    CloneValue(*arg2, result);
//                    *result.fvalue *= *arg1->cvalue;
                    dp_output("Cannot multiply a matrix to a complex number\n");
                    break;
                case typeFitsFile:
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    result.fvalue->ReadFITS(arg2->ffvalue->c_str());
//                    *result.fvalue *= *arg1->cvalue;
                    dp_output("Cannot multiply a FITS file to a complex number\n");
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a complex number\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a complex number\n");
                    break;
            }
                break;
            case typeStr:
                dp_output("Cannot multiply anything to a string\n");
                break;
            case typeFits: switch(arg2->type) {
                case typeCon:
                    CloneValue(*arg1, &result);
                    *result.fvalue *= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    *result.fvalue *= arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot multiply a complex number to a matrix\n");
//                    CloneValue(*arg1, &result);
//                    *result.fvalue *= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a matrix\n");
                    break;
                case typeFits:
                    if (isVariable(arg1->fvalue) == 0) {
                        CloneValue(*arg1, &result);
                        *result.fvalue *= *arg2->fvalue;
                    } else if (isVariable(arg2->fvalue) == 0) {
                        CloneValue(*arg2, &result);
                        *result.fvalue *= *arg1->fvalue;
                    } else {
                        CloneValue(*arg1, &result);
                        *result.fvalue *= *arg2->fvalue;
                    }
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= *arg1->fvalue;
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a matrix\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a matrix\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= (double)arg2->lvalue;
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= arg2->dvalue;
                    break;
                case typeCom:
                    dp_output("Cannot multiply a complex number to a FITS file\n");
//                    result.type = typeFits;
//                    result.fvalue = new Fits();
//                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
//                    else *result.fvalue *= *arg2->cvalue;
                    break;
                case typeStr:
                    dp_output("Cannot multiply a string to a FITS file\n");
                    break;
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else *result.fvalue *= *arg2->fvalue;
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else *result.fvalue *= a;
                    }
                    break;
                case typeStrarr:
                    dp_output("Cannot multiply a string array to a FITS file\n");
                    break;
                default:
                    dp_output("Cannot multiply this type to a FITS file\n");
                    break;
            }
                break;
            case typeStrarr:
                dp_output("Cannot multiply anything to a string array\n");
                break;
            default:
                dp_output("Invalid arguments to operator '^'\n");
                break;
        }
            break;
/* END: dead code */
        case '#': switch (arg1->type) {
            case typeFits: switch(arg2->type) {
                case typeFits:
                    CloneValue(*arg1, &result);
                    result.fvalue->matrix_mul(*arg2->fvalue);
                    break;
                case typeFitsFile: {
                    Fits a;

                    if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        CloneValue(*arg1, &result);
                        result.fvalue->matrix_mul(a);
                    }
                }
                    break;
                case typeCon:
                    CloneValue(*arg1, &result);
                    result.fvalue->mul((double)(arg2->lvalue));
                    break;
                case typeDbl:
                    CloneValue(*arg1, &result);
                    result.fvalue->mul(arg2->dvalue);
                    break;
                default:
                    dp_output("Cannot do matrix multiplication with this type\n");
                    break;
            }
                break;
            case typeFitsFile: switch(arg2->type) {
                case typeFits:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else result.fvalue->matrix_mul(*arg2->fvalue);
                    break;
                case typeCon:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else result.fvalue->mul((double)(arg2->lvalue));
                    break;
                case typeDbl:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else result.fvalue->mul(arg2->dvalue);
                    break;
                case typeFitsFile:
                    result.type = typeFits;
                    result.fvalue = CreateFits();
                    if (!result.fvalue->ReadFITS(arg1->ffvalue->c_str())) result.type = typeUnknown;
                    else {
                        Fits a;
                        if (!a.ReadFITS(arg2->ffvalue->c_str())) result.type = typeUnknown;
                        else result.fvalue->matrix_mul(a);
                    }
                    break;
                default:
                    dp_output("Cannot do matrix multiplication with this type\n");
                    break;
            }
                break;
            default:
                dp_output("Invalid arguments to operator '#'\n");
                break;
        }
            break;
        case '%': switch (arg1->type) {
            case typeCon: switch (arg2->type) {
                case typeCon:
                    result.type = typeCon;
                    if (arg2->lvalue != 0) result.lvalue = arg1->lvalue % arg2->lvalue;
                    else result.lvalue = 0;
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    if (arg2->dvalue != 0.0) {
                        result.dvalue = (double)(int)(arg1->lvalue / arg2->dvalue);
                        result.dvalue = arg1->lvalue - arg2->dvalue * result.dvalue;
                    } else {
                        result.dvalue = 0.0;
                    }
                    break;
                default:
                    dp_output("Wrong arguments to modulo operator\n");
                    break;
            }
                break;
            case typeDbl: switch (arg2->type) {
                case typeCon:
                    result.type = typeDbl;
                    if (arg2->lvalue != 0) {
                        result.dvalue = (double)(int)(arg1->dvalue / ((double)arg2->lvalue));
                        result.dvalue = arg1->dvalue - arg2->lvalue * result.dvalue;
                    } else {
                        result.dvalue = 0.0;
                    }
                    break;
                case typeDbl:
                    result.type = typeDbl;
                    if (arg2->dvalue != 0.0) {
                        result.dvalue = (double)(int)(arg1->dvalue / arg2->dvalue);
                        result.dvalue = arg1->dvalue - arg2->dvalue * result.dvalue;
                    } else {
                        result.dvalue = 0.0;
                    }
                    break;
                default:
                    dp_output("Wrong arguments to modulo operator\n");
                    break;
                }
                break;
            case typeFits:
                result.type = typeFits;
                CloneValue(*arg1, &result);
                result.fvalue->setType(R4);
                switch (arg2->type) {
                case typeCon:
                    if (arg2->lvalue != 0) {
                        double value;
                        for (unsigned long n = 0; n < result.fvalue->Nelements(); n++) {
                            value = (double)(int)(arg1->fvalue->ValueAt(n) / ((double)arg2->lvalue));
                            result.fvalue->r4data[n] = arg1->fvalue->ValueAt(n) - arg2->lvalue * value;
                        }
                    } else {
                        *result.fvalue = 0.0;
                    }
                    break;
                case typeDbl:
                    if (arg2->dvalue != 0.0) {
                        double value;
                        for (unsigned long n = 0; n < result.fvalue->Nelements(); n++) {
                            value = (double)(int)(arg1->fvalue->ValueAt(n) / arg2->dvalue);
                            result.fvalue->r4data[n] = arg1->fvalue->ValueAt(n) - arg2->dvalue * value;
                        }
                    } else {
                        *result.fvalue = 0.0;
                    }
                    break;
                default:
                    dp_output("Wrong arguments to modulo operator\n");
                    break;
                }
                break;
            default:
                yyerror("Wrong arguments to modulo operator\n");
                break;
            }
                break;

        default:
            dp_output("Invalid operator '%c'\n", operation);
            break;
    }

    return result;
}

nodeEnum matchArgTypes(conValue *va) {
    nodeEnum rv;

    if ((va[0].type == typeUnknown) || (va[1].type == typeUnknown)) return typeUnknown;
    if ((va[0].type == typeFits) || (va[1].type == typeFits)) {
        rv = typeFits;
        if (va[0].type == typeCon) {
            va[0].type = typeDbl;
            va[0].dvalue = (double)va[0].lvalue;
        } else if (va[1].type == typeCon) {
            va[1].type = typeDbl;
            va[1].dvalue = (double)va[1].lvalue;
        }
    } else if ((va[0].type == typeStr) || (va[1].type == typeStr)) {
        rv = typeStr;
        if (va[0].type == typeDbl) {
            va[0].svalue = CreateString(va[0].dvalue);
            va[0].type = typeStr;
        } else if (va[0].type == typeCon) {
            va[0].svalue = CreateString(va[0].lvalue);
            va[0].type = typeStr;
        } else if (va[0].type == typeCom) {
            va[0].svalue = CreateString(*va[0].cvalue);
            va[0].type = typeStr;
        } else if (va[1].type == typeDbl) {
            va[1].svalue = CreateString(va[1].dvalue);
            va[1].type = typeStr;
        } else if (va[1].type == typeCon) {
            va[1].svalue = CreateString(va[1].lvalue);
            va[1].type = typeStr;
        } else if (va[1].type == typeCom) {
            va[1].svalue = CreateString(*va[1].cvalue);
            va[1].type = typeStr;
        }
    } else if ((va[0].type == typeCom) || (va[1].type == typeCom)) {
        rv = typeCom;
        if (va[0].type == typeCon) {
            va[0].type = typeCom;
            va[0].cvalue = CreateComplex((double)(va[0].lvalue));
        } else if (va[0].type == typeDbl) {
            va[0].type = typeCom;
            va[0].cvalue = CreateComplex(va[0].dvalue);
        } else if (va[1].type == typeCon) {
            va[1].type = typeCom;
            va[1].cvalue = CreateComplex((double)(va[1].lvalue));
        } else if (va[1].type == typeDbl) {
            va[1].type = typeCom;
            va[1].cvalue = CreateComplex(va[1].dvalue);
        }
    } else if ((va[0].type == typeDbl) || (va[1].type == typeDbl)) {
        rv = typeDbl;
        if (va[0].type == typeCon) {
            va[0].type = typeDbl;
            va[0].dvalue = (double)(va[0].lvalue);
        } else if (va[1].type == typeCon) {
            va[1].type = typeDbl;
            va[1].dvalue = (double)(va[1].lvalue);
        }
    } else {
        rv = typeCon;
    }
    return rv;
}

//conValue ex(nodeType *p);

/* extract a range argument */
int extractRangeArgs(conValue *s, nodeType *p, conValue *args) {
    int i;
    long nops;
    conValue eArg;

/* check argument types */
    if ((s->type != typeFits)
     && (s->type != typeStrarr)
         && (s->type != typeDpArr)
         && (s->type != typeStr)
     && (s->type != typeCon)
     && (s->type != typeDbl)
     && (s->type != typeCom)) {
        yyerror("Wrong argument to access subset");
        return 0;
    }

    nops = p->opr.op[1]->rng.nops;
    if ((s->type == typeStrarr) && (nops > 2)) {
        yyerror("Too many arguments to access subset of stringarray");
        return 0;
    } else if ((s->type == typeFits) && (nops > s->fvalue->Naxis(0) * 2)) {
        yyerror("Too many arguments to access subset of fits array");
        return 0;
        } else if ((s->type == typeDpArr) && (nops > 2)) {
                yyerror("Too many arguments to element of Fits List");
                return 0;
        } else if ((s->type == typeStr) && (nops > 2)) {
        yyerror("Too many arguments to access subset of string");
        return 0;
    }

    for (i = 1; i <= nops; i++) {
        args[i - 1].type = typeCon;
        if (p->opr.op[1]->rng.op[i - 1] == NULL) {
            if (i % 2 == 1) {
                args[i - 1].lvalue = 1;
            } else {
                if (p->opr.op[1]->rng.op[i - 2] == NULL) {
                    if (s->type == typeFits) {
                        if (nops == 2) args[i - 1].lvalue = s->fvalue->Nelements();
                        else args[i - 1].lvalue = s->fvalue->Naxis(i / 2);
                    } else {
                        args[i - 1].lvalue = s->svalue->length();
                    }
                } else {
                    args[i - 1].lvalue = args[i - 2].lvalue;
                }
            }
        } else {
            eArg = ex(p->opr.op[1]->rng.op[i - 1]);
            if (eArg.type == typeDbl) {
                eArg.type = typeCon;
                eArg.lvalue = (long)eArg.dvalue;
            }
            if (eArg.type != typeCon) {
                if (eArg.type == typeFits) {
                    args[0] = eArg;
                    return 1;
                } else {
                    yyerror("Wrong arg type to access single elements");
                    return 0;
                }
            }
            args[i - 1].lvalue = eArg.lvalue;
            if (indexBase == 0) args[i - 1].lvalue++;
        }
    }
    return nops;
}

conValue ex(nodeType *p) {
    conValue va[2];
    conValue rv, er;
    int o, index;
    int success;
    long onaxis1, onaxis2, omethod;

    onaxis1 = variables[3].lvalue;
    onaxis2 = variables[4].lvalue;
    omethod = variables[6].lvalue;

    rv.lvalue = 0;
    rv.svalue = NULL;
    rv.cvalue = NULL;
    rv.fvalue = NULL;
    rv.ffvalue = NULL;
    rv.arrvalue = NULL;
        rv.dparrvalue = NULL;
    rv.type = typeCon;

    er.lvalue = 0;
    er.svalue = NULL;
    er.cvalue = NULL;
    er.fvalue = NULL;
    er.ffvalue = NULL;
    er.arrvalue = NULL;
    er.dparrvalue = NULL;
    er.type = typeUnknown;

    success = 1;

    if (!p) return rv;
    if (p->type == typeUnknown) return er;

    switch(p->type) {

        case typePgplot: dopgplot(p);
            variables[6].lvalue = omethod;
            break;

        case typeCon: rv = p->con.value; break;

        case typeId: rv = variables[p->id.i]; break;

        case typeFnc: rv = resolveFunction(p); break;

        case typeOpr: switch(p->opr.oper) {

            case WHERE:
                va[0] = ex(p->opr.op[0]->opr.op[0]);
                switch (va[0].type) {
                    case typeDbl:
                    case typeCon: {
                        double value, value2;
                        bool comparisonTrue = FALSE;

                        va[1] = ex(p->opr.op[0]->opr.op[1]);
                        if (va[1].type == typeCon) {
                            value = (double)va[1].lvalue;
                        } else if (va[1].type == typeDbl) {
                            value = va[1].dvalue;
                        } else {
                            success = 0;
                            break;
                        }
                        if (va[0].type == typeCon) value2 = (double)va[0].lvalue;
                        else value2 = va[0].dvalue;
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        rv.fvalue->create(1, 1, I4);
                        switch (p->opr.op[0]->opr.oper) {
                            case '<': comparisonTrue = (value2 < value); break;
                            case '>': comparisonTrue = (value2 > value); break;
                            case NE: comparisonTrue = (value2 != value); break;
                            case EQ: comparisonTrue = (value2 == value); break;
                            case GE: comparisonTrue = (value2 >= value); break;
                            case LE: comparisonTrue = (value2 <= value); break;
                            default: break;
                        }
                        if (comparisonTrue) rv.fvalue->i4data[0] = indexBase;
                        else rv.fvalue->resize(0);
                    }
                    break;

                    case typeFits: {
                        Fits *f = va[0].fvalue;
                        unsigned long n, i;
                        long r;
                        double value;

                        if (p->opr.op[0]->opr.nops != 2) {
                            dp_output("Wrong number of arguments for where.\n");
                            success = 0;
                            break;
                        }
                        va[1] = ex(p->opr.op[0]->opr.op[1]);
                        if (va[1].type == typeCon) {
                            value = (double)va[1].lvalue;
                        } else if (va[1].type == typeDbl) {
                            value = va[1].dvalue;
                        } else {
                            success = 0;
                            break;
                        }
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        rv.fvalue->create(f->Nelements(), 1, I4);
                        i = 0;
                        for (n = 0; n < f->Nelements(); n++) {
                            r = 0;
                            switch (p->opr.op[0]->opr.oper) {
                                case '<': r = (f->ValueAt(n) < value); break;
                                case '>': r = (f->ValueAt(n) > value); break;
                                case NE: r = (f->ValueAt(n) != value); break;
                                case EQ: r = (f->ValueAt(n) == value); break;
                                case GE: r = (f->ValueAt(n) >= value); break;
                                case LE: r = (f->ValueAt(n) <= value); break;
                                default: break;
                            }
                            if (r) {
                                if (indexBase == 0) {
                                    rv.fvalue->i4data[i] = n;
                                } else {
                                    rv.fvalue->i4data[i] = n+1;
                                }
                                i++;
                            }
                        }
                        rv.fvalue->resize(i);
                    }
                        break;
                    case typeStr: dp_output("String\n"); break;
                    default: break;
                }
                if (p->opr.nops == 2) {
                    int index = -1;
                    if (p->opr.op[1]->type == typeId) {
                        index = p->opr.op[1]->id.i;
                    } else if (p->opr.op[1]->con.value.type == typeFitsFile) {
                        conValue _tmpvalue = ex(p->opr.op[1]);
                        if (_tmpvalue.type == typeFitsFile) {
                            index = createVariable((char *)_tmpvalue.ffvalue->c_str());
                        }
                    }
                    if (index != -1) {
                        variables[index].type = typeCon;
                        variables[index].lvalue = rv.fvalue->Nelements();
                    } else {
                        dp_output("WHERE: Count argument must be of type VARIABLE");
                    }
                }
                break;

            case WHILE:
                looplock++;
                while(ex(p->opr.op[0]).lvalue) {
                    ex(p->opr.op[1]);
                    freePointerlist(); //$ 10.04.2005: wieder aktiviert
                    if (ScriptInterrupt) {
                        looplock = 0;
                        break;
                    }
                }
                looplock--;
                break;

            case FOR:
                looplock++;
                if (p->opr.nops == 3) {
                    long index;
                    conValue v;

                    ex(p->opr.op[0]);
                    index = p->opr.op[0]->opr.op[0]->id.i;
                    if (variables[index].type == typeDbl) {
                        variables[index].type = typeCon;
                        variables[index].lvalue = (long)variables[index].dvalue;
                    }
                    v = ex(p->opr.op[1]);
                    if (v.type == typeDbl) {
                        v.type = typeCon;
                        v.lvalue = (long)v.dvalue;
                    }
                    if ((variables[index].type != typeCon) || (v.type != typeCon)) {
                        yyerror("IDL type loops must have integer arguments");
                        break;
                    }
                    while (variables[index].lvalue <= v.lvalue) {
                        ex(p->opr.op[2]);
                        variables[index].lvalue++;
                        v = ex(p->opr.op[1]);
                        if (v.type == typeDbl) v.lvalue = (long)v.dvalue;
                        freePointerlist(); //$ 10.04.2005: wieder aktiviert
                        if (ScriptInterrupt) {
                            looplock = 0;
                            break;
                        }
                    }
                } else {
                    ex(p->opr.op[0]);
                    while(ex(p->opr.op[1]).lvalue) {
                        ex(p->opr.op[3]);
                        ex(p->opr.op[2]);
                        freePointerlist(); //$ 10.04.2005: wieder aktiviert
                        if (ScriptInterrupt) {
                            looplock = 0;
                            break;
                        }
                    }
                }
                looplock--;
                                if (looplock < 0) {
                                    looplock = 0;
                                }
#ifdef DPQT
                                if (looplock == 0) {
                                    dpUpdateVar(fitsMainWindow->getCurrentBufferIndex());
                                }
#endif
                break;

            case IF:
                va[0] = ex(p->opr.op[0]);
                if (va[0].type != typeCon) {
                    success = 0;
                    yyerror("Wrong argument for conditional statement");
                    break;
                }
                if (va[0].lvalue) ex(p->opr.op[1]);
                else if (p->opr.nops > 2) ex(p->opr.op[2]);
                break;

            case NEWFITS: {
                int i;
                long dim, j, inc;
                conValue l;

                if (p->opr.op[0]->rng.op[0] != NULL) {
                    l = ex(p->opr.op[0]->rng.op[0]);
                    if ((l.type == typeStr) || (l.type == typeStrarr)) {
                        rv.type = typeStrarr;
                        rv.arrvalue = CreateStringArray();
                        for (i = 0; i < p->opr.op[0]->rng.nops; i++) {
                            if (p->opr.op[0]->rng.op[i] != NULL) {
                                l = ex(p->opr.op[0]->rng.op[i]);
                                if (l.type == typeStr) {
                                    rv.arrvalue->append(*l.svalue);
                                } else if (l.type == typeStrarr) {
                                    for (dpint64 n = 0; n < l.arrvalue->count(); n++) rv.arrvalue->append((*l.arrvalue)[n]);
                                } else {
                                    dp_output("Wrong argument to insert into a string array\n");
                                }
                            }
                        }
                    } else if (l.type == typeFits) {
                        if (p->opr.op[0]->rng.nops == 2) {
                            CloneValue(l, &rv);
                        } else {
                            dim = l.fvalue->Naxis(1);
                            rv.type = typeFits;
                            rv.fvalue = CreateFits();
                            rv.fvalue->create(dim, p->opr.op[0]->rng.nops / 2);
                            rv.fvalue->setRange(*l.fvalue, 1, dim, 1, 1, 1, 1);
                            for (i = 2; i < p->opr.op[0]->rng.nops; i+=2) {
                                if (p->opr.op[0]->rng.op[i] != NULL) {
                                    l = ex(p->opr.op[0]->rng.op[i]);
                                    if (l.type == typeFits) {
                                        if (l.fvalue->Naxis(1) > dim) {
                                            dim = l.fvalue->Naxis(1);
                                            rv.fvalue->resize(dim, p->opr.op[0]->rng.nops/2);
                                        }
                                        rv.fvalue->setRange(*l.fvalue, 1, l.fvalue->Naxis(1), i/2+1, i/2+1, 1, 1);
                                    } else dp_output("WARNING - matrix element %i is not a vector\n", i/2+1);
                                }
                            }
                        }
                    } else {
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();

                        if (!rv.fvalue->create(p->opr.op[0]->rng.nops, 1, R8)) {
                            success = 0;
                            break;
                        }
                        dim = 0;
                        for (i = 0; i < p->opr.op[0]->rng.nops; i++) {
                            if (p->opr.op[0]->rng.op[i] != NULL) {
                                if (i > 0) l = ex(p->opr.op[0]->rng.op[i]);
                                if (l.type == typeCon) {
                                    l.type = typeDbl;
                                    l.dvalue = (double)l.lvalue;
                                }
                                if (l.type == typeDbl) {
                                    if (i % 2 == 0) {
                                        rv.fvalue->r8data[dim] = l.dvalue;
                                        dim++;
                                    } else {
                                        if (l.dvalue != rv.fvalue->ValueAt(dim - 1)) {
                                            inc = (long)fabs(l.dvalue - rv.fvalue->ValueAt(dim - 1)) - 1;
                                            rv.fvalue->resize(rv.fvalue->Nelements() + inc, 1);
                                            if (l.dvalue > rv.fvalue->ValueAt(dim - 1)) {
                                                for (j = dim; j < dim + inc + 1; j++) {
                                                    rv.fvalue->r8data[j] = rv.fvalue->r8data[j - 1] + 1.0;
                                                }
                                            } else {
                                                for (j = dim; j < dim + inc + 1; j++) {
                                                    rv.fvalue->r8data[j] = rv.fvalue->r8data[j - 1] - 1.0;
                                                }
                                            }
                                            dim += inc + 1;
                                        }
                                    }
                                } else {
                                    yyerror("Wrong argument type to set an array");
                                    success = 0;
                                    break;
                                }
                            }
                        }
                        if (success) {
                            rv.fvalue->resize(dim, 1, 1);
                        }
                    }
                }
            }
                break;


            case RANGE: {
                int i;
                conValue eArgs[10];

/* check argument types */
                for (i = 0; i < 10; i++) eArgs[i].type = typeCon;
                eArgs[0] = ex(p->opr.op[0]);
                if (eArgs[0].type == typeFitsFile) {
                    for (i = 1; i < 10; i++) eArgs[i].lvalue = 0;
                    for (i = 1; i <= p->opr.op[1]->rng.nops; i++) {
                        if (p->opr.op[1]->rng.op[i - 1] == NULL) {
                            eArgs[i].type = typeCon;
                            if (i % 2 == 1) eArgs[i].lvalue = 1;
                            else {
                                if (p->opr.op[1]->rng.op[i - 2] == NULL)
                                    eArgs[i].lvalue = eArgs[i - 1].lvalue = 0;
                                else
                                    eArgs[i].lvalue = eArgs[i - 1].lvalue;
                            }
                        } else {
                            eArgs[i] = ex(p->opr.op[1]->rng.op[i - 1]);
                            if (indexBase == 0) eArgs[i].lvalue++;
                        }
                        if (eArgs[i].type == typeDbl) {
                            eArgs[i].type = typeCon;
                            eArgs[i].lvalue = (long)eArgs[i].dvalue;
                            if (indexBase == 0) eArgs[i].lvalue++;
                        }
                        if (eArgs[i].type != typeCon) {
                            yyerror("Wrong arg type to access single elements");
                            success = 0;
                            break;
                        }
                    }
                    rv.type = typeFits;
                    rv.fvalue = CreateFits();
                    if (!rv.fvalue->ReadFITS(eArgs[0].ffvalue->c_str(), eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, eArgs[4].lvalue, eArgs[5].lvalue, eArgs[6].lvalue)) {
                        success = 0;
                        break;
                    }
                    break;
                }
                if (eArgs[0].type == typeStr) {
                    if (p->opr.op[1]->rng.nops != 2) {
                        yyerror("Wrong number of arguments to access substring");
                        success = 0;
                        break;
                    }
                    rv.type = typeStr;
                    if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                        rv.svalue = CreateString(*eArgs[0].svalue);
                        break;
                    }
                    if (p->opr.op[1]->rng.op[1] == NULL) {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                            eArgs[1].type = typeCon;
                        }
                        if (indexBase == 0) eArgs[1].lvalue++;
                        eArgs[2].type = typeCon;
                        eArgs[2].lvalue = eArgs[1].lvalue;
                    } else {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        eArgs[2] = ex(p->opr.op[1]->rng.op[1]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].type = typeCon;
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                        }
                        if (eArgs[2].type == typeDbl) {
                            eArgs[2].type = typeCon;
                            eArgs[2].lvalue = (long)eArgs[2].dvalue;
                        }
                        if (indexBase == 0) eArgs[1].lvalue++;
                        if (indexBase == 0) eArgs[2].lvalue++;
                    }
                    if (eArgs[1].type == typeFits) {
                        rv.type = typeStr;
                        rv.svalue = CreateString(*eArgs[0].svalue);
                        reindexString(*rv.svalue, *eArgs[1].fvalue);
                        break;
                    }
                    if ((eArgs[1].type != typeCon) || (eArgs[2].type != typeCon)) {
                        yyerror("Wrong arg type to access single elements");
                        success = 0;
                        break;
                    }
                    if ((eArgs[1].lvalue < 1) || (eArgs[1].lvalue > eArgs[2].lvalue) || (eArgs[2].lvalue > (long)eArgs[0].svalue->length())) {
                        yyerror("Value out of range");
                        success = 0;
                        break;
                    }
                    rv.type = typeStr;
                    dpString tmpstr(*eArgs[0].svalue);
                    rv.svalue = CreateString();
                    *rv.svalue = tmpstr.mid(eArgs[1].lvalue-1, eArgs[2].lvalue-eArgs[1].lvalue+1);
                    break;
                }
                if (eArgs[0].type == typeStrarr) {
                    if (p->opr.op[1]->rng.nops != 2) {
                        yyerror("Wrong number of arguments to access substring");
                        success = 0;
                        break;
                    }
                    rv.type = typeStrarr;
                    if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                        rv.arrvalue = CreateStringArray(*eArgs[0].arrvalue);
                        break;
                    }
                    if (p->opr.op[1]->rng.op[1] == NULL) {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                            eArgs[1].type = typeCon;
                        }
                        if (indexBase == 0) eArgs[1].lvalue++;
                        eArgs[2].type = typeCon;
                        eArgs[2].lvalue = eArgs[1].lvalue;
                    } else {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        eArgs[2] = ex(p->opr.op[1]->rng.op[1]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].type = typeCon;
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                        }
                        if (eArgs[2].type == typeDbl) {
                            eArgs[2].type = typeCon;
                            eArgs[2].lvalue = (long)eArgs[2].dvalue;
                        }
                        if (indexBase == 0) eArgs[1].lvalue++;
                        if (indexBase == 0) eArgs[2].lvalue++;
                    }
                    if (eArgs[1].type == typeFits) {
                        rv.type = typeStrarr;

                        rv.arrvalue = CreateStringArray(*eArgs[0].arrvalue);
                        success = reindexStringArray(*rv.arrvalue, *eArgs[1].fvalue);
                        break;
                    }
                    if ((eArgs[1].type != typeCon) || (eArgs[2].type != typeCon)) {
                        yyerror("Wrong arg type to access single elements");
                        success = 0;
                        break;
                    }
                    if ((eArgs[1].lvalue < 1) || (eArgs[1].lvalue > eArgs[2].lvalue) || (eArgs[1].lvalue > (long)eArgs[0].arrvalue->count()) || eArgs[2].lvalue > (long)eArgs[0].arrvalue->count()) {
                        yyerror("Value out of range");
                        success = 0;
                        break;
                    }
                    if (eArgs[1].lvalue == eArgs[2].lvalue) {
                        rv.type = typeStr;
                        rv.svalue = CreateString((*eArgs[0].arrvalue)[eArgs[1].lvalue - 1]);
                        break;
                    } else {
                        rv.arrvalue = CreateStringArray();
                        for (i = eArgs[1].lvalue - 1; i < eArgs[2].lvalue; i++) {
                            rv.arrvalue->append((*eArgs[0].arrvalue)[i]);
                        }
                        break;
                    }
                }
                                if (eArgs[0].type == typeDpArr) {
                                    if (p->opr.op[1]->rng.nops != 2) {
                                            yyerror("Wrong number of arguments to access member of FITS list");
                                            success = 0;
                                            break;
                                    }


                                    if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                                        yyerror("Wrong number of arguments to access member of FITS list");
                                        success = 0;
                                        break;
                                    }
                                    if (p->opr.op[1]->rng.op[1] == NULL) {
                                            eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                                            if (eArgs[1].type == typeDbl) {
                                                    eArgs[1].lvalue = (long)eArgs[1].dvalue;
                                                    eArgs[1].type = typeCon;
                                            }
                                            eArgs[2].type = typeCon;
                                            eArgs[2].lvalue = eArgs[1].lvalue;
                                            if ((eArgs[1].lvalue < 0) || (eArgs[1].lvalue > (long)eArgs[0].dparrvalue->size()-1)) {
                                                    yyerror("Value out of range");
                                                    success = 0;
                                                    break;
                                            }
                                            dpuserType dpinp, dprv;

                                            dpinp = *((dpuserType *)(eArgs[0].dparrvalue->at(eArgs[1].lvalue)));
//                                            dprv.copy(dpinp);
                                            dprv.deep_copy(dpinp);

                                            switch (dprv.type) {
                                                case typeFits:
                                                    addToListOfFits(dprv.fvalue);
                                                    break;
                                                case typeStrarr:
                                                    dprv.deep_copy(dpinp);
                                                    addToListOfdpStringArrays(dprv.arrvalue);
                                                    break;
                                                default:
                                                    break;
                                            }

                                            rv = dprv.toConValue();
//                                            rv.type = typeFits;
//                                            rv.fvalue = CreateFits();
//                                            rv.fvalue->copy(*((*(eArgs[0].dparrvalue))[eArgs[1].lvalue]));
                                            break;
                                    } else {
                                        yyerror("Wrong number of arguments to access member of FITS list");
                                        success = 0;
                                        break;
                                    }



                                }
                if (eArgs[0].type == typeCon || eArgs[0].type == typeDbl || eArgs[0].type == typeCom) {
                    if (p->opr.op[1]->rng.nops != 2) {
                        yyerror("Wrong number of arguments to access single number");
                        success = 0;
                        break;
                    }
                    if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                        rv.type = eArgs[0].type;
                        rv.lvalue = eArgs[0].lvalue;
                        rv.dvalue = eArgs[0].lvalue;
                        rv.cvalue = eArgs[0].cvalue;
                        break;
                    }
                    if (p->opr.op[1]->rng.op[1] == NULL) {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                            eArgs[1].type = typeCon;
                        }
                        if (eArgs[1].lvalue != indexBase) {
                            yyerror("Wrong number of arguments to access single number");
                            success = 0;
                            break;
                        }
                        rv.type = eArgs[0].type;
                        rv.lvalue = eArgs[0].lvalue;
                        rv.dvalue = eArgs[0].dvalue;
                        rv.cvalue = eArgs[0].cvalue;
                        break;
                    } else {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        eArgs[2] = ex(p->opr.op[1]->rng.op[1]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].type = typeCon;
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                        }
                        if (eArgs[2].type == typeDbl) {
                            eArgs[2].type = typeCon;
                            eArgs[2].lvalue = (long)eArgs[2].dvalue;
                        }
                        if (eArgs[1].lvalue != indexBase || eArgs[2].lvalue != indexBase) {
                            yyerror("Wrong number of arguments to access single number");
                            success = 0;
                            break;
                        }
                        rv.type = eArgs[0].type;
                        rv.lvalue = eArgs[0].lvalue;
                        rv.dvalue = eArgs[0].lvalue;
                        rv.cvalue = eArgs[0].cvalue;
                        break;
                    }
                }
                if (eArgs[0].type != typeFits) {
                    yyerror("Wrong arg type to access subset");
                    success = 0;
                    break;
                }
                if (p->opr.op[1]->rng.nops == 2) {
                    if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                        success = CloneValue(eArgs[0], &rv);
                        break;
                    }
                    if (p->opr.op[1]->rng.op[1] == NULL) {
                        eArgs[1] = ex(p->opr.op[1]->rng.op[0]);
                        if (eArgs[1].type == typeDbl) {
                            eArgs[1].type = typeCon;
                            eArgs[1].lvalue = (long)eArgs[1].dvalue;
                        }
                        if (indexBase == 0) eArgs[1].lvalue++;
                        if (eArgs[1].type == typeCon) {
                            if ((eArgs[1].lvalue > 0) && (eArgs[1].lvalue <= (long)eArgs[0].fvalue->Nelements())) {
                                                            if (eArgs[0].fvalue->membits == C16) {
                                                                if (fabs(eArgs[0].fvalue->cdata[eArgs[1].lvalue - 1].i) < dpTOLERANCE) {
                                                                    rv.type = typeDbl;
                                                                    rv.dvalue = eArgs[0].fvalue->cdata[eArgs[1].lvalue - 1].r;
                                                                } else {
                                                                    rv.type = typeCom;
                                                                    rv.cvalue = CreateComplex(eArgs[0].fvalue->cdata[eArgs[1].lvalue - 1].r, eArgs[0].fvalue->cdata[eArgs[1].lvalue - 1].i);
                                                                }
                                                            } else {
                                rv.type = typeDbl;
                                rv.dvalue = eArgs[0].fvalue->ValueAt(eArgs[1].lvalue - 1);
                                                            }
                            } else {
                                dp_output("Index out of range\n");
                                success = FALSE;
                            }
                            break;
                        } else if (eArgs[1].type == typeFits) {
                            rv.type = typeFits;
                            rv.fvalue = CreateFits();
                            success = eArgs[0].fvalue->extractRange(*rv.fvalue, *eArgs[1].fvalue);
                            break;
                        }
                    }
                }
                if (eArgs[0].fvalue->Naxis(0) != p->opr.op[1]->rng.nops / 2) {
                    yyerror("Wrong number of axes");
                    success = 0;
                    break;
                }
                for (i = 1; i <= p->opr.op[1]->rng.nops; i++) {
                    if (p->opr.op[1]->rng.op[i - 1] == NULL) {
                        eArgs[i].type = typeCon;
                        if (i % 2 == 1) eArgs[i].lvalue = 1;
                        else {
                            if (p->opr.op[1]->rng.op[i - 2] == NULL)
                                eArgs[i].lvalue = eArgs[0].fvalue->Naxis(i / 2);
                            else
                                eArgs[i].lvalue = eArgs[i - 1].lvalue;
                        }
                    } else {
                        eArgs[i] = ex(p->opr.op[1]->rng.op[i - 1]);
                        if (indexBase == 0) {
                            if (eArgs[i].type == typeCon) eArgs[i].lvalue++;
                            if (eArgs[i].type == typeDbl) eArgs[i].dvalue++;
                        }
                    }
                    if (eArgs[i].type == typeDbl) {
                        eArgs[i].type = typeCon;
                        eArgs[i].lvalue = nint(eArgs[i].dvalue);
                    }
                    if ((eArgs[i].type != typeCon) && (eArgs[i].type != typeFits)) {
                        yyerror("Wrong arg type to access single elements");
                        success = 0;
                        break;
                    }
                    if (eArgs[i].type == typeFits) eArgs[i].lvalue = 1;
                    if (eArgs[i].lvalue < 1) {
                        yyerror("Value out of range");
                        success = 0;
                        break;
                    }
                }
                for (i = 1; i < p->opr.nops; i += 2) {
                    if (eArgs[i].lvalue > eArgs[i + 1].lvalue) {
                        yyerror("invalid range");
                        success = 0;
                        break;
                    }
                    if (eArgs[i].lvalue > eArgs[0].fvalue->Naxis((i + 1)/2)) {
                        yyerror("Value out of range");
                        success = 0;
                        break;
                    }
                    if (eArgs[i + 1].lvalue > eArgs[0].fvalue->Naxis((i + 1)/2)) {
                        yyerror("Value out of range");
                        success = 0;
                        break;
                    }
                }
                if ((eArgs[1].type == typeCon) && (eArgs[3].type == typeCon) && (eArgs[5].type == typeCon)) {
                    if (eArgs[0].fvalue->Naxis(0) == 1) {
                        if (eArgs[1].lvalue == eArgs[2].lvalue) {
                                                    if (eArgs[0].fvalue->membits == C16) {
                                                        if (fabs(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, 1)].i) < dpTOLERANCE) {
                                                            rv.type = typeDbl;
                                                            rv.dvalue = eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, 1)].r;
                                                        } else {
                                                            rv.type = typeCom;
                                                            rv.cvalue = CreateComplex(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, 1)].r, eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, 1)].i);
                                                        }
                                                    } else {
                                                        rv.type = typeDbl;
                            rv.dvalue = eArgs[0].fvalue->ValueAt(eArgs[0].fvalue->F_I(eArgs[1].lvalue, 1));
                                                    }
                            break;
                        } else
                            rv.type = typeFits;
                    } else if (eArgs[0].fvalue->Naxis(0) == 2) {
                        if ((eArgs[1].lvalue == eArgs[2].lvalue) && (eArgs[3].lvalue == eArgs[4].lvalue)) {
                                                    if (eArgs[0].fvalue->membits == C16) {
                                                        if (fabs(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue)].i) < dpTOLERANCE) {
                                                            rv.type = typeDbl;
                                                            rv.dvalue = eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue)].r;
                                                        } else {
                                                            rv.type = typeCom;
                                                            rv.cvalue = CreateComplex(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue)].r, eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue)].i);
                                                        }
                                                    } else {
                                                        rv.type = typeDbl;
                                                        rv.dvalue = eArgs[0].fvalue->ValueAt(eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue));
                                                    }
                            break;
                        } else
                            rv.type = typeFits;
                    } else if (eArgs[0].fvalue->Naxis(0) == 3) {
                        if ((eArgs[1].lvalue == eArgs[2].lvalue) && (eArgs[3].lvalue == eArgs[4].lvalue) && (eArgs[5].lvalue == eArgs[6].lvalue)) {
                                                    if (eArgs[0].fvalue->membits == C16) {
                                                        if (fabs(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue, eArgs[5].lvalue)].i) < dpTOLERANCE) {
                                                            rv.type = typeDbl;
                                                            rv.dvalue = eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue, eArgs[5].lvalue)].r;
                                                        } else {
                                                            rv.type = typeCom;
                                                            rv.cvalue = CreateComplex(eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue, eArgs[5].lvalue)].r, eArgs[0].fvalue->cdata[eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue, eArgs[5].lvalue)].i);
                                                        }
                                                    } else {
                                                        rv.type = typeDbl;
                            rv.dvalue = eArgs[0].fvalue->ValueAt(eArgs[0].fvalue->F_I(eArgs[1].lvalue, eArgs[3].lvalue, eArgs[5].lvalue));
                                                    }
                            break;
                        } else
                            rv.type = typeFits;
                    }
                    rv.fvalue = CreateFits();
                    if (eArgs[0].fvalue->Naxis(0) == 1)
                        success = eArgs[0].fvalue->extractRange(*rv.fvalue, eArgs[1].lvalue, eArgs[2].lvalue, 1, 1, 1, 1);
                    else if (eArgs[0].fvalue->Naxis(0) == 2)
                        success = eArgs[0].fvalue->extractRange(*rv.fvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, eArgs[4].lvalue, 1, 1);
                    else
                        success = eArgs[0].fvalue->extractRange(*rv.fvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, eArgs[4].lvalue, eArgs[5].lvalue, eArgs[6].lvalue);
                } else if ((eArgs[1].type == typeFits) || (eArgs[3].type == typeFits) || (eArgs[5].type == typeFits)) {
                    if (eArgs[1].type + eArgs[3].type + eArgs[5].type == typeFits + typeCon + typeCon) {
                        int n1, n2, n3;
                        Fits *indices = NULL;

                        n1 = eArgs[1].lvalue;
                        n2 = eArgs[3].lvalue;
                        n3 = eArgs[5].lvalue;
                        if (eArgs[1].type == typeFits) {
                            if (p->opr.op[1]->rng.nops > 4) if (n3 != eArgs[6].lvalue) success = FALSE;
                            if (p->opr.op[1]->rng.nops > 2) if (n2 != eArgs[4].lvalue) success = FALSE;
                        } else if (eArgs[3].type == typeFits) {
                            if (n1 != eArgs[2].lvalue) success = FALSE;
                            if (p->opr.op[1]->rng.nops > 4) if (n3 != eArgs[6].lvalue) success = FALSE;
                        } else {
                            if (n1 != eArgs[2].lvalue) success = FALSE;
                            if (n2 != eArgs[4].lvalue) success = FALSE;
                        }
                        if (p->opr.op[1]->rng.nops < 5) n3 = 1;
                        if (p->opr.op[1]->rng.nops < 3) n2 = 1;
                        if (success) {
                            rv.type = typeFits;
                            rv.fvalue = CreateFits();
                            if (eArgs[1].type == typeFits) {
                                success = eArgs[0].fvalue->extractRange(*rv.fvalue, -1, -1, n2, n2, n3, n3);
                                indices = eArgs[1].fvalue;
                            } else if (eArgs[3].type == typeFits) {
                                success = eArgs[0].fvalue->extractRange(*rv.fvalue, n1, n1, -1, -1, n3, n3);
                                indices = eArgs[3].fvalue;
                            } else if (eArgs[5].type == typeFits) {
                                success = eArgs[0].fvalue->extractRange(*rv.fvalue, n1, n1, n2, n2, -1, -1);
                                indices = eArgs[5].fvalue;
                            } else success = FALSE;
                            if (success) {
                                success = rv.fvalue->reindex(*indices);
                            }
                        } else yyerror("Cannot extract a range this way");
                    } else yyerror("Cannot extract a range this way");
                } else success = FALSE;
                }
                    break; /* case RANGE */

                case SETRANGE: {
                    long nops;
                    long i;
                    conValue eArgs[10];
                    conValue var;

/* check argument types */
                    index = p->opr.op[0]->id.i;
                    nops = extractRangeArgs(&variables[index], p, eArgs);
                    if (nops == 0) {
                        success = 0;
                        break;
                    }
                    var = ex(p->opr.op[2]);
                    if (variables[index].type == typeCon || variables[index].type == typeDbl || variables[index].type == typeCom) {
                        if (!(var.type == typeCon || var.type == typeDbl || var.type == typeCom || var.type == typeFits)) {
                            dp_output("Argument is not a number\n");
                            success = 0;
                            break;
                        }
                        bool singleElement = TRUE;
                        if (nops == 1) {
                            if (eArgs[0].fvalue->Nelements() != 1) singleElement = FALSE;
                            if (eArgs[0].fvalue->ValueAt(0) != indexBase) singleElement = FALSE;
                        } else {
                            for (i = 0; i < nops; i++) {
                                dp_debug("setRange: Arg %i is %i\n", eArgs[i].lvalue);
                                if (eArgs[i].lvalue != 1) singleElement = FALSE;
                            }
                        }
                        if (!singleElement) {
                            dp_output("Variable needs to be an array in this context\n");
                            success = 0;
                            break;
                        }
                        variables[index].type = var.type;
                        if (var.type == typeCon) variables[index].lvalue = var.lvalue;
                        if (var.type == typeDbl) variables[index].dvalue = var.dvalue;
                        if (var.type == typeCom) variables[index].cvalue = CreateComplex(*var.cvalue);
                    }

                    if (variables[index].type == typeStrarr) {
                        if (eArgs[0].lvalue < 1) {
                            dp_output("Setting range: Index <= 0 not allowed for string array variable %s\n", svariables[index].c_str());
                            success = 0;
                            break;
                        }
                        if (var.type == typeStr) {
                            for (long n = eArgs[0].lvalue - 1; n <= eArgs[1].lvalue - 1; n++) (*variables[index].arrvalue)[n] = (*var.svalue);
                        } else {
                            dp_output("Argument is not a string\n");
                            success = 0;
                            break;
                        }
                    } else if (variables[index].type == typeStr) {
                        if (var.type != typeStr) {
                            dp_output("Argument is not a string\n");
                            success = 0;
                            break;
                        }
                        if (eArgs[1].lvalue == 0) eArgs[1].lvalue = eArgs[0].lvalue;
                        if (eArgs[0].lvalue < 1) {
                            dp_output("Setting range: Index <= 0 not allowed for string variable %s\n", svariables[index].c_str());
                            success = 0;
                            break;
                        }
                        variables[index].svalue->remove(eArgs[0].lvalue - 1, eArgs[1].lvalue - eArgs[0].lvalue + 1);
                        variables[index].svalue->insert(eArgs[0].lvalue - 1, *var.svalue);
                    } else if (variables[index].type == typeFits) {
                        if (var.type == typeCon) {
                            var.type = typeDbl;
                            var.dvalue = (double)var.lvalue;
                        }
                        if (var.type == typeFitsFile) {
                            var.type = typeFits;
                            var.fvalue = CreateFits();
                            success = var.fvalue->ReadFITS(var.ffvalue->c_str());
                            if (success == 0) break;
                        }
                        if ((var.type != typeDbl) && (var.type != typeFits)) {
                            yyerror("invalid argument for setting range");
                            success = 0;
                            break;
                        }
                        if (nops == 1) {
                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->setRawRange(var.dvalue, *eArgs[0].fvalue);
//                                break;
                            } else {
                                yyerror("invalid argument for setting range");
                                success = 0;
                                break;
                            }
                        } else if (nops == 2) {
                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->setRawRange(var.dvalue, eArgs[0].lvalue, eArgs[1].lvalue);
//                                break;
                            } else {
                                if (var.type != typeFits) {
                                    yyerror("invalid argument for setting range");
                                    success = 0;
                                    break;
                                }
                                variables[index].fvalue->setRange(*var.fvalue, eArgs[0].lvalue, eArgs[1].lvalue, 1, 1, 1, 1);
                            }
                        } else if (variables[index].fvalue->Naxis(0) == 2) {
                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->setRange(var.dvalue, eArgs[0].lvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, 1, 1);
//                                break;
                            } else {
                                if (var.type != typeFits) {
                                    yyerror("invalid argument for setting range");
                                    success = 0;
                                    break;
                                }
                                variables[index].fvalue->setRange(*var.fvalue, eArgs[0].lvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, 1, 1);
                            }
                        } else if (variables[index].fvalue->Naxis(0) == 3) {
                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->setRange(var.dvalue, eArgs[0].lvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, eArgs[4].lvalue, eArgs[5].lvalue);
//                                break;
                            } else {
                                if (var.type != typeFits) {
                                    yyerror("invalid argument for setting range");
                                    success = 0;
                                    break;
                                }
                                success = variables[index].fvalue->setRange(*var.fvalue, eArgs[0].lvalue, eArgs[1].lvalue, eArgs[2].lvalue, eArgs[3].lvalue, eArgs[4].lvalue, eArgs[5].lvalue);
                            }
                        }
                    } else if (variables[index].type == typeDpArr) {
                        if (eArgs[0].lvalue < 0) {
                            dp_output("Setting range: Index < 0 not allowed for Fits List variable %s\n", svariables[index].c_str());
                            success = 0;
                            break;
                        } else if (eArgs[0].lvalue > variables[index].dparrvalue->size()-1) {
                            dp_output("Setting range: Index > %i not allowed for Fits List variable %s\n", eArgs[0].lvalue, svariables[index].c_str());
                            success = 0;
                            break;
                        }
                        if ((var.type != typeFits) && (var.type != typeStrarr)) {
                            dp_output("Setting range: Argument must be of type FITS or String Array");
                            success = 0;
                            break;
                        }
                        switch ((*variables[index].dparrvalue).at(eArgs[0].lvalue)->type) {
                            case typeFits:
                                addToListOfFits((*variables[index].dparrvalue).at(eArgs[0].lvalue)->fvalue);
                                break;
                            case typeStrarr:
                                addToListOfdpStringArrays((*variables[index].dparrvalue).at(eArgs[0].lvalue)->arrvalue);
                                break;
                            default:
                                break;
                        }

                        dpuserType *toAppend_tmp, *toAppend;
                        toAppend_tmp = new dpuserType(var);
                        toAppend = new dpuserType;
                        switch (var.type) {
                            case typeFits:
                                if (isVariable(toAppend_tmp->fvalue)) {
                                    toAppend->deep_copy(*toAppend_tmp);
                                    ((*variables[index].dparrvalue)[eArgs[0].lvalue])->copy(*toAppend);
                                } else {
                                    deleteFromListOfFits(toAppend_tmp->fvalue);
                                    ((*variables[index].dparrvalue)[eArgs[0].lvalue])->copy(*toAppend_tmp);
                                }
                                break;
                            case typeStrarr:
                                if (isVariable(toAppend_tmp->arrvalue)) {
                                    toAppend->deep_copy(*toAppend_tmp);
                                    ((*variables[index].dparrvalue)[eArgs[0].lvalue])->copy(*toAppend);
                                } else {
                                    deleteFromListOfdpStringArrays(toAppend_tmp->arrvalue);
                                    ((*variables[index].dparrvalue)[eArgs[0].lvalue])->copy(*toAppend_tmp);
                                }
                                break;
                            default: break;
                        }
                }
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break; /* case SETRANGE */

                case RANGEPlusP: {
                    int n, i;
                    conValue eArgs[10];
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    n = extractRangeArgs(&variables[index], p, eArgs);
                    if (n == 0) {
                        yyerror("Error extracting range arguments");
                        success = 0;
                        break;
                    }
                    for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                    success = variables[index].fvalue->incRange(n, args);
                    if (!success) yyerror("Error incrementing range");
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;
                case RANGEMinusM: {
                    int n, i;
                    conValue eArgs[10];
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    n = extractRangeArgs(&variables[index], p, eArgs);
                    if (n == 0) {
                        yyerror("Error extracting range arguments");
                        success = 0;
                        break;
                    }
                    for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                    success = variables[index].fvalue->decRange(n, args);
                    if (!success) yyerror("Error decrementing range");
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;
                case RANGEPlusE: {
                    int n, i;
                    conValue eArgs[10];
                    conValue var, va[2];
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    if (variables[index].type == typeStrarr) {
                        if (p->opr.op[1]->rng.nops != 2) {
                            yyerror("Wrong number of arguments to access subset of stringarray");
                            success = 0;
                            break;
                        }
                        var = ex(p->opr.op[2]);
                        if ((p->opr.op[1]->rng.op[0] == NULL) && (p->opr.op[1]->rng.op[1] == NULL)) {
                            for (n = 0; n < (long)variables[index].arrvalue->count(); n++) {
                                (*variables[index].arrvalue)[n] += *var.svalue;
                            }
                        } else if (p->opr.op[1]->rng.op[1] == NULL) {
                            va[0] = ex(p->opr.op[1]->rng.op[0]);
                            if (va[0].type == typeDbl) {
                                va[0].lvalue = (long)va[0].dvalue;
                                va[0].type = typeCon;
                            }
                            if (va[0].type != typeCon) {
                                yyerror("Invalid index specifier");
                                success = 0;
                                break;
                            }
                            if ((va[0].lvalue < 1) || (va[0].lvalue > (long)variables[index].arrvalue->count())) {
                                yyerror("Value out of bounds");
                                success = 0;
                                break;
                            }
                            (*variables[index].arrvalue)[va[0].lvalue-1] += *var.svalue;
                        } else {
                            va[0] = ex(p->opr.op[1]->rng.op[0]);
                            va[1] = ex(p->opr.op[1]->rng.op[1]);
                            if (va[0].type == typeDbl) {
                                va[0].lvalue = (long)va[0].dvalue;
                                va[0].type = typeCon;
                            }
                            if (va[1].type == typeDbl) {
                                va[1].lvalue = (long)va[1].dvalue;
                                va[1].type = typeCon;
                            }
                            if ((va[0].type != typeCon) || (va[1].type != typeCon)) {
                                yyerror("Invalid index specifier");
                                success = 0;
                                break;
                            }
                            if ((va[0].lvalue < 1) || (va[0].lvalue > (long)variables[index].arrvalue->count()) ||
                                    (va[1].lvalue < 1) || (va[1].lvalue > (long)variables[index].arrvalue->count()) ||
                                    (va[1].lvalue < va[0].lvalue)) {
                                yyerror("Value out of bounds");
                                success = 0;
                                break;
                            }
                            for (n = va[0].lvalue - 1; n < va[1].lvalue; n++) {
                                (*variables[index].arrvalue)[n] += *var.svalue;
                            }
                        }
                    } else {
                        n = extractRangeArgs(&variables[index], p, eArgs);
                        if (n == 0) {
                            yyerror("Error extracting range arguments");
                            success = 0;
                            break;
                        }
                        for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                        var = ex(p->opr.op[2]);
                        if (var.type == typeCon) {
                            var.type = typeDbl;
                            var.dvalue = (double)var.lvalue;
                        }

                        if ((n == 1) && (eArgs[0].type == typeFits)) {
                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->addRawRange(var.dvalue, *eArgs[0].fvalue);
                            } else {
                                yyerror("invalid argument for adding range");
                                success = 0;
                                break;
                            }
                        } else {

                            if ((var.type != typeDbl) && (var.type != typeFits)) {
                                yyerror("invalid argument for setting range");
                                success = 0;
                                break;
                            }

                            if (var.type == typeDbl) {
                                success = variables[index].fvalue->addRange(var.dvalue, n, args);
                                if (!success) {
                                    yyerror("Error adding constant to range");
                                    break;
                                }
                            } else if (var.type == typeFits) {
                                success = variables[index].fvalue->addRange(*var.fvalue, n, args);
                                if (!success) {
                                    yyerror("Error adding array to range");
                                    break;
                                }
                            }
                        }
                    }
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;

                case RANGEMinusE: {
                    int n, i;
                    conValue eArgs[10];
                    conValue var;
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    n = extractRangeArgs(&variables[index], p, eArgs);
                    if (n == 0) {
                        yyerror("Error extracting range arguments");
                        success = 0;
                        break;
                    }
                    for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                    var = ex(p->opr.op[2]);
                    if (var.type == typeCon) {
                        var.type = typeDbl;
                        var.dvalue = (double)var.lvalue;
                    }

                    if ((n == 1) && (eArgs[0].type == typeFits)) {
                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->subRawRange(var.dvalue, *eArgs[0].fvalue);
                        } else {
                            yyerror("invalid argument for adding range");
                            success = 0;
                            break;
                        }
                    } else {
                        if ((var.type != typeDbl) && (var.type != typeFits)) {
                            yyerror("invalid argument for setting range");
                            success = 0;
                            break;
                        }

                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->subRange(var.dvalue, n, args);
                            if (!success) {
                                yyerror("Error adding constant to range");
                                break;
                            }
                        } else if (var.type == typeFits) {
                            success = variables[index].fvalue->subRange(*var.fvalue, n, args);
                            if (!success) {
                                yyerror("Error adding array to range");
                                break;
                            }
                        }
                    }
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;

                case RANGEMulE: {
                    int n, i;
                    conValue eArgs[10];
                    conValue var;
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    n = extractRangeArgs(&variables[index], p, eArgs);
                    if (n == 0) {
                        yyerror("Error extracting range arguments");
                        success = 0;
                        break;
                    }
                    for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                    var = ex(p->opr.op[2]);
                    if (var.type == typeCon) {
                        var.type = typeDbl;
                        var.dvalue = (double)var.lvalue;
                    }

                    if ((n == 1) && (eArgs[0].type == typeFits)) {
                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->mulRawRange(var.dvalue, *eArgs[0].fvalue);
                        } else {
                            yyerror("invalid argument for adding range");
                            success = 0;
                            break;
                        }
                    } else {
                        if ((var.type != typeDbl) && (var.type != typeFits)) {
                            yyerror("invalid argument for setting range");
                            success = 0;
                            break;
                        }

                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->mulRange(var.dvalue, n, args);
                            if (!success) {
                                yyerror("Error adding constant to range");
                                break;
                            }
                        } else if (var.type == typeFits) {
                            success = variables[index].fvalue->mulRange(*var.fvalue, n, args);
                            if (!success) {
                                yyerror("Error adding array to range");
                                break;
                            }
                        }
                    }
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;

                case RANGEDivE: {
                    int n, i;
                    conValue eArgs[10];
                    conValue var;
                    long args[10];

                    index = p->opr.op[0]->id.i;
                    n = extractRangeArgs(&variables[index], p, eArgs);
                    if (n == 0) {
                        yyerror("Error extracting range arguments");
                        success = 0;
                        break;
                    }
                    for (i = 0; i < n; i++) args[i] = eArgs[i].lvalue;
                    var = ex(p->opr.op[2]);
                    if (var.type == typeCon) {
                        var.type = typeDbl;
                        var.dvalue = (double)var.lvalue;
                    }

                    if ((n == 1) && (eArgs[0].type == typeFits)) {
                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->divRawRange(var.dvalue, *eArgs[0].fvalue);
                        } else {
                            yyerror("invalid argument for adding range");
                            success = 0;
                            break;
                        }
                    } else {
                        if ((var.type != typeDbl) && (var.type != typeFits)) {
                            yyerror("invalid argument for setting range");
                            success = 0;
                            break;
                        }

                        if (var.type == typeDbl) {
                            success = variables[index].fvalue->divRange(var.dvalue, n, args);
                            if (!success) {
                                yyerror("Error adding constant to range");
                                break;
                            }
                        } else if (var.type == typeFits) {
                            success = variables[index].fvalue->divRange(*var.fvalue, n, args);
                            if (!success) {
                                yyerror("Error adding array to range");
                                break;
                            }
                        }
                    }
#ifdef DPQT
                    // Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                }
                    break;
                case ';':
                    if ((p->opr.op[0] == NULL) && (p->opr.op[1] == NULL)) {
//                        freePointerlist();
                    }
                    ex(p->opr.op[0]); rv = ex(p->opr.op[1]); break;
                case '=':
#ifdef DPQT
// Lock QFitsView buffer
//                    dpusermutex->lock();
//                    if (fitsMainWindow) buffers[p->opr.op[0]->id.i].data = NULL;
//                    dpusermutex->unlock();
#endif /* DPQT */
                    rv = ex(p->opr.op[1]);
                    if (rv.type == typeUnknown) {
                        success = 0;
                    } else if (rv.type == typeFitsFile) {
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        success = rv.fvalue->ReadFITS(rv.ffvalue->c_str());
                    } else if (rv.type == typeStr) {
                        rv.type = typeStr;
                        rv.svalue = CreateString(*rv.svalue);
                    } else if (rv.type == typeFits) {
                        if (isVariable(rv.fvalue) == 1) {
                            Fits *_tmp;
                            _tmp = CreateFits();
                            success = _tmp->copy(*rv.fvalue);
                            if (success) rv.fvalue = _tmp;
                        }
                    } else if (rv.type == typeCom) {
                        if (isVariable(rv.cvalue) == 1) {
                            rv.cvalue = CreateComplex(*rv.cvalue);
                        }
                    } else if (rv.type == typeStrarr) {
                        if (isVariable(rv.arrvalue) == 1) {
                            rv.arrvalue = CreateStringArray(*rv.arrvalue);
                        }
                    } else if (rv.type == typeDpArr) {
                        if (isVariable(rv.dparrvalue) == 1) {
                            rv.dparrvalue = CreateDpList(*rv.dparrvalue);
                        }
                    }
                    if (success) {
                        if (p->opr.op[0]->id.i == 7) {
                            if (rv.type == typeDbl) {
                                rv.lvalue = (long)rv.dvalue;
                                rv.type = typeCon;
                            }
                            if (rv.type != typeCon) {
                                dp_output("Variable tmpmem must be of integer type\n");
                                success = 0;
                                break;
                            } else if (rv.lvalue < 1) {
                                dp_output("Variable tmpmem must be >= 1\n");
                                success = 0;
                                break;
                            }
                            MEDIAN_MEM = rv.lvalue;
                        }
                        if (svariables[p->opr.op[0]->id.i] == "buffer1") {
                                                        if (rv.type != typeFits && rv.type != typeDpArr) {
                                dp_output("Variable buffer1 must be of FITS type\n");
                                success = 0;
                                break;
                            }
                        }
#ifdef DPQT
// Lock QFitsView buffer
                        QWriteLocker locker(&buffersLock);
                        if (rv.type == typeFits) {
                            if (variables[p->opr.op[0]->id.i].type == typeFits) {
                                resetGUIsettings =  (rv.fvalue->matches(*(variables[p->opr.op[0]->id.i].fvalue)));
                            } else {
                                resetGUIsettings = false;
                            }
                        }
#endif
                        variables[p->opr.op[0]->id.i] = rv;
            } else {
//TODO: Delete the variable? See free() command in dpuser.pgplot.cpp
            if (svariables[p->opr.op[0]->id.i] != "buffer1") {
                svariables[p->opr.op[0]->id.i] = "";
            }
          }
#ifdef DPQT
// Notify QFitsView of variable change
                        dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                    break;
                case WRITEFITS: rv = ex(p->opr.op[1]);
                    va[0] = ex(p->opr.op[0]);
                    if (rv.type == typeFitsFile) {
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        success = rv.fvalue->ReadFITS(rv.ffvalue->c_str());
                    }
                    if (rv.type != typeFits) {
                        yyerror("Don't know how to write this to a fits file");
                        success = 0;
                        break;
                    }
                    if (success) {
                        if (va[0].type == typeFitsFile)
                            success = rv.fvalue->WriteFITS(va[0].ffvalue->c_str());
                        else if (va[0].type == typeStr)
                            success = rv.fvalue->WriteFITS(va[0].svalue->c_str());
                    }
                    break;
        case UMINUS: rv = ex(p->opr.op[0]);
                    switch(rv.type) {
                        case typeCon: rv.lvalue *= -1; break;
                        case typeDbl: rv.dvalue *= -1.0; break;
                        case typeCom:
                            if (isVariable(rv.cvalue) != 0) {
                                rv.cvalue = CreateComplex(*rv.cvalue);
                            }
                            *rv.cvalue *= -1.0;
                            break;
                        case typeFitsFile:
                            rv.type = typeFits;
                            rv.fvalue = CreateFits();
                            if (!rv.fvalue->ReadFITS(rv.ffvalue->c_str())) {
                                success = 0;
                                break;
                            }
                        case typeFits:
                            if (isVariable(rv.fvalue) != 0) {
                                Fits *_tmp = rv.fvalue;
                                rv.fvalue = CreateFits();
                                if (!rv.fvalue->copy(*_tmp)) {
                                    success = 0;
                                    break;
                                }
                            }
                            *rv.fvalue *= -1.0; break;
                        default: success = 0; break;
                    }
                    break;
                case PlusE:
                case MinusE:
                case MulE:
                case DivE:
                    o = p->opr.oper;
                    index = p->opr.op[0]->id.i;
                    va[0] = variables[index];
                    va[1] = ex(p->opr.op[1]);
                    if (va[0].type == typeFits) {
                        if (va[1].type == typeFitsFile) {
                            va[1].fvalue = CreateFits();
                            success = va[1].fvalue->ReadFITS(va[1].ffvalue->c_str());
                            va[1].type = typeFits;
                        }
                    }
                    if (!success) break;
                    rv.type = matchArgTypes(va);
                    if (rv.type == typeUnknown) {
                        success = 0;
                        break;
                    }
                    switch (va[0].type) {
                        case typeDbl: switch(o) {
                            case PlusE: rv.dvalue = va[0].dvalue + va[1].dvalue; break;
                            case MinusE: rv.dvalue = va[0].dvalue - va[1].dvalue; break;
                            case MulE: rv.dvalue = va[0].dvalue * va[1].dvalue; break;
                            case DivE: rv.dvalue = va[0].dvalue / va[1].dvalue; break;
                            default: success = 0; break;
                        }
                        variables[index] = rv;
                        break;
                        case typeCon: switch(o) {
                            case PlusE: rv.lvalue = va[0].lvalue + va[1].lvalue; break;
                            case MinusE: rv.lvalue = va[0].lvalue - va[1].lvalue; break;
                            case MulE: rv.lvalue = va[0].lvalue * va[1].lvalue; break;
                            case DivE:
                                if (va[0].lvalue % va[1].lvalue != 0) {
                                    rv.type = typeDbl;
                                    rv.dvalue = (double)va[0].lvalue / (double)va[1].lvalue;
                                } else {
                                    rv.lvalue = va[0].lvalue / va[1].lvalue;
                                }
                                break;
                            default: success = 0; break;
                        }
                        variables[index] = rv;
                        break;
                        case typeCom: rv = va[0];
                        switch(o) {
                            case PlusE: *rv.cvalue = *va[0].cvalue + *va[1].cvalue; break;
                            case MinusE: *rv.cvalue = *va[0].cvalue - *va[1].cvalue; break;
                            case MulE: *rv.cvalue = *va[0].cvalue * *va[1].cvalue; break;
                            case DivE: *rv.cvalue = *va[0].cvalue / *va[1].cvalue; break;
                            default: success = 0; break;
                        }
                        variables[index] = rv;
                        break;
                        case typeFits: {
                            rv = va[0];
#ifdef DPQT
// Lock QFitsView buffer
                            QWriteLocker locker(&buffersLock);
#endif
/*                            if (va[1].type == typeFits) {
                                if ((rv.fvalue->Naxis(1) != va[1].fvalue->Naxis(1)) ||
                                        (rv.fvalue->Naxis(2) != va[1].fvalue->Naxis(2))) {
                                    yyerror("The two FITS do not match in size");
                                    success = 0;
                                    break;
                                }
                            }*/
                            switch(va[1].type) {
                                case typeFits: switch(o) {
                                    case PlusE: *rv.fvalue += *va[1].fvalue; break;
                                    case MinusE: *rv.fvalue -= *va[1].fvalue; break;
                                    case MulE: *rv.fvalue *= *va[1].fvalue; break;
                                    case DivE: *rv.fvalue /= *va[1].fvalue; break;
                                    default: success = 0; break;
                                }
                                break;
                                case typeDbl: switch(o) {
                                    case PlusE: *rv.fvalue += va[1].dvalue; break;
                                    case MinusE: *rv.fvalue -= va[1].dvalue; break;
                                    case MulE: *rv.fvalue *= va[1].dvalue; break;
                                    case DivE: *rv.fvalue /= va[1].dvalue; break;
                                    default: success = 0; break;
                                }
                                break;
                                default: success = 0; yyerror("invalid operation to fits"); break;
                            }
                            variables[index] = rv;
                        }
                            break;
                        case typeStr: switch(o) {
                            case PlusE: switch (va[1].type) {
                                case typeStr: *variables[index].svalue += *va[1].svalue; break;
                                default: success = 0; yyerror("Cannot add this to a string\n");break;
                            }
                                break;
                            default: success = 0; yyerror("Invalid operator for strings\n"); break;
                        }
                        break;
                        case typeStrarr: switch(o) {
                            case PlusE: switch (va[1].type) {
                                case typeStrarr: *variables[index].arrvalue += *va[1].arrvalue; break;
                                case typeStr: variables[index].arrvalue->append(*va[1].svalue); break;
                                default: break;
                            }
                        }
                        break;
                        case typeDpArr: switch(o) {
                            case PlusE: {
                                dpuserType *toAppend_tmp, *toAppend;
                                toAppend_tmp = new dpuserType(va[1]);
                                toAppend = new dpuserType;
                                switch (va[1].type) {
                                    case typeFits:
                                        if (isVariable(toAppend_tmp->fvalue)) {
                                            toAppend->deep_copy(*toAppend_tmp);
                                            variables[index].dparrvalue->push_back(toAppend);
                                        } else {
                                            deleteFromListOfFits(toAppend_tmp->fvalue);
                                            variables[index].dparrvalue->push_back(toAppend_tmp);
                                        }
                                        break;
                                    case typeStrarr:
                                        if (isVariable(toAppend_tmp->arrvalue)) {
                                            toAppend->deep_copy(*toAppend_tmp);
                                            variables[index].dparrvalue->push_back(toAppend);
                                        } else {
                                            deleteFromListOfdpStringArrays(toAppend_tmp->arrvalue);
                                            variables[index].dparrvalue->push_back(toAppend_tmp);
                                        }
                                        break;
                                    default: break;
                                }
                            }
                        }
                        break;
                        default: success = 0; break;
                    }
#ifdef DPQT
// Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                    break;
                case PlusP:
                    index = p->opr.op[0]->id.i;
                    if (variables[index].type == typeDbl) variables[index].dvalue++;
                    if (variables[index].type == typeCon) variables[index].lvalue++;
                    if (variables[index].type == typeCom) *variables[index].cvalue += 1.0;
                    if (variables[index].type == typeFits) {
#ifdef DPQT
// Lock QFitsView buffer
                        QWriteLocker locker(&buffersLock);
#endif
                        *variables[index].fvalue += 1.0;
                    }
                    rv = variables[index];
#ifdef DPQT
// Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                    break;
                case MinusM:
                    index = p->opr.op[0]->id.i;
                    if (variables[index].type == typeDbl) variables[index].dvalue--;
                    if (variables[index].type == typeCon) variables[index].lvalue--;
                    if (variables[index].type == typeCom) *variables[index].cvalue -= 1.0;
                    if (variables[index].type == typeFits) {
#ifdef DPQT
// Lock QFitsView buffer
                        QWriteLocker locker(&buffersLock);
#endif
                        *variables[index].fvalue -= 1.0;
                    }
                    rv = variables[index];
#ifdef DPQT
// Notify QFitsView of variable change
                    dpUpdateVar(p->opr.op[0]->id.i);
#endif /* DPQT */
                    break;
                case AND:
                    va[0] = ex(p->opr.op[0]);
                    va[1] = ex(p->opr.op[1]);
                    if (va[0].type == typeFits) {
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        rv.fvalue->dpAND(*(va[0].fvalue), *(va[1].fvalue));
//                        CloneValue(va[0], &rv);
//                        rv.fvalue->whereAND(*va[1].fvalue);
                    } else {
                        rv.type = typeCon;
                        rv.lvalue = va[0].lvalue && va[1].lvalue;
                    }
                    break;
                case OR:
                    va[0] = ex(p->opr.op[0]);
                    va[1] = ex(p->opr.op[1]);
                    if (va[0].type == typeFits) {
                        rv.type = typeFits;
                        rv.fvalue = CreateFits();
                        rv.fvalue->dpOR(*(va[0].fvalue), *(va[1].fvalue));
//                        CloneValue(va[0], &rv);
//                        rv.fvalue->whereOR(*va[1].fvalue);
                    } else {
                        rv.type = typeCon;
                        rv.lvalue = va[0].lvalue || va[1].lvalue;
                    }
                    break;
                case '!': rv.type = typeCon;
                    rv = ex(p->opr.op[0]);
                    rv.lvalue = !rv.lvalue;
                    break;
                case '?': if (ex(p->opr.op[0]).lvalue) rv = ex(p->opr.op[1]);
                else rv = ex(p->opr.op[2]);
                break;

        case '+':
        case '-':
        case '*':
        case '/':
        case '#':
        case '%':
            va[0] = ex(p->opr.op[0]);
            if (va[0].type == typeUnknown) success = FALSE;
            else va[1] = ex(p->opr.op[1]);
            if (va[1].type == typeUnknown) success = FALSE;
            if (!success)
                break;
            rv = doArithmetic(&va[0], p->opr.oper, &va[1]);
            break;
                case '^':
                case '<':
                case '>':
                case GE:
                case LE:
                case NE:
                case EQ:
                    o = p->opr.oper;

                    va[0] = ex(p->opr.op[0]);
                    if (va[0].type == typeUnknown)
                        success = FALSE;
                    else
                        va[1] = ex(p->opr.op[1]);
                    if (va[1].type == typeUnknown)
                        success = FALSE;
                    if (!success)
                        break;
/* START: dead code */
                    if ((o == '+') && ((va[0].type == typeStrarr) || (va[1].type == typeStrarr))) {
                        rv.type = typeStrarr;
                        if (va[0].type == typeStr) {
                            rv.arrvalue = CreateStringArray();
                            rv.arrvalue->append(*va[0].svalue);
                        } else if (isVariable(va[0].arrvalue) == 1) {
                            rv.arrvalue = CreateStringArray(*va[0].arrvalue);
                        } else {
                            rv.arrvalue = va[0].arrvalue;
                        }
                        switch (va[1].type) {
                            case typeStrarr: *rv.arrvalue += *va[1].arrvalue; break;
                            case typeStr: rv.arrvalue->append(*va[1].svalue); break;
                            default: success = 0; break;
                        }
                        break;
                    }
/* END: dead code */
                    if (va[0].type == typeFitsFile) {
                        va[0].fvalue = CreateFits();
                        success = va[0].fvalue->ReadFITS(va[0].ffvalue->c_str());
                        va[0].type = typeFits;
                    }

                    if (!success) break;
                    if (va[1].type == typeFitsFile) {
                        va[1].fvalue = CreateFits();
                        success = va[1].fvalue->ReadFITS(va[1].ffvalue->c_str());
                        va[1].type = typeFits;
                    }

                    if (!success) break;
                    rv.type = matchArgTypes(va);
                    if (rv.type == typeUnknown) {
                        success = 0;
                        break;
                    }

                    if ((o == '<') || (o == '>') || (o == GE) || (o == LE) || (o == NE) || (o == EQ)) {
/*                        rv.type = typeCon; */
                    }
                    if ((o == '^') && (rv.type == typeCon)) {
                        va[0].dvalue = (double)va[0].lvalue;
                        va[0].type = typeDbl;
                        va[1].dvalue = (double)va[1].lvalue;
                        va[1].type = typeDbl;
                        rv.type = typeDbl;
                    }
                    switch (rv.type) {
                        case typeDbl: switch (o) {
/* START: dead code */
                            case '+': rv.dvalue = va[0].dvalue + va[1].dvalue; break;
                            case '-': rv.dvalue = va[0].dvalue - va[1].dvalue; break;
                            case '*': rv.dvalue = va[0].dvalue * va[1].dvalue; break;
                            case '/': rv.dvalue = va[0].dvalue / va[1].dvalue; break;
/* END: dead code */
                            case '^': rv.dvalue = pow(va[0].dvalue, va[1].dvalue);
                                if (!gsl_finite(rv.dvalue)) {
                                    rv.type = typeCom;
                                    rv.cvalue = CreateComplex(complex_pow(dpComplex(va[0].dvalue), dpComplex(va[1].dvalue)));
                                }
                                break;
                            case '<': rv.type = typeCon; rv.lvalue = va[0].dvalue < va[1].dvalue; break;
                            case '>': rv.type = typeCon; rv.lvalue = va[0].dvalue > va[1].dvalue; break;
                            case GE: rv.type = typeCon; rv.lvalue = va[0].dvalue >= va[1].dvalue; break;
                            case LE: rv.type = typeCon; rv.lvalue = va[0].dvalue <= va[1].dvalue; break;
                            case NE: rv.type = typeCon; rv.lvalue = va[0].dvalue != va[1].dvalue; break;
                            case EQ: rv.type = typeCon; rv.lvalue = va[0].dvalue == va[1].dvalue; break;
                            default: success = 0; break;
                        }
                            break;
                        case typeCon: switch (o) {
/* START: dead code */
                            case '+': rv.lvalue = va[0].lvalue + va[1].lvalue; break;
                            case '-': rv.lvalue = va[0].lvalue - va[1].lvalue; break;
                            case '*': rv.lvalue = va[0].lvalue * va[1].lvalue; break;
                            case '/':
                                if (va[1].lvalue == 0) {
                                    rv.type = typeDbl;
                                    rv.dvalue = (double)va[0].lvalue / (double)va[1].lvalue;
                                } else if (va[0].lvalue % va[1].lvalue != 0) {
                                    rv.type = typeDbl;
                                    rv.dvalue = (double)va[0].lvalue / (double)va[1].lvalue;
                                } else {
                                    rv.lvalue = va[0].lvalue / va[1].lvalue;
                                }
                                break;
/* END: dead code */
                            case '<': rv.lvalue = va[0].lvalue < va[1].lvalue; break;
                            case '>': rv.lvalue = va[0].lvalue > va[1].lvalue; break;
                            case GE: rv.lvalue = va[0].lvalue >= va[1].lvalue; break;
                            case LE: rv.lvalue = va[0].lvalue <= va[1].lvalue; break;
                            case NE: rv.lvalue = va[0].lvalue != va[1].lvalue; break;
                            case EQ: rv.lvalue = va[0].lvalue == va[1].lvalue; break;
                            default: success = 0; break;
                        }
                            break;
                        case typeCom: switch (o) {
/* START: dead code */
                            case '+': rv.cvalue = CreateComplex(*va[0].cvalue + *va[1].cvalue); break;
                            case '-': rv.cvalue = CreateComplex(*va[0].cvalue - *va[1].cvalue); break;
                            case '*': rv.cvalue = CreateComplex(*va[0].cvalue * *va[1].cvalue); break;
                            case '/': rv.cvalue = CreateComplex(*va[0].cvalue / *va[1].cvalue); break;
/* END: dead code */
                            case '^':
                rv.cvalue = CreateComplex(complex_pow(*va[0].cvalue, *va[1].cvalue));
                break;
                            case NE: rv.type = typeCon; rv.lvalue = *va[0].cvalue != *va[1].cvalue; break;
                            case EQ: rv.type = typeCon; rv.lvalue = *va[0].cvalue == *va[1].cvalue; break;
                            default: success = 0; yyerror("Operator not applicable to complex numbers"); break;
                        }
                            break;
                        case typeFits:
                            if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                if ((va[0].fvalue->Naxis(1) != va[1].fvalue->Naxis(1)) ||
                                        (va[0].fvalue->Naxis(2) != va[1].fvalue->Naxis(2))) {
                                    yyerror("The two FITS do not match in size");
                                    success = 0;
                                    break;
                                }
                            }
                            switch (o) {
                            case '>':
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpGT(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpGT(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpLT(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
                            case GE:
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpGE(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpGE(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpLE(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
                            case '<':
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpLT(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpLT(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpGT(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
                            case LE:
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpLE(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpLE(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpGE(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
                            case EQ:
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpEQ(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpEQ(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpEQ(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
                            case NE:
                                rv.fvalue = CreateFits();
                                if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpNE(*(va[0].fvalue), *(va[1].fvalue));
                                } else if ((va[0].type == typeFits) && (va[1].type == typeDbl)) {
                                    success = rv.fvalue->dpNE(*(va[0].fvalue), va[1].dvalue);
                                } else if ((va[0].type == typeDbl) && (va[1].type == typeFits)) {
                                    success = rv.fvalue->dpNE(*(va[1].fvalue), va[0].dvalue);
                                }
                                break;
/* START: dead code */
                            case '+': if (va[0].type == typeDbl) {
                                if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[1].fvalue);
                                }
                                if (success) *rv.fvalue += va[0].dvalue;
                                break;
                            } else if (va[1].type == typeDbl) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                }
                                if (success) *rv.fvalue += va[1].dvalue;
                                break;
                            } else if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                    *rv.fvalue += *va[1].fvalue;
                                } else if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                    *rv.fvalue += *va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                    if (success) *rv.fvalue += *va[1].fvalue;
                                }
                                break;
                            } else {
                                yyerror("invalid operation to fits");
                                success = 0;
                                break;
                            }
                                break;
                            case '-': if (va[0].type == typeDbl) {
                                if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[1].fvalue);
                                }
                                if (success) {
                                    *rv.fvalue *= -1.0;
                                    *rv.fvalue += va[0].dvalue;
                                }
                                break;
                            } else if (va[1].type == typeDbl) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                }
                                if (success) *rv.fvalue -= va[1].dvalue;
                                break;
                            } else if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                    *rv.fvalue -= *va[1].fvalue;
                                } else if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                    *rv.fvalue *= -1.0;
                                    *rv.fvalue += *va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                    if (success) *rv.fvalue -= *va[1].fvalue;
                                }
                                break;
                            } else {
                                yyerror("invalid operation to fits");
                                success = 0;
                                break;
                            }
                                break;
                            case '*': if (va[0].type == typeDbl) {
                                if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[1].fvalue);
                                }
                                if (success) *rv.fvalue *= va[0].dvalue;
                                break;
                            } else if (va[1].type == typeDbl) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                }
                                if (success) *rv.fvalue *= va[1].dvalue;
                                break;
                            } else if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                    *rv.fvalue *= *va[1].fvalue;
                                } else if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                    *rv.fvalue *= *va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                    if (success) *rv.fvalue *= *va[1].fvalue;
                                }
                                break;
                            } else {
                                yyerror("invalid operation to fits");
                                success = 0;
                                break;
                            }
                                break;
                            case '/': if (va[0].type == typeDbl) {
                                if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[1].fvalue);
                                }
                                if (success) {
                                    rv.fvalue->invert();
                                    *rv.fvalue *= va[0].dvalue;
                                }
                                break;
                            } else if (va[1].type == typeDbl) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                }
                                if (success) *rv.fvalue /= va[1].dvalue;
                                break;
                            } else if ((va[0].type == typeFits) && (va[1].type == typeFits)) {

                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                    *rv.fvalue /= *va[1].fvalue;
                                } else if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                    rv.fvalue->invert();
                                    *rv.fvalue *= *va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                    if (success) *rv.fvalue /= *va[1].fvalue;
                                }
                                break;
                            } else {
                                yyerror("invalid operation to fits");
                                success = 0;
                                break;
                            }
/* END: dead code */
                            case '^': if (va[0].type == typeDbl) {
                                if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[1].fvalue);
                                }
                                if (success) {
                    if (rv.fvalue->getType() == C16) {
                        success = rv.fvalue->setType(C16);
                        if (success) {
                            dpComplex tmp;
                            for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                                tmp = complex_pow(dpComplex(va[0].dvalue),
                                                  dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i));
                                rv.fvalue->cdata[i].r = tmp.real();
                                rv.fvalue->cdata[i].i = tmp.imag();
                            }
                        }
                    } else {
                        success = rv.fvalue->setType(R8);
                        if (success) {
                            for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                                rv.fvalue->r8data[i] = pow(va[0].dvalue, rv.fvalue->r8data[i]);
                            }
                        }
                    }
                                }
                                break;
                            } else if (va[1].type == typeDbl) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                                }
                                if (success) *rv.fvalue ^= va[1].dvalue;
                                break;
                            } else if ((va[0].type == typeFits) && (va[1].type == typeFits)) {
                                if (isVariable(va[0].fvalue) == 0) {
                                    rv.fvalue = va[0].fvalue;

                  if ((rv.fvalue->getType() == C16) || (va[1].fvalue->getType() == C16)) {
                    if (success)
                        success = rv.fvalue->setType(C16);
                    if (success) {
                        dpComplex tmp;
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            if (va[1].fvalue->getType() == C16) {
                                tmp = complex_pow(dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i),
                                                  dpComplex(va[1].fvalue->cdata[i].r, va[1].fvalue->cdata[i].i));
                            } else {
                                tmp = complex_pow(dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i),
                                                  dpComplex(va[1].fvalue->ValueAt(i)));
                            }
                            rv.fvalue->cdata[i].r = tmp.real();
                            rv.fvalue->cdata[i].i = tmp.imag();
                        }
                    }
                  } else {
                    if (success)
                        success = rv.fvalue->setType(R8);
                    if (success) {
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            rv.fvalue->r8data[i] = pow(rv.fvalue->r8data[i], va[1].fvalue->ValueAt(i));
                        }
                    }
                  }
                                } else if (isVariable(va[1].fvalue) == 0) {
                                    rv.fvalue = va[1].fvalue;
                  if ((rv.fvalue->getType() == C16) || (va[0].fvalue->getType() == C16)) {
                    if (success)
                        success = rv.fvalue->setType(C16);
                    if (success) {
                        dpComplex tmp;
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            if (va[0].fvalue->getType() == C16) {
                                tmp = complex_pow(dpComplex(va[0].fvalue->cdata[i].r, va[0].fvalue->cdata[i].i),
                                                  dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i));
                            } else {
                                tmp = complex_pow(dpComplex(va[0].fvalue->ValueAt(i)),
                                                  dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i));
                            }
                            rv.fvalue->cdata[i].r = tmp.real();
                            rv.fvalue->cdata[i].i = tmp.imag();
                        }
                    }
                  } else {
                    if (success)
                        success = rv.fvalue->setType(R8);
                    if (success) {
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            rv.fvalue->r8data[i] = pow(va[0].fvalue->ValueAt(i), rv.fvalue->r8data[i]);
                        }
                    }
                  }
                                } else {
                                    rv.fvalue = CreateFits();
                                    success = rv.fvalue->copy(*va[0].fvalue);
                  if ((rv.fvalue->getType() == C16) || (va[1].fvalue->getType() == C16)) {
                    if (success)
                        success = rv.fvalue->setType(C16);
                    if (success) {
                        dpComplex tmp;
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            if (va[1].fvalue->getType() == C16) {
                                tmp = complex_pow(dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i),
                                                    dpComplex(va[1].fvalue->cdata[i].r, va[1].fvalue->cdata[i].i));
                            } else {
                                tmp = complex_pow(dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i),
                                                    dpComplex(va[1].fvalue->ValueAt(i)));
                            }
                            rv.fvalue->cdata[i].r = tmp.real();
                            rv.fvalue->cdata[i].i = tmp.imag();
                        }
                    }
                  } else {
                    if (success)
                        success = rv.fvalue->setType(R8);
                    if (success) {
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                            rv.fvalue->r8data[i] = pow(rv.fvalue->ValueAt(i), va[1].fvalue->ValueAt(i));
                        }
                    }
                  }
                                }
                                break;
                            } else if (va[1].type == typeCom) {
                    if (isVariable(va[0].fvalue) == 0) {
                        rv.fvalue = va[0].fvalue;
                    } else {
                        rv.fvalue = CreateFits();
                        if (success)
                            success = rv.fvalue->copy(*va[0].fvalue);
                    }

                    if (success)
                        success = rv.fvalue->setType(C16);

                    if (success) {
                        dpComplex tmp;
                        for (unsigned long i = 0; i < rv.fvalue->Nelements(); i++) {
                                tmp = complex_pow(dpComplex(rv.fvalue->cdata[i].r, rv.fvalue->cdata[i].i),
                                                  dpComplex(va[1].cvalue->real(), va[1].cvalue->imag()));
                            rv.fvalue->cdata[i].r = tmp.real();
                            rv.fvalue->cdata[i].i = tmp.imag();
                        }
                    }

                                break;
                            } else {
                                yyerror("invalid operation to fits");
                                success = 0;
                                break;
                            }
                                break;
                            default:
                success = 0;
                yyerror("invalid operation to fits");
                break;
                        }
                            break;
                        case typeStr: switch(o) {
/* START: dead code */
                            case '+': if (isVariable(va[0].svalue) == 0) {
                                rv.svalue = va[0].svalue;
                            } else {
                                rv.svalue = CreateString(*va[0].svalue);
                            }
                                *rv.svalue += *va[1].svalue;
                                break;
/* END: dead code */
                            case '<': rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) < 0; break;
                            case '>': rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) > 0; break;
                            case GE: rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) >= 0; break;
                            case LE: rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) <= 0; break;
                            case NE: rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) != 0; break;
                            case EQ: rv.type = typeCon; rv.lvalue = strcmp(va[0].svalue->c_str(), va[1].svalue->c_str()) == 0; break;
                            default: rv.type = typeUnknown; yyerror("Invalid operator for strings"); break;
                        }
                            break;
                        default: success = 0; break;
                    }
                    break;
      }
            break;
        default: success = 0; break;
    }

    if (success) {
        return rv;
    }

    return er;
}

int isStringAVariable(const char *s) {
    int i;

    for (i = 0; i < nvariables; i++) {
        if (svariables[i] == s) return i;
    }
    return -1;
}
