In this case, I parse the floating point number using (a subset of) the syntax specified for the atof function. (I don't accept D or d as exponent indicators).
[whitespace] [sign] [digits] [.digits] [{ e | E} [sign]
digits]
(Actually, I don't let the user type the whitespace in, but we'll talk about that below). The parsing is done via a Finite State Machine (FSM) which takes the current state and the current character and decodes against a table indicating the next state. The table is encoded as a sequence of case statements inside a switch. In each match, I can do one or more of the following
- "Eat" the character, removing it from the input stream, or leaving it for the next state to process
- Set the next state
- Set an indicator as to whether the string is complete, incomplete, or erroneous.
This is encoded as shown (partially) below. To set the "indicator", I set a brush value to the pointer to a predefined brush. If the brush ever gets set to the "error" indicator, the loop ends.
int state = S0; for(int i = 0; brush != &errorBrush && i < s.GetLength();) { /* scan string */ TCHAR ch = s[i]; switch(MAKELONG(state, ch)) { /* states */ case MAKELONG(S0, _T(' ')): case MAKELONG(S0, _T('\t')): i++; continue; case MAKELONG(S0, _T('+')): case MAKELONG(S0, _T('-')): i++; brush = &partialBrush; state = IPART; continue; case MAKELONG(S0, _T('0')): ¤ ¤ ¤ case MAKELONG(S0, _T('9')): state = IPART; continue; case MAKELONG(S0, _T('.')): i++; state = FPART; brush = &partialBrush; continue; case MAKELONG(S0, _T('E')): case MAKELONG(S0, _T('e')): i++; state = ESIGN; brush = &partialBrush; continue; case MAKELONG(IPART, _T('0')): ¤ ¤ ¤ case MAKELONG(IPART, _T('9')): i++; brush = &OKBrush; continue; case MAKELONG(IPART, _T('.')): i++; brush = &OKBrush; state = FPART; continue; case MAKELONG(IPART, _T('e')): case MAKELONG(IPART, _T('E')): i++; brush = &partialBrush; state = ESIGN; continue; case MAKELONG(FPART, _T('0')): case MAKELONG(FPART, _T('9')): i++; brush = &OKBrush; continue; case MAKELONG(FPART, _T('e')): case MAKELONG(FPART, _T('E')): i++; brush = &partialBrush; state = ESIGN; continue; case MAKELONG(ESIGN, _T('+')): case MAKELONG(ESIGN, _T('-')): i++; brush = &partialBrush; state = EPART; continue; case MAKELONG(ESIGN, _T('0')): case MAKELONG(ESIGN, _T('1')): ¤ ¤ ¤ case MAKELONG(ESIGN, _T('9')): state = EPART; continue; case MAKELONG(EPART, _T('0')): ¤ ¤ ¤ case MAKELONG(EPART, _T('9')): i++; brush = &OKBrush; continue; default: brush = &errorBrush; continue; } /* states */ } /* scan string */
To absorb a character, I just increment the pointer (i++). You can create a similar table to parse a date, time, or any other field you can define.
Comments