# Parse a Steuermann Spec file # # This is an exyapps grammer in specfile.exy import nodes %% parser specfile: ignore: "[ \r\t\n]+" ignore: "#.*\n" token END: "$" token HOSTGROUP: "HOSTGROUP" token IF: "IF" token IFNOT: "IFNOT" token TABLE: "TABLE" token HOST : "HOST" token CMD: "CMD" token OPT: "OPT" token AFTER: "AFTER" token RUN: "RUN" token LOCAL: "LOCAL" token IMPORT: "IMPORT" token DEBUG: "DEBUG" token name: "[a-zA-Z0-9_.-]+" token STAR: "\*" token cmdname: "[a-zA-Z0-9_.-]+" token tablename: "[a-zA-Z0-9_.-]+" token wildname: "[@]{0,1}[*?a-zA-Z0-9_.-]+" token string: '"[^"]*"' token SLASH: "/" token COLON: ":" token hostgroup: "@[a-zA-Z0-9_.-]+" # watch carefully: none of the keywords are "END" on a line by themselves token CONDITIONS: 'CONDITIONS[^"]*\n[\s]*END[ \t]*\n' rule start: table_list END {{ return table_list }} rule table_list: table_section + rule table_section: DEBUG string {{ print "-->debug: %s"%string }} | hostgroup_def | CONDITIONS {{ nodes.declare_conditions( CONDITIONS, self._scanner.filename ) }} | TABLE tablename {{ table_name = tablename }} HOST {{ hostlist = [ ] }} ( name {{ hostlist.append(name) }} | hostgroup {{ hostlist = hostlist + nodes.get_hostgroup( hostgroup ) }} )+ command_cond<> + | IMPORT string {{ self.data.import_list.append( string[1:-1] ) }} ## rule hostgroup_def : HOSTGROUP hostgroup {{ nodes.define_hostgroup( hostgroup) }} ( hostgroup_front<> hostgroup_back<> )+ rule hostgroup_front<> : IF name {{ return nodes.check_condition(name, self._scanner.filename ) }} | IFNOT name {{ return not nodes.check_condition(name, self._scanner.filename ) }} | {{ return True }} rule hostgroup_back<> : COLON ( name {{ if accept_nodes : nodes.add_hostgroup( hg, name ) }} | hostgroup {{ if accept_nodes : nodes.add_hostgroup( hg, hostgroup ) }} )* rule command_cond<> : IF name COLON command {{ if nodes.check_condition(name, self._scanner.filename ) : self.data.add_command_list( table_name, hostlist, [ command ] ) }} | IFNOT name COLON command {{ if not nodes.check_condition(name, self._scanner.filename ) : self.data.add_command_list( table_name, hostlist, [ command ] ) }} | command {{ self.data.add_command_list( table_name, hostlist, [ command ] ) }} rule command: # a single command, including any number of AFTER clauses CMD {{ cmd_pos = self._scanner.get_pos() }} cmdname {{ cmd_name=cmdname; script=cmdname; x_after_clause = [ ] }} [ RUN string {{ script = string[1:-1]; script_type='r' }} | LOCAL string {{ script = string[1:-1]; script_type='l' }} ] ( {{ after_pos = self._scanner.get_pos() }} AFTER optword after_spec {{ x_after_clause.append( (after_spec, optword, after_pos) ) }} )* {{ return ( cmd_name, script, script_type, x_after_clause, cmd_pos ) }} # in the AFTER clause, you can say OPT to mean the node is optional (not an error if it does not exist) rule optword: OPT {{ return 0 }} | {{ return 1 }} rule after_spec: wildname {{ rval = wildname }} [ COLON wildname {{ rval = rval + ':' + wildname }} ] [ SLASH wildname {{ rval = rval + '/' + wildname }} ] {{ return rval }} %%