From patchwork Thu Dec 27 06:33:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yang Zhong X-Patchwork-Id: 10743475 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7942013BF for ; Thu, 27 Dec 2018 06:40:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 63755284D2 for ; Thu, 27 Dec 2018 06:40:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 50B93287C6; Thu, 27 Dec 2018 06:40:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 251CD284D2 for ; Thu, 27 Dec 2018 06:39:59 +0000 (UTC) Received: from localhost ([127.0.0.1]:49731 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gcPKo-0008Fz-AR for patchwork-qemu-devel@patchwork.kernel.org; Thu, 27 Dec 2018 01:39:58 -0500 Received: from eggs.gnu.org ([208.118.235.92]:54684) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gcPGM-0002sb-7B for qemu-devel@nongnu.org; Thu, 27 Dec 2018 01:35:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gcPG5-00047L-CH for qemu-devel@nongnu.org; Thu, 27 Dec 2018 01:35:14 -0500 Received: from mga11.intel.com ([192.55.52.93]:57851) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gcPG4-00041J-Om for qemu-devel@nongnu.org; Thu, 27 Dec 2018 01:35:05 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Dec 2018 22:35:04 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,404,1539673200"; d="scan'208";a="103617269" Received: from he.bj.intel.com ([10.238.157.85]) by orsmga006.jf.intel.com with ESMTP; 26 Dec 2018 22:35:02 -0800 From: Yang Zhong To: qemu-devel@nongnu.org Date: Thu, 27 Dec 2018 14:33:58 +0800 Message-Id: <20181227063419.12981-5-yang.zhong@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181227063419.12981-1-yang.zhong@intel.com> References: <20181227063419.12981-1-yang.zhong@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.93 Subject: [Qemu-devel] [RFC PATCH 04/25] minikconfig: add AST X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: yang.zhong@intel.com, peter.maydell@linaro.org, thuth@redhat.com, sameo@linux.intel.com, pbonzini@redhat.com, ehabkost@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Paolo Bonzini Add Python classes that represent the Kconfig abstract syntax tree. The abstract syntax tree is stored as a list of clauses. For example: config FOO depends on BAR select BAZ is represented as three clauses: FOO depends on BAR FOO default n select BAZ if FOO Signed-off-by: Paolo Bonzini --- scripts/minikconf.py | 116 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 18 deletions(-) diff --git a/scripts/minikconf.py b/scripts/minikconf.py index 9e33d80514..f1851c3570 100644 --- a/scripts/minikconf.py +++ b/scripts/minikconf.py @@ -26,11 +26,84 @@ __all__ = [ 'KconfigParserError', 'KconfigData', 'KconfigParser' ] # ------------------------------------------- class KconfigData: + 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) + + class AND(Expr): + def __init__(self, lhs, rhs): + self.lhs = lhs + self.rhs = rhs + def __str__(self): + return "(%s && %s)" % (self.lhs, self.rhs) + + class OR(Expr): + def __init__(self, lhs, rhs): + self.lhs = lhs + self.rhs = rhs + def __str__(self): + return "(%s || %s)" % (self.lhs, self.rhs) + + class NOT(Expr): + def __init__(self, lhs): + self.lhs = lhs + def __str__(self): + return "!%s" % (self.lhs) + + class Var(Expr): + def __init__(self, name): + self.name = name + self.value = None + def __str__(self): + return self.name + + class Clause: + def __init__(self, dest): + self.dest = dest + + class AssignmentClause(Clause): + def __init__(self, dest, value): + KconfigData.Clause.__init__(self, dest) + self.value = value + def __str__(self): + return "%s=%s" % (self.dest, 'y' if self.value else 'n') + + class DefaultClause(Clause): + def __init__(self, dest, value, cond=None): + KconfigData.Clause.__init__(self, dest) + self.value = value + self.cond = cond + 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) + + class DependsOnClause(Clause): + def __init__(self, dest, expr): + KconfigData.Clause.__init__(self, dest) + self.expr = expr + def __str__(self): + return "config %s depends on %s" % (self.dest, self.expr) + + class SelectClause(Clause): + def __init__(self, dest, cond): + KconfigData.Clause.__init__(self, dest) + self.cond = cond + def __str__(self): + return "select %s if %s" % (self.dest, self.cond) + def __init__(self): self.previously_included = [] self.incl_info = None self.defined_vars = set() - self.referenced_vars = set() + self.referenced_vars = dict() + self.clauses = list() # semantic analysis ------------- @@ -48,26 +121,28 @@ class KconfigData: if (var in self.defined_vars): raise Exception('variable "' + var + '" defined twice') - self.defined_vars.add(var) + self.defined_vars.add(var.name) # var is a string with the variable's name. - # - # For now this just returns the variable's name itself. def do_var(self, var): - self.referenced_vars.add(var) - return var + if (var in self.referenced_vars): + return self.referenced_vars[var] + + var_obj = self.referenced_vars[var] = KconfigData.Var(var) + return var_obj def do_assignment(self, var, val): - pass + self.clauses.append(KconfigData.AssignmentClause(var, val)) def do_default(self, var, val, cond=None): - pass + self.clauses.append(KconfigData.DefaultClause(var, val, cond)) def do_depends_on(self, var, expr): - pass + self.clauses.append(KconfigData.DependsOnClause(var, expr)) def do_select(self, var, symbol, cond=None): - pass + cond = (cond & var) if not (cond is None) else var + self.clauses.append(KconfigData.SelectClause(symbol, cond)) # ------------------------------------------- # KconfigParser implements a recursive descent parser for (simplified) @@ -229,31 +304,34 @@ class KconfigParser: def parse_primary(self): if self.tok == TOK_NOT: self.get_token() - self.parse_primary() + val = ~self.parse_primary() elif self.tok == TOK_LPAREN: self.get_token() - self.parse_expr() + val = self.parse_expr() if self.tok != TOK_RPAREN: raise KconfigParserError(self, 'Expected ")"') self.get_token() elif self.tok == TOK_ID: - self.parse_var() + val = self.parse_var() else: raise KconfigParserError(self, 'Expected "!" or "(" or identifier') + return val # disj: primary (OR primary)* def parse_disj(self): - self.parse_primary() + lhs = self.parse_primary() while self.tok == TOK_OR: self.get_token() - self.parse_primary() + lhs = lhs | self.parse_primary() + return lhs # expr: disj (AND disj)* def parse_expr(self): - self.parse_disj() + lhs = self.parse_disj() while self.tok == TOK_AND: self.get_token() - self.parse_disj() + lhs = lhs & self.parse_disj() + return lhs # condition: IF expr # | empty @@ -422,4 +500,6 @@ class KconfigParser: if __name__ == '__main__': fname = len(sys.argv) > 1 and sys.argv[1] or 'Kconfig.test' - KconfigParser.parse(open(fname, 'r')) + data = KconfigParser.parse(open(fname, 'r')) + for i in data.clauses: + print i