xref: /openbmc/qemu/scripts/minikconf.py (revision b5ab62b3c0050612c7f9b0b4baeb44ebab42775a)
1b92e7daeSPhilippe Mathieu-Daudé#!/usr/bin/env python3
2d4fdccadSPaolo Bonzini#
3d4fdccadSPaolo Bonzini# Mini-Kconfig parser
4d4fdccadSPaolo Bonzini#
5d4fdccadSPaolo Bonzini# Copyright (c) 2015 Red Hat Inc.
6d4fdccadSPaolo Bonzini#
7d4fdccadSPaolo Bonzini# Authors:
8d4fdccadSPaolo Bonzini#  Paolo Bonzini <pbonzini@redhat.com>
9d4fdccadSPaolo Bonzini#
10d4fdccadSPaolo Bonzini# This work is licensed under the terms of the GNU GPL, version 2
11d4fdccadSPaolo Bonzini# or, at your option, any later version.  See the COPYING file in
12d4fdccadSPaolo Bonzini# the top-level directory.
13d4fdccadSPaolo Bonzini
14d4fdccadSPaolo Bonziniimport os
15d4fdccadSPaolo Bonziniimport sys
1682f51817SPaolo Bonziniimport re
17f3494749SPaolo Bonziniimport random
18d4fdccadSPaolo Bonzini
19f7082a9aSPaolo Bonzini__all__ = [ 'KconfigDataError', 'KconfigParserError',
20f3494749SPaolo Bonzini            'KconfigData', 'KconfigParser' ,
21f3494749SPaolo Bonzini            'defconfig', 'allyesconfig', 'allnoconfig', 'randconfig' ]
22d4fdccadSPaolo Bonzini
23d4fdccadSPaolo Bonzinidef debug_print(*args):
24d4fdccadSPaolo Bonzini    #print('# ' + (' '.join(str(x) for x in args)))
25d4fdccadSPaolo Bonzini    pass
26d4fdccadSPaolo Bonzini
27d4fdccadSPaolo Bonzini# -------------------------------------------
28d4fdccadSPaolo Bonzini# KconfigData implements the Kconfig semantics.  For now it can only
29d4fdccadSPaolo Bonzini# detect undefined symbols, i.e. symbols that were referenced in
30d4fdccadSPaolo Bonzini# assignments or dependencies but were not declared with "config FOO".
31d4fdccadSPaolo Bonzini#
32d4fdccadSPaolo Bonzini# Semantic actions are represented by methods called do_*.  The do_var
33d4fdccadSPaolo Bonzini# method return the semantic value of a variable (which right now is
34d4fdccadSPaolo Bonzini# just its name).
35d4fdccadSPaolo Bonzini# -------------------------------------------
36d4fdccadSPaolo Bonzini
37f7082a9aSPaolo Bonziniclass KconfigDataError(Exception):
38f7082a9aSPaolo Bonzini    def __init__(self, msg):
39f7082a9aSPaolo Bonzini        self.msg = msg
40f7082a9aSPaolo Bonzini
41f7082a9aSPaolo Bonzini    def __str__(self):
42f7082a9aSPaolo Bonzini        return self.msg
43f7082a9aSPaolo Bonzini
44f3494749SPaolo Bonziniallyesconfig = lambda x: True
45f3494749SPaolo Bonziniallnoconfig = lambda x: False
46f3494749SPaolo Bonzinidefconfig = lambda x: x
47f3494749SPaolo Bonzinirandconfig = lambda x: random.randint(0, 1) == 1
48f3494749SPaolo Bonzini
49d4fdccadSPaolo Bonziniclass KconfigData:
5053167f56SPaolo Bonzini    class Expr:
5153167f56SPaolo Bonzini        def __and__(self, rhs):
5253167f56SPaolo Bonzini            return KconfigData.AND(self, rhs)
5353167f56SPaolo Bonzini        def __or__(self, rhs):
5453167f56SPaolo Bonzini            return KconfigData.OR(self, rhs)
5553167f56SPaolo Bonzini        def __invert__(self):
5653167f56SPaolo Bonzini            return KconfigData.NOT(self)
5753167f56SPaolo Bonzini
58f7082a9aSPaolo Bonzini        # Abstract methods
59f7082a9aSPaolo Bonzini        def add_edges_to(self, var):
60f7082a9aSPaolo Bonzini            pass
61f7082a9aSPaolo Bonzini        def evaluate(self):
62f7082a9aSPaolo Bonzini            assert False
63f7082a9aSPaolo Bonzini
6453167f56SPaolo Bonzini    class AND(Expr):
6553167f56SPaolo Bonzini        def __init__(self, lhs, rhs):
6653167f56SPaolo Bonzini            self.lhs = lhs
6753167f56SPaolo Bonzini            self.rhs = rhs
6853167f56SPaolo Bonzini        def __str__(self):
6953167f56SPaolo Bonzini            return "(%s && %s)" % (self.lhs, self.rhs)
7053167f56SPaolo Bonzini
71f7082a9aSPaolo Bonzini        def add_edges_to(self, var):
72f7082a9aSPaolo Bonzini            self.lhs.add_edges_to(var)
73f7082a9aSPaolo Bonzini            self.rhs.add_edges_to(var)
74f7082a9aSPaolo Bonzini        def evaluate(self):
75f7082a9aSPaolo Bonzini            return self.lhs.evaluate() and self.rhs.evaluate()
76f7082a9aSPaolo Bonzini
7753167f56SPaolo Bonzini    class OR(Expr):
7853167f56SPaolo Bonzini        def __init__(self, lhs, rhs):
7953167f56SPaolo Bonzini            self.lhs = lhs
8053167f56SPaolo Bonzini            self.rhs = rhs
8153167f56SPaolo Bonzini        def __str__(self):
8253167f56SPaolo Bonzini            return "(%s || %s)" % (self.lhs, self.rhs)
8353167f56SPaolo Bonzini
84f7082a9aSPaolo Bonzini        def add_edges_to(self, var):
85f7082a9aSPaolo Bonzini            self.lhs.add_edges_to(var)
86f7082a9aSPaolo Bonzini            self.rhs.add_edges_to(var)
87f7082a9aSPaolo Bonzini        def evaluate(self):
88f7082a9aSPaolo Bonzini            return self.lhs.evaluate() or self.rhs.evaluate()
89f7082a9aSPaolo Bonzini
9053167f56SPaolo Bonzini    class NOT(Expr):
9153167f56SPaolo Bonzini        def __init__(self, lhs):
9253167f56SPaolo Bonzini            self.lhs = lhs
9353167f56SPaolo Bonzini        def __str__(self):
9453167f56SPaolo Bonzini            return "!%s" % (self.lhs)
9553167f56SPaolo Bonzini
96f7082a9aSPaolo Bonzini        def add_edges_to(self, var):
97f7082a9aSPaolo Bonzini            self.lhs.add_edges_to(var)
98f7082a9aSPaolo Bonzini        def evaluate(self):
99f7082a9aSPaolo Bonzini            return not self.lhs.evaluate()
100f7082a9aSPaolo Bonzini
10153167f56SPaolo Bonzini    class Var(Expr):
10253167f56SPaolo Bonzini        def __init__(self, name):
10353167f56SPaolo Bonzini            self.name = name
10453167f56SPaolo Bonzini            self.value = None
105f7082a9aSPaolo Bonzini            self.outgoing = set()
106f7082a9aSPaolo Bonzini            self.clauses_for_var = list()
10753167f56SPaolo Bonzini        def __str__(self):
10853167f56SPaolo Bonzini            return self.name
10953167f56SPaolo Bonzini
110f7082a9aSPaolo Bonzini        def has_value(self):
111f7082a9aSPaolo Bonzini            return not (self.value is None)
112f7082a9aSPaolo Bonzini        def set_value(self, val, clause):
113f7082a9aSPaolo Bonzini            self.clauses_for_var.append(clause)
114f7082a9aSPaolo Bonzini            if self.has_value() and self.value != val:
115*f9423e9fSPaolo Bonzini                print("The following clauses were found for " + self.name, file=sys.stderr)
116f7082a9aSPaolo Bonzini                for i in self.clauses_for_var:
117f7082a9aSPaolo Bonzini                    print("    " + str(i), file=sys.stderr)
118f7082a9aSPaolo Bonzini                raise KconfigDataError('contradiction between clauses when setting %s' % self)
119f7082a9aSPaolo Bonzini            debug_print("=> %s is now %s" % (self.name, val))
120f7082a9aSPaolo Bonzini            self.value = val
121f7082a9aSPaolo Bonzini
122f7082a9aSPaolo Bonzini        # depth first search of the dependency graph
123f7082a9aSPaolo Bonzini        def dfs(self, visited, f):
124f7082a9aSPaolo Bonzini            if self in visited:
125f7082a9aSPaolo Bonzini                return
126f7082a9aSPaolo Bonzini            visited.add(self)
127f7082a9aSPaolo Bonzini            for v in self.outgoing:
128f7082a9aSPaolo Bonzini                v.dfs(visited, f)
129f7082a9aSPaolo Bonzini            f(self)
130f7082a9aSPaolo Bonzini
131f7082a9aSPaolo Bonzini        def add_edges_to(self, var):
132f7082a9aSPaolo Bonzini            self.outgoing.add(var)
133f7082a9aSPaolo Bonzini        def evaluate(self):
134f7082a9aSPaolo Bonzini            if not self.has_value():
135f7082a9aSPaolo Bonzini                raise KconfigDataError('cycle found including %s' % self)
136f7082a9aSPaolo Bonzini            return self.value
137f7082a9aSPaolo Bonzini
13853167f56SPaolo Bonzini    class Clause:
13953167f56SPaolo Bonzini        def __init__(self, dest):
14053167f56SPaolo Bonzini            self.dest = dest
141f7082a9aSPaolo Bonzini        def priority(self):
142f7082a9aSPaolo Bonzini            return 0
143f7082a9aSPaolo Bonzini        def process(self):
144f7082a9aSPaolo Bonzini            pass
14553167f56SPaolo Bonzini
14653167f56SPaolo Bonzini    class AssignmentClause(Clause):
14753167f56SPaolo Bonzini        def __init__(self, dest, value):
14853167f56SPaolo Bonzini            KconfigData.Clause.__init__(self, dest)
14953167f56SPaolo Bonzini            self.value = value
15053167f56SPaolo Bonzini        def __str__(self):
151f7082a9aSPaolo Bonzini            return "CONFIG_%s=%s" % (self.dest, 'y' if self.value else 'n')
152f7082a9aSPaolo Bonzini
153f7082a9aSPaolo Bonzini        def process(self):
154f7082a9aSPaolo Bonzini            self.dest.set_value(self.value, self)
15553167f56SPaolo Bonzini
15653167f56SPaolo Bonzini    class DefaultClause(Clause):
15753167f56SPaolo Bonzini        def __init__(self, dest, value, cond=None):
15853167f56SPaolo Bonzini            KconfigData.Clause.__init__(self, dest)
15953167f56SPaolo Bonzini            self.value = value
16053167f56SPaolo Bonzini            self.cond = cond
161f7082a9aSPaolo Bonzini            if not (self.cond is None):
162f7082a9aSPaolo Bonzini                self.cond.add_edges_to(self.dest)
16353167f56SPaolo Bonzini        def __str__(self):
16453167f56SPaolo Bonzini            value = 'y' if self.value else 'n'
16553167f56SPaolo Bonzini            if self.cond is None:
16653167f56SPaolo Bonzini                return "config %s default %s" % (self.dest, value)
16753167f56SPaolo Bonzini            else:
16853167f56SPaolo Bonzini                return "config %s default %s if %s" % (self.dest, value, self.cond)
16953167f56SPaolo Bonzini
170f7082a9aSPaolo Bonzini        def priority(self):
171f7082a9aSPaolo Bonzini            # Defaults are processed just before leaving the variable
172f7082a9aSPaolo Bonzini            return -1
173f7082a9aSPaolo Bonzini        def process(self):
174f7082a9aSPaolo Bonzini            if not self.dest.has_value() and \
175f7082a9aSPaolo Bonzini                    (self.cond is None or self.cond.evaluate()):
176f7082a9aSPaolo Bonzini                self.dest.set_value(self.value, self)
177f7082a9aSPaolo Bonzini
17853167f56SPaolo Bonzini    class DependsOnClause(Clause):
17953167f56SPaolo Bonzini        def __init__(self, dest, expr):
18053167f56SPaolo Bonzini            KconfigData.Clause.__init__(self, dest)
18153167f56SPaolo Bonzini            self.expr = expr
182f7082a9aSPaolo Bonzini            self.expr.add_edges_to(self.dest)
18353167f56SPaolo Bonzini        def __str__(self):
18453167f56SPaolo Bonzini            return "config %s depends on %s" % (self.dest, self.expr)
18553167f56SPaolo Bonzini
186f7082a9aSPaolo Bonzini        def process(self):
187f7082a9aSPaolo Bonzini            if not self.expr.evaluate():
188f7082a9aSPaolo Bonzini                self.dest.set_value(False, self)
189f7082a9aSPaolo Bonzini
19053167f56SPaolo Bonzini    class SelectClause(Clause):
19153167f56SPaolo Bonzini        def __init__(self, dest, cond):
19253167f56SPaolo Bonzini            KconfigData.Clause.__init__(self, dest)
19353167f56SPaolo Bonzini            self.cond = cond
194f7082a9aSPaolo Bonzini            self.cond.add_edges_to(self.dest)
19553167f56SPaolo Bonzini        def __str__(self):
19653167f56SPaolo Bonzini            return "select %s if %s" % (self.dest, self.cond)
19753167f56SPaolo Bonzini
198f7082a9aSPaolo Bonzini        def process(self):
199f7082a9aSPaolo Bonzini            if self.cond.evaluate():
200f7082a9aSPaolo Bonzini                self.dest.set_value(True, self)
201f7082a9aSPaolo Bonzini
202f3494749SPaolo Bonzini    def __init__(self, value_mangler=defconfig):
203f3494749SPaolo Bonzini        self.value_mangler = value_mangler
204d4fdccadSPaolo Bonzini        self.previously_included = []
205d4fdccadSPaolo Bonzini        self.incl_info = None
206d4fdccadSPaolo Bonzini        self.defined_vars = set()
20753167f56SPaolo Bonzini        self.referenced_vars = dict()
20853167f56SPaolo Bonzini        self.clauses = list()
209d4fdccadSPaolo Bonzini
210d4fdccadSPaolo Bonzini    # semantic analysis -------------
211d4fdccadSPaolo Bonzini
212d4fdccadSPaolo Bonzini    def check_undefined(self):
213d4fdccadSPaolo Bonzini        undef = False
214d4fdccadSPaolo Bonzini        for i in self.referenced_vars:
215d4fdccadSPaolo Bonzini            if not (i in self.defined_vars):
216d4fdccadSPaolo Bonzini                print("undefined symbol %s" % (i), file=sys.stderr)
217d4fdccadSPaolo Bonzini                undef = True
218d4fdccadSPaolo Bonzini        return undef
219d4fdccadSPaolo Bonzini
220f7082a9aSPaolo Bonzini    def compute_config(self):
221f7082a9aSPaolo Bonzini        if self.check_undefined():
222f7082a9aSPaolo Bonzini            raise KconfigDataError("there were undefined symbols")
223f7082a9aSPaolo Bonzini            return None
224f7082a9aSPaolo Bonzini
225f7082a9aSPaolo Bonzini        debug_print("Input:")
226f7082a9aSPaolo Bonzini        for clause in self.clauses:
227f7082a9aSPaolo Bonzini            debug_print(clause)
228f7082a9aSPaolo Bonzini
229f7082a9aSPaolo Bonzini        debug_print("\nDependency graph:")
230f7082a9aSPaolo Bonzini        for i in self.referenced_vars:
231f7082a9aSPaolo Bonzini            debug_print(i, "->", [str(x) for x in self.referenced_vars[i].outgoing])
232f7082a9aSPaolo Bonzini
233f7082a9aSPaolo Bonzini        # The reverse of the depth-first order is the topological sort
234f7082a9aSPaolo Bonzini        dfo = dict()
235f7082a9aSPaolo Bonzini        visited = set()
236f7082a9aSPaolo Bonzini        debug_print("\n")
237f7082a9aSPaolo Bonzini        def visit_fn(var):
238f7082a9aSPaolo Bonzini            debug_print(var, "has DFS number", len(dfo))
239f7082a9aSPaolo Bonzini            dfo[var] = len(dfo)
240f7082a9aSPaolo Bonzini
241f7082a9aSPaolo Bonzini        for name, v in self.referenced_vars.items():
242f7082a9aSPaolo Bonzini            self.do_default(v, False)
243f7082a9aSPaolo Bonzini            v.dfs(visited, visit_fn)
244f7082a9aSPaolo Bonzini
245f7082a9aSPaolo Bonzini        # Put higher DFS numbers and higher priorities first.  This
246f7082a9aSPaolo Bonzini        # places the clauses in topological order and places defaults
247f7082a9aSPaolo Bonzini        # after assignments and dependencies.
248f7082a9aSPaolo Bonzini        self.clauses.sort(key=lambda x: (-dfo[x.dest], -x.priority()))
249f7082a9aSPaolo Bonzini
250f7082a9aSPaolo Bonzini        debug_print("\nSorted clauses:")
251f7082a9aSPaolo Bonzini        for clause in self.clauses:
252f7082a9aSPaolo Bonzini            debug_print(clause)
253f7082a9aSPaolo Bonzini            clause.process()
254f7082a9aSPaolo Bonzini
255f7082a9aSPaolo Bonzini        debug_print("")
256f7082a9aSPaolo Bonzini        values = dict()
257f7082a9aSPaolo Bonzini        for name, v in self.referenced_vars.items():
258f7082a9aSPaolo Bonzini            debug_print("Evaluating", name)
259f7082a9aSPaolo Bonzini            values[name] = v.evaluate()
260f7082a9aSPaolo Bonzini
261f7082a9aSPaolo Bonzini        return values
262f7082a9aSPaolo Bonzini
263d4fdccadSPaolo Bonzini    # semantic actions -------------
264d4fdccadSPaolo Bonzini
265d4fdccadSPaolo Bonzini    def do_declaration(self, var):
266d4fdccadSPaolo Bonzini        if (var in self.defined_vars):
267f7082a9aSPaolo Bonzini            raise KconfigDataError('variable "' + var + '" defined twice')
268d4fdccadSPaolo Bonzini
26953167f56SPaolo Bonzini        self.defined_vars.add(var.name)
270d4fdccadSPaolo Bonzini
271d4fdccadSPaolo Bonzini    # var is a string with the variable's name.
272d4fdccadSPaolo Bonzini    def do_var(self, var):
27353167f56SPaolo Bonzini        if (var in self.referenced_vars):
27453167f56SPaolo Bonzini            return self.referenced_vars[var]
27553167f56SPaolo Bonzini
27653167f56SPaolo Bonzini        var_obj = self.referenced_vars[var] = KconfigData.Var(var)
27753167f56SPaolo Bonzini        return var_obj
278d4fdccadSPaolo Bonzini
279d4fdccadSPaolo Bonzini    def do_assignment(self, var, val):
28053167f56SPaolo Bonzini        self.clauses.append(KconfigData.AssignmentClause(var, val))
281d4fdccadSPaolo Bonzini
282d4fdccadSPaolo Bonzini    def do_default(self, var, val, cond=None):
283f3494749SPaolo Bonzini        val = self.value_mangler(val)
28453167f56SPaolo Bonzini        self.clauses.append(KconfigData.DefaultClause(var, val, cond))
285d4fdccadSPaolo Bonzini
286d4fdccadSPaolo Bonzini    def do_depends_on(self, var, expr):
28753167f56SPaolo Bonzini        self.clauses.append(KconfigData.DependsOnClause(var, expr))
288d4fdccadSPaolo Bonzini
289d4fdccadSPaolo Bonzini    def do_select(self, var, symbol, cond=None):
29053167f56SPaolo Bonzini        cond = (cond & var) if cond is not None else var
29153167f56SPaolo Bonzini        self.clauses.append(KconfigData.SelectClause(symbol, cond))
292d4fdccadSPaolo Bonzini
293d4fdccadSPaolo Bonzini    def do_imply(self, var, symbol, cond=None):
29453167f56SPaolo Bonzini        # "config X imply Y [if COND]" is the same as
29553167f56SPaolo Bonzini        # "config Y default y if X [&& COND]"
29653167f56SPaolo Bonzini        cond = (cond & var) if cond is not None else var
29753167f56SPaolo Bonzini        self.do_default(symbol, True, cond)
298d4fdccadSPaolo Bonzini
299d4fdccadSPaolo Bonzini# -------------------------------------------
300d4fdccadSPaolo Bonzini# KconfigParser implements a recursive descent parser for (simplified)
301d4fdccadSPaolo Bonzini# Kconfig syntax.
302d4fdccadSPaolo Bonzini# -------------------------------------------
303d4fdccadSPaolo Bonzini
304d4fdccadSPaolo Bonzini# tokens table
305d4fdccadSPaolo BonziniTOKENS = {}
306d4fdccadSPaolo BonziniTOK_NONE = -1
307d4fdccadSPaolo BonziniTOK_LPAREN = 0;   TOKENS[TOK_LPAREN] = '"("';
308d4fdccadSPaolo BonziniTOK_RPAREN = 1;   TOKENS[TOK_RPAREN] = '")"';
309d4fdccadSPaolo BonziniTOK_EQUAL = 2;    TOKENS[TOK_EQUAL] = '"="';
310d4fdccadSPaolo BonziniTOK_AND = 3;      TOKENS[TOK_AND] = '"&&"';
311d4fdccadSPaolo BonziniTOK_OR = 4;       TOKENS[TOK_OR] = '"||"';
312d4fdccadSPaolo BonziniTOK_NOT = 5;      TOKENS[TOK_NOT] = '"!"';
313d4fdccadSPaolo BonziniTOK_DEPENDS = 6;  TOKENS[TOK_DEPENDS] = '"depends"';
314d4fdccadSPaolo BonziniTOK_ON = 7;       TOKENS[TOK_ON] = '"on"';
315d4fdccadSPaolo BonziniTOK_SELECT = 8;   TOKENS[TOK_SELECT] = '"select"';
316d4fdccadSPaolo BonziniTOK_IMPLY = 9;    TOKENS[TOK_IMPLY] = '"imply"';
317d4fdccadSPaolo BonziniTOK_CONFIG = 10;  TOKENS[TOK_CONFIG] = '"config"';
318d4fdccadSPaolo BonziniTOK_DEFAULT = 11; TOKENS[TOK_DEFAULT] = '"default"';
319d4fdccadSPaolo BonziniTOK_Y = 12;       TOKENS[TOK_Y] = '"y"';
320d4fdccadSPaolo BonziniTOK_N = 13;       TOKENS[TOK_N] = '"n"';
321d4fdccadSPaolo BonziniTOK_SOURCE = 14;  TOKENS[TOK_SOURCE] = '"source"';
322d4fdccadSPaolo BonziniTOK_BOOL = 15;    TOKENS[TOK_BOOL] = '"bool"';
323d4fdccadSPaolo BonziniTOK_IF = 16;      TOKENS[TOK_IF] = '"if"';
324d4fdccadSPaolo BonziniTOK_ID = 17;      TOKENS[TOK_ID] = 'identifier';
325d4fdccadSPaolo BonziniTOK_EOF = 18;     TOKENS[TOK_EOF] = 'end of file';
326d4fdccadSPaolo Bonzini
327d4fdccadSPaolo Bonziniclass KconfigParserError(Exception):
328d4fdccadSPaolo Bonzini    def __init__(self, parser, msg, tok=None):
329d4fdccadSPaolo Bonzini        self.loc = parser.location()
330d4fdccadSPaolo Bonzini        tok = tok or parser.tok
331d4fdccadSPaolo Bonzini        if tok != TOK_NONE:
332d4fdccadSPaolo Bonzini            location = TOKENS.get(tok, None) or ('"%s"' % tok)
333d4fdccadSPaolo Bonzini            msg = '%s before %s' % (msg, location)
334d4fdccadSPaolo Bonzini        self.msg = msg
335d4fdccadSPaolo Bonzini
336d4fdccadSPaolo Bonzini    def __str__(self):
337d4fdccadSPaolo Bonzini        return "%s: %s" % (self.loc, self.msg)
338d4fdccadSPaolo Bonzini
339d4fdccadSPaolo Bonziniclass KconfigParser:
340f3494749SPaolo Bonzini
341d4fdccadSPaolo Bonzini    @classmethod
342f3494749SPaolo Bonzini    def parse(self, fp, mode=None):
343f3494749SPaolo Bonzini        data = KconfigData(mode or KconfigParser.defconfig)
344d4fdccadSPaolo Bonzini        parser = KconfigParser(data)
345d4fdccadSPaolo Bonzini        parser.parse_file(fp)
346d4fdccadSPaolo Bonzini        return data
347d4fdccadSPaolo Bonzini
348d4fdccadSPaolo Bonzini    def __init__(self, data):
349d4fdccadSPaolo Bonzini        self.data = data
350d4fdccadSPaolo Bonzini
351d4fdccadSPaolo Bonzini    def parse_file(self, fp):
352d4fdccadSPaolo Bonzini        self.abs_fname = os.path.abspath(fp.name)
353d4fdccadSPaolo Bonzini        self.fname = fp.name
354d4fdccadSPaolo Bonzini        self.data.previously_included.append(self.abs_fname)
355d4fdccadSPaolo Bonzini        self.src = fp.read()
356d4fdccadSPaolo Bonzini        if self.src == '' or self.src[-1] != '\n':
357d4fdccadSPaolo Bonzini            self.src += '\n'
358d4fdccadSPaolo Bonzini        self.cursor = 0
359d4fdccadSPaolo Bonzini        self.line = 1
360d4fdccadSPaolo Bonzini        self.line_pos = 0
361d4fdccadSPaolo Bonzini        self.get_token()
362d4fdccadSPaolo Bonzini        self.parse_config()
363d4fdccadSPaolo Bonzini
36482f51817SPaolo Bonzini    def do_assignment(self, var, val):
36582f51817SPaolo Bonzini        if not var.startswith("CONFIG_"):
36682f51817SPaolo Bonzini            raise Error('assigned variable should start with CONFIG_')
36782f51817SPaolo Bonzini        var = self.data.do_var(var[7:])
36882f51817SPaolo Bonzini        self.data.do_assignment(var, val)
36982f51817SPaolo Bonzini
370d4fdccadSPaolo Bonzini    # file management -----
371d4fdccadSPaolo Bonzini
372d4fdccadSPaolo Bonzini    def error_path(self):
373d4fdccadSPaolo Bonzini        inf = self.data.incl_info
374d4fdccadSPaolo Bonzini        res = ""
375d4fdccadSPaolo Bonzini        while inf:
376d4fdccadSPaolo Bonzini            res = ("In file included from %s:%d:\n" % (inf['file'],
377d4fdccadSPaolo Bonzini                                                       inf['line'])) + res
378d4fdccadSPaolo Bonzini            inf = inf['parent']
379d4fdccadSPaolo Bonzini        return res
380d4fdccadSPaolo Bonzini
381d4fdccadSPaolo Bonzini    def location(self):
382d4fdccadSPaolo Bonzini        col = 1
383d4fdccadSPaolo Bonzini        for ch in self.src[self.line_pos:self.pos]:
384d4fdccadSPaolo Bonzini            if ch == '\t':
385d4fdccadSPaolo Bonzini                col += 8 - ((col - 1) % 8)
386d4fdccadSPaolo Bonzini            else:
387d4fdccadSPaolo Bonzini                col += 1
388d4fdccadSPaolo Bonzini        return '%s%s:%d:%d' %(self.error_path(), self.fname, self.line, col)
389d4fdccadSPaolo Bonzini
390d4fdccadSPaolo Bonzini    def do_include(self, include):
391d4fdccadSPaolo Bonzini        incl_abs_fname = os.path.join(os.path.dirname(self.abs_fname),
392d4fdccadSPaolo Bonzini                                      include)
393d4fdccadSPaolo Bonzini        # catch inclusion cycle
394d4fdccadSPaolo Bonzini        inf = self.data.incl_info
395d4fdccadSPaolo Bonzini        while inf:
396d4fdccadSPaolo Bonzini            if incl_abs_fname == os.path.abspath(inf['file']):
397d4fdccadSPaolo Bonzini                raise KconfigParserError(self, "Inclusion loop for %s"
398d4fdccadSPaolo Bonzini                                    % include)
399d4fdccadSPaolo Bonzini            inf = inf['parent']
400d4fdccadSPaolo Bonzini
401d4fdccadSPaolo Bonzini        # skip multiple include of the same file
402d4fdccadSPaolo Bonzini        if incl_abs_fname in self.data.previously_included:
403d4fdccadSPaolo Bonzini            return
404d4fdccadSPaolo Bonzini        try:
405ddd633e5SStefan Hajnoczi            fp = open(incl_abs_fname, 'rt', encoding='utf-8')
406d4fdccadSPaolo Bonzini        except IOError as e:
407d4fdccadSPaolo Bonzini            raise KconfigParserError(self,
408d4fdccadSPaolo Bonzini                                '%s: %s' % (e.strerror, include))
409d4fdccadSPaolo Bonzini
410d4fdccadSPaolo Bonzini        inf = self.data.incl_info
411d4fdccadSPaolo Bonzini        self.data.incl_info = { 'file': self.fname, 'line': self.line,
412d4fdccadSPaolo Bonzini                'parent': inf }
413d4fdccadSPaolo Bonzini        KconfigParser(self.data).parse_file(fp)
414d4fdccadSPaolo Bonzini        self.data.incl_info = inf
415d4fdccadSPaolo Bonzini
416d4fdccadSPaolo Bonzini    # recursive descent parser -----
417d4fdccadSPaolo Bonzini
418d4fdccadSPaolo Bonzini    # y_or_n: Y | N
419d4fdccadSPaolo Bonzini    def parse_y_or_n(self):
420d4fdccadSPaolo Bonzini        if self.tok == TOK_Y:
421d4fdccadSPaolo Bonzini            self.get_token()
422d4fdccadSPaolo Bonzini            return True
423d4fdccadSPaolo Bonzini        if self.tok == TOK_N:
424d4fdccadSPaolo Bonzini            self.get_token()
425d4fdccadSPaolo Bonzini            return False
426d4fdccadSPaolo Bonzini        raise KconfigParserError(self, 'Expected "y" or "n"')
427d4fdccadSPaolo Bonzini
428d4fdccadSPaolo Bonzini    # var: ID
429d4fdccadSPaolo Bonzini    def parse_var(self):
430d4fdccadSPaolo Bonzini        if self.tok == TOK_ID:
431d4fdccadSPaolo Bonzini            val = self.val
432d4fdccadSPaolo Bonzini            self.get_token()
433d4fdccadSPaolo Bonzini            return self.data.do_var(val)
434d4fdccadSPaolo Bonzini        else:
435d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Expected identifier')
436d4fdccadSPaolo Bonzini
437d4fdccadSPaolo Bonzini    # assignment_var: ID (starting with "CONFIG_")
438d4fdccadSPaolo Bonzini    def parse_assignment_var(self):
439d4fdccadSPaolo Bonzini        if self.tok == TOK_ID:
440d4fdccadSPaolo Bonzini            val = self.val
441d4fdccadSPaolo Bonzini            if not val.startswith("CONFIG_"):
442d4fdccadSPaolo Bonzini                raise KconfigParserError(self,
443d4fdccadSPaolo Bonzini                           'Expected identifier starting with "CONFIG_"', TOK_NONE)
444d4fdccadSPaolo Bonzini            self.get_token()
445d4fdccadSPaolo Bonzini            return self.data.do_var(val[7:])
446d4fdccadSPaolo Bonzini        else:
447d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Expected identifier')
448d4fdccadSPaolo Bonzini
449d4fdccadSPaolo Bonzini    # assignment: var EQUAL y_or_n
450d4fdccadSPaolo Bonzini    def parse_assignment(self):
451d4fdccadSPaolo Bonzini        var = self.parse_assignment_var()
452d4fdccadSPaolo Bonzini        if self.tok != TOK_EQUAL:
453d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Expected "="')
454d4fdccadSPaolo Bonzini        self.get_token()
455d4fdccadSPaolo Bonzini        self.data.do_assignment(var, self.parse_y_or_n())
456d4fdccadSPaolo Bonzini
457d4fdccadSPaolo Bonzini    # primary: NOT primary
458d4fdccadSPaolo Bonzini    #       | LPAREN expr RPAREN
459d4fdccadSPaolo Bonzini    #       | var
460d4fdccadSPaolo Bonzini    def parse_primary(self):
461d4fdccadSPaolo Bonzini        if self.tok == TOK_NOT:
462d4fdccadSPaolo Bonzini            self.get_token()
46353167f56SPaolo Bonzini            val = ~self.parse_primary()
464d4fdccadSPaolo Bonzini        elif self.tok == TOK_LPAREN:
465d4fdccadSPaolo Bonzini            self.get_token()
46653167f56SPaolo Bonzini            val = self.parse_expr()
467d4fdccadSPaolo Bonzini            if self.tok != TOK_RPAREN:
468d4fdccadSPaolo Bonzini                raise KconfigParserError(self, 'Expected ")"')
469d4fdccadSPaolo Bonzini            self.get_token()
470d4fdccadSPaolo Bonzini        elif self.tok == TOK_ID:
47153167f56SPaolo Bonzini            val = self.parse_var()
472d4fdccadSPaolo Bonzini        else:
473d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Expected "!" or "(" or identifier')
47453167f56SPaolo Bonzini        return val
475d4fdccadSPaolo Bonzini
476d4fdccadSPaolo Bonzini    # disj: primary (OR primary)*
477d4fdccadSPaolo Bonzini    def parse_disj(self):
47853167f56SPaolo Bonzini        lhs = self.parse_primary()
479d4fdccadSPaolo Bonzini        while self.tok == TOK_OR:
480d4fdccadSPaolo Bonzini            self.get_token()
48153167f56SPaolo Bonzini            lhs = lhs | self.parse_primary()
48253167f56SPaolo Bonzini        return lhs
483d4fdccadSPaolo Bonzini
484d4fdccadSPaolo Bonzini    # expr: disj (AND disj)*
485d4fdccadSPaolo Bonzini    def parse_expr(self):
48653167f56SPaolo Bonzini        lhs = self.parse_disj()
487d4fdccadSPaolo Bonzini        while self.tok == TOK_AND:
488d4fdccadSPaolo Bonzini            self.get_token()
48953167f56SPaolo Bonzini            lhs = lhs & self.parse_disj()
49053167f56SPaolo Bonzini        return lhs
491d4fdccadSPaolo Bonzini
492d4fdccadSPaolo Bonzini    # condition: IF expr
493d4fdccadSPaolo Bonzini    #       | empty
494d4fdccadSPaolo Bonzini    def parse_condition(self):
495d4fdccadSPaolo Bonzini        if self.tok == TOK_IF:
496d4fdccadSPaolo Bonzini            self.get_token()
497d4fdccadSPaolo Bonzini            return self.parse_expr()
498d4fdccadSPaolo Bonzini        else:
499d4fdccadSPaolo Bonzini            return None
500d4fdccadSPaolo Bonzini
501d4fdccadSPaolo Bonzini    # property: DEFAULT y_or_n condition
502d4fdccadSPaolo Bonzini    #       | DEPENDS ON expr
503d4fdccadSPaolo Bonzini    #       | SELECT var condition
504d4fdccadSPaolo Bonzini    #       | BOOL
505d4fdccadSPaolo Bonzini    def parse_property(self, var):
506d4fdccadSPaolo Bonzini        if self.tok == TOK_DEFAULT:
507d4fdccadSPaolo Bonzini            self.get_token()
508d4fdccadSPaolo Bonzini            val = self.parse_y_or_n()
509d4fdccadSPaolo Bonzini            cond = self.parse_condition()
510d4fdccadSPaolo Bonzini            self.data.do_default(var, val, cond)
511d4fdccadSPaolo Bonzini        elif self.tok == TOK_DEPENDS:
512d4fdccadSPaolo Bonzini            self.get_token()
513d4fdccadSPaolo Bonzini            if self.tok != TOK_ON:
514d4fdccadSPaolo Bonzini                raise KconfigParserError(self, 'Expected "on"')
515d4fdccadSPaolo Bonzini            self.get_token()
516d4fdccadSPaolo Bonzini            self.data.do_depends_on(var, self.parse_expr())
517d4fdccadSPaolo Bonzini        elif self.tok == TOK_SELECT:
518d4fdccadSPaolo Bonzini            self.get_token()
519d4fdccadSPaolo Bonzini            symbol = self.parse_var()
520d4fdccadSPaolo Bonzini            cond = self.parse_condition()
521d4fdccadSPaolo Bonzini            self.data.do_select(var, symbol, cond)
522d4fdccadSPaolo Bonzini        elif self.tok == TOK_IMPLY:
523d4fdccadSPaolo Bonzini            self.get_token()
524d4fdccadSPaolo Bonzini            symbol = self.parse_var()
525d4fdccadSPaolo Bonzini            cond = self.parse_condition()
526d4fdccadSPaolo Bonzini            self.data.do_imply(var, symbol, cond)
527d4fdccadSPaolo Bonzini        elif self.tok == TOK_BOOL:
528d4fdccadSPaolo Bonzini            self.get_token()
529d4fdccadSPaolo Bonzini        else:
530d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Error in recursive descent?')
531d4fdccadSPaolo Bonzini
532d4fdccadSPaolo Bonzini    # properties: properties property
533d4fdccadSPaolo Bonzini    #       | /* empty */
534d4fdccadSPaolo Bonzini    def parse_properties(self, var):
535d4fdccadSPaolo Bonzini        had_default = False
536d4fdccadSPaolo Bonzini        while self.tok == TOK_DEFAULT or self.tok == TOK_DEPENDS or \
537d4fdccadSPaolo Bonzini              self.tok == TOK_SELECT or self.tok == TOK_BOOL or \
538d4fdccadSPaolo Bonzini              self.tok == TOK_IMPLY:
539d4fdccadSPaolo Bonzini            self.parse_property(var)
540d4fdccadSPaolo Bonzini
541d4fdccadSPaolo Bonzini        # for nicer error message
542d4fdccadSPaolo Bonzini        if self.tok != TOK_SOURCE and self.tok != TOK_CONFIG and \
543d4fdccadSPaolo Bonzini           self.tok != TOK_ID and self.tok != TOK_EOF:
544d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'expected "source", "config", identifier, '
545d4fdccadSPaolo Bonzini                    + '"default", "depends on", "imply" or "select"')
546d4fdccadSPaolo Bonzini
547d4fdccadSPaolo Bonzini    # declaration: config var properties
548d4fdccadSPaolo Bonzini    def parse_declaration(self):
549d4fdccadSPaolo Bonzini        if self.tok == TOK_CONFIG:
550d4fdccadSPaolo Bonzini            self.get_token()
551d4fdccadSPaolo Bonzini            var = self.parse_var()
552d4fdccadSPaolo Bonzini            self.data.do_declaration(var)
553d4fdccadSPaolo Bonzini            self.parse_properties(var)
554d4fdccadSPaolo Bonzini        else:
555d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'Error in recursive descent?')
556d4fdccadSPaolo Bonzini
557d4fdccadSPaolo Bonzini    # clause: SOURCE
558d4fdccadSPaolo Bonzini    #       | declaration
559d4fdccadSPaolo Bonzini    #       | assignment
560d4fdccadSPaolo Bonzini    def parse_clause(self):
561d4fdccadSPaolo Bonzini        if self.tok == TOK_SOURCE:
562d4fdccadSPaolo Bonzini            val = self.val
563d4fdccadSPaolo Bonzini            self.get_token()
564d4fdccadSPaolo Bonzini            self.do_include(val)
565d4fdccadSPaolo Bonzini        elif self.tok == TOK_CONFIG:
566d4fdccadSPaolo Bonzini            self.parse_declaration()
567d4fdccadSPaolo Bonzini        elif self.tok == TOK_ID:
568d4fdccadSPaolo Bonzini            self.parse_assignment()
569d4fdccadSPaolo Bonzini        else:
570d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'expected "source", "config" or identifier')
571d4fdccadSPaolo Bonzini
572d4fdccadSPaolo Bonzini    # config: clause+ EOF
573d4fdccadSPaolo Bonzini    def parse_config(self):
574d4fdccadSPaolo Bonzini        while self.tok != TOK_EOF:
575d4fdccadSPaolo Bonzini            self.parse_clause()
576d4fdccadSPaolo Bonzini        return self.data
577d4fdccadSPaolo Bonzini
578d4fdccadSPaolo Bonzini    # scanner -----
579d4fdccadSPaolo Bonzini
580d4fdccadSPaolo Bonzini    def get_token(self):
581d4fdccadSPaolo Bonzini        while True:
582d4fdccadSPaolo Bonzini            self.tok = self.src[self.cursor]
583d4fdccadSPaolo Bonzini            self.pos = self.cursor
584d4fdccadSPaolo Bonzini            self.cursor += 1
585d4fdccadSPaolo Bonzini
586d4fdccadSPaolo Bonzini            self.val = None
587d4fdccadSPaolo Bonzini            self.tok = self.scan_token()
588d4fdccadSPaolo Bonzini            if self.tok is not None:
589d4fdccadSPaolo Bonzini                return
590d4fdccadSPaolo Bonzini
591d4fdccadSPaolo Bonzini    def check_keyword(self, rest):
592d4fdccadSPaolo Bonzini        if not self.src.startswith(rest, self.cursor):
593d4fdccadSPaolo Bonzini            return False
594d4fdccadSPaolo Bonzini        length = len(rest)
59567163caeSPaolo Bonzini        if self.src[self.cursor + length].isalnum() or self.src[self.cursor + length] == '_':
596d4fdccadSPaolo Bonzini            return False
597d4fdccadSPaolo Bonzini        self.cursor += length
598d4fdccadSPaolo Bonzini        return True
599d4fdccadSPaolo Bonzini
600d4fdccadSPaolo Bonzini    def scan_token(self):
601d4fdccadSPaolo Bonzini        if self.tok == '#':
602d4fdccadSPaolo Bonzini            self.cursor = self.src.find('\n', self.cursor)
603d4fdccadSPaolo Bonzini            return None
604d4fdccadSPaolo Bonzini        elif self.tok == '=':
605d4fdccadSPaolo Bonzini            return TOK_EQUAL
606d4fdccadSPaolo Bonzini        elif self.tok == '(':
607d4fdccadSPaolo Bonzini            return TOK_LPAREN
608d4fdccadSPaolo Bonzini        elif self.tok == ')':
609d4fdccadSPaolo Bonzini            return TOK_RPAREN
610d4fdccadSPaolo Bonzini        elif self.tok == '&' and self.src[self.pos+1] == '&':
611d4fdccadSPaolo Bonzini            self.cursor += 1
612d4fdccadSPaolo Bonzini            return TOK_AND
613d4fdccadSPaolo Bonzini        elif self.tok == '|' and self.src[self.pos+1] == '|':
614d4fdccadSPaolo Bonzini            self.cursor += 1
615d4fdccadSPaolo Bonzini            return TOK_OR
616d4fdccadSPaolo Bonzini        elif self.tok == '!':
617d4fdccadSPaolo Bonzini            return TOK_NOT
618d4fdccadSPaolo Bonzini        elif self.tok == 'd' and self.check_keyword("epends"):
619d4fdccadSPaolo Bonzini            return TOK_DEPENDS
620d4fdccadSPaolo Bonzini        elif self.tok == 'o' and self.check_keyword("n"):
621d4fdccadSPaolo Bonzini            return TOK_ON
622d4fdccadSPaolo Bonzini        elif self.tok == 's' and self.check_keyword("elect"):
623d4fdccadSPaolo Bonzini            return TOK_SELECT
624d4fdccadSPaolo Bonzini        elif self.tok == 'i' and self.check_keyword("mply"):
625d4fdccadSPaolo Bonzini            return TOK_IMPLY
626d4fdccadSPaolo Bonzini        elif self.tok == 'c' and self.check_keyword("onfig"):
627d4fdccadSPaolo Bonzini            return TOK_CONFIG
628d4fdccadSPaolo Bonzini        elif self.tok == 'd' and self.check_keyword("efault"):
629d4fdccadSPaolo Bonzini            return TOK_DEFAULT
630d4fdccadSPaolo Bonzini        elif self.tok == 'b' and self.check_keyword("ool"):
631d4fdccadSPaolo Bonzini            return TOK_BOOL
632d4fdccadSPaolo Bonzini        elif self.tok == 'i' and self.check_keyword("f"):
633d4fdccadSPaolo Bonzini            return TOK_IF
634d4fdccadSPaolo Bonzini        elif self.tok == 'y' and self.check_keyword(""):
635d4fdccadSPaolo Bonzini            return TOK_Y
636d4fdccadSPaolo Bonzini        elif self.tok == 'n' and self.check_keyword(""):
637d4fdccadSPaolo Bonzini            return TOK_N
638d4fdccadSPaolo Bonzini        elif (self.tok == 's' and self.check_keyword("ource")) or \
639d4fdccadSPaolo Bonzini              self.tok == 'i' and self.check_keyword("nclude"):
640d4fdccadSPaolo Bonzini            # source FILENAME
641d4fdccadSPaolo Bonzini            # include FILENAME
642d4fdccadSPaolo Bonzini            while self.src[self.cursor].isspace():
643d4fdccadSPaolo Bonzini                self.cursor += 1
644d4fdccadSPaolo Bonzini            start = self.cursor
645d4fdccadSPaolo Bonzini            self.cursor = self.src.find('\n', self.cursor)
646d4fdccadSPaolo Bonzini            self.val = self.src[start:self.cursor]
647d4fdccadSPaolo Bonzini            return TOK_SOURCE
6481b29af2fSMarc-André Lureau        elif self.tok.isalnum():
649d4fdccadSPaolo Bonzini            # identifier
650d4fdccadSPaolo Bonzini            while self.src[self.cursor].isalnum() or self.src[self.cursor] == '_':
651d4fdccadSPaolo Bonzini                self.cursor += 1
652d4fdccadSPaolo Bonzini            self.val = self.src[self.pos:self.cursor]
653d4fdccadSPaolo Bonzini            return TOK_ID
654d4fdccadSPaolo Bonzini        elif self.tok == '\n':
655d4fdccadSPaolo Bonzini            if self.cursor == len(self.src):
656d4fdccadSPaolo Bonzini                return TOK_EOF
657d4fdccadSPaolo Bonzini            self.line += 1
658d4fdccadSPaolo Bonzini            self.line_pos = self.cursor
659d4fdccadSPaolo Bonzini        elif not self.tok.isspace():
660d4fdccadSPaolo Bonzini            raise KconfigParserError(self, 'invalid input')
661d4fdccadSPaolo Bonzini
662d4fdccadSPaolo Bonzini        return None
663d4fdccadSPaolo Bonzini
664d4fdccadSPaolo Bonziniif __name__ == '__main__':
66582f51817SPaolo Bonzini    argv = sys.argv
666f3494749SPaolo Bonzini    mode = defconfig
667f3494749SPaolo Bonzini    if len(sys.argv) > 1:
668f3494749SPaolo Bonzini        if argv[1] == '--defconfig':
669f3494749SPaolo Bonzini            del argv[1]
670f3494749SPaolo Bonzini        elif argv[1] == '--randconfig':
671f3494749SPaolo Bonzini            random.seed()
672f3494749SPaolo Bonzini            mode = randconfig
673f3494749SPaolo Bonzini            del argv[1]
674f3494749SPaolo Bonzini        elif argv[1] == '--allyesconfig':
675f3494749SPaolo Bonzini            mode = allyesconfig
676f3494749SPaolo Bonzini            del argv[1]
677f3494749SPaolo Bonzini        elif argv[1] == '--allnoconfig':
678f3494749SPaolo Bonzini            mode = allnoconfig
679f3494749SPaolo Bonzini            del argv[1]
680f3494749SPaolo Bonzini
68182f51817SPaolo Bonzini    if len(argv) == 1:
68282f51817SPaolo Bonzini        print ("%s: at least one argument is required" % argv[0], file=sys.stderr)
68382f51817SPaolo Bonzini        sys.exit(1)
68482f51817SPaolo Bonzini
685f3494749SPaolo Bonzini    if argv[1].startswith('-'):
686f3494749SPaolo Bonzini        print ("%s: invalid option %s" % (argv[0], argv[1]), file=sys.stderr)
687f3494749SPaolo Bonzini        sys.exit(1)
688f3494749SPaolo Bonzini
689f3494749SPaolo Bonzini    data = KconfigData(mode)
69082f51817SPaolo Bonzini    parser = KconfigParser(data)
6916b7ac49dSPaolo Bonzini    external_vars = set()
69282f51817SPaolo Bonzini    for arg in argv[3:]:
69382f51817SPaolo Bonzini        m = re.match(r'^(CONFIG_[A-Z0-9_]+)=([yn]?)$', arg)
69482f51817SPaolo Bonzini        if m is not None:
69582f51817SPaolo Bonzini            name, value = m.groups()
69682f51817SPaolo Bonzini            parser.do_assignment(name, value == 'y')
6976b7ac49dSPaolo Bonzini            external_vars.add(name[7:])
69882f51817SPaolo Bonzini        else:
699ddd633e5SStefan Hajnoczi            fp = open(arg, 'rt', encoding='utf-8')
70082f51817SPaolo Bonzini            parser.parse_file(fp)
70182f51817SPaolo Bonzini            fp.close()
70282f51817SPaolo Bonzini
70382f51817SPaolo Bonzini    config = data.compute_config()
70482f51817SPaolo Bonzini    for key in sorted(config.keys()):
705c5b35f03SMarc-André Lureau        if key not in external_vars and config[key]:
706c5b35f03SMarc-André Lureau            print ('CONFIG_%s=y' % key)
70782f51817SPaolo Bonzini
708ddd633e5SStefan Hajnoczi    deps = open(argv[2], 'wt', encoding='utf-8')
70982f51817SPaolo Bonzini    for fname in data.previously_included:
71082f51817SPaolo Bonzini        print ('%s: %s' % (argv[1], fname), file=deps)
71182f51817SPaolo Bonzini    deps.close()
712