/*  $VER: vbcc (parse_expr.c) V0.4  */

#include "vbc.h"

static char FILE_[]=__FILE__;

np expression(void)
/*  Komma-Ausdruecke                                        */
{
    np left,right,new;
    left=assignment_expression();
    if(!left->flags) return(0);
    killsp();
    while(*s==','){
        s++;
        killsp();
        right=assignment_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->ntyp=0;
        new->flags=KOMMA;
        left=new;
        killsp();
    }
    return(left);
}
np assignment_expression(void)
/*  Zuweisungsausdruecke                                    */
{
    np left,new;int c=0;
    left=conditional_expression();
    killsp();
    if(*s!='='&&*(s+1)!='='&&*(s+2)!='=') return(left);
    if(*s=='=') {c=ASSIGN;s++;} else
    {if(*s=='*'&&*(s+1)=='=') {c=ASSIGNMULT;s+=2;}  else
    {if(*s=='/'&&*(s+1)=='=') {c=ASSIGNDIV;s+=2;}   else
    {if(*s=='%'&&*(s+1)=='=') {c=ASSIGNMOD;s+=2;}   else
    {if(*s=='+'&&*(s+1)=='=') {c=ASSIGNADD;s+=2;}   else
    {if(*s=='-'&&*(s+1)=='=') {c=ASSIGNSUB;s+=2;}   else
    {if(*s=='&'&&*(s+1)=='=') {c=ASSIGNAND;s+=2;}   else
    {if(*s=='^'&&*(s+1)=='=') {c=ASSIGNXOR;s+=2;}   else
    {if(*s=='|'&&*(s+1)=='=') {c=ASSIGNOR;s+=2;}    else
    {if(*s=='<'&&*(s+1)=='<') {c=ASSIGNLSHIFT;s+=3;}else
    {if(*s=='>'&&*(s+1)=='>') {c=ASSIGNRSHIFT;s+=3;}else {return(left);}
    }}}}}}}}}}
    new=mymalloc(NODES);
    new->left=left;
    new->ntyp=0;
    if(c==ASSIGN){
        new->right=assignment_expression();
        new->flags=ASSIGN;
    }else{
        /*  ASSIGNOP(a,b)->ASSIGN(a,OP(a,b))    */
        new->flags=ASSIGNADD;   /* nur zum Merken, dass nur einmal  */
                                /* ausgewertet werden darf          */
        new->right=mymalloc(NODES);
        new->right->left=left;
        new->right->right=assignment_expression();
        new->right->ntyp=0;
        if(c==ASSIGNMULT) new->right->flags=MULT;
        if(c==ASSIGNDIV) new->right->flags=DIV;
        if(c==ASSIGNMOD) new->right->flags=MOD;
        if(c==ASSIGNADD) new->right->flags=ADD;
        if(c==ASSIGNSUB) new->right->flags=SUB;
        if(c==ASSIGNAND) new->right->flags=AND;
        if(c==ASSIGNXOR) new->right->flags=XOR;
        if(c==ASSIGNOR) new->right->flags=OR;
        if(c==ASSIGNLSHIFT) new->right->flags=LSHIFT;
        if(c==ASSIGNRSHIFT) new->right->flags=RSHIFT;
    }
    return(new);
}
np conditional_expression(void)
/*  Erledigt ? :  momentan noch nicht implementiert         */
{
    np left,new;
    left=logical_or_expression();
    killsp();
    if(*s=='?'){    /*  hier ein while  ?   */
        s++;killsp();
        new=mymalloc(NODES);
        new->flags=COND;
        new->ntyp=0;
        new->left=left;
        new->right=mymalloc(NODES);
        new->right->flags=COLON;
        new->right->ntyp=0;
        new->right->left=expression();
        killsp();
        if(*s==':'){s++;killsp();} else error(70);
        new->right->right=conditional_expression();
        left=new;
        killsp();
    }
    return(left);
}
np logical_or_expression(void)
/*  Erledigt ||                                             */
{
    np left,right,new;
    left=logical_and_expression();
    killsp();
    while(*s=='|'&&*(s+1)=='|'){
        s+=2;
        killsp();
        right=logical_and_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=LOR;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np logical_and_expression(void)
/*  Erledigt &&                                             */
{
    np left,right,new;
    left=inclusive_or_expression();
    killsp();
    while(*s=='&'&&*(s+1)=='&'){
        s+=2;
        killsp();
        right=inclusive_or_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=LAND;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np inclusive_or_expression(void)
/*  Erledigt |                                              */
{
    np left,right,new;
    left=exclusive_or_expression();
    killsp();
    while(*s=='|'&&*(s+1)!='|'&&*(s+1)!='='){
        s++;
        killsp();
        right=exclusive_or_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=OR;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np exclusive_or_expression(void)
/*  Erledigt ^                                              */
{
    np left,right,new;
    left=and_expression();
    killsp();
    while(*s=='^'&&*(s+1)!='='){
        s++;
        killsp();
        right=and_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=XOR;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np and_expression(void)
/*  Erledigt &                                              */
{
    np left,right,new;
    left=equality_expression();
    killsp();
    while(*s=='&'&&*(s+1)!='&'&&*(s+1)!='='){
        s++;
        killsp();
        right=equality_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=AND;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np equality_expression(void)
/*  Erledigt == und !=                                      */
{
    np left,right,new;int c;
    left=relational_expression();
    killsp();
    while((*s=='='||*s=='!')&&*(s+1)=='='){
        if(*s=='!') c=INEQUAL; else c=EQUAL;
        s+=2;
        killsp();
        right=relational_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=c;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np relational_expression(void)
/*  Erledigt <,>,<=,>=                                      */
{
    np left,right,new;int c;
    left=shift_expression();
    killsp();
    while((*s=='<'&&*(s+1)!='<')||(*s=='>'&&*(s+1)!='>')){
        if(*s++=='<'){
            if(*s=='='){s++;c=LESSEQ;}else c=LESS;
        }else{
            if(*s=='='){s++;c=GREATEREQ;}else c=GREATER;
        }
        killsp();
        right=shift_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=c;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np shift_expression(void)
/*  Erledigt <<,>>                                          */
{
    np left,right,new;int c;
    left=additive_expression();
    killsp();
    while((*s=='<'&&*(s+1)=='<'&&*(s+2)!='=')||(*s=='>'&&*(s+1)=='>'&&*(s+2)!='=')){
        if(*s=='<') c=LSHIFT; else c=RSHIFT;
        s+=2;
        killsp();
        right=additive_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=c;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np additive_expression(void)
/*  Erledigt +,-                                            */
{
    np left,right,new;int c;
    left=multiplicative_expression();
    killsp();
    while((*s=='+'||*s=='-')&&*(s+1)!='='){
        if(*s++=='+') c=ADD; else c=SUB;
        killsp();
        right=multiplicative_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=c;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np multiplicative_expression(void)
/*  Erledigt *,/,%                                          */
{
    np left,right,new;int c;
    left=cast_expression();
    killsp();
    while((*s=='*'||*s=='/'||*s=='%')&&*(s+1)!='='){
        if(*s=='*') c=MULT; else {if(*s=='/') c=DIV; else c=MOD;}
        s++;
        killsp();
        right=cast_expression();
        new=mymalloc(NODES);
        new->left=left;
        new->right=right;
        new->flags=c;
        new->ntyp=0;
        left=new;
        killsp();
    }
    return(left);
}
np cast_expression(void)
/*  Erledigt (typ)                                          */
{
    np new;char *imerk,buff[MAXI];
    killsp();
    if(*s!='('||!declaration(1)) return(unary_expression());
    s++;killsp();
    new=mymalloc(NODES);
    new->flags=CAST;
    new->right=0;
    imerk=ident;ident=buff;
    new->ntyp=declarator(declaration_specifiers());
    ident=imerk;
    killsp();
    if(*s!=')') error(59); else s++;
    new->left=cast_expression();
    return(new);
}
np unary_expression(void)
/*  Erledigt !,~,++,--,+,-,*,&,sizeof                       */
{
    np new;char *merk=s,buff[MAXI];int done=0;
    killsp();
    if((*s!='s'&&*s!='+'&&*s!='-'&&*s!='&'&&*s!='*'&&*s!='~'&&*s!='!')||*(s+1)=='=') return(postfix_expression());
    if(*s=='s'){
        merk=s;cpbez(buff,0);s=merk;
        if(strcmp("sizeof",buff)) return(postfix_expression());
        else{
            s+=6;killsp();
            new=mymalloc(NODES);
            new->flags=CEXPR;
            new->ntyp=mymalloc(TYPS);
            new->ntyp->flags=UNSIGNED|LONG;
            new->ntyp->next=0;
            new->right=0;
            new->left=0;
            if(*s=='('&&declaration(1)){
                struct Typ *t;
                s++;killsp();
                merk=ident;ident=buff;
                t=declarator(declaration_specifiers());
                if(type_uncomplete(t)) error(176);
                ident=merk;
                new->val.vulong=zl2zul(szof(t));
                freetyp(t);
                killsp();
                if(*s!=')') error(59); else s++;
            }else{
                np tree;
                killsp();
                tree=unary_expression();
                if(!tree||!type_expression(tree)){
                    new->val.vulong=zl2zul(l2zl(0L));
                    error(73);
                }else{
                    if(type_uncomplete(tree->ntyp)) error(176);
                    new->val.vulong=zl2zul(szof(tree->ntyp));
                }
                if(tree) free_expression(tree);killsp();
            }
            return(new);
        }
    }
    new=mymalloc(NODES);
    new->right=0;
    new->ntyp=0;
    if(*s=='+'&&!done)
        if(*(s+1)=='+'){
            s+=2;done=1;
            new->left=unary_expression();
            new->flags=PREINC;
        }else{
            s++;free(new);
            return(cast_expression());
        }
    if(*s=='-'&&!done){
        done=1;
        if(*(s+1)=='-'){
            s+=2;
            new->left=unary_expression();
            new->flags=PREDEC;
        }else{
            s++;
            new->left=cast_expression();
            new->flags=MINUS;
        }
    }
    if(*s=='&'&&!done){
        s++;done=1;
        new->left=cast_expression();
        new->flags=ADDRESS;
    }
    if(*s=='*'&&!done){
        s++;done=1;
        new->left=cast_expression();
        new->flags=CONTENT;
    }
    if(*s=='~'&&!done){
        s++;done=1;
        new->left=cast_expression();
        new->flags=KOMPLEMENT;
    }
    if(*s=='!'&&!done){
        s++;done=1;
        new->left=cast_expression();
        new->flags=NEGATION;
    }
    new->right=0;
    new->ntyp=0;
    return(new);
}
np postfix_expression(void)
/*  Erledigt [],(),.,->,++,--                                   */
{
    np new,left;int done;
    left=primary_expression();
    killsp();
    while(*s=='['||*s=='('||*s=='.'||(*s=='-'&&((*(s+1)=='-')||(*(s+1)=='>')))
          ||(*s=='+'&&*(s+1)=='+')){
        done=0;
        new=mymalloc(NODES);
        new->ntyp=0;
        new->right=0;
        new->left=left;
        if(*s=='-'){
            s++;done=1;
            if(*s=='-'){
                s++;
                new->flags=POSTDEC;
            }else{
                s++; killsp();
                new->flags=DSTRUCT;
                new->right=identifier_expression();
                new->right->flags=MEMBER;
                new->left=mymalloc(NODES);
                new->left->ntyp=0;
                new->left->left=left;
                new->left->right=0;
                new->left->flags=CONTENT;
            }
        }
        if(*s=='['&&!done){
            s++; killsp();done=1;
            new->flags=CONTENT;
            new->left=mymalloc(NODES);
            new->left->flags=ADD;
            new->left->ntyp=0;
            new->left->left=left;
            new->left->right=expression();
            killsp();
            if(*s!=']') error(62); else s++;
        }
        if(*s=='+'&&!done){
            s+=2;done=1;
            new->flags=POSTINC;
        }
        if(*s=='.'&&!done){
            s++;killsp();done=1;
            new->right=identifier_expression();
            new->flags=DSTRUCT;
            new->right->flags=MEMBER;
        }
        if(*s=='('&&!done){
            struct argument_list *al,*first_alist=0,*last_alist=0;np n;
            s++;killsp();done=1;
            new->flags=CALL;
            new->right=0;
            while(*s!=')'){
                n=assignment_expression();
                al=mymalloc(sizeof(struct argument_list));
                al->arg=n;al->next=0;
                if(last_alist){
                    last_alist->next=al;
                    last_alist=al;
                }else{
                    last_alist=first_alist=al;
                }
                killsp();
                if(*s==',') {s++;killsp();if(*s==')') error(59);} /* hier noch strenger */
            }
            new->alist=first_alist;
            if(*s!=')') error(59); else s++;
        }
        left=new;
        killsp();
    }
    return(left);
}
np primary_expression(void)
/*  Hier fehlt noch allerhand                               */
{
    np new;
    if((*s>='0'&&*s<='9')||*s=='.') return(constant_expression());
    if(*s=='\"'||*s=='\''||(*s=='L'&&(*(s+1)=='\''||*(s+1)=='\"'))) return(string_expression());
    if(*s=='('){
        s++;killsp();
        new=expression();
        killsp();
        if(*s!=')') error(59); else s++;
        return(new);
    }
    return(identifier_expression());
}
np string_expression(void)
/*  Gibt Zeiger auf string oder Zeichenkonstante zurueck    */
{
    np new; char f,string[MAXINPUT],*p;int flag,val;zlong zl;
    if(*s=='L') s++;    /*  Noch keine erweiterten Zeichen  */
    p=string;f=*s++;
    while(1){
        while(*s!=f&&p<&string[MAXINPUT-1]){
            if(*s=='\\'){
                s++;
                if(*s=='\\'){*p++='\\';s++;continue;}
                if(*s=='n'){*p++='\n';s++;continue;}
                if(*s=='t'){*p++='\t';s++;continue;}
                if(*s=='r'){*p++='\r';s++;continue;}
                if(*s=='v'){*p++='\v';s++;continue;}
                if(*s=='b'){*p++='\b';s++;continue;}
                if(*s=='f'){*p++='\f';s++;continue;}
                if(*s=='a'){*p++='\a';s++;continue;}
                if(*s=='\?'){*p++='\?';s++;continue;}
                if(*s=='\''){*p++='\'';s++;continue;}
                if(*s=='\"'){*p++='\"';s++;continue;}
                flag=val=0;
                while(*s>='0'&&*s<='7'&&flag<3){
                    val=val*8+*s-'0';
                    s++;flag++;
                }
                if(flag){*p++=val;continue;}
                if(*s=='x'){
                    s++;val=0;
                    while((*s>='0'&&*s<='9')||(*s>='a'&&*s<='f')||(*s>='A'&&*s<='F')){
                        val=val*16;
                        if(*s>='0'&&*s<='9') val+=*s-'0';
                        if(*s>='a'&&*s<='f') val+=*s-'a'+10;
                        if(*s>='A'&&*s<='F') val+=*s-'A'+10;
                        s++;
                    }
                    *p++=val;continue;
                }
                error(71);
            }
            *p++=*s++;
        }
        if(*s!=f) error(74); else s++;
        killsp();
        if(f!='\"'||*s!=f) break; else s++;
    }
    *p=0;
    new=mymalloc(NODES);
    new->ntyp=mymalloc(TYPS);
    if(f=='\"'){
        struct const_list *cl,**prev;int i;
        new->ntyp->flags=ARRAY;
        new->ntyp->size=l2zl((long)(p-string)+1);
        new->ntyp->next=mymalloc(TYPS);
        new->ntyp->next->flags=STRINGCONST|CHAR;
        new->ntyp->next->next=0;
        new->flags=STRING;
        prev=(struct const_list **)&new->identifier;
        for(i=0;i<p-string+1;i++){
            cl=mymalloc(CLS);
            cl->next=0;
            cl->tree=0;
            cl->other=mymalloc(CLS);
            cl->other->next=cl->other->other=0;
            cl->other->tree=0;
            cl->other->val.vchar=zl2zc(l2zl((long)string[i]));
            *prev=cl;
            prev=&cl->next;
        }
/*        new->identifier=add_identifier(string,p-string);*/
        new->val.vlong=l2zl(0L);
    }else{
        char *l;
        new->ntyp->flags=CONST|INT;
        new->ntyp->next=0;
        new->flags=CEXPR;
        zl=l2zl(0L);
        p--;
        if(p>string) error(72);
        for(BIGENDIAN?(l=string):(l=p);BIGENDIAN?(l<=p):(l>=string);BIGENDIAN?(l++):(l--)){
            /*  zl=zl<<CHAR_BIT+*p  */
            zl=zllshift(zl,char_bit);
            zl=zladd(zl,l2zl((long)*l));
            new->val.vint=zl2zi(zl);
        }
    }
    new->left=new->right=0;
    return(new);
}
np constant_expression(void)
/*  Gibt Zeiger auf erzeugt Struktur fuer Konstante zurueck */
/*  Es werden die Werte aus <limits.h> benutzt.             */
{
    np new; zdouble db;
    zulong value,zbase,digit;unsigned long base=10,t;
    char *merk;int warned=0;
    merk=s;
    value=ul2zul(0L);
    new=mymalloc(NODES);
    new->ntyp=mymalloc(TYPS);
    new->ntyp->flags=0;
    new->ntyp->next=0;
    new->flags=CEXPR;
    new->left=new->right=0;
    new->sidefx=0;
    if(*s=='0'){
        s++;
        if(*s=='x'||*s=='X'){s++;base=16;} else base=8;
    }
    zbase=ul2zul(base);
    if(*s>='0'&&*s<='9') t=*s-'0'; else{
    if(*s>='a'&&*s<='f') t=*s-'a'+10; else{
    if(*s>='A'&&*s<='F') t=*s-'A'+10; else{t=20;}}}
    while(t<base){
        digit=ul2zul(t);
        if(!warned){
            if(!zulleq(value,zuldiv(zulsub(t_max[UNSIGNED|LONG],digit),zbase)))
                warned=1;
        }
        value=zuladd(zulmult(value,zbase),digit);
        s++;
        if(*s>='0'&&*s<='9') t=*s-'0'; else{
        if(*s>='a'&&*s<='f') t=*s-'a'+10; else{
        if(*s>='A'&&*s<='F') t=*s-'A'+10; else{t=20;}}}
    }
    while(*s=='u'||*s=='U'||*s=='l'||*s=='L'){
        if(*s=='u'||*s=='U'){
            if(zulleq(value,UINT_MAX)) new->ntyp->flags=UNSIGNED|INT;
             else               new->ntyp->flags=UNSIGNED|LONG;
        }else{
            if(zulleq(value,LONG_MAX)) new->ntyp->flags=LONG;
             else               new->ntyp->flags=UNSIGNED|LONG;
        }
        s++;
    }
    if(*s=='.'||*s=='e'||*s=='E'){
    /*  Fliesskommakonstante, ignoriert vorher berechneten Wert, falls er   */
    /*  nicht dezimal und nicht 0 war (da er dann oktal war)                */
        if(*merk=='0'&&!zuleqto(value,ul2zul(0UL))){
            value=ul2zul(0UL);zbase=ul2zul(10UL);
            while(*merk>='0'&&*merk<='9'){
                digit=ul2zul((unsigned long)(*merk-'0'));
                value=zuladd(zulmult(value,zbase),digit);
                merk++;
            }
            if(merk!=s) error(75);
        }
        db=zul2zd(value);
        if(*s=='.'){
        /*  Teil hinter Kommastellen    */
            zdouble zquot,zbased,digit;
            s++;
            zbased=d2zd(10);zquot=d2zd(0.1);
            while(*s>='0'&&*s<='9'){
                digit=d2zd((double)(*s-'0'));
                db=zdadd(db,zdmult(digit,zquot));
                zquot=zddiv(zquot,zbased);
                s++;
            }

        }
        if(*s=='e'||*s=='E'){
        /*  Exponentialdarstellung  */
            int exp,vorz,i;zdouble zbased;
            zbased=d2zd((double)10);
            s++;
            if(*s=='-'){
                s++;vorz=-1;
            }else{
                vorz=1;if(*s=='+') s++;
            }
            exp=0;
            while(*s>='0'&&*s<='9') exp=exp*10+*s++-'0';
            for(i=0;i<exp;i++){
                if(vorz>0) db=zdmult(db,zbased);
                    else   db=zddiv(db,zbased);
            }
        }
        new->ntyp->flags=DOUBLE;
        if(*s=='f'||*s=='F'){
            new->ntyp->flags=FLOAT;s++;
        }else{
        /*  long double werden nicht unterstuetzt und sind==double :-(  */
            if(*s=='l'||*s=='L') s++;
        }
    }else{
        if(warned) error(211);
        if(new->ntyp->flags==0){
            if(base==10){
                if(zulleq(value,INT_MAX)) new->ntyp->flags=INT; else{
                if(zulleq(value,LONG_MAX)) new->ntyp->flags=LONG; else{
                                    new->ntyp->flags=UNSIGNED|LONG;error(212);}}
            }else{
                if(zulleq(value,INT_MAX)) new->ntyp->flags=INT; else{
                if(zulleq(value,UINT_MAX))new->ntyp->flags=UNSIGNED|INT; else{
                if(zulleq(value,LONG_MAX))new->ntyp->flags=LONG; else{
                                   new->ntyp->flags=UNSIGNED|LONG;error(212);}}}
            }
        }
    }

    if(new->ntyp->flags==FLOAT) new->val.vfloat=zd2zf(db);
    if(new->ntyp->flags==DOUBLE) new->val.vdouble=db;
    if(new->ntyp->flags==INT) new->val.vint=zl2zi(zul2zl(value));
    if(new->ntyp->flags==(UNSIGNED|INT)) new->val.vuint=zul2zui(value);
    if(new->ntyp->flags==LONG) new->val.vlong=zul2zl(value);
    if(new->ntyp->flags==(UNSIGNED|LONG)) new->val.vulong=value;
    return(new);
}
np identifier_expression(void)
/*  Erzeugt Identifier mit Knoten                           */
{
    np new;char buff[MAXI];
    killsp();cpbez(buff,1);
    new=mymalloc(NODES);
    new->flags=IDENTIFIER;
    new->left=new->right=0;
    new->identifier=add_identifier(buff,strlen(buff));
    new->ntyp=0;
    new->sidefx=0;
    new->val.vlong=l2zl(0L);
    if(new->identifier==empty) {error(76);new->flags=0;}
    return(new);
}
void free_alist(struct argument_list *p)
/*  Gibt argument_list inkl. expressions frei                   */
{
    struct argument_list *merk;
    while(p){
        merk=p->next;
        if(p->arg) free_expression(p->arg);
        free(p);
        p=merk;
    }
}
void free_expression(np p)
/*  Gibt expression mit allen Typen etc. frei                   */
{
    if(!p) return;
    if(p->flags==ASSIGNADD){
        if(!p->right){ierror(0);return;}
        if(p->right->left==p->left)  p->left=0;
        if(p->right->right==p->left) p->left=0;
    }
    if(p->flags==CALL&&p->alist) free_alist(p->alist);
    if(p->ntyp) freetyp(p->ntyp);
    if(p->left) free_expression(p->left);
    if(p->right) free_expression(p->right);
    free(p);
}

