//===== Флаги компиляции #pragma option w32c #stack 0x8000 #argc TRUE //===== Подключаемые модули #include "wapi.h--" #include "enums.h--" #include "data.h--" #include "opcodesc.h--" #include "tree.h--" #include "directiv.h--" #include "tokscan.h--" #include "exe.h--" #include "generate.h--" #include "parser.h--" //===== Главная функция программы main() dword count,pari,cmdline; { stdout=GetStdHandle(STD_OUTPUT_HANDLE); WRITESTR("\n32-Compiler Version 0.01\tXAC (C) 1999."); WRITESTR("\nBased on SPHINX C-- Compiler Peter Cellik (C) 1995.\n"); // Разбор коммандной строки: 32.exe [/map] [/debug] pari=@PARAMCOUNT(); for(count=1;count Unknown command line option: '"); WRITESTR(cmdline); WRITESTR("'\n"); ExitProcess(e_unknowncommandline); } } ELSE{ // Копируем имя исходного файла без расширения EDI=#rawfilename; for(;;){ $LODSB IF(AL=='.')||(AL==0)BREAK; // Есть расширение? $STOSB; } AL=0; $STOSB; lstrcpyA(#inputfile,cmdline); // Копируем имя входного файла с расширением } } IF(rawfilename[0]==0){ errmsg(); WRITESTR("No input file specified"); pari=1; } IF(pari < 2){ WRITESTR("\nUsage: 32.exe [/MAP] [/DEBUG] "); WRITESTR("\n\t/MAP\t<< generate map file"); WRITESTR("\n\t/DEBUG\t<< generate .TDS - debug info file\n"); ExitProcess(e_noinputspecified); } GetMem(); // выделение памяти для компиляции TokInit(); // инициализация списков Compile(); IF( error == 0 )EAX=e_ok; ELSE EAX=e_someerrors; ExitProcess(EAX); } //===== Компилятор Compile() { IF(makemapfile)StartMapfile(); WRITESTR("Compiling ...\n"); Preview(#inputfile); CompileAll(); /*if( endifcount > 0 ) preerror("#endif expected before end of file"); if( outptr%16 != 0 ) // paragraph align the end of the code seg outptr += 16 - outptr%16;*/ DoLink(); // Формирование link IF(posts > 0)DoPosts(); // Обновление всех post адресов SeekUndefined(treestart); if(error==0){ wsprintfA(#mapstr,"\nCOMPILING FINISHED.\tErrors: %d\tLines: %u\n",error,totallines); WRITESTR(#mapstr); runfilesize = outptr-output; postsize += postsize%2; PrintMemsizes(GetStdHandle(STD_OUTPUT_HANDLE)); IF(WriteEXE()==0) { wsprintfA(#mapstr,"\nRun File Saved (%ld bytes).\n",runfilesize); WRITESTR(#mapstr); wsprintfA(#mapstr,"DLL: %d\tAPI: %d \n",DLLcount,APIcount); WRITESTR(#mapstr); } // if(dbg) // dotds(); // do turbo debugger line info } IF(makemapfile)FinishMapfile(); } // ---- Предварительная обработка файла Preview(dword filename) long hold; char trialfilename[FILENAMESIZE]; { lstrcpyA(#trialfilename,filename); hold = LoadInputfile(#trialfilename); IF(EAX==-2)unabletoopen(#trialfilename); IF(hold!=0)ExitProcess(e_cannotopeninput); lstrcpyA(#currentfilename,#trialfilename); module++; IF(module>16; lstrcpyA(#currentfilename,FILENAMESIZE*currmod+#modules); NextChar(); cha2 = cha; inptr2=inptr; IF(tok==tk_proc){ Proc(cpt_near); DoPoststrings(); } ELSE IF(tok==tk_var)GlobalVar(type); ELSE preerror("Bad input format\n"); } ELSE{ // post-переменная без размерности ESI=ptr; DSDWORD[ESI+recnumber] = postsize; DSDWORD[ESI+recpost] = 1; postsize+=TypeSize(type); } } // ---- Компиляция всех процедур и объявлений данных CompileAll() { IF(SearchTree(#tok,#type,#src,#post,"main",#number))AX=3; // Console ELSE IF(SearchTree(#tok,#type,#src,#post,"WinMain",#number))AX=2; // GUI ELSE{ preerror("Main not found"); return; } OptSubSystem=AX; OptEntryPointRVA=OptBaseOfCode+outptr-output; CompileSrc(treeptr); // Компиляция main WHILE(SeekToDo(treestart)){ ESI=treeptr; wsprintfA(#mapstr,"==>%3d %8lXh %8lXh %6Xh\t%s\n",DSDWORD[ESI+rectok], DSDWORD[ESI+rectype],DSDWORD[ESI+recnumber],DSDWORD[ESI+recpost], DSDWORD[ESI+recid]); fprint(mapfile,#mapstr); CompileSrc(treeptr); // Компиляция исходников } IF(makemapfile) fprint(mapfile,"Compile all sources\n"); } // ---- Обработка параметров при объявлении процедуры DeclareParams() dword paramtok,paramtype; { LL: IF(tok==tk_command)GetDirAddr(#Jmp_Commands,number); ELSE EAX=-1; IF(EAX==#CmdShort){ paramtok = tk_param; paramtype=tk_short; } ELSE IF(EAX==#CmdWord){ paramtok = tk_param; paramtype=tk_word; } ELSE IF(EAX==#CmdChar){ paramtok = tk_param; paramtype=tk_char; } ELSE IF(EAX==#CmdByte){ paramtok = tk_param; paramtype=tk_byte; } ELSE IF(EAX==#CmdInt){ paramtok = tk_param; paramtype=tk_int; } ELSE IF(EAX==#CmdDword){ paramtok = tk_param; paramtype=tk_dword; } ELSE{ datatype_expected(); NextTok(); } for(;;){ NextTok(); IF(tok==tk_id ){ paramsize += 4; AddLocalvar(#string,paramtok,paramtype,paramsize); } ELSE IF(tok==tk_semicolon){ NextTok(); $JMP LL } ELSE IF(tok==tk_closebracket)BREAK; ELSE IF(tok!=tk_comma)idexpected(); } } // ---- Обработка локальных переменных при объявлении процедуры DeclareLocals() dword size; dword loctok,loctype; { LL: IF(tok==tk_command)GetDirAddr(#Jmp_Commands,number); IF(EAX==#CmdShort){ loctok = tk_local; loctype=tk_short; size = 2; } else IF(EAX==#CmdWord){ loctok = tk_local; loctype=tk_word; size = 2; } else IF(EAX==#CmdChar){ loctok = tk_local; loctype=tk_char; size = 1; } ELSE IF(EAX==#CmdByte){ loctok = tk_local; loctype=tk_byte; size = 1; } ELSE IF(EAX==#CmdInt){ loctok = tk_local; loctype=tk_int; size = 4; } ELSE IF(EAX==#CmdDword){ loctok = tk_local; loctype=tk_dword; size = 4; } ELSE IF(tok==tk_eof)||(tok==tk_openbrace)$JMP L1 ELSE{ datatype_expected(); NextTok(); goto LL; } for(;;){ NextTok(); IF(tok==tk_id){ AddLocalvar(#string,loctok,loctype,localsize); IF(tok2==tk_openblock){ NextTok(); NextTok(); localsize += DoConstLongMath()*size; EAX=localsize; $TEST EAX,3; IF(NOTZEROFLAG){ EAX=EAX>>2+1<<2; localsize=EAX; // Выравнивание на dword } expecting(tk_closeblock); } ELSE localsize+=4; } ELSE IF(tok==tk_semicolon){ NextTok(); $JMP LL } ELSE IF(tok==tk_openbrace)||(tok==tk_eof)BREAK; ELSE IF(tok!=tk_comma)idexpected(); } L1: IF(paramsize==0)Asm("push ebp; mov ebp,esp;"); wsprintfA(#mapstr,"sub esp,%d;",localsize); Asm(#mapstr); } // ---- Обработка обращения к уже описанной процедуре DoAnyProc() byte s[80]; { wsprintfA(#s,"call %s;",#string); NextTok(); DoParams(); Asm(#s); } // ---- Обработка ранее объвленной, но пока не известной метки dword DoAnyUndefproc(dword expectedreturn) byte s[80]; { IF( tok2 == tk_colon ){ // метка number = outptr-output+OptImageBase+OptBaseOfCode; tok = tk_proc; ESI=treeptr; DSDWORD[ESI+rectok] = tok; DSDWORD[ESI+recnumber] = number; DSDWORD[ESI+recpost] = 0; NextTok(); // move past id NextTok(); // move past : RETURN(tokens); } IF( tok2 == tk_openbracket ){ wsprintfA(#s,"call %s;",#string); NextTok(); DoParams(); Asm(#s); RETURN(tk_dword); } undefinederror(); NextTok(); return(tk_int); } // ---- Обработка обращения к API функции dword doAPI() dword hold; byte s[IDLENGTH]; { if( tok2 == tk_openbracket ){ hold = treeptr; GetVarname(#s); NextTok(); DoParams(); IF(posts>=MAXPOSTS){ preerror("maximum number of API procedure calls exceeded"); return(tokens); } EBX=hold; IF(DSDWORD[EBX+recpost]==0) { // Первый вызов API? DSDWORD[EBX+recpost]=1; // отметим вызов данной API APIcount++; EAX=DSDWORD[EBX+rectype]; // Указатель на DLL, в котором находится API DSDWORD[EAX+recmodline]++; // Увеличим счетчик API, вызванных из DLL } OUTWORD(0x15FF); // call [dword] SetPost(hold,POST_API); OUTDWORD(0); IF(list){ fprint(mapfile,"\t//\tcall "); fprint(mapfile,#s); fprint(mapfile,"\n"); } return(tk_int); } undefinederror(); NextTok(); return(tokens); } // ---- Обработка программного блока {...} void DoBlock() { expecting(tk_openbrace); for(;;){ IF(tok==tk_eof){ unexpectedeof(); BREAK; } IF(tok == tk_closebrace){ NextTok(); BREAK; } DoCommand(); } } // ---- Обработка одной команды внутри блока DoCommand() { LL: FastSearch(#string,#St_Sizes);// Это размер операнда? IF(CARRYFLAG){ // Да: byte,word или dword type=EAX<<1+tk_byte; string[0]=0; tok=tk_var; GOTO LL; } IF(tok==tk_mnemonics){ DoMnemonics(); NextTok(); } else IF(tok==tk_directive){ GetDirAddr(#Jmp_Directives,number); EAX(); } else IF(tok==tk_command){ GetDirAddr(#Jmp_Commands,number); EAX(); } else IF(tok==tk_id){ DoId(tk_void); IF(EAX!=tokens)NextSemiNext(); } else IF(tok==tk_undefproc){ DoAnyUndefproc(tk_void); IF(EAX!=tokens)NextSemiNext(); } else IF(tok==tk_proc){ DoAnyProc(); NextSemiNext(); } else IF(tok==tk_API){ IF(doAPI()!=tokens)NextSemiNext(); } else IF(tok==tk_var)||(tok==tk_local)||(tok==tk_param)||(tok==tk_reg)DoVar(type); ELSE IF(tok==tk_openblock)DoVar(tk_dword); ELSE IF(tok==tk_string){ Macros(); NextSemiNext(); } ELSE IF(tok==tk_locallabel)DoLocalPost(); ELSE IF(tok==tk_openbrace)DoBlock(); ELSE IF(tok==tk_comma)||(tok==tk_semicolon)NextTok(); ELSE IF(tok==tk_eof)unexpectedeof(); /* case tk_from: NextTok(); DoFrom(0); NextSemiNext(); break; case tk_extract: NextTok(); DoExtract(0); SemiNext(); break; */ } // ---- Обработка новых идентификаторов dword DoId(dword expectedreturn) byte s[80]; { IF(tok2 == tk_colon){ // метка? number = outptr-output+OptImageBase+OptBaseOfCode; tok = tk_proc; post = 0; AddToTree(#string); NextTok(); NextTok(); // пропустим идентификатор и : EAX=tokens; } ELSE IF(tok2 == tk_openbracket){ // вызов процедуры wsprintfA(#s,"call %s;",#string); tok = tk_undefproc; number=0; post=1; AddToTree(#string); NextTok(); DoParams(); Asm(#s); EAX=expectedreturn; } ELSE{ undefinederror(); NextTok(); EAX=tk_int; } } // ---- Обработка параметров при вызове процедуры DoParams() { IF(tok==tk_openbracket){ inptr2--; DoParam(); NextTok(); } ELSE expecting(tk_openbracket); } // ---- Обработка ... DoVar(dword vartype) dword next,vtok; byte varName[2*IDLENGTH]; byte varName2[2*IDLENGTH]; { next=1; vtok=GetVarname(#varName); NextTok(); IF(tok==tk_assign){ NextTok(); IF(tok2notstopper()){ DoExpr(#varName,vtok,vartype,"mov"); next=0; } ELSE GetIntoVar(#varName,vtok,vartype); } else IF(tok==tk_minusminus){ // Var--; wsprintfA(#mapstr,"dec %s",#varName); Asm(#mapstr); } else IF(tok==tk_plusplus){ // Var++; wsprintfA(#mapstr,"inc %s",#varName); Asm(#mapstr); } else IF(tok==tk_plusequals){ // Var+=Expr; NextTok(); DoExpr(#varName,tk_var,vartype,"add"); next=1; } else IF(tok==tk_minusequals){ // Var-=Expr; NextTok(); DoExpr(#varName,tk_var,vartype,"sub"); next=1; } else IF(tok==tk_andequals){ // Var&=Expr; NextTok(); DoExpr(#varName,tk_var,vartype,"and"); next=1; } else IF(tok==tk_xorequals){ // Var^=Expr; NextTok(); DoExpr(#varName,tk_var,vartype,"xor"); next=1; } else IF(tok==tk_orequals){ // Var|=Expr; NextTok(); DoExpr(#varName,tk_var,vartype,"or"); next=1; } else if(tok==tk_swap){ // Var>>=Expr; NextTok(); IF(tok == tk_number)wsprintfA(#mapstr,"shr %s,%d",#varName,DoConstMath()); ELSE{ Expression("cl",tk_reg,tk_byte); wsprintfA(#mapstr,"shr %s,cl",#varName); next=0; } Asm(#mapstr); } ELSE operatorexpected(); IF(next)NextSemiNext(); ELSE SemiNext(); } // ---- Обработка ссылок вперед DoPosts() dword addhold,i; { i=0; while(i db 4,'AA',1,'AD',2,'BC',_END // +-----+ // | 'B' | ---> db 6,'AC',3,'AR",_END // +-----+ // | ... | // +-----+ // | 'Z' | ---> db 0,'AK',5,'Z',_END // +-----+ InitList(dword keylist,table) dword ptr; { ptr=LocalAlloc(0x40,SORTSIZE*256); IF(EAX==NULL)outofmemory2(); EDI>'9')EAX=0; ELSE EAX=1; } // ---- Чтение входного файла в буфер long LoadInputfile(dword infile) dword fhandle, size; { fhandle=_lopen(infile,0); IF(EAX==-1){ GetLastError(); return(-2); } EAX=GetFileSize(EAX,0); IF(EAX==-1){ unabletoopen(infile); _lclose(fhandle); return(-1); } size=EAX; input=LocalAlloc(0x40,EAX+2); // Заполненная нулями IF(EAX==NULL){ preerror("Not enough memory for input buffer"); _lclose(fhandle); RETURN(-1); } EAX=_lread(fhandle,input,size); IF(EAX!=size){ preerror("File Read error"); _lclose(fhandle); RETURN(-1); } _lclose(fhandle); inptr = input; inptr2 = input; endoffile = 0; // На начале файла return(0); } // ---- Обработка макроса Macros() byte holdcha; byte s[STRLEN],s2[STRLEN]; { IF(makemapfile){ fprint(mapfile,#string); fprint(mapfile,"\n"); } holdcha=cha2; $PUSH linenum2,inptr2,number,tok2,tok,input,inptr,currmod, linenumber,endoffile,displaytokerrors; lstrcpyA(#s,#string); lstrcpyA(#s2,#string2); input=#s; inptr=input; inptr2=input; endoffile=0; // На начале файла NextChar(); cha2=cha; inptr2=inptr; linenum2 = 1; NextTok(); for(;;){ IF(tok==tk_eof)BREAK; DoCommand(); } lstrcpyA(#string,#s); lstrcpyA(#string2,#s2); $POP displaytokerrors,endoffile,linenumber,currmod,inptr,input,tok,tok2, number,inptr2,linenum2; cha2=holdcha; } // ---- Очистка списка локальных переменных KillLocals() dword ptr1,ptr2; { ptr2=locallist; WHILE( ptr2 != NULL ){ ptr1=ptr2; IF( DSDWORD[EAX+localtok]==tk_locallabel) // Проверка на незакрытые метки localunresolved(EAX+localid); EAX=ptr2; ptr2=DSDWORD[EAX+localnext]; GlobalFree(ptr1); } locallist = NULL; paramsize = 0; localsize = 0; } // ---- Завершение тела процедуры LeaveProc() { IF(localsize > 0)Asm("leave"); ELSE{ IF(paramsize > 0)Asm("pop ebp"); } IF( current_proc_type == cpt_far ){ IF(paramsize == 0)EAX="retf"; ELSE{ wsprintfA(#mapstr,"retf %d;",paramsize); EAX=#mapstr; } } ELSE{ IF(paramsize == 0)EAX="ret"; ELSE{ wsprintfA(#mapstr,"ret %d;",paramsize); EAX=#mapstr; } } Asm(EAX); } // ---- Чтение очередного символа из входного буфера NextChar() { ESI> 0)Asm("push ebp;mov ebp,esp"); IF( tok != tk_openbrace )DeclareLocals(); DoBlock(); // Обработка тела процедуры { ... } LeaveProc(); KillLocals(); } // ---- Запись двойного слова по адресу SetDword(dword ptr, value) { EDI> "); } // ---- expected(dword ch) byte hstr[80]; { wsprintfA(#hstr,"'%c' expected",ch); preerror(#hstr); } // ---- expectederror(dword str) byte hstr[80]; { IF(displaytokerrors){ wsprintfA(#hstr,"'%s' expected",str); preerror(#hstr); } } // ---- Проверка текущего token на заданный тип expecting(dword want) { if(want!=tok){ IF(want==tk_closebracket) expected(')'); else IF(want==tk_openbracket) expected('('); ELSE IF(want==tk_semicolon) expected(';'); ELSE IF(want==tk_colon) expected(':'); ELSE IF(want==tk_openblock) expected('['); ELSE IF(want==tk_closeblock) expected(']'); ELSE IF(want==tk_openbrace) expected('{'); ELSE IF(want==tk_closebrace) expected('}'); ELSE IF(want==tk_comma) expected(','); ELSE preerror("expecting a different token"); } NextTok(); } // ---- /*idalreadydefined() byte holdstr[80]; { wsprintfA(#holdstr,"identifier %s already defined",#string); preerror(#holdstr); NextTok(); } */ // ---- idexpected() { preerror("undefined 'identifier' expected"); } // ---- Внутренняя ошибка компилятора internalerror(dword str) { error++; wsprintfA(#mapstr,"%s(%d)#%d> *** SERIOUS COMPILER INTERNAL ERROR ***\n>%s.\n", #currentfilename,linenumber,error,str); WRITESTR(#mapstr); wsprintfA(#mapstr,"STRING:%s\n",#string); WRITESTR(#mapstr); wsprintfA(#mapstr,"TOK:%d\tPOST:%d\tnumber:%ld\n",tok,post,number); WRITESTR(#mapstr); wsprintfA(#mapstr,"STRING2:%s\n",#string2); WRITESTR(#mapstr); wsprintfA(#mapstr,"TOK2:%d\tPOST2:%d\tnumber2:%ld\n",tok2,post2,number2); WRITESTR(#mapstr); WRITESTR("Oh no.\n"); IF(makemapfile)CloseHandle(mapfile); ExitProcess(e_internalerror); } // ---- localunresolved(dword str) byte holdstr[80]; { wsprintfA(#holdstr,"local jump label '%s' unresolved",str); preerror(#holdstr); } // ---- maxwordpostserror () { preerror("maximum number of word post location references exceeded"); } // ---- /*notyet() { preerror("specified syntax not handled in this version!!!"); } */ // ---- numexpected() { preerror("'number' expected"); } // ---- operatorexpected () { preerror("operator identifier expected"); } // ---- outofmemory() { preerror("Compiler out of memory"); IF( makemapfile )CloseHandle(mapfile); ExitProcess(e_outofmemory); } // ---- outofmemory2() { errmsg(); WRITESTR("Not enough memory for the compiler's buffers.\n"); ExitProcess(e_outofmemory ); } // ---- Ошибка в текущей строке: показ номера строки и имени файла preerror(dword str) { IF(error < maxerrors){ error++; wsprintfA(#mapstr,"%s (%d)#%d> %s.\n",#currentfilename,linenumber,error,str); WRITESTR(#mapstr); IF(makemapfile)fprint(mapfile,#mapstr); } ELSE toomanyerrors(); } // ---- /*regnameerror() { preerror("register name cannot be used as an identifier"); NextTok(); } */ // ---- Требуется строка stringexpected() { preerror("'string' expected"); } // ---- Недопустимый операнд для swap swaperror () { preerror("invalid or incompatable swap item"); } // ---- Предельное число ошибок - выход toomanyerrors() { IF( makemapfile )CloseHandle(mapfile); ExitProcess( e_toomanyerrors ); } // ---- unabletoopen(dword str) byte hstr[80]; { wsprintfA(#hstr,"unable to open file '%s'",str); preerror(#hstr); } // ---- undefinederror() byte holdstr[80]; { wsprintfA(#holdstr,"'%s' undefined",#string); preerror(holdstr); } // ---- unexpectedeof() { preerror("unexpected END OF FILE"); } // ---- warning(dword str) { wsprintfA(#mapstr,"%s (%d)Warning> %s.\n",#currentfilename,linenumber,str); WRITESTR(#mapstr); IF(makemapfile)fprint(mapfile,#mapstr); } /* void TestProc() char buf[20]; { $pushad wsprintfA(#buf,"%08X\n",SSDWORD[EBP+4]); WRITESTR(#buf); $popad } */