Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Ragel EOF actions working

I'm working with Ragel to evaluate FSAs, and I want to embed a user action that runs whenever my machine finishes testing the input. I need this action to run regardless of whether or not the machine ends in an accepting state or not. I have this modified example taken from the Ragel guide that illustrates what I'm going for:

#include <string.h>
#include <stdio.h>

%%{
    machine foo;
    main := ( 'foo' | 'bar' ) 0 @{ res = 1; } $/{ finished = 1; };
}%%
%% write data;
int main( int argc, char **argv ) {
    int cs, res = 0, finished = 0;
    if ( argc > 1 ) {
        char *p = argv[1];
        char *pe = p + strlen(p) + 1;
        char* eof = pe;
        %% write init;
        %% write exec;
    }

    printf("result = %i\n", res );
    printf("finished = %i\n", finished);

    return 0;
}

My goal for this example is for res to be 1 when the input is either 'foo' or 'bar', while finished is 1 no matter the input. I can't get this to work though - finished seems to be 1 when res is 1, and 0 when res is 0.

Any help would be awesome.

like image 621
Mark Avatar asked Apr 29 '13 07:04

Mark


2 Answers

The eof action will take place when p == pe == eof. Another important thing is that when your state machine can't match any state, the state will go to error and the match will stop, which means you can never go to the end.

Let's see when you input foo1. When parsing to o, everything is ok. Howerver the next charactor 1 can't match any state you specify, so an error occurs. You can never meet the eof action. So the variable res and finish is both 0.

When you input foo, every thing is ok. The state can go to the end. So the eof action take place.

You can set the error action to see what happens:

%%{
    main := ( 'foo' | 'bar' ) 0 @{ res = 1; } $err{ printf("error : %c", fc);} $/{ finished = 1; };
}%%

And you may try this code to meet your needs:

%%{
    main := (( 'foo' | 'bar' ) 0 @{ res = 1; } | any* ) $/{ finished = 1; };
}%%
like image 92
akawhy Avatar answered Sep 22 '22 17:09

akawhy


Try this:

main := ( 
    'foo' 0 @2 @{ res = 1; } | 
    'bar' 0 @2 @{ res = 1; } |
    any*
    ) @{ finished = 1; };
like image 27
bdnt Avatar answered Sep 19 '22 17:09

bdnt