/* >REKEN */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <time.h>

#define POSITIEF 1
#define NUL 0
#define NEGATIEF -1
#define MAXLEN 1000
#define TRUE 1
#define FALSE 0
#define KLEINER -1
#define GELIJK 0
#define GROTER 1
#define PUSH 0x00687370L /*'psh'*/ 
#define POP  0x00706F70L /*'pop'*/
#define MOD  0x00646F6DL /*'mod'*/
#define DIV  0x00766964L /*'div'*/
#define LIST 0x0074736CL /*'lst'*/
#define LOAD 0x00746567L /*'get'*/
#define TYPE 0x00747570L /*'put'*/
#define TABL 0x006C6274L /*'tbl'*/
#define TSET 0x006C6573L /*'sel'*/
#define FLAG 0x00676C66L /*'flg'*/
#define FAC  0x00636166L /*'fac' in flg$fac */
#define PI   0x00006970L /*'pi' */
#define IM   0x00000069L /*'i'  */
#define XX   0x00000065L /*'e'  */
#define MINEEN 0x0000312DL /*'-1'*/
/* vlaggen in knoop */
#define NOT              1L
#define SNIJAF          (1L<< 1)
#define SUCCES          (1L<< 2)
#define KLAAR           (1L<< 3)
#define DUBBEL_GEBRUIKT (1L<< 4)
#define KLEINER_DAN     (1L<< 5)
#define GROTER_DAN      (1L<< 6)
#define UNIFY           (1L<< 7)
#define INDIRECT        (1L<< 8)
#define NUMBER          (1L<< 9)
#define BREUK           (1L<<10)
#define ATOM            (1L<<11)
#define NONIDENT        (1L<<12)
#define DUBBEL_INDIRECT (1L<<13)
#define IDENT           (1L<<14)
#define WORDT   (1L<<16) 
#define KOMMA   (2L<<16)
#define OF      (3L<<16)
#define EN      (4L<<16)
#define MATCH   (5L<<16)
#define DOT     (6L<<16)  /* dummy */
#define PLUS    (7L<<16)
#define MAAL    (8L<<16)
#define EXP     (9L<<16)
#define LOG    (10L<<16)
#define DIF    (11L<<16)
#define FUN    (12L<<16)
#define OPOP   (14L<<16)
#define BEZET           (1L<<31)

#define KILOKNOPEN    20
#define PROMILLAGE4   20
#define PROMILLAGE8  450
#define PROMILLAGE12 530

#define OPERATOR (15L<<16)

#define kop(kn) ((kn)->flgs & OPERATOR)
#define klopcode(kn) (kop(kn) >> 16)

struct knoop
    {
    unsigned long flgs;
    union
        {
        struct 
            {
            struct knoop *links,*rechts;
            } p;
        long iobj;
        char obj;
        } u;
    } voorbeeld,*nulknoop,*eenknoop,*nilknoop,*hknoop,*jknoop,*adr[10],
knopen[4],*m0=NULL,*m1=NULL,*f0=NULL,*f1=NULL,*f4=NULL,*f5=NULL;

typedef struct knoop sk;
typedef sk *psk;
typedef psk *ppsk;
typedef char *qgetal;
typedef char *ngetal;
typedef char **ppchar;
typedef char *pchar;
typedef int *pint;

struct kknoop
    {
    unsigned long flgs;
    psk links,rechts;
    };

char
*soperator[16]=
{"?","=",",","|","&",":",".","+","*","^","L","D","$","?","?","?"},
niks[]="",
min[]="-",
streep[]="/",
maalmineen[]="*-1)",
nul[]="0",
een[]="1",
mineen[]="-1",
twee[]="2",
mintwee[]="-2",
vier[]="4",
hekje1[]="\t1",
hekje2[]="\t2",
hekje3[]="\t3",
hekje4[]="\t4",
hekje7[]="\t7",
plus[]="+",
maal[]="*",
macht[]="^",
haakjeopen[]="(",
haakjesluit[]=")",
op[2]={0,0},
resteken(pchar,pchar),
*koncat(char**),
*concat(char *plijst,...),
*opb(ppsk pkn,pchar),
lijst[MAXLEN+1],
redlijst[MAXLEN+1],
tx,
ty;

struct deelres
    {
    ngetal quot;
    ngetal rest;
    };                        

qgetal
geheeldelen(qgetal,qgetal),
modulo(qgetal,qgetal),
qdema(ngetal,ngetal,ngetal,ngetal),
qmaal(qgetal,qgetal),
qndeel(ngetal,ngetal),
qplus(qgetal,qgetal),
qqdeel(qgetal,qgetal);

ngetal
cyfer(int n),
nmaal(ngetal,ngetal),
nplus(ngetal,ngetal),
ox,
oy,
px,
py;

void
*alloc4(void),
*alloc8(void),
*alloc12(void),
*bmalloc(int n),
a_bc_to_ab_ac(ppsk pkn,char*),
ab_c_to_ac_bc(ppsk pkn,char*,psk lknoop),
bezetting(void),
bfree(void *p),
copyflags(psk bron,ppsk pkn),
eindknoop(psk wortel),
evalnaam(ppsk pkn),
flinkertak(ppsk pkn),
hresult(psk),
init_ruimte(void),
init_variabelen(void),
init_opcode(void),
linkertak(ppsk pkn),
lst(psk kn),
nndeel(ngetal,ngetal,struct deelres *),
nuldelen(void),
numboom(ppsk pkn,psk linksopknoop,pchar conc[]),
opaf(char**,char*,char*,char*,char*,int),
opmaak(psk ,int,int opc),
rechtertak(ppsk pkn),
result(psk),
splits(qgetal,ngetal *,ngetal *),
supernul(ngetal,char),
tbw(ppsk ,pchar,pchar),
trac(void),
vgl(psk kn1,psk kn2),
vrijopb(ppsk pkn,char **),
vrijtbw(ppsk pkn,pchar conc[]),
wis(psk),
xyinit(ngetal,ngetal);

int 
assign(ppsk pkn),
bereken_verschil(qgetal s,qgetal p),
casemacht(ppsk pkn),
compare(psk s,psk p),
complic_term(ppsk pkn),
copy_insert(char *string,psk pknoop),
delete(char *string),
differentieren(ppsk pkn),
eindnum(char*,char**,char**,char*),
evalueer(ppsk pkn),
find_w(psk naamknoop,ppsk pknoop),
functies(ppsk pkn),
getalcheck(qgetal s),
insert(char *string,psk pknoop),
is_afhankelyk_van(psk el,psk lijst),
is_constant(psk),
is_digit(int kar),
kngetalcheck(psk),
knis_qgetal(psk),is_qgetal(qgetal s),
linksbrengen(ppsk pkn),
machtbuitenhaakjes(ppsk pkn),
match(psk sub,psk pat),
match_verschil(int versch,psk s,psk p),
naamwoord_w(psk bron,ppsk pknoop),
output(ppsk pkn,void (*hoe)()),
psh(char *string,psk pknoop,psk hoe),
rechtsbrengen(ppsk pkn),
samenvoegen_of_sorteren(ppsk pkn,psk(*sorteerdeel)(),char *hogere_operator),
sel(psk naamknoop,psk selector),
stapelmacht(ppsk pkn),
startboom_w(char *lijst,ppsk pkn),
substdiff(ppsk pkn),
substlog(ppsk pkn),
substmaal(ppsk pkn),
substmacht(ppsk pkn),
substplus(ppsk pkn),
try_le_elq(psk fun,ppsk pkn),
tryq(ppsk pkn,psk fun),
vergelijk(qgetal,qgetal),
zoeknaam(char *string,struct vars **pvoorvar,struct vars **pnavar);

psk
base(psk pknoop),
copievan(psk ,pchar),
eerste(psk kn),
nonnumfactor(psk pknoop),
quotient_w(psk s,psk p),
rest(psk kn),
subboomcopie(psk),
verschil_w(psk s,psk p),
zelfde_als_w(psk kn);

ppsk
linkeroperand(ppsk pkn);

struct byte4
    {
    unsigned long flgs;
    } *p4,*p4start,*p4end;

struct byte8
    {
    unsigned long flgs;
    long rest1;
    } *p8,*p8start,*p8end;

struct byte12
    {
    unsigned long flgs;
    long rest1;
    long rest2;
    } *p12,*p12start,*p12end;

unsigned
xlengte,
ylengte;

long
globalloc=0,
alloc_cnt=0,
cnts[256],
totcnt=0,
al4=PROMILLAGE4*KILOKNOPEN,
al8=PROMILLAGE8*KILOKNOPEN,
al12=PROMILLAGE12*KILOKNOPEN;

int 
carry,
evaldiepte=0,
abseen,
factorize=FALSE,
geheel,
optab[256],
teken,
trace=FALSE,
dummy_op=PLUS,
ind,
is_groter,
is_gelyk;

struct vars 
    {
    char *name;
    struct vars *next;
    long n;
    long selector;
    psk value[1]; /* arraysize wordt door psh veranderd */
    } *variabelen[256];

FILE
*fpi,
*fpo;

int main()
{
#ifdef ARM
clock_t time0;
#endif
#ifdef MAPSTORE 
extern int _mapstore(void);
#endif
psk anker;
init_variabelen();
init_ruimte();
init_opcode();
anker=NULL;
fpi=stdin;
fpo=stdout;
voorbeeld.flgs = SUCCES | BEZET;
voorbeeld.u.obj=0;

nulknoop = &knopen[1];
nulknoop->flgs = SUCCES | BEZET | IDENT;
nulknoop->u.obj = '0';
*(&(nulknoop->u.obj)+1) = 0;

eenknoop = &knopen[2];
eenknoop->flgs = SUCCES | BEZET | IDENT;
eenknoop->u.obj = '1';
*(&(eenknoop->u.obj)+1) = 0;

nilknoop = &knopen[3];
nilknoop->flgs = SUCCES | BEZET | IDENT;
nilknoop->u.obj = 0;

lijst[0]=0;

opb(&m0,"?*(%+%)^?*?");
opb(&m1,"?*(%+%)*?");
opb(&f0,"pop$(arg,psh$(b,c,d,e,n),\\,!arg:?b*(%?c+%?d)^(?n&!n:>1&!n:~/)*?e&!b*pow$((!c+!d)^!n)*!e)");
opb(&f1,"pop$(arg,psh$(b,c,d,e),\\,!arg:?b*(%?c+%?d)*?e&!b*!c*!e+!b*!d*!e)");
opb(&f4,"pop$(arg,psh$l,\\,!arg:?l^(?+?*!lL?*?+?)&!_03)");
opb(&f5,"pop$(arg,psh$l,\\,!arg:?lL(?*!l^?*?)&!_04)");

startboom_w(
"_01=pop$(psh$(l,r),\\,!arg:!x&!v|!arg:?%l.?%r&_01$!l._01$!r|!arg)",
&anker);

startboom_w("_02=!cnt:!tot&!res|!res+(sbs$(!xD!f:?f,!x,0))*((!fac*(!cnt+1:?cnt)):?fac)^-1*!x^!cnt:?res&!_02",&anker);

startboom_w("_03=pop$(psh$(a,b,c,d,e),!arg:?l^(?a+?b*!lL?c*?d+?e)&!l^(!a+!e)*!c^(!b*!d))",&anker);

startboom_w("_04=pop$(psh$(a,b,c),!arg:?lL(?a*!l^?b*?c)&!lL(!a*!c)+!b)",&anker);
startboom_w(
"_05=pop$(psh$(l,r),\\,(!arg:!!x&!!v:%?l.%?r|!arg:%?l.%?r)&_05$!l._05$!r|!arg)",
&anker);

startboom_w("taylor=pop$(psh$(f,tot,x,fac,cnt,res),\\,!arg:(?%f,?%x,?%tot)&(fac=1)&(cnt=0)&((sbs$(!f,!x,0)):?res)&!_02)",&anker);

startboom_w("_sn=e^(!arg*i)*i*-1/2+e^(!arg*i*-1)*i*1/2",&anker);

startboom_w("_cs=e^(!arg*i)*1/2+e^(!arg*i*-1)*1/2",&anker);

startboom_w("pow=pop$(psh$(a,b,n),\\,!arg:(?%a+?%b)^(?n&!n:>1)&(!n:2&!a^2+!b^2+!a*!b*2|!n:3&!a^3+!b^3+!a^2*!b*3+!a*!b^2*3|mod$(!n,2):0&pow$((!a+!b)^(!n*1/2))^2|pow$((!a+!b)^((!n+-1)*1/2))^2*(!a+!b)))",&anker);

startboom_w("sbs=pop$(psh$(e,x,v,l,r),\\,!arg:(?%e,?%x,?%v)&_01$!e)",
&anker); /* sbs$(<dir>expressie,<dir>patroon,<dir>substitutie) , 
            substitutie wordt bij aanroep van sbs geevalueerd */

startboom_w("sb2=pop$(psh$(e,x,v,l,r),\\,!arg:(?%x,?%v,?%e)&_05$!e)",
&anker); /* sb2$(<dir>expressie,<indir>patroon,<indir>substitutie) , 
            patroon en substitutie worden "laat" geevalueerd */



for(;;)
    {
    strcpy(redlijst,lijst);
    scanf(" %1000s",lijst);
    switch(lijst[0])
        {
        case '.' :
            exit(0);
        case ',' :
            break;
        case '\"' :
            printf(redlijst);
            break;
        case '+' :
            trace=!trace;
            break;
        default :
            #ifdef ARM
            time0=clock();
            #endif
            if(startboom_w(lijst,&anker))
                {
                result(anker);
                printf("\nja\n");
                }
            else
                printf("nee\n");
            wis(anker);
            #ifdef ARM
            printf("%d centiseconden\n",clock()-time0);
            #endif
            anker=NULL;
            printf("Gealloceerd:%d\n",globalloc);
            bezetting();
#ifdef MAPSTORE
            _mapstore();
#endif
        }
    }
}

void trac()
{
psk anker;
char lijst[1000];
trace=FALSE;
anker=NULL;
do
    {
    printf("Voer expressie in:\n");
    lijst[0]=0;
    scanf(" %1000s",lijst);
    if(lijst[0]!=',')
        {
        if(startboom_w(lijst,&anker))
            {
            result(anker);
            printf("\nja\n");
            }
        else
            printf("nee\n");
        }
    printf("Gealloceerd:%d\n",globalloc);
    }
while(lijst[0]!=',');
trace=TRUE;
if(anker)
    wis(anker);
}

int startboom_w(lijst,pkn)
char *lijst;
ppsk pkn;
{
if(*pkn)
    wis(*pkn);
*pkn=NULL;
tbw(pkn,lijst,lijst+strlen(lijst)-1);
return evalueer(pkn);
}

int is_constant(kn)
psk kn;
{
if(kop(kn))
    return is_constant(kn->u.p.links) && is_constant(kn->u.p.rechts);
else
    if(knis_qgetal(kn)
    || kn->u.iobj==IM
    || kn->u.iobj==PI
    || kn->u.iobj==XX)
        return TRUE;
    else
        return FALSE;
}

int knis_qgetal(kn)
psk kn;
{
return !kop(kn) && 
       is_qgetal(&(kn->u.obj));
}

int is_qgetal(s)
qgetal s;
{
return isdigit(*s) || *s == '-';
}

void init_opcode()
{
int tel;
for(tel=0;tel<256;tel++)
    {
    cnts[tel]=0;
    switch (tel)
        {
        case '=' : optab[tel] = WORDT;break;
        case ',' : optab[tel] = KOMMA;break;
        case '|' : optab[tel] = OF   ;break;
        case '&' : optab[tel] = EN   ;break;
        case ':' : optab[tel] = MATCH;break;
        case '.' : optab[tel] = DOT  ;break;   /* dummy */
        case '+' : optab[tel] = PLUS ;break;
        case '*' : optab[tel] = MAAL ;break;
        case '^' : optab[tel] = EXP  ;break;
        case 'L' : optab[tel] = LOG  ;break;
        case 'D' : optab[tel] = DIF  ;break;
        case '$' : optab[tel] = FUN  ;break;
        default  : optab[tel] = OPERATOR;break;
        };
    }
}

psk copievan(kn,string) 
psk kn;
pchar string;
{
psk ret;
ret = bmalloc(sizeof(unsigned long)+strlen(string)+1);
ret->flgs = kn->flgs;
ret->u.iobj=0;
strcpy(&(ret->u.obj),string);
return ret;
}

void vrijopb(pkn,conc)
ppsk pkn;
pchar conc[];
{
bfree(opb(pkn,koncat(conc)));
}

void vrijtbw(pkn,conc)
ppsk pkn;
pchar conc[];
{
char *lijst;
if(*pkn)
    wis(*pkn);
lijst=koncat(conc);
tbw(pkn,lijst,lijst+strlen(lijst)-1);
bfree(lijst);
}

psk zelfde_als_w(kn)
psk kn;
{
if(kn->flgs & DUBBEL_GEBRUIKT)
    return subboomcopie(kn);
else
    {
    kn->flgs |= DUBBEL_GEBRUIKT;
    return kn;
    }
}

char *opb(pkn,lijst)
ppsk pkn;
pchar lijst;
{
static int adrs[11],ind;
char *py;
int *padr,succes;
if((py=strchr(lijst,'\t')) != NULL)
    {
    for(padr=adrs;py;)
        {
        py++;
        ind=*py-'0';
        *padr++=ind;
        if(adr[ind]->flgs & DUBBEL_GEBRUIKT)
            {
            printf("adr[%d]->flgs & DUBBEL_GEBRUIKT\n",ind);
            result(adr[ind]);
            printf("\nFOUT DUS in %s",lijst);
            }
        adr[ind]->flgs |= DUBBEL_GEBRUIKT;
        py=strchr(py,'\t');
        }
    *padr=0;
    if(*pkn)
        {
        succes=(*pkn)->flgs & SUCCES;
        wis(*pkn);
        }
    else
        succes=SUCCES;
    for(padr=adrs;*padr;padr++)
        adr[*padr]->flgs &=~DUBBEL_GEBRUIKT;
    }
else
    if(*pkn)
        {
        succes=(*pkn)->flgs & SUCCES;
        wis(*pkn);
        }
    else
        succes=SUCCES;
tbw(pkn,lijst,lijst+strlen(lijst)-1);
(*pkn)->flgs ^=(succes ^ SUCCES);
return lijst;
}

void wis(top)
psk top;
{
if(!(top->flgs & DUBBEL_GEBRUIKT))
    {
    if(kop(top))
        {
        wis(top->u.p.links);
        wis(top->u.p.rechts);
        }                                                                           bfree(top);
    }
else
    top->flgs &=~DUBBEL_GEBRUIKT;
}

void tbw(pkn,start,finish)
ppsk pkn;
pchar start,finish;
{
register char *px;
char *wortel;
int teken;
register int aantal_haakjes;
int overtollige_haakjes;
aantal_haakjes = 0;
teken = OPOP;
overtollige_haakjes = INT_MAX;
for(px=finish;px >= start;px--)
    {
    switch(*px)
        {
        case ')' :
            aantal_haakjes++;
            break;
        case '(' :
            aantal_haakjes--;
            break;
        default  :
            {
            if(overtollige_haakjes > aantal_haakjes)
                {
                register int hteken;
                overtollige_haakjes = aantal_haakjes;
                if((hteken = optab[*px]) < OPERATOR)
                    {
                    teken = hteken;
                    wortel = px;
                    }
                }
            else
                {
                if(overtollige_haakjes == aantal_haakjes)
                    {
                    register int hteken;
                    if((hteken = optab[*px]) <= teken)
                        {
                        if(teken > hteken)
                            {
                            teken = hteken;
                            wortel = px;
                            }
                        else
                            {
                            if(hteken != PLUS && 
                               hteken != MAAL && 
                               hteken != MATCH)
                                wortel = px;
                            }
                        }
                    }
                }
            }
        }
    }
if(teken == OPOP)
    {
    register char *begin;
    begin=start+overtollige_haakjes;
    if(*begin > ('\v'|'\t'))
        {
        register long vlag;
        wortel = finish - overtollige_haakjes + 1;
        teken = *wortel;
        *wortel = 0;
        vlag=SUCCES | BEZET;
        for(;*begin;begin++)
            {
            switch(*begin)
                {
                case '~' :
                    vlag ^=NOT;
                    vlag ^=SUCCES;
                    continue;
                case '!' :
                    if(vlag & INDIRECT)
                        vlag |= DUBBEL_INDIRECT; 
                    else
                        vlag |= INDIRECT;
                    continue;
                case '?' :
                    vlag |= UNIFY;
                    continue;
                case '<' :
                    vlag |= KLEINER_DAN;
                    continue;
                case '>' :
                    vlag |= GROTER_DAN;
                    continue;
                case '#' :
                    vlag |= NUMBER;
                    continue;
                case '/' :
                    vlag |= BREUK;
                    continue;
                case '@' :
                    vlag |= ATOM;
                    continue;
                case '%' :
                    vlag |= NONIDENT;
                    continue;
                default :
                    *pkn = copievan(&voorbeeld,begin);
                    (*pkn)->flgs=vlag;
                    *wortel = teken;
                    return;
                }
            }
        *pkn = copievan(&voorbeeld,begin);
        (*pkn)->flgs=vlag;
        *wortel = teken;
        }
    else
        {
        if(*begin == '\v')
            *pkn = subboomcopie(adr[*++begin-'0']);
        else
            *pkn = adr[*++begin-'0'];
        }
    }
else
    {
    *pkn = bmalloc(sizeof(struct kknoop));
    (*pkn)->flgs = teken | (BEZET | SUCCES);
    tbw(&((*pkn)->u.p.links),start+overtollige_haakjes,wortel-1);
    tbw(&((*pkn)->u.p.rechts),wortel+1,finish-overtollige_haakjes);
    }
}

int evalueer(pkn)
ppsk pkn;
{
while(!((*pkn)->flgs & KLAAR))
    {
    if((*pkn)->flgs & DUBBEL_GEBRUIKT)
        {
        (*pkn)->flgs &=~DUBBEL_GEBRUIKT;
        *pkn=subboomcopie(*pkn);
        }
    if(trace)
        {
        result(*pkn);
        putc('\n',fpo);
        }
    (*pkn)->flgs |=KLAAR;
    switch(kop(*pkn))
        {
        case WORDT :
            if(evalueer(&((*pkn)->u.p.links)) && 
               assign(pkn))
                linkertak(pkn);
            else
                flinkertak(pkn);
            continue;
        case KOMMA :
/*          rechtsbrengen(pkn); KAN HIER NIET*/
            evalueer(&((*pkn)->u.p.links));
            evalueer(&((*pkn)->u.p.rechts));
            rechtsbrengen(pkn);
            if(!kop((*pkn)->u.p.links) && !((*pkn)->u.p.links->u.obj))
                rechtertak(pkn);
            else
                if(!kop((*pkn)->u.p.rechts) && 
                   !((*pkn)->u.p.rechts->u.obj))
                    linkertak(pkn);
            continue;
        case PLUS :          
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                if(linksbrengen(pkn)
                || substplus(pkn)
                || samenvoegen_of_sorteren(pkn,&nonnumfactor,maal) 
                || factorize /* als er gefactorizeerd moet worden, dan
                                complic_term niet uitvoeren */  
                || complic_term(pkn)
                  );
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;
        case MAAL :
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                if(linksbrengen(pkn)
                || substmaal(pkn)
                || samenvoegen_of_sorteren(pkn,&base,macht));
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;
        case EXP :
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                if(stapelmacht(pkn)        /* (a^b)^c->a^(b*c)             */
                || substmacht(pkn)         /* 0^a 1^a a^0 a^1 n^-1 i^n     */                   || machtbuitenhaakjes(pkn) /* (a+b)^(c+n)->(a+b)^c*(a+b)^n */
                                           /* (a*b)^c->a^c*b^c             */
                || casemacht(pkn)
                || try_le_elq(f4,pkn));
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;                   
        case LOG :
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                if(substlog(pkn)
                || try_le_elq(f5,pkn));
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;
        case DIF :
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                if(!substdiff(pkn))
                    {
                    if(!differentieren(pkn))
                        (*pkn)->flgs ^=SUCCES; /*??????*/
                    }
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;
        case FUN :
            if(evalueer(&((*pkn)->u.p.links)) && 
               evalueer(&((*pkn)->u.p.rechts)))
                {
                rechtsbrengen(pkn);
                if(!functies(pkn))
                    (*pkn)->flgs ^=SUCCES;
                }
            else
                (*pkn)->flgs ^=SUCCES;
            continue;
        case MATCH :
            if(evalueer(&((*pkn)->u.p.links))
            && match((*pkn)->u.p.links,(*pkn)->u.p.rechts))
                linkertak(pkn);
            else
                flinkertak(pkn);
            continue;
        case EN :
            rechtsbrengen(pkn);
            if(evalueer(&((*pkn)->u.p.links)))
                rechtertak(pkn);
            else
                flinkertak(pkn);
            continue;
        case OF :
            rechtsbrengen(pkn);
            if(evalueer(&((*pkn)->u.p.links)))
                linkertak(pkn);
            else
                rechtertak(pkn);
            continue;
        case DOT :
            (*pkn)->flgs &=(~OPERATOR & ~KLAAR);
            (*pkn)->flgs |=dummy_op;
            continue;
        default : 
            if((*pkn)->flgs & INDIRECT)
                evalnaam(pkn);
        }
    }
if(trace)
    {
    if((*pkn)->flgs & SUCCES)
        printf("S:");
    else
        printf("F:");
    result(*pkn);
    putc('\n',fpo);
    trac();
    }
return (*pkn)->flgs & SUCCES;
}

void evalnaam(pkn)
ppsk pkn;
{
psk adr;
adr=NULL;
if(naamwoord_w(*pkn,&adr))
    {
    if(adr->flgs & DUBBEL_GEBRUIKT)
        {
        adr->flgs &=~DUBBEL_GEBRUIKT;
        adr=subboomcopie(adr);
        }
    wis(*pkn);
    *pkn=adr;
    }
else
    (*pkn)->flgs ^=SUCCES;
}

int tryq(pkn,fun)
ppsk pkn;
psk fun;
{
psk anker;
psh("arg",*pkn,NULL);
(*pkn)->flgs |=KLAAR;
anker=subboomcopie(fun);
if(evalueer(&anker))
    {
    wis(*pkn);
    *pkn=anker;
    return TRUE;
    }
else
    {
    wis(anker);
    return FALSE;
    }
}

int complic_term(pkn)
ppsk pkn;
{
ppsk hulp;
hulp=linkeroperand(pkn);
switch(kop(*hulp))
    {
    case MAAL :
    case EXP  :
        if((match(*hulp,m0) && tryq(hulp,f0))
        || (match(*hulp,m1) && tryq(hulp,f1)))
            {
            (*pkn)->flgs &=~KLAAR;
            (*pkn)->u.p.links->flgs &=~KLAAR;
            return TRUE;
            }
        /* "doorvallen" is de bedoeling */
    default :
        {
        hulp=&((*pkn)->u.p.rechts);
        switch(kop(*hulp))
            {
            case MAAL :
            case EXP  :
                if((match(*hulp,m0) && tryq(hulp,f0))
                || (match(*hulp,m1) && tryq(hulp,f1)))
                    {
                    (*pkn)->flgs &=~KLAAR;
                    return TRUE;
                    }
                else
                    return FALSE;
            }
        }
    }
return FALSE;
}

int try_le_elq(fun,pkn)
psk fun;
ppsk pkn;
{
if(!kop((*pkn)->u.p.rechts))
    return FALSE;
else
    return tryq(pkn,fun);
}

int assign(pkn)
ppsk pkn;
{
register psk lknoop;
return !kop(lknoop=(*pkn)->u.p.links) &&
       insert(&(lknoop->u.obj),(*pkn)->u.p.rechts);
}

void init_variabelen()
{
int tel;
for(tel=0;tel<256;variabelen[tel++]=NULL);
}

int psh(string,pknoop,dim)
char *string;
psk pknoop;
psk dim;
{
struct vars *navar,*voorvar,*nieuwvar;
long oldn;
if(!*string || *string=='\\' ||
   (dim && !(kngetalcheck(dim) && geheel && teken==POSITIEF)))
    return FALSE;
if(!zoeknaam(string,&voorvar,&navar))
    {
    insert(string,pknoop);
    if(dim)
        zoeknaam(string,&voorvar,&navar);
    else
        return TRUE;
    }
if(dim)
    {
    navar->n=atoi(&dim->u.obj)-1;
    navar->selector=0;
    oldn=-1;
    }
else
    {
    oldn=navar->n;
    navar->n++;
    navar->selector=navar->n;
    }
nieuwvar=bmalloc(sizeof(struct vars) + navar->n*sizeof(psk));
memcpy(nieuwvar,
       navar,
       sizeof(struct vars) + navar->n*sizeof(psk));
if(voorvar==NULL)
    variabelen[*string]=nieuwvar;
else
    voorvar->next=nieuwvar;
bfree(navar);
for(;++oldn <= nieuwvar->n;)
    nieuwvar->value[oldn]=zelfde_als_w(pknoop);
if(trace)
    {
    printf("psh %s=",nieuwvar->name);
    result(nieuwvar->value[nieuwvar->n]);
    putc('\n',fpo);
    }
return TRUE;
}

int copy_insert(string,pknoop)
char *string;
psk pknoop;
{
int res;
psk kn;
kn=subboomcopie(pknoop);
res=insert(string,kn);
wis(kn);
return res;
}

int insert(string,pknoop)
char *string;
psk pknoop;
{
struct vars *navar,*voorvar,*nieuwvar;
if(!*string || *string=='\\')
    return FALSE;

if(zoeknaam(string,&voorvar,&navar))
    {
    if(navar->selector <= navar->n)
        {
        wis(navar->value[navar->selector]);
        navar->value[navar->selector]=zelfde_als_w(pknoop);
        }
    else
        return FALSE;
    if(trace)
        {
        printf("wijzig %s=",navar->name);
        result(navar->value[navar->n]);
        putc('\n',fpo);
        }
    }
else
    {
    nieuwvar=bmalloc(sizeof(struct vars));
    nieuwvar->name=strcpy(bmalloc(strlen(string)+1),string);
    nieuwvar->next=navar;
    nieuwvar->n=0;
    nieuwvar->selector=0;
    if(voorvar==NULL)
        variabelen[*string]=nieuwvar;
    else
        voorvar->next=nieuwvar;
    nieuwvar->value[0]=zelfde_als_w(pknoop);
    if(trace)
        {
        printf("nieuw %s=",nieuwvar->name);
        result(nieuwvar->value[nieuwvar->n]);
        putc('\n',fpo);
        }
    }
return TRUE;
}

int zoeknaam(string,pvoorvar,pnavar)
char *string;
struct vars **pvoorvar,**pnavar;
{
struct vars *navar,*voorvar;
for(voorvar=NULL,navar=variabelen[*string];
    navar && (strcmp(navar->name,string) < 0);
    voorvar=navar,navar=navar->next);
/* voorvar < string <= navar */
*pvoorvar=voorvar;
*pnavar=navar;
return navar && !strcmp(navar->name,string);
}

int find_w(naamknoop,pknoop)
psk naamknoop;
ppsk pknoop;
{
struct vars *navar;
for(navar=variabelen[naamknoop->u.obj];
    navar && (strcmp(navar->name,&(naamknoop->u.obj)) < 0);
    navar=navar->next);
if(navar && !strcmp(navar->name,&(naamknoop->u.obj))
   && navar->selector <= navar->n
   && pknoop)
    {
    if(*pknoop)
        wis(*pknoop);
    *pknoop=zelfde_als_w(navar->value[navar->selector]);
    return TRUE;
    }
else          
    return FALSE;
}

int sel(naamknoop,selector)
psk naamknoop;
psk selector;
{
struct vars *navar;
for(navar=variabelen[naamknoop->u.obj];
    navar && (strcmp(navar->name,&(naamknoop->u.obj)) < 0);
    navar=navar->next);
/* eerste naam in een rij gelijke wordt gevonden */
if(navar && !strcmp(navar->name,&(naamknoop->u.obj))
   && kngetalcheck(selector) && geheel && teken!=NEGATIEF)
    {                        
    navar->selector=atoi(&selector->u.obj);
    return TRUE;
    }
else          
    return FALSE;
}

int delete(string)
char *string;
{
struct vars *navar,*voorvar,*nieuwvar;
if(zoeknaam(string,&voorvar,&navar))
    {
    if(trace)
        {
        printf("del %s=",navar->name);
        result(navar->value[navar->n]);
        putc('\n',fpo);
        }

    wis(navar->value[navar->n]);

    if(navar->n)
        {
        nieuwvar=bmalloc(sizeof(struct vars) + 
                         --(navar->n)*sizeof(psk));
        memcpy(nieuwvar,
               navar,
               sizeof(struct vars) + navar->n*sizeof(psk));
        if(voorvar)
            voorvar->next=nieuwvar;
        else
            variabelen[*string]=nieuwvar;
        if(nieuwvar->n < nieuwvar->selector)
            nieuwvar->selector=nieuwvar->n;
        }
    else
        {
        if(voorvar)
            voorvar->next=navar->next;
        else
            variabelen[*string]=navar->next;
        bfree(navar->name);
        }
    bfree(navar);
    return TRUE;
    }
else
    return FALSE;
}

int is_afhankelyk_van(el,lijst)
psk el,lijst;
{
psk hlp,hlp2;

if(!lijst)
    return FALSE;

vgl(el,(hlp=eerste(lijst)));
if(is_gelyk)
    return TRUE;

if(kop(hlp))
    {
    if(is_afhankelyk_van(el,hlp->u.p.links)
    || is_afhankelyk_van(el,hlp->u.p.rechts))
        return TRUE;
    }
else
    {
    hlp2=NULL;
    if(find_w(hlp,&hlp2))
        {
        if(is_afhankelyk_van(el,hlp2))
            {
            wis(hlp2);
            return TRUE;
            }
        else
            wis(hlp2);
        }
    }
return is_afhankelyk_van(el,rest(lijst));
}

int functies(pkn)
ppsk pkn;
{
char *wijzer;
static pchar conc[]={NULL,NULL,NULL,NULL,NULL};
int ikar;
register psk lknoop;
psk rknoop,rrknoop,rlknoop,rrlknoop;
if(kop(lknoop=(*pkn)->u.p.links))
    return TRUE;
rknoop=(*pkn)->u.p.rechts;
if(kop(rknoop))
    {
    rrknoop=rknoop->u.p.rechts;
    rlknoop=rknoop->u.p.links;
    }
switch(lknoop->u.iobj)
    {
    case PUSH :
        for(rrknoop=rknoop;
            kop(rrknoop) == KOMMA && 
            !kop(rrlknoop=rrknoop->u.p.links) &&
            psh(&(rrlknoop->u.obj),rrlknoop,NULL);
            rrknoop=rrknoop->u.p.rechts);
        if(!kop(rrknoop))
            psh(&(rrknoop->u.obj),rrknoop,NULL);
        rechtertak(pkn);
        return TRUE;
    case POP :
        while(kop(rknoop) == KOMMA && 
              !kop(rknoop->u.p.links) &&
              delete(&(rknoop->u.p.links->u.obj)))
            rknoop=rknoop->u.p.rechts;
        if(kop(rknoop)==KOMMA)
            {
            adr[2]=rknoop->u.p.rechts;
            }
        else
            adr[2]=rknoop;
        opb(pkn,hekje2);
        return TRUE;
    case MOD :
        if(knis_qgetal(rlknoop) &&
           knis_qgetal(rrknoop))
            {
            conc[0]=modulo(&(rlknoop->u.obj),
                           &(rrknoop->u.obj));
            conc[1]=NULL;
            vrijtbw(pkn,conc);
            bfree(conc[0]);
            }
        return TRUE;
    case DIV :
        if(knis_qgetal(rlknoop) &&
           knis_qgetal(rrknoop))
            {
            conc[0]=geheeldelen(&(rlknoop->u.obj),
                                &(rrknoop->u.obj));
            conc[1]=NULL;
            vrijtbw(pkn,conc);
            bfree(conc[0]);
            }
        return TRUE;
    case LIST :
        output(pkn,lst);
        return TRUE;
    case LOAD :/* get$file */
        if(kop(rknoop))
            return FALSE;
        else
            {
            fpi=fopen(&(rknoop->u.obj),"r");
            if(fpi==NULL)
                {
                printf("openen %s mislukt\n",&(rknoop->u.obj));
                return FALSE;
                }
            for(wijzer=lijst;(ikar=getc(fpi))!=EOF;)
                {
                putchar(ikar);
                if(ikar==';')
                    {
                    *wijzer=0;
                    if(lijst[0])
                        {
                        startboom_w(lijst,pkn);
                        }
                    wijzer=lijst;      
                    }
                else
                    if(ikar > ' ')
                        *wijzer++=ikar;
                }
            fclose(fpi);
            }
        return TRUE;
    case TYPE : /* put$(file,mode,knoop) of put$knoop */
        output(pkn,result);
        return TRUE;
    case TABL : /* tbl$(varnaam,lengte) */
        if(kop(rknoop))
            return psh(&(rlknoop->u.obj),nulknoop,rrknoop);
        else
            return FALSE;
    case TSET : /* sel$(varnaam,pos) */ /* tabelelementselectie */
        if(kop(rknoop) &&
           sel(rlknoop,rrknoop))
            {
            adr[2]=rlknoop;
            opb(pkn,hekje2);
            return TRUE;
            }
        else
            return FALSE;
    case FLAG : /* flg$fac */
        if(rknoop->u.iobj==FAC)
            factorize=TRUE;
        else
            factorize=FALSE;
        return TRUE;
    default :
        adr[1]=NULL;
        if(find_w((*pkn)->u.p.links,&adr[1]))
            {
            if(adr[1]->flgs & DUBBEL_GEBRUIKT)
                {
                adr[1]->flgs &=~DUBBEL_GEBRUIKT;
                adr[1]=subboomcopie(adr[1]);
                }
            psh("arg",(*pkn)->u.p.rechts,NULL);
            opb(pkn,"pop$(arg,\\,\t1)");
            return TRUE;
            }
        else
            return TRUE; /*FALSE; ???????? */
    }
}

int output(pkn,hoe)
ppsk pkn;
void (*hoe)();
{
#define NEW "w"
#define APP "a"
FILE *redfpo;
psk rknoop,rrknoop;
char *mode;
if(kop(rknoop=(*pkn)->u.p.rechts)==KOMMA && 
   kop(rrknoop=rknoop->u.p.rechts)==KOMMA &&
   !kop(rrknoop->u.p.links) &&
   (mode=&(rrknoop->u.p.rechts->u.obj),
    !strcmp(mode,"NEW")||!strcmp(mode,"APP")))
    {
    redfpo=fpo; 
    fpo=fopen(&(rrknoop->u.p.links->u.obj),!strcmp(mode,"NEW") ? NEW : APP);
    if(fpo==NULL)
        {
        printf("%s kan niet geopend worden\n",&(rrknoop->u.p.links->u.obj));
        return FALSE;
        }
    (*hoe)(rknoop->u.p.links,99);
    putc(';',fpo);
    putc('\n',fpo);
    fclose(fpo);
    fpo=redfpo;
    adr[2]=rknoop->u.p.links;
    opb(pkn,hekje2);
    }
else
    {
    (*hoe)(rknoop,99);
    putc('\n',fpo);
    rechtertak(pkn);
    }
return TRUE;
}

void lst(kn)
psk kn;
{
struct vars *navar;
char *naam;
int tel,alfabet,n;
if(kop(kn))
    return;
tel=0;
naam=&(kn->u.obj);
for(alfabet=0;alfabet<256;alfabet++)
for(navar=variabelen[alfabet];
    navar;
    navar=navar->next)
    {
    tel++;
    if((kn->u.obj == '\\') || !strcmp(navar->name,naam))
        {
        for(n=navar->n;n>=0;n--)
            {
            printf("%d %d ",n,navar->selector);
            putc('(',fpo);
            fprintf(fpo,"%s=",navar->name);
            result(navar->value[n]);
            putc(')',fpo);
            putc(';',fpo);
            putc('\n',fpo);
            }
        }
    }
printf("Totaal %d variabelen",tel);
}

int bereken_verschil(s,p)
qgetal s,p;
{
qgetal prod,verschil;
prod = qmaal(mineen,p);
verschil = qplus(s,prod);
getalcheck(verschil);
bfree(prod);
bfree(verschil);
return teken;
}

psk verschil_w(s,p)
psk s,p;
{
psk res;
qgetal prod,verschil;
prod = qmaal(mineen,&(p->u.obj));
res = copievan(&voorbeeld,(verschil=qplus(&(s->u.obj),prod)));
bfree(prod);
bfree(verschil);
return res;
}

psk quotient_w(s,p)
psk s,p;
{
psk res;
qgetal quotient;
res = copievan(&voorbeeld,(quotient=qqdeel(&(s->u.obj),&(p->u.obj))));
bfree(quotient);
return res;
}

int match(sub,pat)
psk sub,pat;
{
/* FAAL = TRUE als NOT-vlag aan staat. Infixoperatoren hebben geen flgs */
#undef FAAL
#define FAAL (pat->flgs & NOT)
psk loc;
if(kop(sub))
    {
    if(sub->u.p.links->flgs & SNIJAF)
        return match(sub->u.p.rechts,pat);
    else
        if(sub->u.p.rechts->flgs & SNIJAF)
            return match(sub->u.p.links,pat);
    }
switch(kop(pat))
    {
    case 0 :
        if(pat->flgs & NONIDENT)
            {
            if((sub->flgs & IDENT) ^ FAAL)
                return FALSE;
            }
        if(pat->flgs & ATOM)
            {
            if(kop(sub) ^ FAAL)
                return FALSE;
            }
        if(pat->flgs & (BREUK | NUMBER))
            {
            if((kop(sub)
            || !getalcheck(&(sub->u.obj))
            || (geheel && pat->flgs & BREUK))
               ^
                FAAL)
                return FALSE;
            }
        if(pat->flgs & UNIFY)             /*  ?  */
            {
            if(pat->u.obj)
                {
                if(pat->flgs & INDIRECT)  /*  ?! of ?!! */
                    {
                    loc=NULL;
                    if(naamwoord_w(pat,&loc))
                        {
                        if(!evalueer(&loc)
                         ^ (kop(loc) || !insert(&(loc->u.obj),sub))
                         ^ FAAL)
                            {
                            wis(loc);
                            return FALSE;
                            }
                        else
                            {
                            wis(loc);
                            return TRUE;
                            }
                        }
                    else
                        return FAAL;
                    }
                else
                    {
                    return copy_insert(&(pat->u.obj),sub) ^ FAAL;
                    }
                }
            else
                return !FAAL;
            }
        if(pat->flgs & INDIRECT)          /*  ! of !! */
            {
            loc=NULL;
            if(naamwoord_w(pat,&loc))
                {
                if( !match(sub,loc)
               /*    ^
                    (loc->flgs & NOT)*/
                   ^
                    FAAL)
                    {
                    wis(loc);
                    return FALSE;
                    }
                else
                    {
                    wis(loc);
                    return TRUE;
                    }
                }
            else
                return FAAL;
            }
        if(pat->u.obj)
            return compare(sub,pat);
        else
            return TRUE;
    case PLUS :
        if(match(sub,pat->u.p.links) &&
           match(nulknoop,pat->u.p.rechts))
            return TRUE;
#if 0
        if(knis_qgetal(pat->u.p.links) && knis_qgetal(sub))
            {
            if(match((loc=verschil_w(sub,pat->u.p.links)),pat->u.p.rechts))
                {
                wis(loc);
                return TRUE;
                }
            else
                {
                wis(loc);
                return FALSE;
                }
            }
#endif
        if(kop(sub)==PLUS)
            {
            for(loc=sub->u.p.links;;loc=loc->u.p.links)
                {
                loc->flgs |=SNIJAF;
                if(match(loc,pat->u.p.links) && 
                   match(sub,pat->u.p.rechts))
                    {
                    loc->flgs &=~SNIJAF;
                    return TRUE;
                    }
                loc->flgs &=~SNIJAF;
                if(pat->u.p.rechts->flgs & ATOM)
                    return FALSE;
                if(kop(loc)!=PLUS)
                    break;
                }
            }
        return match(nulknoop,pat->u.p.links) && 
               match(sub,pat->u.p.rechts);
    case MAAL :
        if(match(sub,pat->u.p.links) &&
           match(eenknoop,pat->u.p.rechts))
            return TRUE;
#if 0
        if(knis_qgetal(pat->u.p.links) && knis_qgetal(sub))
            {
            if(match((loc=quotient_w(sub,pat->u.p.links)),pat->u.p.rechts))
                {
                wis(loc);
                return TRUE;
                }
            else
                {
                wis(loc);
                return FALSE;
                }
            }
#endif
        if(kop(sub)==MAAL)
            {
            for(loc=sub->u.p.links;;loc=loc->u.p.links)
                {
                loc->flgs |=SNIJAF;
                if(match(loc,pat->u.p.links) && 
                   match(sub,pat->u.p.rechts))
                    {
                    loc->flgs &=~SNIJAF;
                    return TRUE;
                    }
                loc->flgs &=~SNIJAF;
                if(pat->u.p.rechts->flgs & ATOM)
                    return FALSE;
                if(kop(loc)!=MAAL)
                    break;
                }
            }
        return match(eenknoop,pat->u.p.links) && 
               match(sub,pat->u.p.rechts);
    case DOT :
        if(kop(sub) &&
           match(sub->u.p.links,pat->u.p.links) &&
           match(sub->u.p.rechts,pat->u.p.rechts))
            {
            dummy_op=kop(sub);
            return TRUE;
            }
        else
            return FALSE;
    case KOMMA :
        if(match(nilknoop,pat->u.p.links) &&
           match(sub,pat->u.p.rechts))
            return TRUE;
        if(kop(sub)==KOMMA)
            {
            for(loc=sub->u.p.rechts;;loc=loc->u.p.rechts)
                {
                loc->flgs |=SNIJAF;
                if(match(sub,pat->u.p.links) && 
                   match(loc,pat->u.p.rechts))
                    {
                    loc->flgs &=~SNIJAF;
                    return TRUE;
                    }
                loc->flgs &=~SNIJAF;
                if(pat->u.p.links->flgs & ATOM)
                    return FALSE;
                if(kop(loc)!=KOMMA)
                    break;
                }
            }
        return match(sub,pat->u.p.links) && 
               match(nilknoop,pat->u.p.rechts);
    case EN :
        if(match(sub,pat->u.p.links))
            {
            loc=subboomcopie(pat->u.p.rechts);
            if(evalueer(&loc))
                {
                wis(loc);
                return TRUE;
                }
            else
                wis(loc);
            }
        return FALSE;
    case OF :
        return match(sub,pat->u.p.links) 
            || match(sub,pat->u.p.rechts);
    default :
        return kop(sub)==kop(pat) &&
               match(sub->u.p.links,pat->u.p.links) &&
               match(sub->u.p.rechts,pat->u.p.rechts);
    }
}

int compare(s,p)
psk s,p;
{
#undef FAAL
#define FAAL (p->flgs & NOT)
int teken;
if(knis_qgetal(s))
    {
    if(knis_qgetal(p))
        return match_verschil(bereken_verschil(&(s->u.obj),&(p->u.obj)),s,p);
    else
        return FAAL;
    }
else
    {
    if(kop(s))
        return FAAL;
    teken=strcmp(&(s->u.obj),&(p->u.obj));
    if(teken>0)
        teken=POSITIEF;
    else
        if(teken<0)
            teken=NEGATIEF;
    return match_verschil(teken,s,p);
    }
}

int match_verschil(versch,s,p)
int versch;
psk s,p;
{
#undef FAAL
#define FAAL (p->flgs & NOT)
#define PGRT (p->flgs & GROTER_DAN)
#define PKLN (p->flgs & KLEINER_DAN)
#define PONG  (PGRT && PKLN)
#define EPGRT (PGRT && !PKLN)
#define EPKLN (PKLN && !PGRT)
switch(versch)
    {
    case POSITIEF :
        if(s->flgs & KLEINER_DAN)
            return FALSE;
        return FAAL ^ (PGRT && 1);
    /*    if(FAAL)
            return !PGRT;
        else
            return EPGRT;*/
    case NUL :
        switch(s->flgs & (GROTER_DAN|KLEINER_DAN))
            {
            case GROTER_DAN|KLEINER_DAN :
                return FAAL ^ PONG;
            case GROTER_DAN :
                return FAAL ^ PONG ^ EPGRT;
            case KLEINER_DAN :
                return FAAL ^ PONG ^ EPKLN;
            default :
                return !FAAL ^ (PGRT || PKLN);
            }
    default :
        if(s->flgs & GROTER_DAN)
            return FALSE;
        return FAAL ^ (PKLN && 1);
/*        if(FAAL)
            return !PKLN;
        else
            return EPKLN;*/
    }
}

int naamwoord_w(bron,pkn)
psk bron;
ppsk pkn;
{
if(find_w(bron,pkn) &&
   (!((*pkn)->flgs & INDIRECT) || naamwoord_w(*pkn,pkn)))
    {
    if(!(bron->flgs & DUBBEL_INDIRECT))
        {
        copyflags(bron,pkn);
        return TRUE;
        }
    else
        {
        if(!kop(*pkn) || (evalueer(pkn) && !kop(*pkn)))
            {
            if(naamwoord_w(*pkn,pkn))
                {
                copyflags(bron,pkn);
                return TRUE;
                }
            else
                return FALSE;
            }
        }
    }
if(*pkn)
    wis(*pkn);
return FALSE;
}

void copyflags(bron,pkn)
psk bron;
ppsk pkn;
{
if((bron->flgs & (KLEINER_DAN | GROTER_DAN)) || !(bron->flgs & SUCCES))
    {
    if((*pkn)->flgs & DUBBEL_GEBRUIKT)
        {
        (*pkn)->flgs &=~DUBBEL_GEBRUIKT;
        *pkn=subboomcopie(*pkn);
        }                                                                      
    (*pkn)->flgs|=bron->flgs & (KLEINER_DAN | GROTER_DAN);
    (*pkn)->flgs^=(bron->flgs & SUCCES) ^ SUCCES;
    }
}

psk eerste(kn)
psk kn;
{
if(kop(kn)==KOMMA)
    return kn->u.p.links;
else
    return kn;
}

psk rest(kn)
psk kn;
{
if(kop(kn)==KOMMA)
    return kn->u.p.rechts;
else
    return NULL;
}
              
int samenvoegen_of_sorteren(pkn,sorteerdeel,hogere_operator)
ppsk pkn;
psk(*sorteerdeel)();
char *hogere_operator;
{
static char *conc[]={NULL,NULL,NULL,NULL},
hekjetweepluseen[]="(\t2+1)",
hekjetweezes[]="(\t2+\t6)";
psk iknoop,lknoop,rknoop,temp;
iknoop=*pkn;
lknoop=*linkeroperand(pkn);
rknoop=iknoop->u.p.rechts;
hknoop=(*sorteerdeel)(lknoop);
jknoop=(*sorteerdeel)(rknoop);
vgl(hknoop,jknoop);
if(is_gelyk)
    {
    /* a*n+a*m */
    /* a^n*a^m */
    if(hknoop != lknoop)
        {
        adr[1]=hknoop;
        adr[2]=lknoop->u.p.rechts;
        conc[0]=hekje1;
        conc[1]=soperator[klopcode(lknoop)];
        if(jknoop==rknoop)
            {
            /* a*n+a */
            /* a^n*a */
            conc[2]=hekjetweepluseen;
            /* a*(n+1) */
            /* a^(n+1) */
            }
        else
            {
            /* a*n+a*m */
            /* a^n*a^m */
            adr[6]=rknoop->u.p.rechts;
            conc[2]=hekjetweezes;
            /* a*(n+m) */
            /* a^(n+m) */
            }
        }
    else
        {
        if(jknoop != rknoop)
            {
            /* a+a*m */
            /* a*a^m */
            adr[1]=jknoop;
            adr[2]=rknoop->u.p.rechts;
            conc[0]=hekje1;
            conc[1]=soperator[klopcode(rknoop)];
            conc[2]=hekjetweepluseen;
            /* a*(m+1) */
            /* a^(m+1) */
            }
        else
            {
            /* a+a */
            /* a*a */
            adr[7]=jknoop;
            conc[0]=hekje7;
            conc[1]=hogere_operator;
            conc[2]=twee;
            /* a*2 */
            /* a^2 */
            }
        }
    conc[3]=NULL;
    if(lknoop != (temp=iknoop->u.p.links))
        {
        conc[2]=koncat(conc);
        adr[4] = temp->u.p.links;
        conc[0]=hekje4;
        conc[1]=soperator[klopcode(iknoop)];
        vrijopb(pkn,conc);
        bfree(conc[2]);
        }
    else
        vrijopb(pkn,conc);
    return TRUE;
    }
else
    {
    if((is_groter || knis_qgetal(hknoop)) && 
       !knis_qgetal(jknoop))
        {
        /* b*n+a*m */
        /* b^n*a^m */
        /* l*n+a*m */
        /* l^n*a^m */
        adr[1]=rknoop;
        conc[0]=hekje1;
        conc[1]=soperator[klopcode(iknoop)];
        conc[2]=hekje2;
        if(iknoop->u.p.links==lknoop)
            {
            adr[2]=lknoop;
            vrijopb(pkn,conc);
            }
        else
            {
            conc[2]=koncat(conc);
            adr[2]=lknoop;
            adr[3]=iknoop->u.p.links->u.p.links;
            conc[0]=hekje3;
            conc[1]=soperator[klopcode(iknoop)];
            vrijopb(pkn,conc);
            bfree(conc[2]);
            }
        return TRUE;
        /* a*m+b*n */
        /* a^m*b^n */
        /* a*m+l*n */
        /* a^m*l^n */
        }
    }
return FALSE;
}

psk nonnumfactor(pknoop)
psk pknoop;
{
if(kop(pknoop)==MAAL && knis_qgetal(pknoop->u.p.rechts))
    return pknoop->u.p.links;
else
    return pknoop;
}

psk base(pknoop)
psk pknoop;
{
if(kop(pknoop)==EXP)
    return pknoop->u.p.links;
else
    return pknoop;
}

int casemacht(pkn)
ppsk pkn;
{
static char *conc[]={NULL,NULL,NULL,NULL,NULL},
haakmineen[]=")^-1",
haakhekje1macht[]="(\t1^",
macht2maaleenmacht[]=")^2*\v1^";
psk iknoop,lknoop,rknoop;
if(!kngetalcheck((*pkn)->u.p.links))
    return FALSE;
iknoop=*pkn;
lknoop=iknoop->u.p.links;
if(kngetalcheck(rknoop=iknoop->u.p.rechts) && 
   teken != NUL && 
   !abseen &&
   geheel)
    {
    adr[1]=lknoop;
    if(teken==NEGATIEF)
        {                  
        /* (a+b)^-n = ((a+b)^n)^-1 */
        conc[0]=haakhekje1macht;
        conc[1]=qmaal(mineen,&(rknoop->u.obj));
        conc[2]=haakmineen;
        vrijopb(pkn,conc);
        bfree(conc[1]);
        }  
    else
        {
        if(vergelijk(twee,&(rknoop->u.obj))==KLEINER)
            {
            /* (a+b)^n = (a+b)^(n\2)*(a+b)^(n mod 2) */
            conc[0]=haakhekje1macht;
            conc[1]=geheeldelen(&(rknoop->u.obj),twee);
            conc[2]=macht2maaleenmacht;
            conc[3]=modulo(&(rknoop->u.obj),twee);
            vrijopb(pkn,conc);
            bfree(conc[1]);
            bfree(conc[3]);
            }
        else
            {
            /* (a+b)^2 = (a+b)*(a+b) */
            conc[0]="(\t1*\v1)";
            conc[1]=NULL;
            vrijopb(pkn,conc);
            }
        }
    return TRUE;
    }
return FALSE;
}

int differentieren(pkn)
ppsk pkn;
{
psk lknoop,rknoop;
rknoop=(*pkn)->u.p.rechts;
if(knis_qgetal(lknoop=(*pkn)->u.p.links) || kop(lknoop))
    return FALSE;
if(knis_qgetal(rknoop))
    opb(pkn,nul);
else
    if(kop(rknoop) == PLUS)
        a_bc_to_ab_ac(pkn,plus);
    else
        {
        if(kop(rknoop))
            {
            adr[2]=rknoop->u.p.links;
            adr[1]=lknoop;
            adr[3]=rknoop->u.p.rechts;
            switch(kop(rknoop))
                {
                case MAAL :
                    opb(pkn,"(\v1D\v2*\v3+\t2*\t1D\t3)");
                    break;
                case EXP:
                    opb(pkn,
                         "(\t2^(\t3+-1)*\v3*\t1D\v2+\v2^\v3*eL\v2*\v1D\v3)");
                    break;
                case LOG :
                    opb(pkn,
                    "(\t2^-1*eL\v2^-2*eL\t3*\t1D\v2+\v3^-1*eL\v2^-1*\v1D\v3)");
                    break;
                }
            }
        else
            return FALSE;
        }
return TRUE;
}

int machtbuitenhaakjes(pkn)
ppsk pkn;
{
psk iknoop,lknoop,rknoop;
iknoop=*pkn;
rknoop=iknoop->u.p.rechts;
lknoop=iknoop->u.p.links;
if(kop(rknoop)==PLUS && 
   kop(lknoop)==PLUS &&
   kngetalcheck(rknoop->u.p.rechts) && 
   geheel && 
   teken==POSITIEF)
    {
    a_bc_to_ab_ac(pkn,maal);
    return TRUE;
    }
else
    if(kop(lknoop)==MAAL)
            {
            ab_c_to_ac_bc(pkn,maal,lknoop);
            return TRUE;
            }
return FALSE;
}

void a_bc_to_ab_ac(pkn,pkar)
ppsk pkn;
char *pkar;
{
static pchar conc[]={"((\t1",NULL,"\t2)",NULL,"(\v1",NULL,"\t3))",NULL};
psk iknoop,rknoop;
iknoop=*pkn;
rknoop=iknoop->u.p.rechts;
adr[1]=iknoop->u.p.links;
adr[2]=rknoop->u.p.links;
adr[3]=rknoop->u.p.rechts;
conc[1]=soperator[klopcode(iknoop)];
conc[3]=pkar;
conc[5]=soperator[klopcode(iknoop)];
vrijopb(pkn,conc);
}      

void ab_c_to_ac_bc(pkn,pkar,lknoop)
ppsk pkn;
char *pkar;
psk lknoop;
{
static pchar conc[]={hekje1,NULL,hekje3,NULL,hekje2,NULL,"\v3",NULL};
adr[1]=lknoop->u.p.links;
adr[2]=lknoop->u.p.rechts;
adr[3]=(*pkn)->u.p.rechts;
conc[1]=soperator[klopcode(*pkn)];
conc[3]=pkar;
conc[5]=soperator[klopcode(*pkn)];
vrijopb(pkn,conc);
}

int linksbrengen(pkn)
ppsk pkn;
{
register psk rknoop;
register int gedaan;
gedaan = FALSE;
for(;kop(rknoop=(*pkn)->u.p.rechts)==kop(*pkn);)
    {
    gedaan=TRUE;
    rknoop->flgs &=~KLAAR;
    (*pkn)->u.p.rechts=rknoop->u.p.rechts;
    rknoop->u.p.rechts=rknoop->u.p.links;
    rknoop->u.p.links=(*pkn)->u.p.links;
    (*pkn)->u.p.links=rknoop;
    }
if(gedaan)
    (*pkn)->flgs &=~KLAAR;
return gedaan;
}

int rechtsbrengen(pkn)
ppsk pkn;
{
register psk lknoop;
register int gedaan;
gedaan = FALSE;
for(;kop(lknoop=(*pkn)->u.p.links)==kop(*pkn);)
    {
    gedaan=TRUE;
    lknoop->flgs &=~KLAAR;
    (*pkn)->u.p.links=lknoop->u.p.links;
    lknoop->u.p.links=lknoop->u.p.rechts;
    lknoop->u.p.rechts=(*pkn)->u.p.rechts;
    (*pkn)->u.p.rechts=lknoop;
    }
if(gedaan)
    (*pkn)->flgs &=~KLAAR;
return gedaan;
}

int stapelmacht(pkn)
ppsk pkn;
{
psk lknoop;
int gedaan;
gedaan = FALSE;
for(;  (
         (lknoop=(*pkn)->u.p.links)->flgs & KLAAR
       ) 
     &&
       kop(lknoop)== EXP
     &&
       (
           (
               kop((*pkn)->u.p.rechts) 
             || 
               (*pkn)->u.p.rechts->u.iobj!=MINEEN
             || 
               (
                   !kop(lknoop->u.p.rechts) 
                 && 
                   lknoop->u.p.rechts->u.obj == '-'
               )
           )
         ||
           kop(lknoop->u.p.links) != PLUS
       );)
    {
    gedaan=TRUE;
    lknoop->flgs &=~KLAAR & ~OPERATOR; /* KLAAR vlag uitzetten */
    lknoop->flgs |=MAAL;
    adr[1]=lknoop->u.p.links;
    adr[2]=lknoop->u.p.rechts;
    adr[3]=(*pkn)->u.p.rechts;
    opb(pkn,"(\t1^(\t2*\t3))");
    }
return gedaan;
}

int substplus(pkn)
ppsk pkn;
{    
static pchar conc[]={NULL,NULL,NULL,NULL};
psk lknoop,rknoop;
if(!kop(rknoop=(*pkn)->u.p.rechts) && rknoop->u.obj=='0')
    {
    linkertak(pkn);
    return TRUE;
    }
else
    {
    lknoop=*linkeroperand(pkn);
    if(knis_qgetal(lknoop) && knis_qgetal(rknoop))
        {
        conc[1]=plus;
        conc[2]=qplus(&(lknoop->u.obj),&(rknoop->u.obj));
        numboom(pkn,lknoop,conc);
        return TRUE;
        }
    else
        return FALSE;
    }
}

int substmaal(pkn)
ppsk pkn;
{    
static pchar conc[]={NULL,NULL,NULL,NULL};
psk lknoop,rknoop;
qgetal linkervar,rechtervar;
if(kop(lknoop=*linkeroperand(pkn)))         
    linkervar=NULL;
else
    {
    linkervar=&(lknoop->u.obj);
    if(*linkervar=='0')
        {
        opb(pkn,nul);
        return TRUE;
        }
    }
if(kop(rknoop=(*pkn)->u.p.rechts))                  
    return FALSE;
else
    {
    rechtervar=&(rknoop->u.obj);
    if(*rechtervar=='0')
        {
        opb(pkn,nul);
        return TRUE;
        }
    }
if(rknoop->u.iobj=='1')
    linkertak(pkn);
else
    if(linkervar && is_qgetal(linkervar) && is_qgetal(rechtervar))
        {
        conc[1]=maal;
        conc[2]=qmaal(linkervar,rechtervar);
        numboom(pkn,lknoop,conc);
        }
    else
        return FALSE;
return TRUE;
}

int substmacht(pkn)
ppsk pkn;
{    
static char *conc[]={NULL,NULL,NULL,NULL},
       haakjei[]="(i^";
qgetal iexponent,rechtervar,hiexponent;
psk lknoop,rknoop;
if(!kop(rknoop=(*pkn)->u.p.rechts))
    {
    switch(rknoop->u.iobj)
        {
        case '0' :
            opb(pkn,een);
            return TRUE;
        case '1' :
            linkertak(pkn);
            return TRUE;
        }
    }

if(kop(lknoop=(*pkn)->u.p.links))
    return FALSE;

switch(lknoop->u.iobj)
    {
    case '0' :
    case '1' :
        linkertak(pkn);
        return TRUE;
    }

if(kop(rknoop) || !kngetalcheck(rknoop))
    return FALSE;

if(knis_qgetal(lknoop))
    {
    if(teken==NEGATIEF && abseen)
        {
        conc[2]=qqdeel(een,&(lknoop->u.obj));
        numboom(pkn,lknoop,conc);
        return TRUE;
        }
    else
        return FALSE;
    }

if(lknoop->u.iobj==IM
&& (vergelijk((rechtervar=&(rknoop->u.obj)),nul)==KLEINER 
 || vergelijk(twee,rechtervar)<=GELIJK))
    {
    iexponent=modulo(rechtervar,vier);
    if(*iexponent=='0')
        opb(pkn,een);
    else
        if(!strcmp(iexponent,twee))
            opb(pkn,mineen);
        else
            {   
            conc[0]=haakjei;
            if(vergelijk(iexponent,twee)==GROTER)
                { 
                hiexponent=iexponent;
                iexponent=qplus(hiexponent,mintwee);
                bfree(hiexponent);
                conc[2]=maalmineen;
                }
            else
                conc[2]=haakjesluit;
            conc[1]=iexponent;
            vrijtbw(pkn,conc);
            }
    bfree(iexponent);
    return TRUE;
    }
return FALSE;
}

int kngetalcheck(pknoop)
psk pknoop;
{
if(!kop(pknoop) && getalcheck(&(pknoop->u.obj)))
    {
    pknoop->flgs |= NUMBER;
    if(geheel)
        pknoop->flgs &=~BREUK;
    else
        pknoop->flgs |= BREUK;
    return TRUE;
    }
else
    {
    pknoop->flgs &=~NUMBER;
    pknoop->flgs &=~BREUK;
    return FALSE;
    }
}

int getalcheck(s)
qgetal s;
{
char *wyzer;
if(!is_qgetal(s))
    return FALSE;
wyzer=s;
geheel=TRUE;
abseen=FALSE;
switch(*wyzer)
    {
    case '-' : 
        wyzer++;
        teken=NEGATIEF;
        break;
    case '0' :
        teken=NUL;
        return TRUE;
    default :
        teken=POSITIEF;
    }
if(*wyzer == '1')
    if(*++wyzer == 0)
        {
        abseen=TRUE;
        return TRUE;
        }
for(;*wyzer;wyzer++)
    {
    if(*wyzer == '/')
        {
        geheel=FALSE;
        return TRUE;
        }
    }
return TRUE;
}

int substlog(pkn)
ppsk pkn;
{    
static char *conc[]={NULL,NULL,NULL,NULL},
pluseen[]="+1)",hekje1L[]="(\t1L",Lhekje1maalmineen[]="L\t1*-1)";
qgetal linkervar,rechtervar;
psk lknoop,rknoop;
if(kop(rknoop=(*pkn)->u.p.rechts))
    {
    vgl((*pkn)->u.p.links,rknoop);
    if(is_gelyk)
        {
        opb(pkn,een);
        return TRUE;
        }
    else
        return FALSE;
    }
if(kop(lknoop=(*pkn)->u.p.links))
    return FALSE;
if(!strcmp(rechtervar=&(rknoop->u.obj),
           linkervar=&(lknoop->u.obj)))
    {
    opb(pkn,een);
    return TRUE;
    }
if(rknoop->u.iobj=='1')
    {
    opb(pkn,nul);
    return TRUE;
    }
else
    {
    if(knis_qgetal(rknoop) && knis_qgetal(lknoop=(*pkn)->u.p.links))
        {
        linkervar=&(lknoop->u.obj);
        if(vergelijk(linkervar,een)==KLEINER)
            { 
            /* (1/n)Lm = nLm*-1 */
            adr[1]=rknoop;
            conc[0]=haakjeopen;
            conc[1]=qqdeel(een,linkervar);
            conc[2]=Lhekje1maalmineen;
            vrijopb(pkn,conc);
            bfree(conc[1]);
            return TRUE;
            }
        if(vergelijk(linkervar,rechtervar)==KLEINER)
            { 
            /* nLm = nL(m/n)+1 */
            conc[0]=hekje1L;
            adr[1]=lknoop;
            conc[1]=qqdeel(rechtervar,linkervar);
            conc[2]=pluseen;
            vrijopb(pkn,conc);
            bfree(conc[1]);
            return TRUE;
            }
        }
    }
return FALSE;
}

int substdiff(pkn)
ppsk pkn;
{    
static pchar conc[]={NULL,NULL,NULL,NULL};
psk lknoop,rknoop;
lknoop=(*pkn)->u.p.links;
rknoop=(*pkn)->u.p.rechts;
if(knis_qgetal(lknoop) && knis_qgetal(rknoop))
    {
    conc[2]=cyfer('0');
    numboom(pkn,lknoop,conc);
    return TRUE;
    }
else
    {
    if(is_constant(lknoop) || is_constant(rknoop))
        {
        opb(pkn,nul);
        return TRUE;
        }
    else
        {
        vgl(lknoop,rknoop);
        if(is_gelyk)
            {
            opb(pkn,een);
            return TRUE;
            }
        else
            if((kop(rknoop) == FUN || !kop(rknoop)) &&
               is_afhankelyk_van(lknoop,rknoop))
                {
                return TRUE;
                }
            else
                if(!kop(rknoop))
                    {
                    opb(pkn,nul);
                    }
        }
    }
return FALSE;
}

void numboom(pkn,lknoop,conc)
ppsk pkn;
psk lknoop;
pchar conc[];
{
if(lknoop==(*pkn)->u.p.links)
    {
    conc[0]=niks;
    conc[1]=niks;
    }
else
    {
    conc[0]=hekje1;
    adr[1]=(*pkn)->u.p.links->u.p.links;
    }
vrijopb(pkn,conc);
bfree(conc[2]);
}

void linkertak(pkn)
ppsk pkn;
{
psk lknoop;
lknoop=(*pkn)->u.p.links;
lknoop->flgs ^= ((*pkn)->flgs & SUCCES) ^ SUCCES;
wis((*pkn)->u.p.rechts);
bfree(*pkn);
*pkn=lknoop;
}

void flinkertak(pkn)
ppsk pkn;
{
psk lknoop;
lknoop=(*pkn)->u.p.links;
lknoop->flgs &=~SUCCES;
lknoop->flgs |=((*pkn)->flgs & SUCCES) ^ SUCCES;
wis((*pkn)->u.p.rechts);
bfree(*pkn);
*pkn=lknoop;
}

void rechtertak(pkn)
ppsk pkn;
{
psk rknoop;
rknoop=(*pkn)->u.p.rechts;
rknoop->flgs ^= ((*pkn)->flgs & SUCCES) ^ SUCCES;
wis((*pkn)->u.p.links);
bfree(*pkn);
*pkn=rknoop;
}

ppsk linkeroperand(pkn)
ppsk pkn;
{
ppsk temp;
int teken;
temp=&((*pkn)->u.p.links);
return((teken=kop(*pkn))==kop(*temp) && 
        (teken==PLUS || teken==MAAL) ?
       &(*temp)->u.p.rechts : temp);
}

void result(wortel)
psk wortel;
{
static int ouder,kind;
if(kop(wortel))
    {
    ouder=kop(wortel);
    kind=kop(wortel->u.p.links);
    if(ouder > kind || (ouder==kind && ouder > MAAL))
        hresult(wortel->u.p.links);
    else
        result(wortel->u.p.links);

    putc(*soperator[klopcode(wortel)],fpo);

    ouder=kop(wortel);
    kind=kop(wortel->u.p.rechts);
    if(ouder > kind || (ouder==kind && ouder > MAAL))
        hresult(wortel->u.p.rechts);
    else
        result(wortel->u.p.rechts);
    }
else
    eindknoop(wortel);
}

void hresult(wortel)
psk wortel;
{
static int ouder,kind;
if(kop(wortel))
    {
    putc('(',fpo);
    ouder=kop(wortel);
    kind=kop(wortel->u.p.links);
    if(ouder > kind || (ouder==kind && ouder > MAAL))
        hresult(wortel->u.p.links);
    else
        result(wortel->u.p.links);

    putc(*soperator[klopcode(wortel)],fpo);

    ouder=kop(wortel);
    kind=kop(wortel->u.p.rechts);
    if(ouder > kind || (ouder==kind && ouder > MAAL))
        hresult(wortel->u.p.rechts);
    else
        result(wortel->u.p.rechts);
    putc(')',fpo);
    }
else
    eindknoop(wortel);
}

void eindknoop(wortel)
psk wortel;
{
if(wortel->flgs & NOT)
    putc('~',fpo);
if(wortel->flgs & KLEINER_DAN)
    putc('<',fpo);
if(wortel->flgs & GROTER_DAN)
    putc('>',fpo);
if(wortel->flgs & BREUK)
    putc('/',fpo);
else
    if(wortel->flgs & NUMBER)
        putc('#',fpo);
if(wortel->flgs & ATOM)
    putc('@',fpo);
if(wortel->flgs & NONIDENT)
    putc('%',fpo);
if(wortel->flgs & UNIFY)
    putc('?',fpo);
if(wortel->flgs & INDIRECT)
    putc('!',fpo);
if(wortel->flgs & DUBBEL_INDIRECT)
    putc('!',fpo);
fprintf(fpo,&(wortel->u.obj));
}

char *koncat(pplijst)
char **pplijst;
{
char *toe,*point,**argp,*ret;
int totlengte;
totlengte=0;
for(argp=pplijst;*argp;totlengte += strlen(*argp++));
ret=point=bmalloc(totlengte+1);
for(;*pplijst;pplijst++)
    {
    for(toe=*pplijst;*toe;)
        *point++ = *toe++;
    *point=0;
    }
return ret;
}

char *concat(plijst
#ifdef ARM
             ,...)
#endif
char *plijst;
{
char *toe,*point,**argp,*ret;
int totlengte;
totlengte=0;
for(argp=&plijst;*argp;totlengte += strlen(*argp++));
ret=point=bmalloc(totlengte+1);
for(argp=&plijst;*argp;argp++)
    {
    for(toe=*argp;*toe;)
        *point++ = *toe++;
    *point=0;
    }
return ret;
}

psk subboomcopie(src)
psk src;
{
psk goal;
if(kop(src))
    {
    if(src->u.p.links->flgs & SNIJAF)
        return subboomcopie(src->u.p.rechts);
    else
        if(src->u.p.rechts->flgs & SNIJAF)
            return subboomcopie(src->u.p.links);
        else
            {
            goal = bmalloc(sizeof(struct kknoop));
            goal->flgs = src->flgs;
            goal->u.p.links  = subboomcopie(src->u.p.links);
            goal->u.p.rechts = subboomcopie(src->u.p.rechts);
            }
    }
else
    goal = copievan(src,&(src->u.obj));
goal->flgs &=~(SNIJAF | DUBBEL_GEBRUIKT);
return goal;
}

qgetal qplus(qx,qy)
qgetal qx,qy;
{
ngetal xt,xn,yt,yn,pa,pb,som;
qgetal res;
splits(qx,&xt,&xn);
splits(qy,&yt,&yn);
pa=nmaal(xt,yn);
bfree(xt);
pb=nmaal(yt,xn);
bfree(yt);
som=nplus(pa,pb);
bfree(pa);
bfree(pb);
pa=nmaal(xn,yn);
bfree(xn);
bfree(yn);
res=qndeel(som,pa);
bfree(som);
bfree(pa);
return res;
}

qgetal qmaal(qx,qy)
qgetal qx,qy;
{
ngetal xt,xn,yt,yn;
splits(qx,&xt,&xn);
splits(qy,&yt,&yn);
return qdema(xt,xn,yt,yn);
}

qgetal qqdeel(qx,qy)
qgetal qx,qy;
{
ngetal xt,xn,yt,yn;
splits(qx,&xt,&xn);
splits(qy,&yt,&yn);
return qdema(xt,xn,yn,yt);
}

void splits(qget,ptel,pnoem)
qgetal qget;
ngetal *ptel,*pnoem;
{
ngetal on,pn;
for(on=qget;*on && *on != '/';on++);
if(*on)
    {
    *on='\0';
    *ptel=strcpy(bmalloc(on-qget+1),qget);
    *on++='/';
    for(pn=on;*pn;pn++);
    *pnoem=strcpy(bmalloc(pn-on+1),on);
    }
else
    {
    *ptel=strcpy(bmalloc(on-qget+1),qget);
    *pnoem=cyfer('1');
    }
}

qgetal qdema(x1,x2,y1,y2)
ngetal x1,x2,y1,y2;
{
ngetal pa,pb;
qgetal res;
pa=nmaal(x1,y1);
bfree(x1);
bfree(y1);
pb=nmaal(x2,y2);
bfree(x2);
bfree(y2);
res=qndeel(pa,pb);
bfree(pa);
bfree(pb);
return(res);
}

qgetal qndeel(x,y)
ngetal x,y;
{
char *res,teken;
struct deelres resx,resy;
ngetal ggd,hrest;
if(*x=='0')
    return cyfer('0');
else
    if(*y=='0')
        {
        nuldelen();
        return cyfer('0');
        }
ggd=x;
hrest=y;
do
    {
    nndeel(ggd,hrest,&resx);
    if(ggd != x && ggd != y)
        bfree(ggd);
    ggd=hrest;
    hrest=resx.rest;
    bfree(resx.quot);
    }
while(*hrest != '0');
if(hrest!=y)
    bfree(hrest);
nndeel(x,ggd,&resx);
bfree(resx.rest);
nndeel(y,ggd,&resy);
bfree(resy.rest);
if(ggd!=y)
    bfree(ggd);
teken=resteken(resx.quot,resy.quot);
res=concat((teken=='+'?niks:min),
           (resx.quot+1),
           ((*(resy.quot+1)=='1' && !*(resy.quot+2)) ? NULL : streep),
           (resy.quot+1),
           NULL);
bfree(resx.quot);
bfree(resy.quot);
return res;
}

void nndeel(x,y,pres)
ngetal x,y;
struct deelres *pres;
{
ngetal i1,i2,i3;
char *wyzer;
ngetal hquot,hrest;
xyinit(x,y);
if(*oy=='0')
    nuldelen();
hrest=bmalloc(2+xlengte);
*hrest='0';
i1=ox;
for(wyzer=hrest+1;wyzer<=hrest+xlengte;*wyzer++=*i1++);
*wyzer=0;
if(xlengte>=ylengte)
    hquot=bmalloc(3+xlengte-ylengte);
else
    hquot=bmalloc(2);
*hquot='0';
i3=hquot;
for(i1=hrest+ylengte;i1<=hrest+xlengte;i1++)
    {
    *++i3='0'-1;
    do
        {
        i2=i1;
        opaf(&i2,hrest+1,i1,oy,py,-1);
        (*i3)++;
        }
    while(!carry);
    i2=i1;
    opaf(&i2,hrest+1,i1,oy,py,1);
    }
*++i3=0;
supernul(hrest,tx);
supernul(hquot,resteken(x,y));
pres->rest=hrest;
pres->quot=hquot;
}

void nuldelen()
{
printf("\ndelen door nul!\n");
}

ngetal cyfer(n)
int n;
{
ngetal res;
res=bmalloc(4);
*(int*)res=n;
return res;
}

ngetal nmaal(x,y)
ngetal x,y;
{
ngetal res,i1,i2;
int lengte;
char *wyzer,*tussen;
xyinit(x,y);
res=bmalloc((lengte=1+xlengte+ylengte)+1);
for(wyzer=res;wyzer<res+lengte;*wyzer++='0');
*wyzer=0;
for(i1=px;i1>=ox;i1--)
    {
    tussen=--wyzer;
    for(i2=py;i2>=oy;i2--)
        {
        register int prod,karry;
        register char *tussen2;
        prod=(*i1-'0')*(*i2-'0');
        *tussen += prod%10;
        karry=prod/10;
        tussen2=tussen--;
        do
            {
            if(*tussen2 > '9')
                {
                karry++;
                *tussen2 -=10;
                }
            *--tussen2+=karry;
            karry=0;
            }
        while(*tussen2 > '9');
        }
    }
supernul(res,resteken(x,y));
return res;
}

char resteken(k1,k2)
char *k1,*k2;
{
return *k1=='-' ^ *k2=='-' ? '-' : '+';
}

ngetal nplus(x,y)
ngetal x,y;
{
ngetal hp,res,hres;
char ht;
int maxlen,xgrotery;
xyinit(x,y);
res=bmalloc(1+(maxlen=2+(xlengte>ylengte ? xlengte : ylengte)));
*res=*(res+1)='0';
hres=res+maxlen;
*hres-- =0;
if(xlengte==ylengte)
    xgrotery=strncmp(ox,oy,maxlen);
else
    if(xlengte>ylengte)
        xgrotery=1;
    else
        xgrotery=-1;
if(xgrotery<0)
    {
    ht=ty;
    ty=tx;
    tx=ht;
    hp=py;
    py=px;
    px=hp;
    hp=oy;
    oy=ox;
    ox=hp;
    }
if(tx==ty)
    {
    opaf(&hres,ox,px,oy,py,1);
    if(carry)
        *--hres='1';
    }
else
    opaf(&hres,ox,px,oy,py,-1);
supernul(res,tx);
return res;
}

void opaf(pres,bx,ex,by,ey,act)
char **pres,*bx,*ex,*by,*ey;
int act;
{
register char *i1,*i2,*wyzer;
register int lcarry;
lcarry=0;
i1=*pres;
i2=ex;
wyzer=ey;
do
    {
    *i1 = *i2 + lcarry + act * (*wyzer-'0');
    if(*i1 > '9')
        {
        lcarry = 1;
        *i1 -=10;
        }
    else
        if(*i1 < '0')
            {
            lcarry = -1;
            *i1 +=10;
            }
        else
            lcarry = 0;
    i1--;
    i2--;
    wyzer--;
    }
while(wyzer>=by);
for(;i2>=bx;)
    {
    *i1 = *i2 + lcarry;
    if(*i1 > '9')
        {
        lcarry = 1;
        *i1 -=10;
        }
    else
        if(*i1 < '0')
            {
            lcarry = -1;
            *i1 +=10;
            }
        else
            lcarry = 0;
    i1--;
    i2--;
    }
*pres=i1+1;
carry=lcarry;
}

void xyinit(x,y)
ngetal x,y;
{
xlengte=eindnum(&tx,&ox,&px,x);
ylengte=eindnum(&ty,&oy,&py,y);
}

int eindnum(pteken,ppkarb,ppkare,pkar)
char *pteken,**ppkarb,**ppkare,*pkar;
{
register char *pb,*pe;
pe=*ppkare;
pb=*ppkarb= is_digit(*pkar) ? pkar : pkar+1;
*pteken= pb==pkar ? '+' : *pkar;
for(pe = pb;is_digit(*++pe););
*ppkare=pe-1;
return pe - pb;
}

int is_digit(k)
int k;
{
return k >= '0' && k <= '9';
}

void supernul(nget,teken)
ngetal nget;
char teken;
{
ngetal pnget,pnget1;
for(pnget=nget;*pnget=='0';pnget++);
if(*pnget)
    {
    pnget1=nget;
    *pnget1++ = teken;
    for(;*pnget;*pnget1++ = *pnget++);
    *pnget1=0;
    }
else
    {
    *nget='0';
    *(nget+1)=0;
    }
}

void vgl(kn1,kn2)
psk kn1,kn2;
{
static int hulp;
if(kop(kn1))
    {
    if(kop(kn2))
        {
        if((hulp=kop(kn1) - kop(kn2))!=0)
            {
            is_gelyk=FALSE;
            is_groter=(hulp>0);
            return;
            }
        else
            {
            vgl(kn1->u.p.links,kn2->u.p.links);
            if(is_gelyk)
                vgl(kn1->u.p.rechts,kn2->u.p.rechts);
            }
        }
    else
        {
        is_gelyk=FALSE;
        is_groter=TRUE;
        return;
        }
    }
else
    {
    if(kop(kn2))
        {
        is_gelyk=FALSE;
        is_groter=FALSE;
        return;
        }
    else
        {
        if((hulp=strcmp(&(kn1->u.obj),&(kn2->u.obj)))!=0)
            {
            is_gelyk=FALSE;
            is_groter=(hulp>0);
            return;
            }
        else
            {
            is_groter=FALSE;
            is_gelyk =TRUE;
            }
        }
    }
}

int vergelijk(qx,qy)
qgetal qx,qy;
{
qgetal minqy,som;
int res;
minqy=qmaal(mineen,qy);
som=qplus(qx,minqy);
bfree(minqy);
switch(*som)
    {
    case '0' :
        res=GELIJK;
        break;
    case '-' :
        res=KLEINER;
        break;
    default  :
        res=GROTER;
    }
bfree(som);
return res;         
}

#if FALSE
qgetal absoluut(qx)
qgetal qx;
{
switch(*qx)
    {
    case '-' : return qmaal(mineen,qx);
    default  : return qmaal(een,qx);
    }
}
#endif

qgetal modulo(qx,qy)
qgetal qx;
qgetal qy;
{
struct deelres deling;
qgetal res,hres,p1,p2;
qgetal xt,xn,yt,yn;
splits(qx,&xt,&xn);          
splits(qy,&yt,&yn);          
nndeel((p1=nmaal(xt,yn)),(p2=nmaal(xn,yt)),&deling);
bfree(xt);
bfree(yt);
bfree(p1);
bfree(p2);
bfree(deling.quot);
res=qqdeel((p1=qqdeel(deling.rest,xn)),yn);
bfree(xn);
bfree(yn);
bfree(p1);
bfree(deling.rest);
if((*res=='-' && *qy!='-') || (*res!='-' && *qy=='-'))
    {
    hres=res;
    res=qplus(hres,qy);
    bfree(hres);
    }
return res;
}

qgetal geheeldelen(qx,qy)
qgetal qx,qy;
{
struct deelres deling;
qgetal xt,xn,yt,yn,res,p1,p2;
splits(qx,&xt,&xn);
splits(qy,&yt,&yn);
nndeel((p1=nmaal(xt,yn)),(p2=nmaal(xn,yt)),&deling);
bfree(xt);
bfree(yt);
bfree(xn);
bfree(yn);
bfree(p1);
bfree(p2);
bfree(deling.rest);
res=qplus(nul,deling.quot);
bfree(deling.quot);
return res;
}

void init_ruimte()
{
long *i;
p4start=malloc(PROMILLAGE4*sizeof(struct byte4)*KILOKNOPEN);
p4end=p4start+PROMILLAGE4*KILOKNOPEN;
p4=p4start;
for(i=(long*)p4start;
    i<(long*)p4end;
    i+=sizeof(struct byte4)/sizeof(long))
    *i=0;
p8start=malloc(PROMILLAGE8*sizeof(struct byte8)*KILOKNOPEN);
p8end=p8start+PROMILLAGE8*KILOKNOPEN;
p8=p8start;
for(i=(long*)p8start;
    i<(long*)p8end;
    i+=sizeof(struct byte8)/sizeof(long))
    *i=0;
p12start=malloc(PROMILLAGE12*sizeof(struct byte12)*KILOKNOPEN);
p12end=p12start+PROMILLAGE12*KILOKNOPEN;
p12=p12start;
for(i=(long*)p12start;
    i<(long*)p12end;
    i+=sizeof(struct byte12)/sizeof(long))
    *i=0;
printf("p4 %ld - %ld p8 %ld - %ld p12 %ld - %ld\n",
(long)p4start,(long)p4end,
(long)p8start,(long)p8end,
(long)p12start,(long)p12end);
}

void bfree(p)
void *p;
{
globalloc--;
if(p >= (void*)p4start &&
   p <  (void*)p4end)
    {
    *(long*)p=0;
    if(!al4++)
        p4=p;
    }
else
    if(p >= (void*)p8start &&
       p <  (void*)p8end)
        {
        *(long*)p=0;
        if(!al8++)
            p8=p;
        }
    else
        if(p >= (void*)p12start &&
           p <  (void*)p12end)
            {
            *(long*)p=0;
            if(!al12++)
                p12=p;
            }
        else
            free(p);
}

void *bmalloc(n)
int n;
{
int tel,tel1;
void *res;
globalloc++;
alloc_cnt++;
if(n<256)
    cnts[n]++;
totcnt+=n;
switch((n+3)/4)
    {
    case 1 :
        if(al4 && (res=alloc4())!= NULL)
            return res;
    case 2 :
        if(al8 && (res=alloc8())!= NULL)
            return res;
    case 3 :
        if(al12 && (res=alloc12())!= NULL)
            return res;
    }
res=malloc(n);
if(res)
    return res;
printf("GEHEUGEN VOL NA %d ALLOCATIES MET GEMIDDELDE LENGTE %d\n",
    globalloc,totcnt/alloc_cnt);
for(tel=0;tel<16;tel++)
    {
    for(tel1=0;tel1<256;tel1+=16)
        printf("%d ",(cnts[tel+tel1]*1000+500)/alloc_cnt);
    putchar('\n');
    }
bezetting();
exit(0);
return NULL;
}

void *alloc4()
{
register struct byte4 *start,*rp4,*rp4end;
rp4=start=p4;
rp4end=p4end;
while(rp4->flgs)
    {
    if(++rp4 >= rp4end)
        rp4=p4start;
    if(rp4==start)
        return NULL;
    }
al4--;
/*
if(!al4)
    bezetting();
*/
rp4->flgs=BEZET;
return p4=rp4;
}

void *alloc8()
{
register struct byte8 *start,*rp8,*rp8end;
rp8=start=p8;
rp8end=p8end;
while(rp8->flgs)
    {
    if(++rp8 >= rp8end)
        rp8=p8start;
    if(rp8==start)
        return NULL;
    }
al8--;
/*
if(!al8)
    bezetting();
*/
rp8->flgs=BEZET;
return p8=rp8;
}

void *alloc12()
{
register struct byte12 *start,*rp12,*rp12end;
rp12=start=p12;
rp12end=p12end;
while(rp12->flgs)
    {
    if(++rp12 >= rp12end)
        rp12=p12start;
    if(rp12==start)
        return NULL;
    }
al12--;
/*
if(!al12)
    bezetting();
*/
rp12->flgs=BEZET;
return p12=rp12;
}

void bezetting()
{
printf("bezet (promilles) 1 woord : %d, 2 woorden : %d, 3 woorden : %d\n",
1000-(al4 *1000)/(PROMILLAGE4 *KILOKNOPEN),
1000-(al8 *1000)/(PROMILLAGE8 *KILOKNOPEN),
1000-(al12*1000)/(PROMILLAGE12*KILOKNOPEN));
printf("meer dan 3 woorden (absoluut): %d\n",
globalloc+al4+al8+al12-1000*KILOKNOPEN);
}
