[ragel-users] Action for leaving a machine from a non-final state

M Conrad silverdirk-rgl at silverdirk.com
Tue Feb 28 16:47:31 UTC 2012


There's lots of ways to accomplish what you want, and it's hard to say if
one way is really better than another, but my favorite way to work with
these sorts of problems is to have all my data in one buffer, and then use
pointers to mark the bounds.

So, instead of copying one character at a time, and "goto" bouncing
between states, I would

     open = /.*\*OPEN\*/ %{ start_of_data= p; };
     close = /\*CLOS\*/ >{ if (!end_of_data) end_of_data= p; }
         @!{ end_of_data= NULL; }
         %{ process_data(); start_of_data= end_of_data= NULL; fret; };
     data := . | close;

end_of_data gets set every time the machine sees a "*", but then if it
doesn't complete the pattern it will get set again later.  Meanwhile, you
need to keep enlarging the buffer in other code, and if the buffer address
changes, alter the start_of_data and end_of_data pointers to match.

If you would rather use a static buffer, and process the data in pieces,
you would need something like this each time your buffer was full:

     shift_buffer() {
       if (start_of_data) {
         int ofs= start_of_data - buffer;
         int data_count= (end_of_data)? end_of_data - start_of_data
                       : sizeof(buffer) - ofs;
         int keep_count= sizeof(buffer) - ofs - data_count;

         // process portion of data
         printf("Data: '%.*s'\n", data_count, start_of_data);

         memmove(buffer, start_of_data+data_count, keep_count);
         start_of_data= buffer;
         end_of_data= buffer;
         p= buffer+keep_count;
       }
     }

The pointers and fixed buffer are more complicated, but it results in a
faster machine, since you don't write to memory on most data characters.

Hope that helps.

-Mike

On Tue, 21 Feb 2012 18:27:18 -0500, Ivan Reche <ivan.reche at gmail.com>
wrote:

> 2012/2/20 <ragel-user at jgoettgens.de>
>
>>   Ivan,
>>
>> so you need to mark the beginning and the end of either “command” or
>> “data” mode given the keywords “*OPEN*”  and “*CLOS*”. Right? Once  
>> matched
>> it is entirely up to you what to do with the matched text (User Actions,
>> chapter 3). You could post a typical token stream and an outline of your
>> ragel specs. Otherwise it is difficult to see the cause of your problem.
>>
>> jg
>>
>>
>> _______________________________________________
>> ragel-users mailing list
>> ragel-users at complang.org
>> http://www.complang.org/mailman/listinfo/ragel-users
>>
>
> I'm sorry if my post wasn't clear enough.
>
> I've managed to achieve the results that I expect, although I don't know  
> if
> it is the most effective way to do it. I'm gonna post it in this e-mail.  
> My
> objective is to read the stream of characters between the *OPEN* and  
> *CLOS*
> "tokens". Thanks in advance for any tips or insights on this.
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <stdbool.h>
>
> %%{
>
>     machine test;
>
>     action open_found {
>         printf("FOUND OPEN\r\n");
>         fgoto data;
>     }
>     action close_found {
>         printf("FOUND CLOSE\r\n");
>         fgoto main;
>     }
>     action new_data_char {
>         printf("NEW CHAR: %c, lock: %d\n", fc, lock_data);
>         if (!lock_data)
>             rec[count++] = fc;
>     }
>     action close_candidate {
>         printf("CLOSE CANDIDATE: %c\n", fc);
>         lock_data = true;
>         cacount = 0;
>         fhold; fgoto clos;
>     }
>     action not_close {
>         printf("NOT CLOSE: %c, candidate: %s, cacount: %d\n", fc,
> candidate, cacount);
>         lock_data = false;
>         strncat(rec, candidate, cacount);
>         count += cacount;
>         fgoto data;
>     }
>     action store_candidate_char {
>         printf("CANDIDATE CHAR: %c\n", fc);
>         candidate[cacount++] = fc;
>     }
>
>     open = /.*\*OPEN\*/;
>     close = /.*\*CLOS\*/;
>
>     main :=
>         (open %open_found)+;
>
>     data := /.*\*/ @~new_data_char %~close_candidate;
>     clos := /\*CLOS\*/ $/{fbreak;} $store_candidate_char @!(not_close)
> @close_found;
>
> }%%
>
> %% write data;
>
> const char *p, *pe, *eof;
> int cs;
> const char *ts, *te;
> int act;
> int stack[128] = {0};
> int top;
>
> char rec[1024] = {0};
> unsigned int count = 0;
> char candidate[1024] = {0};;
> unsigned int cacount = 0;
> bool lock_data = false;
>
> bool parse(const char * str) {
>     p = str; pe = str + strlen(str); eof = pe;
>
>     %% write exec;
>
>     return true;
> }
>
> int main(int argc, char **argv) {
>     char buf[2048] =
> "aaaaaaaaaa*OPEN*bbbbbbbb*CLbbbbbbbbb*CLOS*aaaaaaaaaaaaaaaaaaaa";
>
>     %% write init;
>
>     parse(buf);
>
>     printf("data[%d] = %s\n", count, rec);
>     return 0;
> }

_______________________________________________
ragel-users mailing list
ragel-users at complang.org
http://www.complang.org/mailman/listinfo/ragel-users


More information about the ragel-users mailing list