#States of PPF parsing DFA

NEW   #Have just read a newline char. Clean for new input.
COM   #Is in comment mode until newline found
SPACE #Has read whitespace, will only accept more whitespace, until newline
SETVAR   #Have just read variable name; following chars must be upper-case
         #HEX digits which will form the value to set the variable to.
CLOSEVAL #Have read number of digits of hex appropriate to variable (according
         #to template for current mode). Following char must be either
         #whitespace or newline, in which case the variable will be set
         #and the appropriate state changed to.
CLOSEPKT #Have read uppercase command character (actions). Following char
         #must be either whitespace or newline, in which case the action
         #will be carried out.
FAIL     #Have read invalid input. Might change back to state NEW on
         #reading a newline, or might stay in FAIL perpetually for sanity's
         #sake. If possible to change back, will probably maintain a counter
         #for number of errors, such that if lots accumulate, it probably
         #indicates a serious mismatch.

#...

State changes:
NEW: # ->COM(nop)
     [\s] ->SPACE(nop)
     [a-z]->SETVAR(set lhs=char)
     [A-Z]->CLOSEPKT(set cmd=char)
     [\r\n]->NEW(nop)
     .->FAIL(return fail)

COM: [\r\n]->NEW(nop)
     .->COM(nop)

SPACE: [\s]->SPACE(nop)
     [\r\n]->NEW(nop)
     .->FAIL(return fail)
SETVAR: [0-9A-F] if enough characters, CLOSEVAL
                 else SETVAR, char++
        .->FAIL(return fail)
CLOSEVAL: [\s] set variable to val, ->SPACE(put val in lhs)
          [\r\n] set variable to val, ->NEW(put val in lhs)
          .->FAIL(return fail)
CLOSEPKT: [\s] Issue command, ->SPACE(return cmd,plus relevant vars)
          [\r\n] Issue command, ->NEW(return cmd,plus relevant vars)
          .->FAIL(return fail)
FAIL: .->FAIL(return fail)


#
Packet returns:
Caller must pass parser function a buffer in which to write the packet; the
buffer could be a local var passed by address, or a pointer to dynamically
allocated space on the heap, or whatever. It is also caller's job to deal
with any freeing etc that might be necessary;
Packets are likely to be sent to the accompanying writer function; the
writer is guaranteed to have finished with the data in the buffer as soon
as it returns, so the caller may free it or recycle it as necessary.

Contents of packet:
Packets could be in 2 types, each type with one version of the reader and of
the writer function to work with it; One type could transfer unparsed strings
of the hex values, the other could translate them into unsigned longs. The
advantage of the strings approach is less overhead for when just moving the
packets around, plus you can use a NULL pointer to indicate that a variable
is irrelevant to a specific command.
The advantage of the translated approach is if the variables are being
interpreted much (it's quicker to not read them twice), and there should
be less space wasted. NB: In either case, it's uncertain what range to limit
values to; 16 bit? 32 bit? More?

