Is this the right way to do it ?

Gaspard Bucher gasp... at teti.ch
Wed Oct 31 07:58:21 UTC 2007


I am implementing a parser to read commands from user (interactive) or
from a stored file. The idea is to build the objects and their
relation inside rubyk (http://rubyk.org). Some examples of the syntax:

create a metronome object: m1 = Metro(120)
create a metronome object: m1 = Metro(metro:120) # same as above
create a note out object:     n  = NoteOut(velocity:80 port:"funk")
create a script object:         cooking = Script(".... Lua code ....")
create links:               m1.1 => 1.cooking, cooking.1 =>
1.n

Here is a rough prototype to implement the parsing using ragel (have
been using flex/lemon).

Am I doing this right ? More precisely :
1. is there a better way to extract token values ( instead of by
repeated @a appends) ?
2. would it be simpler to use ragel only for building the tokens and
let lemon handle the actions ?

Thanks for your answers.

Gaspard

=================== prototype.rl ========
#include <iostream>
#include <cstdio>
#define MAX_BUFFER_SIZE 2048

%%{
  machine foo;
  write data noerror;
}%%

class Command
{
public:
  void parse(char * str)
  {
    char *p = str; // data pointer
    char *pe = str + strlen(str); // past end
    int cs;        // machine state
    int len = 0;
    char token[MAX_BUFFER_SIZE + 1];

    %%{
      action a {
        if (len >= MAX_BUFFER_SIZE) {
          std::cerr << "Buffer overflow !" << std::endl;
          // stop parsing
          return;
        }
        token[len] = fc; /* append */
        len++;
      }

      action set_var {
        token[len] = '\0';
        mVariable = token;
        len = 0;
      }

      action key {
        token[len] = '\0';
        std::cout << "[key   :" << token << "]" << std::endl;
        len = 0;
      }

      action set_klass {
        token[len] = '\0';
        mClass = token;
        len = 0;
      }

      action space {
        printf(" ");
      }

      action ret {
        printf("\n");
      }

      action set_string {
        token[len] = '\0';
        mValue = token;
        len = 0;
      }

      action set_float {
        token[len] = '\0';
        mValue = token;
        len = 0;
      }

      action set_integer {
        token[len] = '\0';
        mValue = token;
        len = 0;
      }

      action set_from {
        mFromPort = atoi(mValue.c_str());
        mFrom = mVariable;
      }

      action create_instance {
        std::cout << "NEW  (" << mVariable << "=" << mClass << "()" <<
")" << std::endl;
      }

      action create_link {
        mToPort = atoi(mValue.c_str());
        mTo   = mVariable;
        std::cout << "LINK (" << mFrom << "." << mFromPort << "=>" <<
mToPort << "." << mTo << ")" << std::endl;
      }

      ws     = (' ' | '\n' | '\t')+;

      identifier = 'a'..'z' @a (digit | alpha | '_')* @a;

      var    = identifier %set_var;

      klass  = 'A'..'Z' @a (digit | alpha | '_')* @a %set_klass;

      string  = '"' ([^"\\] | '\n' | ( '\\' (any | '\n') ))* @a
%set_string '"';
      float   = ('1'..'9' @a digit* @a '.' @a digit+ @a) %set_float;
      integer = ('1'..'9' @a digit* @a) %set_integer;

      value  = (string | float | integer);

      key    = identifier %key;

      param  = (key ':' ws* value);

      parameters = value | (param ws*)+;

      create_instance = var ws* '=' ws* klass '(' parameters? ')'
@create_instance;

      create_link = var '.' integer @set_from ws* '=>' ws* integer '.'
var @create_link;

      main := ((create_instance | create_link) ws*)+  ;

      write init;
      write exec;
    }%%

    printf("\n");
  }
private:
  std::string mVariable, mFrom, mTo, mClass, mValue;
  int         mFromPort,     mToPort;
};

int main()
{
  Command cmd;
  cmd.parse("a=Value() b=Super(23.3)c=This(hey:\"mosdffasl\" come:
3)\na.1=>1.b a.2=>2.b");
}
===========================



More information about the ragel-users mailing list