Как переходить между состояниями?
Вам нужно для начала расписать лексемы, построить конечный автомат и доработать его для вычисления значений лексем. Пример для алфавита [a-z0-9=], идентификаторов, целых чисел и присвоения:
<буква> := [a-z]
<цифра> := [0-9]
<равно> := [=]
<идентификатор> := <буква>(<буква>|<цифра>)*
<число> := <цифра>(<цифра>)*
Автомат:_    [a-z]  [0-9]  [=]  ¬
s0    s1     s2    ok  end
s1    s1     s1    ok  ok
s2    ok     s2    ok  ok
Доработанный автомат:_       in == ['a'-'z']                     in == ['0'-'9']                    in == ['=']           ¬
s0    val := in; next; s1                 val := in-'0'; next; s2            next; ret(ASSIGN)  ret(EOT)
s1    val := concat(val, in); next; s1    val := concat(val, in); next; s1   ret(IDENT, val)    ret(IDENT, val)
s2    ret(INTEGER, val)                   val := val*10+in-'0'; next; s2     ret(INTEGER, val)  ret(INTEGER, val)
s0 - исходное состояние, in - текущий символ, next - переход к следующему символу в потоке, ret возвращает тип лексемы и её значение.
Список переходов при анализе 'a1=95':
Первый вызов:s0 ('a') -> val := 'a'; next; s1
s1 ('1') -> val := 'a1'; next; s1
s1 ('=') -> ret(IDENT, 'a1')
Второй вызов:s0 ('=') -> next; ret(ASSIGN)
Третий вызов:s0 ('9') -> val := 9; next; s2
s2 ('5') -> val := 95; next; s2
s2 (¬) -> ret(INTEGER, 95)
Следующие вызовы:s0 (¬) -> ret(EOT)
открой для себя flex