minikconf.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. #!/usr/bin/env python3
  2. #
  3. # Mini-Kconfig parser
  4. #
  5. # Copyright (c) 2015 Red Hat Inc.
  6. #
  7. # Authors:
  8. # Paolo Bonzini <pbonzini@redhat.com>
  9. #
  10. # This work is licensed under the terms of the GNU GPL, version 2
  11. # or, at your option, any later version. See the COPYING file in
  12. # the top-level directory.
  13. import os
  14. import sys
  15. import re
  16. import random
  17. __all__ = [ 'KconfigDataError', 'KconfigParserError',
  18. 'KconfigData', 'KconfigParser' ,
  19. 'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ]
  20. def debug_print(*args):
  21. #print('# ' + (' '.join(str(x) for x in args)))
  22. pass
  23. # -------------------------------------------
  24. # KconfigData implements the Kconfig semantics. For now it can only
  25. # detect undefined symbols, i.e. symbols that were referenced in
  26. # assignments or dependencies but were not declared with "config FOO".
  27. #
  28. # Semantic actions are represented by methods called do_*. The do_var
  29. # method return the semantic value of a variable (which right now is
  30. # just its name).
  31. # -------------------------------------------
  32. class KconfigDataError(Exception):
  33. def __init__(self, msg):
  34. self.msg = msg
  35. def __str__(self):
  36. return self.msg
  37. allyesconfig = lambda x: True
  38. allnoconfig = lambda x: False
  39. defconfig = lambda x: x
  40. randconfig = lambda x: random.randint(0, 1) == 1
  41. class KconfigData:
  42. class Expr:
  43. def __and__(self, rhs):
  44. return KconfigData.AND(self, rhs)
  45. def __or__(self, rhs):
  46. return KconfigData.OR(self, rhs)
  47. def __invert__(self):
  48. return KconfigData.NOT(self)
  49. # Abstract methods
  50. def add_edges_to(self, var):
  51. pass
  52. def evaluate(self):
  53. assert False
  54. class AND(Expr):
  55. def __init__(self, lhs, rhs):
  56. self.lhs = lhs
  57. self.rhs = rhs
  58. def __str__(self):
  59. return "(%s && %s)" % (self.lhs, self.rhs)
  60. def add_edges_to(self, var):
  61. self.lhs.add_edges_to(var)
  62. self.rhs.add_edges_to(var)
  63. def evaluate(self):
  64. return self.lhs.evaluate() and self.rhs.evaluate()
  65. class OR(Expr):
  66. def __init__(self, lhs, rhs):
  67. self.lhs = lhs
  68. self.rhs = rhs
  69. def __str__(self):
  70. return "(%s || %s)" % (self.lhs, self.rhs)
  71. def add_edges_to(self, var):
  72. self.lhs.add_edges_to(var)
  73. self.rhs.add_edges_to(var)
  74. def evaluate(self):
  75. return self.lhs.evaluate() or self.rhs.evaluate()
  76. class NOT(Expr):
  77. def __init__(self, lhs):
  78. self.lhs = lhs
  79. def __str__(self):
  80. return "!%s" % (self.lhs)
  81. def add_edges_to(self, var):
  82. self.lhs.add_edges_to(var)
  83. def evaluate(self):
  84. return not self.lhs.evaluate()
  85. class Var(Expr):
  86. def __init__(self, name):
  87. self.name = name
  88. self.value = None
  89. self.outgoing = set()
  90. self.clauses_for_var = list()
  91. def __str__(self):
  92. return self.name
  93. def has_value(self):
  94. return not (self.value is None)
  95. def set_value(self, val, clause):
  96. self.clauses_for_var.append(clause)
  97. if self.has_value() and self.value != val:
  98. print("The following clauses were found for " + self.name, file=sys.stderr)
  99. for i in self.clauses_for_var:
  100. print(" " + str(i), file=sys.stderr)
  101. raise KconfigDataError('contradiction between clauses when setting %s' % self)
  102. debug_print("=> %s is now %s" % (self.name, val))
  103. self.value = val
  104. # depth first search of the dependency graph
  105. def dfs(self, visited, f):
  106. if self in visited:
  107. return
  108. visited.add(self)
  109. for v in self.outgoing:
  110. v.dfs(visited, f)
  111. f(self)
  112. def add_edges_to(self, var):
  113. self.outgoing.add(var)
  114. def evaluate(self):
  115. if not self.has_value():
  116. raise KconfigDataError('cycle found including %s' % self)
  117. return self.value
  118. class Clause:
  119. def __init__(self, dest):
  120. self.dest = dest
  121. def priority(self):
  122. return 0
  123. def process(self):
  124. pass
  125. class AssignmentClause(Clause):
  126. def __init__(self, dest, value):
  127. KconfigData.Clause.__init__(self, dest)
  128. self.value = value
  129. def __str__(self):
  130. return "CONFIG_%s=%s" % (self.dest, 'y' if self.value else 'n')
  131. def process(self):
  132. self.dest.set_value(self.value, self)
  133. class DefaultClause(Clause):
  134. def __init__(self, dest, value, cond=None):
  135. KconfigData.Clause.__init__(self, dest)
  136. self.value = value
  137. self.cond = cond
  138. if not (self.cond is None):
  139. self.cond.add_edges_to(self.dest)
  140. def __str__(self):
  141. value = 'y' if self.value else 'n'
  142. if self.cond is None:
  143. return "config %s default %s" % (self.dest, value)
  144. else:
  145. return "config %s default %s if %s" % (self.dest, value, self.cond)
  146. def priority(self):
  147. # Defaults are processed just before leaving the variable
  148. return -1
  149. def process(self):
  150. if not self.dest.has_value() and \
  151. (self.cond is None or self.cond.evaluate()):
  152. self.dest.set_value(self.value, self)
  153. class DependsOnClause(Clause):
  154. def __init__(self, dest, expr):
  155. KconfigData.Clause.__init__(self, dest)
  156. self.expr = expr
  157. self.expr.add_edges_to(self.dest)
  158. def __str__(self):
  159. return "config %s depends on %s" % (self.dest, self.expr)
  160. def process(self):
  161. if not self.expr.evaluate():
  162. self.dest.set_value(False, self)
  163. class SelectClause(Clause):
  164. def __init__(self, dest, cond):
  165. KconfigData.Clause.__init__(self, dest)
  166. self.cond = cond
  167. self.cond.add_edges_to(self.dest)
  168. def __str__(self):
  169. return "select %s if %s" % (self.dest, self.cond)
  170. def process(self):
  171. if self.cond.evaluate():
  172. self.dest.set_value(True, self)
  173. def __init__(self, value_mangler=defconfig):
  174. self.value_mangler = value_mangler
  175. self.previously_included = []
  176. self.incl_info = None
  177. self.defined_vars = set()
  178. self.referenced_vars = dict()
  179. self.clauses = list()
  180. # semantic analysis -------------
  181. def check_undefined(self):
  182. undef = False
  183. for i in self.referenced_vars:
  184. if not (i in self.defined_vars):
  185. print("undefined symbol %s" % (i), file=sys.stderr)
  186. undef = True
  187. return undef
  188. def compute_config(self):
  189. if self.check_undefined():
  190. raise KconfigDataError("there were undefined symbols")
  191. return None
  192. debug_print("Input:")
  193. for clause in self.clauses:
  194. debug_print(clause)
  195. debug_print("\nDependency graph:")
  196. for i in self.referenced_vars:
  197. debug_print(i, "->", [str(x) for x in self.referenced_vars[i].outgoing])
  198. # The reverse of the depth-first order is the topological sort
  199. dfo = dict()
  200. visited = set()
  201. debug_print("\n")
  202. def visit_fn(var):
  203. debug_print(var, "has DFS number", len(dfo))
  204. dfo[var] = len(dfo)
  205. for name, v in self.referenced_vars.items():
  206. self.do_default(v, False)
  207. v.dfs(visited, visit_fn)
  208. # Put higher DFS numbers and higher priorities first. This
  209. # places the clauses in topological order and places defaults
  210. # after assignments and dependencies.
  211. self.clauses.sort(key=lambda x: (-dfo[x.dest], -x.priority()))
  212. debug_print("\nSorted clauses:")
  213. for clause in self.clauses:
  214. debug_print(clause)
  215. clause.process()
  216. debug_print("")
  217. values = dict()
  218. for name, v in self.referenced_vars.items():
  219. debug_print("Evaluating", name)
  220. values[name] = v.evaluate()
  221. return values
  222. # semantic actions -------------
  223. def do_declaration(self, var):
  224. if (var in self.defined_vars):
  225. raise KconfigDataError('variable "' + var + '" defined twice')
  226. self.defined_vars.add(var.name)
  227. # var is a string with the variable's name.
  228. def do_var(self, var):
  229. if (var in self.referenced_vars):
  230. return self.referenced_vars[var]
  231. var_obj = self.referenced_vars[var] = KconfigData.Var(var)
  232. return var_obj
  233. def do_assignment(self, var, val):
  234. self.clauses.append(KconfigData.AssignmentClause(var, val))
  235. def do_default(self, var, val, cond=None):
  236. val = self.value_mangler(val)
  237. self.clauses.append(KconfigData.DefaultClause(var, val, cond))
  238. def do_depends_on(self, var, expr):
  239. self.clauses.append(KconfigData.DependsOnClause(var, expr))
  240. def do_select(self, var, symbol, cond=None):
  241. cond = (cond & var) if cond is not None else var
  242. self.clauses.append(KconfigData.SelectClause(symbol, cond))
  243. def do_imply(self, var, symbol, cond=None):
  244. # "config X imply Y [if COND]" is the same as
  245. # "config Y default y if X [&& COND]"
  246. cond = (cond & var) if cond is not None else var
  247. self.do_default(symbol, True, cond)
  248. # -------------------------------------------
  249. # KconfigParser implements a recursive descent parser for (simplified)
  250. # Kconfig syntax.
  251. # -------------------------------------------
  252. # tokens table
  253. TOKENS = {}
  254. TOK_NONE = -1
  255. TOK_LPAREN = 0; TOKENS[TOK_LPAREN] = '"("';
  256. TOK_RPAREN = 1; TOKENS[TOK_RPAREN] = '")"';
  257. TOK_EQUAL = 2; TOKENS[TOK_EQUAL] = '"="';
  258. TOK_AND = 3; TOKENS[TOK_AND] = '"&&"';
  259. TOK_OR = 4; TOKENS[TOK_OR] = '"||"';
  260. TOK_NOT = 5; TOKENS[TOK_NOT] = '"!"';
  261. TOK_DEPENDS = 6; TOKENS[TOK_DEPENDS] = '"depends"';
  262. TOK_ON = 7; TOKENS[TOK_ON] = '"on"';
  263. TOK_SELECT = 8; TOKENS[TOK_SELECT] = '"select"';
  264. TOK_IMPLY = 9; TOKENS[TOK_IMPLY] = '"imply"';
  265. TOK_CONFIG = 10; TOKENS[TOK_CONFIG] = '"config"';
  266. TOK_DEFAULT = 11; TOKENS[TOK_DEFAULT] = '"default"';
  267. TOK_Y = 12; TOKENS[TOK_Y] = '"y"';
  268. TOK_N = 13; TOKENS[TOK_N] = '"n"';
  269. TOK_SOURCE = 14; TOKENS[TOK_SOURCE] = '"source"';
  270. TOK_BOOL = 15; TOKENS[TOK_BOOL] = '"bool"';
  271. TOK_IF = 16; TOKENS[TOK_IF] = '"if"';
  272. TOK_ID = 17; TOKENS[TOK_ID] = 'identifier';
  273. TOK_EOF = 18; TOKENS[TOK_EOF] = 'end of file';
  274. class KconfigParserError(Exception):
  275. def __init__(self, parser, msg, tok=None):
  276. self.loc = parser.location()
  277. tok = tok or parser.tok
  278. if tok != TOK_NONE:
  279. location = TOKENS.get(tok, None) or ('"%s"' % tok)
  280. msg = '%s before %s' % (msg, location)
  281. self.msg = msg
  282. def __str__(self):
  283. return "%s: %s" % (self.loc, self.msg)
  284. class KconfigParser:
  285. @classmethod
  286. def parse(self, fp, mode=None):
  287. data = KconfigData(mode or KconfigParser.defconfig)
  288. parser = KconfigParser(data)
  289. parser.parse_file(fp)
  290. return data
  291. def __init__(self, data):
  292. self.data = data
  293. def parse_file(self, fp):
  294. self.abs_fname = os.path.abspath(fp.name)
  295. self.fname = fp.name
  296. self.data.previously_included.append(self.abs_fname)
  297. self.src = fp.read()
  298. if self.src == '' or self.src[-1] != '\n':
  299. self.src += '\n'
  300. self.cursor = 0
  301. self.line = 1
  302. self.line_pos = 0
  303. self.get_token()
  304. self.parse_config()
  305. def do_assignment(self, var, val):
  306. if not var.startswith("CONFIG_"):
  307. raise Error('assigned variable should start with CONFIG_')
  308. var = self.data.do_var(var[7:])
  309. self.data.do_assignment(var, val)
  310. # file management -----
  311. def error_path(self):
  312. inf = self.data.incl_info
  313. res = ""
  314. while inf:
  315. res = ("In file included from %s:%d:\n" % (inf['file'],
  316. inf['line'])) + res
  317. inf = inf['parent']
  318. return res
  319. def location(self):
  320. col = 1
  321. for ch in self.src[self.line_pos:self.pos]:
  322. if ch == '\t':
  323. col += 8 - ((col - 1) % 8)
  324. else:
  325. col += 1
  326. return '%s%s:%d:%d' %(self.error_path(), self.fname, self.line, col)
  327. def do_include(self, include):
  328. incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname),
  329. include)
  330. # catch inclusion cycle
  331. inf = self.data.incl_info
  332. while inf:
  333. if incl_abs_fname == os.path.abspath(inf['file']):
  334. raise KconfigParserError(self, "Inclusion loop for %s"
  335. % include)
  336. inf = inf['parent']
  337. # skip multiple include of the same file
  338. if incl_abs_fname in self.data.previously_included:
  339. return
  340. try:
  341. fp = open(incl_abs_fname, 'rt', encoding='utf-8')
  342. except IOError as e:
  343. raise KconfigParserError(self,
  344. '%s: %s' % (e.strerror, include))
  345. inf = self.data.incl_info
  346. self.data.incl_info = { 'file': self.fname, 'line': self.line,
  347. 'parent': inf }
  348. KconfigParser(self.data).parse_file(fp)
  349. self.data.incl_info = inf
  350. # recursive descent parser -----
  351. # y_or_n: Y | N
  352. def parse_y_or_n(self):
  353. if self.tok == TOK_Y:
  354. self.get_token()
  355. return True
  356. if self.tok == TOK_N:
  357. self.get_token()
  358. return False
  359. raise KconfigParserError(self, 'Expected "y" or "n"')
  360. # var: ID
  361. def parse_var(self):
  362. if self.tok == TOK_ID:
  363. val = self.val
  364. self.get_token()
  365. return self.data.do_var(val)
  366. else:
  367. raise KconfigParserError(self, 'Expected identifier')
  368. # assignment_var: ID (starting with "CONFIG_")
  369. def parse_assignment_var(self):
  370. if self.tok == TOK_ID:
  371. val = self.val
  372. if not val.startswith("CONFIG_"):
  373. raise KconfigParserError(self,
  374. 'Expected identifier starting with "CONFIG_"', TOK_NONE)
  375. self.get_token()
  376. return self.data.do_var(val[7:])
  377. else:
  378. raise KconfigParserError(self, 'Expected identifier')
  379. # assignment: var EQUAL y_or_n
  380. def parse_assignment(self):
  381. var = self.parse_assignment_var()
  382. if self.tok != TOK_EQUAL:
  383. raise KconfigParserError(self, 'Expected "="')
  384. self.get_token()
  385. self.data.do_assignment(var, self.parse_y_or_n())
  386. # primary: NOT primary
  387. # | LPAREN expr RPAREN
  388. # | var
  389. def parse_primary(self):
  390. if self.tok == TOK_NOT:
  391. self.get_token()
  392. val = ~self.parse_primary()
  393. elif self.tok == TOK_LPAREN:
  394. self.get_token()
  395. val = self.parse_expr()
  396. if self.tok != TOK_RPAREN:
  397. raise KconfigParserError(self, 'Expected ")"')
  398. self.get_token()
  399. elif self.tok == TOK_ID:
  400. val = self.parse_var()
  401. else:
  402. raise KconfigParserError(self, 'Expected "!" or "(" or identifier')
  403. return val
  404. # disj: primary (OR primary)*
  405. def parse_disj(self):
  406. lhs = self.parse_primary()
  407. while self.tok == TOK_OR:
  408. self.get_token()
  409. lhs = lhs | self.parse_primary()
  410. return lhs
  411. # expr: disj (AND disj)*
  412. def parse_expr(self):
  413. lhs = self.parse_disj()
  414. while self.tok == TOK_AND:
  415. self.get_token()
  416. lhs = lhs & self.parse_disj()
  417. return lhs
  418. # condition: IF expr
  419. # | empty
  420. def parse_condition(self):
  421. if self.tok == TOK_IF:
  422. self.get_token()
  423. return self.parse_expr()
  424. else:
  425. return None
  426. # property: DEFAULT y_or_n condition
  427. # | DEPENDS ON expr
  428. # | SELECT var condition
  429. # | BOOL
  430. def parse_property(self, var):
  431. if self.tok == TOK_DEFAULT:
  432. self.get_token()
  433. val = self.parse_y_or_n()
  434. cond = self.parse_condition()
  435. self.data.do_default(var, val, cond)
  436. elif self.tok == TOK_DEPENDS:
  437. self.get_token()
  438. if self.tok != TOK_ON:
  439. raise KconfigParserError(self, 'Expected "on"')
  440. self.get_token()
  441. self.data.do_depends_on(var, self.parse_expr())
  442. elif self.tok == TOK_SELECT:
  443. self.get_token()
  444. symbol = self.parse_var()
  445. cond = self.parse_condition()
  446. self.data.do_select(var, symbol, cond)
  447. elif self.tok == TOK_IMPLY:
  448. self.get_token()
  449. symbol = self.parse_var()
  450. cond = self.parse_condition()
  451. self.data.do_imply(var, symbol, cond)
  452. elif self.tok == TOK_BOOL:
  453. self.get_token()
  454. else:
  455. raise KconfigParserError(self, 'Error in recursive descent?')
  456. # properties: properties property
  457. # | /* empty */
  458. def parse_properties(self, var):
  459. had_default = False
  460. while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \
  461. self.tok == TOK_SELECT or self.tok == TOK_BOOL or \
  462. self.tok == TOK_IMPLY:
  463. self.parse_property(var)
  464. # for nicer error message
  465. if self.tok != TOK_SOURCE and self.tok != TOK_CONFIG and \
  466. self.tok != TOK_ID and self.tok != TOK_EOF:
  467. raise KconfigParserError(self, 'expected "source", "config", identifier, '
  468. + '"default", "depends on", "imply" or "select"')
  469. # declaration: config var properties
  470. def parse_declaration(self):
  471. if self.tok == TOK_CONFIG:
  472. self.get_token()
  473. var = self.parse_var()
  474. self.data.do_declaration(var)
  475. self.parse_properties(var)
  476. else:
  477. raise KconfigParserError(self, 'Error in recursive descent?')
  478. # clause: SOURCE
  479. # | declaration
  480. # | assignment
  481. def parse_clause(self):
  482. if self.tok == TOK_SOURCE:
  483. val = self.val
  484. self.get_token()
  485. self.do_include(val)
  486. elif self.tok == TOK_CONFIG:
  487. self.parse_declaration()
  488. elif self.tok == TOK_ID:
  489. self.parse_assignment()
  490. else:
  491. raise KconfigParserError(self, 'expected "source", "config" or identifier')
  492. # config: clause+ EOF
  493. def parse_config(self):
  494. while self.tok != TOK_EOF:
  495. self.parse_clause()
  496. return self.data
  497. # scanner -----
  498. def get_token(self):
  499. while True:
  500. self.tok = self.src[self.cursor]
  501. self.pos = self.cursor
  502. self.cursor += 1
  503. self.val = None
  504. self.tok = self.scan_token()
  505. if self.tok is not None:
  506. return
  507. def check_keyword(self, rest):
  508. if not self.src.startswith(rest, self.cursor):
  509. return False
  510. length = len(rest)
  511. if self.src[self.cursor + length].isalnum() or self.src[self.cursor + length] == '_':
  512. return False
  513. self.cursor += length
  514. return True
  515. def scan_token(self):
  516. if self.tok == '#':
  517. self.cursor = self.src.find('\n', self.cursor)
  518. return None
  519. elif self.tok == '=':
  520. return TOK_EQUAL
  521. elif self.tok == '(':
  522. return TOK_LPAREN
  523. elif self.tok == ')':
  524. return TOK_RPAREN
  525. elif self.tok == '&' and self.src[self.pos+1] == '&':
  526. self.cursor += 1
  527. return TOK_AND
  528. elif self.tok == '|' and self.src[self.pos+1] == '|':
  529. self.cursor += 1
  530. return TOK_OR
  531. elif self.tok == '!':
  532. return TOK_NOT
  533. elif self.tok == 'd' and self.check_keyword("epends"):
  534. return TOK_DEPENDS
  535. elif self.tok == 'o' and self.check_keyword("n"):
  536. return TOK_ON
  537. elif self.tok == 's' and self.check_keyword("elect"):
  538. return TOK_SELECT
  539. elif self.tok == 'i' and self.check_keyword("mply"):
  540. return TOK_IMPLY
  541. elif self.tok == 'c' and self.check_keyword("onfig"):
  542. return TOK_CONFIG
  543. elif self.tok == 'd' and self.check_keyword("efault"):
  544. return TOK_DEFAULT
  545. elif self.tok == 'b' and self.check_keyword("ool"):
  546. return TOK_BOOL
  547. elif self.tok == 'i' and self.check_keyword("f"):
  548. return TOK_IF
  549. elif self.tok == 'y' and self.check_keyword(""):
  550. return TOK_Y
  551. elif self.tok == 'n' and self.check_keyword(""):
  552. return TOK_N
  553. elif (self.tok == 's' and self.check_keyword("ource")) or \
  554. self.tok == 'i' and self.check_keyword("nclude"):
  555. # source FILENAME
  556. # include FILENAME
  557. while self.src[self.cursor].isspace():
  558. self.cursor += 1
  559. start = self.cursor
  560. self.cursor = self.src.find('\n', self.cursor)
  561. self.val = self.src[start:self.cursor]
  562. return TOK_SOURCE
  563. elif self.tok.isalnum():
  564. # identifier
  565. while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_':
  566. self.cursor += 1
  567. self.val = self.src[self.pos:self.cursor]
  568. return TOK_ID
  569. elif self.tok == '\n':
  570. if self.cursor == len(self.src):
  571. return TOK_EOF
  572. self.line += 1
  573. self.line_pos = self.cursor
  574. elif not self.tok.isspace():
  575. raise KconfigParserError(self, 'invalid input')
  576. return None
  577. if __name__ == '__main__':
  578. argv = sys.argv
  579. mode = defconfig
  580. if len(sys.argv) > 1:
  581. if argv[1] == '--defconfig':
  582. del argv[1]
  583. elif argv[1] == '--randconfig':
  584. random.seed()
  585. mode = randconfig
  586. del argv[1]
  587. elif argv[1] == '--allyesconfig':
  588. mode = allyesconfig
  589. del argv[1]
  590. elif argv[1] == '--allnoconfig':
  591. mode = allnoconfig
  592. del argv[1]
  593. if len(argv) == 1:
  594. print ("%s: at least one argument is required" % argv[0], file=sys.stderr)
  595. sys.exit(1)
  596. if argv[1].startswith('-'):
  597. print ("%s: invalid option %s" % (argv[0], argv[1]), file=sys.stderr)
  598. sys.exit(1)
  599. data = KconfigData(mode)
  600. parser = KconfigParser(data)
  601. external_vars = set()
  602. for arg in argv[3:]:
  603. m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg)
  604. if m is not None:
  605. name, value = m.groups()
  606. parser.do_assignment(name, value == 'y')
  607. external_vars.add(name[7:])
  608. else:
  609. fp = open(arg, 'rt', encoding='utf-8')
  610. parser.parse_file(fp)
  611. fp.close()
  612. config = data.compute_config()
  613. for key in sorted(config.keys()):
  614. if key not in external_vars and config[key]:
  615. print ('CONFIG_%s=y' % key)
  616. deps = open(argv[2], 'wt', encoding='utf-8')
  617. for fname in data.previously_included:
  618. print ('%s: %s' % (argv[1], fname), file=deps)
  619. deps.close()