Hey Mike, thanks for the example. I ended up playing with a simplified
version of the Concurrent example, to get the NULL-detection I
described, and examining the generated output. I came to the same
conclusion as you regarding {p, pe, cs}, but it's always good to hear
it from a second source. The result is something like this:
typedef struct {
void (*on_null)(size_t pos);
} par_cb_t;
typedef struct {
int cs;
} par_t;
void par_exec(par_t *par, void *buf, size_t buf_len, par_cb_t *cb, void *ud) {
int cs = par->cs;
void *p = buf;
void *pe = NULL == buf ? NULL : p + buf_len - 1;
%% write exec;
par->cs = cs;
}
In order to get the userdata stuff I wanted, the caller populates a
callback structure, and all the actions call their associated callback
in this structure with ud. This could pretty easily be done without
the callback structure by just passing a function pointer that takes
both a userdata and an event type, since all the events have the same
prototype, if you're doing what I'm doing and notifying the buffer
index on the beginning and ending of machines that represent a
particular type of entity.
k
On Sun, Nov 11, 2012 at 7:09 AM, Michael Conrad
Post by Karel SedláÄekThanks, but could you maybe give me a 10-liner that exemplifies this
kind of behavior inside another application? Let's say I have my own
event loop set up to feed Ragel buffers. Where do I (or does Ragel)
allocate and store it's state? How do I get the pair of functions
described above that are parameterized over the state and consume
incremental new input? Can I have Ragel pass me a bit of userdata as
well, where I can keep the parse state and the thing receiving the
events? Keeping it simple, how about a parser that has an in-action
that tells a C function got_null(void *userdata, size_t start_addr)
void got_null(void *userdata, size_t start_addr);
int parse_null(ragel_state_t *st, void *buf, size_t buf_len, void *userdata);
int parse_null_eof(rage_state_t *st, void *userdata);
Well, maybe not a 10-liner, but I think I have a single function that might
make it clear.
Ragel generates code that uses special named variables. You can either map
these to code (as I did with 'stack' and 'eof') or use local variables (like
with 'p' and 'pe'). Or, mix and match. You get to persist them however you
like.
As you can see, ragel's engine (as I'm using it) is nothing more than a
generated while loop state machine. The state is entirely stored in the
variables [p, pe, cs] and I give it an rvalue for 'eof'. I'm also using the
[stack, top] for recursion ability. You can preserve these state variables
however you like.
bool wiki_scanner_scanMore(wiki_scanner_t *scanner) {
const char
*p= scanner->curPos,
*pe= scanner->bufferLimit;
int cs= scanner->curState;
log_pos(start); //macro that prints trace info for debugging
%%{
variable stack scanner->stateStack;
variable top scanner->stateStackPos;
variable eof (scanner->eof? pe : NULL);
prepush {
if (scanner->stateStackPos >= scanner->stateStackLen) {
if (!scanner_enlarge_stateStack(scanner)) {
fprintf(stderr, "ltw_scanner: recursion limit: %d levels
deep; scan may emit incorrect results.\n", scanner->stateStackPos);
scanner->stateStackPos--;
}
}
}
write exec;
}%%
assert(p == pe);
scanner->curPos= p;
scanner->curState= cs;
return true;
}
Hope that helps.
-Mike
_______________________________________________
ragel-users mailing list
ragel-users at complang.org
http://www.complang.org/mailman/listinfo/ragel-users