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