/*
        SCC - The Snakessoft C(ish) Compiler

        By Snakessoft/RodneyMcConnell

         Started  4th August 2001
         finished 14th August 2001
           (actually took only 6 daze, even doe interest died a little)
           (NOTE: that was just a basic working version)


    [Not my first attempt at a C compiler, but my last!!!]
 [Not the fastest code generation, could have made me a optimizing tree,
                  but could not have been arsed]

Decided, interperting C source, is a waste of my time....
so removed the option ;) Now this is really quite shite


     -Decided to VERY minimise it to get it going 'strongly'
     -AND it'll now be easily interpreted!!!

NOTEs:
 [Procedures return in bracketreg (ecx)]
 [pos: are gobal, so you can jump from procedure to another procedure!!!]
 [directives must be the only thing in a line, and defines will not be
  unpacked in directive lines]




       ... works like
                A:Store linepos
                B: skip to ...
                C: do it, then push count
                d:store linepos
                E:use linepos 1 till ...
                f:set pos to linepos 2



Future?:
      + /= etc fix (note, += etc work)
      +programs can use command line parameters
      +allow asm as a condition eg if(a==1)asm nop
        or at least a better error message
      +allow ... in parameters
      +set up the command line paramters argv,argc (may already work!!!)
      +define a(x) x+x+1 etc...
      +initial values = { data,data.. } (read lines...)
                (this will be really handy for arrays)
      +Multi pointers
      +structs,typedefs
      +brackets in the evals eg if a==1 || (b==2 && c==2))
      +enum support'd? Need to get the syntax, think its enum {a,b,c} ????
      +'const'
      +dublicate case error checking

      +possible update of sasm to make it easier to include in other procs
       and include it here-BUT: don't really need it...

      +No asm, pcode out (interpreter time...)
*/

#define SCC_ver_    "1.0Beta"


#define MAX_PARM   30
//3=int 4 =long (32bit option fix up)
#define DEFAULT_TYPE 3
//32bit fixup will make these ecx-should we? (If type long????)
#define MATHREG "eax"
#define midMATHREG "ax"
#define smallMATHREG "al"
#define OTHERREG "ebx"
#define midOTHERREG "bx"
#define smallOTHERREG "bl"
#define BRACKETREG "ecx"
#define midBRACKETREG "cx"
#define smallBRACKETREG "cl"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

char *autodefines[]={"_SCC_","1",
                     NULL, NULL };

char *keywords[]={ "goto","asm","for","while",
                   "return","if","else","switch","case","default",
                   "unsigned","int","short","long","char","void",
                   "sizeof","extern","break",
                   NULL};
char *directives[]={ "include","define","ifdef","ifndef","undef","endif",
                     "else",
                   NULL};
char *types[]={  "unsigned","char","short","int","long","void",
                 "extern",
                  NULL};
char re_dir=0;
char *re_name;
FILE *re_hnd=NULL;
char pr_str[255];
void print_f(char *str){
 if(re_dir==0)printf("%s",str);
 else if(re_hnd)fprintf(re_hnd,"%s",str);
return; }


char in_proc,in_main,had_main;
int topgobalstr,toplocalstr;

char out32=0, mem_model=2, out_type=0, asm_out=0;

char las_was_if,in_switch,in_case;
char out_of_mem=0;
int malfreecntr=0;
int cur_if_num=0;

int lineno=1;
int total_linecntr=0;
char *filename=NULL;

//char *local_str=NULL, *gobal_str=NULL;
char *gobal_str=NULL;

#define theMAXPATH  80
char inc_dir[theMAXPATH+14];

char debug_type=0,in_ifdef,in_multi_asm;
char prg_out=0;

char asm_la_str[257];

FILE *hnd=NULL;

int getexpr(char ineval, char parmtype);
int do_keyword(char *w);
int do_directive();
int find_define(char *label);
void free_def();


typedef struct inc_stack{
                char *name;
                int lineno;
                FILE *hnd;
                struct inc_stack *prev;
                }inc_stack;
inc_stack *top_include=NULL;
char in_include;

#define ERROR   1
#define WARNING 0
int err_cnt,warn_cnt,total_err=0, total_warn=0;
void error(char *str,int wh){
 if(wh==ERROR) { err_cnt++; total_err++; sprintf(pr_str,"ERROR:"); print_f(pr_str); }
 else { warn_cnt++; total_warn++; sprintf(pr_str,"WARNING:"); print_f(pr_str); }
 sprintf(pr_str,"%s (",str); print_f(pr_str);
 if(in_include){ sprintf(pr_str, "included:"); print_f(pr_str); }
 sprintf(pr_str,"%s:Line %d)\n",filename,lineno);
 print_f(pr_str);
return; }

FILE *outfile=NULL;

void pop_include(){
 inc_stack *t;
 if(top_include==NULL)return;
 if(outfile)fprintf(outfile,";\n; endof include file %s\n;\n",filename);

 if(filename){ free(filename); malfreecntr--; }
 filename=top_include->name;
 if(hnd)fclose(hnd);
 hnd=top_include->hnd;
 lineno=top_include->lineno;
 t=top_include; top_include=top_include->prev;
 free(t); malfreecntr--;

 if(top_include==NULL)in_include=0;
return; }

void do_include(char *fname,int tp){
 inc_stack *t;
 char str[100];
 t=(inc_stack *)malloc(sizeof(inc_stack));
 if(t==NULL){ out_of_mem=1; return; }
 malfreecntr++;
 t->prev=top_include; top_include=t;
 t->hnd=NULL; t->lineno=lineno;
 t->name=filename;
 if(tp==2){
         filename=(char *)malloc(strlen(fname)+(strlen(inc_dir))+3);
         if(filename!=NULL){ malfreecntr++;
                             strcpy(filename,inc_dir);
                             strcat(filename,"\\");
                             strcat(filename,fname); }
         else out_of_mem=1;
                }
 else{
         filename=(char *)malloc(strlen(fname)+1);
         if(filename!=NULL){ malfreecntr++; strcpy(filename,fname); }
         else out_of_mem=1;
         }
 t->hnd=hnd;

 if(outfile)fprintf(outfile,";\n; include file %s\n;\n",filename);
 hnd=fopen(filename,"r");
 if(hnd==NULL){ 
                sprintf(str,"Cannot open include file \"%s\"",filename);
                pop_include();
                error(str,ERROR);
                return;    }
 lineno=0;
 in_include=1;
return; }

void free_includes(){
inc_stack *t;
 while(top_include){
                t=top_include->prev;
                if(top_include->name){ free(top_include->name);
                                       malfreecntr--; }
                if(top_include->hnd)fclose(hnd);
                free(top_include);
                malfreecntr--;
                top_include=t;
                }
 in_include=0;
return; }

typedef struct def_stack{
                char *name;
                char *line;
                char removedit;
                struct def_stack *prev;
                }def_stack;
def_stack *cur_def=NULL, *top_def=NULL;


typedef struct if_tree{
                char type;
                int m_num;
                int s_num;
                char linet;
                char in_case;//for the switch
                struct if_tree *prev;
                }if_tree;
if_tree *top_if_tree=NULL, *top_if_line_tree=NULL;

void pop_if_tree();
int pop_if_line_tree();
if_tree *free_if_tree(if_tree *top);

char *outfilename=NULL;


char donttab=0;
int go_assemble(){
  char k=asm_la_str[0];

  if(outfile){
                if(donttab==0 && k!='_' && k!=';' && asm_la_str[strlen(asm_la_str)-1]!=':')fprintf(outfile,"      ");
                fprintf(outfile,"%s\n",asm_la_str);
                }
  else { sprintf(pr_str,"%s\n",asm_la_str);
         print_f(pr_str);
        }

//todo--ONLY IF WE EVER INLINK SASM
return 0; }

void mul_mathreg_size(char size){
  if(prg_out){
        sprintf(asm_la_str,"M%d",size);
        go_assemble();
        return; 
        }
   switch(size){
        case 1: sprintf(asm_la_str,"Mov %s,%d",BRACKETREG,1); break;
        case 2: sprintf(asm_la_str,"Mov %s,%d",BRACKETREG,2); break;
        default: sprintf(asm_la_str,"Mov %s,%d",BRACKETREG,4);
                break; }
   go_assemble();
   sprintf(asm_la_str,"Mul %s",BRACKETREG);
   go_assemble();
return; }
void mov_mathreg_numberand_push_ax(int num){
        if(prg_out)sprintf(asm_la_str,"O1 %d",num);
        else{
                sprintf(asm_la_str,"Mov %s,%d",MATHREG,num);
                go_assemble();
                sprintf(asm_la_str,"Push %s",midMATHREG);
                }
        go_assemble();                
return; }
void asm_ret(){
        if(prg_out) sprintf(asm_la_str,"R");
        else sprintf(asm_la_str,"Ret");
        go_assemble();
        return; }
void cmp_mathreg_0(){
        if(prg_out)sprintf(asm_la_str,"CM 0");
        else sprintf(asm_la_str,"Cmp %s,0",MATHREG);
        go_assemble();
        return; }
void mov_bp_to_bracketreg_and_sub(int pos,char sub){
        if(prg_out){
                sprintf(asm_la_str,"O2");
                go_assemble();
                if(pos!=0){
                        if(sub)sprintf(asm_la_str,"O3 %d",pos);
                        else sprintf(asm_la_str,"O4 %d",pos);
                        go_assemble();
                                }
                return; }

        if(out32)sprintf(asm_la_str,"Mov %s,ebp",BRACKETREG); 
        else sprintf(asm_la_str,"Mov %s,bp",BRACKETREG);
        go_assemble();
        if(pos!=0){ if(sub)sprintf(asm_la_str,"Sub %s,%d",BRACKETREG,pos);
                    else sprintf(asm_la_str,"Add %s,%d",BRACKETREG,pos);
                    go_assemble(); }
        return; }
void mov_bp_otherreg_and_subit(int pos,char sub){
        if(prg_out){
                sprintf(asm_la_str,"O5");
                go_assemble();
                if(pos!=0){
                         if(sub)sprintf(asm_la_str,"O6 %d",pos);
                         else sprintf(asm_la_str,"O7 %d",pos);
                         go_assemble();
                                }
                return; }
        if(out32)sprintf(asm_la_str,"Mov %s,ebp",OTHERREG);
        else sprintf(asm_la_str,"Mov %s,bp",OTHERREG);
        go_assemble();
        if(pos!=0){ if(sub)sprintf(asm_la_str,"Sub %s,%d",OTHERREG,pos);
                    else sprintf(asm_la_str,"Add %s,%d",OTHERREG,pos);
                    go_assemble(); }
        return; }
void subadjust_sp(int num){
        //if(out32)num*=4; else num*=2;
        if(num!=0){ if(prg_out)sprintf(asm_la_str,"O8 %d",num);
                    else sprintf(asm_la_str,"Sub sp,%d",num);
                    go_assemble(); }
        return; }
void adjust_sp(int num){
        //if(out32)num*=4; else num*=2;
        if(num!=0){ if(prg_out)sprintf(asm_la_str,"O9 %d",num);
                    else sprintf(asm_la_str,"Add sp,%d",num);
                    go_assemble(); }
        return; }
void mov_sp_bp(){
        if(prg_out)sprintf(asm_la_str,"Oa");
        else if(out32)sprintf(asm_la_str,"Mov ebp,esp");
        else sprintf(asm_la_str,"Mov bp,sp");
        go_assemble();
        return; }
void push_bp_sp(){
        if(prg_out){
                sprintf(asm_la_str,"Ob");
                go_assemble();
                }
        else if(out32){
                sprintf(asm_la_str,"Push ebp"); go_assemble();
                sprintf(asm_la_str,"Push esp"); go_assemble();
                  }
        else{
                sprintf(asm_la_str,"Push bp"); go_assemble();
                sprintf(asm_la_str,"Push sp"); go_assemble();
                        }
         return; }
void pop_sp_bp(){
        if(prg_out){
                sprintf(asm_la_str,"Oc");
                go_assemble();
                        }
        else if(out32){
                sprintf(asm_la_str,"Pop esp"); go_assemble();
                sprintf(asm_la_str,"Pop ebp"); go_assemble();
                }
        else{
                sprintf(asm_la_str,"Pop sp"); go_assemble();
                sprintf(asm_la_str,"Pop bp"); go_assemble();
                }
         return; }
void call_proc(char *str){
        if(prg_out)sprintf(asm_la_str,"a @_%s",str);
        else sprintf(asm_la_str,"Call @_%s",str);
        go_assemble();
        return; }
void incdec_it(char wh,char islabel, char sz, char *str,char use_cs){
        char tmpstr[10];
        if(prg_out){
                if(islabel){
                        if(wh)sprintf(asm_la_str,"I+%d %s",sz,str);
                        else sprintf(asm_la_str,"I-%d %s",sz,str);
                        }
                else{
                        if(wh)sprintf(asm_la_str,"i+%d %s",sz,str);
                        else sprintf(asm_la_str,"i-%d %s",sz,str);
                        }
                return;
                }
        if(islabel){
                switch(sz){
                        case 1: sprintf(tmpstr," byte "); break;
                        case 2: sprintf(tmpstr," word "); break;
                        default: sprintf(tmpstr," dword ");
                        }
                }
        else sprintf(tmpstr," ");
                if(wh)sprintf(asm_la_str,"Inc%s[%s]",tmpstr,str);
                else sprintf(asm_la_str,"Dec%s[%s]",tmpstr,str);
        go_assemble();
        return; }
void not_bracketreg(){
        if(prg_out)sprintf(asm_la_str,"Od");
        else sprintf(asm_la_str,"Not %s",BRACKETREG);
        go_assemble();
        return; }
void neg_bracketreg(){
        if(prg_out)sprintf(asm_la_str,"Oe");
        else sprintf(asm_la_str,"Neg %s",BRACKETREG);
        go_assemble();
        return; }
void xor_bracketreg(){
        if(prg_out)sprintf(asm_la_str,"XB");
        else sprintf(asm_la_str,"Xor %s,%s",BRACKETREG,BRACKETREG);
        go_assemble();
        return; }
void xor_mathreg(){
        if(prg_out)sprintf(asm_la_str,"XM");
        else sprintf(asm_la_str,"Xor %s,%s",MATHREG,MATHREG);
        go_assemble();
        return; }
void xor_otherreg(){
        if(prg_out)sprintf(asm_la_str,"XO");
        else sprintf(asm_la_str,"Xor %s,%s",OTHERREG,OTHERREG);
        go_assemble();
        return; }
void mov_direct_to_bracketreg(char sz,char *str, char use_cs){
        if(sz!=4) xor_bracketreg();
        switch(sz){
                case 1:if(prg_out)sprintf(asm_la_str,"Of1 %s",str);
                       else sprintf(asm_la_str,"Mov %s,[%s]",smallBRACKETREG,str);
                       break;
                case 2: if(prg_out)sprintf(asm_la_str,"Of2 %s",str);
                        else sprintf(asm_la_str,"Mov %s,[%s]",midBRACKETREG,str);
                        break;
                default:if(prg_out)sprintf(asm_la_str,"Of3 %s",str);
                        else sprintf(asm_la_str,"Mov %s,[%s]",BRACKETREG,str);
                break;
                      }
        go_assemble();
        return; }
void pop_otherreg(){
        if(prg_out)sprintf(asm_la_str,"OgO");
        else sprintf(asm_la_str,"Pop %s",OTHERREG);
        go_assemble();
        return; }
void pop_bracketreg(){
        if(prg_out)sprintf(asm_la_str,"OgB");
        else sprintf(asm_la_str,"Pop %s",BRACKETREG);
        go_assemble();
        return; }
void pop_mathreg(){
        if(prg_out)sprintf(asm_la_str,"OgM");
        else sprintf(asm_la_str,"Pop %s",MATHREG);
        go_assemble();
        return; }
void push_mathreg(){
        if(prg_out)sprintf(asm_la_str,"Oh3");
        else sprintf(asm_la_str,"Push %s",MATHREG);
        go_assemble();
        return; }
void push_parametermathreg(int size){
        switch(size){
                 case 1:// sprintf(asm_la_str,"Push %s",smallMATHREG); break;
                 case 2:  if(prg_out)sprintf(asm_la_str,"Oh2"); 
                          else sprintf(asm_la_str,"Push %s",midMATHREG);
                          break;
                 default: if(prg_out)sprintf(asm_la_str,"Oh3");
                          else sprintf(asm_la_str,"Push %s",MATHREG);
                        }
        go_assemble(); 
        return; }
void push_otherreg(){
        if(prg_out)sprintf(asm_la_str,"Oi"); 
        else sprintf(asm_la_str,"Push %s",OTHERREG);
         go_assemble();
        return; }
void mov_mathreg_to_bracketreg(){
        if(prg_out)sprintf(asm_la_str,"Oj"); 
        else sprintf(asm_la_str,"Mov %s,%s",BRACKETREG,MATHREG);
        go_assemble();
        return; }
void set_otherreg(int num){
        if(prg_out)sprintf(asm_la_str,"Ok %d",num); 
        else sprintf(asm_la_str,"Mov %s,%d",OTHERREG,num);
        go_assemble();
        return; }
void mov_mathreg_to_otherreg(){
        if(prg_out)sprintf(asm_la_str,"Ol"); 
        else sprintf(asm_la_str,"Mov %s,%s",OTHERREG,MATHREG);
        go_assemble();
        return; }
void mov_to_otherreg_direct(char *wot,char use_cs){
 if(out32==0) xor_otherreg();
        if(prg_out)sprintf(asm_la_str,"Om %s",wot);
        else if(out32)sprintf(asm_la_str,"Mov %s,[%s]",OTHERREG,wot);
        else sprintf(asm_la_str,"Mov %s,[%s]",midOTHERREG,wot);
 go_assemble();
return; }
void add_mathreg_to_otherreg(){
        if(prg_out)sprintf(asm_la_str,"On");
        else sprintf(asm_la_str,"Add %s,%s",OTHERREG,MATHREG);
        go_assemble();
        return; }
void add_labeloffset_to_mathreg(char *label){
        if(prg_out)sprintf(asm_la_str,"Op %s",label);
        else if(out32)sprintf(asm_la_str,"Add %s,Offset %s",MATHREG,label);
        else sprintf(asm_la_str,"Add %s,Offset %s",midMATHREG,label);
        go_assemble();
        return; }
void mov_labeloffset_to_mathreg(char *label){
        if(out32==0) xor_mathreg();
        if(prg_out)sprintf(asm_la_str,"Oq %s",label);
        else if(out32)sprintf(asm_la_str,"Mov %s,Offset %s",MATHREG,label);
        else sprintf(asm_la_str,"Mov %s,Offset %s",midMATHREG,label);
        go_assemble();
        return; }
void mov_labeloffset_to_bracketreg(char islabel,char *label){
        char tmpstr[10];
        if(islabel)sprintf(tmpstr,",Offset");
        else sprintf(tmpstr,",");
        if(out32==0) xor_bracketreg();
        if(prg_out)sprintf(asm_la_str,"Or %s",label);
        else if(out32)sprintf(asm_la_str,"Mov %s%s %s",BRACKETREG,tmpstr,label);
        else sprintf(asm_la_str,"Mov %s%s %s",midBRACKETREG,tmpstr,label);
        go_assemble();
        return; }


char word[257],line[257], *lineptr;
int lptr;

int ischarnum(char k);
void get_nextword();

void syntaxerror(int num, char k){
  char str[100];
  if(ischarnum(k)==1){lptr--; get_nextword();
                       sprintf(str,"Syntax Error%d before \"%s\"",num,word);
                        }
  else sprintf(str,"Syntax Error%d before \'%c\'",num,k);
  error(str,ERROR);
return; }

int legal_labelname(char *name){
 int a;
 for(a=0; ;a++){ if(keywords[a]==NULL)break;
                 if(!strcmp(keywords[a],name))return 1;
                        }
 for(a=0; ;a++){ if(directives[a]==NULL)break;
                 if(!strcmp(directives[a],name))return 1;
                        }
return 0; }

int ismathsym(char k){
   switch(k){ //+= etc
       case '+': case '-': case '*':  case '/':
       case '|': case '&': return k;
                }
return 0; }


void asm_do_mathstomathreg(char islabel,char mathsym,char *wot,char is_signed){
 char tmpstr[10];
 char tmpstr2[10];
 char *lareg,*oreg;


 if(prg_out){
        sprintf(asm_la_str,"Ou %c %s",mathsym,wot);
        go_assemble();
        return;
        }

 lareg=MATHREG; oreg=BRACKETREG;
 if(islabel){ sprintf(tmpstr,"Offset ");
              sprintf(tmpstr2,"dword ");
               if(out32==0) { lareg=midMATHREG; oreg=midBRACKETREG;
                              sprintf(tmpstr2,"word ");
                              }
               }
 else { sprintf(tmpstr," "); sprintf(tmpstr2," "); }
  switch(mathsym){
        case '%':
                 if(islabel==0){sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                                if(is_signed)sprintf(asm_la_str,"IDiv %s%s%s",tmpstr2,tmpstr,wot);
                                else sprintf(asm_la_str,"Div %s%s%s",tmpstr2,tmpstr,wot);
                                go_assemble();
                                }
                 else{
                          sprintf(asm_la_str,"Mov %s,Offset %s",oreg,wot);
                          go_assemble();
                          sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                          if(is_signed)sprintf(asm_la_str,"IDiv %s",oreg);
                          else sprintf(asm_la_str,"Div %s",oreg);
                          go_assemble();
                                }
                if(toupper(lareg[0])=='E')sprintf(asm_la_str,"Mov %s,edx",lareg);
                else if(toupper(lareg[1])=='L')sprintf(asm_la_str,"Mov %s,dl",lareg);
                else sprintf(asm_la_str,"Mov %s,dx",lareg);
                go_assemble();
                 break;
        case '+': sprintf(asm_la_str,"Add %s,%s%s",lareg,tmpstr,wot); go_assemble(); break;
        case '-': sprintf(asm_la_str,"Sub %s,%s%s",lareg,tmpstr,wot); go_assemble(); break;
        case '*': if(islabel==0){
                          if(is_signed)sprintf(asm_la_str,"IMul %s%s%s",tmpstr2,tmpstr,wot);
                          else sprintf(asm_la_str,"Mul %s%s%s",tmpstr2,tmpstr,wot);
                          go_assemble();
                          }
                   else{
                          sprintf(asm_la_str,"Mov %s,Offset %s",oreg,wot);
                          go_assemble();
                          if(is_signed)sprintf(asm_la_str,"IMul %s",oreg);
                          else sprintf(asm_la_str,"Mul %s",oreg);
                          go_assemble();
                                }
                   break;
        case '/': if(islabel==0){
                                sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                                if(is_signed)sprintf(asm_la_str,"Div %s%s%s",tmpstr2,tmpstr,wot);
                                 sprintf(asm_la_str,"IDiv %s%s%s",tmpstr2,tmpstr,wot);
                                go_assemble();
                                }
                   else{
                          sprintf(asm_la_str,"Mov %s,Offset %s",oreg,wot);
                          go_assemble();
                          sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                          if(is_signed)sprintf(asm_la_str,"IDiv %s",oreg);
                          else sprintf(asm_la_str,"Div %s",oreg);
                          go_assemble();
                                }
                   break;
        case '|': sprintf(asm_la_str,"Or %s,%s%s",lareg,tmpstr,wot); go_assemble(); break;
        case '&': sprintf(asm_la_str,"And %s,%s%s",lareg,tmpstr,wot); go_assemble(); break;
        default:  sprintf(asm_la_str,"Mov %s,%s%s",lareg,tmpstr,wot); go_assemble();
                }
return; }

void asm_do_mathsnumtomathreg(char mathsym,long num,char is_signed){
  char str[100];
  if(prg_out){
        sprintf(asm_la_str,"Os %d %ld",mathsym,num); go_assemble();
        return;
        }
  if(mathsym=='/' || mathsym=='*' || mathsym=='%'){
        sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
        sprintf(asm_la_str,"Mov %s,%ld",BRACKETREG,num); go_assemble();
        if(mathsym=='*'){
                 if(is_signed) sprintf(asm_la_str,"IMul %s",BRACKETREG);
                 else sprintf(asm_la_str,"Mul %s",BRACKETREG);
                 go_assemble();
                        }
        else{
                 if(is_signed) sprintf(asm_la_str,"IDiv %s",BRACKETREG);
                 else sprintf(asm_la_str,"Div %s",BRACKETREG);
                 go_assemble();
                 if(mathsym=='%'){
                            sprintf(asm_la_str,"Mov %s,edx",MATHREG);
                            go_assemble();
                                }
                }
         }
  else{
        sprintf(str,"%ld",num);
        asm_do_mathstomathreg(0,mathsym,str,is_signed);
        }
return; }


void asm_do_labeltomathreg(char islabel, char regfirst,char sz,char mathsym,char *wot, char use_cs, char is_signed){
 char tmpstr[100];
 char tmpstr2[100];
 char tmpstr_reg[100];
 char *t1,*t2;
 char nedtoxor=0;

 if(prg_out){
        sprintf(asm_la_str,"Ot %d %d %s",sz,mathsym,wot);
        go_assemble();
        return;
        }
 sprintf(tmpstr,"[%s]",wot);
 if(islabel==0)sprintf(tmpstr2," ");
 else switch(sz){
                case 1: sprintf(tmpstr2," byte"); break;
                case 2: sprintf(tmpstr2," word"); break;
                default: sprintf(tmpstr2," dword");
                    }

 switch(sz){
        case 1: sprintf(tmpstr_reg,"%s",smallMATHREG); nedtoxor=1; break;
        case 2: sprintf(tmpstr_reg,"%s",midMATHREG); nedtoxor=1;  break;
        default: sprintf(tmpstr_reg,"%s",MATHREG);
                }
 if(regfirst==0) { t1=tmpstr; t2=tmpstr_reg; nedtoxor=0;}
 else { t2=tmpstr; t1=tmpstr_reg;  }

 switch(mathsym){
        case '%': sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                  if(is_signed)sprintf(asm_la_str,"IDiv%s %s",tmpstr2,t2);
                  else sprintf(asm_la_str,"Div%s %s",tmpstr2,t2);
                  go_assemble();
                  switch(sz){
                        case 1: sprintf(asm_la_str,"Mov %s,dl",t1); break;
                        case 2: sprintf(asm_la_str,"Mov %s,dx",t1); break;
                        default: sprintf(asm_la_str,"Mov %s,edx",t1);
                        }
                  go_assemble();
                  break;
        case '+': sprintf(asm_la_str,"Add %s,%s",t1,t2); go_assemble(); break;
        case '-': sprintf(asm_la_str,"Sub %s,%s",t1,t2); go_assemble(); break;
        case '*': if(is_signed)sprintf(asm_la_str,"IMul%s %s",tmpstr2,t2);
                  else sprintf(asm_la_str,"Mul%s %s",tmpstr2,t2);
                  go_assemble();  break;
        case '/': sprintf(asm_la_str,"Xor edx,edx"); go_assemble();
                  if(is_signed)sprintf(asm_la_str,"IDiv%s %s",tmpstr2,t2);
                  else sprintf(asm_la_str,"Div%s %s",tmpstr2,t2);
                  go_assemble(); break;
        case '|': sprintf(asm_la_str,"Or %s,%s",t1,t2); go_assemble(); break;
        case '&': sprintf(asm_la_str,"And %s,%s",t1,t2); go_assemble(); break;
        default: if(nedtoxor)xor_mathreg();
                 sprintf(asm_la_str,"Mov %s,%s",t1,t2); go_assemble();
                }
return; }


typedef struct goto_pos{
                char *name;
                int lineused;
                int defline;
                char found;
                struct goto_pos *prev;
                }goto_pos;
goto_pos *top_goto_pos=NULL;

void free_goto_pos(int chk){
 goto_pos *t;
 char str[100];
 while(top_goto_pos){
                t=top_goto_pos->prev;
                if(top_goto_pos->found==0 && chk){
                                sprintf(str,"Location \"%s\" not found. First used on line %d",top_goto_pos->name,top_goto_pos->lineused);
                                error(str,ERROR);
                                                }
                if(top_goto_pos->name){ free(top_goto_pos); malfreecntr--; }
                free(top_goto_pos); malfreecntr--;
                top_goto_pos=t;
                }
return; }

void store_goto_pos(char *name, char fnd){
 goto_pos *t;
 t=(goto_pos *)malloc(sizeof(goto_pos));
 if(t==NULL){ out_of_mem=1; return; }
 malfreecntr++;
 t->prev=top_goto_pos; top_goto_pos=t;
 t->lineused=lineno;
 t->defline=lineno;
 t->found=fnd;
 t->name=(char *)malloc(strlen(name)+1);
 if(t->name==NULL){ out_of_mem=1; return; }
 malfreecntr++;
 strcpy(t->name,name);
return; }

int fadd_gotopos(char *name,char fnd){
 goto_pos *t;
 char str[100];
 t=top_goto_pos;
 while(t){
         if(!strcmp(name,t->name)){
                                  if(t->found && fnd){
                                              sprintf(str,"\"%s\" already defined in line %d",t->name,t->defline);
                                              error(str,ERROR);
                                                }
                                  else if(fnd==1){ t->found=1; t->defline=lineno; }
                                  return t->found;
                                  }
         t=t->prev;
            }
 store_goto_pos(name,fnd);
return 0;}

typedef struct brac_store{
                        char sym;
                        char type;
                        struct brac_store *prev;
                        }brac_store;
brac_store *top_brac=NULL;

void pop_bracstore(){
 brac_store *tp;
  tp=top_brac->prev;
  free(top_brac); malfreecntr--;
  top_brac=tp;
return; }

void free_bracstore(){
 brac_store *tp;
 while(top_brac){
        tp=top_brac->prev;
        free(top_brac); malfreecntr--;
        top_brac=tp;
        }
return; }

int brackstore(char mathsym,char type){
 brac_store *tp;

 tp=(brac_store *)malloc(sizeof(brac_store));
 if(tp==NULL){ out_of_mem=1; return 1; }
 malfreecntr++;
 tp->prev=top_brac; top_brac=tp;
 tp->sym=mathsym;
 tp->type=type;
return 0; }

void skipspaces(){
  for(;;){ if(lineptr[lptr]!=32 && lineptr[lptr]!=9)break;  lptr++; }
return; }

int ischarnum(char k){
 k=toupper(k);
 if(k>='A' && k<='Z')return 1; if(k=='_')return 1;
 if(k>='0' && k<='9')return 2;
return 0; }

void get_nextword(){
 char k;
 int a=0;
  skipspaces();
  for(;;){   k=line[lptr];  if(ischarnum(k)==0)break;
             word[a++]=k; lptr++;     }
  word[a]=0;
return; }

long dothemath(short mathsym,long num1,long num2){
 switch(mathsym){
                case 0:num1=num2; break;
                case '+':num1+=num2; break;
                case '-':num1-=num2; break;
                case '*':num1*=num2; break;
                case '/':num1/=num2; break;
                case '|':num1|=num2; break;
                case '&':num1&=num2; break;
                //case '^':num1^=num2; break;
                //case '<':num1=num1<<num2; break;
                //case '>':num1=num1>>num2; break;
                //case '%':num1%=num2; break;
                        }
return num1; }

long pass_num;
int get_nextnumber(char domaths,char makeitminus){
 int endit=0,base=10,bp;
 char k,mathsym=0;
 long tmp=0;
 pass_num=0;

 for(;;){
        if(toupper(lineptr[lptr+1])=='X'){ lptr+=2; base=0x10;}
        if(toupper(lineptr[lptr+1])=='B'){ lptr+=2; base=2; }
        if(toupper(lineptr[lptr+1])=='O'){ lptr+=2; base=8; }
        tmp=0;
        for(;;){
               k=toupper(lineptr[lptr]);
               if(k<'0' || k>'9'){
                               if(base==0x10){
                                         if(k<'A' || k>'F')break;
                                                }
                                else break;
                                }
               if(k>='A'){ k-='A'; k+=10; }
               else k-='0';
               tmp*=base;
               if(k>base){ error("Digit out of range",ERROR);
                           return 1; }
               tmp+=k;
               lptr++;
                        }
        if(makeitminus){        tmp=-tmp;
                                makeitminus=0; }                        
        pass_num=dothemath(mathsym,pass_num,tmp);
        if(domaths==0)break; 
        skipspaces();
        switch(lineptr[lptr]){
                      case '+': case '|': case '&':
                      case '-': case '^': case '%':
                      case '*': case '<': case '>':
                      case '/': bp=lptr;
                                mathsym=lineptr[lptr]; lptr++;
                                skipspaces();
                                if(ischarnum(lineptr[lptr])!=2){
                                                     lptr=bp;
                                                     endit=1;
                                                        }
                                break;
                      default: endit=1;
                        }
        if(endit)break;
            }
return 0; }

int get_findnextword(){//return 1 if keyword (skips sizeof)
 int a=0;
 get_nextword();
 if(!strcmp(word,"sizeof"))return -1;
 for(;;){
        if(keywords[a]==NULL)break;        
        if(!strcmp(keywords[a],word))return a;
        a++;
        }
return -1; }

int is_it_signed(char type){
 for(;;){
       if(type>10) type/=10;
       else break;
        }
 if(type>5)return 0;
return 1; }

int test_type(char force,char curtype,char newtype, char disp){
 int ret=0;
 int src=0;
 int pointer1=0,type1=0,unsigned1=0;
 int pointer2=0,type2=0,unsigned2=0;

 src=force; if(src<1 && curtype>-1)src=curtype;

 for(;;){
       if(src>10){ src/=10; pointer1++; }
       else break;
        }
 for(;;){  if(newtype>10){ newtype/=10; pointer2++; }
           else break;
                }

 if(src>5){ src-=5; unsigned1=1; } type1=src;
 if(newtype>5){ newtype-=5; unsigned2=1; } type2=newtype;

 //we don't care signed!=unsigned etc...
 if(type2>0 && type1==5 && type2!=5){ if(disp)error("Type mismatch",WARNING); ret=1; }
 else if(type1>0 && type2==5 && type1!=5){ if(disp)error("Type mismatch",WARNING); ret=2; }
 else if(pointer1!=pointer2){
                //if(disp)error("Using an Integer as a pointer",WARNING);
                ret=3; }
return ret; }
int getsize(int type){
 int sz=0,p;
 p=type/10; type=type-(p*10);
 if(type>5)type-=5;
 if(p>0){    if(out32)return 4;
             return 2;
                }
 switch(type){
           case 1: sz=1; break;
           case 2: sz=1; if(out32)sz=2; break;
           case 3: sz=2; if(out32)sz=4; break;
           case 4: case 5: sz=4; break;
           default: sz=2; if(out32)sz=4;
            }
return sz; }
// 1 = char
// 2 = short
// 3 = int
// 4 = long
// 5 = void
// 6 = unsigned char
// 7 = unsigned short
// 8 = unsigned int
// 9 = unsigned long
//+10 per *
short use_extern;
int las_pos;
int checkforce(int forc){
 int a,ret=0,g1=0,type=0,unsign=0;
 int add=0;
 use_extern=0;
 las_pos=lptr;
 for(;;){
     skipspaces();
     las_pos=lptr;
     lophere:
     if(lineptr[lptr]=='*'){    if(add==1){
                                        error("Can only have single pointer",ERROR);
                                        return -1;
                                        }
                                add++; lptr++; goto lophere; }
     if(forc==1 && lineptr[lptr]==')'){ lptr++; break; }
     get_nextword();
     if(word[0]==0)break;
     g1=0;
     for(a=0;;){
        if(types[a]==NULL)break;
        if(!strcmp(types[a],"extern")){//can force extern!!!
                             if(!strcmp(word,"extern")){
                                                       if(forc){ error("Illegal use of extern",ERROR);
                                                                return 1;  }
                                                       use_extern=1;
                                                       }
                                }
        else if(!strcmp(types[a],word)){ 
                        g1=1;
                        if(a==5 && (type!=0 || unsign!=0)){
                                                error("Incompatiable types",ERROR);
                                                return -1; }
                        if(a==0)unsign=1;
                        else type=a;
                        }
         a++;
            }
     if(g1==0){ if(forc==0)break;
                if(type!=0 || unsign !=0){
                                error("Invalid use of force",ERROR);
                                return -1; }
                return 0; }
     }
 ret=type;
 if(unsign)ret+=5;
 if(add) ret+=(add*10);
return ret; }

//toplabel_stack (use lab type then we can use labelfree to free it ;)
typedef struct lab_hold{
                char *name;
                char type;//+(pointers*10)
                long initial_value;
                char initial_isstring;
                char *intial_string;
                int amountneeded;//for arrays
                int local_real_pos;
                int local_real_size;
                char islocal;
                char is_parameter;
                //int array_ceil[MAX_ARRAY+1];
                char sz;//1,2,4 char,int,long
                char isextern;
                //char array_dem;
                struct lab_hold *prev;
                }lab_hold;

typedef struct proc_hold{
                char *name;
                int parmcnt;
                int type;
                char declr;//offically
                char found;
                char isextern;
                int line1st;
                int linedec;
                int parmsize;
                char lastparmsz;
                char parmstr[MAX_PARM+1];
                struct proc_hold *prev;
                }proc_hold;
proc_hold *tmp_proc,*top_proc=NULL;
proc_hold *thecur_proc=NULL;

void fixup_parameters(proc_hold *proc);

void free_procs(){
 while(top_proc){
        tmp_proc=top_proc->prev;
        if(top_proc->name){ free(top_proc->name); malfreecntr--; }
        free(top_proc); malfreecntr--;
        top_proc=tmp_proc;
          }
return; }

int check_procs(){//also dumps extern procs
 int ret=0;
 char str[100];
 tmp_proc=top_proc;
 while(tmp_proc){
        if(tmp_proc->found==0){
                sprintf(str,"Procedure %s Not found (1st used line %d)",tmp_proc->name,tmp_proc->line1st);
                error(str,ERROR);
                ret=1;
                   }
        else if(tmp_proc->isextern){
                    if(prg_out) error("PRG cannot have extern",ERROR);
                    sprintf(asm_la_str,"extern %s",tmp_proc->name);
                    go_assemble();
                        }
        tmp_proc=tmp_proc->prev;
                }
return ret; }

int faddproc(char found, char lassz, int parmsz, int declr, int isextern, int type, int parmcnt,char *name,char *parmstr){
 int a,ret=0,fnd=0,mat;
 char stt[100];

 tmp_proc=top_proc;
 while(tmp_proc){
              if(!strcmp(tmp_proc->name,name)){ fnd=1; break; }
              tmp_proc=tmp_proc->prev;
                }

 if(fnd==1){  //Yes..Check parm match (if we can)
          if(declr==0)return 0;//no need
          tmp_proc->parmsize=parmsz;
          tmp_proc->lastparmsz=lassz;
          if(parmcnt<tmp_proc->parmcnt){
                        sprintf(stt,"Missing parameter in %s (First used line %d)",name,tmp_proc->line1st);
                        error(stt,ERROR); return -1; }
          if(parmcnt>tmp_proc->parmcnt){
                        sprintf(stt,"Extra parameter in %s (First used line %d)",name,tmp_proc->line1st);
                        error(stt,ERROR); return -1; }
          if(declr){
                if(tmp_proc->found==0){tmp_proc->found=1;
                                       tmp_proc->linedec=lineno;
                                        }
                else {  sprintf(stt,"Procedure %s already declared",name);
                        error(stt,ERROR); return -1; }
                }
          else if(tmp_proc->line1st==-1) tmp_proc->line1st=lineno;
          if(parmstr[0])
              for(a=0; a<tmp_proc->parmcnt; a++){
                       mat=test_type(-1,tmp_proc->parmstr[a],parmstr[a],0);
                       if(mat==1 || mat==2) sprintf(stt,"Parameter %d, type mismatch in call to %s",a,name);
                       if(mat==3) sprintf(stt,"Using Integer as pointer, Parameter %d in call to %s",a,name);
                       if(mat)error(stt,WARNING);
                              }
                }
 else{//make it
   ret=1;
   tmp_proc=(proc_hold *)malloc(sizeof(proc_hold));
   if(tmp_proc==NULL){ out_of_mem=1; return -1; }
   malfreecntr++;
   tmp_proc->prev=top_proc; top_proc=tmp_proc;

   tmp_proc->parmcnt=parmcnt;
   tmp_proc->type=type;
   tmp_proc->found=found;
   tmp_proc->isextern=isextern;
   tmp_proc->line1st=lineno;
   tmp_proc->linedec=lineno;
   tmp_proc->parmsize=parmsz;
   tmp_proc->lastparmsz=lassz;
   tmp_proc->parmstr[0]=0;
   for(a=0;a<parmcnt;a++) tmp_proc->parmstr[a]=parmstr[a];
   tmp_proc->name=(char *)malloc(strlen(name)+1);
   if(tmp_proc->name){
                malfreecntr++;
                strcpy(tmp_proc->name,name);
                                }
/*   if(declr){
       tmp_proc->linedec=lineno;
       tmp_proc->found=1;
       }
  else{
       tmp_proc->line1st=lineno;
       tmp_proc->found=0;
                }*/
        }
return ret; }

int make_label(int type,char *name, int siz,int bextern,int is_parameter);
int declar_proc(int type,char *name){
 int a,parmcnt=0,b,cn,stor=0;
 int parmsz=0,lsz=0;
 char parmstr[MAX_PARM+1];
 char label[100];
 char fnd=0;

 strcpy(label,word);
 cn=lptr;for(;;){
                if(lineptr[cn]==0)break;
                if(lineptr[cn++]=='{'){ stor=1; break; }
                }

 for(a=0; a<MAX_PARM; a++){
                        skipspaces();
                        if(lineptr[lptr]==')'){ lptr++; break; }
                        if(lineptr[lptr]==0 || lineptr[lptr]=='{'){
                                        error("Missing ) in procedure declaration",ERROR);
                                        return 1;
                                        }
                        if(lineptr[lptr]=='.'){
                                           error("... not supported yet",ERROR);
                                           return 1;

                                            for(;;)
                                                if(lineptr[++lptr]!='.')break;
                                            skipspaces();
                                            if(lineptr[lptr]!=')'){
                                                              error("... must be the last parameter",ERROR);
                                                              return 1;
                                                                }
                                            //lsz=0;
                                            b=-1;//multi
                                            parmstr[parmcnt++]=b;
                                                        }
                        else{
                          b=checkforce(0);
                          if(b==-1)return 1;
                          lsz=getsize(b); if(lsz==1)lsz=2;//no 8bit parmaeters on stack
                          parmsz+=lsz;
                          parmstr[parmcnt++]=b;                                                  
                        
                          if(stor){ //store label name
                                in_proc=1;//store locally
                                make_label(b,word,0,0,1);
                                in_proc=0;
                                        }
                          }
                        if(lineptr[lptr]==',')lptr++;
                        else if(lineptr[lptr]==')'){lptr++; break; }
                        else { 
                                error("Missing ) in procedure declaration",ERROR);
                                return 1;
                                  }
                        }
 skipspaces();
 if(lineptr[lptr]=='{')fnd=1;
 if(faddproc(fnd,lsz,parmsz,1,use_extern,type,parmcnt,label,parmstr)==-1)return 1;
 fixup_parameters(tmp_proc);
 
 if(lineptr[lptr]=='{'){ in_proc=1; lptr++;
                        tmp_proc->found=1;
                        if(prg_out)sprintf(asm_la_str,"P _%s",label);
                        else sprintf(asm_la_str,"_%s:",label);
                        go_assemble();
                        thecur_proc=tmp_proc;
                        if(!strcmp(label,"main"))in_main=1;
                                }
 if(lineptr[lptr]==0);
 else { sprintf(label,"Unexpected %c at end of declaration",lineptr[lptr]);
        error(label,ERROR);
        }
return 0; }

lab_hold *top_lab_local=NULL,*top_lab_gobal=NULL,*tmp_lab;

lab_hold *free_lab(lab_hold *top){
 while(top){
         tmp_lab=top->prev;
         if(top->name){ free(top->name); malfreecntr--; }
         if(top->intial_string){ free(top->intial_string); malfreecntr--; }
         free(top); malfreecntr--;
         top=tmp_lab;
         }
return top; }

int find_lab(char *name){
 tmp_lab=top_lab_local;
 while(tmp_lab){ if(!strcmp(tmp_lab->name,name))return 1;
                 tmp_lab=tmp_lab->prev;
                }
 tmp_lab=top_lab_gobal;
 while(tmp_lab){ if(!strcmp(tmp_lab->name,name))return 1;
                 tmp_lab=tmp_lab->prev;
                }
return 0; }

int make_label(int type,char *name, int siz,int bextern,int is_parameter){//,int dc){
 char str[100];
// lab_hold *argh=NULL;

  if(legal_labelname(name)){
                      error("Illegal use of a reserved word",ERROR);
                     return 1;
                           }

 find_lab(name);
 if(tmp_lab){
        sprintf(str,"Label %s already declared",name);
        error(str,ERROR);
        return 1;
        }
 else{
     //(We use in_proc to decide if it's local or gobal)
     tmp_lab=(lab_hold *)malloc(sizeof(lab_hold));
     if(tmp_lab==NULL){out_of_mem=1; return 1; }
     malfreecntr++;
    /* if(in_proc && is_parameter){
                if(top_lab_local==NULL){ tmp_lab->prev=NULL;
                                          top_lab_local=tmp_lab;
                                                }
                else{   for(argh=top_lab_local;;){  if(argh->prev==NULL)break;
                                                     argh=argh->prev;
                                                        }
                        tmp_lab->prev=argh->prev;
                        argh->prev=tmp_lab;
                                }
                }
     else*/
     if(in_proc){ tmp_lab->prev=top_lab_local; top_lab_local=tmp_lab; }
     else{ tmp_lab->prev=top_lab_gobal; top_lab_gobal=tmp_lab; }
     tmp_lab->type=type;
     tmp_lab->name=(char *)malloc(strlen(name)+1);
     //tmp_lab->array_dem=dc;
     tmp_lab->initial_isstring=-1;
     tmp_lab->sz=getsize(type);
     tmp_lab->is_parameter=is_parameter;
     tmp_lab->intial_string=NULL;
     tmp_lab->amountneeded=siz;
     tmp_lab->initial_value=0;
     tmp_lab->isextern=bextern;

     tmp_lab->islocal=in_proc;

     //if(is_parameter && in_proc && argh)tmp_lab->local_real_pos=argh->local_real_pos+argh->local_real_size;
     //else
     if(tmp_lab->prev==NULL)tmp_lab->local_real_pos=0;
     else {
        if(is_parameter==0 && tmp_lab->prev->is_parameter==1)tmp_lab->local_real_pos=0;
        else  tmp_lab->local_real_pos=tmp_lab->prev->local_real_pos+tmp_lab->prev->local_real_size;
        }

     tmp_lab->local_real_size=tmp_lab->sz;//for now...

     if(tmp_lab->name==NULL){ out_of_mem=1; return 1; }
     malfreecntr++;
     strcpy(tmp_lab->name,name);
     } 
return 0; }

typedef struct autodef{
                char *name;
                char *pos;
                struct autodef *prev;
                }autodef;
autodef *top_autodef_local=NULL, *top_autodef_gobal=NULL;

autodef *free_auto_define(autodef *top){
 autodef *t;
 while(top){
            t=top->prev;
            if(top->name){ free(top->name); malfreecntr--; }
            if(top->pos){ free(top->pos); malfreecntr--; }
            free(top); malfreecntr--;
            top=t;
            }
return top; }

void make_autodef(char *name, char local, char *str){
 autodef *f;
 f=(autodef *)malloc(sizeof(autodef));
 if(f==NULL){ out_of_mem=1; return; } malfreecntr++;
 if(local){ f->prev=top_autodef_local; top_autodef_local=f; }
 else{ f->prev=top_autodef_gobal; top_autodef_gobal=f; }
 f->name=NULL;
 f->pos=(char *)malloc(strlen(str)+1);
 if(f->pos==NULL){ out_of_mem=1; return; } malfreecntr++;
 strcpy(f->pos,str);
 f->name=(char *)malloc(strlen(name)+1);
 if(f->name==NULL){ out_of_mem=1; return; } malfreecntr++;
 strcpy(f->name,name);
return; }

void autodefine_local(char *name){
 lab_hold *t;
 char str[100];
 int adr_sz=2;
 if(out32)adr_sz=4;

 t=top_lab_local;
 while(t){ if(!strcmp(t->name,name))break;
           t=t->prev;
                }
 if(t){  if(t->is_parameter)sprintf(str," bp+%d",t->local_real_pos+adr_sz);
         else sprintf(str," bp-%d",t->local_real_pos+t->local_real_size);
         if(out32)str[0]='e';

         make_autodef(name,1,str);
        }
return; }
void autodefine_gobal(char *name){
 lab_hold *t;
 char str[255];
 t=top_lab_gobal;
 while(t){ if(!strcmp(t->name,name))break;
           t=t->prev;
                }
 if(t){
        sprintf(str,"_%s",t->name);
        make_autodef(name,0,str);
        }
return; }
char *check_autodef(char *name){
 autodef *f;
 f=top_autodef_local;
 while(f){
           if(!strcmp(f->name,name))return f->pos;
           f=f->prev;
                }
 f=top_autodef_gobal;
 while(f){
           if(!strcmp(f->name,name))return f->pos;
           f=f->prev;
                }
return NULL; }

int do_autodefs(char *str){
 char *str2;
 str2=check_autodef(str);
 if(str2){ strcat(line,str2); return 1; }
return 0; }


/*int getceil(int dist,lab_hold *l){
 int num=0;
 int maxdist=l->array_dem;

 for(;dist+1<maxdist;dist++){
                if(num==0)num=l->array_ceil[dist+1];
                else num*=l->array_ceil[dist+1];
                }
return num; }*/

int giverealvalueof();
int storestring(int kee);

long pas_inital_value;
int len_of_it;
int get_initial_value(char strshit,char type, int arr){
 int po,ty;
 char k,ismin=0,ret=0;
 char str[40];

 len_of_it=1;
 pas_inital_value=0;
 po=type/10; ty=type-(po*10);
 skipspaces();

 k=lineptr[lptr];
 if(k=='-'){ lptr++; ismin=1; k=lineptr[lptr]; }

 if(k=='\''){ //call the routine to get this (remember the \n etc
              lptr++;
              pas_inital_value=giverealvalueof(); lptr++;
              if(lineptr[lptr]!='\''){ error("Missing \'",ERROR);
                                     return 1; }
              lptr++;
                }
 else if(k>='0' && k<='9'){
                if(get_nextnumber(1,ismin)==1)return 1;
                pas_inital_value=pass_num;
                if(po)error("Setting a pointer with an integer",WARNING);
                                }
 else if(k=='\"'){ if(ismin==1){ error("Illegal label declaration value",ERROR);
                                        return 1; }
                if(po==0 && arr==0)error("Setting an integer with a pointer",WARNING);
                if(strshit==-1)storestring(0);
                else pas_inital_value=storestring(1);
                ret=-1;
                }
 else{ error("Illegal label declaration value",ERROR); return 1; }
 skipspaces();
 if(lineptr[lptr]!=0){
                sprintf(str,"Unexpected %c",lineptr[lptr]);
                error(str,ERROR); return 1;
                                }
return ret; }

void add_initial_str(lab_hold *ourlab){
 char *st;

 st=(char *)malloc(strlen(word)+1);
 if(st==NULL){ out_of_mem=1; return; }
 malfreecntr++;
 strcpy(st,word);
 ourlab->intial_string=st;
return; }

int get_local_realsize(lab_hold *tp);

int declar_label(){
 int type;//,point=0;
 int thesize;
 char ismin,k,canbeproc=1;
// int array_ceil[MAX_ARRAY+1];
// char kk=1;

// for(type=0; type<MAX_ARRAY; type++) array_ceil[type]=0;

back_to_top:

 thesize=0; ismin=0;
 type=checkforce(0);
 if(type==-1)return 1;

 pas_inital_value=0;

 skipspaces();
 if(lineptr[lptr]=='('){ lptr++; //Delaring a proc
                         if(canbeproc==0){
                                          error("Illegal declaration",ERROR);
                                          return 1;
                                                }
                         if(in_proc){  error("Cannot have procedure inside procedure",ERROR);
                                      return 1;
                                        }
                         declar_proc(type,word);
                         return 0;
                               }
 if(lineptr[lptr]=='['){
                      lptr++;
                      skipspaces();
                      if(lineptr[lptr]==']'){//array
                                   lptr++;
                                   skipspaces();
                                   thesize=-1;
                                        }
                       else for(;;){                        
                        skipspaces();
                        if(lineptr[lptr]=='-'){lptr++; ismin=1; }
                        if(ischarnum(lineptr[lptr])!=2){
                                                    error("Must be a number",ERROR);
                                                    return 1;
                                                        }
                        if(get_nextnumber(1,ismin))return 1;
                        //array_ceil[point]=pass_num;
                        //if(thesize==0)
                        thesize=pass_num;
                        //else thesize*=pass_num;
                        if(lineptr[lptr]!=']'){ error("Missing ]",ERROR);
                                                      return 1; }
                     /*   point++;
                       if(point>=MAX_ARRAY){
                                  error("Too many dimensions in array",ERROR);
                                            return 1; }
                      */

                        lptr++;
                         skipspaces();
                         if(lineptr[lptr]!='[')break;
                         lptr++;
                         error("Only supports single dimension array",ERROR);
                         return 1;
                          }
                        }
 if(lineptr[lptr]=='='){ lptr++; //initial value (MUST BE CONSTANT)
        if(thesize==-1)make_label(type,word,1,use_extern,0);//,point);
        else make_label(type,word,thesize,use_extern,0);//,point);
         if(in_proc)autodefine_local(word);
         else autodefine_gobal(word);
        if(use_extern==1 && in_proc==0){
                        error("Cannot give an extern a value",ERROR);
                        return 1;
                        }
         if(in_proc){lptr=las_pos;//set locals differently
                    if(lineptr[lptr]=='*')lptr++;//ignore this I think for pre initial
                    if(tmp_lab)tmp_lab->local_real_size=get_local_realsize(tmp_lab);//for now...
                    getexpr(0,1);
                    if(lineptr[lptr-1]==',')lptr--;
                    else if(lineptr[lptr-1]==')'){ error("Syntax error",ERROR);
                                                   return 1; }
                      }
         else{
                 k=get_initial_value(thesize,tmp_lab->type,tmp_lab->amountneeded);
                 if(k==1) return 1;
                 if(k==-1)tmp_lab->initial_isstring=in_proc;
                 tmp_lab->initial_value=pas_inital_value;
                 if(thesize==-1){tmp_lab->amountneeded=len_of_it;
                                add_initial_str(tmp_lab);
                                 }
                 if(tmp_lab)tmp_lab->local_real_size=get_local_realsize(tmp_lab);//for now...
                             }
                        }
 else { if(thesize==-1)thesize=1;
        make_label(type,word,thesize,use_extern,0);//,point);
        if(tmp_lab)tmp_lab->local_real_size=get_local_realsize(tmp_lab);//for now...
         if(in_proc)autodefine_local(word);
         else autodefine_gobal(word);
        }

 canbeproc=0;

 skipspaces();
 if(lineptr[lptr]==','){lptr++; goto back_to_top; }

/* if(kk==0){
       for(type=0; type<MAX_ARRAY; type++) tmp_lab->array_ceil[type]=array_ceil[type];
                }*/
return 0; }

char *store_lastring(int local,int num,char *current, char *toadd){
 char me[100];
 sprintf(me,"String%d: db \"",num);
 if(current==NULL){
                current=(char *)malloc(strlen(toadd)+strlen(me)+1);
                if(current==NULL){ out_of_mem=1; return NULL; }
                malfreecntr++;
                current[0]=0;
                }
 else{  current=(char *)realloc(current,strlen(me)+strlen(toadd)+strlen(current)+1);
        if(current==NULL){ out_of_mem=1; malfreecntr--; return NULL; }
                }
  strcat(current,me); strcat(current,toadd);
return current; }


int get_local_realsize(lab_hold *tp){//amount of locals
 int num=0;
 int po,ty,mulp,shval=1,intval=2;
 if(out32){ shval=2; intval=4; }
 if(tp==NULL)return 0;

        po=0; ty=tp->type;
        po=ty/10; ty-=(po*10);

          if(tp->isextern);//ha ha
          else if(po){
                   num+=intval;
                   if(tp->amountneeded>0){mulp=tp->amountneeded;
                                       switch(ty){
                                               case 1: case 6: num+=mulp; break;//char
                                               case 2: case 7: num+=(shval*mulp); break; //short
                                               case 5: case 4: case 9: num+=(4*mulp);; break;//long
                                               default: num+=(intval*mulp); break;//int
                                                        }
                                        }//amount needed
                        }//po
          else if(tp->intial_string){
                           num+=strlen(tp->intial_string)-2;
                                }
          else{
               mulp=1;
               if(tp->amountneeded>0)mulp=tp->amountneeded;
               switch(ty){
                       case 1: case 6: num+=mulp; break;//char
                       case 2: case 7: num+=(shval*mulp); break; //short
                       case 5: case 4: case 9: num+=(4*mulp);; break;//long
                       default: num+=(intval*mulp); break;//int
                                        }
                                }
return num; }

void fixup_parameters(proc_hold *proc){
 int pos;
 lab_hold *tp;
 tp=top_lab_local;
 while(tp){
        if(tp->is_parameter){
                        pos=((proc->parmsize-proc->lastparmsz)-tp->local_real_pos);
//printf("(%d)\n",pos);
//printf("!parmsize %d - lastparmsz %d - realpos %d\n",proc->parmsize,proc->lastparmsz,tp->local_real_pos);
                        tp->local_real_pos=pos;

                 autodefine_local(tp->name);
                                }
        tp=tp->prev;
        }
return; }

int get_local_amount(){
  int num=0;
  lab_hold *tp;
  tp=top_lab_local;
  while(tp){
        if(tp->is_parameter==0)num+=tp->local_real_size;
        tp=tp->prev; }
return num; }

void dump_label_pos(lab_hold *tp){
 int adr_sz=2;
 if(out32)adr_sz=4;
  while(tp){
         if(tp->is_parameter)
                          sprintf(asm_la_str,"; _%s @ +%d (size = %d)",tp->name,tp->local_real_pos+adr_sz,tp->local_real_size);
         else sprintf(asm_la_str,"; _%s @ -%d (size = %d)",tp->name,tp->local_real_pos,tp->local_real_size);
          go_assemble();
          tp=tp->prev;
                }
return; }

void dump_variables(short local,lab_hold *tp){
 int po,ty;
 char *intsiz1="db";
 char *intsiz2="dw";
 char *intsiz3="dd";
 char *intis,*shortis;
 char wot[10];
 char inivalue[40];
 int num=2;

 intis=intsiz2; shortis=intsiz1;
 if(out32){ intis=intsiz3; shortis=intsiz2; num=4; }

 if(outfile)fprintf(outfile,"\n");

 if(local)sprintf(asm_la_str,"; Local Variables(stack instead)");
 else sprintf(asm_la_str,"; Gobal Variables");
 go_assemble();

 if(outfile)fprintf(outfile,"\n");
 while(tp){
        po=0; ty=tp->type;
        po=ty/10; ty-=(po*10);

        if(tp->isextern){  if(out32)sprintf(asm_la_str,"extern _%s",tp->name);
                           else sprintf(asm_la_str,"extern _%s",tp->name);
                           go_assemble();
                                }
        else {
               if(tp->initial_isstring>-1){
                          //if(tp->initial_isstring)sprintf(inivalue,"Offset Loc_str%ld",tp->initial_value);
                          //else
                          sprintf(inivalue,"Offset String%ld",tp->initial_value);
                                        }
                else sprintf(inivalue,"%ld",tp->initial_value);
                if(po){ 
                      if(tp->amountneeded==0){
                                            if(prg_out)sprintf(asm_la_str,"D2 _%s %s",tp->name,inivalue);
                                            else sprintf(asm_la_str,"_%s %s %s",tp->name,intis,inivalue);
                                            go_assemble();
                                                }
                       else{  if(prg_out)sprintf(asm_la_str,"D2 _%s Offset %s+%d",tp->name,tp->name,num);
                              else sprintf(asm_la_str,"_%s %s Offset %s+%d",tp->name,intis,tp->name,num);
                              go_assemble();
                              switch(ty){
                                        case 1: case 6: if(prg_out)sprintf(asm_la_str,"d1 %d",tp->amountneeded);
                                                        sprintf(asm_la_str,"  dub_db %d",tp->amountneeded);
                                                        break;//char
                                        case 2: case 7: if(prg_out)sprintf(asm_la_str,"d2 %d",tp->amountneeded);
                                                        sprintf(asm_la_str,"  dub_%s %d",shortis,tp->amountneeded);
                                                        break; //short
                                        case 5: case 4: case 9:
                                                        if(prg_out)sprintf(asm_la_str,"d4 %d",tp->amountneeded);
                                                        sprintf(asm_la_str,"  dub_dd %d",tp->amountneeded);
                                                        break;//long
                                        default:        if(prg_out)sprintf(asm_la_str,"d2 %d",tp->amountneeded);
                                                        sprintf(asm_la_str," dub_%s %d",intis,tp->amountneeded);
                                                        break;//int
                                                }
                                go_assemble();
                                }
                        }
                else{ //to do ini value
                      if(tp->intial_string){
                              if(prg_out) sprintf(asm_la_str,"T _%s \"%s",tp->name,tp->intial_string);
                              else sprintf(asm_la_str,"_%s db \"%s",tp->name,tp->intial_string);
                              asm_la_str[strlen(asm_la_str)-1]=0;//remove the \n
                              go_assemble();
                                      }
                      else{
                       if(tp->amountneeded>0){sprintf(wot," dub_");//array
                                        sprintf(inivalue,"%d",tp->amountneeded);
                                                }
                      else {sprintf(wot," ");
                            if(tp->initial_isstring>-1){
                                  //if(tp->initial_isstring)sprintf(inivalue,"Offset Loc_str%ld",tp->initial_value);
                                  //else
                                  sprintf(inivalue,"Offset String%ld",tp->initial_value);
                                                }
                             else sprintf(inivalue,"%ld",tp->initial_value);
                                }
                      switch(ty){
                                case 1: case 6: if(prg_out)sprintf(asm_la_str,"D1 _%s%s %s",tp->name,wot,inivalue);
                                                else sprintf(asm_la_str,"_%s%sdb %s",tp->name,wot,inivalue);
                                                break;//char
                                case 2: case 7: if(prg_out)sprintf(asm_la_str,"D2 _%s%s %s",tp->name,wot,inivalue);
                                                else sprintf(asm_la_str,"_%s%s%s %s",tp->name,wot,shortis,inivalue);
                                                break; //short
                                case 5: case 4: case 9:
                                                if(prg_out)sprintf(asm_la_str,"D4 _%s%s %s",tp->name,wot,inivalue);
                                                else sprintf(asm_la_str,"_%s%sdd %s",tp->name,wot,inivalue);
                                                break;//long
                                default:        if(prg_out)sprintf(asm_la_str,"D2 _%s%s %s",tp->name,wot,inivalue);
                                                else sprintf(asm_la_str,"_%s%s%s %s",tp->name,wot,intis,inivalue);
                                                break;//int
                                        }
                        go_assemble();
                                }
                        }
                }
        tp=tp->prev;
           }
return; }


int giverealvalueof(){
 int num=0;
 char k;
 k=lineptr[lptr];
 if(k=='\\'){ lptr++;  k=lineptr[lptr];
             if(k>='0' && k<='9')num=k-'0';
             else switch(k){
                  case 't': num=9; break;
                  case 'n': num=10; break;
                  case '\'': num=39; break;
                  case '\"': num=34; break;
                  case '\\': num=92; break;                  
                    }//switch
                }
 else num=k;
return num; }

void dump_string(short local, char *str){
 int a,op=0;
 char k;

 if(outfile)fprintf(outfile,"\n");

// if(local)sprintf(asm_la_str,"; Local Strings");
// else
 sprintf(asm_la_str,"; Strings"); go_assemble();

 if(outfile)fprintf(outfile,"\n");
 for(a=0; a<strlen(str); a++){
                k=str[a]; if(op>254)op=254;
                if(k=='\n'){  asm_la_str[op]=0; op=0; donttab=1;
                              go_assemble(); donttab=0; }
                if(k=='\\'){   a++; asm_la_str[op++]='\"'; asm_la_str[op++]=',';
                               k=str[a];
                               if(k>='0' && k<='9'){
                                                asm_la_str[op++]=k;
                                                asm_la_str[op++]=',';
                                                }
                               else switch(k){
                                      case 't': //printf("\",%d,\"",'\t');
                                                asm_la_str[op++]='9';
                                                asm_la_str[op++]=',';
                                                break;
                                      case 'n': //printf("\",%d,\"",'\n');
                                                asm_la_str[op++]='1';
                                                asm_la_str[op++]='0';
                                                asm_la_str[op++]=',';
                                                break;
                                      case '\'':
                                                asm_la_str[op++]='3';
                                                asm_la_str[op++]='9';
                                                asm_la_str[op++]=',';
                                                break;
                                      case '\"':
                                                asm_la_str[op++]='3';
                                                asm_la_str[op++]='4';
                                                asm_la_str[op++]=',';
                                                break;
                                      case '\\': //printf("\",%d,\"",k);
                                                asm_la_str[op++]='9';
                                                asm_la_str[op++]='2';
                                                asm_la_str[op++]=',';
                                                break;
                                           }//switch
                               asm_la_str[op++]='\"';
                                  }// \ ah
                else asm_la_str[op++]=k;//printf("%c",k);
                }
return; }

int test_string(char *str){
 int a;
 char k;
 for(a=0; a<strlen(str); a++){
      k=str[a];
      if(k=='\\')switch(k){
                       case 't': case 'n': case '\'':
                       case '\"': case '\\': break;
                       default: return 1;
                                }
                }
return 0;}

int storestring(int kee){
 char k,ls=0;
 int a=0;
 lptr++;//past the "
 len_of_it=1;
 for(;;){
        k=lineptr[lptr++];
        if(k=='\"' && ls!='\\')break;
        word[a++]=k; len_of_it++;
        if(a>254){  error("String too long,truncated",WARNING);  break;  }
        ls=k;
           }
 word[a++]='\"';
 word[a++]=',';  word[a++]='0';
 word[a++]='\n';  word[a]=0;

 if(test_string(word)==1)error("Illegal character in string",WARNING);
 if(kee==0)return 0;
 //if(in_proc) { local_str=store_lastring(1,toplocalstr++,local_str,word);
 //              return toplocalstr-1; }
 gobal_str=store_lastring(0,topgobalstr++,gobal_str,word);
return topgobalstr-1; }

void parmerror(int t,char *name){//missing
 char str[100];
 if(t==0)sprintf(str,"Missing Parameter in call to %s",name);
 else sprintf(str,"Too many Parameters in call to %s",name);
 error(str,ERROR);
return; }

void errorlabelnotfound(char *name){
 char str[100];
 sprintf(str,"Label %s not found",name);
 error(str,ERROR);
return; }

int do_the_eval(int etype,char *reg1,char *reg2){
 if(prg_out)sprintf(asm_la_str,"Cm");
 else sprintf(asm_la_str,"Cmp %s,%s",reg1,reg2);
 go_assemble();
 switch(etype){
               case 0:  if(prg_out)sprintf(asm_la_str,"S1");
                        else sprintf(asm_la_str,"Sete %s",smallOTHERREG);
                        go_assemble();break;
               case 1: if(prg_out)sprintf(asm_la_str,"S2");
                        else sprintf(asm_la_str,"Setne %s",smallOTHERREG);
                        go_assemble(); break;
               case 2: if(prg_out)sprintf(asm_la_str,"S3");
                       else sprintf(asm_la_str,"Setg %s",smallOTHERREG);
                        go_assemble();break;
               case 3: if(prg_out)sprintf(asm_la_str,"S4");
                       else sprintf(asm_la_str,"Setge %s",smallOTHERREG);
                        go_assemble(); break;
               case 4: if(prg_out)sprintf(asm_la_str,"S5");
                       else sprintf(asm_la_str,"Setl %s",smallOTHERREG);
                        go_assemble();break;
               case 5: if(prg_out)sprintf(asm_la_str,"S6");
                       else sprintf(asm_la_str,"Setle %s",smallOTHERREG);
                        go_assemble();break;
                }
 if(prg_out)sprintf(asm_la_str,"XM");
 else sprintf(asm_la_str,"Xor %s,%s",MATHREG,MATHREG);
 go_assemble();
 if(prg_out)sprintf(asm_la_str,"Mi");
 sprintf(asm_la_str,"Mov %s,%s",smallMATHREG,smallOTHERREG);
 go_assemble();
return 0; }


#include "getexpr.h"

#include "main.h"

#include "keywords.h"

