<autotree>

gr_taskfile: gr_block(s) /^\Z/ { $return = $item[1] }

gr_block: gr_defineblock  { $return = $item[1] }
	| gr_taskblock { $return = $item[1] }
        | <error>

gr_defineblock: gr_globalfields

gr_globalfields: 'global' gr_fielddeclarations

gr_taskblock: gr_taskname '{' <commit> gr_localfields(?) gr_out gr_in(?) gr_do(s) '}'
	    | <error>

gr_localfields: 'fields' gr_fielddeclarations

gr_out: 'out' '{' gr_ofilespec(s) '}'

gr_in: 'in' '{' gr_ifilespec(s) '}'

gr_do: 'do' gr_interpreter gr_code

gr_ofilespec: gr_fileid '{' gr_quotedstring gr_identifier(s?) '}'
	    | <error>

gr_ifilespec: gr_fileid '{' gr_quotedstring gr_identifier(s?) '}'
	    | <error>

gr_quotedstring: '"' <commit> /[^"]+/ '"' { $return = $item[3]; }
               | "'" <commit> /[^']+/ "'" { $return = $item[3]; }

gr_fielddeclarations: '{' gr_fielddec(s /;/) gr_code(?) '}'

gr_fielddec: gr_fieldname gr_regexstring(?)

gr_code: '%{' /.+ (?! %} | }% )/ ( '%}' | '}%' ) { $return = $item[2]; }

gr_regexstring: '/' <commit> /[^\/]+/ '/' { $return = $item[3]; }
	      | 'm[' <commit> /[^]]+/ "]" { $return = $item[3]; }
              | 'm(' <commit> /[^)]+/ ")" { $return = $item[3]; }
              | 'm<' <commit> /[^?]+/ ">" { $return = $item[3]; }

gr_taskname:    gr_identifier { $return = $item[1]; }
gr_fileid:      gr_identifier { $return = $item[1]; }
gr_fieldname:   gr_identifier { $return = $item[1]; }
gr_interpreter: gr_identifier { $return = $item[1]; }

gr_identifier: /[A-Za-z_]\w*/ { $return = $item[1]; }
