📄 prnval.asm
字号:
TITLE PRNVAL - Print values
page 56,132
;***
; PRNVAL - Print values
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; This module contains B$P<term><type> and B$PEOS interfaces.
;
; The PRINT, WRITE, and LPRINT statements have a large number of
; runtime calls that can be generated, based on the list of
; expressions given. There is a unique preamble call for each such
; statement (except PRINT), to correctly set up flags, vectors, etc.
; The actual printing call itself is one of 15 possibilities, based
; on the argument type, and one of three possible ways of terminating
; the print: ',', ';', or EOL. Each of these 15 calls is in the
; form B$P<term><type> where <term> specifies the print termination
; method, and <type> specifies the type of the argument.
;
; <term>:
; C == ',' (i.e., something like 'PRINT X,' was specified)
; S == ';'
; E == EOL (neither ',' nor ';' was specified)
;
; <type>:
; I2 == two byte integer
; I4 == four byte integer
; R4 == single precision real
; R8 == double precision real
; SD == string
;
; Thus, for example, a call to B$PER4 would be used to print a s.p.
; value and terminate with a EOL.
;
; The list of expressions can be of any size; for each additional
; expression, another one of the fifteen possible runtime calls is
; generated. After the last such expression, a call to B$PEOS is
; generated (if not terminated with EOL). If no expression is
; specified, a NULL string is printed, so 'PRINT' would generate a
; call to B$PESD with a null string as the parameter (print a string,
; terminate with EOL).
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc
;Code segments:
useSeg DK_TEXT ;disk I/O
useSeg MT_TEXT ;floating point math.
useSeg NH_TEXT ;near heap
useSeg ER_TEXT ;error handling
useSeg CN_TEXT ;concole I/O
;Data segments:
useSeg CONST ;constant definitions
useSeg _DATA ;initialized variables
useSeg _BSS ;uninitialized variables
INCLUDE seg.inc
INCLUDE baslibma.inc
INCLUDE devdef.inc
INCLUDE files.inc
INCLUDE rtps.inc ; constants shared with QBI
INCLUDE idmac.inc
SUBTTL local constant definitions
page
CLMWID EQU 14 ;column width
COMA EQU 0 ;comma
SEMI EQU 1 ;semicolumn
EOL EQU 2 ;forced EOL
TTY EQU 0 ;default for b$PTRFIL is TTY
PRSTM EQU 0 ;print statement
CHANL EQU 1 ;#
USING EQU 2 ;using
WRSTM EQU 4 ;write statement
LPSTM EQU 8 ;lprint statement
InpDefault EQU 0FFH ;default for b$Finput
SUBTTL data definitions
page
sBegin CONST
labelW TTYVEC ;vector for PRINT
staticW ,B$TTY_GPOS ;cursor position
staticW ,B$TTY_GWID ;line width
staticW ,B$$TCR ;force EOL
staticW ,B$TTY_SOUT ;write one character
staticW ,B$TYPSTR ;write a string with BX=*sd
staticW ,B$TYPCNT ;write a string with CX=length
staticW ,B$OUTCNT ;write a string char. by char.
staticW ,TTY_PRTCHK ; check if EOL needs to be forced
sEnd
sBegin _DATA
externB b$PRFG ;print flag, may be combined from below
;0: PRINT stmt
;1: # (channel)
;2: USING
;4: WRITE stmt
;8: LPRINT stmt
;e.g. 3 means PRINT # USING
labelW <PUBLIC,b$VECS> ; print value vectors
staticW VPOS,B$TTY_GPOS ;cursor position
staticW VWID,B$TTY_GWID ;line width
staticW VWCLF,B$$TCR ;force EOL
staticW VWCH,B$TTY_SOUT ;write one character
staticW VTYP,B$TYPSTR ;BX=*sd
staticW VTYPCNT,B$TYPCNT ;BX=*sd, CX=length
staticW VOUTCNT,B$OUTCNT ;SI=point to string, CX=length
staticW VPRTCHK,TTY_PRTCHK ; check if EOL needs to be forced
SizeOfVecs EQU (($-b$VECS)/2) ;length of b$VECS table in words
globalB b$FInput,InpDefault ;Where is input comming from
globalW b$GetOneVal,<DK_TEXTOFFSET NoGetValAssert> ; vector
;to routine which INPUT will
;will use to get next data
globalW b$pGetValDefault,<DK_TEXTOFFSET NoGetValAssert>
;if no input statement is
;present, attempts to call
;indirect through b$GetOneVal
;will die by assertion in
;non-release runtimes.
globalW b$pFLUSH,Near_Ret,1 ;conditional vector for B$FLUSH
externB b$CRTWIDTH ; screen width
sEnd
sBegin _BSS
globalW b$PUSG,,1 ;print using routine
EVEN ; for safety
externW b$TempSD ; static string descriptor
globalW b$StkBottom,,1 ; used to clean the stack after TTY inp
externW b$?TYP ; [b$VTYP|b$TTYP] (defined in global.inc)
externB b$VTYP ; value type (defined in global.inc)
externB b$TTYP ; terminator type (defined in global.inc)
externW b$PTRFIL ; print channel #
externW b$pSTDALCTMP ; indirect B$STDALCTMP vector
externB b$LPTFDB ; FDB for line printer
externB b$Buf1
sEnd
SUBTTL code externals
page
sBegin DK_TEXT
externNP B$CNTRL ; needed during B$WRIT
sEnd
sBegin MT_TEXT
externNP B$FOUTBX
sEnd
sBegin CN_TEXT
externNP B$TTY_GPOS ;cursor position
externNP B$TTY_GWID ;line width
externNP B$$TCR ;force EOL
externNP B$TTY_SOUT ;write one character
externNP B$TYPSTR ;write a string with BX=*sd
externNP B$TYPCNT ;write a string with CX=length
externNP B$OUTCNT ;write a string char. by char.
sEnd
assumes CS,DK_TEXT
sBegin DK_TEXT
SUBTTL print interfaces -- B$P<term><type>(<param>)
page
;***
; B$P<term><type>(<param>) -- print an item for :
; PRINT, PRINT #, PRINT USING, PRINT # USING,
; WRITE, WRITE #,
; LPRINT, LPRINT USING.
;
;Purpose:
; These are interfaces to the compiler. Each entry point sets up
; (1) types of value & terminator, and
; (2) a pointer to that item,
; and then fall through PRINT, which performs actual printing job.
;
; <term>, <type> & <param> may vary as follows:
; <term>:
; C: Comma used as terminator
; S: Semi used as terminator
; E: End of statement used as terminator
; <type>:
; I2: Two byte integer
; I4: Four byte integer
; SD: String (string descriptor)
; <param>:
; A parameter of type <type> to be printed.
;
;
;Entry:
; Parameter was pushed in stack.
; <type> Val = Number if <type> is numerical type
; = String descriptor if <type> is string
;
;Exit:
; through B$PRINT
;Uses:
; none
;Exceptions:
;
;*******************************************************************************
;========================
; Print I2, |
;========================
cProc B$PCI2,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,COMA SHL 8 + VT_I2 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print this item
cEnd nogen ;no code generated
;========================
; Print I2; |
;========================
cProc B$PSI2,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,SEMI SHL 8 + VT_I2 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print I2 |
;========================
cProc B$PEI2,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,EOL SHL 8 + VT_I2 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print I4, |
;========================
cProc B$PCI4,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,COMA SHL 8 + VT_I4 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print I4; |
;========================
cProc B$PSI4,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,SEMI SHL 8 + VT_I4 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print I4 |
;========================
cProc B$PEI4,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,EOL SHL 8 + VT_I4 ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print a$, |
;========================
cProc B$PCSD,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,COMA SHL 8 + VT_SD ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print a$; |
;========================
cProc B$PSSD,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,SEMI SHL 8 + VT_SD ;AX=[terminator type | value type]
JMP SHORT B$PRINT ;print the item
cEnd nogen ;no code generated
;========================
; Print a$ |
;========================
cProc B$PESD,<PUBLIC,FAR>
cBegin nogen ;no stack frame generated
MOV AX,EOL SHL 8 + VT_SD ;AX=[terminator type | value type]
cEnd nogen ;no code generated
SUBTTL actual routine to print an item
page
;***
;B$PRINT - continue the print interfaces to print an item
;
;Purpose:
; Print an item for PRINT/WRITE/LPRINT statement.
;
; Printing an item is affected by:
; (1) whether it's a 'print using'
; (2) whether it prints a string (numbers need to be translated)
; (3) whether it is a print stmt or is a write stmt.
; In case of write stmt, the following are different:
; (a) no leading blank for a positive number if '+' omitted
; (b) no ending space for a number
; (c) string delimited by '"'
; (d) comma delimiting items
;
; One major difference here is that numbers also use the string output
; routine to print on a device. The string output routine outputs one
; string a time, if it fits the rest of the line, which is faster than
; iteratively outputs one character a time.
;
; Certainly, one piece of code, which serves such many functions, can't
; be as clean as some simple routines do. However, there still has its
; logic as follows:
;
; B$PRINT (TerminatorType_&_ValueType)
; {
; if channel on, test the mode is not input
; if error then give "bad file mode"
; get pointer of the item to be printed from stack
; set up types
;
; /* print the item */
;
; if the request was PRINT USING, then
; call print using routine
; else /* not a PRINT USING */
; if the request was printing a number, then
; translate the number into digital string
; if the request was a WRITE statement, then
; special process the leading & ending space
; else /* printing a string */
; if the request was a WRITE statement, then
; special process the string delimitor
; print the string
;
; /* process the terminator */
;
; if the terminator was a EOL, then force a carrage return
; if the terminator was a COMMA, then fill the rest of the column
; with blanks
; if the terminator was a SEMI-COLUMN and the request was a WRITE
; statement, then print a ','
;
; /* handle the exit process explicitly */
;
; play around with BP and SP
;
; /* When exit the stack looks like : */
; /* __________________ */
; /* | SI | */
; /* |----------------| */
; /* | DS (if ?WIN) | */
; /* BP -->|----------------| */
; /* | BP | */
; /* |----------------| */
; /* | Ret offset | */
; /* |----------------| */
; /* | Ret segment | */
; /* Val -->|----------------| */
; /* | Parameter | */
; /* (variable len) \................\ */
; /* \................\ */
; /* old SP -->|----------------| */
; /* |________________| */
; /* */
; }
;Entry:
; [AH] = [terminator type]
; [AL] = [value type]
; in stack,
; Val = first word of item, where item is either I2,I4,R4,R8 or sd/psd
;Exit:
; none
;Uses:
; none
;Exceptions:
; bad file mode
; I/O error or Disk full error when flush the buffer if a EOL encountered
;*******************************************************************************
;NOTE!: This routine has a manually
;generated epilogue due to variable number
;of parameters. If you change the prologue,
;here you must also change the epilogue
;further down.
cProc B$PRINT,<PUBLIC,FAR>,<SI> ;common routine, has to be declared
; as FAR for setting up stack frame correctly.
; SI saved
ParmW Val ;dummy parameter, which points to the first
; byte of the actual parameter regardless how
; many bytes it is; this also forces to set
; up the stack frame
cBegin ;stack frame is set up and SI is saved
MOV [b$?TYP],AX ;set up b$VTYP & b$TTYP
LEA BX,Val ;get the address of parameter
CMP AL,VT_SD ; is this a string parm?
JNZ ChkString ; brif not - BX has the pointer to the value
MOV BX,[BX] ; if SD, BX has the value, not pointer
ChkString:
TEST [b$PRFG],USING ;is print using on ?
JNZ PRTUSG ;Brif yes
CMP AL,VT_SD ;printing a string ?
JZ PRTSTR ;Brif yes
;[2] At this moment, [BX]=*I2,*I4,*R4 or *R8.
; Currently B$FOUTBX changes all registers except BP. This has to be
; changed later on.
CALL B$FOUTBX ; Hopefully, the return from B$FOUTBX
; are BX containing the address of the
; string and AX is the length
MOV SI,BX ; SI=*Number
TEST [b$PRFG],WRSTM ;is write statement on ?
JNZ WRTVAL ;Brif is write stmt
ADD BX,AX ;bx points to the terminate byte (00)
INC AX ;increment the length of the digital string
MOV BYTE PTR [BX]," " ;Number always followed by " "
;Note: the static buffer for translating a
; number must at least one byte longer
; than the maximum possible length.
cCall MAKESD ;[BX]=*sd on return
PRTIT1: ;at this entry, check whether a EOL is needed
PUSH BX ;save psd
cCall [VPRTCHK] ; CY if room is not enough (possibly a EOL
; was already forced), needs AX=len of string
POP BX ;get back psd
PRTIT2: ;at this entry, no check for EOL (write)
PUSH BX ; save psd
CALL [VTYP] ;print the string, needs [BX]=psd
POP BX ; get back psd
CALL [b$pSTDALCTMP] ; deallocate the temp if it is
PRTEND:
MOV AL,[b$TTYP] ; get delimiter type
CBW ; extend to use word ops
DEC AX ; test for EOL delimiter
JG PRTCLF ; Brif end with LF-CR
TEST [b$PRFG],WRSTM ;is write stmt on ?
JZ PRTEND2 ; Brif not
MOV AL,"," ; here if comma or semi and write stmt
CALL [VWCH] ;write the character
JMP SHORT PRINTX ;exit to caller
WRTVAL: ;write stmt take off the leading " "
CMP BYTE PTR [BX]," " ;is first a blank ?
JNZ WTMKSD ;Brif not, go make sd & print it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -