/*

        The main reading and sorting routines,
        Unpacks the define etc...

        (readline(),do_defines() handle it)

*/

long stack_size=0x200;

void makedefine(char *label,char *rest);
void do_default_defines(){
 int cntr=0;
 for(;;){
        if(autodefines[cntr]==NULL)break;
        makedefine(autodefines[cntr],autodefines[cntr+1]);
        cntr+=2;
                }
return; }

int find_declar(char *str){
 int a;
 for(a=0; ;a++){
             if(types[a]==NULL)break;
             if(!strcmp(types[a],word))return 1;
                }
return 0; }

void do_asm(char *rest){
 int a;
 char edasm=0;
 a=strlen(rest); if(rest[a-1]=='}'){ rest[a-1]=0; edasm=1; }
 sprintf(asm_la_str,"%s",rest);
 go_assemble();
 if(edasm)pop_if_tree();
return; }

char last_was_ret;
void end_proc(){
 int a;
        if(thecur_proc->type!=5 && thecur_proc->type!=10 && last_was_ret==0)
                                        error("procedure should return a value",WARNING);
        in_proc=0;
        if(last_was_ret==0)asm_ret();
        if(prg_out)sprintf(asm_la_str,"P @_%s",thecur_proc->name);//procname
        else sprintf(asm_la_str,"@_%s:",thecur_proc->name);//procname
        go_assemble();
        if(in_main){ had_main=1;
                if(prg_out)sprintf(asm_la_str,"!"); 
                else if(out_type==1)sprintf(asm_la_str,"Start:"); 
                else sprintf(asm_la_str,".Start"); go_assemble();
              if(prg_out==0){
                if(out32){
                        sprintf(asm_la_str,"Mov eax,Seg Data"); go_assemble();
                        sprintf(asm_la_str,"Mov ds,eax"); go_assemble();
                        sprintf(asm_la_str,"Mov ss,eax"); go_assemble();
                        sprintf(asm_la_str,"Mov esp,Offset StackPos+%ld",stack_size); go_assemble();
                         }
                else{
                        sprintf(asm_la_str,"Mov ax,Seg Data"); go_assemble();
                        sprintf(asm_la_str,"Mov ds,ax"); go_assemble();
                        sprintf(asm_la_str,"Mov ss,ax"); go_assemble();
                        sprintf(asm_la_str,"Mov sp,Offset StackPos+%ld",stack_size); go_assemble();
                        }
                  }
//todo                                                        
// set up the command line parameters
                }
        //if(thecur_proc->parmsize>0)adjust_sp(thecur_proc->parmsize);
        mov_sp_bp();
        if(top_lab_local){
//                a=top_lab_local->local_real_pos+top_lab_local->local_real_size;//amount of locals
//printf(">%d : ",a);
//                a-=thecur_proc->parmsize;
                a=get_local_amount();
                if(a>0)subadjust_sp(a);//amount of locals
//printf(" %d\n",a);
                        }
        //if(in_main)
        if(prg_out)sprintf(asm_la_str,"a _%s",thecur_proc->name);//proc name
        else sprintf(asm_la_str,"Call _%s",thecur_proc->name);//proc name
        //else sprintf(asm_la_str,"Jmp _%s",thecur_proc->name);//proc name
        go_assemble();
        if(in_main==0){
                a=get_local_amount();
                if(a>0)adjust_sp(a);
                asm_ret();
                        }
        if(in_main){
                if(prg_out)sprintf(asm_la_str,"*");
                else{        
                        if(thecur_proc->type==5 || thecur_proc->type==10)sprintf(asm_la_str,"Mov ax,4c00h");
                        else sprintf(asm_la_str,"Mov ah,4ch");
                        go_assemble();
                        sprintf(asm_la_str,"Int 21h");
                        }
                        go_assemble();
                if(outfile)fprintf(outfile,";\n");
                }
        if(top_lab_local && debug_type)dump_label_pos(top_lab_local);//dump_variables(1,top_lab_local);
        in_main=0;
        //if(local_str){dump_string(1,local_str);
        //              free(local_str);
        //              malfreecntr--;
        //              local_str=NULL; }
        top_lab_local=free_lab(top_lab_local);
        top_autodef_local=free_auto_define(top_autodef_local);
        thecur_proc=NULL;
        if(outfile)fprintf(outfile,"\n");
return; }

char our_line_pushed;
int do_line(char *line,char reset){
        int expr_st,a;
        char can_directive=1;
//printf(">%d\n",lineno);
        if(reset)lptr=0;
        lineptr=line;
        if(in_multi_asm){ do_asm(lineptr); return 0; }
        our_line_pushed=0;
  anothergo:
        skipspaces();
        expr_st=lptr;
        if(lineptr[0]==0){ pop_if_line_tree(); return 0; }
        if(lineptr[lptr]==0){ pop_if_line_tree(); return 0; }
        if(ischarnum(lineptr[lptr])!=0){//character
                                last_was_ret=0;
                                if(debug_type){sprintf(asm_la_str,"; %s",line); go_assemble(); }
                                a=get_findnextword();
                                if(a!=-1){
                                       if(find_declar(word)){
                                                if(in_switch>0 && in_case==0){
                                                         error("Out of case",ERROR);
                                                         return 1;
                                                             }
                                                    if(can_directive==0){ error("Cannot declare a label here",ERROR);
                                                                                return 0; }
                                                    lptr=expr_st;
                                                    declar_label();
                                                                }
                                        else {
                                             if(in_switch>0 && in_case==0 && strcmp(word,"case") && strcmp(word,"default")){
                                                         error("Out of case",ERROR);
                                                         return 1;
                                                             }

                                               if(in_proc==0){
                                                        error("Out of Procedure",ERROR);
                                                        return 1; //just stop
                                                        }
                                                can_directive=0;
                                                a=do_keyword(word);
                                                if(a==2)goto anothergo;
                                                pop_if_line_tree();
                                                        }
                                                }
                                else{
                                       skipspaces();
                                       if(in_proc==0 && lineptr[lptr]=='('){
                                                        lptr++;
                                                        declar_proc(DEFAULT_TYPE,word); }
                                       else{
                                               if(in_switch>0 && in_case==0){
                                                                      error("Out of case",ERROR);
                                                                      return 1;
                                                                        }
                                               if(in_proc==0){ error("Out of Procedure",ERROR);
                                                              return 1; //just stop
                                                                }
                                                lptr=expr_st;
                                                a=getexpr(0,0);
                                                if(a==0 && has_effect==0)error("Code has no effect",WARNING);
                                                if(a==3)goto anothergo;
                                                pop_if_line_tree();
                                                 }
                                             }
                                        }
        else{//symbol
                if(lineptr[lptr]!='}')last_was_ret=0;
                switch(lineptr[lptr]){
                         case 0: pop_if_line_tree(); break;
                         case '#': if(can_directive==0){ error("Cannot have a directive here",ERROR);
                                                        break; }
                                    lptr++;
                                    do_directive();
                                   break;//directive
                         case '{': error("Unexpected {",ERROR); break; 
                         case '}':  lptr++;
                                    if(pop_if_line_tree())last_was_ret=0;
                                    if(top_if_tree) {
                                                last_was_ret=0;
                                                pop_if_tree();
                                                }
                                    else if(in_proc) end_proc();
                                    else error("Unexpected }",ERROR);
                                        break;//pop tree
                         default:
                                 if(in_switch>0 && in_case==0){
                                                             error("Out of case",ERROR);
                                                             return 1;
                                                                   }
                                  if(in_proc==0){ error("Out of Procedure",ERROR);
                                                  return 1; //just stop
                                                }
                                  else{
                                          a=getexpr(0,0);
                                          if(a==0 && has_effect==0)error("Code has no effect",WARNING);
                                          if(a==3)goto anothergo;
                                          pop_if_line_tree();
                                          }
                                }
                        }
return 0; }

char gobal_was_asm;

void do_defines(){
 int a,lp=0,wp;
 char k=-1,instr=0,instr2=0,ls;
 char str2[257];
 strcpy(str2,line);

 for(a=0;;){
        if(k==0)break;
        k=str2[a++];
        if(k==0)break;
        if(instr==0 && instr2==0 && ischarnum(k)==1){
                                        word[0]=k;
                                        for(wp=1;;){
                                               k=str2[a++];
                                               if(ischarnum(k)==0)break;
                                               word[wp++]=k;
                                                }
                                         word[wp]=0;
                                         line[lp]=0;
                                         if(find_define(word)!=-1)strcat(line,cur_def->line);
                                         else if(gobal_was_asm==0) strcat(line,word);
                                         else if(do_autodefs(word)==0) strcat(line,word);
                                         lp=strlen(line);
                                        }
        if(k=='\"' && instr2==0){
                        if(instr==1 && ls!='\\')instr=0;
                        else instr=1;
                             }
        if(k=='\'' && instr==0){
                        if(instr2==1 && ls!='\\')instr2=0;
                        else instr2=1;
                             }
        line[lp++]=k;

        ls=k;
                }
 line[lp]=0;
 line[lp+1]=0;
return; }


//FILE *hnd=NULL;
int endofit;


char we_where_directive;
int readline(){
 int ret=0;
 int ptr,k,ls=0;
 char in_str=0,in_str2=0,skip=0,inder=0,inasmline=0;

 gobal_was_asm=0;
 if(in_multi_asm)inasmline=1;
 we_where_directive=0;
    for(ptr=0; ptr<256;){//readline
                k=fgetc(hnd);

                if(k=='\n' && (in_str || in_str2)){ error("Unterminated String",ERROR); skip=1; break; }
                if(k=='\n'){ lineno++;total_linecntr++; if(inder || inasmline)break;  k=32; }
                if(in_str==0 && in_str2==0){
                                if(inasmline==0 && inder==0 && k==';')break;
                                if(k=='#'){inder=1; we_where_directive=1; }
                                if(ptr>3 && k==' ' && line[ptr-1]=='m' && line[ptr-2]=='s' &&
                                   line[ptr-3]=='a' && line[ptr-4]==' ')inasmline=1;
                                if(ptr==3 && k==' ' && line[ptr-1]=='m' && line[ptr-2]=='s' &&
                                   line[ptr-3]=='a')inasmline=1;
                                }
                if(k=='\'' && in_str==0){ if(in_str2==1 && ls!='\\')in_str2=0;
                                          else in_str2=1; }
                if(k=='\"' && in_str2==0){ if(in_str==1 && ls!='\\')in_str=0;
                                           else in_str=1; }
                if(in_str==0 && in_str2==0 && k=='*' && ls=='/'){//remmark
                                     ptr--;//remove the /
                                     ls=0;
                                     for(;;){
                                           k=fgetc(hnd);
                                           if(k=='\n'){lineno++;total_linecntr++;}
                                           if(k=='*'){
                                                  k=fgetc(hnd);
                                                  if(k=='\n'){lineno++;total_linecntr++;}
                                                  if(k=='/') break;
                                                        }
                                           if(k<1){ error("Comment Never Ended",WARNING);
                                                        break; }
                                                }
                                        }
                else if(in_str==0 && in_str2==0 && k=='/' && ls=='/'){//remmark
                                   ls=0; ptr--;
                                   for(;;){ k=fgetc(hnd);
                                            if(k=='\n'){lineno++;total_linecntr++;}
                                            if(k=='\n' || k<1)break;
                                             }
                                        }
                else if(k<1){   if(inder)break;
                                if(top_include) pop_include();
                                else endofit=1;
                                break;
                              }
                else line[ptr++]=ls=k;                                
                if(inder==0 && in_str==0 && in_str2==0 && k=='{')break;
                if(inder==0 && in_str==0 && in_str2==0 && k=='}')break;
                }
  line[ptr]=0;
  if(ptr>254){ error("Line too long",ERROR); skip=1; }
  if(skip)ret=1;
  gobal_was_asm=inasmline;
return ret; }

int compilefile(char *name){

 endofit=0;

 filename=name;
 for(;;){
  las_was_if=0;
  if(readline()==0){
                 if(we_where_directive==0)do_defines();
                 if(do_line(line,1)==1)endofit=1;
                 for(;;){
                         if(las_was_if==0)break;
                         las_was_if=0;
                         if(do_line(line,0)==1){ if(endofit)break;
                                                 endofit=1; }
                                  }
                 }  
  if(endofit)break;
   }
 

 if(prg_out)sprintf(asm_la_str,":");
 else if(mem_model!=1 && out_type!=1) sprintf(asm_la_str,"Seg Data");
 else sprintf(asm_la_str,"Data:");
 go_assemble();
 if(top_lab_gobal)dump_variables(0,top_lab_gobal);
 if(gobal_str)dump_string(0,gobal_str);
 check_procs();//this'll also dump the externs
 if(in_ifdef>0)error("#if without #endif",WARNING);
 if(in_proc || top_if_tree)error("Missing }",ERROR);
 if(had_main && prg_out==0){
         if(outfile)fprintf(outfile,"\n");
         sprintf(asm_la_str,"StackPos:"); go_assemble();
         sprintf(asm_la_str,"Dub_db 0%lxh",stack_size);
         go_assemble();
         }
  free_goto_pos(1);//this'll also check them
return 0; }

void free_else();
void free_all(){
         free_bracstore();
         free_procs();
         free_goto_pos(0);

         top_lab_local=free_lab(top_lab_local);
         top_lab_gobal=free_lab(top_lab_gobal);

        top_if_tree=free_if_tree(top_if_tree);
        top_if_line_tree=free_if_tree(top_if_line_tree);
        free_def();
        free_includes();

        free_else();

        top_autodef_local=free_auto_define(top_autodef_local);
        top_autodef_gobal=free_auto_define(top_autodef_gobal);

         //if(local_str){ free(local_str); malfreecntr--; local_str=NULL; }
         if(gobal_str){ free(gobal_str); malfreecntr--; gobal_str=NULL; }
return; }

typedef struct filehold{
                char *name;
                struct filehold *prev;
                }filehold;
filehold *top_filecomp=NULL;

void compilefiles(){
 filehold *tmpf;
 int cn;
 char str[100];
 
 while(top_filecomp){
         lineno=1;
         err_cnt=warn_cnt=0; cur_if_num=0; in_ifdef=0; in_multi_asm=0;
         in_proc=0; in_main=0; had_main=0; last_was_ret=0; in_switch=0;
         in_include=0; las_was_if=0; in_case=0;
         topgobalstr=toplocalstr=0;

         do_default_defines();

         if(out_of_mem==1)break;

           hnd=fopen(top_filecomp->name,"r");
           if(hnd==NULL){ sprintf(str,"Cannot open file %s",top_filecomp->name);
                          error(str,ERROR); break; }

            outfilename=(char *)malloc(strlen(top_filecomp->name)+5);
            if(outfilename==NULL){ out_of_mem=1; break; }
            malfreecntr++;
            strcpy(outfilename,top_filecomp->name);
            for(cn=strlen(outfilename);cn>0; cn--)
                                       if(outfilename[cn]=='.'){ outfilename[cn]=0;
                                                                 break; }
            if(prg_out)strcat(outfilename,".prg");
            else strcat(outfilename,".asm");
            outfile=fopen(outfilename,"w");
            if(outfile==NULL){ sprintf(str,"Couldn't open output file %s",outfilename);
                                error(str,ERROR); break; }
             fprintf(outfile,";\n");
             fprintf(outfile,"; %s\n",top_filecomp->name);
             fprintf(outfile,";\n");
             fprintf(outfile,"; File generated by SCC %s\n",SCC_ver_);
             fprintf(outfile,"; SCC by Snakessoft/RodneyMcConnell (www.geocities.com/snakessoft)\n");
             fprintf(outfile,";\n");
        if(prg_out==0){
          if(out32)fprintf(outfile,"     .out32\n");
          if(mem_model==1)fprintf(outfile,"      .Model TINY\n");
          else fprintf(outfile,"      .Model NotTINY\n");
          if(out_type==1)fprintf(outfile,"      .outCOM\n");
          if(out_type==2)fprintf(outfile,"      .outLIB\n");
          fprintf(outfile,"      .CaseSensi\n");
          fprintf(outfile,"      .AssumeDSCS\n");
          fprintf(outfile,"      .Stack %lxh\n",stack_size);
          fprintf(outfile,"      .SetMax 0h\n");

          if(out_type==1)fprintf(outfile,"      Jmp Start\n");
          }
         if(compilefile(top_filecomp->name)==1){ fclose(hnd); break; }

         fclose(hnd);

         sprintf(pr_str,"%s Compiled: Errors:%d, Warnings %d, Lines %d\n",filename,err_cnt,warn_cnt,lineno);
         print_f(pr_str);
         

         if(outfile)fclose(outfile);
         outfile=NULL;
         /*if(asm_out==0){
                    sprintf(str,"sasm ");
                    if(out_type==1)strcat(str,"+c ");
                    else if(out_type==2)strcat(str,"+l ");
                    if(out32)strcat(str,"+3 ");
                    if(mem_model==1)strcat(str,"+m1 ");
                    else strcat(str,"+m2 ");
                    strcat(str,outfilename);
                    // cn=system(str);
                    // if(cn==-1)error("Failed to execute sasm.exe",ERROR);
                    // remove(outfilename);
                        }*/
         if(outfilename!=NULL) { free(outfilename); malfreecntr--; outfilename=NULL;}
         free_all();
         tmpf=top_filecomp->prev;
         if(top_filecomp->name){ free(top_filecomp->name);
                                   malfreecntr--; }
         free(top_filecomp);
         malfreecntr--;
         top_filecomp=tmpf;
           }
 if(outfile)fclose(outfile);
return; }

int storefiletocompile(char *name){
  filehold *tmpf;
  int cn;
  char k;

  tmpf=(filehold *)malloc(sizeof(filehold));
  if(tmpf==NULL){ out_of_mem=1; return 1; }
  malfreecntr++;

  tmpf->prev=top_filecomp; top_filecomp=tmpf;  
  
  k=4;
  for(cn=strlen(name); cn>0; cn--)
				  if(name[cn]=='.'){ k=0; break; }
  tmpf->name=(char *)malloc(strlen(name)+1+k);
  if(tmpf->name==NULL){ out_of_mem=1; return 1; }
  malfreecntr++;  
  strcpy(tmpf->name,name);
  if(k>0)strcat(tmpf->name,".c");
return 0; }

void free_storedfilenames(){
  filehold *tmpf;
  while(top_filecomp){
            tmpf=top_filecomp->prev;            
            if(top_filecomp->name){ free(top_filecomp->name);
                                    malfreecntr--; }
            free(top_filecomp);
            malfreecntr--;
            top_filecomp=tmpf;
                }
return; }

long wotisnum(char *str){
 int cntr=0;
 long num=0;
 char k;
 for(;;){
        k=toupper(str[cntr++]);
        if(k>='0' && k<='9'){ num*=0x10; num+=k-'0'; }
        else if(k>='A' && k<='F'){ num*=0x10; num+=(k-'A')+10; }
        else break;
                }
return num; }

int main(int argc,char **argv){
 char had1=0;
 int a;

 asm_out=1;
 outfilename=NULL; outfile=NULL;

 getcwd(inc_dir,theMAXPATH);
 for(a=0; a<strlen(inc_dir); a++) if(inc_dir[a]=='/') inc_dir[a]='\\';

 if(argc>1)
    for(a=argc-1; a>0; a--){
      //if(a>0 && !stricmp(argv[a-1],"+i")){//set include directory
      //                      strcpy(inc_dir,argv[a]);
      //                      a--;
      //                                  }
      if(argv[a][0]=='+' && toupper(argv[a][1])=='I'){
               strcpy(inc_dir,argv[a]+2);
                }
      else if(argv[a][0]=='+' && toupper(argv[a][1])=='S'){//stack size
                                        stack_size=wotisnum(argv[a]+2);
                                                }
      else if(!stricmp(argv[a],"+H")){had1=2; break; }//help
      else if(!stricmp(argv[a],"+3"))out32=1;//32bit
      else if(!stricmp(argv[a],"+C"))mem_model=1, out_type=1;//Com (MUST BE tiny model)
      else if(!stricmp(argv[a],"+L"))out_type=2;//LIB file
      else if(!stricmp(argv[a],"+D"))debug_type=1;//if asm, prints the c command
      //else if(!stricmp(argv[a],"+P"))prg_out=1;//interpreter
      else if(!stricmp(argv[a],"+M1"))mem_model=1;//model tiny
      else if(!stricmp(argv[a],"+M2"))mem_model=2;//model not tiny(default)
      else if(argv[a][0]=='>'){
                        re_dir=1;
                        re_name=argv[a]+1;
                        }
      else {    had1=1;
                if(argv[a][0])if(storefiletocompile(argv[a]))break; }
        }
 if(re_dir){
        re_hnd=fopen(re_name,"w");
        if(re_hnd==NULL)re_dir=0;
        }

 sprintf(pr_str,"SCC %s: C(ish) Compiler\n",SCC_ver_);
 print_f(pr_str);
 sprintf(pr_str,"(c)2001 Snakesoft/Rodney McConnell (snakessoft@yahoo.co.uk, breed@mindless.com)\n");
 print_f(pr_str);
 sprintf(pr_str,"Visit the home of snakessoft http://www.geocities.com/snakessoft\n\n");
 print_f(pr_str);
 if(had1==0){ sprintf(pr_str,"Usage: scc filename.c     [+H For Help]\n");
                print_f(pr_str);if(re_hnd)fclose(re_hnd); exit(-1); }
 if(had1==2){ 
            sprintf(pr_str,"Optional parameters:\n +3 = 32Bit Output\n");
            print_f(pr_str);
            sprintf(pr_str," +C = OutPut Com file\n");
            print_f(pr_str);
            sprintf(pr_str," +L = Output Lib file\n");
            print_f(pr_str);
            //sprintf(pr_str," +P = OutPut PRG file (interpreter)\n");
            //print_f(pr_str);
            sprintf(pr_str," +D = Put Source in Asm file\n");
            print_f(pr_str);
            sprintf(pr_str," +Ixxx = set Include Directory xxx\n");
            print_f(pr_str);
            sprintf(pr_str," +Mx = Memory Model (x= 1 Tiny, 2=Normal)\n");
            print_f(pr_str);
            sprintf(pr_str,"\nUsage: sc filename.c [Optional Parameters]\n");
            print_f(pr_str);
            if(re_hnd)fclose(re_hnd);
            exit(-1);
 					}

 if(out_of_mem==1){ sprintf(pr_str,"Out of Memory...\n"); print_f(pr_str);
                    if(re_hnd)fclose(re_hnd);
                        exit(-1); }

 compilefiles(); 
 if(out_of_mem==1) error("Out of Memory...",ERROR); 
 sprintf(pr_str,"\nSCC Operation complete: Total lines %d\n",total_linecntr);
 print_f(pr_str);
 sprintf(pr_str,"Total Errors in this Operation %d\n",total_err);
 print_f(pr_str);
 sprintf(pr_str,"Total Warnings in this Operation %d\n",total_warn);
 print_f(pr_str);

 free_storedfilenames(); free_all();
 if(outfilename!=NULL) { free(outfilename); malfreecntr--; outfilename=NULL;}
 if(outfile)fclose(outfile);

 if(malfreecntr!=0){ sprintf(pr_str,"Memory Error (%d)\n",malfreecntr);
                     print_f(pr_str);    }
 if(re_hnd)fclose(re_hnd);
return 0; }


