| 
									
										
										
										
											2020-01-30 17:32:26 +01:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | # | 
					
						
							|  |  |  | # Mini-Kconfig parser | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (c) 2015 Red Hat Inc. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Authors: | 
					
						
							|  |  |  | #  Paolo Bonzini <pbonzini@redhat.com> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This work is licensed under the terms of the GNU GPL, version 2 | 
					
						
							|  |  |  | # or, at your option, any later version.  See the COPYING file in | 
					
						
							|  |  |  | # the top-level directory. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  | import random | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  | __all__ = [ 'KconfigDataError', 'KconfigParserError', | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |             'KconfigData', 'KconfigParser' , | 
					
						
							|  |  |  |             'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ] | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def debug_print(*args): | 
					
						
							|  |  |  |     #print('# ' + (' '.join(str(x) for x in args))) | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # ------------------------------------------- | 
					
						
							|  |  |  | # KconfigData implements the Kconfig semantics.  For now it can only | 
					
						
							|  |  |  | # detect undefined symbols, i.e. symbols that were referenced in | 
					
						
							|  |  |  | # assignments or dependencies but were not declared with "config FOO". | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Semantic actions are represented by methods called do_*.  The do_var | 
					
						
							|  |  |  | # method return the semantic value of a variable (which right now is | 
					
						
							|  |  |  | # just its name). | 
					
						
							|  |  |  | # ------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  | class KconfigDataError(Exception): | 
					
						
							|  |  |  |     def __init__(self, msg): | 
					
						
							|  |  |  |         self.msg = msg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.msg | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  | allyesconfig = lambda x: True | 
					
						
							|  |  |  | allnoconfig = lambda x: False | 
					
						
							|  |  |  | defconfig = lambda x: x | 
					
						
							|  |  |  | randconfig = lambda x: random.randint(0, 1) == 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | class KconfigData: | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class Expr: | 
					
						
							|  |  |  |         def __and__(self, rhs): | 
					
						
							|  |  |  |             return KconfigData.AND(self, rhs) | 
					
						
							|  |  |  |         def __or__(self, rhs): | 
					
						
							|  |  |  |             return KconfigData.OR(self, rhs) | 
					
						
							|  |  |  |         def __invert__(self): | 
					
						
							|  |  |  |             return KconfigData.NOT(self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         # Abstract methods | 
					
						
							|  |  |  |         def add_edges_to(self, var): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         def evaluate(self): | 
					
						
							|  |  |  |             assert False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class AND(Expr): | 
					
						
							|  |  |  |         def __init__(self, lhs, rhs): | 
					
						
							|  |  |  |             self.lhs = lhs | 
					
						
							|  |  |  |             self.rhs = rhs | 
					
						
							|  |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return "(%s && %s)" % (self.lhs, self.rhs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def add_edges_to(self, var): | 
					
						
							|  |  |  |             self.lhs.add_edges_to(var) | 
					
						
							|  |  |  |             self.rhs.add_edges_to(var) | 
					
						
							|  |  |  |         def evaluate(self): | 
					
						
							|  |  |  |             return self.lhs.evaluate() and self.rhs.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class OR(Expr): | 
					
						
							|  |  |  |         def __init__(self, lhs, rhs): | 
					
						
							|  |  |  |             self.lhs = lhs | 
					
						
							|  |  |  |             self.rhs = rhs | 
					
						
							|  |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return "(%s || %s)" % (self.lhs, self.rhs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def add_edges_to(self, var): | 
					
						
							|  |  |  |             self.lhs.add_edges_to(var) | 
					
						
							|  |  |  |             self.rhs.add_edges_to(var) | 
					
						
							|  |  |  |         def evaluate(self): | 
					
						
							|  |  |  |             return self.lhs.evaluate() or self.rhs.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class NOT(Expr): | 
					
						
							|  |  |  |         def __init__(self, lhs): | 
					
						
							|  |  |  |             self.lhs = lhs | 
					
						
							|  |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return "!%s" % (self.lhs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def add_edges_to(self, var): | 
					
						
							|  |  |  |             self.lhs.add_edges_to(var) | 
					
						
							|  |  |  |         def evaluate(self): | 
					
						
							|  |  |  |             return not self.lhs.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class Var(Expr): | 
					
						
							|  |  |  |         def __init__(self, name): | 
					
						
							|  |  |  |             self.name = name | 
					
						
							|  |  |  |             self.value = None | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             self.outgoing = set() | 
					
						
							|  |  |  |             self.clauses_for_var = list() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return self.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def has_value(self): | 
					
						
							|  |  |  |             return not (self.value is None) | 
					
						
							|  |  |  |         def set_value(self, val, clause): | 
					
						
							|  |  |  |             self.clauses_for_var.append(clause) | 
					
						
							|  |  |  |             if self.has_value() and self.value != val: | 
					
						
							|  |  |  |                 print("The following clauses were found for " + self.name) | 
					
						
							|  |  |  |                 for i in self.clauses_for_var: | 
					
						
							|  |  |  |                     print("    " + str(i), file=sys.stderr) | 
					
						
							|  |  |  |                 raise KconfigDataError('contradiction between clauses when setting %s' % self) | 
					
						
							|  |  |  |             debug_print("=> %s is now %s" % (self.name, val)) | 
					
						
							|  |  |  |             self.value = val | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # depth first search of the dependency graph | 
					
						
							|  |  |  |         def dfs(self, visited, f): | 
					
						
							|  |  |  |             if self in visited: | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             visited.add(self) | 
					
						
							|  |  |  |             for v in self.outgoing: | 
					
						
							|  |  |  |                 v.dfs(visited, f) | 
					
						
							|  |  |  |             f(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def add_edges_to(self, var): | 
					
						
							|  |  |  |             self.outgoing.add(var) | 
					
						
							|  |  |  |         def evaluate(self): | 
					
						
							|  |  |  |             if not self.has_value(): | 
					
						
							|  |  |  |                 raise KconfigDataError('cycle found including %s' % self) | 
					
						
							|  |  |  |             return self.value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class Clause: | 
					
						
							|  |  |  |         def __init__(self, dest): | 
					
						
							|  |  |  |             self.dest = dest | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def priority(self): | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         def process(self): | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class AssignmentClause(Clause): | 
					
						
							|  |  |  |         def __init__(self, dest, value): | 
					
						
							|  |  |  |             KconfigData.Clause.__init__(self, dest) | 
					
						
							|  |  |  |             self.value = value | 
					
						
							|  |  |  |         def __str__(self): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             return "CONFIG_%s=%s" % (self.dest, 'y' if self.value else 'n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def process(self): | 
					
						
							|  |  |  |             self.dest.set_value(self.value, self) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class DefaultClause(Clause): | 
					
						
							|  |  |  |         def __init__(self, dest, value, cond=None): | 
					
						
							|  |  |  |             KconfigData.Clause.__init__(self, dest) | 
					
						
							|  |  |  |             self.value = value | 
					
						
							|  |  |  |             self.cond = cond | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             if not (self.cond is None): | 
					
						
							|  |  |  |                 self.cond.add_edges_to(self.dest) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         def __str__(self): | 
					
						
							|  |  |  |             value = 'y' if self.value else 'n' | 
					
						
							|  |  |  |             if self.cond is None: | 
					
						
							|  |  |  |                 return "config %s default %s" % (self.dest, value) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return "config %s default %s if %s" % (self.dest, value, self.cond) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def priority(self): | 
					
						
							|  |  |  |             # Defaults are processed just before leaving the variable | 
					
						
							|  |  |  |             return -1 | 
					
						
							|  |  |  |         def process(self): | 
					
						
							|  |  |  |             if not self.dest.has_value() and \ | 
					
						
							|  |  |  |                     (self.cond is None or self.cond.evaluate()): | 
					
						
							|  |  |  |                 self.dest.set_value(self.value, self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class DependsOnClause(Clause): | 
					
						
							|  |  |  |         def __init__(self, dest, expr): | 
					
						
							|  |  |  |             KconfigData.Clause.__init__(self, dest) | 
					
						
							|  |  |  |             self.expr = expr | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             self.expr.add_edges_to(self.dest) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return "config %s depends on %s" % (self.dest, self.expr) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def process(self): | 
					
						
							|  |  |  |             if not self.expr.evaluate(): | 
					
						
							|  |  |  |                 self.dest.set_value(False, self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |     class SelectClause(Clause): | 
					
						
							|  |  |  |         def __init__(self, dest, cond): | 
					
						
							|  |  |  |             KconfigData.Clause.__init__(self, dest) | 
					
						
							|  |  |  |             self.cond = cond | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             self.cond.add_edges_to(self.dest) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         def __str__(self): | 
					
						
							|  |  |  |             return "select %s if %s" % (self.dest, self.cond) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |         def process(self): | 
					
						
							|  |  |  |             if self.cond.evaluate(): | 
					
						
							|  |  |  |                 self.dest.set_value(True, self) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |     def __init__(self, value_mangler=defconfig): | 
					
						
							|  |  |  |         self.value_mangler = value_mangler | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         self.previously_included = [] | 
					
						
							|  |  |  |         self.incl_info = None | 
					
						
							|  |  |  |         self.defined_vars = set() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         self.referenced_vars = dict() | 
					
						
							|  |  |  |         self.clauses = list() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # semantic analysis ------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_undefined(self): | 
					
						
							|  |  |  |         undef = False | 
					
						
							|  |  |  |         for i in self.referenced_vars: | 
					
						
							|  |  |  |             if not (i in self.defined_vars): | 
					
						
							|  |  |  |                 print("undefined symbol %s" % (i), file=sys.stderr) | 
					
						
							|  |  |  |                 undef = True | 
					
						
							|  |  |  |         return undef | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |     def compute_config(self): | 
					
						
							|  |  |  |         if self.check_undefined(): | 
					
						
							|  |  |  |             raise KconfigDataError("there were undefined symbols") | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         debug_print("Input:") | 
					
						
							|  |  |  |         for clause in self.clauses: | 
					
						
							|  |  |  |             debug_print(clause) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         debug_print("\nDependency graph:") | 
					
						
							|  |  |  |         for i in self.referenced_vars: | 
					
						
							|  |  |  |             debug_print(i, "->", [str(x) for x in self.referenced_vars[i].outgoing]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # The reverse of the depth-first order is the topological sort | 
					
						
							|  |  |  |         dfo = dict() | 
					
						
							|  |  |  |         visited = set() | 
					
						
							|  |  |  |         debug_print("\n") | 
					
						
							|  |  |  |         def visit_fn(var): | 
					
						
							|  |  |  |             debug_print(var, "has DFS number", len(dfo)) | 
					
						
							|  |  |  |             dfo[var] = len(dfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for name, v in self.referenced_vars.items(): | 
					
						
							|  |  |  |             self.do_default(v, False) | 
					
						
							|  |  |  |             v.dfs(visited, visit_fn) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Put higher DFS numbers and higher priorities first.  This | 
					
						
							|  |  |  |         # places the clauses in topological order and places defaults | 
					
						
							|  |  |  |         # after assignments and dependencies. | 
					
						
							|  |  |  |         self.clauses.sort(key=lambda x: (-dfo[x.dest], -x.priority())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         debug_print("\nSorted clauses:") | 
					
						
							|  |  |  |         for clause in self.clauses: | 
					
						
							|  |  |  |             debug_print(clause) | 
					
						
							|  |  |  |             clause.process() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         debug_print("") | 
					
						
							|  |  |  |         values = dict() | 
					
						
							|  |  |  |         for name, v in self.referenced_vars.items(): | 
					
						
							|  |  |  |             debug_print("Evaluating", name) | 
					
						
							|  |  |  |             values[name] = v.evaluate() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return values | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |     # semantic actions ------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def do_declaration(self, var): | 
					
						
							|  |  |  |         if (var in self.defined_vars): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:58 +08:00
										 |  |  |             raise KconfigDataError('variable "' + var + '" defined twice') | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         self.defined_vars.add(var.name) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # var is a string with the variable's name. | 
					
						
							|  |  |  |     def do_var(self, var): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         if (var in self.referenced_vars): | 
					
						
							|  |  |  |             return self.referenced_vars[var] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var_obj = self.referenced_vars[var] = KconfigData.Var(var) | 
					
						
							|  |  |  |         return var_obj | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_assignment(self, var, val): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         self.clauses.append(KconfigData.AssignmentClause(var, val)) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_default(self, var, val, cond=None): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |         val = self.value_mangler(val) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         self.clauses.append(KconfigData.DefaultClause(var, val, cond)) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_depends_on(self, var, expr): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         self.clauses.append(KconfigData.DependsOnClause(var, expr)) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_select(self, var, symbol, cond=None): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         cond = (cond & var) if cond is not None else var | 
					
						
							|  |  |  |         self.clauses.append(KconfigData.SelectClause(symbol, cond)) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_imply(self, var, symbol, cond=None): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         # "config X imply Y [if COND]" is the same as | 
					
						
							|  |  |  |         # "config Y default y if X [&& COND]" | 
					
						
							|  |  |  |         cond = (cond & var) if cond is not None else var | 
					
						
							|  |  |  |         self.do_default(symbol, True, cond) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # ------------------------------------------- | 
					
						
							|  |  |  | # KconfigParser implements a recursive descent parser for (simplified) | 
					
						
							|  |  |  | # Kconfig syntax. | 
					
						
							|  |  |  | # ------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # tokens table | 
					
						
							|  |  |  | TOKENS = {} | 
					
						
							|  |  |  | TOK_NONE = -1 | 
					
						
							|  |  |  | TOK_LPAREN = 0;   TOKENS[TOK_LPAREN] = '"("'; | 
					
						
							|  |  |  | TOK_RPAREN = 1;   TOKENS[TOK_RPAREN] = '")"'; | 
					
						
							|  |  |  | TOK_EQUAL = 2;    TOKENS[TOK_EQUAL] = '"="'; | 
					
						
							|  |  |  | TOK_AND = 3;      TOKENS[TOK_AND] = '"&&"'; | 
					
						
							|  |  |  | TOK_OR = 4;       TOKENS[TOK_OR] = '"||"'; | 
					
						
							|  |  |  | TOK_NOT = 5;      TOKENS[TOK_NOT] = '"!"'; | 
					
						
							|  |  |  | TOK_DEPENDS = 6;  TOKENS[TOK_DEPENDS] = '"depends"'; | 
					
						
							|  |  |  | TOK_ON = 7;       TOKENS[TOK_ON] = '"on"'; | 
					
						
							|  |  |  | TOK_SELECT = 8;   TOKENS[TOK_SELECT] = '"select"'; | 
					
						
							|  |  |  | TOK_IMPLY = 9;    TOKENS[TOK_IMPLY] = '"imply"'; | 
					
						
							|  |  |  | TOK_CONFIG = 10;  TOKENS[TOK_CONFIG] = '"config"'; | 
					
						
							|  |  |  | TOK_DEFAULT = 11; TOKENS[TOK_DEFAULT] = '"default"'; | 
					
						
							|  |  |  | TOK_Y = 12;       TOKENS[TOK_Y] = '"y"'; | 
					
						
							|  |  |  | TOK_N = 13;       TOKENS[TOK_N] = '"n"'; | 
					
						
							|  |  |  | TOK_SOURCE = 14;  TOKENS[TOK_SOURCE] = '"source"'; | 
					
						
							|  |  |  | TOK_BOOL = 15;    TOKENS[TOK_BOOL] = '"bool"'; | 
					
						
							|  |  |  | TOK_IF = 16;      TOKENS[TOK_IF] = '"if"'; | 
					
						
							|  |  |  | TOK_ID = 17;      TOKENS[TOK_ID] = 'identifier'; | 
					
						
							|  |  |  | TOK_EOF = 18;     TOKENS[TOK_EOF] = 'end of file'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class KconfigParserError(Exception): | 
					
						
							|  |  |  |     def __init__(self, parser, msg, tok=None): | 
					
						
							|  |  |  |         self.loc = parser.location() | 
					
						
							|  |  |  |         tok = tok or parser.tok | 
					
						
							|  |  |  |         if tok != TOK_NONE: | 
					
						
							|  |  |  |             location = TOKENS.get(tok, None) or ('"%s"' % tok) | 
					
						
							|  |  |  |             msg = '%s before %s' % (msg, location) | 
					
						
							|  |  |  |         self.msg = msg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return "%s: %s" % (self.loc, self.msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class KconfigParser: | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |     def parse(self, fp, mode=None): | 
					
						
							|  |  |  |         data = KconfigData(mode or KconfigParser.defconfig) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         parser = KconfigParser(data) | 
					
						
							|  |  |  |         parser.parse_file(fp) | 
					
						
							|  |  |  |         return data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, data): | 
					
						
							|  |  |  |         self.data = data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parse_file(self, fp): | 
					
						
							|  |  |  |         self.abs_fname = os.path.abspath(fp.name) | 
					
						
							|  |  |  |         self.fname = fp.name | 
					
						
							|  |  |  |         self.data.previously_included.append(self.abs_fname) | 
					
						
							|  |  |  |         self.src = fp.read() | 
					
						
							|  |  |  |         if self.src == '' or self.src[-1] != '\n': | 
					
						
							|  |  |  |             self.src += '\n' | 
					
						
							|  |  |  |         self.cursor = 0 | 
					
						
							|  |  |  |         self.line = 1 | 
					
						
							|  |  |  |         self.line_pos = 0 | 
					
						
							|  |  |  |         self.get_token() | 
					
						
							|  |  |  |         self.parse_config() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     def do_assignment(self, var, val): | 
					
						
							|  |  |  |         if not var.startswith("CONFIG_"): | 
					
						
							|  |  |  |             raise Error('assigned variable should start with CONFIG_') | 
					
						
							|  |  |  |         var = self.data.do_var(var[7:]) | 
					
						
							|  |  |  |         self.data.do_assignment(var, val) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |     # file management ----- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def error_path(self): | 
					
						
							|  |  |  |         inf = self.data.incl_info | 
					
						
							|  |  |  |         res = "" | 
					
						
							|  |  |  |         while inf: | 
					
						
							|  |  |  |             res = ("In file included from %s:%d:\n" % (inf['file'], | 
					
						
							|  |  |  |                                                        inf['line'])) + res | 
					
						
							|  |  |  |             inf = inf['parent'] | 
					
						
							|  |  |  |         return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def location(self): | 
					
						
							|  |  |  |         col = 1 | 
					
						
							|  |  |  |         for ch in self.src[self.line_pos:self.pos]: | 
					
						
							|  |  |  |             if ch == '\t': | 
					
						
							|  |  |  |                 col += 8 - ((col - 1) % 8) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 col += 1 | 
					
						
							|  |  |  |         return '%s%s:%d:%d' %(self.error_path(), self.fname, self.line, col) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def do_include(self, include): | 
					
						
							|  |  |  |         incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname), | 
					
						
							|  |  |  |                                       include) | 
					
						
							|  |  |  |         # catch inclusion cycle | 
					
						
							|  |  |  |         inf = self.data.incl_info | 
					
						
							|  |  |  |         while inf: | 
					
						
							|  |  |  |             if incl_abs_fname == os.path.abspath(inf['file']): | 
					
						
							|  |  |  |                 raise KconfigParserError(self, "Inclusion loop for %s" | 
					
						
							|  |  |  |                                     % include) | 
					
						
							|  |  |  |             inf = inf['parent'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # skip multiple include of the same file | 
					
						
							|  |  |  |         if incl_abs_fname in self.data.previously_included: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2020-05-21 16:36:16 +01:00
										 |  |  |             fp = open(incl_abs_fname, 'rt', encoding='utf-8') | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         except IOError as e: | 
					
						
							|  |  |  |             raise KconfigParserError(self, | 
					
						
							|  |  |  |                                 '%s: %s' % (e.strerror, include)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inf = self.data.incl_info | 
					
						
							|  |  |  |         self.data.incl_info = { 'file': self.fname, 'line': self.line, | 
					
						
							|  |  |  |                 'parent': inf } | 
					
						
							|  |  |  |         KconfigParser(self.data).parse_file(fp) | 
					
						
							|  |  |  |         self.data.incl_info = inf | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # recursive descent parser ----- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # y_or_n: Y | N | 
					
						
							|  |  |  |     def parse_y_or_n(self): | 
					
						
							|  |  |  |         if self.tok == TOK_Y: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         if self.tok == TOK_N: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         raise KconfigParserError(self, 'Expected "y" or "n"') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # var: ID | 
					
						
							|  |  |  |     def parse_var(self): | 
					
						
							|  |  |  |         if self.tok == TOK_ID: | 
					
						
							|  |  |  |             val = self.val | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             return self.data.do_var(val) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Expected identifier') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # assignment_var: ID (starting with "CONFIG_") | 
					
						
							|  |  |  |     def parse_assignment_var(self): | 
					
						
							|  |  |  |         if self.tok == TOK_ID: | 
					
						
							|  |  |  |             val = self.val | 
					
						
							|  |  |  |             if not val.startswith("CONFIG_"): | 
					
						
							|  |  |  |                 raise KconfigParserError(self, | 
					
						
							|  |  |  |                            'Expected identifier starting with "CONFIG_"', TOK_NONE) | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             return self.data.do_var(val[7:]) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Expected identifier') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # assignment: var EQUAL y_or_n | 
					
						
							|  |  |  |     def parse_assignment(self): | 
					
						
							|  |  |  |         var = self.parse_assignment_var() | 
					
						
							|  |  |  |         if self.tok != TOK_EQUAL: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Expected "="') | 
					
						
							|  |  |  |         self.get_token() | 
					
						
							|  |  |  |         self.data.do_assignment(var, self.parse_y_or_n()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # primary: NOT primary | 
					
						
							|  |  |  |     #       | LPAREN expr RPAREN | 
					
						
							|  |  |  |     #       | var | 
					
						
							|  |  |  |     def parse_primary(self): | 
					
						
							|  |  |  |         if self.tok == TOK_NOT: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |             val = ~self.parse_primary() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         elif self.tok == TOK_LPAREN: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |             val = self.parse_expr() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |             if self.tok != TOK_RPAREN: | 
					
						
							|  |  |  |                 raise KconfigParserError(self, 'Expected ")"') | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |         elif self.tok == TOK_ID: | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |             val = self.parse_var() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Expected "!" or "(" or identifier') | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         return val | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # disj: primary (OR primary)* | 
					
						
							|  |  |  |     def parse_disj(self): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         lhs = self.parse_primary() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         while self.tok == TOK_OR: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |             lhs = lhs | self.parse_primary() | 
					
						
							|  |  |  |         return lhs | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # expr: disj (AND disj)* | 
					
						
							|  |  |  |     def parse_expr(self): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |         lhs = self.parse_disj() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |         while self.tok == TOK_AND: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:57 +08:00
										 |  |  |             lhs = lhs & self.parse_disj() | 
					
						
							|  |  |  |         return lhs | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # condition: IF expr | 
					
						
							|  |  |  |     #       | empty | 
					
						
							|  |  |  |     def parse_condition(self): | 
					
						
							|  |  |  |         if self.tok == TOK_IF: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             return self.parse_expr() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # property: DEFAULT y_or_n condition | 
					
						
							|  |  |  |     #       | DEPENDS ON expr | 
					
						
							|  |  |  |     #       | SELECT var condition | 
					
						
							|  |  |  |     #       | BOOL | 
					
						
							|  |  |  |     def parse_property(self, var): | 
					
						
							|  |  |  |         if self.tok == TOK_DEFAULT: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             val = self.parse_y_or_n() | 
					
						
							|  |  |  |             cond = self.parse_condition() | 
					
						
							|  |  |  |             self.data.do_default(var, val, cond) | 
					
						
							|  |  |  |         elif self.tok == TOK_DEPENDS: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             if self.tok != TOK_ON: | 
					
						
							|  |  |  |                 raise KconfigParserError(self, 'Expected "on"') | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             self.data.do_depends_on(var, self.parse_expr()) | 
					
						
							|  |  |  |         elif self.tok == TOK_SELECT: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             symbol = self.parse_var() | 
					
						
							|  |  |  |             cond = self.parse_condition() | 
					
						
							|  |  |  |             self.data.do_select(var, symbol, cond) | 
					
						
							|  |  |  |         elif self.tok == TOK_IMPLY: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             symbol = self.parse_var() | 
					
						
							|  |  |  |             cond = self.parse_condition() | 
					
						
							|  |  |  |             self.data.do_imply(var, symbol, cond) | 
					
						
							|  |  |  |         elif self.tok == TOK_BOOL: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Error in recursive descent?') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # properties: properties property | 
					
						
							|  |  |  |     #       | /* empty */ | 
					
						
							|  |  |  |     def parse_properties(self, var): | 
					
						
							|  |  |  |         had_default = False | 
					
						
							|  |  |  |         while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \ | 
					
						
							|  |  |  |               self.tok == TOK_SELECT or self.tok == TOK_BOOL or \ | 
					
						
							|  |  |  |               self.tok == TOK_IMPLY: | 
					
						
							|  |  |  |             self.parse_property(var) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # for nicer error message | 
					
						
							|  |  |  |         if self.tok != TOK_SOURCE and self.tok != TOK_CONFIG and \ | 
					
						
							|  |  |  |            self.tok != TOK_ID and self.tok != TOK_EOF: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'expected "source", "config", identifier, ' | 
					
						
							|  |  |  |                     + '"default", "depends on", "imply" or "select"') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # declaration: config var properties | 
					
						
							|  |  |  |     def parse_declaration(self): | 
					
						
							|  |  |  |         if self.tok == TOK_CONFIG: | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             var = self.parse_var() | 
					
						
							|  |  |  |             self.data.do_declaration(var) | 
					
						
							|  |  |  |             self.parse_properties(var) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'Error in recursive descent?') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # clause: SOURCE | 
					
						
							|  |  |  |     #       | declaration | 
					
						
							|  |  |  |     #       | assignment | 
					
						
							|  |  |  |     def parse_clause(self): | 
					
						
							|  |  |  |         if self.tok == TOK_SOURCE: | 
					
						
							|  |  |  |             val = self.val | 
					
						
							|  |  |  |             self.get_token() | 
					
						
							|  |  |  |             self.do_include(val) | 
					
						
							|  |  |  |         elif self.tok == TOK_CONFIG: | 
					
						
							|  |  |  |             self.parse_declaration() | 
					
						
							|  |  |  |         elif self.tok == TOK_ID: | 
					
						
							|  |  |  |             self.parse_assignment() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'expected "source", "config" or identifier') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # config: clause+ EOF | 
					
						
							|  |  |  |     def parse_config(self): | 
					
						
							|  |  |  |         while self.tok != TOK_EOF: | 
					
						
							|  |  |  |             self.parse_clause() | 
					
						
							|  |  |  |         return self.data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # scanner ----- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_token(self): | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             self.tok = self.src[self.cursor] | 
					
						
							|  |  |  |             self.pos = self.cursor | 
					
						
							|  |  |  |             self.cursor += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.val = None | 
					
						
							|  |  |  |             self.tok = self.scan_token() | 
					
						
							|  |  |  |             if self.tok is not None: | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def check_keyword(self, rest): | 
					
						
							|  |  |  |         if not self.src.startswith(rest, self.cursor): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         length = len(rest) | 
					
						
							| 
									
										
										
										
											2019-03-12 17:48:48 +01:00
										 |  |  |         if self.src[self.cursor + length].isalnum() or self.src[self.cursor + length] == '_': | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |             return False | 
					
						
							|  |  |  |         self.cursor += length | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def scan_token(self): | 
					
						
							|  |  |  |         if self.tok == '#': | 
					
						
							|  |  |  |             self.cursor = self.src.find('\n', self.cursor) | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         elif self.tok == '=': | 
					
						
							|  |  |  |             return TOK_EQUAL | 
					
						
							|  |  |  |         elif self.tok == '(': | 
					
						
							|  |  |  |             return TOK_LPAREN | 
					
						
							|  |  |  |         elif self.tok == ')': | 
					
						
							|  |  |  |             return TOK_RPAREN | 
					
						
							|  |  |  |         elif self.tok == '&' and self.src[self.pos+1] == '&': | 
					
						
							|  |  |  |             self.cursor += 1 | 
					
						
							|  |  |  |             return TOK_AND | 
					
						
							|  |  |  |         elif self.tok == '|' and self.src[self.pos+1] == '|': | 
					
						
							|  |  |  |             self.cursor += 1 | 
					
						
							|  |  |  |             return TOK_OR | 
					
						
							|  |  |  |         elif self.tok == '!': | 
					
						
							|  |  |  |             return TOK_NOT | 
					
						
							|  |  |  |         elif self.tok == 'd' and self.check_keyword("epends"): | 
					
						
							|  |  |  |             return TOK_DEPENDS | 
					
						
							|  |  |  |         elif self.tok == 'o' and self.check_keyword("n"): | 
					
						
							|  |  |  |             return TOK_ON | 
					
						
							|  |  |  |         elif self.tok == 's' and self.check_keyword("elect"): | 
					
						
							|  |  |  |             return TOK_SELECT | 
					
						
							|  |  |  |         elif self.tok == 'i' and self.check_keyword("mply"): | 
					
						
							|  |  |  |             return TOK_IMPLY | 
					
						
							|  |  |  |         elif self.tok == 'c' and self.check_keyword("onfig"): | 
					
						
							|  |  |  |             return TOK_CONFIG | 
					
						
							|  |  |  |         elif self.tok == 'd' and self.check_keyword("efault"): | 
					
						
							|  |  |  |             return TOK_DEFAULT | 
					
						
							|  |  |  |         elif self.tok == 'b' and self.check_keyword("ool"): | 
					
						
							|  |  |  |             return TOK_BOOL | 
					
						
							|  |  |  |         elif self.tok == 'i' and self.check_keyword("f"): | 
					
						
							|  |  |  |             return TOK_IF | 
					
						
							|  |  |  |         elif self.tok == 'y' and self.check_keyword(""): | 
					
						
							|  |  |  |             return TOK_Y | 
					
						
							|  |  |  |         elif self.tok == 'n' and self.check_keyword(""): | 
					
						
							|  |  |  |             return TOK_N | 
					
						
							|  |  |  |         elif (self.tok == 's' and self.check_keyword("ource")) or \ | 
					
						
							|  |  |  |               self.tok == 'i' and self.check_keyword("nclude"): | 
					
						
							|  |  |  |             # source FILENAME | 
					
						
							|  |  |  |             # include FILENAME | 
					
						
							|  |  |  |             while self.src[self.cursor].isspace(): | 
					
						
							|  |  |  |                 self.cursor += 1 | 
					
						
							|  |  |  |             start = self.cursor | 
					
						
							|  |  |  |             self.cursor = self.src.find('\n', self.cursor) | 
					
						
							|  |  |  |             self.val = self.src[start:self.cursor] | 
					
						
							|  |  |  |             return TOK_SOURCE | 
					
						
							| 
									
										
										
										
											2019-08-17 12:05:17 +04:00
										 |  |  |         elif self.tok.isalnum(): | 
					
						
							| 
									
										
										
										
											2019-01-23 14:55:56 +08:00
										 |  |  |             # identifier | 
					
						
							|  |  |  |             while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_': | 
					
						
							|  |  |  |                 self.cursor += 1 | 
					
						
							|  |  |  |             self.val = self.src[self.pos:self.cursor] | 
					
						
							|  |  |  |             return TOK_ID | 
					
						
							|  |  |  |         elif self.tok == '\n': | 
					
						
							|  |  |  |             if self.cursor == len(self.src): | 
					
						
							|  |  |  |                 return TOK_EOF | 
					
						
							|  |  |  |             self.line += 1 | 
					
						
							|  |  |  |             self.line_pos = self.cursor | 
					
						
							|  |  |  |         elif not self.tok.isspace(): | 
					
						
							|  |  |  |             raise KconfigParserError(self, 'invalid input') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     argv = sys.argv | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |     mode = defconfig | 
					
						
							|  |  |  |     if len(sys.argv) > 1: | 
					
						
							|  |  |  |         if argv[1] == '--defconfig': | 
					
						
							|  |  |  |             del argv[1] | 
					
						
							|  |  |  |         elif argv[1] == '--randconfig': | 
					
						
							|  |  |  |             random.seed() | 
					
						
							|  |  |  |             mode = randconfig | 
					
						
							|  |  |  |             del argv[1] | 
					
						
							|  |  |  |         elif argv[1] == '--allyesconfig': | 
					
						
							|  |  |  |             mode = allyesconfig | 
					
						
							|  |  |  |             del argv[1] | 
					
						
							|  |  |  |         elif argv[1] == '--allnoconfig': | 
					
						
							|  |  |  |             mode = allnoconfig | 
					
						
							|  |  |  |             del argv[1] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     if len(argv) == 1: | 
					
						
							|  |  |  |         print ("%s: at least one argument is required" % argv[0], file=sys.stderr) | 
					
						
							|  |  |  |         sys.exit(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:17 +08:00
										 |  |  |     if argv[1].startswith('-'): | 
					
						
							|  |  |  |         print ("%s: invalid option %s" % (argv[0], argv[1]), file=sys.stderr) | 
					
						
							|  |  |  |         sys.exit(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = KconfigData(mode) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     parser = KconfigParser(data) | 
					
						
							| 
									
										
										
										
											2019-06-24 20:18:46 +02:00
										 |  |  |     external_vars = set() | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     for arg in argv[3:]: | 
					
						
							|  |  |  |         m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg) | 
					
						
							|  |  |  |         if m is not None: | 
					
						
							|  |  |  |             name, value = m.groups() | 
					
						
							|  |  |  |             parser.do_assignment(name, value == 'y') | 
					
						
							| 
									
										
										
										
											2019-06-24 20:18:46 +02:00
										 |  |  |             external_vars.add(name[7:]) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2020-05-21 16:36:16 +01:00
										 |  |  |             fp = open(arg, 'rt', encoding='utf-8') | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |             parser.parse_file(fp) | 
					
						
							|  |  |  |             fp.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     config = data.compute_config() | 
					
						
							|  |  |  |     for key in sorted(config.keys()): | 
					
						
							| 
									
										
										
										
											2019-07-25 23:36:15 +04:00
										 |  |  |         if key not in external_vars and config[key]: | 
					
						
							|  |  |  |             print ('CONFIG_%s=y' % key) | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 16:36:16 +01:00
										 |  |  |     deps = open(argv[2], 'wt', encoding='utf-8') | 
					
						
							| 
									
										
										
										
											2019-01-23 14:56:00 +08:00
										 |  |  |     for fname in data.previously_included: | 
					
						
							|  |  |  |         print ('%s: %s' % (argv[1], fname), file=deps) | 
					
						
							|  |  |  |     deps.close() |