#include <../../nrnconf.h>
/* /local/src/master/nrn/src/oc/getsym.cpp,v 1.2 1996/02/16 16:19:26 hines Exp */
/*
getsym.cpp,v
 * Revision 1.2  1996/02/16  16:19:26  hines
 * OCSMALL used to throw out things not needed by teaching programs
 *
 * Revision 1.1.1.1  1994/10/12  17:22:08  hines
 * NEURON 3.0 distribution
 *
 * Revision 1.4  92/08/18  07:31:38  hines
 * arrays in different objects can have different sizes.
 * Now one uses araypt(symbol, SYMBOL) or araypt(symbol, OBJECTVAR) to
 * return index of an array variable.
 *
 * Revision 1.3  91/10/18  14:40:36  hines
 * symbol tables now are type Symlist containing pointers to first and last
 * symbols.  New symbols get added onto the end.
 *
 * Revision 1.2  91/10/17  15:01:28  hines
 * VAR, STRING now handled with pointer to value located in object data space
 * to allow future multiple objects. Ie symbol for var, string, objectvar
 * has offset into a pointer data space.
 *
 * Revision 1.1  91/10/11  11:12:03  hines
 * Initial revision
 *
 * Revision 3.9  89/07/20  09:52:17  mlh
 * code functions no longer in hoc.h
 *
 * Revision 3.7  89/07/13  08:21:30  mlh
 * stack functions involve specific types instead of Datum
 *
 * Revision 3.4  89/07/12  10:27:00  mlh
 * Lint free
 *
 * Revision 3.3  89/07/10  15:46:00  mlh
 * Lint pass1 is silent. Inst structure changed to union.
 *
 * Revision 2.0  89/07/07  11:36:58  mlh
 * *** empty log message ***
 *
 * Revision 1.1  89/07/07  11:16:01  mlh
 * Initial revision
 *
*/

/* Psym *hoc_getsym("variable") returns a pointer to a new Psym structure
    that contains info used to find where the variable keeps its data.
    Array indices cannot involve local variables.
    Example: hoc_getsym("a[i][j]") depends on the values of i and j when
    hoc_getsym is called; and not on their values when the Psym is used.

   double hoc_getsymval(Psym *p) returns the value of the variable. If an
    array, the indices used are the values they had when hoc_getsym
    was called.

   hoc_assignsym(Psym *p, double val) sets the value of the variable.

   hoc_execstr(char *s) compiles and executes the string
*/
#if OCSMALL
#else

#include "hocgetsym.h"
#include "parse.hpp"
#include "hocparse.h"
#include "code.h"

Psym* hoc_getsym(const char* cp) {
    Symbol *sp, *sym;
    Symlist* symlist = (Symlist*) 0;
    Inst *last, *pcsav;
    int i, n;
    char s[256];
    Psym* p = 0;

    Sprintf(s, "{%s}\n", cp);
    sp = hoc_install("", PROCEDURE, 0., &symlist);
    sp->u.u_proc->defn.in = STOP;
    sp->u.u_proc->list = (Symlist*) 0;
    sp->u.u_proc->nauto = 0;
    n = hoc_xopen_run(sp, s);
    last = (Inst*) sp->u.u_proc->defn.in + n;
    if (n < 5 || last[-3].pf != hoc_eval) {
        hoc_execerror(s, " not a variable");
    }
    last[-3].in = STOP; /*before doing last EVAL*/
    pcsav = hoc_pc;
    hoc_execute(sp->u.u_proc->defn.in);
    hoc_pc = pcsav;

    sym = hoc_spop();
    switch (sym->type) {
    case UNDEF:
        hoc_execerror(s, " is undefined");
    case VAR:
        if (ISARRAY(sym)) {
            Arrayinfo* a;
            if (sym->subtype == NOTUSER) {
                a = OPARINFO(sym);
            } else {
                a = sym->arayinfo;
            }
            p = (Psym*) emalloc((unsigned) (sizeof(Psym) + a->nsub));
            p->arayinfo = a;
            ++a->refcount;
            p->nsub = a->nsub;
            for (i = p->nsub; i > 0;) {
                p->sub[--i] = hoc_xpop();
            }
        } else {
            p = (Psym*) emalloc(sizeof(Psym));
            p->arayinfo = 0;
            p->nsub = 0;
        }
        p->sym = sym;
        break;
    case AUTO:
        hoc_execerror(s, " is local variable");
    default:
        hoc_execerror(s, " not a variable");
    }
    hoc_free_list(&symlist);
    return p;
}

static void arayonstack(Psym* p) {
    int i;
    double d;

    if (p->nsub) {
        if (!ISARRAY(p->sym) || p->nsub != p->arayinfo->nsub) {
            hoc_execerror("wrong number of subscripts for ", p->sym->name);
        }
        for (i = 0; i < p->nsub; i++) {
            d = p->sub[i];
            hoc_pushx(d);
        }
    }
}

double hoc_getsymval(Psym* p) {
    arayonstack(p);
    hoc_pushs(p->sym);
    hoc_eval();
    return hoc_xpop();
}

void hoc_assignsym(Psym* p, double val) {
    arayonstack(p);
    hoc_pushx(val);
    hoc_pushs(p->sym);
    hoc_assign();
    hoc_nopop();
}

void hoc_execstr(const char* cp) {
    Symbol* sp;
    Symlist* symlist = (Symlist*) 0;
    Inst* pcsav;
    char s[256];

    Sprintf(s, "{%s}\n", cp);
    sp = hoc_install("", PROCEDURE, 0., &symlist);
    sp->u.u_proc->defn.in = STOP;
    sp->u.u_proc->list = (Symlist*) 0;
    sp->u.u_proc->nauto = 0;
    IGNORE(hoc_xopen_run(sp, s));
    pcsav = hoc_pc;
    hoc_execute(sp->u.u_proc->defn.in);
    hoc_pc = pcsav;
    hoc_free_list(&symlist);
}
#endif /*OCSMALL*/
