home *** CD-ROM | disk | FTP | other *** search
- page 66, 132
- ;----- nansi_p.asm --------------------------------------------------------
- ; A state machine implementation of the mechanics of ANSI terminal control
- ; string parsing.
- ; (C) 1986 Daniel Kegel, Pasadena, CA
- ; May be distributed for educational and personal use only
- ;
- ; Entered with a jump to f_escape when driver finds an escape, or
- ; to f_in_escape when the last string written to this device ended in the
- ; middle of an escape sequence.
- ;
- ; Exits by jumping to f_ANSI_exit when an escape sequence ends, or
- ; to f_not_ANSI when a bad escape sequence is found, or (after saving state)
- ; to f_loopdone when the write ends in the middle of an escape sequence.
- ;
- ; Parameters are stored as bytes in param_buffer. If a parameter is
- ; omitted, it is stored as zero. Each character in a keyboard reassignment
- ; command counts as one parameter.
- ;
- ; When a complete escape sequence has been parsed, the address of the
- ; ANSI routine to call is found in ansi_fn_table.
- ;
- ; Register usage during parsing:
- ; DS:SI points to the incoming string.
- ; CX holds the length remaining in the incoming string.
- ; ES:DI points to the current location on the memory-mapped screen.
- ; DX is number of characters remaining on the current screen line.
- ; BX points to the current paramter byte being assembled from the incoming
- ; string. (Stored in cur_parm_ptr between device driver calls, if needed.)
- ;
- ; The registers are set as follows before calling the ANSI subroutine:
- ; AX = max(1, value of first parameter)
- ; CX = number of paramters
- ; SI = offset of second parameter from CS
- ; DS = CS
- ; ES:DI points to the current location on the memory-mapped screen.
- ; DX is number of characters remaining on the current screen line.
- ; The subroutine is free to trash AX, BX, CX, SI, and DS.
- ; It must preserve ES, and can alter DX and DI if it wants to move the
- ; cursor.
- ;
- ; Revision history:
- ; 7 July 85: created by DRK
- ;------------------------------------------------------------------------
-
- ; From nansi.asm
- extrn f_not_ANSI:near ; exit: abort bad ANSI cmd
- extrn f_ANSI_exit:near ; exit: good cmd done
- extrn f_loopdone:near ; exit: ran out of chars. State saved.
- extrn escvector:word ; saved state: where to jump
- extrn cur_parm_ptr:word ; saved state: where to put next param
- extrn string_term:byte ; saved state: what ends string
- extrn cur_x:byte, max_x:byte ; 0 <= cur_x <= max_x
- extrn cur_attrib:byte ; current color/attribute
- extrn xlate_tab_ptr:word
-
- ; from nansi_f.asm
- extrn ansi_fn_table:word ; ANSI subroutine table
-
- ; Used in nansi.asm
- public f_escape ; entry: found an escape
- public f_in_escape ; entry: restore state, keep parsing
-
- ; Used in nansi_i.asm and nansi_f.asm
- public param_buffer, param_end, redef_end
-
-
- code segment byte public 'CODE'
- assume cs:code
-
- ; More saved state
- in_num db ? ; true if between a digit and a semi in parse
-
- param_buffer dw 3000h ; address of first byte free for new params
- param_end dw 3030h ; address of end of free area
- redef_end dw 3030h ; address of end of redefinition area
- ; These initialized values are only for debugging
-
- ;----- next_is -------------------------------------------------------
- ; Next_is is used to advance to the next state. If there are characters
- ; left in the input string, we jump immediately to the new state;
- ; otherwise, we shut down the recognizer, and wait for the next call
- ; to the device driver.
- next_is macro statename
- loop statename
- mov ax, offset statename
- jmp sleep
- endm
-
- ;----- sleep --------------------------------------------------------
- ; Remember bx and next state, then jump to device driver exit routine.
- ; Device driver will re-enter at f_in_escape upon next invocation
- ; because escvector is nonzero; parsing will then be resumed.
- sleep: mov cs:cur_parm_ptr, bx
- mov cs:escvector, ax
- jmp f_loopdone
-
- ;----- f_in_escape ---------------------------------------------------
- ; Main loop noticed that escvector was not zero.
- ; Recall value of BX saved when sleep was jumped to, and jump into parser.
- f_in_escape:
- mov bx, cs:cur_parm_ptr
- jmp word ptr cs:escvector
-
- fbr_syntax_error_gate: ; jumped to from inside f_bracket
- jmp syntax_error
-
- ;----- f_escape ------------------------------------------------------
- ; We found an escape. Next character should be a left bracket.
- f_escape:
- next_is f_bracket
-
- ;----- f_bracket -----------------------------------------------------
- ; Last char was an escape. This one should be a [; if not, print it.
- ; Next char should begin a parameter string.
- f_bracket:
- lodsb
- cmp al, '['
- jnz fbr_syntax_error_gate
- ; Set up for getting a parameter string.
- mov bx, cs:param_buffer
- mov byte ptr cs:[bx], 0
- mov cs:in_num, 0
- next_is f_get_args
-
- ;----- f_get_args ---------------------------------------------------
- ; Last char was a [. If the current char is a '=' or a '?', eat it.
- ; In any case, proceed to f_get_param.
- ; This is only here to strip off the strange chars that follow [ in
- ; the SET/RESET MODE escape sequence.
- f_get_args:
- lodsb
- cmp al, '='
- jz fga_ignore
- cmp al, '?'
- jz fga_ignore
- dec si ; let f_get_param fetch al again
- jmp short f_get_param
- fga_ignore:
- next_is f_get_param
-
- ;----- f_get_param ---------------------------------------------------
- ; Last char was one of the four characters "]?=;".
- ; We are getting the first digit of a parameter, a quoted string,
- ; a ;, or a command.
- f_get_param:
- lodsb
- cmp al, '0'
- jb fgp_may_quote
- cmp al, '9'
- ja fgp_may_quote
- ; It's the first digit. Initialize current parameter with it.
- sub al, '0'
- mov byte ptr cs:[bx], al
- mov cs:in_num, 1 ; set flag for sensing at cmd exec
- next_is f_in_param
- fgp_may_quote:
- cmp al, '"'
- jz fgp_isquote
- cmp al, "'"
- jnz fgp_semi_or_cmd ; jump to code shared with f_in_param
- fgp_isquote:
- mov cs:string_term, al ; save it for end of string
- next_is f_get_string ; and read string into param_buffer
-
- ;----- f_get_string -------------------------------------
- ; Last character was a quote or a string element.
- ; Get characters until ending quote found.
- f_get_string:
- lodsb
- cmp al, cs:string_term
- jz fgs_init_next_param
- mov byte ptr cs:[bx], al
- cmp bx, cs:param_end
- adc bx, 0 ; if bx<param_end bx++;
- next_is f_get_string
- ; Ending quote was found.
- fgs_init_next_param:
- mov byte ptr cs:[bx], 0 ; initialize new parameter
- ; | Eat following semicolon, if any.
- next_is f_eat_semi
-
- ;----- f_eat_semi -------------------------------------
- ; Last character was an ending quote.
- ; If this char is a semi, eat it; else unget it.
- ; Next state is always f_get_param.
- f_eat_semi:
- lodsb
- cmp al, ';'
- jz fes_eaten
- inc cx
- dec si
- fes_eaten:
- next_is f_get_param
-
- ;----- syntax_error ---------------------------------------
- ; A character was rejected by the state machine. Exit to
- ; main loop, and print offending character. Let main loop
- ; decrement CX (length of input string).
- syntax_error:
- mov cs:escvector, 0
- mov ah, cs:cur_attrib
- mov bx, cs:xlate_tab_ptr
- jmp f_not_ANSI ; exit, print offending char
-
- ;------ f_in_param -------------------------------------
- ; Last character was a digit.
- ; Looking for more digits, a semicolon, or a command character.
- f_in_param:
- lodsb
- cmp al, '0'
- jb fgp_semi_or_cmd
- cmp al, '9'
- ja fgp_semi_or_cmd
- ; It's another digit. Add into current parameter.
- sub al, '0'
- xchg byte ptr cs:[bx], al
- push dx
- mov dl, 10
- mul dl
- pop dx
- add byte ptr cs:[bx], al
- next_is f_in_param
- ; Code common to states get_param and in_param.
- ; Accepts a semicolon or a command letter.
- fgp_semi_or_cmd:
- cmp al, ';'
- jnz fgp_not_semi
- cmp bx, cs:param_end ; prepare for next param-
- adc bx, 0 ; if bp<param_end bp++;
- ; Set new param to zero, enter state f_get_param.
- mov cs:in_num, 0 ; no longer inside number
- jmp fgs_init_next_param ; spaghetti code attack!
- fgp_not_semi:
- ; It must be a command letter.
- cmp al, '@'
- jb syntax_error
- cmp al, 'z'
- ja syntax_error
- cmp al, 'Z'
- jbe fgp_is_cmd
- cmp al, 'a'
- jb syntax_error
- ; It's a lower-case command letter.
- ; Remove hole between Z and a to save space in table.
- sub al, 'a'-'['
- fgp_is_cmd:
- ; It's a command letter. Save registers, convert letter
- ; into address of routine, set up new register usage, call routine.
- push si ; These three registers hold info
- push cx ; having to do with the input string,
- push ds ; which has no interest at all to the
- ; control routine.
-
- push cs
- pop ds ; ds is now cs
-
- sub al, '@' ; first command is @: insert chars
- cbw
- add ax, ax
- add ax, offset ansi_fn_table
- ; ax is now pointer to command routine address in table
-
- mov cx, bx
- mov si, param_buffer ; si is now pointer to parameters
- sub cx, si ;
- test in_num, 1
- jz fip_out_num
- inc cx
- fip_out_num: ; cx is now # of parameters
-
- xchg ax, bx ; save pointer to routine in bx
-
- ; Calculate cur_x from DX.
- mov al, max_x
- inc ax
- sub al, dl
- mov cur_x, al
-
- ; Get first parameter into AX; if defaulted, set it to 1.
- mov ah, 0
- lodsb
- or al, al
- jnz fgp_callem
- inc ax
- or ah, ah ; save Zflag for eid -- hyc 10-30-90
- fgp_callem:
- ; Finally, call the command subroutine.
- call word ptr [bx]
-
- pop ds
- pop cx
- pop si
-
- mov ah, cs:cur_attrib ; Prepare for STOSW.
- mov bx, cs:xlate_tab_ptr ; Prepare for translation.
- mov cs:escvector, 0 ; No longer parsing escape sequence.
- ; Set flags for reentry at loopnz
- or dx, dx ; "Any columns left on line?"
- ; Re-enter at bottom of main loop.
- jmp f_ansi_exit
-
-
- code ends
- end ; of nansi_p.asm
-
-