/*

  handles the expression

*/

char has_effect;
char exprtype;
int getexpr(char ineval, char parmtype){
        int a,bp,forcenxt=0,retme=0;
        char nxtisminus=0,nextincdec=0,brackcnt=0,mustend=0,nextisnot=0;
        char mathsym=0,nextisaddress=0,nextpoints=0,islabel=1;
        char parmcnt=0,do_eval=0,do_evalwhen=0;
        char do_evaltype=0,dist,got_arr=0;
        proc_hold *our_proc;
        lab_hold *our_lab;
        char makingit,curtype=-1;
        char multi_call,but_minus_1;
        char may_error;
        int got_size;
        char label_addresser[100];
        char tmp_str[20];
        char use_cs=0,first_thing=1;
        char cur_is_signed=1,la_size;
        exprtype=DEFAULT_TYPE;//defaults to int
        has_effect=0;
        for(;;){
             anotherloop:
             skipspaces();
             if(lineptr[lptr]==0){if(lineptr[lptr+1]==0)lptr++; break;}
             if(lineptr[lptr]=='!' && lineptr[lptr+1]!='='){ nextisnot=1;
                                                             first_thing=0;
                                                             lptr++; }
             if(lineptr[lptr]=='-') { nxtisminus=1; lptr++;first_thing=0; }
             if(lineptr[lptr]=='&') { nextisaddress=1; lptr++; first_thing=0;}
             if(lineptr[lptr]=='*') { nextpoints=1; lptr++; first_thing=0;
                                      if(lineptr[lptr]=='*'){
                                                      error("SCC only supports single pointers",ERROR);
                                                      return 1; }
                                      }
             if(lineptr[lptr]=='+' && lineptr[lptr+1]=='+'){ lptr+=2;first_thing=0;
                                         nextincdec=1; has_effect=1;  }
             else if(lineptr[lptr]=='-' && lineptr[lptr+1]=='-'){  lptr+=2;first_thing=0;
                                       nextincdec=2; has_effect=1; }
             skipspaces();

             a=ischarnum(lineptr[lptr]);
             if(a==1){ get_nextword();//char
                       if(!strcmp(word,"sizeof")){
                                          skipspaces();
                                          if(lineptr[lptr]!='('){ error("Missing ( in call of sizeof",ERROR);
                                                                  return 1; }
                                          lptr++;
                                          a=checkforce(0);
                                          if(a==-1)return 1;
                                          skipspaces();
                                          if(lineptr[lptr]!=')'){ error("Missing ) in call of sizeof",ERROR);
                                                                 return 1; }
                                          lptr++;
                                          asm_do_mathsnumtomathreg(mathsym,getsize(a),cur_is_signed);
                                          goto repeatpart2;
                                                }
                       if(legal_labelname(word)){
                                      error("Illegal use of a reserved word",ERROR);
                                      return 1;  }
                        if(lineptr[lptr]==':'){
                                          lptr++;
                                          if(ineval || parmtype || first_thing==0){ error("Syntax error",ERROR); return 1; }
                                          if(prg_out)sprintf(asm_la_str,"P _%s",word);
                                          else sprintf(asm_la_str,"_%s:",word);
                                          go_assemble();
                                          fadd_gotopos(word,1);
                                          skipspaces(); if(lineptr[lptr]==0 || lineptr[lptr]=='{' || lineptr[lptr]=='}')has_effect=1;
                                          first_thing=0;
                                          return 3;
                                                }
                        first_thing=0;
                        skipspaces();
                        if(lineptr[lptr]=='('){ lptr++;//proc call
                                              skipspaces(); parmcnt=0;
                                              multi_call=0; got_size=0; but_minus_1=0;
                                              if(legal_labelname(word)){
                                                               error("Illegal use of a reserved word",ERROR);
                                                               return 1;  }
                                              makingit=forcenxt; if(makingit<1)makingit=curtype;
                                              makingit=faddproc(0,0,0,0,0,makingit,0,word,NULL);
                                              if(makingit==0)
                                                        cur_is_signed=is_it_signed(tmp_proc->type);//was our_proc
                                              if(makingit==-1)return 1;
                                              our_proc=tmp_proc;//bak this up
                                              if(islabel==0) push_otherreg();
                                              if(mathsym) push_mathreg();
                                              push_bp_sp();

                                              if(lineptr[lptr]==')') lptr++;
                                              else{
                                                  for(;;){
                                                     parmcnt++;
                                                     if(getexpr(0,1)==1)return 1;
                                                     if(makingit){our_proc->parmstr[parmcnt-1]=exprtype;
                                                                  our_proc->parmsize+=getsize(exprtype);
                                                                  our_proc->lastparmsz=getsize(exprtype);
                                                                        }
                                                     else {
                                                        if(our_proc->parmstr[parmcnt-1]==-1)multi_call=parmcnt;
                                                        if(multi_call==0)test_type(-1,our_proc->parmstr[parmcnt-1],exprtype,1);
                                                        }
                                                     if(multi_call){push_parametermathreg(getsize(exprtype));
                                                                    got_size+=getsize(exprtype);
                                                                        }
                                                     else push_parametermathreg(getsize(our_proc->parmstr[parmcnt-1]));//depending on size!!!
                                                     if(lineptr[lptr-1]==')')break;
                                                     else if(lineptr[lptr-1]==',');
                                                     else { error("Missing )",ERROR);
                                                            return 1; }
                                                     }//for
                                                  }//else
                                                  if(our_proc->parmstr[parmcnt+0]==-1 && multi_call==0){ multi_call=1; but_minus_1=1; }
                                                if(makingit)our_proc->parmcnt=parmcnt;
                                                else if(multi_call==0 && our_proc->parmcnt<parmcnt)parmerror(1,our_proc->name);
                                                else if(our_proc->parmcnt>parmcnt){
                                                                                if(our_proc->parmstr[parmcnt+0]==-1){
                                                                                                     if(our_proc->parmcnt-1>parmcnt)parmerror(0,our_proc->name);//missing
                                                                                                                                }
                                                                                else parmerror(0,our_proc->name);//missing
                                                                                }

                                                if(makingit==0)test_type(forcenxt,curtype,our_proc->type,1);
                                                else fixup_parameters(our_proc);//so they are +offsets

                                                if(multi_call)//push parmcnt
                                                               mov_mathreg_numberand_push_ax(parmcnt-(multi_call-1)-but_minus_1);

                                                call_proc(our_proc->name);
                                                if(parmcnt>0) {
                                                        if(multi_call)adjust_sp(our_proc->parmsize+got_size+2);
                                                        else adjust_sp(our_proc->parmsize);
                                                        }

                                                pop_sp_bp();
                                                if(mathsym) pop_mathreg();
                                                a=our_proc->type; if(a>10)a/=10;
                                                if(our_proc->type!=5 && our_proc->type!=10)
                                                                     asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                 if(islabel==0) pop_otherreg();
                                                has_effect=1;
                                                }
                        else{
                         find_lab(word);
                         if(tmp_lab==NULL){ errorlabelnotfound(word); return 1; }
                         cur_is_signed=is_it_signed(tmp_lab->type);
                         if(curtype==-1){curtype=tmp_lab->type;
                                         if(nextpoints)curtype-=10;
                                         }
                         else {
                                 if(nextpoints && tmp_lab->type>10)test_type(forcenxt,curtype,tmp_lab->type-10,1);
                                 else test_type(forcenxt,curtype,tmp_lab->type,1);
                                 }

                        dist=0; 
                        a=forcenxt; if(a==0)a=tmp_lab->type;
                        may_error=0;
                        if(nextpoints && a<11)error("Making a Pointer from an Integer",WARNING);
                        if(curtype!=-1 && curtype<11 && nextpoints==0 && a>10)may_error=1;//error("Making an Integer from a Pointer",WARNING);

                         //if(forcenxt)type=forcenxt;
                          forcenxt=0;

                           //store label pointer (so we can get name etc later
                           our_lab=tmp_lab;
                           use_cs=1;
                           if(our_lab->islocal){
                                if(our_lab->is_parameter){
                                        if(prg_out)sprintf(label_addresser,"#+%d",tmp_lab->local_real_pos+4);
                                        else if(out32)sprintf(label_addresser,"ebp+%d",tmp_lab->local_real_pos+4);
                                        else sprintf(label_addresser,"bp+%d",tmp_lab->local_real_pos+2);
                                                        }
                                else {
                                        if(prg_out)sprintf(label_addresser,"#-%d",tmp_lab->local_real_pos+tmp_lab->local_real_size);
                                        else if(out32)sprintf(label_addresser,"ebp-%d",tmp_lab->local_real_pos+tmp_lab->local_real_size);
                                        else sprintf(label_addresser,"bp-%d",tmp_lab->local_real_pos+tmp_lab->local_real_size);
                                        }
                                use_cs=0;
                                        }
                           else sprintf(label_addresser,"_%s",tmp_lab->name);
                           islabel=1;
                          if((lineptr[lptr]=='-' && lineptr[lptr+1]=='>') || lineptr[lptr]=='.'){
                                        error("SCC Doesn't support structures",ERROR);
                                        return 1; }

                     skipspaces();
                     la_size=getsize(our_lab->type);
                     if(nextpoints || (lineptr[lptr]=='[' && tmp_lab->type>10)){
                          mov_to_otherreg_direct(label_addresser,use_cs); use_cs=0;
                          if(prg_out)strcpy(label_addresser,"?");
                          else strcpy(label_addresser,OTHERREG);
                          islabel=0;
                          nextpoints=0;
                          la_size=our_lab->type;
                          if(la_size>10)la_size/=10;
                          la_size=getsize(la_size);
                                }
                     else if(may_error)error("Making an Integer from a Pointer",WARNING);

                     if(lineptr[lptr]=='['){//array access
                                           if(mathsym!=0) push_mathreg();
                                           if(islabel==0) push_otherreg();
                                            dist=0;
                                           got_arr=1;
                                           for(;;){
                                                  lptr++;
                                                              
                                                  if(getexpr(0,1)==1)return 1;
                                                  if(la_size>1)//for int arrays etc that >1 byte each
                                                                       mul_mathreg_size(la_size);
                                                                        
                                                  if(lineptr[lptr-1]!=']'){ error("Missing ]",ERROR);
                                                                                return 1; }
                                                  skipspaces();
                                                  dist++;
                                                  if(lineptr[lptr]!='[')break;
                                                  error("Only supports single dimension arrays",ERROR);
                                                  return 1;
                                                        }
                                           if(islabel==0){
                                                   pop_otherreg();
                                                   add_mathreg_to_otherreg();
                                                         }
                                           else{   if(our_lab->islocal){
                                                       if(our_lab->is_parameter)
                                                                mov_bp_otherreg_and_subit(our_lab->local_real_pos+2+(out32*2),0);
                                                        else mov_bp_otherreg_and_subit(our_lab->local_real_pos,1);

                                                       add_mathreg_to_otherreg();
                                                        }
                                                   else{
                                                           add_labeloffset_to_mathreg(label_addresser);
                                                           mov_mathreg_to_otherreg();
                                                        }
                                                   }
                                           strcpy(label_addresser,OTHERREG);
                                            islabel=0;
                                           if(mathsym!=0)pop_mathreg();
                                                }
                     if(nextincdec){
                                     if(nextincdec==1) incdec_it(1,islabel,our_lab->sz,label_addresser,use_cs);
                                     else incdec_it(1,islabel,our_lab->sz,label_addresser,use_cs);
                                     nextincdec=0; has_effect=1;
                                      }
                     skipspaces();
                     if(lineptr[lptr]=='+' && lineptr[lptr+1]=='+'){
                                        lptr+=2; has_effect=1; nextincdec=1;
                                        }
                     else if(lineptr[lptr]=='-' && lineptr[lptr+1]=='-'){
                                        lptr+=2; has_effect=1; nextincdec=2;
                                        }
                     if((lineptr[lptr]=='=' && lineptr[lptr+1]!='=') ||
                       (ismathsym(lineptr[lptr]) && lineptr[lptr+1]=='=')){
                                                if(lineptr[lptr]!='='){ mathsym=lineptr[lptr];
                                                                        lptr++;
                                                                        }
                                                else mathsym=0;
                                                if(brackcnt==0 && ineval) error("Possible incorrect use of =",WARNING);
                                                lptr++;
                                                if(nextisaddress || nxtisminus || nextisnot){
                                                                      error("Invalid operation",ERROR);
                                                                      return 1;
                                                                        }
                                                if(got_arr==0 && our_lab->amountneeded>0)error("Addressing an array without element",WARNING);
                                                if(islabel==0) push_otherreg();
                                                if(getexpr(0,1)==1)return 1;
                                                if(islabel==0) pop_otherreg();
                                                if(lineptr[lptr-1]==')' || lineptr[lptr-1]==',')lptr--;
                                                has_effect=1;
                                                asm_do_labeltomathreg(islabel,0,our_lab->sz ,mathsym,label_addresser,use_cs,cur_is_signed); use_cs=0;
                                                         }
                     else{//access label
                               if(got_arr==0 && our_lab->amountneeded>0)error("Addressing an array without element",WARNING);
                               if(nextisaddress==1){
                                                if(nextisnot){
                                                        if(our_lab->islocal && islabel){
                                                                                   if(our_lab->is_parameter)mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos+2+(out32*2),0);
                                                                                   else mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos,1);
                                                                                        }
                                                        else mov_labeloffset_to_bracketreg(islabel,label_addresser);
                                                        not_bracketreg();
                                                        if(nxtisminus) neg_bracketreg();
                                                        asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                               }
                                                else if(nxtisminus){
                                                            if(our_lab->islocal && islabel){
                                                                                   if(our_lab->is_parameter) mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos+2+(out32*2),0);
                                                                                   else mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos,1);
                                                                                   }
                                                            else mov_labeloffset_to_bracketreg(islabel,label_addresser);
                                                             neg_bracketreg();
                                                             asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                                   }
                                                else {
                                                        if(our_lab->islocal && islabel){
                                                                             if(our_lab->is_parameter)mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos+2+(out32*2),0);
                                                                             else mov_bp_to_bracketreg_and_sub(our_lab->local_real_pos,1);
                                                                             asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                                             islabel=0;
                                                                                        }
                                                        else asm_do_mathstomathreg(islabel,mathsym,label_addresser,cur_is_signed);//offset label
                                                        }
                                                nextisnot=0;
                                                nxtisminus=0;
                                                nextisaddress=0;
                                                        }
                                else {
                                     if(nextisnot){
                                                mov_direct_to_bracketreg(our_lab->sz,label_addresser,use_cs);use_cs=0;
                                                not_bracketreg();
                                                if(nxtisminus) neg_bracketreg();
                                                asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                nxtisminus=0;
                                                nextisnot=0;
                                                }
                                     else if(nxtisminus){
                                                mov_direct_to_bracketreg(our_lab->sz,label_addresser,use_cs);use_cs=0;
                                                neg_bracketreg();
                                                asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                nxtisminus=0;
                                                }
                                     else { asm_do_labeltomathreg(islabel,1,our_lab->sz ,mathsym,label_addresser,use_cs,cur_is_signed); use_cs=0; }
                                     }//else
                               if(nextincdec){
                                     if(nextincdec==1) incdec_it(1,islabel,our_lab->sz,label_addresser,use_cs);
                                     else incdec_it(1,islabel,our_lab->sz,label_addresser,use_cs);
                                     has_effect=1; use_cs=0;
                                        }
                                }
                          }
                  }
             else if(a==2){//number
                           if(get_nextnumber(1,0))return 1;
                           if(nextisnot){ pass_num=!pass_num; nextisnot=0; }
                           if(nxtisminus){ pass_num=-pass_num; nxtisminus=0;
                                                 }
                           asm_do_mathsnumtomathreg(mathsym,pass_num,cur_is_signed);
                                        }
             else {
                switch(lineptr[lptr]){                        
                        case '[':
                        case '(': lptr++; bp=lptr;
                                  forcenxt=checkforce(1);
                                  if(forcenxt==-1)return 1;
                                  if(forcenxt==0){
                                                lptr=bp;
                                                push_mathreg();
                                                if(brackstore(mathsym,lineptr[lptr-1])==1)return 1;
                                                brackcnt++;
                                                mathsym=0;
                                                }
                                  else cur_is_signed=is_it_signed(forcenxt);
                                  goto anotherloop;
                                        break;
                        case ')': 
                        case ',': error("Missing Parameter?",ERROR); return 1;
                        case ']': error("Syntax Error before ]",ERROR); return 1;
                                  break;
                        case '{': error("Unexpected {",ERROR); return 1;
                        case '}': error("Unexpected }",ERROR); return 1;
                        case '\"':
                                if(curtype==-1){
                                             if(forcenxt>0)curtype=forcenxt;
                                             else curtype=11;//assume char *
                                                }
                                else test_type(forcenxt,curtype,11,1);
                                sprintf(tmp_str,"String%d",storestring(1));
                                if(mathsym){ mov_labeloffset_to_bracketreg(1,tmp_str);
                                             asm_do_mathstomathreg(0,mathsym,BRACKETREG,cur_is_signed);
                                                }
                                else mov_labeloffset_to_mathreg(tmp_str);
                                lptr--;//it'll skip this later
                                 break;
                        case '\'':lptr++;
                                  asm_do_mathsnumtomathreg(mathsym,giverealvalueof(),cur_is_signed);
                                  lptr++;//past the character
                                  if(lineptr[lptr]!='\''){ error("Missing \'",ERROR);
                                                                return 1; }
                                  break;
                        default: syntaxerror(1,lineptr[lptr]); return 1;
                            }
                lptr++;
                        }//else
             //part 2
        repeatpart2:
             first_thing=0;
             forcenxt=0; nextpoints=0; nextisaddress=0;
             nextincdec=0; nxtisminus=0; nextisnot=0;
             mathsym=0; got_arr=0;
             skipspaces();
             a=ischarnum(lineptr[lptr]);
             if(a!=0){//char/number
                      syntaxerror(2,lineptr[lptr]);
                      return 1;       }
             else {
                switch(lineptr[lptr]){
                        case '%':
                        case '^':
                        case '/':
                        case '*':
                        case '+': 
                        case '-': mathsym=lineptr[lptr]; break;
                        case '<': if(lineptr[lptr+1]=='<'){
                                               lptr++;
                                               mathsym='<';
                                                        }
                                  else{//must be eval
                                        do_eval=1; do_evalwhen=brackcnt;
                                        do_evaltype=4; push_mathreg(); mathsym=0;
                                        if(lineptr[lptr+1]=='='){
                                                        lptr++;
                                                        do_evaltype=5;
                                                        if(brackcnt==0 && ineval==0)error("Possible incorrect use of <=",WARNING);
                                                        }
                                        else if(brackcnt==0 && ineval==0)error("Possible incorrect use of <",WARNING);
                                        }
                                  break;
                        case '>': if(lineptr[lptr+1]=='>'){
                                               lptr++;
                                               mathsym='>';
                                                        }
                                  else{//must be eval
                                        do_eval=1; do_evalwhen=brackcnt;
                                        do_evaltype=2;
                                        push_mathreg();
                                        mathsym=0;
                                        if(lineptr[lptr+1]=='='){
                                                        lptr++;
                                                        do_evaltype=3;
                                                        if(brackcnt==0 && ineval==0)error("Possible incorrect use of >=",WARNING);
                                                        }
                                        else if(brackcnt==0 && ineval==0)error("Possible incorrect use of >",WARNING);
                                        }
                                  break;
                        case '!': if(lineptr[lptr+1]!='=') mathsym='!';
                                  else{//eval
                                       lptr++;
                                        if(brackcnt==0 && ineval==0)error("Possible incorrect use of !=",WARNING);
                                        do_eval=1; do_evalwhen=brackcnt; do_evaltype=1;
                                        push_mathreg(); mathsym=0;
                                                }
                                  break;
                        case '&': if(lineptr[lptr+1]=='&'){
                                        if(ineval==0){
                                                   error("Incorrect use of &&",ERROR);
                                                   return 1; }
                                         retme='&';
                                                }
                                  else mathsym='&';
                                  break;
                      case '|': if(lineptr[lptr+1]=='|'){
                                        if(ineval==0){
                                                   error("Incorrect use of ||",ERROR);
                                                   return 1; }
                                         retme='|';
                                                }
                                  else mathsym='|';
                                  break;
                        case '=': if(lineptr[lptr+1]!='='){
                                          syntaxerror(3,lineptr[lptr]); return 2;
                                          }
                                lptr++;
                                if(brackcnt==0 && ineval==0)error("Possible incorrect use of ==",WARNING);
                                do_eval=1; do_evalwhen=brackcnt; do_evaltype=0;
                                push_mathreg(); mathsym=0;
                                break;
                        case ']':
                        case ')':
                                  if(brackcnt==0){ //-if we are parameter type
                                                if(parmtype)mustend=1;
                                                else { error("Unexpected )",ERROR);
                                                        return 1;
                                                            }
                                                 }
                                  else {
                                       if(do_eval==1 && do_evalwhen==brackcnt){
                                                         pop_bracketreg();
                                                         do_the_eval(do_evaltype,BRACKETREG,MATHREG);
                                                         do_eval=0;
                                                             }
                                             if(top_brac){
                                                        if((top_brac->type=='(' && lineptr[lptr]!=')')
                                                          ||(top_brac->type=='[' && lineptr[lptr]!=']')){
                                                                                        error("Wrong type of close bracket",ERROR);
                                                                                        return 1;
                                                                                        }
                                                        mov_mathreg_to_bracketreg();
                                                        pop_mathreg();
                                                        asm_do_mathstomathreg(0,top_brac->sym,BRACKETREG,cur_is_signed);
                                                        }
                                               else pop_mathreg();
                                        pop_bracstore();
                                        brackcnt--;
                                        lptr++;
                                        goto repeatpart2;
                                                }
                                  break;
                        case ',': if(parmtype==1)mustend=1;
                                  else if(ineval==0)mathsym=0;
                                  else { error("Unexpected ,",ERROR);
                                         return 1; }
                                 break;
                        case '[': error("Unexpected [",ERROR); return 1;
                        case '{': error("Unexpected {",ERROR); return 1;
                        case '}': error("Unexpected }",ERROR); return 1;
                        case 0: mustend=1; break;
                        case '(': 
                        default: syntaxerror(4,lineptr[lptr]); return 1;
                            }//switch
                lptr++;
                        }//else
                if(retme || mustend)break;
                    }
      if(brackcnt>0){  error("Missing )",ERROR);  return 1;  }
      if(do_eval==1){
                 pop_bracketreg();
                 do_the_eval(do_evaltype,BRACKETREG,MATHREG);
                 do_eval=0;
                     }
 exprtype=DEFAULT_TYPE; if(curtype!=-1)exprtype=curtype;
 a=lineptr[lptr-1];
return retme;}

