Changes in tools/config.py [a35b458:aca97582] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tools/config.py
ra35b458 raca97582 42 42 import random 43 43 44 RULES_FILE = sys.argv[1] 44 ARGPOS_RULES = 1 45 ARGPOS_CHOICE = 2 46 ARGPOS_PRESET = 3 47 48 RULES_FILE = sys.argv[ARGPOS_RULES] 45 49 MAKEFILE = 'Makefile.config' 46 50 MACROS = 'config.h' 47 51 PRESETS_DIR = 'defaults' 52 53 class BinaryOp: 54 def __init__(self, operator, left, right): 55 assert operator in ('&', '|', '=', '!=') 56 57 self._operator = operator 58 self._left = left 59 self._right = right 60 61 def evaluate(self, config): 62 if self._operator == '&': 63 return self._left.evaluate(config) and \ 64 self._right.evaluate(config) 65 if self._operator == '|': 66 return self._left.evaluate(config) or \ 67 self._right.evaluate(config) 68 69 # '=' or '!=' 70 if not self._left in config: 71 config_val = '' 72 else: 73 config_val = config[self._left] 74 if config_val == '*': 75 config_val = 'y' 76 77 if self._operator == '=': 78 return self._right == config_val 79 return self._right != config_val 80 81 # Expression parser 82 class CondParser: 83 TOKEN_EOE = 0 84 TOKEN_SPECIAL = 1 85 TOKEN_STRING = 2 86 87 def __init__(self, text): 88 self._text = text 89 90 def parse(self): 91 self._position = -1 92 self._next_char() 93 self._next_token() 94 95 res = self._parse_expr() 96 if self._token_type != self.TOKEN_EOE: 97 self._error("Expected end of expression") 98 return res 99 100 def _next_char(self): 101 self._position += 1 102 if self._position >= len(self._text): 103 self._char = None 104 else: 105 self._char = self._text[self._position] 106 self._is_special_char = self._char in \ 107 ('&', '|', '=', '!', '(', ')') 108 109 def _error(self, msg): 110 raise RuntimeError("Error parsing expression: %s:\n%s\n%s^" % 111 (msg, self._text, " " * self._token_position)) 112 113 def _next_token(self): 114 self._token_position = self._position 115 116 # End of expression 117 if self._char == None: 118 self._token = None 119 self._token_type = self.TOKEN_EOE 120 return 121 122 # '&', '|', '=', '!=', '(', ')' 123 if self._is_special_char: 124 self._token = self._char 125 self._next_char() 126 if self._token == '!': 127 if self._char != '=': 128 self._error("Expected '='") 129 self._token += self._char 130 self._next_char() 131 self._token_type = self.TOKEN_SPECIAL 132 return 133 134 # <var> or <val> 135 self._token = '' 136 self._token_type = self.TOKEN_STRING 137 while True: 138 self._token += self._char 139 self._next_char() 140 if self._is_special_char or self._char == None: 141 break 142 143 def _parse_expr(self): 144 """ <expr> ::= <or_expr> ('&' <or_expr>)* """ 145 146 left = self._parse_or_expr() 147 while self._token == '&': 148 self._next_token() 149 left = BinaryOp('&', left, self._parse_or_expr()) 150 return left 151 152 def _parse_or_expr(self): 153 """ <or_expr> ::= <factor> ('|' <factor>)* """ 154 155 left = self._parse_factor() 156 while self._token == '|': 157 self._next_token() 158 left = BinaryOp('|', left, self._parse_factor()) 159 return left 160 161 def _parse_factor(self): 162 """ <factor> ::= <var> <cond> | '(' <expr> ')' """ 163 164 if self._token == '(': 165 self._next_token() 166 res = self._parse_expr() 167 if self._token != ')': 168 self._error("Expected ')'") 169 self._next_token() 170 return res 171 172 if self._token_type == self.TOKEN_STRING: 173 var = self._token 174 self._next_token() 175 return self._parse_cond(var) 176 177 self._error("Expected '(' or <var>") 178 179 def _parse_cond(self, var): 180 """ <cond> ::= '=' <val> | '!=' <val> """ 181 182 if self._token not in ('=', '!='): 183 self._error("Expected '=' or '!='") 184 185 oper = self._token 186 self._next_token() 187 188 if self._token_type != self.TOKEN_STRING: 189 self._error("Expected <val>") 190 191 val = self._token 192 self._next_token() 193 194 return BinaryOp(oper, var, val) 48 195 49 196 def read_config(fname, config): … … 59 206 inf.close() 60 207 61 def check_condition(text, config, rules):62 "Check that the condition specified on input line is True (only CNF and DNF is supported)"63 64 ctype = 'cnf'65 66 if (')|' in text) or ('|(' in text):67 ctype = 'dnf'68 69 if ctype == 'cnf':70 conds = text.split('&')71 else:72 conds = text.split('|')73 74 for cond in conds:75 if cond.startswith('(') and cond.endswith(')'):76 cond = cond[1:-1]77 78 inside = check_inside(cond, config, ctype)79 80 if (ctype == 'cnf') and (not inside):81 return False82 83 if (ctype == 'dnf') and inside:84 return True85 86 if ctype == 'cnf':87 return True88 89 return False90 91 def check_inside(text, config, ctype):92 "Check for condition"93 94 if ctype == 'cnf':95 conds = text.split('|')96 else:97 conds = text.split('&')98 99 for cond in conds:100 res = re.match(r'^(.*?)(!?=)(.*)$', cond)101 if not res:102 raise RuntimeError("Invalid condition: %s" % cond)103 104 condname = res.group(1)105 oper = res.group(2)106 condval = res.group(3)107 108 if not condname in config:109 varval = ''110 else:111 varval = config[condname]112 if (varval == '*'):113 varval = 'y'114 115 if ctype == 'cnf':116 if (oper == '=') and (condval == varval):117 return True118 119 if (oper == '!=') and (condval != varval):120 return True121 else:122 if (oper == '=') and (condval != varval):123 return False124 125 if (oper == '!=') and (condval == varval):126 return False127 128 if ctype == 'cnf':129 return False130 131 return True132 133 208 def parse_rules(fname, rules): 134 209 "Parse rules file" … … 149 224 150 225 cond = res.group(1) 226 if cond: 227 cond = CondParser(cond).parse() 151 228 varname = res.group(2) 152 229 vartype = res.group(3) … … 232 309 varname, vartype, name, choices, cond = rule 233 310 234 if cond and (not check_condition(cond, config, rules)):311 if cond and not cond.evaluate(config): 235 312 continue 236 313 … … 279 356 280 357 # First check that this rule would make sense 281 if cond: 282 if not check_condition(cond, config, rules): 283 return random_choices(config, rules, start_index + 1) 358 if cond and not cond.evaluate(config): 359 return random_choices(config, rules, start_index + 1) 284 360 285 361 # Remember previous choices for backtracking … … 487 563 488 564 for varname, vartype, name, choices, cond in rules: 489 if cond and (not check_condition(cond, config, rules)):565 if cond and not cond.evaluate(config): 490 566 continue 491 567 … … 514 590 outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix) 515 591 outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix) 516 defs += ' "-DTIMESTAMP_UNIX=%d" \n' % timestamp_unix592 defs += ' "-DTIMESTAMP_UNIX=%d"' % timestamp_unix 517 593 518 594 outmk.write('TIMESTAMP = %s\n' % timestamp) 519 595 outmc.write('#define TIMESTAMP %s\n' % timestamp) 520 defs += ' "-DTIMESTAMP=%s" \n' % timestamp521 522 outmk.write( defs)596 defs += ' "-DTIMESTAMP=%s"' % timestamp 597 598 outmk.write('%s\n' % defs) 523 599 524 600 outmk.close() … … 604 680 parse_rules(RULES_FILE, rules) 605 681 682 if len(sys.argv) > ARGPOS_CHOICE: 683 choice = sys.argv[ARGPOS_CHOICE] 684 else: 685 choice = None 686 687 if len(sys.argv) > ARGPOS_PRESET: 688 preset = sys.argv[ARGPOS_PRESET] 689 else: 690 preset = None 691 606 692 # Input configuration file can be specified on command line 607 693 # otherwise configuration from previous run is used. 608 if len(sys.argv) >= 4:609 profile = parse_profile_name( sys.argv[3])694 if preset is not None: 695 profile = parse_profile_name(preset) 610 696 read_presets(profile, config) 611 697 elif os.path.exists(MAKEFILE): … … 613 699 614 700 # Default mode: check values and regenerate configuration files 615 if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):701 if choice == 'default': 616 702 if (infer_verify_choices(config, rules)): 617 703 preprocess_config(config, rules) … … 621 707 # Hands-off mode: check values and regenerate configuration files, 622 708 # but no interactive fallback 623 if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'):624 # We deliberately test sys.argv >= 4because we do not want709 if choice == 'hands-off': 710 # We deliberately test this because we do not want 625 711 # to read implicitly any possible previous run configuration 626 if len(sys.argv) < 4:712 if preset is None: 627 713 sys.stderr.write("Configuration error: No presets specified\n") 628 714 return 2 … … 637 723 638 724 # Check mode: only check configuration 639 if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):725 if choice == 'check': 640 726 if infer_verify_choices(config, rules): 641 727 return 0 … … 643 729 644 730 # Random mode 645 if (len(sys.argv) == 3) and (sys.argv[2] == 'random'):731 if choice == 'random': 646 732 ok = random_choices(config, rules, 0) 647 733 if not ok: … … 676 762 varname, vartype, name, choices, cond = rule 677 763 678 if cond and (not check_condition(cond, config, rules)):764 if cond and not cond.evaluate(config): 679 765 continue 680 766
Note:
See TracChangeset
for help on using the changeset viewer.