added a couple missing includes

added a couple missing includes

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>

using std::cout;
using std::cerr;
using std::endl;
using std::ifstream;
using std::ofstream;

%%{
	machine garticle;
	write data;
}%%

int main( int argc, char **argv )
{
	std::ios::sync_with_stdio(false);

	if ( argc != 5 ) {
		cerr << "usage: garticle <dump-file> <article-index> <section> <article>" << endl;
		return -1;
	}

	char *dumpFile = argv[1];
	char *articleIndex = argv[2];
	char *section = argv[3];
	char *article = argv[4];

	ifstream dump( dumpFile );
	if ( !dump.is_open() ) {
		cerr << "error: unable to open " << dumpFile << " for reading" << endl;
		return -1;
	}

	ifstream index( articleIndex );
	if ( !index.is_open() ) {
		cerr << "error: unable to open " << articleIndex <<  " for writing" << endl;
		return -1;
	}

	long long articleNum = atoll(article);
	index.seekg( articleNum * sizeof(long long) );

	long long start, end;
	index.read( (char*)&start, sizeof(long long) );
	index.read( (char*)&end, sizeof(long long) );

	long long len = end - start;
	char *buf = new char[len];
	dump.seekg( start-5 );
	dump.read( buf, len );

	char tn[2048];
	long ptn = 0;
	bool emit = false;

	char *p = buf, *pe = buf+len;
	int cs;

	%%{
		newline = '\n';
		sp = [ \t\n\r];

		name = [a-zA-Z:_0-9]+;

		# Tag names.
		tag_name = name
			>{ ptn = 0; }
			${ tn[ptn++] = *p; }
			%{ tn[ptn++] = 0; }
			;

		attr_name = name;

		# Attributes
		attr_val = '"' ( [^"\\] | newline | ( '\\' any ) )* '"';
		attr = attr_name '=' attr_val;
		attrs = ( sp attr )*;

		action maybe_open {
			if ( strcmp( tn, section ) == 0 )
				emit = true;
		}

		action maybe_close {
			if ( strcmp( tn, section ) == 0 )
				emit = false;
		}

		# Tags
		tag = '<' tag_name %maybe_open attrs sp? ( '>' | '/>' );
		close_tag = '</' tag_name %maybe_close '>';

		# Character data, not spaces and not tag starts.
		char_data_char = ^('<'|'&');
		char_data = char_data_char+
			${
				if ( emit )
					cout << *p;
			} ;

		defined_entities =
			'quot' %{if (emit) cout << '"';} |
			'amp' %{if (emit) cout << '&';} |
			'apos' %{if (emit) cout << '\'';} |
			'lt' %{if (emit) cout << '<';} |
			'gt' %{if (emit) cout << '>';};

		entity_ref = '&' defined_entities ';';

		main := (
				tag |
				close_tag |
				entity_ref |
				char_data
			)*
			;

		write init;
		write exec;
	}%%

	if ( cs < garticle_first_final ) {
		cerr << endl << endl << "garticle: error parsing dump file" << endl;
		return 1;
	}

	//cout.write( buf, len );
	cout << endl;

	return 0;
}

#include <iostream>
#include <fstream>

using std::cout;
using std::cerr;
using std::endl;
using std::ifstream;
using std::ofstream;

%%{
	machine garticle;
	write data;
}%%

int main( int argc, char **argv )
{
	std::ios::sync_with_stdio(false);

	if ( argc != 5 ) {
		cerr << "usage: garticle <dump-file> <article-index> <section> <article>" << endl;
		return -1;
	}

	char *dumpFile = argv[1];
	char *articleIndex = argv[2];
	char *section = argv[3];
	char *article = argv[4];

	ifstream dump( dumpFile );
	if ( !dump.is_open() ) {
		cerr << "error: unable to open " << dumpFile << " for reading" << endl;
		return -1;
	}

	ifstream index( articleIndex );
	if ( !index.is_open() ) {
		cerr << "error: unable to open " << articleIndex <<  " for writing" << endl;
		return -1;
	}

	long long articleNum = atoll(article);
	index.seekg( articleNum * sizeof(long long) );

	long long start, end;
	index.read( (char*)&start, sizeof(long long) );
	index.read( (char*)&end, sizeof(long long) );

	long long len = end - start;
	char *buf = new char[len];
	dump.seekg( start-5 );
	dump.read( buf, len );

	char tn[2048];
	long ptn = 0;
	bool emit = false;

	char *p = buf, *pe = buf+len;
	int cs;

	%%{
		newline = '\n';
		sp = [ \t\n\r];

		name = [a-zA-Z:_0-9]+;

		# Tag names.
		tag_name = name
			>{ ptn = 0; }
			${ tn[ptn++] = *p; }
			%{ tn[ptn++] = 0; }
			;

		attr_name = name;

		# Attributes
		attr_val = '"' ( [^"\\] | newline | ( '\\' any ) )* '"';
		attr = attr_name '=' attr_val;
		attrs = ( sp attr )*;

		action maybe_open {
			if ( strcmp( tn, section ) == 0 )
				emit = true;
		}

		action maybe_close {
			if ( strcmp( tn, section ) == 0 )
				emit = false;
		}

		# Tags
		tag = '<' tag_name %maybe_open attrs sp? ( '>' | '/>' );
		close_tag = '</' tag_name %maybe_close '>';

		# Character data, not spaces and not tag starts.
		char_data_char = ^('<'|'&');
		char_data = char_data_char+
			${
				if ( emit )
					cout << *p;
			} ;

		defined_entities =
			'quot' %{if (emit) cout << '"';} |
			'amp' %{if (emit) cout << '&';} |
			'apos' %{if (emit) cout << '\'';} |
			'lt' %{if (emit) cout << '<';} |
			'gt' %{if (emit) cout << '>';};

		entity_ref = '&' defined_entities ';';

		main := (
				tag |
				close_tag |
				entity_ref |
				char_data
			)*
			;

		write init;
		write exec;
	}%%

	if ( cs < garticle_first_final ) {
		cerr << endl << endl << "garticle: error parsing dump file" << endl;
		return 1;
	}

	//cout.write( buf, len );
	cout << endl;

	return 0;
}


The proper align value is 'justify' not 'justified'

%%{

  machine superredcloth_common;

  action A { reg = p; }
  action T { STORE(text); }
  action X { regs = rb_hash_new(); reg = NULL; }
  action cat { CAT(block); }
  action esc { rb_str_cat_escaped(block, tokstart, tokend); }
  action esc_pre { rb_str_cat_escaped_for_preformatted(block, tokstart, tokend); }
  action ignore { rb_str_append(block, rb_funcall(rb_formatter, rb_intern("ignore"), 1, regs)); }

  # simple
  CRLF = ( '\r'? '\n' ) ;
  default = ^0 ;
  EOF = 0 ;

  # textile modifiers
  A_LEFT = "<" %{ ASET(align, left) } ;
  A_RIGHT = ">" %{ ASET(align, right) } ;
  A_JUSTIFIED = "<>" %{ ASET(align, justify) } ;
  A_CENTER = "=" %{ ASET(align, center) } ;
  A_PADLEFT = "(" >A %{ AINC(padding-left) } ;
  A_PADRIGHT = ")" >A %{ AINC(padding-right) } ;
  A_HLGN = ( A_LEFT | A_RIGHT | A_JUSTIFIED | A_CENTER | A_PADLEFT | A_PADRIGHT ) ;
  A_LIMIT = ( A_LEFT | A_CENTER | A_RIGHT ) ;
  A_VLGN = ( "-" %{ ASET(valign, middle) } | "^" %{ ASET(valign, top) } | "~" %{ ASET(valign, bottom) } ) ;
  C_CLAS = ( "(" ( [^)#]+ >A %{ STORE(class) } )? ("#" [^)]+ >A %{STORE(id)} )? ")" ) ;
  C_LNGE = ( "[" [^\]]+ >A %{ STORE(lang) } "]" ) ;
  C_STYL = ( "{" [^}]+ >A %{ STORE(style) } "}" ) ;
  S_CSPN = ( "\\" [0-9]+ >A %{ STORE(colspan) } ) ;
  S_RSPN = ( "/" [0-9]+ >A %{ STORE(rowspan) } ) ;
  D_HEADER = "_" %{ ASET(th, true) } ;
  A = ( ( A_HLGN | A_VLGN )* ) ;
  A2 = ( A_LIMIT? ) ;
  S = ( S_CSPN | S_RSPN )* ;
  C = ( C_CLAS | C_STYL | C_LNGE )* ;
  D = ( D_HEADER ) ;
  N_CONT = "_" %{ ASET(start, continue) };
  N_NUM = digit+ >A %{ STORE(start) };
  N = ( N_CONT | N_NUM )? ;
  PUNCT = ( "!" | '"' | "#" | "$" | "%" | "&" | "'" | "," | "--" | "." | "/" | ":" | ";" | "=" | "?" | "\\" | "^" | "`" | "|" | "~" | "[" | "(" | "<" ) ;
  dotspace = ("." " "*) ;
  indent =  [ \t]* ;

  # text blocks
  trailing = PUNCT - ("'" | '"') ;
  chars = (default - space)+ ;
  phrase = chars -- trailing ;

  # html tags (from Hpricot)
  NameChar = [\-A-Za-z0-9._:?] ;
  Name = [A-Za-z_:] NameChar* ;
  NameAttr = NameChar+ ;
  Q1Attr = [^']* ;
  Q2Attr = [^"]* ;
  UnqAttr = ( space | [^ \t\r\n<>"'] [^ \t\r\n<>]* ) ;
  Nmtoken = NameChar+ ;
  Attr =  NameAttr space* "=" space* ('"' Q2Attr '"' | "'" Q1Attr "'" | UnqAttr space+ ) space* ;
  AttrEnd = ( NameAttr space* "=" space* UnqAttr? | Nmtoken ) ;
  AttrSet = ( Attr | Nmtoken space+ ) ;
  start_tag = "<" Name space+ AttrSet* (AttrEnd)? ">" | "<" Name ">";
  empty_tag = "<" Name space+ AttrSet* (AttrEnd)? "/>" | "<" Name "/>" ;
  end_tag = "</" Name space* ">" ;
  html_comment = "<!--" (default+) :> "-->";

}%%;

%%{

  machine superredcloth_common;

  action A { reg = p; }
  action T { STORE(text); }
  action X { regs = rb_hash_new(); reg = NULL; }
  action cat { CAT(block); }
  action esc { rb_str_cat_escaped(block, tokstart, tokend); }
  action esc_pre { rb_str_cat_escaped_for_preformatted(block, tokstart, tokend); }
  action ignore { rb_str_append(block, rb_funcall(rb_formatter, rb_intern("ignore"), 1, regs)); }

  # simple
  CRLF = ( '\r'? '\n' ) ;
  default = ^0 ;
  EOF = 0 ;

  # textile modifiers
  A_LEFT = "<" %{ ASET(align, left) } ;
  A_RIGHT = ">" %{ ASET(align, right) } ;
  A_JUSTIFIED = "<>" %{ ASET(align, justified) } ;
  A_CENTER = "=" %{ ASET(align, center) } ;
  A_PADLEFT = "(" >A %{ AINC(padding-left) } ;
  A_PADRIGHT = ")" >A %{ AINC(padding-right) } ;
  A_HLGN = ( A_LEFT | A_RIGHT | A_JUSTIFIED | A_CENTER | A_PADLEFT | A_PADRIGHT ) ;
  A_LIMIT = ( A_LEFT | A_CENTER | A_RIGHT ) ;
  A_VLGN = ( "-" %{ ASET(valign, middle) } | "^" %{ ASET(valign, top) } | "~" %{ ASET(valign, bottom) } ) ;
  C_CLAS = ( "(" ( [^)#]+ >A %{ STORE(class) } )? ("#" [^)]+ >A %{STORE(id)} )? ")" ) ;
  C_LNGE = ( "[" [^\]]+ >A %{ STORE(lang) } "]" ) ;
  C_STYL = ( "{" [^}]+ >A %{ STORE(style) } "}" ) ;
  S_CSPN = ( "\\" [0-9]+ >A %{ STORE(colspan) } ) ;
  S_RSPN = ( "/" [0-9]+ >A %{ STORE(rowspan) } ) ;
  D_HEADER = "_" %{ ASET(th, true) } ;
  A = ( ( A_HLGN | A_VLGN )* ) ;
  A2 = ( A_LIMIT? ) ;
  S = ( S_CSPN | S_RSPN )* ;
  C = ( C_CLAS | C_STYL | C_LNGE )* ;
  D = ( D_HEADER ) ;
  N_CONT = "_" %{ ASET(start, continue) };
  N_NUM = digit+ >A %{ STORE(start) };
  N = ( N_CONT | N_NUM )? ;
  PUNCT = ( "!" | '"' | "#" | "$" | "%" | "&" | "'" | "," | "--" | "." | "/" | ":" | ";" | "=" | "?" | "\\" | "^" | "`" | "|" | "~" | "[" | "(" | "<" ) ;
  dotspace = ("." " "*) ;
  indent =  [ \t]* ;

  # text blocks
  trailing = PUNCT - ("'" | '"') ;
  chars = (default - space)+ ;
  phrase = chars -- trailing ;

  # html tags (from Hpricot)
  NameChar = [\-A-Za-z0-9._:?] ;
  Name = [A-Za-z_:] NameChar* ;
  NameAttr = NameChar+ ;
  Q1Attr = [^']* ;
  Q2Attr = [^"]* ;
  UnqAttr = ( space | [^ \t\r\n<>"'] [^ \t\r\n<>]* ) ;
  Nmtoken = NameChar+ ;
  Attr =  NameAttr space* "=" space* ('"' Q2Attr '"' | "'" Q1Attr "'" | UnqAttr space+ ) space* ;
  AttrEnd = ( NameAttr space* "=" space* UnqAttr? | Nmtoken ) ;
  AttrSet = ( Attr | Nmtoken space+ ) ;
  start_tag = "<" Name space+ AttrSet* (AttrEnd)? ">" | "<" Name ">";
  empty_tag = "<" Name space+ AttrSet* (AttrEnd)? "/>" | "<" Name "/>" ;
  end_tag = "</" Name space* ">" ;
  html_comment = "<!--" (default+) :> "-->";

}%%;


Fixes invalid variable reference

Fixes invalid variable reference

%%{

  machine lexer;

  variable data @data;
  variable p    @p;
  variable pe   @pe;
  variable eof  @eof;
  access @;

  number_integer = '-'? [0-9][1-9]*;
  number_frac = '.' [0-9]+;
  number_e = ('e' | 'E') ('+' | '-' | '');
  number_exp = number_e [0-9]+;
  number = number_integer number_frac? number_exp?;

  string_double = '"' ( any -- '"' | '\\"' )* '"';
  identifier = [A-Za-z_$][A-Za-z0-9_$]*;
  string_single = "'" [A-Za-z0-9_$\-]+;

  main := |*
    number        => { emit :number      };
    string_double => { emit :dstring     };
    string_single => { emit :sstring     };
    identifier    => { emit :identifier  };
    '->'          => { emit :arrow       };
    '='           => { emit :equal       };
    '{'           => { emit :lbrack      };
    '('           => { emit :lparen      };
    '['           => { emit :lbrace      };
    '}'           => { emit :rbrack      };
    ')'           => { emit :rparen      };
    ']'           => { emit :rbrace      };
    ':'           => { emit :colon       };
    ','           => { emit :comma       };
    space         => {                   };
    any           => { error             };
  *|;
}%%

module Liquidscript
  class Scanner

    class Lexer

      attr_reader :tokens

      def initialize
        %% write data;
        # %% # fix
        @tokens = []
      end

      def clean!
        @p = nil
        @pe = nil
        @te = nil
        @ts = nil
        @act = nil
        @eof = nil
        @top = nil
        @data = nil
        @stack = nil
      end

      def emit(type)
        @tokens << Token.new(type, @data[@ts..(@te - 1)])
      end

      def error
        raise SyntaxError, "Unexpected #{@data[@ts..(@te-1)].pack('c*')}"
      end

      def perform(data)
        @data = data.unpack("c*") if data.is_a? String
        @eof = data.length

        @tokens = []

        %% write init;
        %% write exec;

        clean!

        @tokens
      end
    end
  end
end

%%{

  machine lexer;

  variable data @data;
  variable p    @p;
  variable pe   @pe;
  variable eof  @eof;
  access @;

  number_integer = '-'? [0-9][1-9]*;
  number_frac = '.' [0-9]+;
  number_e = ('e' | 'E') ('+' | '-' | '');
  number_exp = number_e [0-9]+;
  number = number_integer number_frac? number_exp?;

  string_double = '"' ( any -- '"' | '\\"' )* '"';
  identifier = [A-Za-z_$][A-Za-z0-9_$]*;
  string_single = "'" [A-Za-z0-9_$\-]+;

  main := |*
    number        => { emit :number      };
    string_double => { emit :dstring     };
    string_single => { emit :sstring     };
    identifier    => { emit :identifier  };
    '->'          => { emit :arrow       };
    '='           => { emit :equal       };
    '{'           => { emit :lbrack      };
    '('           => { emit :lparen      };
    '['           => { emit :lbrace      };
    '}'           => { emit :rbrack      };
    ')'           => { emit :rparen      };
    ']'           => { emit :rbrace      };
    ':'           => { emit :colon       };
    ','           => { emit :comma       };
    space         => {                   };
    any           => { error             };
  *|;
}%%

module Liquidscript
  class Scanner

    class Lexer

      attr_reader :tokens

      def initialize
        %% write data;
        # %% # fix
        @tokens = []
      end

      def clean!
        @p = nil
        @pe = nil
        @te = nil
        @ts = nil
        @act = nil
        @eof = nil
        @top = nil
        @data = nil
        @stack = nil
      end

      def emit(type)
        @tokens << Token.new(type, @data[@ts..(@te - 1)])
      end

      def error
        raise SyntaxError, "Unexpected #{@data[ts..(te-1)].pack('c*')}"
      end

      def perform(data)
        @data = data.unpack("c*") if data.is_a? String
        @eof = data.length

        @tokens = []

        %% write init;
        %% write exec;

        clean!

        @tokens
      end
    end
  end
end


simplify

simplify

%%{
  machine params_parser;
  action H { @head = p }
  action T { @tail = p }
  action inject_key { @hash[key] = {} }
  action push { @hash_stack.push @hash; @hash = @hash[key] }
  action pop { @hash = @hash_stack.pop }

  DELIMITER = ','                                   >H@T @{ log(:delimiter) };
  LEVEL = '('+                                      >H@T @{ log(:level) };
  END_LEVEL = ')'+                                  >H@T @{ log(:end_level); };
  INPUT = (any - LEVEL - END_LEVEL - DELIMITER)+    >H@T @{ log(:input); memo_key; };

  main := (
    INPUT
    (
      DELIMITER @inject_key @{ fnext main; } |
      END_LEVEL DELIMITER? @inject_key @pop @{ fret; } |
      LEVEL @inject_key @push @{ fcall main; }
    )
  )*;
}%%

module ParamsTree
  class Parser
    attr_accessor :data

    def initialize
      %% write data;
    end

    def process(input)
      @data = input.unpack('c*')
      stack = []

      @log = []
      @hash = {}
      @hash_stack = []
      @key = nil

      %% write init;
      %% write exec;

      #@hash.inspect
      #@hash_stack.inspect
      @hash_stack.first
    end

    def char
      @data[@head..@tail]
    end

    def strokes
      char.pack('c*')
    end

    def log(token)
      @log << { token => strokes }
    end

    def memo_key
      @key = char
    end

    def key
      @key.pack('c*')
    end
  end
end

s = "default(all,usadasdid(zczxc(pio(xqwe)),cvb)),isdsdd(wow,er),sed(rew,tre,yrt(dfg,gfd))"
puts s
puts ParamsTree::Parser.new.process s

%%{
  machine params_parser;
  action H { @head = p }
  action T { @tail = p }
  action inject_key { @hash[key] = {} }
  action push { @hash_stack.push @hash; @hash = @hash[key] }
  action pop { @hash = @hash_stack.pop }

  DELIMITER = ([, ])                                >H@T @{ log(:delimiter) };
  LEVEL = ('(')+                                    >H@T @{ log(:level) };
  END_LEVEL = (')')+                                >H@T @{ log(:end_level); };
  INPUT = (any - LEVEL - END_LEVEL - DELIMITER)+    >H@T @{ log(:input); memo_key; };

  main := (
    INPUT
    (
      DELIMITER @inject_key @{ fnext main; } |
      END_LEVEL DELIMITER? @inject_key @pop @{ fret; } |
      LEVEL @inject_key @push @{ fcall main; }
    )
  )*;
}%%

module ParamsTree
  class Parser
    attr_accessor :data

    def initialize
      %% write data;
    end

    def process(input)
      @data = input.unpack('c*')
      stack = []

      @log = []
      @hash = {}
      @hash_stack = []
      @key = nil

      %% write init;
      %% write exec;

      #@hash.inspect
      #@hash_stack.inspect
      @hash_stack.first
    end

    def char
      @data[@head..@tail]
    end

    def strokes
      char.pack('c*')
    end

    def log(token)
      @log << { token => strokes }
    end

    def memo_key
      @key = char
    end

    def key
      @key.pack('c*')
    end
  end
end

s = "default(all,usadasdid(zczxc(pio(xqwe)),cvb)),isdsdd(wow,er),sed(rew,tre,yrt(dfg,gfd))"
puts s
puts ParamsTree::Parser.new.process s


Updated Rapa source to 36f91258.

Updated Rapa source to 36f91258.

// vim: filetype=ragel

%%{

  machine unpack;

  action start {
    count = 1;
    rest = false;
    platform = false;
  }

  action start_digit {
    count = fc - '0';
  }

  action count {
    count = count * 10 + (fc - '0');
  }

  action rest {
    count = 0;
    rest = true;
  }

  action zero_count {
    count = 0;
  }

  action platform {
    platform = true;
  }

  action byte_width {
    width = 1;
  }

  action short_width {
    width = 2;
  }

  action int_width {
    width = 4;
  }

  action long_width {
    width = 8;
  }

  action platform_width {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      width = 4;
#else
      width = 8;
#endif
    } else {
      width = 4;
    }
  }

  action set_stop {
    if(!rest) {
      stop = index + width * count;
    }

    if(rest || stop > bytes_size) {
      stop = index + ((bytes_size - index) / width) * width;
    }
  }

  action extra {
    for(; count > 0; count--) {
      array->append(state, Qnil);
    }
  }

  # Integers

  action C {
    unpack_integer(ubyte);
  }

  action c {
    unpack_integer(sbyte);
  }

  action S {
    unpack_integer(u2bytes);
  }

  action s {
    unpack_integer(s2bytes);
  }

  action I {
    unpack_integer(u4bytes);
  }

  action i {
    unpack_integer(s4bytes);
  }

  action L {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      unpack_integer(u4bytes);
#else
      unpack_integer(u8bytes);
#endif
    } else {
      unpack_integer(u4bytes);
    }
  }

  action l {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      unpack_integer(s4bytes);
#else
      unpack_integer(s8bytes);
#endif
    } else {
      unpack_integer(s4bytes);
    }
  }

  action N {
    unpack_integer(u4bytes_be);
  }

  action n {
    unpack_integer(u2bytes_be);
  }

  action V {
    unpack_integer(u4bytes_le);
  }

  action v {
    unpack_integer(u2bytes_le);
  }

  action Q {
    unpack_integer(u8bytes);
  }

  action q {
    unpack_integer(s8bytes);
  }

  # Floats

  action D {
    unpack_double;
  }

  action E {
    unpack_double_le;
  }

  action e {
    unpack_float_le;
  }

  action F {
    unpack_float;
  }

  action G {
    unpack_double_be;
  }

  action g {
    unpack_float_be;
  }

  # Moves

  action X {
    if(rest) count = bytes_size - index;
    index -= count;
  }

  action x {
    if(rest) {
      index = bytes_size;
    } else {
      index += count;
    }
  }

  action at {
    if(!rest) {
      index = count;
    }
  }

  action check_bounds {
    if(index < 0 || index > bytes_size) {
      std::ostringstream msg;
      msg << *p << " outside of string";
      Exception::argument_error(state, msg.str().c_str());
    }
  }

  # String / Encoding helpers

  action bytes {
    bytes = (const char*)self->byte_address() + index;
  }

  action bytes_end {
    bytes_end = (const char*)self->byte_address() + bytes_size;
  }

  action string_width {
    width = 1;
  }

  action bit_width {
    width = 8;
  }

  action hex_width {
    width = 2;
  }

  action remainder {
    remainder = bytes_size - index;
  }

  action rest_count {
    if(rest) {
      count = remainder;
    } else if(count > remainder) {
      count = remainder;
    }
  }

  action string_size {
    if(rest || count > remainder * width) {
      count = remainder * width;
    }
  }

  # Strings

  action A {
    String* string;

    if(count > 0) {
      native_int i;
      for(i = count; i > 0; i--) {
        uint8_t c = bytes[i-1];
        if(c != ' ' && c != '\0')
          break;
      }
      string = String::create(state, bytes, i);
    } else {
      string = String::create(state, "");
    }

    array->append(state, string);
    unpack::increment(index, count, bytes_size);
  }

  action a {
    array->append(state, String::create(state, bytes, count));

    unpack::increment(index, count, bytes_size);
  }

  action Z {
    native_int c;
    for(c = 0; c < count; c++) {
      if(bytes[c] == '\0') break;
    }
    array->append(state, String::create(state, bytes, c));

    if(rest) {
      unpack::increment(index, c < count ? c + 1 : count, bytes_size);
    } else {
      unpack::increment(index, count, bytes_size);
    }
  }

  # Encodings

  action index_increment {
    unpack::increment(index,
                      bytes - ((const char*)self->byte_address() + index),
                      bytes_size);
  }

  action B {
    array->append(state, unpack::bit_high(state, bytes, count));
  }

  action b {
    array->append(state, unpack::bit_low(state, bytes, count));
  }

  action H {
    array->append(state, unpack::hex_high(state, bytes, count));
  }

  action h {
    array->append(state, unpack::hex_low(state, bytes, count));
  }

  action M {
    array->append(state, unpack::quotable_printable(state, bytes, bytes_end, remainder));
  }

  action m {
    array->append(state, unpack::base64_decode(state, bytes, bytes_end, remainder));
  }

  action U {
    unpack::utf8_decode(state, array, bytes, bytes_end, count, index);
  }

  action u {
    array->append(state, unpack::uu_decode(state, bytes, bytes_end, remainder));
  }

  action w {
    unpack::ber_decode(state, array, bytes, bytes_end, count, index);
    index = bytes - (const char*)self->byte_address();
  }

  action non_native_error {
    std::ostringstream msg;
    msg << "'" << *p << "' allowed only after types sSiIlL";
    Exception::argument_error(state, msg.str().c_str());
  }

  action done {
    return array;
  }
}%%

// vim: filetype=ragel

%%{

  machine unpack;

  action start {
    count = 1;
    rest = false;
    platform = false;
  }

  action start_digit {
    count = fc - '0';
  }

  action count {
    count = count * 10 + (fc - '0');
  }

  action rest {
    count = 0;
    rest = true;
  }

  action zero_count {
    count = 0;
  }

  action platform {
    platform = true;
  }

  action byte_width {
    width = 1;
  }

  action short_width {
    width = 2;
  }

  action int_width {
    width = 4;
  }

  action long_width {
    width = 8;
  }

  action platform_width {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      width = 4;
#else
      width = 8;
#endif
    } else {
      width = 4;
    }
  }

  action set_stop {
    stop = rest ? bytes_size + 1 : index + width * count;
    if(stop > bytes_size) {
      stop = index + ((bytes_size - index) / width) * width;
    }
  }

  action extra {
    for(; count > 0; count--) {
      array->append(state, Qnil);
    }
  }

  # Integers

  action C {
    unpack_integer(ubyte);
  }

  action c {
    unpack_integer(sbyte);
  }

  action S {
    unpack_integer(u2bytes);
  }

  action s {
    unpack_integer(s2bytes);
  }

  action I {
    unpack_integer(u4bytes);
  }

  action i {
    unpack_integer(s4bytes);
  }

  action L {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      unpack_integer(u4bytes);
#else
      unpack_integer(u8bytes);
#endif
    } else {
      unpack_integer(u4bytes);
    }
  }

  action l {
    if(platform) {
#if RBX_SIZEOF_LONG == 4
      unpack_integer(s4bytes);
#else
      unpack_integer(s8bytes);
#endif
    } else {
      unpack_integer(s4bytes);
    }
  }

  action N {
    unpack_integer(u4bytes_be);
  }

  action n {
    unpack_integer(u2bytes_be);
  }

  action V {
    unpack_integer(u4bytes_le);
  }

  action v {
    unpack_integer(u2bytes_le);
  }

  action Q {
    unpack_integer(u8bytes);
  }

  action q {
    unpack_integer(s8bytes);
  }

  # Floats

  action D {
    unpack_double;
  }

  action E {
    unpack_double_le;
  }

  action e {
    unpack_float_le;
  }

  action F {
    unpack_float;
  }

  action G {
    unpack_double_be;
  }

  action g {
    unpack_float_be;
  }

  # Moves

  action X {
    if(rest) count = bytes_size - index;
    index -= count;
  }

  action x {
    if(rest) {
      index = bytes_size;
    } else {
      index += count;
    }
  }

  action at {
    if(!rest) {
      index = count;
    }
  }

  action check_bounds {
    if(index < 0 || index > bytes_size) {
      std::ostringstream msg;
      msg << *p << " outside of string";
      Exception::argument_error(state, msg.str().c_str());
    }
  }

  # String / Encoding helpers

  action bytes {
    bytes = (const char*)self->byte_address() + index;
  }

  action bytes_end {
    bytes_end = (const char*)self->byte_address() + bytes_size;
  }

  action string_width {
    width = 1;
  }

  action bit_width {
    width = 8;
  }

  action hex_width {
    width = 2;
  }

  action remainder {
    remainder = bytes_size - index;
  }

  action rest_count {
    if(rest) {
      count = remainder;
    } else if(count > remainder) {
      count = remainder;
    }
  }

  action string_size {
    if(rest || count > remainder * width) {
      count = remainder * width;
    }
  }

  # Strings

  action A {
    String* string;

    if(count > 0) {
      native_int i;
      for(i = count; i > 0; i--) {
        uint8_t c = bytes[i-1];
        if(c != ' ' && c != '\0')
          break;
      }
      string = String::create(state, bytes, i);
    } else {
      string = String::create(state, "");
    }

    array->append(state, string);
    unpack::increment(index, count, bytes_size);
  }

  action a {
    array->append(state, String::create(state, bytes, count));

    unpack::increment(index, count, bytes_size);
  }

  action Z {
    native_int c;
    for(c = 0; c < count; c++) {
      if(bytes[c] == '\0') break;
    }
    array->append(state, String::create(state, bytes, c));

    if(rest) {
      unpack::increment(index, c < count ? c + 1 : count, bytes_size);
    } else {
      unpack::increment(index, count, bytes_size);
    }
  }

  # Encodings

  action index_increment {
    unpack::increment(index,
                      bytes - ((const char*)self->byte_address() + index),
                      bytes_size);
  }

  action B {
    array->append(state, unpack::bit_high(state, bytes, count));
  }

  action b {
    array->append(state, unpack::bit_low(state, bytes, count));
  }

  action H {
    array->append(state, unpack::hex_high(state, bytes, count));
  }

  action h {
    array->append(state, unpack::hex_low(state, bytes, count));
  }

  action M {
    array->append(state, unpack::quotable_printable(state, bytes, bytes_end, remainder));
  }

  action m {
    array->append(state, unpack::base64_decode(state, bytes, bytes_end, remainder));
  }

  action U {
    unpack::utf8_decode(state, array, bytes, bytes_end, count, index);
  }

  action u {
    array->append(state, unpack::uu_decode(state, bytes, bytes_end, remainder));
  }

  action w {
    unpack::ber_decode(state, array, bytes, bytes_end, count, index);
    index = bytes - (const char*)self->byte_address();
  }

  action non_native_error {
    std::ostringstream msg;
    msg << "'" << *p << "' allowed only after types sSiIlL";
    Exception::argument_error(state, msg.str().c_str());
  }

  action done {
    return array;
  }
}%%


Check for final state of correct state machine.

package inet.data.dns;

public class DNSDomainParser {

public static final int MAX_DOMAIN_LENGTH = 255;
public static final int MAX_LABEL_LENGTH = 63;

%% machine domain;
%% write data;

public static boolean
isValid(byte[] data) {
    if (data.length > MAX_DOMAIN_LENGTH)
        return false;

    int lablen = 0;

    int cs = 0;
    int p = 0;
    int pe = data.length;
    int eof = pe;

    %%{
        action beg_label { lablen = ((int) fc) & 0xff; }
        action in_label { (lablen-- > 0) }
        action not_in_label { (lablen <= 0) }

        lablen = 1..63 $beg_label;
        content = ( any when in_label )+;
        terminal = '' when not_in_label;
        label = lablen content <: terminal;
        domain = label+;

        main := domain;

        alphtype byte;
    }%%

    %% write init;
    %% write exec;

    if (cs < domain_first_final || lablen > 0)
        return false;
    return true;
}

%% machine hostname;
%% write data;

public static boolean
isValidHostname(byte[] data, int length, boolean underscores) {
    if (length > MAX_DOMAIN_LENGTH)
        return false;

    int lablen = 0;
    boolean letter = false;

    int cs = 0;
    int p = 0;
    int pe = length;
    int eof = pe;

    %%{
        action beg_label { lablen = ((int) fc) & 0xff; }
        action in_label { (lablen-- > 0) }
        action not_in_label { (lablen <= 0) }
        action underscores { underscores }
        action letter { letter = true; }

        lablen = 1..63 $beg_label;
        let = ( alpha when in_label ) $letter;
        dig = digit when in_label;
        let_dig = let | dig;
        hyp = ( "-" | "_" when underscores ) when in_label;
        let_dig_hyp = let_dig | hyp;
        ldh_str = let_dig_hyp+;
        content = let_dig (ldh_str? let_dig)?;
        terminal = '' when not_in_label;
        label = lablen content <: terminal;
        domain = label+;

        main := domain;

        alphtype byte;
    }%%

    %% write init;
    %% write exec;

    if (cs < hostname_first_final || lablen > 0 || !letter)
        return false;
    return true;
}

}

package inet.data.dns;

public class DNSDomainParser {

public static final int MAX_DOMAIN_LENGTH = 255;
public static final int MAX_LABEL_LENGTH = 63;

%% machine domain;
%% write data;

public static boolean
isValid(byte[] data) {
    if (data.length > MAX_DOMAIN_LENGTH)
        return false;

    int lablen = 0;

    int cs = 0;
    int p = 0;
    int pe = data.length;
    int eof = pe;

    %%{
        action beg_label { lablen = ((int) fc) & 0xff; }
        action in_label { (lablen-- > 0) }
        action not_in_label { (lablen <= 0) }

        lablen = 1..63 $beg_label;
        content = ( any when in_label )+;
        terminal = '' when not_in_label;
        label = lablen content <: terminal;
        domain = label+;

        main := domain;

        alphtype byte;
    }%%

    %% write init;
    %% write exec;

    if (cs < domain_first_final || lablen > 0)
        return false;
    return true;
}

%% machine hostname;
%% write data;

public static boolean
isValidHostname(byte[] data, int length, boolean underscores) {
    if (length > MAX_DOMAIN_LENGTH)
        return false;

    int lablen = 0;
    boolean letter = false;

    int cs = 0;
    int p = 0;
    int pe = length;
    int eof = pe;

    %%{
        action beg_label { lablen = ((int) fc) & 0xff; }
        action in_label { (lablen-- > 0) }
        action not_in_label { (lablen <= 0) }
        action underscores { underscores }
        action letter { letter = true; }

        lablen = 1..63 $beg_label;
        let = ( alpha when in_label ) $letter;
        dig = digit when in_label;
        let_dig = let | dig;
        hyp = ( "-" | "_" when underscores ) when in_label;
        let_dig_hyp = let_dig | hyp;
        ldh_str = let_dig_hyp+;
        content = let_dig (ldh_str? let_dig)?;
        terminal = '' when not_in_label;
        label = lablen content <: terminal;
        domain = label+;

        main := domain;

        alphtype byte;
    }%%

    %% write init;
    %% write exec;

    if (cs < domain_first_final || lablen > 0 || !letter)
        return false;
    return true;
}

}