After each line of Gcode sent from the host to the controller,
all the RepRap G-code interpreters (typically) respond with
a line that starts with "ok" and ends with a newline.
Most of the time it's just those 3 bytes -- "ok\n" -- but occasionally there's some debugging information at the end of the line.
Have you considered maybe starting with one of the RepRap Gcode interpreters that run on an Arduino, and tweaking it to meet your needs,
rather than starting from scratch?
Most of those RepRap interpreters work exactly like Michael Pruitt pointed out --
they have an internal buffer that can hold several lines of Gcode.
The interpreter holds off on sending the "ok" reply until
there is enough room in that buffer for the next line of Gcode.
When there is plenty of space in the buffer,
the interpreter may immediately send "ok" in response to several G1 codes,
buffering them all up,
sending those OKs long before it actually executes any of those commands.
I hear there are a variety of other methods to tell the
drip-feeder software on the host end that the machine is ready for the next line of Gcode:
dnc4U
mentions "XON/XOFF, RTS/CTS Haas Xmodem and Heidenhain Blockwise handshaking protocols".
I wish there was a single standard protocol, or some way to automatically detect which standard protocol today's machine is using.