;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Local Procedures ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; NEAR GetFPToken ; NEAR ParseFP PUBLIC ParseFP ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Local Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; DW ACTION1 ; DW ACTION2 ; DB NEXTSTATE ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NAME FloatingPointParserDriver ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; FLOATPTD ; ; Driver for Parsing Floating-Point Strings ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This file contains the main functions for parsing ASCII floating-point ; numbers. The functions included are: ; ParseFP - parse an ASCII floating-point number ; GetFPToken - get an input token for the parser ; ; Revision History: ; 2/26/03 Glen George initial revision ; 2/24/05 Glen George simplified some code in ParseFP ; updated comments ; local include files $INCLUDE(FLOATPT.INC) PROGRAM SEGMENT PUBLIC 'CODE' ASSUME CS:PROGRAM, DS:NOTHING, ES:NOTHING ; external action routines used by state machine ; assumed to affect no registers EXTRN addDigit:NEAR ;add a digit to the mantissa EXTRN addExpDigit:NEAR ;add a digit to the exponent EXTRN buildFP:NEAR ;build the floating-point number EXTRN doNOP:NEAR ;do nothing EXTRN error:NEAR ;there is an error EXTRN setExp10N:NEAR ;digits to right of decimal point EXTRN setExp10P:NEAR ;digits to left of decimal point EXTRN setExpSign:NEAR ;set exponent sign EXTRN setSign:NEAR ;set mantissa sign ; ParseFP ; ; Description: This procedure parses a passed ASCII string into a binary ; floating-point value. The string must consist of an ; optional sign, followed by 0 or more digits, followed by ; an optional decimal point, followed by 0 or more digits, ; followed by an optional exponent. The exponent consists ; of the letter E or e, followed by an optional sign, ; followed by 1 or more digits. Note that there must be at ; least one digit before the exponent in the value. If the ; format is invalid NaN (not a number) is returned. If the ; number is too large Inf (infinity) is returned. ; ; Operation: Uses a state machine to translate the string. The ; function loops, processing characters until either the ; end state or error state is reached. At that point it ; returns with an appropriate value. ; ; Arguments: DS:DI - pointer to floating-point value to convert. ; Return Value: SI - binary representation of floating-point value ; ; Local Variables: BX - pointer to state transition table ; CL - current state ; Shared Variables: None. ; Global Variables: None. ; ; Input: None. ; Output: None. ; ; Error Handling: If the passed string does not hold a valid floating-point ; value NaN (not a number) is returned as the value. If the ; number will not fit into a 32-bit floating-point value ; +/- Inf is returned. ; ; Algorithms: State Machine. ; Data Structures: None. ; ; Registers Used: flags, AX, BX, CX, DX, SI, DI. ; Stack Depth: 1 word. ; ; Author: Glen George ; Last Modified: Feb. 24, 2005 ParseFP PROC NEAR PUBLIC ParseFP InitParsing: ;setup the state machine MOV CL, ST_INITIAL ;start in the initial state StateMachineLoop: ;main state machine loop CMP CL, ST_END ;see if at the end state JE StateMachineEnd ;if so, all done CMP CL, ST_ERROR ;see if in the error state JE StateMachineEnd ;again, all done if we are ;JMP DoNextToken ;otherwise, keep going DoNextToken: ;get next input for state machine MOV AL, [DI] ;get the input CALL GetFPToken ;and get the token type and value MOV DH, AH ;and save them in DH and CH MOV CH, AL ComputeTransition: ;figure out what transition to do MOV AL, NUM_TOKEN_TYPES ;find row in the table MUL CL ;AX is start of row for current state ADD AL, DH ;get the actual transition ADC AH, 0 ;propagate low byte carry into high byte IMUL BX, AX, SIZE TRANSITION_ENTRY ;now convert to table offset DoActions: ;do the actions (don't affect regs) MOV AL, CH ;get token value back for actions CALL CS:StateTable[BX].ACTION1 ;do the actions CALL CS:StateTable[BX].ACTION2 DoTransition: ;now go to next state MOV CL, CS:StateTable[BX].NEXTSTATE INC DI ;and next character in string JMP StateMachineLoop ;do another transition... StateMachineEnd: ;all done with state machine ;JMP EndParseFP ;so done with parsing EndParseFP: ;done parsing floating-point, return with value RET ParseFP ENDP ; StateTable ; ; Description: This is the state transition table for the state machine. ; Each entry consists of the next state and actions for that ; transition. The rows are associated with the current ; state and the columns with the input type. ; ; Author: Glen George ; Last Modified: Feb. 26, 2003 TRANSITION_ENTRY STRUC ;structure used to define table NEXTSTATE DB ? ;the next state for the transition ACTION1 DW ? ;first action for the transition ACTION2 DW ? ;second action for the transition TRANSITION_ENTRY ENDS ;define a macro to make table a little more readable ;macro just does an offset of the action routine entries to build the STRUC %*DEFINE(TRANSITION(nxtst, act1, act2)) ( TRANSITION_ENTRY< %nxtst, OFFSET(%act1), OFFSET(%act2) > ) StateTable LABEL TRANSITION_ENTRY ;Current State = ST_INITIAL Input Token Type %TRANSITION(ST_MANDIGIT, setExp10P, addDigit) ;TOKEN_DIGIT %TRANSITION(ST_MANSIGN, setSign, doNOP) ;TOKEN_SIGN %TRANSITION(ST_LEADINGDP, setExp10N, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_MANSIGN Input Token Type %TRANSITION(ST_MANDIGIT, setExp10P, addDigit) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_LEADINGDP, setExp10N, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_LEADINGDP Input Token Type %TRANSITION(ST_FRACDIGIT, addDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_MANDIGIT Input Token Type %TRANSITION(ST_MANDIGIT, addDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_FRACDIGIT, setExp10N, doNOP) ;TOKEN_DP %TRANSITION(ST_EXP, doNOP, doNOP) ;TOKEN_EXP %TRANSITION(ST_END, buildFP, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_FRACDIGIT Input Token Type %TRANSITION(ST_FRACDIGIT, addDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_EXP, doNOP, doNOP) ;TOKEN_EXP %TRANSITION(ST_END, buildFP, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_EXP Input Token Type %TRANSITION(ST_EXPDIGIT, addExpDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_EXPSIGN, setExpSign, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_EXPSIGN Input Token Type %TRANSITION(ST_EXPDIGIT, addExpDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_EXPDIGIT Input Token Type %TRANSITION(ST_EXPDIGIT, addExpDigit, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_END, buildFP, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_ERROR Input Token Type %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_SIGN %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_DP %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_EXP %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_EOS %TRANSITION(ST_ERROR, error, doNOP) ;TOKEN_OTHER ;Current State = ST_END Input Token Type %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_DIGIT %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_SIGN %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_DP %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_EXP %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_EOS %TRANSITION(ST_END, doNOP, doNOP) ;TOKEN_OTHER ; GetFPToken ; ; Description: This procedure returns the token class and token value for ; the passed character. The character is truncated to ; 7-bits. ; ; Operation: Looks up the passed character in two tables, one for token ; types or classes, the other for token values. ; ; Arguments: AL - character to look up. ; Return Value: AL - token value for the character. ; AH - token type or class for the character. ; ; Local Variables: BX - table pointer, points at lookup tables. ; Shared Variables: None. ; Global Variables: None. ; ; Input: None. ; Output: None. ; ; Error Handling: None. ; ; Algorithms: Table lookup. ; Data Structures: Two tables, one containing token values and the other ; containing token types. ; ; Registers Used: AX, BX. ; Stack Depth: 0 words. ; ; Author: Glen George ; Last Modified: Feb. 26, 2003 GetFPToken PROC NEAR InitGetFPToken: ;setup for lookups AND AL, TOKEN_MASK ;strip unused bits (high bit) MOV AH, AL ;and preserve value in AH TokenTypeLookup: ;get the token type MOV BX, OFFSET(TokenTypeTable) ;BX points at table XLAT CS:TokenTypeTable ;have token type in AL XCHG AH, AL ;token type in AH, character in AL TokenValueLookup: ;get the token value MOV BX, OFFSET(TokenValueTable) ;BX points at table XLAT CS:TokenValueTable ;have token value in AL EndGetFPToken: ;done looking up type and value RET GetFPToken ENDP ; Token Tables ; ; Description: This creates the tables of token types and token values. ; Each entry corresponds to the token type and the token ; value for a character. Macros are used to actually build ; two separate tables - TokenTypeTable for token types and ; TokenValueTable for token values. ; ; Author: Glen George ; Last Modified: Feb. 26, 2003 %*DEFINE(TABLE) ( %TABENT(TOKEN_EOS, 0) ;<null> (end of string) %TABENT(TOKEN_OTHER, 1) ;SOH %TABENT(TOKEN_OTHER, 2) ;STX %TABENT(TOKEN_OTHER, 3) ;ETX %TABENT(TOKEN_OTHER, 4) ;EOT %TABENT(TOKEN_OTHER, 5) ;ENQ %TABENT(TOKEN_OTHER, 6) ;ACK %TABENT(TOKEN_OTHER, 7) ;BEL %TABENT(TOKEN_OTHER, 8) ;backspace %TABENT(TOKEN_OTHER, 9) ;TAB %TABENT(TOKEN_OTHER, 10) ;new line %TABENT(TOKEN_OTHER, 11) ;vertical tab %TABENT(TOKEN_OTHER, 12) ;form feed %TABENT(TOKEN_OTHER, 13) ;carriage return %TABENT(TOKEN_OTHER, 14) ;SO %TABENT(TOKEN_OTHER, 15) ;SI %TABENT(TOKEN_OTHER, 16) ;DLE %TABENT(TOKEN_OTHER, 17) ;DC1 %TABENT(TOKEN_OTHER, 18) ;DC2 %TABENT(TOKEN_OTHER, 19) ;DC3 %TABENT(TOKEN_OTHER, 20) ;DC4 %TABENT(TOKEN_OTHER, 21) ;NAK %TABENT(TOKEN_OTHER, 22) ;SYN %TABENT(TOKEN_OTHER, 23) ;ETB %TABENT(TOKEN_OTHER, 24) ;CAN %TABENT(TOKEN_OTHER, 25) ;EM %TABENT(TOKEN_OTHER, 26) ;SUB %TABENT(TOKEN_OTHER, 27) ;escape %TABENT(TOKEN_OTHER, 28) ;FS %TABENT(TOKEN_OTHER, 29) ;GS %TABENT(TOKEN_OTHER, 30) ;AS %TABENT(TOKEN_OTHER, 31) ;US %TABENT(TOKEN_OTHER, ' ') ;space %TABENT(TOKEN_OTHER, '!') ;! %TABENT(TOKEN_OTHER, '"') ;" %TABENT(TOKEN_OTHER, '#') ;# %TABENT(TOKEN_OTHER, '$') ;$ %TABENT(TOKEN_OTHER, 37) ;percent %TABENT(TOKEN_OTHER, '&') ;& %TABENT(TOKEN_OTHER, 39) ;' %TABENT(TOKEN_OTHER, 40) ;open paren %TABENT(TOKEN_OTHER, 41) ;close paren %TABENT(TOKEN_OTHER, '*') ;* %TABENT(TOKEN_SIGN, +1) ;+ (positive sign) %TABENT(TOKEN_OTHER, 44) ;, %TABENT(TOKEN_SIGN, -1) ;- (negative sign) %TABENT(TOKEN_DP, 0) ;. (decimal point) %TABENT(TOKEN_OTHER, '/') ;/ %TABENT(TOKEN_DIGIT, 0) ;0 (digit) %TABENT(TOKEN_DIGIT, 1) ;1 (digit) %TABENT(TOKEN_DIGIT, 2) ;2 (digit) %TABENT(TOKEN_DIGIT, 3) ;3 (digit) %TABENT(TOKEN_DIGIT, 4) ;4 (digit) %TABENT(TOKEN_DIGIT, 5) ;5 (digit) %TABENT(TOKEN_DIGIT, 6) ;6 (digit) %TABENT(TOKEN_DIGIT, 7) ;7 (digit) %TABENT(TOKEN_DIGIT, 8) ;8 (digit) %TABENT(TOKEN_DIGIT, 9) ;9 (digit) %TABENT(TOKEN_OTHER, ':') ;: %TABENT(TOKEN_OTHER, ';') ;; %TABENT(TOKEN_OTHER, '<') ;< %TABENT(TOKEN_OTHER, '=') ;= %TABENT(TOKEN_OTHER, '>') ;> %TABENT(TOKEN_OTHER, '?') ;? %TABENT(TOKEN_OTHER, '@') ;@ %TABENT(TOKEN_OTHER, 'A') ;A %TABENT(TOKEN_OTHER, 'B') ;B %TABENT(TOKEN_OTHER, 'C') ;C %TABENT(TOKEN_OTHER, 'D') ;D %TABENT(TOKEN_EXP, 0) ;E (exponent indicator) %TABENT(TOKEN_OTHER, 'F') ;F %TABENT(TOKEN_OTHER, 'G') ;G %TABENT(TOKEN_OTHER, 'H') ;H %TABENT(TOKEN_OTHER, 'I') ;I %TABENT(TOKEN_OTHER, 'J') ;J %TABENT(TOKEN_OTHER, 'K') ;K %TABENT(TOKEN_OTHER, 'L') ;L %TABENT(TOKEN_OTHER, 'M') ;M %TABENT(TOKEN_OTHER, 'N') ;N %TABENT(TOKEN_OTHER, 'O') ;O %TABENT(TOKEN_OTHER, 'P') ;P %TABENT(TOKEN_OTHER, 'Q') ;Q %TABENT(TOKEN_OTHER, 'R') ;R %TABENT(TOKEN_OTHER, 'S') ;S %TABENT(TOKEN_OTHER, 'T') ;T %TABENT(TOKEN_OTHER, 'U') ;U %TABENT(TOKEN_OTHER, 'V') ;V %TABENT(TOKEN_OTHER, 'W') ;W %TABENT(TOKEN_OTHER, 'X') ;X %TABENT(TOKEN_OTHER, 'Y') ;Y %TABENT(TOKEN_OTHER, 'Z') ;Z %TABENT(TOKEN_OTHER, '[') ;[ %TABENT(TOKEN_OTHER, '\') ;\ %TABENT(TOKEN_OTHER, ']') ;] %TABENT(TOKEN_OTHER, '^') ;^ %TABENT(TOKEN_OTHER, '_') ;_ %TABENT(TOKEN_OTHER, '`') ;` %TABENT(TOKEN_OTHER, 'a') ;a %TABENT(TOKEN_OTHER, 'b') ;b %TABENT(TOKEN_OTHER, 'c') ;c %TABENT(TOKEN_OTHER, 'd') ;d %TABENT(TOKEN_EXP, 0) ;e (exponent indicator) %TABENT(TOKEN_OTHER, 'f') ;f %TABENT(TOKEN_OTHER, 'g') ;g %TABENT(TOKEN_OTHER, 'h') ;h %TABENT(TOKEN_OTHER, 'i') ;i %TABENT(TOKEN_OTHER, 'j') ;j %TABENT(TOKEN_OTHER, 'k') ;k %TABENT(TOKEN_OTHER, 'l') ;l %TABENT(TOKEN_OTHER, 'm') ;m %TABENT(TOKEN_OTHER, 'n') ;n %TABENT(TOKEN_OTHER, 'o') ;o %TABENT(TOKEN_OTHER, 'p') ;p %TABENT(TOKEN_OTHER, 'q') ;q %TABENT(TOKEN_OTHER, 'r') ;r %TABENT(TOKEN_OTHER, 's') ;s %TABENT(TOKEN_OTHER, 't') ;t %TABENT(TOKEN_OTHER, 'u') ;u %TABENT(TOKEN_OTHER, 'v') ;v %TABENT(TOKEN_OTHER, 'w') ;w %TABENT(TOKEN_OTHER, 'x') ;x %TABENT(TOKEN_OTHER, 'y') ;y %TABENT(TOKEN_OTHER, 'z') ;z %TABENT(TOKEN_OTHER, '{') ;{ %TABENT(TOKEN_OTHER, '|') ;| %TABENT(TOKEN_OTHER, '}') ;} %TABENT(TOKEN_OTHER, '~') ;~ %TABENT(TOKEN_OTHER, 127) ;rubout ) ; token type table - uses first byte of macro table entry %*DEFINE(TABENT(tokentype, tokenvalue)) ( DB %tokentype ) TokenTypeTable LABEL BYTE %TABLE ; token value table - uses second byte of macro table entry %*DEFINE(TABENT(tokentype, tokenvalue)) ( DB %tokenvalue ) TokenValueTable LABEL BYTE %TABLE PROGRAM ENDS END