如何在DOS/汇编语言中获得希腊字母α?

3

我正在上大学,学习汇编语言课程。我的老师给了我们下面的代码:

.286
.model small
.data
.stack 64h
.cide
main:
 MOV AX,0B800H
 MOV ES,AX
 MOV ES:[240], 7C03H
 MOV AH,1h
 INT 21h

 MOV AX,4C00H
 INT 21h
end main

它简单地在屏幕上将红色心形放置在灰色背景上。我的作业是将那个心形改成α。他还在例子中链接了这个网站:https://www.rapidtables.com/code/text/alt-codes.html,在那里,α的代码是224(E0),但是当我将7C03H更改为7CE0H时,我得到的是Ó而不是α。我尝试了0到255的所有数字,但都没有成功。从我所看到的,int 21h和int 10h中没有任何东西允许使用超过1个字节的字符。
我搜索了一些资料并发现DOS使用的是852代码页,其中没有α。
我能否在程序中以某种方式更改代码页,或者根本无法获得α?我的程序不需要像示例那样完全一样,我可以使用其他中断,例如10h、21h或16h。

3
你可以尝试使用int 21h/ax=6602h,并将 bx = dx = 437,但我从未使用过(不确定是否有效)。无论如何,我认为你的教授只是希望你在在ASCII表中找到该代码后将7C03h更改为7CE0h。CP852在东欧很常见,但是表格和示例通常是针对美国本土的,所以你和你的教授可能使用不同的CP或者他们根本没有考虑过CP。 - Margaret Bloom
2
似乎这不会起作用。我希望DOS能够随着CP更改VGA字体,但情况并非如此。我没有找到任何int 10h服务来更改CP,我认为它太高级了。你可以更改VGA字体,但这绝对不是你的教授希望你花时间去做的事情。我建议,将其保留原样并继续前进 :) - Margaret Bloom
该程序直接在视频内存0xB8000中进行写入:在这种情况下,您写入的字节将根据“视频BIOS代码页”映射为相应的字符,该代码页很可能是CP437,但如果是,则写入0x7CE0就可以正常工作了。你是在真实硬件上运行吗?因为DOSBox的行为符合预期,即会打印出实际的α - Daniel Kamil Kozar
为了使 int 21h/ax=6602h 调用起作用,字符串必须使用 DOS API 打印,因此最可能使用 int 21h/ah=09h 等。另一方面,为了使其工作,DOS 必须知道 VBIOS 的 CP 并执行即时翻译,将 DOS CP 转换为 VBIOS CP,我相信这不是我们可以依靠的东西。 - Daniel Kamil Kozar
此外,如需进一步阅读,请查看Wikipedia上的一篇介绍文本模式工作原理并解释7C03h中的7C等内容的优秀文章。 - Daniel Kamil Kozar
我和其他人一样也很好奇,这是在真实的硬件上(什么类型的硬件)还是某种虚拟机或模拟器DosBox/DosEmu/QEMU/Bochs上运行的?还是真实的硬件,那是什么类型的? - Michael Petch
1个回答

3

更改代码页

斯拉夫语(Latin II)代码页852不包含除ß(Beta)之外的希腊字符,ß常用于德语中。
解决显示希腊字符的方法之一是使用DOS切换代码页。DOS标准代码页437包含一些希腊字符。

如果未安装NLSFUNC:

  • 您可以从命令提示符中使用mode con cp select=437

如果已安装NLSFUNC:

  • 您可以从命令提示符中使用chcp 437
  • 在应用程序内部,您可以使用DOS.SetGlobalCodePage函数6602h。

无论哪种方式,系统都需要正确的配置才能支持多个代码页。以下是我的配置文件摘录:

CONFIG.SYS:

DEVICE=C:\DOS\DISPLAY.SYS CON=(EGA,850,2)
COUNTRY=032,850,C:\DOS\COUNTRY.SYS
INSTALL=C:\DOS\NLSFUNC.EXE

AUTOEXEC.BAT:

C:\DOS\MODE.COM CON CODEPAGE PREPARE=((437 850) C:\DOS\EGA.CPI)
C:\DOS\MODE.COM CON CODEPAGE SELECT=850
C:\DOS\KEYB.COM BE,850,C:\DOS\KEYBOARD.SYS
下面是一个演示程序,展示了如何在应用程序内部切换到代码页437。该程序清楚地证明了从哪里获取字符(通过DOS,BIOS或VRAM)并不重要。切换立即生效,甚至已经显示在屏幕上的字符也会相应地更改。
; Changing code pages from within an application (c) 2021 Sep Roland
; ( With the intention to display Greek characters ... )
; Assemble with FASM

        ORG     256

; If NLSFUNC is not installed, changing code pages is not an option
        xor     bx, bx
        mov     ax, 1400h       ; NLSFUNC.CheckInstallationStatus
        int     2Fh             ; -> AL
        cmp     al, 0FFh
        jne     Print           ; Nlsfunc is NOT installed

; No need to change if Active Code Page is 437
        mov     ax, 6601h       ; DOS.GetGlobalCodePage
        int     21h             ; -> BX DX CF
        jc      Print
        cmp     bx, 437         ; Is Active Code Page == 437 ?
        je      Print

; Temporarily changing the Active Code Page to 437
        push    bx              ; (1)
        mov     bx, 437
        mov     ax, 6602h       ; DOS.SetGlobalCodePage
        int     21h             ; -> CF
        pop     bx              ; (1)
        jc      Print

; Test the character range from 224 to 239
        call    Greek

; Restore previous Active Code Page
        mov     ax, 6602h       ; DOS.SetGlobalCodePage
        int     21h             ; -> CF
        jmp     Exit

Print:  call    Greek

Exit:   mov     ax, 4C00h       ; DOS.TerminateWithReturnCode
        int     21h
; ------------------------------
Greek:  pusha

        mov     dx, .msg1
        mov     ah, 09h         ; DOS.DisplayString
        int     21h
        mov     dl, 224
.a:     mov     ah, 02h         ; DOS.DisplayOutput
        int     21h
        inc     dl
        cmp     dl, 240
        jb      .a

        mov     dx, .msg2
        mov     ah, 09h         ; DOS.DisplayString
        int     21h
        mov     al, 224
.b:     mov     ah, 0Eh         ; BIOS.Teletype
        int     10h
        inc     al
        cmp     al, 240
        jb      .b

        mov     dx, .msg3
        mov     ah, 09h         ; DOS.DisplayString
        int     21h
        mov     bh, 0
        mov     ah, 03h         ; BIOS.GetCursorPosition
        int     10h             ; -> CX, DL is Column, DH is Row
        mov     al, 160
        mul     dh
        mov     dh, 0
        add     ax, dx
        add     ax, dx
        mov     di, ax
        push    es              ; (1)
        mov     ax, 0B800h
        mov     es, ax
        mov     ax, 0EE0h       ; YellowOnBlack ASCII 224
.c:     stosw
        inc     al
        cmp     al, 240
        jb      .c
        pop     es              ; (1)

        mov     dx, .msg4
        mov     ah, 09h         ; DOS.DisplayString
        int     21h

        mov     ah, 00h         ; BIOS.GetKeyboardKey
        int     16h             ; -> AX

        popa
        ret
; - - - - - - - - - - - - - - - 
.msg1   db      13, 10, 'DOS  : $'
.msg2   db      13, 10, 'BIOS : $'
.msg3   db      13, 10, 'VRAM : $'
.msg4   db      13, 10, 'Press any key', 13, 10, '$'
; ------------------------------

不要移除BIOS.GetKeyboardKey调用。如果这样做,你将没有机会实际看到希腊字符...


在德语中使用的不是beta,而是Eszett。实际上,IBM将CP437位置0xE1标识为拉丁文“Sharp s Small”[U+00DF,ß]。它有时只是在OEM字体中呈现为希腊小写字母beta[U+03B2,β],并且它被放置在代码页中的alpha和gamma之间。 - Ruslan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接