兴复汉唐

镜像:https://leisurebamboo.wordpress.com/2023/10/05/tc1
兴复汉唐——Turbo C汉化浅析之一
原文在2005-4-25 发表于 http://www.aogosoft.com/bbs/view.asp?id=39189 ,现有增删。
"汉化"(Sinicization)暂定义为“函数名、变量名、宏名 能用汉字”。

竹闲的贴子,每行不超过43个字符,
从而言逾百行,令阅贴观众狂按 Page-Down,
在此深深致歉。
因为他的ie显示的是大字体,他自己阅贴时在
屏上每行真的不超过43个字符,以此小人之心
度诸位君子之腹,遂有此事。

言归正传,循例先说低版本的Turbo C汉化:

TC 1.0版的tcc.exe,长度为 16'9098字节。
在哈工大的论坛的下载链接上,它被揶揄为
"仅供老一辈程序员使用",
在网上搜索"TC 1.0"时连外国网页也不好找,
好像在www.coldyne.com上还有下载链接。
姑妄言之:

其编译部分为:
cs:00249AB505xxxxCALL far fgetc()
;//xxxx:05B5
cs:00298BF0 MOV SI,AX
cs:002B8BDE MOV BX,SI
cs:002D83C302 ADD BX,02
cs:0030D1E3 SHL BX,1
cs:00328B87A61A MOV AX,[1AA6+BX]
;//此时 AX=分枝枚举值
cs:00368946FE MOV [BP-02],AX
cs:00392DE7FF AX+=19h
cs:003C3D1900 CMP AX,0019
cs:003F7603 JBE 0044
cs:0041E99600 JMP 00DA
cs:00448BD8 MOV BX,AX
cs:0046D1E3 SHL BX,1
cs:00482EFFA74D00 JMP CS:[004D+BX]
;//cs:[004D+(0019+fff6)*2]==00a1
  在 fgetc() 後,tcc.exe 在 ds:1aaa 始的《分枝枚举表》内,查了AL字符所对应case语句的分枝枚举值;再按照该枚举值,跳转到cs:4d 处相应的分枝去。

《分枝枚举表》以 ds:1aaa 始,内共有100h个word,取值从-19h(ffe7h)到0029h 不等,其详细内容为:
dw ffee,ffee,ffee,ffee, ffee,ffee,ffee,ffee;00~07
dw ffee,fff7,ffec,fff7, fff7,fff7,ffee,ffee;08~0f
dw ffee,ffee,ffee,ffee, ffee,ffee,ffee,ffee;10~17
dw ffee,ffee,ffe7,ffee, ffee,ffee,ffee,ffee;18~1f
dw fff7,0000,fff4,fff3, ffee,ffff,fffe,fff2;20~27
dw 0001,0002,fffd,fffc, 0008,fff1,fff0,fffb;28~2f
dw fff5,fff5,fff5,fff5, fff5,fff5,fff5,fff5;'0'~'7'
dw fff5,fff5,001f,0007, ffef,fff8,ffed,001e;'8','9', 3a~3f
 
dw ffee,fff6,fff6,fff6, fff6,fff6,fff6,fff6;'@', 'A'~'G'
dw fff6,fff6,fff6,fff6, fff6,fff6,fff6,fff6;'H'~'O'
dw fff6,fff6,fff6,fff6, fff6,fff6,fff6,fff6;'P'~'W'
dw fff6,fff6,fff6,0003, ffea,0004,fffa,fff6;'X'~'Z', 5b~5f
dw ffee,fff6,fff6,fff6, fff6,fff6,fff6,fff6;60, 'a'~'g'
dw fff6,fff6,fff6,fff6, fff6,fff6,fff6,fff6;'h'~'o'
dw fff6,fff6,fff6,fff6, fff6,fff6,fff6,fff6;'p'~'w'
dw fff6,fff6,fff6,0005, fff9,0006,0029,ffee;'x'~'z', 7b~7f
 
dw 80 dup(ffee)

gbk码或big5码首字节对应的分枝枚举值,全落在该表的後半部分内,且均为-12h(ffeeh)。
(《分枝枚举表》的後半部分 位于tcc.exe的 第[2632A~26429]字节,共80h个字)

  而 枚举值-12h相应的分枝在cs:020Ah,其case语句仅有11h字节,难以改写。若需汉化,祗好将《分枝枚举表》的後半部分,改作80h个“在表中常见的”fff6。


常见的枚举值-0Ah(fff6h),在分枝对应到cs:00A1h处,其编译部分为:
cs:00A1C6061A5F00MOV byte[5F1A],00
...
cs:00BBF684574B02TEST byte[SI+4B57],2
cs:00C07574 JNZ 0136
cs:00C29A8D04xxxx CALL xxxx:048D
cs:00C7E95AFF JMP 0024
;//即 continue; 语句

其中ds:4b57 开始为《ascii码对应属性表》,具体内容为:
db  8 dup(20h);00~07
db 20h,21h,21h;08~0A
db  5 dup(20h);0B~0F
db  8 dup(20h);10~17
db  8 dup(20h);18~1F
db 1,7 dup(0);20~27
db  8 dup(0);28~2F
db 0Ah dup(2);'0'~'9'
db  6 dup(0);3A~3F
db 0,6 dup(14h);'@',"ABCDEF"
db 20 dup(4);'G'~'Z'
db  5 dup(0);5B~5F
db 0,6 dup(18h);60,"abcdef"
db 20 dup(8);'g'~'z'
db  4 dup(0);7B~7E
db 20h;7F
db 80h dup(0);80~FF

  汉化方法仍是将ascii80~FF的对应属性部分
(位于tcc.exe的第[29357h~293D6h]字节,原文为80h个字节,均为0),
换为80h dup(8h)。

  以上所论皆是数据(data)。以下讨论代码(code),共须改动三处:

  tcc 调用 fgetch(可能是 fgetch_1、fgetch_2、fgetch_3、fgetch_4)时:
原文改作
fgetch_4:file_offset == 0x10479
cs:01F956push si
do{lp_8=(lp_struct->lp8)++
cs:01FAC41E225F  les bx,[5F22]
cs:01FE268B570E  mov dx,es:[bx+0E]
cs:0202268B470C  mov ax,es:[bx+0C]
cs:020626FF470C  inc es:word ptr [bx+0C]
cs:020A8BD8  mov bx,ax
cs:020C8EC2  mov es,dx
 c=*lp8
cs:020E268A07  mov al,es:[bx]cs:020E260FB607movzx ax,es:byte ptr [bx]
cs:0211B400  mov ah,00 cs:02128BF0mov si,ax
cs:02138BF0  mov si,ax cs:02143C80cmp al,80
cs:02160F82A500jb 02BF;//normal
 if(!(c & 0x80))
cs:0215F7C68000  test si,0080
cs:02197503  jne 021E cs:021A3CFFcmp al,FF
cs:021BE9A100   jmp 02BF;//normal cs:021C740Fje 022D;//label_ff
 else if(c == 0xFE) cs:021E3CFEcmp al,FE
cs:021E81FEFE00  cmp si,00FE cs:02200F84A800je 02CC;//nothing
cs:02227503  jne 0227
cs:0224E9A500   jmp 02CC;//nothingcs:02243C90cmp al,90
cs:02260F827E00jb 02A8;//label_8x
 else if(c == 0xFF)cs:022AEB1Fjmp 024B;//judge_fd
cs:022781FEFF00  cmp si,00FFcs:022C90nop
cs:022B751E  jne 024B;//judge_fd
label_ff:   {lp_8=(lp_struct->lp8)++
cs:022DC41E225F   les bx,[5F22]
cs:0231268B570E   mov dx,es:[bx+0E]
cs:0235268B470C   mov ax,es:[bx+0C]
cs:023926FF470C   inc es:word ptr [bx+0C]
cs:023D8BD8   mov bx,ax
cs:023F8EC2   mov es,dx
  c=*lp8
cs:0241268A07   mov al,es:[bx]
cs:0244B400   mov ah,00
cs:02468BF0   mov si,ax
cs:0248EB79   jmp 02C3
cs:024A90   }nop
judge_fd:  else if(c == 0xFD)
cs:024B81FEFD00  cmp si,00FD
cs:024F7557  jne 02A8;//label_8xcs:024F756Ejne 02BF;//normal
  {lp_8=(lp_struct->lp8)++
cs:0251C41E225F   les bx,[5F22]
cs:0255268B570E   mov dx,es:[bx+0E]
cs:0259268B470C   mov ax,es:[bx+0C]
cs:025D26FF470C   inc es:word ptr [bx+0C]
cs:02618BD8   mov bx,ax
cs:02638EC2   mov es,dx
  c=*lp8
cs:0265268A07   mov al,es:[bx]
cs:0268B400   mov ah,00
cs:026A8BF0   mov si,ax
  if((c&0x80==0)||(c>=0xFD))
cs:026CF7C68000   test si,0080
cs:02707406   je 0278
cs:027281FEFD00   cmp si,00FD
cs:02767C19   jl 0291
cs:0278B81C00    {mov ax,001C
   ;//enum of '#
   operator not
   followed by
   macro argument name'
cs:027B50    push ax
cs:027C9AFB00F41E    call print_err;//xxxx.00FB
cs:028144    inc sp
cs:028244    inc sp
...
cs:028FEB3B    break;jmp 02CC
   }
cs:0291C41E225F   les bx,[5F22]
cs:029526FF7706   push es:word ptr [bx+06]
cs:029926FF7704   push es:word ptr [bx+04]
cs:029D56   push si
cs:029E9A8205880C   call replace_macro;//cs:0582
cs:02A3B82200   mov ax,0022
cs:02A6EB39   }jmp 02E1
label_8x: else{;//c=0x8?
cs:02A8C41E225F   les bx,[5F22]
cs:02AC26FF7706   push es:word ptr [bx+06]
cs:02B026FF7704   push es:word ptr [bx+04]
cs:02B456   push si
cs:02B59A4E05880C   call reset_pointer;//cs:054E
cs:02BAE87A01   call fgetch_2;//0437
cs:02BDEB22   }jmp 02E1
//if(!(c&80h))
normal:   {if(c)
cs:02BF0BF6   or si,si
cs:02C17404   je 02C7
cs:02C38BC6 EB1A    return(c);
  //mov ax,si; jmp 02E1
cs:02C79A8C03880C   else call free;//cs:038C
  }
nothing:  }while(lp_struct)
cs:02CCA1225F mov ax,[5F22]
cs:02CF0B06245F or ax,[5F24]
cs:02D37403 je 02D8
cs:02D5E922FF jmp 01FA
cs:02D8C7061C64C504 mov word ptr [641C],04C5
cs:02DEE8E401 call fgetch_1;//04C5
cs:02E15E pop si
cs:02E2C3 ret
}
在处理汉字时,原文跳到label_8x(02a8)改动後跳到normal(02bf)。

原文改作
fgetch_2:file_offset == 0x106b7
cs:0437C41E265F les bx,[5F26]
cs:043B26803F00 cmp es:byte ptr [bx],00
cs:043F740A je 044Bcs:043F7417je 0458
cs:0441FF06265F  inc word ptr [5F26]cs:0441FF06265Finc word ptr [5F26]
cs:0445268A07  mov al,es:[bx]cs:0445260FB607movzx ax,es:byte ptr [bx]
cs:04493C80cmp al,80
cs:044B720Ajb 0457
cs:044D3C90cmp al,90
cs:044F7204jb 0455
cs:04513CFDcmp al,FD
cs:04537202jb 0457
cs:044898  cbwcs:0455FECCdec ah
cs:0449EB29  jmp 0474;returncs:0457C3ret
cs:044BC706285F0000 mov wo[5F28],0cs:04586633C0xor eax,eax
cs:0451C706265F0000 mov wo[5F26],0cs:045B66A3265Fmov [5F26],eax
cs:0457A1225F mov ax,[5F22]cs:045F663306..xor eax,[5F22]
cs:045A0B06245F or ax,[5F24]cs:0464BAC504mov dx,04C5;fgetch_1
cs:045E740B je 046Bcs:04677403je 046C
cs:0469BAF901mov dx,01F9;fgetch_4
cs:0460C7061C64F901   {mov wo[641C],01F9cs:046C89161C64mov [641C],dx
cs:0466E890FD   call fgetch_4;01F9cs:0470FFD2call dx
cs:0469EB09   }jmp 0474
cs:046BC7061C64C504 else{mov wo[641C],04C5
cs:0471E85100   call fgetch_1;04C5
  }cs:0472C3ret
cs:047390nop
cs:0474C3 ret
}
在处理汉字时,原文在0448令AX为负数改动後在0445令AX为正数。

原文改作
getch_in_macro(char c):file_offset == 0x11ef1
cs:066155 push bp
cs:06628BEC mov bp,sp
cs:0664F746 if(c & 80h)cs:06648A4606mov al,[bp+06]
068000 test word ptr [bp+06],0080cs:06673C80cmp al,80
cs:06697436 je 06A1;//nothingcs:06697236jb 06A1;//nothing
 {if(lp8<&(str[SIZE-1]))cs:066B3C90cmp al,90
cs:066BA13264  mov ax,[6432]cs:066D720Ajb 0679;//label_8x
cs:066E8CDA  mov dx,dscs:066F3CFCcmp al,FC
cs:0670BB3474  mov bx,7434cs:0671762Ejbe 06A1;//nothing
cs:06738CD9  mov cx,dscs:0673EB0Fjmp 0684;//judge_ov
cs:06753BC3  cmp ax,bxcs:067590 90nop
cs:0677730B  jnb 0684;//judge_ovcs:067790 90nop
label_8x:   {*(lp8++)=0xff
cs:06798BD8   mov bx,ax
cs:067BC607FF   mov byte ptr [bx],FF
cs:067EFF063264   inc word ptr [6432]
cs:0682EB1D   }jmp 06A1;//nothing
judge_ov:  else if(lp8==&(str[SIZE-1]))
cs:0684A13264  mov ax,[6432]
cs:06878CDA  mov dx,ds
cs:0689BB3474  mov bx,7434
cs:068C8CD9  mov cx,ds
cs:068E3BD1  cmp dx,cxcs:068E3BC3cmp ax,bx
cs:0690750F  jne 06A1;//nothingcs:069072E7jb 0679;//label_8x
cs:06923BC3  cmp ax,bxcs:069290 90nop
cs:0694750B  jne 06A1;//nothing
cs:0696B82200   {mov ax,0022
  ;//enum of
  'Macro expansion
  too long'
cs:069950   push ax
cs:069A9AFB00F41E   call print_err;//xxxx.00FB
cs:069F8BE5   mov sp,bp
  }
 }
cs:06A1 nothing:...
cs:06D98BE5 mov sp,bp
cs:06DB8B1E3264 mov bx,[6432]
cs:06DFC60700 mov byte ptr [bx],00
cs:06E25D pop bp
cs:06E3CA0200 retf 0002
;}
在处理汉字时,原文跳到 0679(label_8x)改动後跳到 06a1(nothing)。


  至此,tcc.exe 1.0 版本汉化完毕。 函数名、变量名、宏名 均能用汉字。
但为便于日後tc编译链接,命名时请仍沿用下划线 或英文字母开头。
具体的asm,参阅https://sourceforge.net/projects/difc/files/turbo_c/1.0/


  汉乃百族之长,唐为历朝之冠。当年中国在政治、军事、经济、文化等各方面均居世界前茅;
今日式微,我等後人不肖,编个程序连中文都不能用。
在此并非鼓吹连mov旨令、if关键字都得换成汉语,但若用1个中文变量也会引起编译错误,则起码可责其未考虑13亿人口的需求。
  竹闲不自量力,推出TC汉化系列,冀可一振华夏之气。至于成败利钝,则非竹闲所能逆料也;
唯盼国人齐心戮力,重兴此尧唐的盛世,再睹我大汉的天威。

  Turbo C 更高版本的汉化,敬请关注下期。(待续)

评论

此博客中的热门博文

我的开源软件项目(不定期更新)

heavy metal war 配音评论

tww2