diff --git a/data/eng/Makefile b/data/eng/Makefile index f0f704a10a..1737a4bce5 100644 --- a/data/eng/Makefile +++ b/data/eng/Makefile @@ -222,6 +222,7 @@ CMM_PROGRAMS:=\ games/clicks:GAMES/CLICKS:$(PROGS)/games/clicks/trunk/clicks.c-- \ games/FindNumbers:GAMES/FindNumbers:$(PROGS)/games/FindNumbers/trunk/FindNumbers.c-- \ games/mine:GAMES/MINE:$(PROGS)/games/mine/trunk/mine.c--:/MEOS \ + develop/c--:DEVELOP/C--:$(PROGS)/develop/c--/trunk/32.c-- \ # end of list # List of other files to be included in the image file. diff --git a/programs/develop/c--/trunk/32.c-- b/programs/develop/c--/trunk/32.c-- new file mode 100644 index 0000000000..9250ebfc38 --- /dev/null +++ b/programs/develop/c--/trunk/32.c-- @@ -0,0 +1,1441 @@ +//===== Флаги компиляции +#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 +} */ diff --git a/programs/develop/c--/trunk/data.h-- b/programs/develop/c--/trunk/data.h-- new file mode 100644 index 0000000000..da298b2478 --- /dev/null +++ b/programs/develop/c--/trunk/data.h-- @@ -0,0 +1,157 @@ +//===== Глобальные переменные +// ---- Информация по tokens +dword tok=0; +dword type=0; +dword src=0; +dword post=0; +dword number=0; +byte string[STRLEN]=0; +dword tok2=0; +dword type2=0; +dword src2=0; +dword post2=0; +dword number2=0; +dword modline=0; +byte string2[STRLEN]=0; +// ---- Буфера управляющие флаги +dword currmod=0; // Номер текущего файла +dword displaytokerrors=1;// Флаг вывода сообщен й об ош бке +dword error=0; // Содержит номер текущей ошибк +dword maxerrors = 16; // Предел по количеству ошибок +dword makemapfile=0; // Флаг генерац и MAP-файла +dword dbg=0; // Флаг генерац и TDS-файла для TD32 +dword dbginfo=0; // Указатель на буфер dbg информацией (см.описание в enum dbg_...) +dword dbgs=0; // Текущий указатель в dbginfo +dword input=0; // Указатель на начало динамического буфера с входным файлом +dword inptr=0; // Указатель на текущ символ в буфере input +dword inptr2=0; // Копия inptr +dword endoffile=0; // Флаг конца файла +dword totallines=1; // Общее количество откомпилированных строк +dword linenumber=0; // Номер текущей строки +dword linenum2=0; // Номер следующей строки +dword list=0; // Флаг выдачи листинга +dword label=0; // Сквозной номер для локальных меток +dword mapfile=0; // Handle для MAP файла +dword module=0; // Счетчик откомпилированных модулей +dword outptr=0; // Индекс в output +dword output=0; // Указатель на буфер с кодом +dword localsize=0; // Размер стека под локальными переменными +dword posttype=0; // Указатель на тип POST +dword postloc=0; // Указатель на положение в output +dword postnum=0; // Указатель на значение по postloc +dword posts=0; // Номер текущей записи в posttype, postloc и postnum +dword postsize=0; // Суммарный размер всех post-переменных +dword poststrptr=MAXDATA-1; // Индекс для вывода post-строк +dword procedure_start=0;// Адрес начала процедуры +dword runfilesize=0; +dword startptr=0; // Указатель на main() +dword treestart=0; // Указатель на начало списка идентификаторов +dword treeptr=0; // Указатель на текущу запись в списке идент каторов +dword locallist = NULL; // Указатель на начало списка локальных переменных +dword localptr=NULL; // Указатель на текущую запись в списке локальных +dword DLLcount=0; // Счетчик импортированных DLL +dword APIcount=0; // Счетчик используемых API +dword importFlag=0; // Флаг импорта из DLL +dword DLLlist[MAXDLLS]; +byte currentfilename[FILENAMESIZE] = 0; +byte inputfile[FILENAMESIZE]=0; +byte rawfilename[FILENAMESIZE]=0; +byte mapstr[120]=0; +// ---- DOS&PE headers +word exeheader[34]={ + 0x5A4D,0x40,1,0,2,0,0xFFFF,0, + 0,0,0,0,0x40,0,0,0, + 0xC88C,0xD88E,0x0FBA,0xB400,0xCD09,0xB821,0x4C00,0x21CD, + 0x6957,0x336E,0x2032,0x6E6F,0x796C,0x2421,0x40,0, + 0x4550,0}; +// PE Header +//unsigned dword PEsign = 0x4550; +word PEmachine=0x14C; // target machine = Intel 386 +word PEnSections=1; // XAC - only .text!!! number of sections in Sections table +word PEDate=0; +word PEtime=0; +dword PEpSymbolTable=0; // Offset within COFF file of the symbol table +dword PEnSymbols=0; // number of entries in the symbol table +word PEOptHeaderSize=0xE0; // Size of optional header +word PECharacteristics=0x30E; //0x30E 32-bit+... +// Optional header (only in EX image) +word OptMagic=0x10B; // normal executable +byte OptLmajor=2; // Linker major version number +byte OptLminor=0x37; // Linker minor version number +dword OptCodeSize=0; // Size of the code section +dword OptInitDataSize=0; // Size of the initialized data section +dword OptUninitDataSize=0;// Size of the uninitialized data section (BSS) +dword OptEntryPointRVA=0x1000;// Address of entry point, relative to image base +dword OptBaseOfCode=0x1000;// Address realtive to image base +dword OptBaseOfData=0;//Address realtive to image base +dword OptImageBase=0x00400000;// Preferred address of first byte of image +dword OptSectionAlignment=0x1000; +dword OptFileAlignment=0x200; +word OptOSmajor=1; +word OptOSminor=0; +dword OptUserVersion=0; +word OptSubSysMajor=4; +word OptSubSysMinor=0; +dword OptReserved=0; +dword OptImageSize=0x0; // Size of image, including all headers +dword OptHeaderSize=0x200; //DOSheader+PEheader+ObjectTable +dword OptFileChecksum=0; // Image file checksum +word OptSubSystem=3; // 2-GUI; 3-console +word OptDLLflag=0; +dword OptStackReserveSize=0x100000; +dword OptStackCommitSixe=0x1000; +dword OptHeapReserveSize=0x100000; +dword OptHeapCommitSize=0x1000; +dword OptLoaderSize=0; +dword OptNumOfDataDirectories=16; +// Optional header Data Directories +dword OptExportTableAdr=0; +dword OptExportTableSize=0; +dword OptImportTableAdr=0; +dword OptImportTableSize=0; +dword OptResourceTableAdr=0; +dword OptResourceTablesize=0; +dword OptExceptionTableAdr=0; +dword OptExceptionTableSize=0; +dword OptSecurityTableAdr=0; +dword OptSecurityTableSize=0; +dword OptBaseRelocationTableAdr=0; +dword OptBaseRelocationTableSize=0; +dword OptDebugAdr=0; +dword OptDebugSize=0; +dword OptCopyrightAdr=0; +dword OptCopyrightSize=0; +dword OptGlobalPtrAdr=0; +dword OptGlobalPtrSize=0; +dword OptTLStableAdr=0; +dword OptTLStablesize=0; +dword OptLoadConfigTableAdr=0; +dword OptLoadConfigTableSize=0; +dword OptReserved2[10]={0,0,0,0,0,0,0,0,0,0}; +// Sections Table +// TEXT section header +byte TxtSectionName[8]=".text"; +dword TxtVirtualSize=0; +dword TxtRVAoffset=0x1000; +dword TxtSizeOfRawData=0; +dword TxtPointerToRawData=0x200; +dword TxtPointerToRelocs=0; +dword TxtPointerToLinenumbers=0; +word TxtNumberOfRelocs=0; +word TxtNumberOfLinenumbers=0; +dword TxtSectionFlags=0xE00000E0; // can be executed + contain executable code +// ---- Неиниц руемые данные +dword stdout; // Handle to stdout +byte cha,cha2; +dword numberofids; +dword current_proc_type; // Тип текущей процедуры (cpt_near, cpt_far) +dword returntype; // Тип возвращаемого значения (void, byte, word, ...) +dword paramsize; +dword relation; +dword startlabel,endlabel; +byte modules[MAXMDL*FILENAMESIZE]; +dword St_Mnemonics[26]; +dword St_Registers[26]; +dword St_Directives[26]; +dword St_Sizes[26]; +byte Buffer16[64]; // Буфер для сортировк строк diff --git a/programs/develop/c--/trunk/directiv.h-- b/programs/develop/c--/trunk/directiv.h-- new file mode 100644 index 0000000000..3f7aa89970 --- /dev/null +++ b/programs/develop/c--/trunk/directiv.h-- @@ -0,0 +1,986 @@ +byte Directives={ + "IF","ELSE","ENDIF", // Условная компиляция + "INCLUDE","DEFINE", // Включение файла/Определение константы + "IMPORT", // Импорт из DLL по имени API + "IMPORTN", // Импорт из DLL по номеру API + "MAP", // Генерация MAP-файла + "DEBUG", // Генерация отладочной информации + "LIST", // Выдача ASM-листинга + "DLL", // Генерация DLL-файла + "DB","DW","DD", // Типы переменных + "BYTE","CHAR","WORD","SHORT","DWORD","INT", + "ENUM", // Нумерованные константы + "STRUC", // Определение структуры + "CYCLE","RETURN", + "WHILE","DO","INLINE", + "CONTINUE","BREAK", + "DOCASE","CASE","DEFAULT", + "CARRYFLAG","EXTRACT","FROM", + "NOTCARRYFLAG","NOTOVERFLOW","OVERFLOW", + "ZEROFLAG","NOTZEROFLAG",_END}; +// ----- Для tokens, НЕ обрабатываемых через таблицу переключателей +EMPTY() +{ + WRITESTR(#string); + WRITESTR("-ToDo\n"); + NextTok(); +} + +// ---- Возвращает адрес из Jmp_.... +dword GetDirAddr(dword table,num) +{ + EAX=num<<2+table; + EAX=DSDWORD[EAX]; +} + +// ----- Директива #define +DirDefine() +byte holdid[IDLENGTH]; +dword next; +{ + next=1; + NextTok(); + if(tok==tk_id){ + lstrcpyA(#holdid,#string); // Имя константы + NextTok(); + IF(tok==tk_eof) unexpectedeof(); + ELSE IF(tok==tk_number){ + AddConstToTree(#holdid,DoConstLongMath()); next = 0; + } + ELSE IF(tok==tk_minus){ + IF(tok2==tk_number) { + AddConstToTree(#holdid,DoConstLongMath()); + next = 0; + } + } + ELSE IF(tok==tk_undefproc){ + tok = tk_id; AddToTree(#holdid); + } + ELSE AddToTree(#holdid); + } + ELSE idexpected(); + IF(next)NextTok(); +} + +// -- #enum +DirEnum() +dword counter; +byte holdid[IDLENGTH]; +{ + counter=0; + NextTok(); + IF(tok!=tk_openbrace)expected('{'); + for(;;){ + NextTok(); + IF(tok==tk_id){ + lstrcpyA(#holdid,#string); + IF( tok2 == tk_assign ){ + NextTok(); NextTok(); + IF(tok==tk_number)counter=DoConstLongMath(); + ELSE numexpected(); + } + AddConstToTree(#holdid,counter); + counter++; + CONTINUE; + } + IF(tok==tk_comma)CONTINUE; + IF(tok==tk_semicolon)BREAK; + } + NextTok(); +} + +// Директива #import +DirImport() +{ + NextTok(); + IF(tok==tk_string)GetImport(1); // import по имени API-функций + ELSE stringexpected(); + NextTok(); +} + +// Директива #importN +DirImportN() +{ + NextTok(); + IF(tok==tk_string)GetImport(0); // import по имени API-функций + ELSE stringexpected(); + NextTok(); +} + +// ---- Импорт из DLL +GetImport(dword byName) +dword dll; +dword dllpos,base,export,fptr,i,nexports,nsect,delta; +byte path[80],name[120]; +dword tok0,type0,src0,post0; +dword number0; +dword ord; +dword pname1,pname2,j; +{ + pname1 = 0; ord=0; importFlag=1; + IF(DLLcount>=MAXDLLS)outofmemory2(); + IF(SearchTree(#tok0,#type0,#src0,#post0,#string,#number0))return; // DLL уже импортирован + wsprintfA(#name,"%s",#string); + dll=_lopen(#name,0); + IF(dll== -1){ + GetSystemDirectoryA(#path,80); + wsprintfA(#name,"%s\\%s",#path,#string); + dll=_lopen(#name,0); + IF(dll==-1) { + unabletoopen(#string); + return; + } + } + nsect=0; + _llseek(dll,0x3c,0); _lread(dll,#fptr,4); + _llseek(dll,fptr+120,0); _lread(dll,#export,4); // Get export address + IF(export==0) { + wsprintfA(#mapstr,"ERROR: No export directory in file %s.\n",#string); + preerror(#mapstr); return; + } + _llseek(dll,fptr+6,0); _lread(dll,#nsect,2); // Number of sections + delta=export; + i=1; + while(i<=nsect){ + EAX=i; EAX--; EAX=EAX*40; EAX+=260; EAX+=fptr; // fptr+260+40*(i-1) + _llseek(dll,EAX,0); _lread(dll,#base,4); // RVA of section + IF(base<=export){ + EAX=export-base; + IF(EAXi){ + EAX=i; EAX<<=1; EAX+=fptr; // fptr+2*i + _llseek(dll,EAX,0); _lread(dll,#ord,2);// Ordinal number + EAX=i; EAX<<=2; EAX+=base; // base+4*i + _llseek(dll,EAX,0); _lread(dll,#pname1,8); // address of name + _llseek(dll,pname1+delta,0); _lread(dll,#string,pname2-pname1);// address of Ordinal Table + number=ord+1; // при загрузке используется номер на 1 больше экспортируемого из DLL + AddToTree(#string); +// SHOW(#string);SHOW("\n"); + i++; + } + EAX=i; EAX<<=1; EAX+=fptr; // fptr+2*i + _llseek(dll,EAX,0); _lread(dll,#ord,2); // Ordinal number + j=0; + for(;;){ + _llseek(dll,pname2+delta+j,0); EAX=j; + _lread(dll,#string[EAX],1); EAX=j; + IF(string[EAX]==0)BREAK; + j++; + } + number=ord+1; + AddToTree(#string); + tok=tok0; number=number0;src=src0;type=type0;post=post0; + _lclose(dll); + DLLcount++; importFlag=0; +} + +// ----- Директива #include +DirInclude() +byte s[STRLEN],s2[STRLEN]; +{ + NextTok(); + if(tok==tk_string) { + AL=cha2; + $PUSH EAX,linenum2,inptr2,number,tok2,tok,input,inptr,endoffile, + displaytokerrors,currmod; + lstrcpyA(#s,#string); lstrcpyA(#s2,#string2); + Preview(#s); + lstrcpyA(#string,#s); lstrcpyA(#string2,#s2); + $POP currmod,displaytokerrors,endoffile,inptr,input,tok,tok2,number,inptr2, + linenum2,EAX; + cha2=AL; + NextTok(); + } + ELSE stringexpected(); +} + +// ----- Директива list +DirList() +{ + IF(mapfile==0){ + makemapfile=1; + StartMapfile(); + } + list^=1; // Переключение вывода листинга + NextTok(); +} + +// ----- Директива map +DirMap() +{ + makemapfile = 1; StartMapfile(); + NextTok(); +} + +// ---- Обработка глобальной переменной или процедуры с типом +GetProc(dword vartype) +dword src0,beg,count; +byte var_name[IDLENGTH]; +{ + lstrcpyA(#var_name,#string); // Имя процедуры + beg=inptr2; // отметим начало описания + count=0; EAX=0; // ищем начало блока процедуры + modline=currmod<<16+linenum2; + for(;;){ + ESI>0)loop(i)OP(byte 0); + } + else IF(tok==tk_from){ + NextTok(); + SHOW("count = DoFrom(1);\n"); + i=size*elements; + i-=count; + loop(i)OP(byte 0); + NextTok(); + } + else IF(tok==tk_extract){ + NextTok(); + SHOW("count = DoExtract(1);\n"); + i=size*elements; + i-=count; + loop(i)OP(byte 0); + } + else if(tok==tk_openbrace){ // varname={...}; + ESI=ptr; // Откорректируем ранее сделанную запись + DSDWORD[ESI+recnumber] = outptr-output+OptImageBase+OptBaseOfCode; + DSDWORD[ESI+recpost] = 0; + count = 0; + NextTok(); + for(;;){ + IF(tok==tk_closebrace)break; + ELSE IF(tok==tk_comma)NextTok(); + else IF(tok==tk_plus)NextTok(); + else IF(tok==tk_string){ + i=number; + EDX=#string; + loop(i){ + OP(DSBYTE[EDX]); + EDX++; + count++; + } + IF(tok2!=tk_plus){ + OP(byte 0); + count++; + } + NextTok(); + } + else IF(tok==tk_postnumber){ + SetPost(treeptr,POST_DATA); + OUTDWORD(number); + NextTok(); + } + else IF(tok==tk_number){ +G02: + IF(vartype==tk_byte)OP(byte DoConstDwordMath()); + ELSE IF(vartype==tk_word)OUTWORD(DoConstDwordMath()); + ELSE IF(vartype==tk_char)OP(byte DoConstLongMath()); + ELSE IF(vartype==tk_short) OUTWORD(DoConstLongMath()); + ELSE IF(vartype==tk_dword) OUTDWORD(DoConstDwordMath()); + ELSE IF(vartype==tk_int) OUTDWORD(DoConstLongMath()); + count++; + } + ELSE IF(tok==tk_minus){ + NextTok(); + number=-number; + goto G02; + } + ELSE{ + numexpected(); + NextTok(); + } + } + count=elements-count; + IF(count>0){ + loop(count){ + IF(size==1)OP(byte 0); + ELSE IF(size==2)OUTWORD(0); + ELSE IF(size==4)OUTDWORD(0); + } + } + } + ELSE{ +G04: + ESI=ptr; + DSDWORD[ESI+recnumber] = postsize; + DSDWORD[ESI+recpost] = 1; + postsize = elements * size + postsize; + BREAK; + } + } +} + +//===== Таблица переключателей директив +dword Jmp_Directives={ +// "if","else","endif", // Условная компиляция + #EMPTY,#EMPTY,#EMPTY, +// "include","define", // Включение фа ла + #DirInclude,#DirDefine, +// "import", // Импорт из DLL + #DirImport, +// "importN", // Импорт из DLL + #DirImportN, +// "map", // Генерация MAP-файла + #DirMap, +// "debug", // Генерация отладочной информации + #EMPTY, +// "list", // Выдача ASM-листинга + #DirList, +// "dll", // Генерация DLL-файла + #EMPTY, +// "db","dw","dd", // Типы переменных + #EMPTY,#EMPTY,#EMPTY, +// "byte","char","word","short","dword","int", + #EMPTY,#EMPTY,#EMPTY,#EMPTY,#EMPTY,#EMPTY, +// "enum", // Нумерованные константы + #DirEnum, +// "struc", // Определение структуры + #EMPTY, +// "cycle","return", + #EMPTY,#EMPTY, +// "while","do","inline", + #EMPTY,#EMPTY,#EMPTY, +// "continue","break", + #EMPTY,#EMPTY, +// "docase","case","default", + #EMPTY,#EMPTY,#EMPTY, +// "CARRYFLAG","extract","from", + #EMPTY,#EMPTY,#EMPTY, +// "NOTCARRYFLAG","NOTOVERFLOW","OVERFLOW", + #EMPTY,#EMPTY,#EMPTY, +// "ZEROFLAG","NOTZEROFLAG" + #EMPTY,#EMPTY +}; +//===== Таблица переключателей команд +dword Jmp_Commands={ +// "if","else","endif", // Условная компиляция + #CmdIf,#CmdElse,#EMPTY, +// "include","define", // Включение фа ла + #EMPTY,#EMPTY, +// "import","importN", // Импорт из DLL + #EMPTY,#EMPTY, +// "map", // Генерация MAP-файла + #EMPTY, +// "debug", // Генерация отладочно информации + #EMPTY, +// "list", // Выдача ASM-л стинга + #EMPTY, +// "dll", // Генерация DLL-файла + #EMPTY, +// "db","dw","dd", // Типы переменных + #CmdDb,#CmdDw,#CmdDd, +// "byte","char","word","short","dword","int", + #CmdByte,#CmdChar,#CmdWord,#CmdShort,#CmdDword,#CmdInt, +// "enum", // Нумерованные константы + #CmdEnum, +// "struc", // Определение структуры + #EMPTY, +// "cycle","return", + #CmdCycle,#CmdReturn, +// "while","do","inline", + #CmdWhile,#CmdDo,#EMPTY, +// "continue","break", + #CmdContinue,#CmdBreak, +// "docase","case","default", + #CmdDoCase,#CmdCase,#CmdDefault, +// "CARRYFLAG","extract","from", + #CmdCarryFlag,#EMPTY,#EMPTY, +// "NOTCARRYFLAG","NOTOVERFLOW","OVERFLOW", + #CmdNotCarryFlag,#CmdNotOverflow,#CmdOverflow, +// "ZEROFLAG","NOTZEROFLAG" + #CmdZeroFlag,#CmdNotZeroFlag +}; diff --git a/programs/develop/c--/trunk/enums.h-- b/programs/develop/c--/trunk/enums.h-- new file mode 100644 index 0000000000..f5b62eac62 --- /dev/null +++ b/programs/develop/c--/trunk/enums.h-- @@ -0,0 +1,111 @@ +//===== Глобальные константы +#define SHOW "WRITESTR" +// ---- +#define STD_INPUT_HANDLE -10 +#define STD_OUTPUT_HANDLE -11 +#define STD_ERROR_HANDLE -12 +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 +// ---- +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 +// ---- Константы компилятора +#define _END 0x1B +#define FILENAMESIZE 80 +#define IDLENGTH 65 // Длина имени идентификатора, включая NULL-терминатор +#define MAXDATA 512000 // Размер буферов под код и данные +#define MAXDBGS 50000 // Размер буферов под отладочну информацию +#define MAXDLLS 100 +#define MAXINPUT 512000 // Максимальны размер входного файла +#define MAXMDL 100 // Максимальное число includes +#define MAXPOSTS 150000 // Размер буферов под POST обработку +#define NULL 0 +#define SORTSIZE 20 +#define STRLEN 1000 // Длина буфера под token +// ------------------------------------------ +//===== Нумерованные константы +// ---- Коды возврата +enum{ e_ok, e_outofmemory, e_cannotopeninput, e_toomanyerrors, + e_internalerror, e_noinputspecified, e_unknowncommandline, + e_extract, e_cannotopenmapfile, e_someerrors }; +// ---- Коды tokens tk_xxxx +enum{ +tk_eof,tk_number,tk_string,tk_var, +tk_id, +tk_db,tk_dw,tk_dd,tk_dq, // Типы переменных +tk_byte,tk_char,tk_word,tk_short, +tk_dword,tk_int, +tk_enum, // Нумерованные константы +tk_struc, // Определение структуры +tk_if,tk_else,tk_endif, // Условная компиляция +tk_include,tk_define, // Включение фа ла//Определение константы +tk_import, // Импорт из DLL +tk_map, // Генерация MAP-файла +tk_debug, // Генерация отладочной информации +tk_list, // Выдача ASM-листинга +tk_dll, // Генерация DLL-файла +tk_loop,tk_return,tk_do, +tk_while,tk_void, +tk_continue,tk_break, +tk_docase,tk_case,tk_default, +tk_carryflag,tk_extract,tk_FALSE,tk_from, +tk_notcarryflag,tk_notoverflow,tk_overflow,tk_TRUE, +tk_zeroflag,tk_notzeroflag, +tk_assign,tk_swap, +tk_minus,tk_plus, +tk_minusminus,tk_plusplus,tk_mult,tk_div,tk_mod, +tk_multminus,tk_divminus,tk_modminus,tk_rr,tk_ll, +tk_rrminus, +tk_llminus, +tk_minusequals,tk_plusequals,tk_rrequals,tk_llequals, +tk_or,tk_and,tk_xor,tk_not, +tk_orminus, +tk_andminus,tk_xorminus, +tk_orequals,tk_andequals,tk_xorequals, +tk_equalto, +tk_notequal,tk_greater,tk_greaterequal,tk_less, +tk_lessequal, +tk_oror,tk_andand,tk_openbrace,tk_closebrace, +tk_openbracket,tk_closebracket,tk_openblock,tk_closeblock, +tk_colon,tk_semicolon,tk_comma,tk_period, +tk_dollar,tk_question,tk_tilda, +tk_reg,tk_controlreg,tk_debugreg,tk_testreg,tk_seg, +tk_undefproc,tk_proc, +tk_postnumber, +tk_local,tk_locallabel,tk_param,tk_locnumber, +tk_DLL,tk_API,tk_directive,tk_command,tk_mnemonics, +tokens +}; +// ---- Кодировка типа процедур +enum{ cpt_near, cpt_far }; +// ---- Кодировка POST записей +enum { POST_CALL=1, POST_API, POST_DATA, POST_LOC, POST_STR }; +// ---- Описание структуры в dbginfo: dbg_... +enum{ dbg_mod=0, // Номер модуля + dbg_line=4, // Номер строк в модуле + dbg_loc=8, // Позиция в EXE-файле + dbg_size=12}; // размер структуры +// ---- Описание структуры idrec +enum{ left=0, // Указатель на idrec + right=4, // Указатель на idrec + recid=8, // Имя идентификатора + newid=recid+4, // Указатель на алиас для recid + rectok=newid+4, // Номер token + rectype=rectok+4, // Тип token: void, byte, char, word, ... + recsrc=rectype+4, // Исходный текст + recpost=recsrc+4, // Флаг POST переменной + recnumber=recpost+4, // Значение или offset в recsrc + recmodline=recnumber+4,// Номер модуля и строки + recsize=recnumber+4};// размер структуры +// ---- Описание структуры localrec +enum{ localnext=0, // Указатель на следующую localrec + localid=4, // Имя локально переменной + localtok=localid+IDLENGTH,// Значение token + localtype=localtok+4, // тип переменной + localnumber=localtype+4, // Позиция в стеке + local_size=localnumber+4}; // Размер структуры diff --git a/programs/develop/c--/trunk/examples/docase.c- b/programs/develop/c--/trunk/examples/docase.c- new file mode 100644 index 0000000000..d4240a3ba6 --- /dev/null +++ b/programs/develop/c--/trunk/examples/docase.c- @@ -0,0 +1,17 @@ +#map +#debug +#list +main() // execution always starts at main () +{ +docase{ + EBX+=80; + case(ECX==10) +//#list + EBX=10; + case(EBX<5){ + ECX=5; continue;} + default + EDX+=8; + } +EAX=9; +} \ No newline at end of file diff --git a/programs/develop/c--/trunk/examples/docase.map b/programs/develop/c--/trunk/examples/docase.map new file mode 100644 index 0000000000..c5dd268ad7 --- /dev/null +++ b/programs/develop/c--/trunk/examples/docase.map @@ -0,0 +1,71 @@ +MAP FILE FOR DOCASE.EXE + +{ +docase{ + EBX+=80; + // @L0: + // add EBX,80 + case(ECX==10) + // mov eax,ECX + // cmp eax,0xa + // sete al + // movzx eax,al +//#list + // test eax,eax;jz @L2 + EBX=10; + // mov EBX,10 + case(EBX<5){ + // jmp @L1 + // @L2: + // mov eax,EBX + // cmp eax,0x5 + // setl al + // movzx eax,al + // test eax,eax;jz @L3 + ECX=5; continue;} + // mov ECX,5 + // jmp @L0 + default + EDX+=8; + // jmp @L1 + // @L3: + // add EDX,8 + } +EAX=9; + // @L1: + // mov EAX,9 +} + // ret +Compile all sources + +ALL GLOBAL IDENTIFIERS LIST: +tok type number post IDENTIFIER +104 1Fh 401000h 0h main +File:DOCASE.C-, line=4: +() // execution always starts at main () +{ +docase{ + EBX+=80; + case(ECX==10) +//#list + EBX=10; + case(EBX<5){ + ECX=5; continue;} + default + EDX+=8; + } +EAX=9; +} + + 1 Unique Global Identifiers. + +GLOBAL CONSTANT IDENTIFIER LIST: + + 0 Unique Global Constant Value Identifiers. + +Component Sizes: +Code:128 bytes, Post: 0 bytes +Run file size: 128 bytes + +END OF MAP FILE FOR DOCASE.EXE + diff --git a/programs/develop/c--/trunk/exe.h-- b/programs/develop/c--/trunk/exe.h-- new file mode 100644 index 0000000000..75242f365e --- /dev/null +++ b/programs/develop/c--/trunk/exe.h-- @@ -0,0 +1,145 @@ +// ---- Формирование IMPORT секции +void DoLink() +dword i,j,DirTable,AddrTable,dllName,apiName,byName,hold; +dword dll,api; +{ + OptImportTableAdr=outptr-output; + DirTable=outptr; + if(APIcount==0){ + OUTDWORD(outptr -output + OptBaseOfCode + 4); + OUTDWORD(0x80000001); + OUTDWORD(0); + OUTDWORD(DirTable-output+40+OptBaseOfCode); + OUTDWORD(outptr-output + OptBaseOfCode - 12); + DirTable=outptr; + outptr = outptr + 20; + OUTDWORD('resu'); + OUTDWORD('d.23'); + OUTDWORD('ll'); +// OUTDWORD(0x72657375); OUTDWORD(0x642E3233); OUTDWORD(0x6C6C); + apiName=outptr; + } + else { + EAX=DLLcount+1*20; + outptr+=EAX; // на начало LookupTables + i=0; + while(i= MAXPOSTS)maxwordpostserror(); + EBX=posts<<2+postloc; + DSDWORD[EBX] = outptr; + EBX=posts<<2+postnum; + DSDWORD[EBX] = ref; + EBX=posts<<2+posttype; + DSDWORD[EBX] = ptype; + posts++; +} + +// ---- Пропуск до следующей записи в шаблоне инструкции +SCDEND() +{ + $LODSB + IF(AL!=0){ + $CMP AL,_END + $JNE SCDEND + illegaloperand(); + $POP EAX; // Выход из MapOperands + } +} + +GETSCALING() +{ + NextTok(); // Получим значение масштабного коэффициента + IF(tok==tk_number){ +DoScale: + EA_SCALE=number; // Scale + EA_SIBFLAG=1; // Отметим наличие Sib в 32-битном EA + } + ELSE preerror("ASM: Illegal scaling value\n"); +} + +// ---- Поиск в шаблоне подходящей к операнду записи (для однооперандной инструкции) +GETOL1() +{ + if(DSBYTE[ESI]!=0){ // Инструкция JMP - не проверяем совпадение размеров +G4: + $LODSB + AH=AL&NOLBITS; // Исключим число операндов + if(NOTZEROFLAG){// Это все-таки JMP... + DL=AL&OPBITS; // Маска для типа операнда + IF(DL!=SOO){ // В поле размера операнда содержится информация о типе операнда? + AL&=OLBITS; // Выделим количество операндов + IF(AL!=OL1){ // Шаблон для инструкции с одним операндом? +G3: + do{ + $LODSB // Просмотрим следующую запись шаблона + IF(AL==0)GOTO G4; // Конец записи? + }while(AL!=_END); // Это конец шаблона? + illegaloperand(); // Нет подходящей записи для такой мнемоники + $POP EAX; + $RET // Выход из MapOperands + } + // Обработка записи шаблона +G2: + AL=AH&TRANSBITS; // Выделим размер операнда + $CMP AL,_D + $JBE G5 // Операнд м.б. размера: byte, word, dword + $CMP AL,_OW + $JNE J0 + OPERANDSIZE=_W; + GOTO G40; +J0: + $CMP AL,_OD; + $JNE J1 + OPERANDSIZE=_D; + GOTO G40; +J1: + $CMP AL,NB + $JB G90 // Операнд м.б. размера WB,DW OR BW. + AL-=NB; // Пересчитаем для фиксированных размеров: NB->B,OW->W, AF->D +G90: + $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? + $JNE G3 // Нет - смотрим следующую запись в шаблоне + GOTO G40; // Размеры совпали - продолжим +G5: + $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? + $JA G3 // Нет - смотрим следующую запись в шаблоне + EBX=0; // WBIT/RANDFLAG=0 + DL=AL; + AL=OPERANDSIZE; + IF(DL==_B)&&(AL!=_B)BL++; +// $CMP DL,_B // В шаблоне byte? +// $JNE G20 +// $CMP AL,_B // Операнд byte? +// $JE G20 +// BL++; // W-бит=TRUE +//G20: + $CMP AL,_W // В шаблоне word? + $JNE G30 + $JA G30 + BH++; // Операнд обязательно д.б. word - требуется префикс RAND +G30: + WBIT=BL; + RANDFLAG=BH; // Запомним информацию о префиксе и W-бите +G40: + AH&=NTRANSBITS; // Оставим SOO биты + } + } + } + AL=AH; // Возвратим SOO поле +} + +// ---- Разборка шаблона для двухоперандной инструкции +GETOL2() +{ +G7: + $LODSB // Получим байт из шаблона + AH=AL; + AL&=OLBITS; // Выделим число операндов + $CMP AL,OL2 // Число операндов = 2? + $JE G8 // Да - начнем проверку +G9: + $LODSB // Поиск следующей записи в шаблоне + $OR AL,AL // Конец записи? + $JZ G7 // Да - проверим новую запись + $CMP AL,_END // Конец шаблона? + $JNE G9 // Смотри дальше иначе - ошибка + toomuchoperands(); + $POP EAX; + $RET // Выход из MapOperands +G8: + AH&=NOLBITS; // Исключим число операндов + AL=AH; + AL&=TRANSBITS; // Выделим размер операнда + $CMP AL,_D + $JBE G100 // Операнд м.б. размера: byte, word, dword +G94: + $CMP AL,NB + $JB J0 //G95 // Операнд м.б. размера WB,DW OR BW. + AL-=NB; // Пересчитаем для фиксированных размеров: NB->B,OW->W, AF->D +G95: + $CMP AL,OPERANDSIZE // Размер операнда и размер из шаблона совпали? + $JNE G9 // Размеры не совпали - ищем следующую запись + $JMP G11 // Размеры совпали - продолжим +J0: + $CMP OPDESC[0],CO + $JNE J1 + $CMP AL,WB; + $JNE J1 + OPCONSTSIZE[0]=_W; + OPCONSTSIZE[1]=_B; + GOTO G11; +J1: + $CMP AL,_DW; + $JNE J2; + RANDFLAG=0; + OPCONSTSIZE[0]=_D;// OPCONSTSIZE[1]=_W; + GOTO G11; +J2: + $CMP AL,BW; + $JNE G95 + OPCONSTSIZE[0]=_B; + OPCONSTSIZE[1]=_W; + GOTO G11; +G100: + $CMP OPERANDSIZE,_D + $JA NEAR G9 // Размер операнда > dword - на следующую запись + $CMP OPERANDSIZE,AL + $JB NEAR G9 // Размеры не совпали - ищем следующую запись + EBX=0; + DL=AL; + AL=OPERANDSIZE; + $CMP DL,_B // Размер в шаблоне = byte? + $JNE G50 + $CMP AL,_B // Размер операнда = byte? + $JE G50 + BL++; // W-бит=TRUE +G50: + $CMP AL,_W // В шаблоне word? + $JNE G60 + $JA G60 + BH++; // Операнд обязательно д.б. word - требуется префикс RAND +G60: + WBIT=BL; + RANDFLAG=BH; +G11: + AH&=NTRANSBITS; + AL=AH; // Возвратим SOO поле +} + +// ---- Разборка шаблона для трехоперандной инструкции +GETOL3() +{ +G12: + $LODSB + AH=AL; + AL&=OLBITS; + $CMP AL,OL3 + $JE G13 +G14: + $LODSB //TRY NEXT ENTRY. + $OR AL,AL + $JZ G12 + $CMP AL,_END + $JNE G14 + toomuchoperands(); + $POP EAX; + $RET // Выход из MapOperands +G13: + AH&=NOLBITS; + $CMP OPERANDSIZE,_D //DWORD ? + $JE G15 + $CMP OPERANDSIZE,_W //WORD ? + $JE G16 + preerror("ASM: This instruction required a WORD/DWORD operand\n"); + $RET +G16: + RANDFLAG=1; +G15: + AL=AH&0xE0; +} + +// ---- +CREATE_EA() +{ + EA_M=AL&7; + EA_X=3; +} + +// ---- +CREATE_R() +{ + EA_R=AL&7; +} + +// ---- Генеррация ModRM и Sib +GETMODRMBYTE() +{ + DL=EALENGTH; // Количество регистров в EA + $OR DL,DL // Нет регистров в EA? + $JE NEAR C11 // Да + $TEST EADESC,_W+_D*8 + $JE NEAR E1 // 8-битные регистры нельзя применать в адресе + $TEST EADESC,_W*8 // 16-битный регистр? + $JNE NEAR E4 // 16-битная адресация не разрешена + GETEADISPX(); + $CMP DH,2 + $JNZ X00 + EAX=opDescInd; + OPCONSTSIZE[EAX]=_D; // Обязательно 32-битный disp +X00: + DL--; // 1 регистр? + $JNE N1 // нет... + AL=EADESC&7; + $CMP EA_SIBFLAG,1 // Флаг наличия Sib в 32-битном EA + $JNE L2 // Нет Sib + EA_R2=5; // Фиксируем базовый регистр + EA_M=4; + EA_I=AL; + EDX=opDescInd; + $CMP OPCONSTFLAG[EDX],1 // Используем disp? + $JE L1 + EAX=0; + OPCONSTFLAG[EDX]=1; + EDX<<=2; + OPCONST[EDX]=EAX; // disp=0 в EA +L1: + EDX=opDescInd; + OPCONSTSIZE[EDX]=_D; + EA_X=0; //EA_X=AL; + $RET +L2: + EA_M=AL; + $RET +N1: + EA_M=4; //2 REGISTERS USED. + EA_SIBFLAG=1; + AL=EADESC[1]>>3; + $CMP AL,_W + $JE E5 //ERROR: INDEX REGISTER ISN'T OF SIZE DWORD + AL=EADESC; + AH=EADESC[1]; + EAX&=0x707; + $CMP AH,5 //CAN'T USE BP AS INDEX. + $JE E6 + EA_R2=AL; + EA_I=AH; + $RET +E1: + preerror("ASM: You can't use byte registers in addresses\n"); + $RET +E4: + preerror("ASM: 16-bit addressing mode not allowed\n"); + $RET +E5: + preerror("ASM: You must use a 32-bit registers for scaling\n"); + $RET +E6: + preerror("ASM: You can't use EBP as an index\n"); + $RET +C11: + EA_X=0; + EA_M=5; + ECX=opDescInd; + AL=OPCONSTSIZE[ECX]; + IF(AL==_B)OPCONSTSIZE[ECX]=_D; + ELSE IF(AL==_W)ADDRFLAG=1; +} + +// ---- +GETEADISPX() +{ //CREATE X NIBBLE OF DISPLACEMENT SIZE. + DH=0; + $PUSH ECX + ECX=opDescInd; + IF(OPCONSTFLAG[ECX]==1){ + AL=OPCONSTSIZE[ECX]; + DH=2; //(D)WORD DISPLACEMENT + IF(AL==_B)DH--; //SBYTE DISPLACEMENT + } + EA_X=DH; + $POP ECX +} + +// ---- Инициализация буфера ассемблера +INIT_LINE() +{ + ECX=#opDescInd-#OPERANDSIZE; + AL=0; + EDI=#OPERANDSIZE; + $REP $STOSB; + AL=255; + OPERANDSIZE=AL; + SEGREGISTER=AL; +} + +// ---- Запись переопределения сегмента +WRITEOVERRIDE() +{ + EBX=OVERRIDE; + IF(BL!=0){ + AL=OVERRIDETAB[EBX]-rES; + OP(); + } +} + +// ---- Запись префикса размерности операнда +WRITERAND() +{ + $PUSH EAX + IF(RANDFLAG==1){ + AL=0x66; + OP(); + } + $POP EAX +} + +// ---- Запись константы: CL=TYPE; EDI указатель на значение +WRITECONST() +{ + IF(CL==_B)CL=1; + ELSE IF(CL==_W)CL=2; + ELSE IF(CL==_D)CL=4; + ELSE CL++; + loop(ECX){ + AL=DSBYTE[EDI]; + EDI++; + OP(); + } +} + +// ---- Обработка Override +GETOVERRIDE() +{ + IF(tok==tk_seg)&&(tok2==tk_colon){ + IF(OVERRIDE==0){ + OVERRIDE=number; + $STC // ∙ сегментного регистра + } + ELSE preerror("ASM: Double segment override"); + NextTok(); + NextTok(); // Пропускаем : + } +} + +// ---- Вычисление размера операнда: _B,_W,_D,WB,_DW & RAND-FLAG. AL=SIZE +DEF_OPSIZE() +{ + AH=OPERANDSIZE; + IF(AH==255){ + OPERANDSIZE=AL; // Один операнд + return; + } + IF(AH==AL)return; // Размеры совпадают + IF(AX==0X100){ // RW,RB ? + RANDFLAG=1;// OPERANDSIZE=WB; + return; + } + IF(AX==0X200){ // RD,RB ? + IF(ACTUALMNEMDESC==#PCOMMANDS3_){ +// OPERANDSIZE=_D; + return; + } + OPERANDSIZE=WB; + return; + } + IF(AX==0X201){ //RD,RW + RANDFLAG=1; + OPERANDSIZE=_DW; + } +} + +// ---- Запись префикса адресации +WRITEADDR() +{ + $PUSH EAX + IF(ADDRFLAG==1){ + AL=0x67; + OP(); + } + $POP EAX +} + +// ---- Определение размерности константы +DefConstSize() +{ // Определим размерность константы + EBX=opDescInd; + DL=_D; + IF(OPPOST[EBX]==0){ + EBX=opDescInd<<2; + EAX=OPCONST[EBX]; + DL=_B; // byte + IF(long EAX>=-128){ // -128 + $CMP EAX,0XFF // 255 + $JNG W2 + } + DL++; // _W - word + IF(long EAX>=-32768){ + $CMP EAX,0XFFFF // 65535 + $JNG W2 + } + DL++; // _D - dword + } +W2: + EBX=opDescInd; + OPCONSTSIZE[EBX]=DL; + OPCONSTFLAG[EBX]=1; +} + +// ---- Обработка мнемоники ассемблера +DoMnemonics() +{ + opDescInd=0; + EADescInd=0; + INIT_LINE(); // Очистка буферов + IF(number<24){ + IF(number<8)EBX=#PCOMMANDS1; + ELSE IF(number<12){ + number-=8; + EBX=#PCOMMANDS2; + } + ELSE IF(number<20){ + number-=12; + EBX=#PCOMMANDS3; + } + ELSE{ + number-=20; + EBX=#PCOMMANDS4; + } + number+=DSBYTE[EBX]; + PFLAG=number; + EBX++; + } + ELSE{ + number-=24; + EBX=number<<2; + EBX=TAB_MNEMONICS[EBX]; + IF(EBX>=#T_DAA)&&(EBX<#T_NOT){ // Проверим на наличие инструкции без операндов + ACTUALMNEMDESC=EBX; + IF(tok2==tk_semicolon)NextTok(); + ESI=ACTUALMNEMDESC; + $JMP CreateCode;// Генерация кода для инструкции без операндов + } + } + ACTUALMNEMDESC=EBX; // Запомним указатель на текущий шаблон мнемоники + for(;;){ // Цикл анализа операндов + prevTok=tok; + NextTok(); // Следующий операнд + FastSearch(#string,#St_Sizes);// Это размер операнда? + IF(CARRYFLAG){ // Да: byte,word или dword + OPERANDSIZE=AL; // Запомним _B,_W,_D + continue; + } + GETOVERRIDE(); // Обработка конструкции SEG: +ContLine: // Точка для продолжения обработки текущего + IF(tok==tk_eof)||(tok==tk_semicolon){ + EBX=opDescInd; + IF(OPDESC[EBX]==E){ // Обработка в EA? + DefConstSize(); + GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. + } + IF(prevTok!=tk_mnemonics){ // Были операнды + OPLENGTH++; + IF(OPERANDSIZE==255){ + OPERANDSIZE=_D; // Принудительно установим dword + } + } + $JMP MapOperands + } + else IF(tok==tk_comma){ + IF(opDescInd==3){ + toomuchoperands(); + break; + } + EBX=opDescInd; + IF(OPDESC[EBX]==E){ // Обработка в EA? + DefConstSize(); + GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. + } + opDescInd++; + OPLENGTH++; + } + else IF(tok==tk_openblock){ + EBX=opDescInd; + OPDESC[EBX]=E; // Отметим, что работаем с EA операндом + } + else IF(tok==tk_closeblock){ // ] + DefConstSize(); + GETMODRMBYTE(); // EOL - GENERATE MODRM OPCODE BYTE. + } + else IF(tok==tk_minus){ + IF(tok2 == tk_number){ + NextTok(); + number = -number; + $JMP ContLine; // Продолжим docase без выборки след.token + } + } + else IF(tok==tk_plus) continue; + else IF(tok==tk_mult){ // * + GETSCALING(); // Указан масшаб в Sib + } + else if(tok==tk_reg){ // Обработка регистра +G0: + EBX=opDescInd; + IF(OPDESC[EBX]==E){ // Обработка в EA? + IF(type==tk_byte){ + preerror("ASM: No byte register in address\n"); + return; + } + IF(EALENGTH<2){ // Количество регистров в EA < 2 ? + EALENGTH++; // Отметим, что есть еще один регистр в EA + EBX=EADescInd; + EADESC[EBX]=number; // Запомним ∙ регистра + EADescInd++; + } + ELSE{ // Слишком много регистров в EA + preerror("ASM: too much registers in combination\n"); + return; + } + } + ELSE{ + OPDATA[EBX]=number; // ∙ регистра + OPDESC[EBX]=R; + AH=number&7; + EA_R=AH; + IF(opDescInd!=2){ + AL>>=3; + DEF_OPSIZE(); + } + } + } + else IF(tok==tk_number) { // Обработка константы + IF(tok2==tk_mult){ + DoScale(); + NextTok(); + continue; + } +NUM: + EBX=opDescInd<<2; + OPCONST[EBX]+=number; // Запомним константу + DefConstSize(); // Определим размерность константы + IF(OPDESC[EBX]!=E) // Константа в EA? + OPDESC[EBX]=CO; + } + else IF(tok==tk_postnumber){ + EBX=opDescInd; + OPPOST[EBX]=POST_DATA; + EBX<<=2; + OPPOSTREF[EBX]=treeptr; + ESI=treeptr; + DSDWORD[ESI+recpost]++; + GOTO NUM; + } + else IF(tok==tk_proc){ + IF(post){ + EBX=opDescInd; + OPPOST[EBX]=POST_CALL; + EBX<<=2; + OPPOSTREF[EBX]=treeptr; + ESI=treeptr; + DSDWORD[ESI+recpost]++; + } + $JMP NUM + } + else IF(tok==tk_locallabel){ + EBX=opDescInd<<2; + OPPOSTREF[EBX]=localptr; +I2: + EBX=opDescInd; + $CMP ACTUALMNEMDESC,#T_JCXZ; + $JB I1 + $CMP ACTUALMNEMDESC,#T_CALLFAR; + $JA I1 + OPPOST[EBX]=POST_CALL; + $JMP NUM +I1: + OPPOST[EBX]=POST_DATA; + AL=_D; + DEF_OPSIZE(); + $JMP PARSE_EA1 + } + else IF(tok==tk_undefproc){ +I0: + EBX=opDescInd<<2; + OPPOSTREF[EBX]=treeptr; + GOTO I2; + } + else IF(tok==tk_id){ + tok = tk_undefproc; + post = 1; + number=0; + AddToTree(#string); + GOTO I0; + } + else IF(tok==tk_var){ // Инициализация EA с константой: EA+disp + AL=type-tk_byte>>1; // AL=размер адресуемого операнда (_B,_W,_D) + DEF_OPSIZE(); + EBX=opDescInd; + IF(post){ + EBX<<=2; + OPPOSTREF[EBX]=treeptr; + EBX=opDescInd; + OPPOST[EBX]=POST_DATA; + ESI=treeptr; + DSDWORD[ESI+recpost]++; + } +PARSE_EA1: + OPDESC[EBX]=E; + OPCONSTFLAG[EBX]=1; // Отметим, что работаем с EA операндом + EBX<<=2; + OPCONST[EBX]+=number; // Запомним адрес + } + else IF(tok==tk_seg){ + EBX=opDescInd; + OPDATA[EBX]=number-rES; // ∙ сегментного регистра + SEGREGISTER=AL; + AL<<=3; // Создать код для XSM поля + EA_S=AL; + OPDESC[EBX]=_SR; + AL=_W; + DEF_OPSIZE(); + } + else IF(tok==tk_param)||(tok==tk_local){ +PARSE_PAR: + AL=type-tk_byte>>1; + DEF_OPSIZE(); + EBX=opDescInd; + OPDESC[EBX]=E; + EBX<<=2; // Отметим, что работаем с EA операндом + OPCONST[EBX]+=number; // Запомним адрес + OPCONSTFLAG[EBX]=1; + number=rEBP; + $JMP G0; + } + else IF(tok==tk_controlreg){ + EBX=opDescInd; + OPDESC[EBX]=SYSR; + SYSRNUM=number; + IF(AL==4)SYSRTYPE=_CR4; + ELSE{ + SYSRTYPE=_CR; + SYSRCODE=0; + } + } + ELSE IF(tok==tk_debugreg){ + EBX=opDescInd; + OPDESC[EBX]=SYSR; + SYSRNUM=number; + SYSRTYPE=_DR; + SYSRCODE=1; + } + ELSE IF(tok==tk_testreg){ + EBX=opDescInd; + OPDESC[EBX]=SYSR; + SYSRNUM=number; + SYSRTYPE=_TR; + SYSRCODE=4; + } + ELSE preerror("ASM: Syntax error\n"); + } +} + +CreateScale() +{ + IF(ADDRFLAG)return; + if(EA_SIBFLAG){ // Флаг наличия Sib в 32-битном EA + IF(EA_SCALE==0){ // Отсутствует + EA_SCALING=0; + } + else IF(EA_SCALE==1)EA_SCALING=0; + else IF(EA_SCALE==2)EA_SCALING=0x40; + ELSE IF(EA_SCALE==4)EA_SCALING=0x80; + ELSE IF(EA_SCALE==8)EA_SCALING=0xC0; + ELSE{ + EA_SCALING=0; + IF(EA_SCALE>255)OP(byte 0x69); + ELSE OP(byte 0x6B); + AL=EA_I<<3|EA_I|0xC0; + OP(byte AL); + IF(EA_SCALE>255)OUTDWORD(EA_SCALE); + ELSE OP(byte EA_SCALE); + } + } +} + +// ---- Генерация кода. ESI=ptr на запись о описание мнемоники (запись типа T_...) +CreateCode() +{ + WRITEOVERRIDE(); + CreateScale(); + IF(ADDRFLAG==1){ //ADDR: PREFIX ? + OP(byte 0x67); + } + IF(RANDFLAG==1){ //RAND: PREFIX ? + OP(byte 0x66); + } + EDI=ESI; + IF(ACTUALMNEMDESC==#T_TEST)DBIT=0; //DON'T ADD ANYTHING IF TESTING + $SHL DBIT,1 //SHIFT D-BIT TO THE RIGHT POSITION. +NEXT_DESC_BYTE: // Обработка байта из дескриптора мнемоники + EBX=0; + BL=DSBYTE[EDI]; + EDI++; +NB3: + $CMP BL,X7M + $JA NC3 + $CMP BL,X0M + $JB N24 + AH=BL-X0M; + AL=EA_X<<3|AH<<3|EA_M; + OP(); + GOTO NEXT_DESC_BYTE; +N24: + EBX<<=2; + EBX+=#Dsc_Jump; + $JMP NEAR DSDWORD[EBX] +NC3: + $CMP BL,_END + $JNE E42 + $JMP CreateConstants // Конец шаблона для мнемоники +E42: + preerror("Descriptor damaged\n"); + return; +// OpCode - 1 байт +Dsc_O: + AL=DSBYTE[EDI]+WBIT+DBIT; + EDI++; + OP(); + GOTO NEXT_DESC_BYTE; +// OpCode - 1 слово +Dsc_OW: + AL=DSBYTE[EDI]; + EDI++; + OP(); + AL=DSBYTE[EDI]+WBIT+DBIT; + EDI++; + OP(); + $JMP NEXT_DESC_BYTE +// OpCode - 1 байт и следующий байт, заданный 8-ричной строкой +Dsc_OS: + AL=DSBYTE[EDI]; + EDI++; + OP(); +// OpCode - 8-ричная строка с кодом +Dsc_S: +S01: + CL=3; + EAX=0; + loop(CL){ + AL=DSBYTE[EDI]; + EDI++; + IF(AL=='X'){ //X CHAR + AL=EA_X; + } + ELSE IF(AL=='R')AL=EA_R; + ELSE IF(AL=='M')AL=EA_M; + ELSE IF(AL=='S')AL=SEGREGISTER; + ELSE IF(AL=='N')AL=SYSRNUM; + ELSE IF(AL=='P')AL=PFLAG; + ELSE AL-='0'; + AH=AH<<3|AL; + } + AL=AH+DBIT+WBIT; +N15: + OP(); + $JMP NEXT_DESC_BYTE +// OpCode - ModRM байт +Dsc_XRM: + AL=EA_X<<3|EA_R<<3|EA_M; // Получить регистр из описания мнемоники + GOTO N15; +// OpCode - ModRM с P-флагом (арифметические инструкции) +Dsc_XPM: + AL=EA_X<<3|PFLAG<<3|EA_M; + GOTO N15; +// OpCode - ModRM с сегментным регистром +Dsc_XSM: + AL=EA_X<<3|SEGREGISTER<<3|EA_M; + GOTO N15; +// JMP NEXT_DESC_BYTE +} + +// ---- Разбор закончен -> на генерацию кода по шаблону +MapOperands() +{ +// AL=0; WBIT=AL; DBIT=AL; + opDescInd=0; + ESI=ACTUALMNEMDESC; // Указатель на информацию по генерации + AL=OPLENGTH; // Количество операндов + ECX=#OPDESC; // Указатель на информацию об операндах + ECX=DSDWORD[ECX]; + IF(ESI!=#T_MOV){ // Инструкция MOV? + IF(AL!=0){ + $CMP AL,1 + $JE NEAR ONEOP // Инструкция с одним операндом + $CMP AL,2 + $JE NEAR TWOOPS // Инструкция с двумя операндами + $CMP AL,3 + $JE NEAR THREEOPS // Инструкция с тремя операндами + toomuchoperands(); + return; + } +// ---- Инструкция без операндов + do{ + $LODSB + IF(AL==0)goto CreateCode; // Генерация кода + }while(AL!=_END); + preerror("ASM: Operand required\n"); + return; +// ---- Генерация MOV инструкции + } + $PUSH EAX,ECX + WRITEOVERRIDE(); + CreateScale(); + $POP ECX,EAX + IF(AL!=2){ // 2 OPERANDS IN INSTRUCTION? + preerror("ASM: Two operands required\n"); + return; +L2: + preerror("ASM: Not same size\n"); + return; + } +L1: + BL=0; + AL=OPERANDSIZE; + IF(AL!=_D){ + $CMP AL,_W + $JA L2 + $JNE N4 + RANDFLAG=1; + } + BL=1; +N4: + WBIT=BL; //STORE W-BIT + DL=0; //CLEAR D-BIT + WRITEADDR(); + EBX=0; + BL=CL; + EBX=EBX<<2+#Jmp_Mov; + $JMP NEAR DSDWORD[EBX] +Mov_ERR: + preerror("ASM: a constant can't be used as a destination\n"); + return; +Mov_R: + EBX=0; + BL=CH; + EBX=EBX<<2+#Jmp_Mov_R; + $JMP NEAR DSDWORD[EBX] +Mov_E: + EBX=0; + BL=CH; + EBX=EBX<<2+#Jmp_Mov_E; + $JMP NEAR DSDWORD[EBX] +Mov_R2R: + WRITERAND(); + AL=OPDATA[1]; + AH=OPDATA[0]; + DL=DBIT; + $PUSH EAX + AL=0o210+WBIT; + $SHL DL,1 + AL+=DL; //D-BIT + OP(); + $POP EAX + AL=AL&7<<3; + AH&=7; + AL=AL|AH|0o300; + OP(); + $JMP CreateConstants +Mov_R2E: + AL=OPDATA&7; //AL/AX/EAX ? + $OR AL,AL + $JNE N1 + $CMP EA_M,6 //AR,[DW] POSSIBLE? + $JNE N1 //NO, ONLY AR,[EA] + $CMP ADDRFLAG,0 //32BIT-EA ? + $JE N1 //NO, TRY ANOTHER... + WRITERAND(); + AL=0o240+WBIT; //INSTRUCTION FOUND. + OP(); + $JMP CreateConstants +Mov_E2R: +D1: + AL=OPDATA[1]&7; //[DW],AR POSSIBLE? + $OR AL,AL + $JNE Y1 + $CMP ADDRFLAG,0 //32BIT EA ? + $JNE Y1 //YES, RAVE ON... + $CMP EA_M,6 + $JNE Y1 + WRITERAND(); + AL=0o242+WBIT; //INSTRUCTION FOUND. + OP(); + $JMP CreateConstants +N1: + DL=2; //SET D-BIT +Y1: + DL+=0o210; + WRITERAND(); + AL=DL; + DL=0; + AL+=WBIT; + OP(); + AL=EA_X<<3|EA_R<<3|EA_M; + OP(); + $JMP CreateConstants +E1: + preerror("ASM: Not same size\n"); + return; +//EA,CONSTANT ? +Mov_E2C: + OPCONSTSIZE[1]=OPERANDSIZE; + $CMP AL,_D + $JA E1 + $JE X1 + $CMP AL,_W + $JNE X1 + AL=0x66; + OP(); +X1: + AL=0o306+WBIT; + OP(); + AL=EA_X<<6|EA_M; + OP(); + $JMP CreateConstants +Mov_R2C: + OPCONSTSIZE[1]=OPERANDSIZE; + $CMP OPERANDSIZE,_B + $JNE N2 + AL=OPDATA&7|0o260; + OP(); + $JMP CreateConstants +N2: + $CMP OPERANDSIZE,_D //BYTE, WORD OR DWORD? + $JA NEAR E1 // Not same size + IF(OPERANDSIZE==_W){ + AL=0x66; + OP(); + } + AL=OPDATA&7|0o270; + OP(); + $JMP CreateConstants +E21: + preerror("ASM: Word required\n"); + return; //SEGMENT REGISTER IS ALWAYS WORD. +Mov_S: + AL=0; + $CMP CX,_SR*256+E // mov EA,segreg + $JE O1 + $CMP CX,_SR*256+R // mov segreg,reg + $JE O2 + $CMP CX,R*256+_SR // mov reg,segreg + $JE O3 + $CMP CX,E*256+_SR // mov segreg,EA + $JNE NEAR N12 + AL=2; //SET D-BIT +O1: + $CMP OPERANDSIZE,_W + $JNE E21 + AL+=0o214; + OP(); + AL=EA_X<<6|EA_S|EA_M; + OP(); + $JMP CreateConstants +O2: + $CMP OPERANDSIZE,_W + $JNE E21 + AL=0o214; + OP(); + AL=EA_S|0o300|EA_R; //CREATE XSM BYTE + OP(); + $STC + $RET +O3: + $CMP OPERANDSIZE,_W + $JNE NEAR E21 + AL=0o216; + OP(); + AL=EA_S|0o300|EA_R; + OP(); + $STC + $RET +E31: + preerror("ASM: CR1 only readable\n"); + $RET +E32: + preerror("ASM: SysR must be dword\n"); + $RET +Mov_SYSR: +N12: + AH=0o40; + $CMP CX,SYSR*256+R + $JE O11 + $CMP CX,R*256+SYSR + $JNE N22 //ERROR: ILLEGAL OPERANDS + AH=0o42; + $CMP SYSRTYPE,_CR //CR1 REGISTER USED? + $JNE O11 + $CMP SYSRNUM,1 + $JE E31 //YES, ONLY READ FROM IT. +O11: + AH+=SYSRCODE; + $CMP OPERANDSIZE,_D //SYSTEM REGISTERS ARE ALWAYS DWORD. + $JNE E32 + AL=0o17; + OP(); + $CMP SYSRTYPE,_CR4 //EXCEPTION: CR4 + $JE N22 + AL=AH; + OP(); + AL=SYSRNUM<<3|0o300|EA_R; //CREATE 3NR OPCODE + OP(); + $STC + $RET +N22: + $CMP CX,SYSR*256+R + $JNE N32 + AL=0x22; + OP(); + GOTO L11; +N32: + AL=0x20; + OP(); +L11: + AL=0o340|EA_R; + OP(); + $STC + $RET +// ---- Инструкция с одним операндом +ONEOP: + EBX=CL<<2+#Jmp_Op1; + $JMP NEAR DSDWORD[EBX] +Op1ERR: + preerror("ASM: only use system registers within MOV instruction\n"); + $RET +// RX +L31: + SCDEND(); +Op1R: + GETOL1(); //GET FIRST GENERATION INFO. + $CMP AL,SOR //SINGLE OPERAND/REGISTER ? + $JNE X23 + $JMP CreateCode +X23: + $CMP AL,SOE //CONVERT REGISTER INTO EFFECTIVE ADDRESS? + $JNE L31 +C2: + EA_X=3; + AL=EA_R; + EA_M=AL; + $JMP CreateCode +// EA +L41: + SCDEND(); +Op1E: + GETOL1(); + $CMP AL,SOE //SINGLE OPERAND/EFFECTIVE ADDRESS ? + $JNE X24; + $JMP CreateCode +X24: + $CMP AL,SOM //SINGLE OPERAND/MEMORY POINTER ? + $JNE L41 + $CMP EA_X,0 + $JNE L41 + $CMP EA_M,6 //[WORD CONSTANT]? + $JNE L41 +C11: + $JMP CreateCode +// CO +L51: + SCDEND(); +Op1C: + GETOL1(); + $OR AL,AL //JUMP INSTRUCTION? + $JNE NEAR N13 +// Здесь обработка call&jmp + ECX=OPCONST[0]-OptImageBase-OptBaseOfCode-outptr+output; // Расчет относительного смещения + $LODSB // Получим short или near + $CMP AL,_JB // short? + $JNE N14 + ECX-=2; + $CMP ECX,0xFFFFFF80 + $JL L10 + $CMP ECX,0x7F + $JG L10 + OPCONSTSIZE[0]=_B; +H1: + OPCONST[0]=ECX; + $JMP CreateCode +N14: + EAX=0; + $LODSB // Поправка на размер call или jmp + ECX-=EAX; + OPCONSTSIZE[0]=_D; + GOTO H1; +L10: + $CMP ACTUALMNEMDESC,#T_JCXZ + $JB L51 + $CMP ACTUALMNEMDESC,#T_LOOP + $JA NEAR L51 + preerror("ASM: Jump range too long\n"); + $RET +N13: + $CMP AL,SO3 //CONSTANT VALUE 3 ? + $JNE N23 + $CMP OPCONST[0],3 + $JNE NEAR L51 + OPCONSTFLAG[0]=0; //YES, AVOID CONSTANT GENERATION. + $JMP CreateCode +N23: + $CMP AL,SOC //SINGLE OPERAND/CONSTANT? + $JNE X25 + OPCONSTSIZE[0]=OPERANDSIZE; + $JMP CreateCode +X25: + $CMP AL,SOO_CC //SINGLE OPERAND/SIGNED BYTE ? + $JNE NEAR L51 + IF(OPPOST[0])$JMP L51 + $CMP OPCONST[0],0x7F + $JG NEAR L51 + $CMP OPCONST[0],0xFFFFFF80 + $JL NEAR L51 + OPCONSTSIZE[0]=_B; + $JMP CreateCode +// SR +L61: + SCDEND(); +Op1S: + GETOL1(); + $CMP AL,SOS //SINGLE OPERAND/SEGMENT REGISTER? + $JNE L61 + $JMP CreateCode +// AF +L71: + SCDEND(); +Op1AF: + GETOL1(); + $CMP AL,SOO_AF + $JNE L71 + $JMP CreateCode +// ---- Инструкция с двумя операндами +TWOOPS: + EBX=CL<<2+#Jmp_Op2; + $JMP NEAR DSDWORD[EBX] // Переход по типу первого операнда +//Op2ERRC: +// preerror("ASM: A constant can't be used as a destination\n"); +// return; +Op2ERRS: + preerror("ASM: segment register can only be used within a MOV or PUSH\n"); + return; +Op2ERRSYS: + preerror("ASM: only use system registers within MOV instruction\n"); + return; +Op2ERRAF: + preerror("Absolute FAR addresses can only be used for jumps\n"); + return; +// Первый операнд в 2-операндной инструкции - регистр +Op2R: + EBX=0; + BL=CH; + EBX=EBX<<2+#Jmp_Op2R; + $JMP NEAR DSDWORD[EBX] // Переход по типу второго операнда +// Первый операнд в 2-операндной инструкции - EA +Op2E: + EBX=0; + BL=CH; + EBX=EBX<<2+#Jmp_Op2E; + $JMP NEAR DSDWORD[EBX] // Переход по типу второго операнда +// mnem EA,RX +L81: + SCDEND(); +OpE2R: + GETOL2(); // Обработка записи из шаблона + $CMP AL,DER //EA & R + D-BIT ? + $JE C21 +X26: + $CMP AL,ERO //'ERO' ORDER ? + $JE C21 + $CMP AL,EAO //EA, ? + $JNE L81 // На пропуск записи в шаблоне + $CMP OPDATA[1],rCL //CL REGISTER USED?? + $JNE L81 // На пропуск записи в шаблоне + $CMP DSBYTE[ESI+1],rCL //CL IN GENERATION INFO? + $JNE L81 // На пропуск записи в шаблоне +// CMP OPERANDSIZE,_B //YES, CHECK SIZE. +// JNE L81 // На пропуск записи в шаблоне + ESI++; + ESI++; +C21: + $JMP CreateCode +L91: + SCDEND(); +OpR2E: + GETOL2(); + $CMP AL,DER //DER ? + $JNE N43 + DBIT=1; //(DIRECTION BIT) + $JMP CreateCode +N43: + $CMP AL,REO //REO ? + $JNE L91; + $JMP CreateCode +//RX,RX ? +W2: + ESI++; + GOTO W1; +LA1: + SCDEND(); +OpR2R: + $CMP DSBYTE[ESI],_B+OL2+EAO // байт+2оп+EAold? + $JE W2 //EAO FOUND, R+R COMBINATION NOT PERMITTED. + GETOL2(); // Обработка записи шаблона + $CMP AL,DER // EA,reg или reg,EA с D/W-битом? + $JNE N53 +LB2: + AL=OPDATA[0]; // Преобразуем регистр в EA + CREATE_EA(); + AL=OPDATA[1]; // Второй операнд + CREATE_R(); + $JMP CreateCode +N53: + $CMP AL,ERO + $JE LB2 + $CMP AL,REO + $JNE N63 + AL=OPDATA[1]; //RX,EP + CREATE_EA(); + AL=OPDATA[0]; + CREATE_R(); + $JMP CreateCode +N63: + $CMP AL,EAO + $JNE LA1 // На пропуск записи в шаблоне +W1: + ECX=2; //COMPARE 2 OPERANDS. + opDescInd=0; +LX2: + $LODSB // поле из записи шаблона + $CMP AL,255 //1ST OPERAND OK. + $JE L022 + $CMP AL,AR //AL/AX/EAX? + $JE OL2X_AR + $CMP AL,rDX //DX? + $JE OL2X_DX + $CMP AL,rCL + $JE OL2X_CL + GOTO LA1; // На пропуск записи в шаблоне +OL2X_AR: + EBX=opDescInd; + AH=OPDATA[EBX]&7; // Операнд из мнемоники + $JNZ NEAR LA1 // На пропуск записи в шаблоне +L022: + opDescInd++; + $LOOP LX2 + GOTO L23; +OL2X_DX: + EBX=opDescInd; + $CMP OPDATA[EBX],0o12 + $JNE NEAR LA1 // На пропуск записи в шаблоне + opDescInd++; + $LOOP LX2 + GOTO L23; +OL2X_CL: + EBX=opDescInd; + $CMP OPDATA[EBX],rCL //CL + $JNE NEAR LC1 + opDescInd++; + $LOOP LX2 + $TEST OPDATA[0],8+16 //1ST REGISTER WORD/DWORD? + $JZ L23 + WBIT=1; //YES, SET W-BIT. +L23: + AL=OPDATA[0]; + CREATE_EA(); + $JMP CreateCode +//EA,CONSTANT ? //EA,CONST? +LB1: + SCDEND(); +OpE2C: + GETOL2(); + opDescInd=1; + $CMP AL,ECO + $JNE N73 + OPCONSTSIZE[1]=OPERANDSIZE; + $JMP CreateCode +N73: + $CMP AL,EAO + $JNE N83 + $CMP OPERANDSIZE,_B + $JNE N83 + $CMP DSBYTE[ESI],_1 + $JNE N83 + $CMP OPCONST[4],1 + $JNE N83 + OPCONSTFLAG[1]=0; + ESI++; + $JMP CreateCode +N83: + $CMP AL,ECCO //EA/SIGNED BYTE ? + $JNE LB1 + $CMP OPCONST[4],0xFFFFFF80 + $JL LB1 + $CMP OPCONST[4],0x7F + $JG NEAR LB1 + OPERANDSIZE=_B; //OMIT A SINGLE BYTE ON GENERATION. + $JMP CreateCode +// mnem reg,const +LC1: + SCDEND(); +OpR2C: + GETOL2(); + opDescInd=1; + $CMP AL,RCO; + $JNE Q1 +A0: + OPCONSTSIZE[1]=OPERANDSIZE; + $JMP CreateCode // reg,const +Q1: + $CMP AL,ECO; + $JNE L110 +A1: + AL=EA_R; + CREATE_EA(); + GOTO A0; +L110: + $CMP AL,EAO; + $JE N93 + $CMP AL,ECCO; + $JNE LC1 //SIGNED BYTE CONST ? + $CMP OPCONST[4],0xFFFFFF80; + $JL LC1 + $CMP OPCONST[4],0x7F; + $JG LC1 + OPERANDSIZE=_B; + OPCONSTSIZE[1]=_B; + GOTO A1; //CONVERT REGISTER TO EFFECTIVE ADDRESS AND GENERATE OPCODE. +N93: + ECX=2; //COMPARE 2 OPERAND. +B2: + $LODSB; + $CMP AL,255; + $JE L122 + $CMP AL,AR; + $JE OL2_AR //AL/AX/EAX? + $CMP AL,CO; + $JE OL2_CO //CONSTANT? + $CMP AL,rDX; + $JE OL2_DX //DX? + $CMP AL,_1; + $JE OL2_1 //CONSTANT VALUE 1? + $JMP LC1 +OL2_AR: + AH=OPDATA[0]&7; + $JNZ NEAR LC1 +L122: + $LOOP B2; + $JMP CreateCode +OL2_CO: + $CMP OPDESC[1],CO; + $JNE NEAR LC1 + OPCONSTSIZE[1]=OPERANDSIZE; + GOTO L122; +OL2_DX: + $CMP OPDATA[0],0o12; + $JE L122; + $JMP LC1 +OL2_1: + $CMP OPCONSTSIZE[1],_B; + $JNE NEAR LC1 + $CMP OPCONST[4],1; + $JNE NEAR LC1 + OPCONSTFLAG[1]=0; + $JMP A1 +LD1: + SCDEND(); +// Первый операнд в 2-операндной инструкции - константа +Op2C: + GETOL2(); + $CMP AL,EAO + $JNE LD1 + ECX=2; //COMPARE 2 OPERANDS. + opDescInd=0; +B12: + $LODSB + $CMP AL,255 + $JE L222 + $CMP AL,AR //AL/AX/EAX + $JE XOL2_AR + $CMP AL,CO + $JE XOL2_CO + $CMP AL,rDX //DX + $JE XOL2_DX + $CMP AL,_1 + $JE XOL2_1 + GOTO LD1; +XOL2_AR: + EBX=opDescInd; + AH=OPDATA[EBX]&7; + $JNZ N21 +L222: + opDescInd++; + $LOOP B12 + $JMP CreateCode +N21: + GOTO LD1; +XOL2_CO: + EBX=opDescInd; + $CMP OPDESC[EBX],CO + $JNE LD1 + opDescInd++; + $LOOP B12 + $JMP CreateCode +XOL2_DX: + EBX=opDescInd; + $CMP OPDATA[EBX],0o12 + $JNE NEAR LD1 + opDescInd++; + $LOOP B12 + $JMP CreateCode +XOL2_1: + EDX=opDescInd; + $CMP OPCONSTSIZE[EDX],_B + $JNE NEAR LD1 + EDX<<=2; + $CMP OPCONST[EDX],1 + $JNE NEAR LD1 + EDX=opDescInd; + OPCONSTFLAG[EDX]=0; + AL=EA_R; + CREATE_EA(); + $JMP CreateCode +// Трехоперандная инструкция +LE1: + SCDEND(); +THREEOPS: +D11: + GETOL3(); + $CMP AL,ERO + $JNE N42 + $CMP CX,R*256+E + $JE O21 + $CMP CX,R*256+R + $JNE LE1 + AL=OPDATA[0]; + CREATE_EA(); + AL=OPDATA[1]; + CREATE_R(); + GOTO O21; +N42: + $CMP AL,REO + $JNE N52 //ERROR: INVALID OPERANDS. + $CMP CX,E*256+R + $JE O21 + $CMP CX,R*256+R + $JNE LE1 + AL=OPDATA[1]; + CREATE_EA(); + AL=OPDATA[0]; + CREATE_R(); +O21: + BL=AH&TRANSBITS; + $CMP OPCONSTFLAG[2],1 + $JNE NEAR NA3 + $CMP BL,CC3 + $JNE N52 + $CMP OPCONST[8],0xFFFFFF80 + $JL NEAR LE1 + $CMP OPCONST[8],0x7F + $JG NEAR LE1 + OPCONSTSIZE[2]=_B; + $JMP CreateCode +N52: + $CMP BL,CB3 + $JNE N62 + $CMP OPCONST[8],0xFF + $JA NEAR LE1 + OPCONSTSIZE[2]=_B; + $JMP CreateCode +N62: + $CMP BL,CW3 + $JNE NA3 + $CMP OPCONST[8],0xFFFFFFFF + $JA NEAR LE1 + $CMP RANDFLAG,1 + $JNE NA2 + OPCONSTSIZE[2]=_W; + $JMP CreateCode +NA2: + OPCONSTSIZE[2]=_D; +NA_2: + $JMP CreateCode +NA3: + $CMP BL,CL3 + $JNE NEAR LE1 + $CMP OPDESC[2],R + $JNE NEAR LE1 + $CMP OPDATA[2],rCL + $JE NA_2 + illegaloperand(); +} + +CreateConstants() +{ + $CMP EA_SIBFLAG,1 // Флаг наличия Sib в 32-битном EA + $JNE L3 // Sib отсутствует + $CMP ADDRFLAG,1 + $JE L3 //NO, NORMAL XRM +// Запись SIB - байта + AL=EA_I<<3|EA_R2|EA_SCALING; + OP(); +L3: + $CMP OPCONSTFLAG[0],1 + $JNE NEAR N1 + IF(OPPOST[0])SetPost(OPPOSTREF[0],OPPOST[0]); + ECX=OPCONSTSIZE[0]; + EDI=#OPCONST; // Значение disp в EA + WRITECONST(); +N1: + $CMP OPCONSTFLAG[1],1 + $JNE NEAR N41 + ECX=OPCONSTSIZE[1]; + $CMP CL,AF //ABSOLUTE FAR ? + $JNE D21 + EDI=#OPCONST+4; //YES, CREATE ADDRESS. + CL=_W; //(32 BIT) + $CMP ADDRFLAG,1 + $JNE D2 + ECX=_D; //(48 BIT) +D2: + WRITECONST(); + EDX+=output; + EBX=EDX>>4; + $AND EDX,15 + $PUSH EBX,EDX + $POP EDX //??? + EAX=opDescInd; + DSDWORD[EAX]=EDX; + ECX=_W; + /* AFSEG нигде не определен, надо будет разбираться + EDI=#AFSEG; //(SEGMENT/SELECTOR) */ + + WRITECONST(); + $STC + $RET +D21: + IF(OPPOST[1])SetPost(OPPOSTREF[4],OPPOST[1]); + EDI=#OPCONST+4; + WRITECONST(); +N41: + IF(OPCONSTFLAG[2]==1){ + ECX=OPCONSTSIZE[2]; + EDI=#OPCONST+8; + WRITECONST(); + } +} + +// ---- +illegaloperand() +{ + preerror("ASM: Illegal operand\n"); +} +// ---- +toomuchoperands() +{ + preerror("ASM: Illegal number of operands\n"); +} + +// JUMP TABLES +dword Jmp_Mov={#Mov_R,#Mov_E,#Mov_ERR,#Mov_S, + #Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR}; +dword Jmp_Mov_R={#Mov_R2R,#Mov_R2E,#Mov_R2C,#Mov_S, + #Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR,#Mov_SYSR}; +dword Jmp_Mov_E={#Mov_E2R,#Mov_ERR,#Mov_E2C,#Mov_S, + #Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR,#Mov_ERR}; + +dword Jmp_Op1={#Op1R,#Op1E,#Op1C,#Op1S, + #Op1ERR,#Op1ERR,#Op1ERR,#Op1ERR,#Op1ERR,#Op1AF}; +dword Jmp_Op2={#Op2R,#Op2E,#Op2C,#Op2ERRS, + #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; +dword Jmp_Op2R={#OpR2R,#OpR2E,#OpR2C,#Op2ERRS, + #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; +dword Jmp_Op2E={#OpE2R,0,#OpE2C,#Op2ERRS, + #Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRSYS,#Op2ERRAF}; +//dword TC_JMP={#T_JMPSHORT,#T_JMPNEAR,#T_JMPFAR}; +//dword TC_CALL={0,#T_CALL,#T_CALLFAR}; +//dword TC_J={#T_J,#T_JN,1}; +dword Dsc_Jump={#CreateConstants,#Dsc_O,#Dsc_OW,#Dsc_OS,#Dsc_S,#Dsc_XRM,#Dsc_XPM,#Dsc_XSM}; diff --git a/programs/develop/c--/trunk/opcodesc.h-- b/programs/develop/c--/trunk/opcodesc.h-- new file mode 100644 index 0000000000..613f785e74 --- /dev/null +++ b/programs/develop/c--/trunk/opcodesc.h-- @@ -0,0 +1,591 @@ +//CODE GENERATION DESCRIPTORS +// ========================= +// >>> DESCRIPTION CODES <<< +// ========================= + +//T_: +// DB +// [DB ] +// [DB ] +// DB +// DB +// DB 0 +//OR DB _END //IF THERE'RE NO MORE INFO ABOUT THIS MNEMONIC + +// OPERATION SIZE CODES +enum { _B, //OPERATION MAY BE OF SIZE BYTE,WORD OR DWORD SEIN. THE OPCODE'S + // W BIT INDICATES IF IT'S A BYTE OR WORD OPERATION. + // FOR DWORD OPERATIONS, THE W BIT MUST BE TRUE (WORD OPERATION) + // AND THE RAND:PREFIX MUST BE GENERATED. + _W, //OPERATION SIZE MAY BE WORD OR DWORD. + _D, //OPERATION MAY ONLY BE DWORD. + WB, //1. OPERAND WORD, 2. OPERAND BYTE + _DW, //1. OPERAND DWORD, 2. OPERAND WORD + BW, //1. OPERAND BYTE, 2. OPERAND WORD + NB, //ONLY BYTE SIZE. + _OW, //ONLY WORD SIZE. + _OD, // Only DWORD size + AF}; //ONLY ABSOLUTE FAR 32/48 BIT ADDRESS + +#define _JB 1 //OPERAND IS A JUMP - DESTINATION +/-128 +#define _JW 2 //OPERAND IS A JUMP - DESTINATION +/-32678 + +// 0-2 = OPERATION SIZE CODE +// 3-4 = # OF OPERANDS NEEDED. + +// # OF OPERANDS +#define OL0 0 +#define OL1 0o10 +#define OL2 0o20 +#define OL3 0o30 + +#define OLBITS 0o30 //MASKS FOR # OF OPERANDS. +#define NOLBITS 0o347 +#define TRANSBITS 0o7 //MASKS FOR OPERATION SIZE CODES. +#define NTRANSBITS 0o370 + +// IF OL1, USE THIS OPERAND TYPES: +#define SOJ 0b00000000 //JUMP +#define SOE 0b00100000 //EA +#define SOR 0b01000000 //REG +#define SOC 0b01100000 //CONST +#define SO3 0b10000000 //_3 +#define SOS 0b10100000 //SREG +#define SOM 0b11000000 //EA-MEMORY-POINTER +#define SOO 0b11100000 //THERE IS INFORMATION USING THE OPERAND SIZE CODE BITS. +#define SOO_FS 0o340 //FS-REGISTER +#define SOO_GS 0o341 //GS-REGISTER +#define SOO_AF 0o342 //ABSOLUTE ADRESS +#define SOO_CC 0o343 //SIGNED BYTE +#define OPBITS 0b11100000 + +// IF OL2, USE THOSE INSTEAD: +// 00000000B //DIRECT DESCRIPTOR + //AR,CO +#define ERO 0b00100000 //FIXED EA,REG ORDER +#define REO 0b01000000 //FIXED REG,EA ORDER +#define DER 0b01100000 //EA,REG OR REG,EA DEFINED BY A D-BIT +#define ECO 0b10000000 //EA,CONSTANT// SIZE DEFINED BY W-BIT +#define ECCO 0b10100000 //EA,CC +#define RCO 0b11000000 //REG,CONSTANT// SIZE DEFINED BY W-BIT +#define EAO 0b11100000 //EA,? // SECOND OPERAND DESCRIBED BY OLD DESCIPTORS + //?=_1,rCL,CO + +// OPERAND TYPE CODES +enum { R, //GENERAL REGISTER + E, //EFFEKTIVE ADRESS + CO, //CONSTANT + _SR, //SEGMENT REGISTER + SYSR, //SYSTEM REGISTER + _DR, //DEBUG REGISTER + _TR, //TASK REGISTER + _CR, //CONTROL REGISTER + _CR4, // + _AF, //ABSOLUTE 32/48 BIT FAR ADDRESS + AR=11, //AX/AL REGISTER, INDICATED BY OPERATION SIZE + _1}; //CONSTANT VALUE 1 + +// IF OL3, USE THIS: +// INSTRUCTION WITH THREE OPERANDS ARE ALWAYS OF SIZE WORD. +// THE FOLLOWING CODES DESCRIBE THE 3RD OPERAND. +enum { CB3, //BYTE CONSTANT + CW3, //WORD CONSTANT + CC3, //SBYTE CONSTANT + CL3}; //CL REGISTER + +// OPCODE DESCRIPTORS +enum{ O=1, //OPCODE IS A BYTE + OW, //OPCODE IS A WORD + OS, //OPCODE IS A BYTE PLUS A SECOND BYTE THAT IS DESCRIBED BY AN + //OCTAL STRING. + S, //OCTAL STRING FOLLOWS FOR OPCODE + XRM, //MODRM BYTE + XPM, //MODRM MIT P-FLAG (GRUPPE VON ARITHMETIC INSTRUCTIONS) + XSM, //MODRM MIT SEGMENTREGISTER + X0M,X1M,X2M,X3M,X4M,X5M,X6M,X7M //MODRM WITH CONSTANT R DIGIT + }; + +byte OVERRIDETAB={0o46,0o56,0o66,0o76,0o144,0o145}; +// ---- Кодировка регистров +enum{ rAL ,rCL ,rDL ,rBL ,rAH ,rCH ,rDH ,rBH, // 0-7 byte regs + rAX ,rCX ,rDX ,rBX ,rSP ,rBP ,rSI ,rDI, // 8-15 16-bit word regs + rEAX,rECX,rEDX,rEBX,rESP,rEBP,rESI,rEDI,// 16-23 32-bit regs + rCR0,rCR1,rCR2,rCR3,rCR4,rCR5,rCR6,rCR7,// 24-31 control regs + rDR0,rDR1,rDR2,rDR3,rDR4,rDR5,rDR6,rDR7,// 32-39 debug regs + rTR0,rTR1,rTR2,rTR3,rTR4,rTR5,rTR6,rTR7,// 40-47 test regs + rES,rCS,rSS,rDS, rFS,rGS}; // 48-53 seg regs +byte Registers={ + "AL","CL","DL","BL","AH","CH","DH","BH", + "AX","CX","DX","BX","SP","BP","SI","DI", + "EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI", + "CR0","CR1","CR2","CR3","CR4","CR5","CR6","CR7", + "DR0","DR1","DR2","DR3","DR4","DR5","DR6","DR7", + "TR0","TR1","TR2","TR3","TR4","TR5","TR6","TR7", + "ES","CS","SS","DS","FS","GS",_END}; +byte Sizes={"BYTE","WORD","DWORD",_END}; + +// ---- Описания менмоник +byte PCOMMANDS1={ + 0, //P FLAG STARTS AT 0 + _B+OL2+EAO,AR,CO,S,"0P4", + _B+OL2+DER,S,'0','P','0',XRM,0, + _W+OL2+ECCO,O,0o203,XPM,0, + _B+OL2+ECO,O,0o200,XPM,_END}; + +byte PCOMMANDS2={ + 4, //P FLAG STARTS AT 4 + _B+OL1+SOE,O,0xF6,XPM,_END}; +byte PCOMMANDS3= 0; //P FLAG STARTS AT 0 +byte PCOMMANDS3_={ + _B+OL2+EAO,-1,_1,O,0xD0,XPM,0, + _B+OL2+EAO,-1,rCL,O,0xD2,XPM,0, + _B+OL2+ECCO,O,0xC0,XPM,_END}; + +byte PCOMMANDS4={ + 4, //P FLAG STARTS AT 4 + _W+OL2+ERO,OS,0xF,'2','P','3',XRM,0, + WB+OL2+ECO,OW,0xF,0o272,XPM,_END}; +// Однобайтовые инструкции +byte T_DAA={ O,0o47,_END}; +byte T_DAS={ O,0o57,_END}; +byte T_AAA={ O,0o67,_END}; +byte T_AAD={ OW,0o325,0o12,_END}; +byte T_AAM={ OW,0o324,0o12,_END}; +byte T_AAS={ O,0o77,_END}; +byte T_CWDE={ O,0o230,_END}; +byte T_CBW={ OW,0x66,0o230,_END}; +byte T_CDQ={ O,0o231,_END}; +byte T_CWD={ OW,0x66,0o231,_END}; +byte T_XLATB={ O,0o327,_END}; +byte T_NOP={ O,0o220,_END}; +byte T_WAIT={ O,0o233,_END}; +byte T_LOCK={ O,0o360,_END}; +byte T_HLT={ O,0o364,_END}; +byte T_INTO={ O,0o316,_END}; +byte T_IRET={ O,0o317,_END}; +byte T_POPFD={ O,0o235,_END}; +byte T_POPF={ OW,0x66,0o235,_END}; +byte T_PUSHFD={ O,0o234,_END}; +byte T_PUSHF={ OW,0x66,0o234,_END}; //PUSHF / (#) PUSHFD +byte T_SAHF={ O,0o236,_END}; +byte T_LAHF={ O,0o237,_END}; +byte T_CMC={ O,0o365,_END}; +byte T_CLC={ O,0o370,_END}; +byte T_STC={ O,0o371,_END}; +byte T_CLI={ O,0o372,_END}; +byte T_STI={ O,0o373,_END}; +byte T_CLD={ O,0o374,_END}; +byte T_STD={ O,0o375,_END}; +byte T_PUSHAD={ O,0o140,_END}; +byte T_PUSHA={ OW,0x66,0o140,_END}; +byte T_POPAD={ O,0o141,_END}; +byte T_POPA={ OW,0x66,0o141,_END}; +byte T_INSB={ O,0o154,_END}; +byte T_INSW={ OW,0x66,0o155,_END}; +byte T_INSD={ O,0o155,_END}; +byte T_OUTSB={ O,0o156,_END}; +byte T_OUTSW={ OW,0x66,0o157,_END}; +byte T_OUTSD={ O,0o157,_END}; +byte T_MOVSB={ O,0o244,_END}; +byte T_MOVSW={ OW,0x66,0o245,_END}; +byte T_MOVSD={ O,0o245,_END}; +byte T_CMPSB={ O,0o246,_END}; +byte T_CMPSW={ OW,0x66,0o247,_END}; +byte T_CMPSD={ O,0o247,_END}; +byte T_STOSB={ O,0o252,_END}; +byte T_STOSW={ OW,0x66,0o253,_END}; +byte T_STOSD={ O,0o253,_END}; +byte T_LODSB={ O,0o254,_END}; +byte T_LODSW={ OW,0x66,0o255,_END}; +byte T_LODSD={ O,0o255,_END}; +byte T_SCASB={ O,0o256,_END}; +byte T_SCASW={ OW,0x66,0o257,_END}; +byte T_SCASD={ O,0o257,_END}; +byte T_REP={ O,0o362,_END}; +byte T_REPE={ O,0o363,_END}; +byte T_RAND={ O,0o146,_END}; //RAND: +byte T_ADDR={ O,0o147,_END}; //ADDR: +byte T_LEAVE={ O,0o311,_END}; +byte T_CLTS={ OW,0xF,6,_END}; +byte T_INVD={ OW,0xF,0o10,_END}; +byte T_WBINVD={ OW,0xF,0o11,_END}; +byte T_WRMSR={ OW,0xF,0x30,_END}; //WRMSR WRITE EDXEAX TO MODEL SPECIFIC REG #ECX +byte T_CPUID={ OW,0xF,0xA2,_END}; //CPUID IF EAX=1 SET EDXEAX TO CPU IDENTIFICATION VALUES +byte T_RDMSR={ OW,0xF,0x32,_END}; //RDMSR READ MODEL SPECIFIC REG #ECX TO EDXEAX +byte T_RDTSC={ OW,0xF,0x31,_END}; //RDTSC READ TIME STAMP COUNTER TO EDXEAX +byte T_RSM={ OW,0xF,0xAA,_END}; //RSM RESUME FROM SYSTEM MANAGEMENT MODE +//===== INTEL PENTIUM PRO INSTRUCTIONS +byte T_RDPMC={ OW,0xF,0x33,_END}; //READ PERFORMANCE MONITORING COUNTERS +byte T_UD2={ OW,0xF,0xB,_END}; //UNDEFINED INSTRUCTION EXCEPTION +byte T_EMMX={ OW,0xF,0x77,_END}; //EMPTY MMX STATE +byte T_SALC={ O,0xD6,_END}; +byte T_ICEBP={ O,0xF1,_END}; +byte T_PSHIMW={ OW,0xF,0x71,_END}; +byte T_PSHIMD={ OW,0xF,0x72,_END}; +byte T_PSHIMQ={ OW,0xF,0x73,_END}; + +byte T_NOT={ _B+OL1+SOE,O,0xF6,X2M,_END}; +byte T_NEG={ _B+OL1+SOE,O,0xF6,X3M,_END}; +byte T_INC={ _W+OL1+SOR,S,"10R", + _B+OL1+SOE,O,0xFE,X0M,_END}; +byte T_DEC={ _W+OL1+SOR,S,"11R", + _B+OL1+SOE,O,0xFE,X1M,_END}; +byte T_TEST={ _B+OL2+ERO,O,0o204,XRM,0, //ALPHA:WAS 204O + _B+OL2+REO,O,0o204,XRM,0, //" + _B+OL2+EAO,AR,CO,O,0o250,0, + _B+OL2+ECO,O,0xF6,X0M,_END}; +// EXTENDED 386 INTEGER MULTIPLICATION +byte T_IMUL={ _B+OL1+SOE,O,0xF6,X5M,0, //IMUL EB + _B+OL2+ECO,O,0xC0,X1M,0, + _B+OL2+EAO,-1,_1,O,0xD0,X1M,0, + _B+OL2+EAO,-1,rCL,O,0xD2,X1M,0, + _W+OL1+REO,OW,0xF,0o257,XRM,0, //IMUL RW, EW + OL3+REO+CC3,O,0o153,XRM,0, //IMUL RW, EW, DC + OL3+REO+CW3,O,0o151,XRM,_END}; //IMUL RW, EW, DW +byte T_SHLD={ OL3+ERO+CB3,OW,0xF,0o244,XRM,0, + OL3+ERO+CL3,OW,0xF,0o245,XRM,_END}; +byte T_SHRD={ OL3+ERO+CB3,OW,0xF,0o254,XRM,0, + OL3+ERO+CL3,OW,0xF,0o255,XRM,_END}; +byte T_MOVSX={ WB+OL2+REO,OW,0xF,0o276,XRM,0, + _DW+OL2+REO,OW,0xF,0o277,XRM,_END}; +byte T_MOVZX={ WB+OL2+REO,OW,0xF,0o266,XRM,0, + _DW+OL2+REO,OW,0xF,0o267,XRM,_END}; +byte T_BSWAP={ _D+OL1+SOR,OS,0xF,"31R",_END}; +byte T_BSF={ _W+OL2+REO,OW,0xF,0o274,XRM,_END}; +byte T_BSR={ _W+OL2+REO,OW,0xF,0o275,XRM,_END}; +byte T_CMPXCHG={_B+OL2+ERO,OW,0xF,0xB0,XRM,_END}; +byte T_CMPXCHG486={_B+OL2+ERO,OW,0xF,0xA7,XRM,_END}; +byte T_CMPXCHG8B={_B+OL2+ERO,OW,0xF,0xC7,XRM,_END}; +byte T_XADD={ _B+OL2+ERO,OW,0xF,0xC0,XRM,_END}; +byte T_XCHG={ _W+OL2+EAO,-1,AR,S,"22M", //ALPHA:WAS "22R" BUT GENERATED NOP + _W+OL2+EAO,AR,-1,S,"22R", + _B+OL2+REO,O,0o206,XRM,0, + _B+OL2+ERO,O,0o206,XRM,_END}; +byte T_MOV=0; //DUMMY BYTE +byte T_LEA={ _D+OL2+REO,O,0o215,XRM,_END}; //LEA RW, EN (X != 3) +byte T_LSS={ _D+OL2+REO,OW,0xF,0o262,XRM,_END};//LSS RW, EF (X != 3) +byte T_LFS={ _D+OL2+REO,OW,0xF,0o264,XRM,_END};//LFS RW, EF (X != 3) +byte T_LGS={ _D+OL2+REO,OW,0xF,0o265,XRM,_END};//LGS RW, EF (X != 3) +byte T_LES={ _D+OL2+REO,O,0o304,XRM,_END}; //LES RW, EF (X != 3) +byte T_LDS={ _D+OL2+REO,O,0o305,XRM,_END}; //LDS RW, EF (X != 3) +byte T_SET0={ NB+OL1+SOE,OW,0xF,0o220,X0M,_END}; +byte T_SET1={ NB+OL1+SOE,OW,0xF,0o221,X0M,_END}; +byte T_SET2={ NB+OL1+SOE,OW,0xF,0o222,X0M,_END}; +byte T_SET3={ NB+OL1+SOE,OW,0xF,0o223,X0M,_END}; +byte T_SET4={ NB+OL1+SOE,OW,0xF,0o224,X0M,_END}; +byte T_SET5={ NB+OL1+SOE,OW,0xF,0o225,X0M,_END}; +byte T_SET6={ NB+OL1+SOE,OW,0xF,0o226,X0M,_END}; +byte T_SET7={ NB+OL1+SOE,OW,0xF,0o227,X0M,_END}; +byte T_SET8={ NB+OL1+SOE,OW,0xF,0o230,X0M,_END}; +byte T_SET9={ NB+OL1+SOE,OW,0xF,0o231,X0M,_END}; +byte T_SETA={ NB+OL1+SOE,OW,0xF,0o232,X0M,_END}; +byte T_SETB={ NB+OL1+SOE,OW,0xF,0o233,X0M,_END}; +byte T_SETC={ NB+OL1+SOE,OW,0xF,0o234,X0M,_END}; +byte T_SETD={ NB+OL1+SOE,OW,0xF,0o235,X0M,_END}; +byte T_SETE={ NB+OL1+SOE,OW,0xF,0o236,X0M,_END}; +byte T_SETF={ NB+OL1+SOE,OW,0xF,0o237,X0M,_END}; +// +byte T_JCXZ={ OL1,_JB,O,0o343,_END}; +byte T_LOOPNZ={ OL1,_JB,O,0o340,_END}; +byte T_LOOPZ={ OL1,_JB,O,0o341,_END}; +byte T_LOOP={ OL1,_JB,O,0o342,_END}; +byte T_J0={ OL1,_JB,O,0o160,0, + OL1,_JW,6,OW,0o17,0o200,_END}; +byte T_J1={ OL1,_JB,O,0o161,0, + OL1,_JW,6,OW,0o17,0o201,_END}; +byte T_J2={ OL1,_JB,O,0o162,0, + OL1,_JW,6,OW,0o17,0o202,_END}; +byte T_J3={ OL1,_JB,O,0o163,0, + OL1,_JW,6,OW,0o17,0o203,_END}; +byte T_J4={ OL1,_JB,O,0o164,0, + OL1,_JW,6,OW,0o17,0o204,_END}; +byte T_J5={ OL1,_JB,O,0o165,0, + OL1,_JW,6,OW,0o17,0o205,_END}; +byte T_J6={ OL1,_JB,O,0o166,0, + OL1,_JW,6,OW,0o17,0o206,_END}; +byte T_J7={ OL1,_JB,O,0o167,0, + OL1,_JW,6,OW,0o17,0o207,_END}; +byte T_J8={ OL1,_JB,O,0o170,0, + OL1,_JW,6,OW,0o17,0o210,_END}; +byte T_J9={ OL1,_JB,O,0o171,0, + OL1,_JW,6,OW,0o17,0o211,_END}; +byte T_JA={ OL1,_JB,O,0o172,0, + OL1,_JW,6,OW,0o17,0o212,_END}; +byte T_JB={ OL1,_JB,O,0o173,0, + OL1,_JW,6,OW,0o17,0o213,_END}; +byte T_JC={ OL1,_JB,O,0o174,0, + OL1,_JW,6,OW,0o17,0o214,_END}; +byte T_JD={ OL1,_JB,O,0o175,0, + OL1,_JW,6,OW,0o17,0o215,_END}; +byte T_JE={ OL1,_JB,O,0o176,0, + OL1,_JW,6,OW,0o17,0o216,_END}; +byte T_JF={ OL1,_JB,O,0o177,0, + OL1,_JW,6,OW,0o17,0o217,_END}; +byte T_JMP={ OL1,_JB,O,0o353,0, //JMP SHORT CB + OL1,_JW,5,O,0o351,0, //JMP NEAR CW + _OW+OL1+SOE,O,0o377,X4M,0}; // JMP NEAR EN +byte T_JMPFAR={ _D+OL1+SOE,O,0o377,X5M,0, // JMP FAR EF + OL1+SOO_AF,O,0o352,_END}; //JMP FAR AF +byte T_JMPSHORT={ + OL1,_JB,O,0o353,_END}; //JMP SHORT CB +byte T_JMPNEAR={OL1,_JW,5,O,0o351,0, //JMP NEAR CW + _OW+OL1+SOE,O,0o377,X4M,_END}; // JMP NEAR EN +byte T_CALL={ OL1,_JW,5,O,0o350,0, //CALL CW + _OW+OL1+SOE,O,0o377,X2M,0}; //CALL EN +byte T_CALLFAR={ + OL1+SOO_AF,O,0o232,0, //CALL AF + _D+OL1+SOE,O,0o377,X3M,_END}; //CALL FAR EF +byte T_RETF={ 0,O,0o313,0, //RETF/RET FAR + _OW+OL1+SOC,O,0o312,_END}; //RETF DW/RET FAR DW +byte T_ENTER={ WB+OL2+EAO,CO,CO,O,0o310,_END}; +byte T_BOUND={ _W+OL2+REO,O,0o142,XRM,_END}; //BOUND RW, ED +/*byte T_INT={ NB+OL1+SO3,O,0o314,0, // !!! No interrupts in Win32 + NB+OL1+SOC,O,0o315,_END};*/ +byte T_IN={ NB+OL2+EAO,AR,CO,O,0o344,0, //IN AL, DB + WB+OL2+EAO,AR,CO,O,0o345,0, //IN AX,CO + _B+OL2+EAO,AR,rDX,O,0o354,0, //IN AL,DX + _OW+OL2+EAO,AR,rDX,O,0o355,_END}; //IN AX, DX +byte T_OUT={ NB+OL2+EAO,CO,AR,O,0o346,0, //OUT DB, AL + BW+OL2+EAO,CO,AR,O,0o347,0, //OUT DB, AX + WB+OL2+EAO,rDX,AR,O,0o356,0, //OUT DX, AL + _OW+OL2+EAO,rDX,AR,O,0o357,_END}; //OUT DX, AX +byte T_PUSH={ OL1+SOO_CC,O,0o152,0, + _D+OL1+SOR,S,"12R", + _D+OL1+SOE,O,0o377,X6M,0, + _D+OL1+SOC,O,0o150,0, + OL1+SOO_FS,OW,0xF,0o240,0, + OL1+SOO_GS,OW,0xF,0o250,0, + _OW+OL1+SOS,S,"0S6", //WIEDER ANS ENDE PACKEN + _END}; +byte T_RET={ _OW+OL1+SOC,O,0o302,0, //RET DW + O,0o303,0,_END}; //RET +byte T_POP={ _D+OL1+SOR,S,"13R", + _D+OL1+SOE,O,0o217,X0M,0, + OL1+SOO_FS,OW,0xF,0o241,0, + OL1+SOO_GS,OW,0xF,0o251,0, + _OW+OL1+SOS,S,"0S7",_END}; +byte T_ARPL={ _W+OL2+ERO,O,0o143,XRM,_END}; //ARPL ES, RW +byte T_SLDT={ _OW+OL1+SOE,OW,0xF,0,X0M,_END}; //SLDT EW +byte T_STR={ _OW+OL1+SOE,OW,0xF,0,X1M,_END}; //STR EW +byte T_LLDT={ _OW+OL1+SOE,OW,0xF,0,X2M,_END}; //LLDT EW +byte T_LTR={ _OW+OL1+SOE,OW,0xF,0,X3M,_END}; //LTR EW +byte T_VERR={ _OW+OL1+SOE,OW,0xF,0,X4M,_END}; //VERR EW +byte T_VERW={ _OW+OL1+SOE,OW,0xF,0,X5M,_END}; //VERW EW +byte T_LAR={ _OW+OL1+REO,OW,0xF,2,XRM,_END}; //LAR RW, EW +byte T_LSL={ _OW+OL1+REO,OW,0xF,3,XRM,_END}; //LSL RW, EW +byte T_SGDT={ _OW+OL1+SOM,OW,0xF,1,X0M,_END}; //SGDT EP +byte T_SIDT={ _OW+OL1+SOM,OW,0xF,1,X1M,_END}; //SIDT EP +byte T_LGDT={ _OW+OL1+SOM,OW,0xF,1,X2M,_END}; //LGDT EP +byte T_LIDT={ _OW+OL1+SOM,OW,0xF,1,X3M,_END}; //LIDT EP +byte T_SMSW={ _OW+OL1+SOE,OW,0xF,1,X4M,_END}; //SMSW EW +byte T_LMSW={ _OW+OL1+SOE,OW,0xF,1,X6M,_END}; //LMSW EW +//===== X486 INSTRUCTIONS +byte T_INVLPD={ _OW+OL1+SOM,OW,0xF,0o20,X7M,_END}; //INVLPG EA +//===== INTEL PENTIUM INSTRUCTIONS +byte T_CMPX8={ _OW+OL1+SOE,OW,0xF,0xC7,X1M,_END}; //CMPX8 EW 5 IF EDXEAX=MQ THEN MQ:=ECXEBX, ELSE EAXEDX:=MQ +byte T_CMOV={ _W+OL2,REO,OW,0xF,0x40,XRM,_END}; +//===== MMX INSTRUCTIONS +byte T_EMMS={ _END}; +byte T_UMOV={ _B+OL2,DER,OW,0xF,0x10,XRM,_END}; +#define _Q 1 +#define MMXE 1 +#define MMXP 1 +#define MMXPI 1 +#define MMXPE 1 +#define MMXEP 1 +byte T_PUNPCKLBW={ _D+OL2,MMXE,OW,0xF,0x60,_END}; +byte T_PUNPCKLWD={ _D+OL2,MMXE,OW,0xF,0x61,_END}; +byte T_PUNPCKLDQ={ _D+OL2,MMXE,OW,0xF,0x62,_END}; +byte T_PACKSSWB={ _Q+OL2,MMXE,OW,0xF,0x63,_END}; +byte T_PCMPGTB={ _Q+OL2,MMXE,OW,0xF,0x64,_END}; +byte T_PCMPGTW={ _Q+OL2,MMXE,OW,0xF,0x65,_END}; +byte T_PCMPGTD={ _Q+OL2,MMXE,OW,0xF,0x66,_END}; +byte T_PACKUSWB={ _Q+OL2,MMXE,OW,0xF,0x67,_END}; +byte T_PCMPEQB={ _Q+OL2,MMXE,OW,0xF,0x74,_END}; +byte T_PCMPEQW={ _Q+OL2,MMXE,OW,0xF,0x75,_END}; +byte T_PCMPEQD={ _Q+OL2,MMXE,OW,0xF,0x76,_END}; +byte T_PSRLW={ _Q+OL2,MMXE,OW,0xF,0xD1,_END}; +byte T_PSRLD={ _Q+OL2,MMXE,OW,0xF,0xD2,_END}; +byte T_PSRLQ={ _Q+OL2,MMXE,OW,0xF,0xD3,_END}; +byte T_PMULLW={ _Q+OL2,MMXE,OW,0xF,0xD5,_END}; +byte T_PSRAW={ _Q+OL2,MMXE,OW,0xF,0xE1,_END}; +byte T_PSRAD={ _Q+OL2,MMXE,OW,0xF,0xE2,_END}; +byte T_PMULHW={ _Q+OL2,MMXE,OW,0xF,0xE5,_END}; +byte T_PSLLW={ _Q+OL2,MMXE,OW,0xF,0xF1,_END}; +byte T_PSLLD={ _Q+OL2,MMXE,OW,0xF,0xF2,_END}; +byte T_PSLLQ={ _Q+OL2,MMXE,OW,0xF,0xF3,_END}; +byte T_PMADDWD={ _Q+OL2,MMXE,OW,0xF,0xF5,_END}; +byte T_PUNPCKHBW={ _Q+OL2,MMXE,OW,0xF,0x68,_END}; +byte T_PUNPCKHWD={ _Q+OL2,MMXE,OW,0xF,0x69,_END}; +byte T_PUNPCKHDQ={ _Q+OL2,MMXE,OW,0xF,0x6A,_END}; +byte T_PACKSSDW={ _Q+OL2,MMXE,OW,0xF, 0x6B,_END}; +byte T_MOVD={ _D+OL2,MMXPE,OW,0xF,0x6E,0, + _Q+OL2,MMXEP,OW,0xF,0x7E,_END}; +byte T_MOVQ={ _Q+OL2,MMXE,OW,0xF,0x6F,0, + _Q+OL2,MMXE,OW,0xF,0x7F,_END}; +byte T_PSUBUSB={ _Q+OL2,MMXE,OW,0xF,0xD8,_END}; +byte T_PSUBUSW={ _Q+OL2,MMXE,OW,0xF,0xD9,_END}; +byte T_PAND={ _Q+OL2,MMXE,OW,0xF,0xDB,_END}; +byte T_PADDUSB={ _Q+OL2,MMXE,OW,0xF,0xDC,_END}; +byte T_PADDUSW={ _Q+OL2,MMXE,OW,0xF,0xDD,_END}; +byte T_PANDN={ _Q+OL2,MMXE,OW,0xF,0xDF,_END}; +byte T_PSUBSB={ _Q+OL2,MMXE,OW,0xF,0xE8,_END}; +byte T_PSUBSW={ _D+OL2,MMXE,OW,0xF,0xE9,_END}; +byte T_POR={ _Q+OL2,MMXE,OW,0xF,0xEB,_END}; +byte T_PADDSB={ _Q+OL2,MMXE,OW,0xF,0xEC,_END}; +byte T_PADDSW={ _Q+OL2,MMXE,OW,0xF,0xED,_END}; +byte T_PXOR={ _Q+OL2,MMXE,OW,0xF,0xEF,_END}; +byte T_PSUBB={ _Q+OL2,MMXE,OW,0xF,0xF8,_END}; +byte T_PSUBW={ _Q+OL2,MMXE,OW,0xF,0xF9,_END}; +byte T_PSUBD={ _Q+OL2,MMXE,OW,0xF,0xFA,_END}; +byte T_PADDB={ _Q+OL2,MMXE,OW,0xF,0xFC,_END}; +byte T_PADDW={ _Q+OL2,MMXE,OW,0xF,0xFD,_END}; +byte T_PADDD={ _Q+OL2,MMXE,OW,0xF,0xFE,_END}; +byte T_PSRL={ _Q+OL2,MMXPI,OW,0xF,_END}; +byte T_PSRA={ _Q+OL2,MMXPI,OW,0xF,_END}; +byte T_PSLL={ _Q+OL2,MMXE,OW,0xF,_END}; + +byte Mnemonics={ +// FIRST OF ALL THE COMMANDS WITH A P-FLAG. THIS"LL MAKE THINGS EASIER FOR +// COMPARISON IN THE PARSE ENGINE + //P1=0-7 + "ADD","OR","ADC","SBB/BC","AND","SUB","XOR","CMP", + //P2=4-7 + "MUL","-","DIV","IDIV", + // IMUL ENTFERNT + //P3=0-5/7 + "ROL","ROR","RCL","RCR","SHL/AL","SHR","-","SAR", + //P4=4-7 + "BT","BTS","BTR","BTC", + // USUAL COMMANDS + "NOT","NEG","INC","DEC","TEST", "IMUL","SHLD","SHRD", + "DAA","DAS","AAA","AAS","AAM","AAD", + "MOVSX","MOVZX","CBW","CWDE","CWD","CDQ", + "BSWAP","XLAT/LATB","BSF","BSR", + "CMPXCHG","CMPXCHG486","CMPXCHG8B","XADD", + "NOP","WAIT","LOCK","HLT", //"INT", + "INTO","IRET", + "POPF","POPFD","PUSHF","PUSHFD","SAHF","LAHF", + "CMC","CLC","STC","CLI","STI","CLD","STD", + "PUSH","PUSHA","PUSHAD","POP","POPA","POPAD", + "XCHG","MOV","LEA","LSS","LFS","LGS","LES","LDS", + "ADDR","RAND", + "IN","OUT","INSB","INSW","INSD","OUTSB","OUTSW","OUTSD", + "MOVSB","MOVSW","MOVSD","CMPSB","CMPSW","CMPSD", + "STOSB","STOSW","STOSD","LODSB","LODSW","LODSD", + "SCASB","SCASW","SCASD","REP/EPNE/EPNZ","REPE/EPZ", + "JCXZ/ECXZ","LOOP","LOOPZ/OOPE","LOOPNZ/OOPNE", + "JO","JNO","JC/B/NAE","JNC/AE/NB", + "JE/Z","JNE/NZ","JBE/NA","JA/NBE", + "JS","JNS","JP/PE","JNP/PO","JL/NGE","JGE/NL", + "JLE/NG","JG/NLE", + "SETO","SETNO","SETC/ETB/ETNAE","SETNC/ETAE/ETNB", + "SETE/ETZ","SETNE/ETNZ","SETBE/ETNA","SETA/ETNBE", + "SETS","SETNS","SETP/ETPE","SETNP/ETPO","SETL/ETNGE","SETGE/ETNL", + "SETLE/ETNG","SETG/ETNLE", + "JMPS","JMPN","JMPF","JMP", + "CALL","CALLF","RET","RETF", + "ENTER","LEAVE","BOUND","ARPL", + "SLDT","STR","LLDT","LTR","VERR","VERW","LAR","LSL", + "SGDT","SIDT","LGDT","LIDT","SMSW","LMSW","CLTS", + "INVD","WBINVD","INVLPD", + //INTEL PENTIUM COMMANDS + "WRMSR","CMPX8/MPXCHG8B","CPUID","RDMSR","RDTSC","RSM", + //INTEL PENTIUM PRO INSTRUCTIONS + "RDPMC","UD2","EMMX","SETALC", + //MMX INSTRUCTIONS + "MOVD","MOVQ", //MOVE MMX REG + "PACKUS/PACKUSWB", //PACK MMX REG WITH UNSIGNED SATURATION + "PACKSSWB","PACKSSDW", //PACK MMX REG WITH SIGNED SATURATION + "PUNPCKHBW","PUNPCKHWD", + "PUNPCKHDQ", //UNPACK HIGH ORDER + "PUNPCKLBW","PUNPCKLWD", + "PUNPCKLDQ", //UNPACK LOW ORDER + "PADDB","PADDW","PADDD", //ADD MMX REG WITH WRAP-AROUND + "PADDSB","PADDSW", //" WITH SIGNED SATURATION + "PADDUSB","PADDUSW", //" WITH UNSIGNED SATURATION + "PSUBB","PSUBW","PSUBD", //SUBTRACT MMX REG + "PSUBSB","PSUBSW","PSUBUSB","PSUBUSW", + "PMULH/PMULHW","PMULL/PMULLW","PMADD/PMADDWD", + "PSLLW","PSLLD","PSLLQ","PSRLW","PSRLD","PSRLQ", + "PSRAW","PSRAD","PCMPEQB","PCMPEQW","PCMPEQD", + "PCMPGTB","PCMPGTW","PCMPGTD","PAND","PANDN","POR","PXOR","EMMS",_END}; + +dword TAB_MNEMONICS={ + #T_NOT,#T_NEG,#T_INC,#T_DEC,#T_TEST, + #T_IMUL,#T_SHLD,#T_SHRD, + #T_DAA,#T_DAS,#T_AAA,#T_AAS,#T_AAM,#T_AAD, + #T_MOVSX,#T_MOVZX,#T_CBW,#T_CWDE,#T_CWD,#T_CDQ, + #T_BSWAP,#T_XLATB, + #T_BSF,#T_BSR,#T_CMPXCHG,#T_CMPXCHG486,#T_CMPXCHG8B,#T_XADD, + #T_NOP,#T_WAIT,#T_LOCK,#T_HLT, +// #T_INT, + #T_INTO,#T_IRET, + #T_POPF,#T_POPFD,#T_PUSHF,#T_PUSHFD, + #T_SAHF,#T_LAHF, + #T_CMC,#T_CLC,#T_STC,#T_CLI,#T_STI,#T_CLD,#T_STD, + #T_PUSH,#T_PUSHA,#T_PUSHAD, + #T_POP,#T_POPA,#T_POPAD, + #T_XCHG,#T_MOV, + #T_LEA,#T_LSS,#T_LFS,#T_LGS,#T_LES,#T_LDS, + #T_ADDR,#T_RAND, + #T_IN,#T_OUT, + #T_INSB,#T_INSW,#T_INSD, + #T_OUTSB,#T_OUTSW,#T_OUTSD, + #T_MOVSB,#T_MOVSW,#T_MOVSD, + #T_CMPSB,#T_CMPSW,#T_CMPSD, + #T_STOSB,#T_STOSW,#T_STOSD, + #T_LODSB,#T_LODSW,#T_LODSD, + #T_SCASB,#T_SCASW,#T_SCASD, + #T_REP, + #T_REPE, + #T_JCXZ,#T_LOOP,#T_LOOPZ,#T_LOOPNZ, + #T_J0,#T_J1,#T_J2,#T_J3, + #T_J4,#T_J5,#T_J6,#T_J7, + #T_J8,#T_J9,#T_JA,#T_JB, + #T_JC,#T_JD,#T_JE,#T_JF, + #T_SET0,#T_SET1,#T_SET2,#T_SET3, + #T_SET4,#T_SET5,#T_SET6,#T_SET7, + #T_SET8,#T_SET9,#T_SETA,#T_SETB, + #T_SETC,#T_SETD,#T_SETE,#T_SETF, + #T_JMPSHORT,#T_JMPNEAR,#T_JMPFAR,#T_JMP, + #T_CALL,#T_CALLFAR, + #T_RET,#T_RETF, + #T_ENTER,#T_LEAVE, + #T_BOUND,#T_ARPL, + #T_SLDT,#T_STR,#T_LLDT,#T_LTR,#T_VERR,#T_VERW, + #T_LAR,#T_LSL, + #T_SGDT,#T_SIDT,#T_LGDT,#T_LIDT, + #T_SMSW,#T_LMSW,#T_CLTS, + #T_INVD,#T_WBINVD,#T_INVLPD, +//INTEL PENTIUM INSTRUCTIONS + #T_WRMSR,#T_CMPX8,#T_CPUID,#T_RDMSR,#T_RDTSC,#T_RSM, +//INTEL PENTIUM PRO INSTRUCTIONS + #T_RDPMC,#T_UD2,#T_EMMX,#T_SALC, +//MMX INSTRUCTIONS + #T_MOVD,#T_MOVQ, //MOVE MMX REG + #T_PACKUSWB, //PACK MMX REG WITH UNSIGNED SATURATION + #T_PACKSSWB,#T_PACKSSDW, //PACK MMX REG WITH SIGNED SATURATION + #T_PUNPCKHBW,#T_PUNPCKHWD,#T_PUNPCKHDQ, //UNPACK HIGH ORDER + #T_PUNPCKLBW,#T_PUNPCKLWD,#T_PUNPCKLDQ, //UNPACK LOW ORDER + #T_PADDB,#T_PADDW,#T_PADDD, //ADD MMX REG WITH WRAP-AROUND + #T_PADDSB,#T_PADDSW, //" WITH SIGNED SATURATION + #T_PADDUSB,#T_PADDUSW, //" WITH UNSIGNED SATURATION + #T_PSUBB,#T_PSUBW,#T_PSUBD, //SUBTRACT MMX REG + #T_PSUBSB,#T_PSUBSW, + #T_PSUBUSB,#T_PSUBUSW, + #T_PMULHW, + #T_PMULLW, + #T_PMADDWD, + #T_PSLLW,#T_PSLLD,#T_PSLLQ, + #T_PSRLW,#T_PSRLD,#T_PSRLQ, + #T_PSRAW,#T_PSRAD, + #T_PCMPEQB,#T_PCMPEQW,#T_PCMPEQD, + #T_PCMPGTB,#T_PCMPGTW,#T_PCMPGTD, + #T_PAND, + #T_PANDN, + #T_POR, + #T_PXOR, + #T_EMMS}; + + diff --git a/programs/develop/c--/trunk/parser.h-- b/programs/develop/c--/trunk/parser.h-- new file mode 100644 index 0000000000..503185f7b2 --- /dev/null +++ b/programs/develop/c--/trunk/parser.h-- @@ -0,0 +1,630 @@ +// ---- Генерация выражения +DoExpr(dword var,vtok,vtype,mnem) +byte varName[2*IDLENGTH]; +{ + IF(tok2notstopper()){ + IF(vtok==tk_var)Expression("eax",tk_reg,tk_dword); + ELSE{ + Expression(var,vtok,vtype); + return; + } + } + else{ // Один операнд + tok=GetVarname(#varName); + IF(tok==tk_reg)wsprintfA(#mapstr,"%s %s,%s",mnem,var,#varName); + else IF(tok==tk_var){ + IF(vtok==tk_var)Expression("eax",tk_reg,tk_dword); + ELSE wsprintfA(#mapstr,"%s %s,%s",mnem,var,#varName); + } + else IF(tok==tk_number)wsprintfA(#mapstr,"%s %s,%d",mnem,var,DoConstMath()); + ELSE IF(tok==tk_postnumber)wsprintfA(#mapstr,"%s %s#%s",mnem,var,#varName); + ELSE IF(tok==tk_locnumber){ + wsprintfA(#mapstr,"lea ebx,%s",#varName); + wsprintfA(#mapstr,"%s %s,ebx",mnem,var); + return; + } + Asm(#mapstr); + RETURN; + } + IF(vtype==tk_byte)||(vtype==tk_char)wsprintfA(#mapstr,"%s %s,al",mnem,var); + ELSE IF(vtype==tk_word)||(vtype==tk_short)wsprintfA(#mapstr,"%s %s,ax",mnem,var); + ELSE IF(vtype==tk_dword)||(vtype==tk_int)wsprintfA(#mapstr,"%s %s,eax",mnem,var); + Asm(#mapstr); +} + +// ---- Разборка и трансляция выражений +dword Expression(dword dest,dtok,dtype) +byte s[IDLENGTH]; +{ + GetInto(dest,dtok,dtype); + for(;;){ + Term(#s,dtype); + IF(tok==tk_plus){ + Term(#s,dtype); + wsprintfA(#mapstr,"add %s,%s",dest,#s); + Asm(#mapstr); + } + else IF(tok==tk_minus){ + Term(#s,dtype); + wsprintfA(#mapstr,"sub %s,%s",dest,#s); + Asm(#mapstr); + } + else IF(tok==tk_or){ + Term(#s,dtype); + wsprintfA(#mapstr,"or %s,%s",dest,#s); + Asm(#mapstr); + } + else IF(tok==tk_xor){ + Term(#s,dtype); + wsprintfA(#mapstr,"xor %s,%s",dest,#s); + Asm(#mapstr); + } + else IF(tok==tk_assign)||(tok==tk_equalto){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("sete al"); +SE: + wsprintfA(#mapstr,"movzx %s,al",dest); + Asm(#mapstr); + } + else IF(tok==tk_notequal){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("setne al"); + GOTO SE; + } + else IF(tok==tk_greater){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("setg al"); + $JMP SE; + } + else IF(tok==tk_greaterequal){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("setge al"); + $JMP SE; + } + else IF(tok==tk_less){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("setl al"); + $JMP SE; + } + ELSE IF(tok==tk_lessequal){ + Term(#s,dtype); + wsprintfA(#mapstr,"cmp %s,%s",dest,#s); + Asm(#mapstr); + Asm("setle al"); + $JMP SE; + } + ELSE BREAK; + } + return(relation); +} + +// ---- Чтение очередного элемента выражения +Factor(dword f,ftype) +{ + NextTok(); + IF(tok==tk_openbracket){ + NextTok(); + PushEAX(); + Expression("eax",tk_reg,ftype); + Asm("pop ebx; xchg eax,ebx"); + wsprintfA(f,"%s","ebx"); + } + else IF(tok==tk_number)wsprintfA(f,"%#x",DoConstMath()); + else IF(tok==tk_postnumber)wsprintfA(f,"#%s",#string); + else IF(tok==tk_proc){ + PushEAX(); + DoAnyProc(); + Asm("pop ebx; xchg eax,ebx"); + wsprintfA(f,"%s","ebx"); + } + ELSE IF(tok==tk_API){ + PushEAX(); + doAPI(); + Asm("pop ebx; xchg eax,ebx"); + wsprintfA(f,"%s","ebx"); + } + ELSE IF(tok==tk_var)||(tok==tk_param)||(tok==tk_local)||(tok==tk_openblock)|| + (tok==tk_reg)GetVarname(f); +} + +// ---- +GetInto(dword dest,dtok,dtype) +dword tk; +{ + tk=0; +DOCASE: + IF(tok==tk_minus){ +F_0: + tk=tok; + NextTok(); + GOTO DOCASE; + } + else IF(tok==tk_not){ + relation^=1; + GOTO F_0; + } + else IF(tok==tk_openbracket){ + NextTok(); + Expression(dest,dtok,dtype); + } + else IF(tok==tk_number){ + IF(tk)wsprintfA(#mapstr,"mov %s,-%#x",dest,DoConstMath()); + ELSE wsprintfA(#mapstr,"mov %s,%#x",dest,DoConstMath()); + Asm(#mapstr); + tk=0; + } + else IF(tok==tk_postnumber){ + wsprintfA(#mapstr,"mov %s,#%s",dest,#string); + Asm(#mapstr); + } + else IF(tok==tk_locnumber){ + wsprintfA(#mapstr,"lea ebx,%s",#string); + Asm(#mapstr); + wsprintfA(#mapstr,"mov %s,ebx",dest); + Asm(#mapstr); + } + ELSE IF(tok==tk_proc)DoAnyProc(); + ELSE IF(tok==tk_API)doAPI(); + ELSE IF(tok==tk_var)||(tok==tk_local)||(tok==tk_param)||(tok==tk_reg)|| + (tok==tk_openblock)GetIntoVar(dest,dtok,dtype); + ELSE preerror("Wrong expression member"); +// wsprintfA(#string,dest,"mov %s,%s",#mapstr); +// ESP+=16; Asm(#mapstr); + IF(tk==tk_minus){ + wsprintfA(#mapstr,"neg %s",dest); + Asm(#mapstr); + } + IF(tk==tk_not){ + wsprintfA(#mapstr,"not %s",dest); + Asm(#mapstr); + } +} + +// ---- +GetIntoVar(dword dName,dTok,dType) +byte varName[2*IDLENGTH]; +dword vtype,vtok; +{ + if(dTok==tk_reg){ + if(tok==tk_reg){ // Reg = Reg + IF(dType==tk_dword){// Reg32=Reg + IF(type==tk_dword){ + wsprintfA(#mapstr,"mov %s,%s",dName,#string); + Asm(#mapstr); + } + ELSE IF(type==tk_word)||(type==tk_byte){ +RDW: + wsprintfA(#mapstr,"movzx %s,%s",dName,#string); + Asm(#mapstr); + } + } + else IF(dType==tk_word){ // Reg=Reg + IF(type==tk_dword){ +GERR: + warning("Not same size\n"); + } + ELSE IF(type==tk_word){ + wsprintfA(#mapstr,"mov %s,%s",dName,#string); + Asm(#mapstr); + } + ELSE IF(type==tk_byte)GOTO RDW; + } + ELSE IF(dType==tk_byte){ // Reg=Reg + IF(type==tk_dword)||(type==tk_word)GOTO GERR; + IF(type==tk_byte){ + wsprintfA(#mapstr,"mov %s,%s",dName,#string); + Asm(#mapstr); + } + } + } + else if(tok==tk_var)||(tok==tk_param)||(tok==tk_local)||(tok==tk_openblock){ // Reg = Var + vtype=type; vtok=GetVarname(#varName); + IF(vtype==tk_dword)||(vtype==tk_int)||(dType==vtype){ + wsprintfA(#mapstr,"mov %s,%s",dName,#varName); + } + ELSE IF(vtype==tk_word)||(vtype==tk_byte){ + wsprintfA(#mapstr,"movzx %s,%s",dName,#varName); + } + ELSE IF(vtype==tk_short)||(vtype==tk_char){ + wsprintfA(#mapstr,"movsx %s,%s",dName,#varName); + } + Asm(#mapstr); + } + else IF(tok==tk_number){ // Reg = Const + wsprintfA(#mapstr,"mov %s,%d",dName,DoConstMath()); + Asm(#mapstr); + } + else IF(tok==tk_postnumber){ // Reg = #Var + GetVarname(#varName); + wsprintfA(#mapstr,"mov %s,#%s",dName,#varName); + Asm(#mapstr); + } + ELSE IF(tok==tk_locnumber){ // Reg = #locVar + vtype=type; vtok=GetVarname(#varName); + wsprintfA(#mapstr,"lea %s,%s",dName,#varName); + Asm(#mapstr); + } + } + else if(dTok==tk_var){ + if(tok==tk_reg){ // Var = Reg; + IF(type==tk_dword){ + wsprintfA(#mapstr,"mov dword %s,%s",dName,#string); + Asm(#mapstr); + } + ELSE IF(type==tk_word){ + wsprintfA(#mapstr,"mov word %s,%s",dName,#string); + Asm(#mapstr); + } + ELSE IF(type==tk_byte){ + wsprintfA(#mapstr,"mov byte %s,%s",dName,#string); + Asm(#mapstr); + } + } + else if(tok==tk_var){ // Var = Var; + vtype=type; + vtok=GetVarname(#varName); + IF(dType==tk_byte)||(dType==tk_char){ + wsprintfA(#mapstr,"mov al,%s",#varName); + Asm(#mapstr); + wsprintfA(#mapstr,"mov %s,al",dName); + Asm(#mapstr); + } + else if(dType==tk_word)||(dType==tk_short){ + IF(vtype==tk_byte){ + wsprintfA(#mapstr,"movzx ax,%s",#varName); + Asm(#mapstr); + } + else IF(vtype==tk_char){ + wsprintfA(#mapstr,"movsx ax,%s",#varName); + Asm(#mapstr); + } + ELSE IF(vtype==tk_word)||(vtype==tk_short){ + wsprintfA(#mapstr,"mov ax,%s",#varName); + Asm(#mapstr); + } + ELSE IF(vtype==tk_dword)||(vtype==tk_int){ + wsprintfA(#mapstr,"mov ax,word %s",#varName); + Asm(#mapstr); + } + wsprintfA(#mapstr,"mov %s,ax",dName); + Asm(#mapstr); + } + else if(dType==tk_dword)||(dType==tk_int){ + IF(vtype==tk_byte)||(vtype==tk_word){ + wsprintfA(#mapstr,"movzx eax,%s",#varName); + Asm(#mapstr); + } + ELSE IF(vtype==tk_char)||(vtype==tk_short){ + wsprintfA(#mapstr,"movsx eax,%s",#varName); + Asm(#mapstr); + } + ELSE IF(vtype==tk_dword)||(vtype==tk_int){ + wsprintfA(#mapstr,"mov eax,%s",#varName); + Asm(#mapstr); + } + wsprintfA(#mapstr,"mov %s,eax",dName); + Asm(#mapstr); + } + } + else IF(tok==tk_number){ // Var = Const; + wsprintfA(#mapstr,"mov %s,%d",dName,DoConstMath()); + Asm(#mapstr); + } + else IF(tok==tk_postnumber){ // Var = #Var; + vtype=type; vtok=GetVarname(#varName); + wsprintfA(#mapstr,"mov %s,#%s",dName,#varName); + Asm(#mapstr); + } + ELSE IF(tok==tk_locnumber){ // Var = #locVar; + vtype=type; vtok=GetVarname(#varName); + wsprintfA(#mapstr,"lea ebx,%s",#varName); + Asm(#mapstr); + wsprintfA(#mapstr,"mov %s,ebx",dName); + Asm(#mapstr); + } + } +} + +// ---- Чтение переменной: VarName[reg+reg*Scale+disp] +dword GetVarname(dword varName) +dword vtok; +{ + IF(tok==tk_openblock)GOTO G0; + lstrcpyA(varName,#string); + vtok=tok; + IF(vtok==tk_local)vtok=tk_var; + ELSE IF(vtok==tk_param)vtok=tk_var; + if(tok2==tk_openblock){ + NextTok(); +G0: + vtok=tk_var; + lstrcatA(varName,"["); + for(;;){ + NextTok(); + IF(tok==tk_reg)lstrcatA(varName,#string); + else IF(tok==tk_plus)lstrcatA(varName,"+"); + else IF(tok==tk_mult)lstrcatA(varName,"*"); + ELSE IF(tok==tk_number){ + wsprintfA(#mapstr,"%d",DoConstMath()); + lstrcatA(varName,#mapstr); + } + ELSE IF(tok==tk_postnumber){ + lstrcatA(varName,"#"); + lstrcatA(varName,#string); + } + ELSE IF(tok==tk_closeblock){ + lstrcatA(varName,"]"); + BREAK; + } + ELSE preerror("Illegal index expression in []"); + } + } + return(vtok); +} + +// ---- +Term(dword t,ttype) +{ + for(;;){ + Factor(t,ttype); + IF(tok==tk_mult){ + Factor(t,ttype); + IF(tok==tk_number){ + wsprintfA(#mapstr,"mov ebx,%d",DoConstMath()); + Asm(#mapstr); + wsprintfA(#mapstr,"mul %s","ebx"); + } + ELSE wsprintfA(#mapstr,"mul %s",t); + Asm(#mapstr); + } + else IF(tok==tk_div){ + Factor(t,ttype); + IF(tok==tk_number){ + wsprintfA(#mapstr,"mov ebx,%d",DoConstMath()); + Asm(#mapstr); + wsprintfA(#mapstr,"div %s","ebx"); + } + ELSE wsprintfA(#mapstr,"div %s",t); + Asm(#mapstr); + } + else IF(tok==tk_mod){ + Factor(t,ttype); + IF(tok==tk_number){ + wsprintfA(#mapstr,"mov ebx,%d",DoConstMath()); + Asm(#mapstr); + wsprintfA(#mapstr,"div %s","ebx"); + } + ELSE wsprintfA(#mapstr,"div %s",t); + Asm(#mapstr); + Asm("xchg eax,edx"); + } + ELSE IF(tok==tk_and){ + Factor(t,ttype); + IF(tok==tk_number)wsprintfA(#mapstr,"and ebx,%d",DoConstMath()); + ELSE wsprintfA(#mapstr,"and eax,%s",t); + Asm(#mapstr); + } + ELSE IF(tok==tk_not)Asm("not eax"); + ELSE BREAK; + } +} + +// ---- Сохранение EAX в стеке +PushEAX() +{ + Asm("push eax"); +} + +// ---- Сохранение EAX в стеке +/*PopEAX() +{ + Asm("pop eax"); +} */ + +// ---- Обработка строки-параметра: proc("string") +dword AddPoststring() +dword returnvalue; +{ + IF(posts >= MAXPOSTS){ + preerror("cannot add post string, post queue full"); + ExitProcess(-1); + } + EBX=posts<<2+posttype; + DSDWORD[EBX] = POST_STR; + EBX=posts<<2+postloc; + DSDWORD[EBX] = outptr; + posts++; + returnvalue = MAXDATA-1-poststrptr; + ESI=#string; + EBX> exe-file. Кроме того, большой набор +различных библиотек... которые к тому же существенно меняются от +версии к версии, что совсем не радует. И если вы переходите на новую, +более продвинутую версию компилятора, то нет никакой гарантии, что +вы сможете на нем перекомпилировать свои старые программы - примером +служит DDK от MicroSoft. + Sphinx C-- изначально был задуман и реализован для создания +компактных по размеру COM-файлов и поэтому вполне подходит для +генерации 32-разрядных приложения в модели плоской (flat) памяти. +Помимо этого большим плюсом является идея открытого кода для всех +вызываемых в программе библиотечных функций, реализованная посредством +*.h-- файлов. + Еще одна идея из компилятора Sphinx C--, заслуживающая внимания, - это +динамические процедуры, т.е. процедуры, которые могут быть помещены в тело +компилируемой программы только тогда, когда к ним есть обращение. Таким +образом, в процессе написания программы с использованием динамических +процедур гарантируется включение в тело программы только того кода, +который действительно необходим. + В процессе работы по переводу компилятора Sphinx C-- на платформу Win32 +произведены весьма существенные изменения как в самом компиляторе, так и в +идеях, на которых он реализован. Я не буду здесь выделять все отличия +настоящего компилятора от его прародителя по той простой причине, что те, кто +с ним знаком, их смогут увидеть сами, а тем, кто не имел дела с С--, нет нужды +вникать в эти детали. + Отмечу, однако, что принцип генерации кода, использовавшийся в С--, заменен +на принцип, используемый в макроассемблере TMA Свена Клозе (TMA macro assembler +Sven Klose), с проведением его адаптации к нуждам С--. + В результате появился данный компилятор, целью которого является заполнение +ниши между языком ассемблера и языком С. + + Описание языка. + + Идентификаторы. + + Идентификаторы должны начинаться с буквы или знака подчеркивания, если +являются глобальными, или же должны начинаться с символа @, если они локальные. +Далее может идти любая комбинация цифр, букв или знаков подчеркивания длиной +не более 63 символов. Буквы могут быть как из латинского, так и из национального +алфавита. Несколько примеров: + GoHome + _1234 + ПримерИдентификатора + @LocalLabel2 + + Все идентификаторы, кроме зарезервированных, являются чувствительными к +регистру, т.е. идентификаторы: ToDo и Todo компилятор воспримет как разные. + + Зарезервированные идентификаторы + + Ниже приводится список зарезервированных идентификаторов языка, которые +не могут быть использованы при создании программы иначе, как это определено +в языке: + byte char word short dword int + if else cycle do while return + docase case continue break extract from + enum struct + carryflag overflow zeroflag + notcarryflag notoverflow notzeroflag + а также названия регистров и мнемоники команд ассемблера. + + Еще раз подчеркну, что зарезервироанные слова не зависят от регистра, т.е. +Enum и eNuM компилятор воспримет в любом из вариантов, как начало списка +нумерованных констант. + + Константы + + Числовые константы могут быть заданы в одной из четырех систем счисления: +десятичной, шестнадцатиричной, восмеричной или двоичной. + Десятичные числовые константы задаются обычным образом: 444 или 007. + Шестнадцатиричное представление констант начинается с комбинации 0x: 0xFFF +или 0x088. + Восмеричное представление констант начинается с комбинации 0o: 0o777 или +0o10. + Двоичное представление констант начинается с комбинации 0b: 0b111101 или +0b11101010. + + Символы в константах заключаются в одиночные кавычки ('). Так же как и в С +символы могут заданы с помощью указания их кода после символа '\'. Список +спецсимволов: + '\a', '\b', '\f', '\l', '\n', '\r', '\t' - для форматирования вывода + '\x??' или '\???' - ASCII-символ. Код символа задан либо в 16, 10 значением. + Любые символы после '\' просто принимаются компилятором, таким образом +одиночную кавычку можно указать как '\''. + + Строковые константы задаются путем заключения их в двойные кавычки ("). +Внутри строковой константы допускается указание спецсимволов в одиночных +кавычках. Примеры строковых констант: + "Пример строковой константы\n" + "Need '\"'word'\"' in data declaration" -> Need "word" in data declaration + + При определении числовых и символьных констант допускается использование +выражений, которые вычисляются в процессе компиляции. Значением константы +будет результат вычисления выражения: + 1*2*3/2+4 даст значение константы 7. + Вычисления проводятся слева-направо без учета приоритета операций. + + Стандартные типы данных + + Имеется шесть стандартных типов данных: byte, char, word, short, dword +и int. В таблице приведены размер и диапазон значений для каждого типа: + ------------------------------------------------------------------- + Тип | Размер | Диапазон значений + переменной | в байтах | (десятичн.) | (hex) + ------------------------------------------------------------------- + byte | 1 | 0...255 | 0...0xFF + char | 1 | -127...127 | 0x80...0x7F + word | 2 | 0...65535 | 0...0xFFFF + short | 2 | -32768...32767 | 0x8000...0x7FFF + dword | 4 | 0...4294967295 | 0...0xFFFFFFFF + int | 4 | -2147483648... | 0x80000000 ... + | | 2147483647 | 0x7FFFFFFF + ------------------------------------------------------------------- + + Глобальные переменные + + Объявление переменных имеет обычный для С синтаксис: + + <тип> <список идентификаторов>; + + Список идентификаторов состоит из одного или более идентификаторов, +разделенных запятыми. В списке также могут присутсвовать одномерные массивы, +объявляемые в виде: + <идентификатор>[<размерность>]. + + Примеры объявлений переменных: + dword i,j; // i и j типа dword + byte Tab='\t'; // переменная Tab типа byte с начальным значением + char string[]="This is a string\n"; + int z,b[6]; // z типа int и массив целых - b + + Выражения + + Выражения состоят из левой и правой частей, разделенных либо операцией +присваивания, либо операцией сравнения. Левая часть выражения может быть +либо переменной, либо регистром. В правой части выражения может находиться +произвольное количество переменных, функций, констант, скобок и знаков операций. +Ниже приводится таблица всех допустимых операций: +------------------------------------------------------------------------- +Операция | Значение | Пример +------------------------------------------------------------------------- + = | присвоить или | edi = 33; + | проверить равенство | while(ch = 'a') + + | сложить | eax = Count + 5; + - | вычесть | Count = eax - edi; + * | умножить | x = y * 3; + / | разделить | y = ecx / x; + % | остаток деления | y = edi / 7; + & | логическое AND | a = B & c; + | | логическое OR | a = B | c; + ^ | логическое XOR | a = B ^ c; + << | сдвиг бит влево | x = y << 5; + >> | сдвиг бит вправо | x = y >> 6; + += | увеличить на | a += 6; // a = a + 6; + -= | уменьшить на | a -= 5; // a = a - 5; + &= | побитный AND | a &= 0xF; // a = a & 0xF; + |= | побитный OR | a |= 0o77; // a = a | 0o77; + ^= | побитный XOR | a ^= 0b1101; // a = a ^ 0b1101; + <<= | сдвиг бит влево | a <<= 7; // a = a << 7; + >>= | сдвиг бит вправо | a >>= 3; // a = a >> 3; + >< | обмен(swap) | x >< y; // temp=y; y=x; x=temp; + == | проверить равенство | if( x=='7' ) // для тех, кому так привычнее + > | больше чем | case( x > y ) + < | меньше чем | if( a < 0 ) + >= | больше или равно | while(( b >= a ) & ( x >= ( y - 7 ))) + <= | меньше или равно | if( y <= ( a + b - 30 )) +!= или <>| не равно | case( a != b) или же case( a <> b) + # | адрес переменной | esi = #Count; // esi=адрес переменной Count + + Функции + + Объявление функций имеет вид: + + <тип> <идентификатор>(<список параметров>) + +Список параметров задает типы и имена формальных параметров, используемых при +вызове функции. Компилятор не осуществляет проверку соответствия списка +формальных параметров функции фактическим, поэтому следует внимательно следить +за корректностью вызова функций. + Тип возвращаемого из функции значения можно не указывать. В этом случае +по умолчанию считается, что функция возвращает значение типа dword. Значение +помещается при возврате из функции в регистр eax для типов dword и int, в +регистр ax для типов word и short и в регистр al для типов byte и char. + В списке параметров для каждого параметра указывается его тип. Параметры +одного типа, идущие подряд, разделяются запятыми. Формальные параметры разного +типа в объявлении функции разделяются символом ;. Если тип параметра не задан, +то считается, что параметр имеет тип dword. Не зависимо от типа параметра при +вызове функции для каждого параметра выделяется 4 байта (dword). Это связано +с тем, что в Win32 стек всегда должен иметь выравнивание (alignment) на границу +двойного слова. + Примеры объявления функций и их вызовов. + Объявление Пример вызова + char ToUpper(char ch) upChar = ToUpper('i'); + MergeStrings(dword dest,str1,str2) MergeStrings(#str,"One","+Two"); + получим str="One+Two" + Convert(dword str; int number,base) Convert(#num, -567, 16); + + При вызове функции первый параметр помещается в стек последним. Пример: + WriteFile(handle,"Hello World!\n",14,#dWriteFileCount,0); +будет реализован: + push 0 + push #dWriteFileCount + push 14 + push #"Hello World!" + push handle + call WriteFile + При возврате из функции стек очищается от параметров командой: ret number. + + Все объявляемые в программе функции являются динамическими. Это значит, +что код функции вставляется в программу лишь только в случае обращения к ней. +То же самое относится и к любым глобальным переменным в программе. + + Структурные операторы + + Применение структурных операторов в программе делает ее более удобной для +чтения и анализа. Кроме того, написать несколько структурных операторов проще, +чем путаться в похожих именах большого числа меток и мучиться, придумывая +уникальное имя для каждой новой метки. В то же время не запрещается использовать +и метки в любом месте программы. Хорошо поставленная метка способна здорово +облегчить написание и анализ программы. + + Оператор if. + + В общем виде условный оператор можно записать так: + + if(<условие>) + <группа операторов1> + else + <группа операторов2> + + Алгоритм выполнения условного оператора состоит в следующем: +проверяется <условие>, и если оно истинно, то выполняется <группа операторов1>, +следующая за if, после чего управление передается за конец условного оператора. +Если условие ложно, то управление передается на <группу операторов2>, следующую +за else. Порядок выполнения условного оператора в случае отсутствия else +очевиден. В качестве группы операторов может быть либо один оператор, либо блок +из нескольких операторов в {} скобках. Вот несколько примеров: + if(edx<=2){ + WriteStr("Equal or less two\n"); + return(); + } + else{ + WriteStr("Greater than two\n"); + return(0); + } + + if((x<>0)&(y<>0)) + return(x/y); + + Оператор cycle + + Оператор цикла cycle имеет вид: + + cycle(<счетчик>) <группа операторов> + + Цикл выполняется до тех пор пока значение счетчика не будет равно нулю. +Проверка счетчика на равенство нулю и его уменьшение на единицу производится +в конце группы операторов цикла. Допускается внутри цикла использовать и менять +значение счетчика. Если счетчик не указан, то цикл будет бесконечным. Пример: +#import "kernel32.dll" +#import "user32.dll" +dword Count; +dword dWriteFileCount; +dword handle; +byte s[20]=0; +main(){ +handle=GetStdHandle(-11); +Count=4; +cycle(Count){ + if(Count=2) + Count--; + wsprintfA(#s,"Count=%d\n",Count); ESP+=12; + WriteFile(handle,#s,lstrlenA(#s),#dWriteFileCount,0); + } +} + При выполнении будет выведено: +Count=4 +Count=3 +Count=1 + + Оператор while + + Оператор цикла while имеет вид: + + while(<условие>) + <группа операторов> + + Группа операторов в цикле while выполняется пока <условие> остается +истинным. Пример из описания оператора cycle может быть реализован с помощью +while следующим образом: +Count=4; +while(Count){ + if(Count=2) + Count--; + wsprintfA(#s,"Count=%d\n",Count); ESP+=12; + WriteFile(handle,#s,lstrlenA(#s),#dWriteFileCount,0); + Count--; + } +} + + Оператор do ... while + + Оператор цикла do ... while имеет вид: + + do + <группа операторов> + while(<условие>) + + Группа операторов в цикле do ... while выполняется пока <условие> остается +истинным. Пример из описания оператора cycle может быть реализован с помощью +do ... while следующим образом: +Count=4; +do{ + if(Count=2) + Count--; + wsprintfA(#s,"Count=%d\n",Count); ESP+=12; + WriteFile(handle,#s,lstrlenA(#s),#dWriteFileCount,0); + Count--; + } while(Count) +} + Особенностью оператора do ... while является то, что <группа операторов> +в цикле всегда выполняется не менее одного раза. + + Оператор docase + + Оператор ветвления docase имеет вид: + + docase + <группа операторов 0> + case(<условие1>) + <группа операторов 1> + ... + case(<условиеN>) + <группа операторов N> + default + <группа операторов N1> + + Оператор docase позволяет заменить вложенные группы из if ... else if ... +else ... . Кроме того далее будет показана на примере универсальность этого +оператора. Пример из описания оператора cycle может быть реализован с помощью +docase следующим образом: +Count=4; +docase{ + if(Count=2) + Count--; + wsprintfA(#s,"Count=%d\n",Count); ESP+=12; + WriteFile(handle,#s,lstrlenA(#s),#dWriteFileCount,0); + Count--; + case(Count=0) + break; + default + continue; + } +} + + Операторы continue и break + + Эти операторы используются внутри выше описанных операторов цикла cycle, +while, do...while и операторе docase для перехода на начало цикла или docase +по оператору continue и на выход за конец оператора по break. Пример: + while(cond1){<--╘ + ... | + if(cond2) | + continue; --+ + ... | + if(cond3) | + break; ---+ | + ... | | + } ----------|-+ + <----------+ + + Оператор enum + + Назначение оператора заключается в создании групп нумерованных констант. +Пример: + enum { ab, ac=2, ad, ae=6}; при этом будет: ab=0, ac=2, ad=3, ae=6. + + Оператор struc + + Служит для описания структурированных данных, аналогично С. +Пока не реализован. Можно, используя enum, без всяких проблем работать с +данными любой структуры. Пример: +Для использования структуры: +struct localrec{ + struct localrec *next; + char localid[IDLENGTH]; + int localtok; + int localnumber; + }; +создадим: +// ---- Структура localrec - описание локальной переменной +enum{ localnext=0, // Указатель на следующую localrec + localid=4, // Имя локальной переменной + localtok=localid+IDLENGTH, // Значение token + localtype=localtok+4, // тип переменной + localnumber=localtype+4, // Позиция в стеке + local_size=localnumber+4}; // Размер структуры +И теперь в программе можно использовать нумерованные константы для обращения +к элементам структуры localrec: +// ---- Добавить локальную переменную в список +AddLocalvar(dword str,tk,ltype,num) +dword ptr,newptr; +{ +newptr=LocalAlloc(0x40, local_size); +if(newptr==NULL){ + preerror("Compiler out of memory for local symbol linked list"); + ExitProcess(e_outofmemory); + } +if(locallist==NULL) + locallist = newptr; + else{ + ptr = locallist; EBX=ptr; + docase{ + EAX=[EBX+localnext]; + case(EAX!=0){ + EBX=EAX; continue; + } + } + [EBX+localnext]=newptr; + } +EBX=newptr; lstrcpyA(EBX+localid, str); +EBX=newptr; [EBX+localtok] = tk; [EBX+localtype] = ltype; +[EBX+localnumber] = num; [EBX+localnext] = NULL; localptr = EBX; +} + + Метки + + Требования к именам меток те же, что и к идентификаторам. Исключением +являются локальные метки - они должны начинаться с символа '@'. Локальные +метки доступны только в пределах той функции, в которой они определены, а +глобальные - по всей программе. При создании имен локальных меток следует +учитывать, что компилятор при реализации структурных операторов генерирует +метки вида: @l<число>. Чтобы избежать коллизий, следует для своих меток не +применять такого вида. Любая метка завершается символом двоеточия (:). +Примеры меток: + NotUpperCase: // это глобальная метка + @NotUpperCase: // а это локальная метка + + Индексация массивов + + Элементы массива любого типа индексируются в байтовых единицах, независимо +от типа данных. Это ВСЕГДА следует помнить при работе. Индексы имеют вид, +принятый в ассемблере для 386 CPU: + + <переменная>[<базовый регистр>+<масштаб>*<индексный регистр>+<индекс>] + + Вот несколько примеров: + Str[7]; // седьмой байт из массива Str + IntArray[4*ebx]; // ebx элемент из массива целых - IntArray + ByteArray[esi+8*ecx+300]; + + Специальные условные выражения + + Имеется шесть специальных условных выражений: + CarryFlag, NotCarryFlag, Overflow, NotOverflow, ZeroFlag, NotZeroFlag. Они +служат для генерации кода проверяющего состояние флагов CPU. + + Комментарии + + Комментарии задаются аналогично С. + + Директивы компилятора + + Все директивы компилятора начинаются с символа '#'. Список директив и их +назначение приводятся ниже: + #debug // указывает компилятору на необходимость генерации + // отладочной информации для компилируемой программы + #define // определить константу или идентификатор. Пример: + // #define MAXLINES 400 + // #define less < + // #define SetTrue "eax=1" + // if(lines less MAXLINES) --> if(lines<400) + // SetTrue; --> eax=1; + #dll // указывает компилятору на генерацию DLL-файла. Обычно - exe. + #include // подключение файла с исходным текстом. Аналогично С. + #import // импорт функций из DLL-файла по имени. + #importN // импорт функций из DLL-файла по номеру. Пример смотрите в + // описании структурных операторов cycle, while и т.д. + #list // указывает компилятору на генерацию файла с листингом (.lst) + #map // указывает компилятору на генерацию map-файла (.map) + + Встроенный ассемблер + + Ассемблер поддерживает большую часть инструкций из набора 386, 486 и 586 +процессоров. Мнемоники ассемблера могут быть помещены внутри тела любой функции +без каких-либо ограничений. Пример: +// Выделение слова в Dest из строки символов Source +dword GetWord(dword Source,Dest){ + push esi; push edi; esi=Source; edi=Dest; +// Ищем первый непустой символ +@up: lodsb; cmp al,' '; jz @up; // Пробел + cmp al,0; jz @down // Конец строки Source +// Копируем слово в Dest +@up1: stosb; cmp al,0; jz @down; // Конец строки Source + lodsb; cmp al,' '; jnz @up1; // Не пробел + al=0; jmp @up1 // Отметим конец слова +@down: +// Слово выделено и скопировано в Dest + eax=esi-Source; eax--; // Вычислим длину слова + pop edi; pop esi // Восстановим esi и edi +} + + Заключение + + Не все из вышеописанного реализовано. Это обусловлено в первую очередь тем, +что данная версия является предварительной и основной ее целью является +выявление интереса компьютерной общественности к такому компилятору. + Если Вы заинтересовались этим продуктом или у Вас возникли какие-либо +вопросы, идеи или предложения, то прошу о них сообщить мне по адресу: +halimovskiy@usa.net. + + С уважением А.Халимовский E-mail: halimovskiy@usa.net diff --git a/programs/develop/c--/trunk/tokscan.h-- b/programs/develop/c--/trunk/tokscan.h-- new file mode 100644 index 0000000000..807c8a2e8a --- /dev/null +++ b/programs/develop/c--/trunk/tokscan.h-- @@ -0,0 +1,666 @@ +// ---- Преобразование текущего символа для констукций типа: \n, \x00, т.п. +byte ConvertChar() +dword hold; +{ + IF(cha!='\\')return(cha); + NextChar(); // Обработка следующего за \ + IF(AL>='0')&&(AL<='9'){ +// Десятичная константа + EDX=0; + AL-='0'; + EAX=AL; + EDX+=EAX; + ECX=2; + loop(ECX){ + EBX=EDX; + EDX<<=1; + EBX<<=3; + EDX+=EBX; + NextChar(); + EAX=AL; + IF(AL<'0')||(AL>'9')GOTO ERR; + AL-='0'; + EDX+=EAX; + } + return(DL); +ERR: + expectederror("decimal digit"); + return(0); + } + IF(cha=='a')return('\a'); + IF(cha=='b') return('\b'); + IF(cha=='f') return('\f'); + IF(cha=='l') return(10); + IF(cha=='n') return(13); + IF(cha=='p') return('_'); + IF(cha=='r') return(13); + IF(cha=='t') return('\t'); + IF(cha=='v') return('\v'); + IF(cha=='x'){ // HEX константа + ECX=2; + hold=0; + loop(ECX){ + $PUSH ECX; + NextChar(); + CharUpperA(AL); + EBX=AL; + IF(AL>='0')&&(AL<='9')GOTO LX1; + IF(AL<'A')&&(AL>'F')GOTO ERR1; +LX1: + EDX=hold; + EDX<<=4; + IF(BL>='A')BL-='A'-10-'0'; + BL-='0'; + EDX+=EBX; + hold=EDX; + $POP ECX; + } + return(hold); +ERR1: + $POP ECX; + expectederror("hexdecimal digit"); + return(0); + } + return(cha); +} + +// ---- Разделители +byte Delim1={'#','\"','\'','-','+','*','/','%','|','&','!','^','=','>','<','@',0}; +byte Delim2={':',';','(',')','{','}','[',']',',','.','$','?','~',0}; +// ---- Определение типа token +TokScan(dword tok4,type4,src4,post4,string4,number4) +dword useme,strptr; +dword next; +dword dirPrefix,locPrefix;// Флаги обнаружения #directive или @LocalLabel +{ + dirPrefix=0; + locPrefix=0; +SC_0: + strptr=string4; + next=1; + EAX=number4; + DSDWORD[EAX] = 0; + EAX=type4; + DSDWORD[EAX] = 0; + EAX=src4; + DSDWORD[EAX] = 0; + EAX=post4; + DSDWORD[EAX] = 0; + WhiteSpaces(); + ESI=string4; + DSBYTE[ESI]=0; + ECX=17; + EDI=#Delim1; + AL=cha; + $REPNZ $SCASB; + $JCXZ SC00 // Не первая группа разделителе + EDI=EDI-#Delim1-1<<2+#Jmp_Delim1; + $JMP NEAR DSDWORD[EDI]; +SC00: + ECX=14; + EDI=#Delim2; + AL=cha; + $REPNZ $SCASB; + $JCXZ SC01 // Не вторая группа разделителе + EDI=EDI-#Delim2-1+#tk_delim2; + EAX=DSBYTE[EDI]; + EBX=tok4; + DSDWORD[EBX]=EAX; + $JMP ScEx +SC01: + IF(locPrefix){ + EDI>=IDLENGTH){ + preerror("Maximum length for an identifier exceeded"); + strptr = string4 + IDLENGTH - 1; + } + EDI=strptr; + AL=0; + $STOSB + EBX=tok4; + DSDWORD[EBX]=tk_id; + IF(locPrefix)goto FL; + FastSearch(string4,#St_Directives); // Это зарезервированное слово? + IF(CARRYFLAG){ // Команда обнаружена в списке + EBX=number4; DSDWORD[EBX]=EAX; // Запомним порядковый номер + EBX=tok4; // Укажем соответствующий token + IF(dirPrefix)DSDWORD[EBX]=tk_directive; + ELSE DSDWORD[EBX]=tk_command; + dirPrefix=0; + next=0; + $JMP ScEx + } + FastSearch(string4,#St_Mnemonics); // Это мнемоника? + IF(CARRYFLAG){ // Мнемоника ассемблера + EBX=number4; + DSDWORD[EBX]=EAX; // Запомним номер мнемоники + EBX=tok4; + DSDWORD[EBX]=tk_mnemonics; + next=0; + $JMP ScEx + } + FastSearch(string4,#St_Registers); // Это имя регистра? + IF(CARRYFLAG){ // Регистр + EBX=number4; + DSDWORD[EBX]=EAX; // Запомним номер региста + EAX>>=3; + $CMP EAX,2; + $JG R0 // Управляющие регистры? + EBX=tok4; + DSDWORD[EBX]=tk_reg; + EBX=type4; + EAX<<=1; + DSDWORD[EBX] = EAX + tk_byte; + GOTO R1; +R0: + EBX=tok4; + EAX-=3; + DSDWORD[EBX]=EAX+tk_controlreg; +R1: + next=0; + $JMP ScEx + } +FL: + EAX=tok4; + EAX=DSDWORD[EAX]; + IF(AL==tk_id){ + SearchLocals(tok4,type4,string4,number4); // Есть в списке локальных? + EAX=tok4; + EAX=DSDWORD[EAX]; + IF(AL==tk_id){ + IF(locPrefix){ // @label + EBX=tok4; + DSDWORD[EBX]=tk_locallabel; + IF(displaytokerrors)AddLocalvar(#string,tk_locallabel,0,0); + locPrefix=0; + GOTO FL; + } + SearchTree(tok4,type4,src4,post4,string4,number4); + } + } + IF(dirPrefix){ // Конструкция: #ident + dirPrefix=0; + EBX=tok4; + EAX=DSDWORD[EBX]; + IF(AL==tk_id){ // Есть в списке? + IF(displaytokerrors){ + EAX=post4; + DSDWORD[EAX] = 1; // Добавим в список + EBX=tok4; + DSDWORD[EBX]=tk_undefproc; + AddToTree(string4); + } + } + // Идентификатор есть в списке + EAX=post4; + EAX=DSDWORD[EAX]; + EBX=tok4; + IF(EAX){ // Еще не обработанный идентификатор? + DSDWORD[EBX] = tk_postnumber; + } + ELSE{ + EAX=tok4; + EAX=DSDWORD[EAX]; + IF(EAX==tk_param)DSDWORD[EBX] = tk_locnumber; + ELSE IF(EAX==tk_local)DSDWORD[EBX] = tk_locnumber; + ELSE DSDWORD[EBX] = tk_number; + } + } + next=0; + $JMP ScEx + } + else if(IsNumber(cha)){ // Идентификатор начинается с цифры + EAX=tok4; + DSDWORD[EAX]=tokens; // Пока неизвестный token + if(cha=='0'){ + NextChar(); + IF(cha=='X')||(cha=='x'){ // hex - число + EAX=tok4; + DSDWORD[EAX]=tk_number; +HEX: + NextChar(); + CharUpperA(AL); + $CMP AL,'0'; + $JL EHEX; + $CMP AL,'9'; + $JA HEXAF + AL-='0'; + for(;;){ + EBX=number4; + ECX=DSDWORD[EBX]; + ECX<<=4; + EAX+=ECX; + DSDWORD[EBX]=EAX; + GOTO HEX; +HEXAF: + IF(AL<'A')||(AL>'F')BREAK; + AL-='7'; + } +EHEX: + } + ELSE IF(cha=='B')||(cha=='b'){ // binary число + EAX=tok4; + DSDWORD[EAX]=tk_number; + for(;;){ + NextChar(); + IF(AL!='0')||(AL!='1')BREAK; + AL-='0'; + EBX=number4; + ECX=DSDWORD[EBX]; + ECX<<=1; + EAX+=ECX; + DSDWORD[EBX]=EAX; + } +EBIN: + } + ELSE IF(cha=='O')||(cha=='o'){ // octal число + EAX=tok4; + DSDWORD[EAX]=tk_number; + for(;;){ + NextChar(); + IF(AL<'0')||(AL>'7')BREAK; + AL-='0'; + EBX=number4; + ECX=DSDWORD[EBX]; + ECX<<=3; + EAX+=ECX; + DSDWORD[EBX]=EAX; + } +EOCT: + } + } + EAX=tok4; + EAX=DSDWORD[EAX]; + IF(EAX!=tk_number){ // decimal число + for(;;){ + EAX=cha; + IF(AL<'0')||(AL>'9')BREAK; + AL-='0'; + EBX=number4; + EDX=DSDWORD[EBX]; + ECX=EDX; + EDX<<=1; + ECX<<=3; + EDX+=ECX; + EAX+=EDX; + DSDWORD[EBX]=EAX; + NextChar(); + } + EAX=tok4; + DSDWORD[EAX]=tk_number; + } + next=0; + } + ELSE{ + IF(displaytokerrors)preerror("tokenizer: bad character value"); + NextChar(); + TokScan(tok4,type4,src4,post4,string4,number4); + next=0; + } + $JMP ScEx +Jmp_Number: // #directive || #identifier + NextChar(); + dirPrefix=1; + $JMP SC_0 +Jmp_Local: // @LocalLabel + NextChar(); + locPrefix=1; + $JMP SC01 +Jmp_String: // Строка символов в "" + do{ + NextChar(); + IF(cha=='\"') // Закрывающая кавычка + BREAK; + EAX=strptr-string4; + IF(EAX0){ + WhiteSpaces(); + IF( cha == '*' ){ + NextChar(); + IF(cha == '/' ){ // Закрытие комментария + IF(useme > 0)useme--; // Уменишим счетчик + NextChar(); + } + } + ELSE{ + IF( cha == '/' ){ + NextChar(); + IF( cha == '*' ){ // Вложенный комментарий + useme++; + NextChar(); + } + } + ELSE // Не ограничители комментария + NextChar(); + } + } + IF(endoffile){ + EAX=tok4; + DSDWORD[EAX]=tk_eof; + IF(useme > 0)&&(displaytokerrors)unexpectedeof(); + } + ELSE TokScan(tok4,type4,src4,post4,string4,number4); + } + ELSE IF(cha=='/'){ // Комментарий до конца строки // + do{ + NextChar(); + IF(endoffile)BREAK; + } while(cha!=10 ); + IF(endoffile){ + EAX=tok4; + DSDWORD[EAX]=tk_eof; + } + ELSE{ + WhiteSpaces(); + TokScan(tok4,type4,src4,post4,string4,number4); + } + } + ELSE{ + WhiteSpaces(); + IF(cha=='-'){ + EAX=tok4; DSDWORD[EAX]=tk_divminus; // /- + NextChar(); + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_div; // / + } + } + next = 0; + $JMP ScEx +Jmp_Mod: // % + NextChar(); + WhiteSpaces(); + IF(cha == '-'){ + EAX=tok4; + DSDWORD[EAX] = tk_modminus; // %- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_mod; next=0; + } + $JMP ScEx +Jmp_Or: // | + NextChar(); + IF(cha=='='){ + EAX=tok4; + DSDWORD[EAX]=tk_orequals; // |= + } + ELSE IF(cha=='|'){ + EAX=tok4; + DSDWORD[EAX]=tk_oror; // || + } + ELSE{ + WhiteSpaces(); + IF(cha=='-'){ + EAX=tok4; + DSDWORD[EAX]=tk_orminus; // |- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_or; + next=0; // | + } + } + $JMP ScEx +Jmp_And: // & + NextChar(); + IF(cha=='='){ + EAX=tok4; + DSDWORD[EAX]=tk_andequals; // &= + } + ELSE IF(cha=='&'){ + EAX=tok4; + DSDWORD[EAX]=tk_andand; // && + } + ELSE{ + WhiteSpaces(); + IF(cha == '-'){ + EAX=tok4; + DSDWORD[EAX]=tk_andminus; // &- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_and; + next=0;// & + } + } + $JMP ScEx +Jmp_Not: // ! + NextChar(); + IF(cha == '='){ + EAX=tok4; + DSDWORD[EAX]=tk_notequal; // != + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_not; + next=0; // ! + } + $JMP ScEx +Jmp_Xor: // ^ + NextChar(); + IF(cha == '='){ + EAX=tok4; + DSDWORD[EAX]=tk_xorequals; // ^= + } + ELSE{ + WhiteSpaces(); + IF(cha == '-'){ + EAX=tok4; + DSDWORD[EAX]=tk_xorminus; // ^- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_xor; + next=0; // ^ + } + } + $JMP ScEx +Jmp_Equal: // = + NextChar(); + IF(cha == '='){ + EAX=tok4; + DSDWORD[EAX]=tk_equalto; // == + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_assign; + next=0; // = + } + $JMP ScEx +Jmp_Great: // > + NextChar(); + IF(cha=='>'){ + NextChar(); + IF( cha == '=' ){ + EAX=tok4; + DSDWORD[EAX]=tk_rrequals; // >>= + } + ELSE{ + WhiteSpaces(); + IF(cha == '-'){ + EAX=tok4; + DSDWORD[EAX]=tk_rrminus; // >>- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_rr; + next=0;// >> + } + } + } + ELSE IF(cha=='<'){ + EAX=tok4; + DSDWORD[EAX]=tk_swap; // >< + } + ELSE IF(cha=='='){ + EAX=tok4; + DSDWORD[EAX]=tk_greaterequal; // >= + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_greater; + next= 0; // > + } + GOTO ScEx; +Jmp_Less: // < + NextChar(); + IF(cha=='<'){ + NextChar(); + IF(cha=='='){ + EAX=tok4; + DSDWORD[EAX]=tk_llequals; // <<= + } + ELSE{ + WhiteSpaces(); + IF(cha == '-'){ + EAX=tok4; + DSDWORD[EAX]=tk_llminus; // <<- + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_ll; + next=0; + } + } + } + ELSE IF(cha=='>'){ + EAX=tok4; + DSDWORD[EAX]=tk_notequal; // <> + } + ELSE IF(cha=='='){ + EAX=tok4; + DSDWORD[EAX]=tk_lessequal; // <= + } + ELSE{ + EAX=tok4; + DSDWORD[EAX]=tk_less; + next=0; // < + } +ScEx: + IF(next)NextChar(); +} + +// '#','\"','\'','-','+','*','/','%','|','&','!','^','=','>','<','@' +dword Jmp_Delim1={#Jmp_Number,#Jmp_String,#Jmp_Const,#Jmp_Minus, +#Jmp_Plus,#Jmp_Mul,#Jmp_Div,#Jmp_Mod,#Jmp_Or,#Jmp_And, +#Jmp_Not,#Jmp_Xor,#Jmp_Equal,#Jmp_Great,#Jmp_Less,#Jmp_Local}; + +// ':', ';', '(', ')', +byte tk_delim2={tk_colon,tk_semicolon,tk_openbracket,tk_closebracket, +// '{', '}', '[', ']', ',', +tk_openbrace,tk_closebrace,tk_openblock,tk_closeblock,tk_comma, +//'.', '$', '?', '~' +tk_period,tk_dollar,tk_question,tk_tilda}; diff --git a/programs/develop/c--/trunk/tree.h-- b/programs/develop/c--/trunk/tree.h-- new file mode 100644 index 0000000000..0a1661e180 --- /dev/null +++ b/programs/develop/c--/trunk/tree.h-- @@ -0,0 +1,461 @@ +// ---- Занесение поименованной константы в список +AddConstToTree(dword keystring,constvalue) +dword ptr,newptr; // idrec structure +{ + newptr=LocalAlloc(0x40,recsize); + IF(EAX==NULL){ + preerror("Compiler out of memory for identifier tree"); + ExitProcess(e_outofmemory); + } + ptr=treestart; + IF(EAX == NULL ) // Пустой список? + treestart = newptr; + ELSE{ + for(;;){ +// Поиск свободной ссылки + ESI=ptr; + EAX=lstrcmpA(DSDWORD[ESI+recid],keystring); + ESI=ptr; + IF(long EAX<0){ + // ptr.left + IF(DSDWORD[ESI+left]==0){ // Нашли пустой левый - добавим + DSDWORD[ESI+left]=newptr; + BREAK; // ptr.left=newptr + } + ptr=DSDWORD[ESI+left]; + } + ELSE IF(EAX!=0){ + // ptr.right + IF(DSDWORD[ESI+right]==0){ // Нашли пустой правый - добавим + DSDWORD[ESI+right]=newptr; + BREAK; + } + ptr=DSDWORD[ESI+right]; + } + ELSE internalerror("string found in tree when trying to add to it"); + } + } +// Формируем новую запись в списке + ESI=newptr; + DSDWORD[ESI+recid]=LocalAlloc(0x40,lstrlenA(keystring)+1); + lstrcpyA(DSDWORD[ESI+recid],keystring); + ESI=newptr; + DSDWORD[ESI+newid]= NULL; + DSDWORD[ESI+rectok]=tk_number; + DSDWORD[ESI+recnumber]=constvalue; + DSDWORD[ESI+recpost]=0; + DSDWORD[ESI+left]=NULL; + DSDWORD[ESI+right]=NULL; + DSDWORD[ESI+recmodline] = currmod<<16+linenumber; +} + +// ---- Добавить локальную переменную в список +AddLocalvar(dword str,tk,ltype,num) +dword newptr; +{ + newptr=LocalAlloc(0x40,local_size); + IF(EAX==NULL){ + preerror("Compiler out of memory for local symbol linked list"); + ExitProcess(e_outofmemory); + } + IF(locallist==NULL)locallist = newptr; + ELSE{ + EAX=locallist; + EBX>>16; + EAX=FILENAMESIZE*EBX+#modules; + EBX=EAX; + wsprintfA(#mapstr,"File:%s, line=%-d:\n%s\n",EBX, + DSDWORD[ESI+recmodline]&0xFFFF,DSDWORD[ESI+recsrc]); + fprint(mapfile,#mapstr); + ESI=ptr; LocalFree(DSDWORD[ESI+recsrc]); // Освободим память + DSDWORD[ESI+recsrc]=0; + } + } + numberofids++; + } + ESI=ptr; + DisplayTreeAll(DSDWORD[ESI+left]); +} +} + +// ---- Вывод списка глобальных констант +DisplayTreeConstants(dword ptr) +{ + IF( ptr != NULL ){ + ESI=ptr; + DisplayTreeConstants(DSDWORD[ESI+right]); + ESI=ptr; + EAX=DSDWORD[ESI+rectok]; + IF(EAX == tk_number){ + wsprintfA(#mapstr,"#define %10ld /* %8lX hex */ %s\n", + DSDWORD[ESI+recnumber],DSDWORD[ESI+recnumber],DSDWORD[ESI+recid]); + fprint(mapfile,#mapstr); + numberofids++; + } + ESI=ptr; + DisplayTreeConstants(DSDWORD[ESI+left]); + } +} + +// ---- Вычисление значения беззнаково константы +dword DoConstDwordMath() +dword value; +{ + IF(tok == tk_minus){ + NextTok(); + IF(tok != tk_number){ + numexpected(); + return(0); + } + number = -number; + } + IF(tok != tk_number){ + numexpected(); + return(0); + } + value = number; + while(tok2isopperand()){ + NextTok(); + IF(tok2!=tk_number)return(value); + switch(tok){ + case tk_minus: value -= number2; break; + case tk_plus: value += number2; break; + case tk_xor: value ^= number2; break; + case tk_and: value &= number2; break; + case tk_or: value |= number2; break; + case tk_mod: value = value % number2; BREAK; + case tk_div: value = value / number2; BREAK; + case tk_mult: value = value * number2; BREAK; + case tk_rr: value >>= number2; BREAK; + case tk_ll: value <<= number2; BREAK; + case tk_xorminus: value ^= -number2; BREAK; + case tk_andminus: value &= -number2; BREAK; + case tk_orminus: value |= -number2; BREAK; +/* case(tok==tk_modminus) value %= -number2; + case(tok==tk_divminus) value /= -number2; + case(tok==tk_multminus) value *= -number2; */ + case tk_rrminus: value >>= -number2; BREAK; + case tk_llminus: value <<= -number2; BREAK; + } + NextTok(); + } + return(value); +} + +// ---- Вычисление значения знаковой константы +long DoConstMath() +long value; +{ + IF(tok == tk_minus){ + NextTok(); + IF(tok != tk_number){ + numexpected(); + return(0); + } + number = -number; + } + IF(tok != tk_number){ + numexpected(); + return(0); + } + value = number; + while(tok2isopperand()){ + NextTok(); + IF(tok2 != tk_number) return(value); + switch(tok){ + case tk_minus: value -= number2; break; + case tk_plus: value += number2; break; + case tk_xor: value ^= number2; break; + case tk_and: value &= number2; break; + case tk_or: value |= number2; break; + case tk_mod: value = value % number2; BREAK; + case tk_div: value = value / number2; BREAK; + case tk_mult: value = value * number2; BREAK; + case tk_rr: value >>= number2; BREAK; + case tk_ll: value <<= number2; BREAK; + case tk_xorminus: value ^= -number2; BREAK; + case tk_andminus: value &= -number2; BREAK; + case tk_orminus: value |= -number2; BREAK; +/* case(tok==tk_modminus) value %= -number2; + case(tok==tk_divminus) value /= -number2; + case(tok==tk_multminus) value *= -number2; */ + case tk_rrminus: value >>= -number2; BREAK; + case tk_llminus: value <<= -number2; BREAK; + } + NextTok(); + } + return(value); +} + +// ---- Вычисление значения знаковой константы +long DoConstLongMath() +long value; +{ + value=DoConstMath(); + NextTok(); + return(value); +} + +// ---- Следующий token - операция? +dword tok2isopperand() +{ + EAX=tok2; + IF(EAX==tk_plus)||(EAX==tk_minus)||(EAX==tk_mult)||(EAX==tk_div)||(EAX==tk_mod)|| + (EAX==tk_rr)||(EAX==tk_ll)||(EAX==tk_or)||(EAX==tk_and)||(EAX==tk_xor)|| + (EAX==tk_divminus)||(EAX==tk_modminus)||(EAX==tk_multminus)||(EAX==tk_xorminus)|| + (EAX==tk_orminus)||(EAX==tk_andminus)||(EAX==tk_llminus)||(EAX==tk_rrminus)return(1); + return(0); +} + +// ---- Следующий token закрывает выражение? +dword tok2notstopper () +{ + EAX=tok2; + IF(EAX==tk_semicolon)||(EAX==tk_comma)||(EAX==tk_closebracket)|| + (EAX==tk_openblock)EAX=0; + ELSE EAX=1; +} + +// ---- Поиск в списке локальных переменных +SearchLocals(dword tok4,type4,string4,number4) +{ + if( locallist != NULL ){ + localptr = locallist; +S00: + ESI=EAX; //localptr; + lstrcmpA(string4,ESI+localid); + ESI=localptr; + IF(EAX==0){ // Переменная найдена + EBX=number4; + DSDWORD[EBX]=DSDWORD[ESI+localnumber]; + EBX=type4; + DSDWORD[EBX]=DSDWORD[ESI+localtype]; + EBX=tok4; + EAX=DSDWORD[ESI+localtok]; + DSDWORD[EBX]=EAX; + IF(EAX==tk_local){ + EBX=number4; + DSDWORD[EBX]-=localsize; + } + ELSE IF(EAX==tk_param){ + EBX=number4; + EAX=DSDWORD[EBX]+4; + DSDWORD[EBX]=EAX; + IF(current_proc_type==cpt_far)DSDWORD[EBX]+=4; // move over seg on stack + } + ELSE IF(EAX!=tk_locallabel)&&(EAX!=tk_number)internalerror("Bad *tok4 value in SearchLocals"); + } + ELSE{ + IF(DSDWORD[ESI+localnext]!=NULL){ + localptr=DSDWORD[ESI+localnext]; + $JMP S00 + } + } + } +} + +// ---- Поиск в списке глобальных идентификаторов +dword SearchTree(dword tok4,type4,src4,post4,string4,number4) +dword ptr; +long cmpresult; +{ + cmpresult=123; + ptr = treestart; +// Поиск свободной ссылки + for(;;){ + ESI=EAX; + IF(ESI==0){ + treeptr=NULL; + return(0); // Not found + } + cmpresult = lstrcmpA(DSDWORD[ESI+recid],string4); + ESI=ptr; + IF(cmpresult<0)ptr=DSDWORD[ESI+left]; + ELSE IF(cmpresult>0)ptr=DSDWORD[ESI+right]; + ELSE BREAK; + } + EBX=number4; DSDWORD[EBX]=DSDWORD[ESI+recnumber]; + EBX=type4; DSDWORD[EBX]=DSDWORD[ESI+rectype]; + EBX=src4; DSDWORD[EBX]=DSDWORD[ESI+recsrc]; + EBX=post4; DSDWORD[EBX]=DSDWORD[ESI+recpost]; + EBX=tok4; EAX=DSDWORD[ESI+rectok]; DSDWORD[EBX]=EAX; + IF(EAX==tk_string ){ + EBX=number4; ECX=DSDWORD[EBX]; EDI=string4; + ESI=DSDWORD[ESI+newid]; $REP $MOVSB + } + ELSE{ + IF(DSDWORD[ESI+newid])lstrcpyA(string4,DSDWORD[ESI+newid]); + } + ESI=ptr; + IF(lstrcmpA(DSDWORD[ESI+recid],string4)!=0) // Проверим: менялось ли имя идентификатора + SearchTree(tok4,type4,src4,post4,string4,number4); // Да - повторим поиск + treeptr = ptr; + return(1); +} + +// ---- Поиск неоткомпилированных еще ссылок +dword SeekToDo(dword ptr) +{ + IF(ptr!=NULL){ + ESI=ptr; + IF(SeekToDo(DSDWORD[ESI+right]))RETURN(1); + ESI=ptr; EAX=DSDWORD[ESI+recpost]; + IF(EAX>1){ + treeptr=ptr; ESI=ptr; + number=DSDWORD[ESI+recnumber]; + type=DSDWORD[ESI+rectype]; modline=DSDWORD[ESI+recmodline]; + src=DSDWORD[ESI+recsrc]; + post=DSDWORD[ESI+recpost]; + tok=DSDWORD[ESI+rectok]; RETURN(1); + } + ESI=ptr; + IF(SeekToDo(DSDWORD[ESI+left]))RETURN(1); + } + return(0); +} + +// ---- Поиск незакрытых ссылок +SeekUndefined(dword ptr) +{ + IF( ptr != NULL ){ + ESI=ptr; + SeekUndefined(DSDWORD[ESI+right]); + ESI=ptr; EAX=DSDWORD[ESI+rectok]; + IF(EAX==tk_undefproc){ + wsprintfA(#mapstr,"'%s' undefined\n",DSDWORD[ESI+recid]); + IF( makemapfile )fprint(mapfile,#mapstr); + WRITESTR(#mapstr); + } + ESI=ptr; + SeekUndefined(DSDWORD[ESI+left]); + } +} + diff --git a/programs/develop/c--/trunk/wapi.h-- b/programs/develop/c--/trunk/wapi.h-- new file mode 100644 index 0000000000..86ccca4902 --- /dev/null +++ b/programs/develop/c--/trunk/wapi.h-- @@ -0,0 +1,36 @@ +extern WINAPI "user32.dll" +{ + cdecl long wsprintfA(); + dword IsCharAlphaA(); + dword IsCharAlphaNumericA(); + dword CharUpperA(); + dword CharToOemA(); + +} + +extern WINAPI "kernel32.dll" +{ + long lstrlenA(); + long lstrcmpA(); + dword lstrcpyA(); + dword lstrcpynA(); + dword lstrcatA(); + long _lopen(); + dword _lread(); + dword _lwrite(); + long _llseek(); + long _lclose(); + long _lcreat(); + dword LocalAlloc(); + dword LocalFree(); + dword LocalUnlock(); + dword GetSystemDirectoryA(); + dword GlobalFree(); + dword GetStdHandle(); + dword GetLastError(); + dword GetFileSize(); + dword GetCommandLineA(); + void ExitProcess(); + dword CloseHandle(); + +} \ No newline at end of file