📄 cal.asm
字号:
radix 16 ; gentlemen prefer hex
doscall macro ; call to dos int_21 with a
mov ah,#1 ; one-byte function in ah
int 21
#em
doscall2 macro ; call to dos int_21 with a
mov ax,#1 ; two-byte function in ax
int 21
#em
dosprint macro ; call to dos string-print function
mov dx,offset #1
mov ah,09
int 21
#em
zero macro ; zero a register
xor #1,#1
#em
; assembly options :
; un-comment the next line to make monday the first day of the week :
; monday equ 1
; un-comment the next line to remove the asterisk marking today's date :
; no_splat equ 1
; un-comment the next line to prevent expanding years 00-99 to 2000-2099 :
; no_2dig equ 1
; un-comment the next line to prevent pausing year calendar after june :
; no_pause equ 1
; uninitialized variables :
julian_lo equ 005e ; total number of days since
julian_hi equ 0060 ; december 31, 1752 (two words)
cal1 equ 0064 ; temp storage for year-calendar
; print routine (three bytes)
today equ 0067 ; today's date (byte)
month equ 0068 ; 1 = january, 12 = december (word)
year equ 006a ; 1800 through 2199 (word)
; start of code :
begin:
doscall 2a ; get date from dos
#if !no_splat
mov b [today],dl ; remember today's date
#endif
mov w [year],cx ; use current year as default
mov dl,dh
mov dh,00 ; convert month to a word value
mov w [month],dx ; and use it as default
call parse ; read the command line
mov ax,w [year]
cmp ax,01753xd ; any year less than 1753
jb val_yx ; is an error
cmp ax,02399xd ; any year above 2399
ja val_yx ; is an error
mov ax,w [month]
cmp ax,0001 ; any month below 1
jb val_mx ; is an error
cmp ax,000c ; any month above 12
ja val_mx ; is an error
call print_cal ; display calendar
int 20 ; and exit
val_yx: ; bad year --
mov dx,offset msg_year_bad ; point to bad-year error message
jmp short val_2 ; and skip ahead
val_mx: ; bad month --
mov dx,offset msg_month_bad ; point to bad-month error message
val_2:
doscall 09 ; print error message
int 20 ; and exit
parse: ; read the user's command line:
mov si,0081 ; start of command line
call skip_junk ; skip over any leading spaces
call test_digit ; is next character a digit?
je parse_cal ; if so, get user's value(s)
cmp bl,0d ; end of line? if so, exit
jbe ret ; otherwise fall through to ....
syntax: ; syntax error:
dosprint msg_syntax ; print an error message
int 20 ; and exit
parse_cal: ; get calendar month and year values:
#if !no_splat
mov b [today],00 ; forget today's date
#endif
call get_num ; get first user value
jc ret ; any error, exit (use defaults)
mov w [month],ax ; save first value as month
call skip_junk ; and skip over any separator chars
call get_num ; get second value
jnc > l4 ; save second value as year and exit
; only one value on command line :
dec b [flags] ; note full-year calendar
mov ax,w [month] ; change month to 1 (january]
mov w [month],0001 ; and move first value into the year
l4:
#if !no_2dig
cmp ax,0100xd
jae > l5
add ax,02000xd
l5:
#endif
mov w [year],ax
ret ; and exit
is_junk: ; junk that needs to be skipped ....
inc si ; ignore it and fall through
skip_junk: ; skip past any separator characters:
mov al,b [si] ; examine next char on command line
cmp al,20 ; space?
je is_junk ; skip over spaces
cmp al,'/' ; slash?
je is_junk ; skip over slashes
cmp al,'-' ; minus?
je is_junk ; skip over minuses
; anything else should not be ignored
; so fall through to exit
get_num_bad:
stc
ret
get_num: ; parse number from command line:
zero ax ; start with a value of zero
mov cx,000a ; ten, used for multiplications
call test_digit ; is the first character a digit?
jne get_num_bad ; if not, return error
l1: ; number-parsing loop:
call test_digit ; is next character a digit?
jne get_num_okay ; if not, done parsing number; exit
inc si ; if so, accept digit
sub bl,'0' ; convert ascii to value 0 - 9
mov bh,00 ; 2-byte value
mul cx ; multiply working value by ten
cmp dl,ch ; overflow during multiplication?
jne get_num_bad ; if overflow, return error
add ax,bx ; add in value of digit
jnc l1 ; if no overflow, loop back for next
ret
test_digit: ; is next character a digit?
mov bl,b [si] ; get next character
cmp bl,'0'
jb ret ; no, exit with .z flag clear
cmp bl,'9'
ja ret ; no, exit with .z flag clear
get_num_okay:
cmp bl,bl ; yes, exit with .z set
ret
compute_julian: ; convert date to julian number:
mov ax,w [year] ; get year in .ax
mov bx,ax ; and in .bx
cmp ax,02000xd ; year 2000?
je > l0 ; if so, definitely a leap year
mov cl,0100xd
div cl
cmp ah,00 ; is year divisible by 100?
je > l1 ; if so, not a leap year
test bl,03 ; is year divisible by 4?
jne > l1 ; if not, not a leap year
l0: ; leap year!
mov b [months_table+1],1d ; 29 days in february
l1:
zero cx ; .cx holds a convenient zero
mov bp,cx ; start with january
#if monday
mov w [julian_lo],cx
#else
mov w [julian_lo],0001
#endif
mov w [julian_hi],cx ; and a julian date of four
l2:
mov al,b [months_table+bp] ; get length of month
cbw ; as a two-byte value
inc bp
cmp bp,w [month] ; hit the user's month yet?
je > l4 ; yes, exit this loop
add w [julian_lo],ax ; no, add month length into julian
jmp SHORT l2 ; and loop back for next month
l4: ; added in lengths of previous months:
sub bx,01753xd ; normalize year to zero
mov ax,bx
mov dx,0365xd
mul dx ; multiply year number by 365
add w [julian_lo],ax
adc w [julian_hi],dx ; and add into the julian date
mov ax,bx
shr ax,1
shr ax,1 ; divide year number by four
add w [julian_lo],ax ; to get number of leap-days
adc w [julian_hi],cx ; add leap days into julian date
mov ax,bx
add ax,052xd
mov dl,0100xd
div dl ; and divide by 100
cbw ; to get number of non-leap xx00 years
sub w [julian_lo],ax
sbb w [julian_hi],cx ; subtract from julian date
cmp bx,0247xd
jbe > l8 ; user year greater than 2000?
add w [julian_lo],0001 ; if so, add one (year 2000 is the
adc w [julian_hi],cx ; only leap century in program range)
l8:
mov dx,w [julian_hi]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -