blob: d89fb09271580bda81f3983e1f828b7708693d83 [file] [log] [blame]
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +08001#
2# Mini-Kconfig parser
3#
4# Copyright (c) 2015 Red Hat Inc.
5#
6# Authors:
7# Paolo Bonzini <pbonzini@redhat.com>
8#
9# This work is licensed under the terms of the GNU GPL, version 2
10# or, at your option, any later version. See the COPYING file in
11# the top-level directory.
12
13from __future__ import print_function
14import os
15import sys
16
Paolo Bonzinif7082a92019-01-23 14:55:58 +080017__all__ = [ 'KconfigDataError', 'KconfigParserError',
18 'KconfigData', 'KconfigParser' ]
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +080019
20def debug_print(*args):
21 #print('# ' + (' '.join(str(x) for x in args)))
22 pass
23
24# -------------------------------------------
25# KconfigData implements the Kconfig semantics. For now it can only
26# detect undefined symbols, i.e. symbols that were referenced in
27# assignments or dependencies but were not declared with "config FOO".
28#
29# Semantic actions are represented by methods called do_*. The do_var
30# method return the semantic value of a variable (which right now is
31# just its name).
32# -------------------------------------------
33
Paolo Bonzinif7082a92019-01-23 14:55:58 +080034class KconfigDataError(Exception):
35 def __init__(self, msg):
36 self.msg = msg
37
38 def __str__(self):
39 return self.msg
40
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +080041class KconfigData:
Paolo Bonzini53167f52019-01-23 14:55:57 +080042 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
Paolo Bonzinif7082a92019-01-23 14:55:58 +080050 # Abstract methods
51 def add_edges_to(self, var):
52 pass
53 def evaluate(self):
54 assert False
55
Paolo Bonzini53167f52019-01-23 14:55:57 +080056 class AND(Expr):
57 def __init__(self, lhs, rhs):
58 self.lhs = lhs
59 self.rhs = rhs
60 def __str__(self):
61 return "(%s && %s)" % (self.lhs, self.rhs)
62
Paolo Bonzinif7082a92019-01-23 14:55:58 +080063 def add_edges_to(self, var):
64 self.lhs.add_edges_to(var)
65 self.rhs.add_edges_to(var)
66 def evaluate(self):
67 return self.lhs.evaluate() and self.rhs.evaluate()
68
Paolo Bonzini53167f52019-01-23 14:55:57 +080069 class OR(Expr):
70 def __init__(self, lhs, rhs):
71 self.lhs = lhs
72 self.rhs = rhs
73 def __str__(self):
74 return "(%s || %s)" % (self.lhs, self.rhs)
75
Paolo Bonzinif7082a92019-01-23 14:55:58 +080076 def add_edges_to(self, var):
77 self.lhs.add_edges_to(var)
78 self.rhs.add_edges_to(var)
79 def evaluate(self):
80 return self.lhs.evaluate() or self.rhs.evaluate()
81
Paolo Bonzini53167f52019-01-23 14:55:57 +080082 class NOT(Expr):
83 def __init__(self, lhs):
84 self.lhs = lhs
85 def __str__(self):
86 return "!%s" % (self.lhs)
87
Paolo Bonzinif7082a92019-01-23 14:55:58 +080088 def add_edges_to(self, var):
89 self.lhs.add_edges_to(var)
90 def evaluate(self):
91 return not self.lhs.evaluate()
92
Paolo Bonzini53167f52019-01-23 14:55:57 +080093 class Var(Expr):
94 def __init__(self, name):
95 self.name = name
96 self.value = None
Paolo Bonzinif7082a92019-01-23 14:55:58 +080097 self.outgoing = set()
98 self.clauses_for_var = list()
Paolo Bonzini53167f52019-01-23 14:55:57 +080099 def __str__(self):
100 return self.name
101
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800102 def has_value(self):
103 return not (self.value is None)
104 def set_value(self, val, clause):
105 self.clauses_for_var.append(clause)
106 if self.has_value() and self.value != val:
107 print("The following clauses were found for " + self.name)
108 for i in self.clauses_for_var:
109 print(" " + str(i), file=sys.stderr)
110 raise KconfigDataError('contradiction between clauses when setting %s' % self)
111 debug_print("=> %s is now %s" % (self.name, val))
112 self.value = val
113
114 # depth first search of the dependency graph
115 def dfs(self, visited, f):
116 if self in visited:
117 return
118 visited.add(self)
119 for v in self.outgoing:
120 v.dfs(visited, f)
121 f(self)
122
123 def add_edges_to(self, var):
124 self.outgoing.add(var)
125 def evaluate(self):
126 if not self.has_value():
127 raise KconfigDataError('cycle found including %s' % self)
128 return self.value
129
Paolo Bonzini53167f52019-01-23 14:55:57 +0800130 class Clause:
131 def __init__(self, dest):
132 self.dest = dest
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800133 def priority(self):
134 return 0
135 def process(self):
136 pass
Paolo Bonzini53167f52019-01-23 14:55:57 +0800137
138 class AssignmentClause(Clause):
139 def __init__(self, dest, value):
140 KconfigData.Clause.__init__(self, dest)
141 self.value = value
142 def __str__(self):
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800143 return "CONFIG_%s=%s" % (self.dest, 'y' if self.value else 'n')
144
145 def process(self):
146 self.dest.set_value(self.value, self)
Paolo Bonzini53167f52019-01-23 14:55:57 +0800147
148 class DefaultClause(Clause):
149 def __init__(self, dest, value, cond=None):
150 KconfigData.Clause.__init__(self, dest)
151 self.value = value
152 self.cond = cond
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800153 if not (self.cond is None):
154 self.cond.add_edges_to(self.dest)
Paolo Bonzini53167f52019-01-23 14:55:57 +0800155 def __str__(self):
156 value = 'y' if self.value else 'n'
157 if self.cond is None:
158 return "config %s default %s" % (self.dest, value)
159 else:
160 return "config %s default %s if %s" % (self.dest, value, self.cond)
161
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800162 def priority(self):
163 # Defaults are processed just before leaving the variable
164 return -1
165 def process(self):
166 if not self.dest.has_value() and \
167 (self.cond is None or self.cond.evaluate()):
168 self.dest.set_value(self.value, self)
169
Paolo Bonzini53167f52019-01-23 14:55:57 +0800170 class DependsOnClause(Clause):
171 def __init__(self, dest, expr):
172 KconfigData.Clause.__init__(self, dest)
173 self.expr = expr
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800174 self.expr.add_edges_to(self.dest)
Paolo Bonzini53167f52019-01-23 14:55:57 +0800175 def __str__(self):
176 return "config %s depends on %s" % (self.dest, self.expr)
177
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800178 def process(self):
179 if not self.expr.evaluate():
180 self.dest.set_value(False, self)
181
Paolo Bonzini53167f52019-01-23 14:55:57 +0800182 class SelectClause(Clause):
183 def __init__(self, dest, cond):
184 KconfigData.Clause.__init__(self, dest)
185 self.cond = cond
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800186 self.cond.add_edges_to(self.dest)
Paolo Bonzini53167f52019-01-23 14:55:57 +0800187 def __str__(self):
188 return "select %s if %s" % (self.dest, self.cond)
189
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800190 def process(self):
191 if self.cond.evaluate():
192 self.dest.set_value(True, self)
193
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800194 def __init__(self):
195 self.previously_included = []
196 self.incl_info = None
197 self.defined_vars = set()
Paolo Bonzini53167f52019-01-23 14:55:57 +0800198 self.referenced_vars = dict()
199 self.clauses = list()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800200
201 # semantic analysis -------------
202
203 def check_undefined(self):
204 undef = False
205 for i in self.referenced_vars:
206 if not (i in self.defined_vars):
207 print("undefined symbol %s" % (i), file=sys.stderr)
208 undef = True
209 return undef
210
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800211 def compute_config(self):
212 if self.check_undefined():
213 raise KconfigDataError("there were undefined symbols")
214 return None
215
216 debug_print("Input:")
217 for clause in self.clauses:
218 debug_print(clause)
219
220 debug_print("\nDependency graph:")
221 for i in self.referenced_vars:
222 debug_print(i, "->", [str(x) for x in self.referenced_vars[i].outgoing])
223
224 # The reverse of the depth-first order is the topological sort
225 dfo = dict()
226 visited = set()
227 debug_print("\n")
228 def visit_fn(var):
229 debug_print(var, "has DFS number", len(dfo))
230 dfo[var] = len(dfo)
231
232 for name, v in self.referenced_vars.items():
233 self.do_default(v, False)
234 v.dfs(visited, visit_fn)
235
236 # Put higher DFS numbers and higher priorities first. This
237 # places the clauses in topological order and places defaults
238 # after assignments and dependencies.
239 self.clauses.sort(key=lambda x: (-dfo[x.dest], -x.priority()))
240
241 debug_print("\nSorted clauses:")
242 for clause in self.clauses:
243 debug_print(clause)
244 clause.process()
245
246 debug_print("")
247 values = dict()
248 for name, v in self.referenced_vars.items():
249 debug_print("Evaluating", name)
250 values[name] = v.evaluate()
251
252 return values
253
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800254 # semantic actions -------------
255
256 def do_declaration(self, var):
257 if (var in self.defined_vars):
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800258 raise KconfigDataError('variable "' + var + '" defined twice')
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800259
Paolo Bonzini53167f52019-01-23 14:55:57 +0800260 self.defined_vars.add(var.name)
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800261
262 # var is a string with the variable's name.
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800263 def do_var(self, var):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800264 if (var in self.referenced_vars):
265 return self.referenced_vars[var]
266
267 var_obj = self.referenced_vars[var] = KconfigData.Var(var)
268 return var_obj
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800269
270 def do_assignment(self, var, val):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800271 self.clauses.append(KconfigData.AssignmentClause(var, val))
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800272
273 def do_default(self, var, val, cond=None):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800274 self.clauses.append(KconfigData.DefaultClause(var, val, cond))
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800275
276 def do_depends_on(self, var, expr):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800277 self.clauses.append(KconfigData.DependsOnClause(var, expr))
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800278
279 def do_select(self, var, symbol, cond=None):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800280 cond = (cond & var) if cond is not None else var
281 self.clauses.append(KconfigData.SelectClause(symbol, cond))
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800282
283 def do_imply(self, var, symbol, cond=None):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800284 # "config X imply Y [if COND]" is the same as
285 # "config Y default y if X [&& COND]"
286 cond = (cond & var) if cond is not None else var
287 self.do_default(symbol, True, cond)
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800288
289# -------------------------------------------
290# KconfigParser implements a recursive descent parser for (simplified)
291# Kconfig syntax.
292# -------------------------------------------
293
294# tokens table
295TOKENS = {}
296TOK_NONE = -1
297TOK_LPAREN = 0; TOKENS[TOK_LPAREN] = '"("';
298TOK_RPAREN = 1; TOKENS[TOK_RPAREN] = '")"';
299TOK_EQUAL = 2; TOKENS[TOK_EQUAL] = '"="';
300TOK_AND = 3; TOKENS[TOK_AND] = '"&&"';
301TOK_OR = 4; TOKENS[TOK_OR] = '"||"';
302TOK_NOT = 5; TOKENS[TOK_NOT] = '"!"';
303TOK_DEPENDS = 6; TOKENS[TOK_DEPENDS] = '"depends"';
304TOK_ON = 7; TOKENS[TOK_ON] = '"on"';
305TOK_SELECT = 8; TOKENS[TOK_SELECT] = '"select"';
306TOK_IMPLY = 9; TOKENS[TOK_IMPLY] = '"imply"';
307TOK_CONFIG = 10; TOKENS[TOK_CONFIG] = '"config"';
308TOK_DEFAULT = 11; TOKENS[TOK_DEFAULT] = '"default"';
309TOK_Y = 12; TOKENS[TOK_Y] = '"y"';
310TOK_N = 13; TOKENS[TOK_N] = '"n"';
311TOK_SOURCE = 14; TOKENS[TOK_SOURCE] = '"source"';
312TOK_BOOL = 15; TOKENS[TOK_BOOL] = '"bool"';
313TOK_IF = 16; TOKENS[TOK_IF] = '"if"';
314TOK_ID = 17; TOKENS[TOK_ID] = 'identifier';
315TOK_EOF = 18; TOKENS[TOK_EOF] = 'end of file';
316
317class KconfigParserError(Exception):
318 def __init__(self, parser, msg, tok=None):
319 self.loc = parser.location()
320 tok = tok or parser.tok
321 if tok != TOK_NONE:
322 location = TOKENS.get(tok, None) or ('"%s"' % tok)
323 msg = '%s before %s' % (msg, location)
324 self.msg = msg
325
326 def __str__(self):
327 return "%s: %s" % (self.loc, self.msg)
328
329class KconfigParser:
330 @classmethod
331 def parse(self, fp):
332 data = KconfigData()
333 parser = KconfigParser(data)
334 parser.parse_file(fp)
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800335 return data
336
337 def __init__(self, data):
338 self.data = data
339
340 def parse_file(self, fp):
341 self.abs_fname = os.path.abspath(fp.name)
342 self.fname = fp.name
343 self.data.previously_included.append(self.abs_fname)
344 self.src = fp.read()
345 if self.src == '' or self.src[-1] != '\n':
346 self.src += '\n'
347 self.cursor = 0
348 self.line = 1
349 self.line_pos = 0
350 self.get_token()
351 self.parse_config()
352
353 # file management -----
354
355 def error_path(self):
356 inf = self.data.incl_info
357 res = ""
358 while inf:
359 res = ("In file included from %s:%d:\n" % (inf['file'],
360 inf['line'])) + res
361 inf = inf['parent']
362 return res
363
364 def location(self):
365 col = 1
366 for ch in self.src[self.line_pos:self.pos]:
367 if ch == '\t':
368 col += 8 - ((col - 1) % 8)
369 else:
370 col += 1
371 return '%s%s:%d:%d' %(self.error_path(), self.fname, self.line, col)
372
373 def do_include(self, include):
374 incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname),
375 include)
376 # catch inclusion cycle
377 inf = self.data.incl_info
378 while inf:
379 if incl_abs_fname == os.path.abspath(inf['file']):
380 raise KconfigParserError(self, "Inclusion loop for %s"
381 % include)
382 inf = inf['parent']
383
384 # skip multiple include of the same file
385 if incl_abs_fname in self.data.previously_included:
386 return
387 try:
388 fp = open(incl_abs_fname, 'r')
389 except IOError as e:
390 raise KconfigParserError(self,
391 '%s: %s' % (e.strerror, include))
392
393 inf = self.data.incl_info
394 self.data.incl_info = { 'file': self.fname, 'line': self.line,
395 'parent': inf }
396 KconfigParser(self.data).parse_file(fp)
397 self.data.incl_info = inf
398
399 # recursive descent parser -----
400
401 # y_or_n: Y | N
402 def parse_y_or_n(self):
403 if self.tok == TOK_Y:
404 self.get_token()
405 return True
406 if self.tok == TOK_N:
407 self.get_token()
408 return False
409 raise KconfigParserError(self, 'Expected "y" or "n"')
410
411 # var: ID
412 def parse_var(self):
413 if self.tok == TOK_ID:
414 val = self.val
415 self.get_token()
416 return self.data.do_var(val)
417 else:
418 raise KconfigParserError(self, 'Expected identifier')
419
420 # assignment_var: ID (starting with "CONFIG_")
421 def parse_assignment_var(self):
422 if self.tok == TOK_ID:
423 val = self.val
424 if not val.startswith("CONFIG_"):
425 raise KconfigParserError(self,
426 'Expected identifier starting with "CONFIG_"', TOK_NONE)
427 self.get_token()
428 return self.data.do_var(val[7:])
429 else:
430 raise KconfigParserError(self, 'Expected identifier')
431
432 # assignment: var EQUAL y_or_n
433 def parse_assignment(self):
434 var = self.parse_assignment_var()
435 if self.tok != TOK_EQUAL:
436 raise KconfigParserError(self, 'Expected "="')
437 self.get_token()
438 self.data.do_assignment(var, self.parse_y_or_n())
439
440 # primary: NOT primary
441 # | LPAREN expr RPAREN
442 # | var
443 def parse_primary(self):
444 if self.tok == TOK_NOT:
445 self.get_token()
Paolo Bonzini53167f52019-01-23 14:55:57 +0800446 val = ~self.parse_primary()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800447 elif self.tok == TOK_LPAREN:
448 self.get_token()
Paolo Bonzini53167f52019-01-23 14:55:57 +0800449 val = self.parse_expr()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800450 if self.tok != TOK_RPAREN:
451 raise KconfigParserError(self, 'Expected ")"')
452 self.get_token()
453 elif self.tok == TOK_ID:
Paolo Bonzini53167f52019-01-23 14:55:57 +0800454 val = self.parse_var()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800455 else:
456 raise KconfigParserError(self, 'Expected "!" or "(" or identifier')
Paolo Bonzini53167f52019-01-23 14:55:57 +0800457 return val
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800458
459 # disj: primary (OR primary)*
460 def parse_disj(self):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800461 lhs = self.parse_primary()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800462 while self.tok == TOK_OR:
463 self.get_token()
Paolo Bonzini53167f52019-01-23 14:55:57 +0800464 lhs = lhs | self.parse_primary()
465 return lhs
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800466
467 # expr: disj (AND disj)*
468 def parse_expr(self):
Paolo Bonzini53167f52019-01-23 14:55:57 +0800469 lhs = self.parse_disj()
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800470 while self.tok == TOK_AND:
471 self.get_token()
Paolo Bonzini53167f52019-01-23 14:55:57 +0800472 lhs = lhs & self.parse_disj()
473 return lhs
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800474
475 # condition: IF expr
476 # | empty
477 def parse_condition(self):
478 if self.tok == TOK_IF:
479 self.get_token()
480 return self.parse_expr()
481 else:
482 return None
483
484 # property: DEFAULT y_or_n condition
485 # | DEPENDS ON expr
486 # | SELECT var condition
487 # | BOOL
488 def parse_property(self, var):
489 if self.tok == TOK_DEFAULT:
490 self.get_token()
491 val = self.parse_y_or_n()
492 cond = self.parse_condition()
493 self.data.do_default(var, val, cond)
494 elif self.tok == TOK_DEPENDS:
495 self.get_token()
496 if self.tok != TOK_ON:
497 raise KconfigParserError(self, 'Expected "on"')
498 self.get_token()
499 self.data.do_depends_on(var, self.parse_expr())
500 elif self.tok == TOK_SELECT:
501 self.get_token()
502 symbol = self.parse_var()
503 cond = self.parse_condition()
504 self.data.do_select(var, symbol, cond)
505 elif self.tok == TOK_IMPLY:
506 self.get_token()
507 symbol = self.parse_var()
508 cond = self.parse_condition()
509 self.data.do_imply(var, symbol, cond)
510 elif self.tok == TOK_BOOL:
511 self.get_token()
512 else:
513 raise KconfigParserError(self, 'Error in recursive descent?')
514
515 # properties: properties property
516 # | /* empty */
517 def parse_properties(self, var):
518 had_default = False
519 while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \
520 self.tok == TOK_SELECT or self.tok == TOK_BOOL or \
521 self.tok == TOK_IMPLY:
522 self.parse_property(var)
Paolo Bonzinid4fdcca2019-01-23 14:55:56 +0800523
524 # for nicer error message
525 if self.tok != TOK_SOURCE and self.tok != TOK_CONFIG and \
526 self.tok != TOK_ID and self.tok != TOK_EOF:
527 raise KconfigParserError(self, 'expected "source", "config", identifier, '
528 + '"default", "depends on", "imply" or "select"')
529
530 # declaration: config var properties
531 def parse_declaration(self):
532 if self.tok == TOK_CONFIG:
533 self.get_token()
534 var = self.parse_var()
535 self.data.do_declaration(var)
536 self.parse_properties(var)
537 else:
538 raise KconfigParserError(self, 'Error in recursive descent?')
539
540 # clause: SOURCE
541 # | declaration
542 # | assignment
543 def parse_clause(self):
544 if self.tok == TOK_SOURCE:
545 val = self.val
546 self.get_token()
547 self.do_include(val)
548 elif self.tok == TOK_CONFIG:
549 self.parse_declaration()
550 elif self.tok == TOK_ID:
551 self.parse_assignment()
552 else:
553 raise KconfigParserError(self, 'expected "source", "config" or identifier')
554
555 # config: clause+ EOF
556 def parse_config(self):
557 while self.tok != TOK_EOF:
558 self.parse_clause()
559 return self.data
560
561 # scanner -----
562
563 def get_token(self):
564 while True:
565 self.tok = self.src[self.cursor]
566 self.pos = self.cursor
567 self.cursor += 1
568
569 self.val = None
570 self.tok = self.scan_token()
571 if self.tok is not None:
572 return
573
574 def check_keyword(self, rest):
575 if not self.src.startswith(rest, self.cursor):
576 return False
577 length = len(rest)
578 if self.src[self.cursor + length].isalnum() or self.src[self.cursor + length] == '|':
579 return False
580 self.cursor += length
581 return True
582
583 def scan_token(self):
584 if self.tok == '#':
585 self.cursor = self.src.find('\n', self.cursor)
586 return None
587 elif self.tok == '=':
588 return TOK_EQUAL
589 elif self.tok == '(':
590 return TOK_LPAREN
591 elif self.tok == ')':
592 return TOK_RPAREN
593 elif self.tok == '&' and self.src[self.pos+1] == '&':
594 self.cursor += 1
595 return TOK_AND
596 elif self.tok == '|' and self.src[self.pos+1] == '|':
597 self.cursor += 1
598 return TOK_OR
599 elif self.tok == '!':
600 return TOK_NOT
601 elif self.tok == 'd' and self.check_keyword("epends"):
602 return TOK_DEPENDS
603 elif self.tok == 'o' and self.check_keyword("n"):
604 return TOK_ON
605 elif self.tok == 's' and self.check_keyword("elect"):
606 return TOK_SELECT
607 elif self.tok == 'i' and self.check_keyword("mply"):
608 return TOK_IMPLY
609 elif self.tok == 'c' and self.check_keyword("onfig"):
610 return TOK_CONFIG
611 elif self.tok == 'd' and self.check_keyword("efault"):
612 return TOK_DEFAULT
613 elif self.tok == 'b' and self.check_keyword("ool"):
614 return TOK_BOOL
615 elif self.tok == 'i' and self.check_keyword("f"):
616 return TOK_IF
617 elif self.tok == 'y' and self.check_keyword(""):
618 return TOK_Y
619 elif self.tok == 'n' and self.check_keyword(""):
620 return TOK_N
621 elif (self.tok == 's' and self.check_keyword("ource")) or \
622 self.tok == 'i' and self.check_keyword("nclude"):
623 # source FILENAME
624 # include FILENAME
625 while self.src[self.cursor].isspace():
626 self.cursor += 1
627 start = self.cursor
628 self.cursor = self.src.find('\n', self.cursor)
629 self.val = self.src[start:self.cursor]
630 return TOK_SOURCE
631 elif self.tok.isalpha():
632 # identifier
633 while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_':
634 self.cursor += 1
635 self.val = self.src[self.pos:self.cursor]
636 return TOK_ID
637 elif self.tok == '\n':
638 if self.cursor == len(self.src):
639 return TOK_EOF
640 self.line += 1
641 self.line_pos = self.cursor
642 elif not self.tok.isspace():
643 raise KconfigParserError(self, 'invalid input')
644
645 return None
646
647if __name__ == '__main__':
648 fname = len(sys.argv) > 1 and sys.argv[1] or 'Kconfig.test'
Paolo Bonzini53167f52019-01-23 14:55:57 +0800649 data = KconfigParser.parse(open(fname, 'r'))
Paolo Bonzinif7082a92019-01-23 14:55:58 +0800650 print data.compute_config()