beh semplice: un nome di variabile non può iniziare con un numero, quindi se stavi parsando un numero e trovi un punto, sarà un numero in virgola mobile. Anche se vuoi parsare espressioni tipo ".25", di sicuro non può essere il punto inteso come indicizzazione in struttura.
Esempi:
12.48 -- Vede 1 e inizia a leggere un "numero"; quando arriva al . capisce che non è "intero" ma è "float", e quindi finisce le ultime due cifre.
.88 -- il punto è seguito da un numero: è per forza un numero float nella forma 0.xxx (e di sicuro non può essere una struttura, perchè non hai il nome della struttura su cui applicare il punto).
p123.z4 -- parte da "p", deve essere un identificatore. Continua leggendo "p123" come identificatore. Quando incontra il punto, è ovvio che non può essere un numero, e quindi viene emesso il token di indicizzazione in struttura. Continua leggendo "z4" che è un identificatore valido e termina.
456.0abc7 -- Errore: inizia leggendo 456, vede il punto (=> è un float in forma 456.xxx), legge 0 e gli va ancora bene, legge "a" e si ferma in errore in quanto "a" non è una cifra valida.
98.abc77 -- inizia leggendo "98", al punto capisce che è float, si ferma al "a" in quanto si aspettava la parte decimale fatta solo da cifre (nota che, in se, "abc77" è un identificatore valido, però avendolo trovato mentre il lexer era in modalità "numero float" non ci va bene).
kk_a8.9087 -- vede "k" e parte in modalità identificatore; legge "kk_a8" che è un identificatore valido, al punto capisce che deve essere una struttura (ed emette il token adeguato), però dopo incontra un "9" che non va bene come carattere iniziale di un identificatore, e quindi si ferma in errore (nota che di per se "9087" è un numero valido).
Insomma, il lexer deve avere uno stato su cui può lavorare, non puoi parsare solo guardando un carattere alla volta.
Per i prefissi scientifici, la situazione è la stessa: sei nel quarto caso (456.0abc7), solo che in questo caso (mettiamo 456.01M), quando incontri M, puoi vedere nella tabellina di prefissi validi, scopri che lo è, e quindi lo includi nel numero (o magari scali direttamente il numero della potenza adeguata), solo che poi devi star attento a portare il lexer via dalla modalità "numero", perchè non puoi avere 123.23M214, quindi qualsiasi cifra successiva va segnata come errore.
Per l'esponente, stesso discorso di sopra, solo che una volta che incontri "e" o "E", invece di portare il lexer in modalità "niente cifre", lo porti in modalità "lettura esponente", e procedi come per qualsiasi altro numero.
TL;DR: un numero lo discrimini da un identificatore perchè un numero inizia con una cifra, mentre un identificatore con una lettera (o "_").