def parse_and_calculate_constants(self): self.lex = lexer.lexer try: self.pars = parser.Parser(self.nta.declaration, self.lex) except Exception: opaal.util.emergencyExitUppaalCParser( "Error in parsing the model to calculation constants.") self.declvisitor = parser.DeclVisitor(self.pars) self.declvisitor.visit(self.pars.AST) self.constants = {} #constant overrides for (cident, cval) in self.constant_overrides.iteritems(): #XXX assumes expression is already python self.constants[cident] = eval(cval, {}, self.constants) #evaluate constants to values for (cident, cval) in self.declvisitor.constants.iteritems(): if not cident in self.constants: self.constants[cident] = eval(util.expression_to_python(cval), {}, self.constants) try: #evaluate VarDecl expressions for vdecl in self.declvisitor.variables: util.eval_vardecl_expressions(vdecl, self.constants) except Exception: opaal.util.emergencyExitUppaalCParser( "Error in evaluating variable properties (e.g. array dimensions), for '%s'." % (vdecl.identifier))
def test_parse_extern_dbm(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_extern_dbm.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children #pars.AST.visit() declvisitor = parser.DeclVisitor(pars) #print declvisitor.variables self.assertEqual(len(declvisitor.variables), 5) self.assertEqual(declvisitor.variables[0], ('dbm', 'DBMFederation', [], None)) self.assertEqual(declvisitor.variables[1], ('dbm.x', 'DBMClock', [], None)) self.assertEqual(declvisitor.variables[2], ('dbm.c', 'DBMClock', [], None)) self.assertEqual(declvisitor.variables[3][0], 'dbm.y') #('dbm.y', 'DBMClock', [10]) self.assertEqual(declvisitor.variables[3][1], 'DBMClock') self.assertEqual(len(declvisitor.variables[3][2]), 1) self.assertEqual(declvisitor.variables[3][2][0].children[0].leaf, 10) self.assertEqual(declvisitor.variables[4][0], 'dbm.z') #('dbm.z', 'DBMClock', [10, 20]) self.assertEqual(declvisitor.variables[4][1], 'DBMClock') self.assertEqual(len(declvisitor.variables[4][2]), 2) self.assertEqual(declvisitor.variables[4][2][0].children[0].leaf, 10) self.assertEqual(declvisitor.variables[4][2][1].children[0].leaf, 20)
def add_template_promote_local_vars(self, nta, temp): """Add the template @temp to the nta @nta, promoting local variables to uniquely named global variables in the process.""" lex = lexer.lexer try: pars = parser.Parser(temp.declaration, lex, typedefDict=self.pars.typedefDict) except Exception: opaal.util.emergencyExitUppaalCParser("Error parsing template declarations.") declvisitor = parser.DeclVisitor(pars) declvisitor.visit(pars.AST) for (c, _) in declvisitor.clocks: newident = "%s_%s" % (temp.name, c) assert declvisitor.get_type(newident) == None self.rename_var_in_temp(temp, c, newident) for (varname, _, _, _) in declvisitor.variables: newident = "%s_%s" % (temp.name, varname) assert declvisitor.get_type(newident) == None self.rename_var_in_temp(temp, varname, newident) for const in declvisitor.constants: newident = "%s_%s" % (temp.name, const) assert declvisitor.get_type(newident) == None self.rename_var_in_temp(temp, const, newident) for func_ast in declvisitor.functions: oldident = func_ast.leaf[1].children[0] newident = "%s_%s" % (temp.name, oldident) assert declvisitor.get_type(newident) == None self.rename_var_in_temp(temp, oldident, newident) nta.declaration += "\n/******** Declarations for %s ********/\n%s\n" % (temp.name, temp.declaration) temp.declaration = "" nta.templates += [temp]
def test_parse_extern3(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_extern3.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children pars.AST.visit() declvisitor = parser.DeclVisitor(pars) self.assertTrue('WideningIntRange' in pars.externList) self.assertEqual(declvisitor.get_type('x'), 'WideningIntRange') wideningIntRangeTypeNode = pars.typedefDict['WideningIntRange'] print "typedefdict:" wideningIntRangeTypeNode.visit() self.assertEqual(wideningIntRangeTypeNode.leaf.type, "Identifier") self.assertEqual(wideningIntRangeTypeNode.leaf.leaf, "WideningIntRange") self.assertEqual(len(wideningIntRangeTypeNode.children), 1) self.assertEqual(wideningIntRangeTypeNode.children[0].type, 'FunctionCall') parameters = wideningIntRangeTypeNode.children[0].leaf self.assertEqual(len(parameters), 4) self.assertEqual(parameters[0].leaf, 1) self.assertEqual(parameters[1].leaf, 2) self.assertEqual(parameters[2].leaf, 3) self.assertEqual(parameters[3].leaf, 9)
def test_parse_extern(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_extern.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children #pars.AST.visit() declvisitor = parser.DeclVisitor(pars)
def test_parse_declarations2(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_simple_declarations2.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children pars.AST.visit() declvisitor = parser.DeclVisitor(pars) self.assertEqual(res[7].type, 'VarDecl') self.assertEqual(res[7].leaf.type, 'TypeInt') self.assertEqual(res[7].children[0].type, 'Identifier') self.assertEqual(res[7].children[0].leaf, 'lalala') self.assertEqual(res[7].children[0].children[0].type, 'Assignment') self.assertEqual(res[7].children[0].children[0].leaf.type, 'Identifier') self.assertEqual(res[7].children[0].children[0].leaf.leaf, 'lalala') self.assertEqual(res[12].type, 'VarDecl') self.assertEqual(res[12].leaf.type, 'TypeBool') self.assertEqual(res[12].children[0].type, 'Identifier') self.assertEqual(res[12].children[0].leaf, 'msg') self.assertEqual(res[12].children[0].children[0].type, 'Index') self.assertEqual(res[12].children[0].children[1].type, 'Index') self.assertEqual(declvisitor.variables[0], ('L', 'TypeInt', [], 0)) #self.assertEqual(declvisitor.variables[1], ('lalala', 'int', [], _)) self.assertEqual(declvisitor.variables[1][0], 'lalala') self.assertEqual(declvisitor.variables[1][1], 'TypeInt') self.assertEqual(declvisitor.variables[1][2], []) self.assertEqual(declvisitor.variables[1][3].type, 'Expression') self.assertEqual(declvisitor.variables[1][3].children[0].type, 'Number') self.assertEqual(declvisitor.variables[1][3].children[0].leaf, 3) self.assertEqual(declvisitor.variables[3][0], 'lock') self.assertEqual(declvisitor.variables[3][1], 'TypeBool') self.assertEqual(declvisitor.variables[3][2], []) self.assertEqual(declvisitor.variables[3][3].type, 'Expression') self.assertEqual(declvisitor.variables[3][3].children[0].type, 'False') self.assertEqual(declvisitor.variables[4][0], 'lock2') self.assertEqual(declvisitor.variables[4][1], 'TypeBool') self.assertEqual(declvisitor.variables[4][2], []) self.assertEqual(declvisitor.variables[4][3].children[0].type, 'True') self.assertEqual(declvisitor.clocks, [('time', 10), ('y1', 10), ('y2', 10), ('y3', 10), ('y4', 10)]) self.assertEqual(declvisitor.channels, [('take', []), ('release', [])])
def test_parse_constants(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_parse_constants.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children pars.AST.visit() declvisitor = parser.DeclVisitor(pars) inorder = ["a", "b", "c", "d"] #should return the constants in file order self.assertEqual(declvisitor.constants.keys(), inorder)
def test_parse_extern2(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_extern2.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children pars.AST.visit() declvisitor = parser.DeclVisitor(pars) self.assertTrue('TestExternalLattice' in pars.externList) self.assertEqual(declvisitor.get_type('mylat'), 'TestExternalLattice')
def parse_and_calculate_constants(self): self.lex = lexer.lexer try: self.pars = parser.Parser(self.nta.declaration, self.lex) except Exception: opaal.util.emergencyExitUppaalCParser("Error parsing the model for calculating constants.") self.declvisitor = parser.DeclVisitor(self.pars) self.declvisitor.visit(self.pars.AST) self.constants = {} #constant overrides for (cident, cval) in self.constant_overrides.iteritems(): #XXX assumes expression is already python self.constants[cident] = eval(cval, {}, self.constants) #evaluate constants to values for (cident, cval) in self.declvisitor.constants.iteritems(): if not cident in self.constants: self.constants[cident] = eval(util.expression_to_python(cval), {}, self.constants)
def test_parse_declarations(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_simple_declarations.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) res = pars.AST.children #pars.AST.visit() declvisitor = parser.DeclVisitor(pars) self.assertEqual(declvisitor.variables, [('a', 'TypeInt', [], 0), ('b', 'TypeBool', [], False), ('b1', 'TypeBool', [], False), ('b2', 'TypeBool', [], False)]) self.assertEqual(len(declvisitor.clocks), 1) self.assertEqual(declvisitor.clocks[0][0], 'c') self.assertEqual(declvisitor.channels, [('d', [])]) self.assertEqual(declvisitor.urgent_channels, [('e', [])]) self.assertEqual(declvisitor.broadcast_channels, [('f', [])]) self.assertEqual(declvisitor.urgent_broadcast_channels, [('g', [])])
def test_parse_typedef(self): test_file = open(os.path.join(os.path.dirname(__file__), 'test_typedef.txt'), "r") lex = lexer.lexer pars = parser.Parser(test_file.read(), lex) pars.AST.visit() self.assertEqual(len(pars.AST.children), 8) self.assertEqual(len(pars.typedefDict), 4) self.assertTrue('myStructType' in pars.typedefDict) self.assertTrue('adr' in pars.typedefDict) self.assertTrue('DBMClock' in pars.typedefDict) self.assertTrue('clock' in pars.typedefDict) ctype = pars.typedefDict['clock'] self.assertEqual(ctype.type, 'NodeTypedef') self.assertEqual(ctype.leaf, 'clock') self.assertEqual(len(ctype.children), 1) self.assertEqual(ctype.children[0], pars.typedefDict['DBMClock']) declvisitor = parser.DeclVisitor(pars) #XXX parses to deeply into structs! self.assertEqual(len(declvisitor.variables), 5) pars.AST.visit() print declvisitor.variables varnames = [x for (x, _, _, _) in declvisitor.variables] self.assertTrue('m' in varnames) self.assertTrue(('m', 'myStructType', [], None) in declvisitor.variables) self.assertTrue('n' in varnames) self.assertTrue(('n', 'adr', [], None) in declvisitor.variables) self.assertTrue('n2' in varnames) for (x, _, _, initval) in declvisitor.variables: if x == "n2": self.assertEqual(initval.type, "Expression") self.assertEqual(initval.children[0].type, "Number") self.assertEqual(initval.children[0].leaf, 3) self.assertTrue('c' in varnames) self.assertTrue(('c', 'DBMClock', [], None) in declvisitor.variables)
def __init__(self, model, constant_overrides=dict()): model = SimplifyModel(model, constant_overrides).simplify() self.model = model self.transitions = {} self.sync_transitions = {} self.dynamic_sync_transitions = {} self.templatename_to_idx = {} self.num_templates = len(self.model.templates) self.invariants = {} self.externs = {} self.analyzer = AnalyzeModel(model, constant_overrides) self.analyzer.analyze() #mapping from template => location id => nice name self.location_labels = defaultdict(dict) lex = lexer.lexer pars = parser.Parser(model.declaration, lex) declvisitor = parser.DeclVisitor(pars) declvisitor.visit(pars.AST) self.clocks = declvisitor.clocks self.constants = self.analyzer.constants #evaluate array dimensions to values self.variables = [] for (vident, vtype, vdimensions, initval) in declvisitor.variables: for (dim, dim_idx) in zip(vdimensions, range(len(vdimensions))): vdimensions[dim_idx] = eval(util.expression_to_python(dim), {}, self.constants) if initval: initval = eval(util.expression_to_python(initval), {}, self.constants) elif vtype not in ['DBMFederation', 'DBMClock']: initval = 0 self.variables += [(vident, vtype, vdimensions, initval)] #evaluate channel array dimensions to values self.channels = [] self.channel_identifiers = [] def crossproduct(vdimensions): if len(vdimensions) == 1: for i in xrange(vdimensions[0]): yield "[%d]" % i else: for i in xrange(vdimensions[0]): for t in crossproduct(vdimensions[1:]): yield ("[%d]" % i) + t for (vident, vdimensions) in declvisitor.channels: self.channel_identifiers += [vident] if len(vdimensions) == 0: self.channels += [vident] continue for (dim, dim_idx) in zip(vdimensions, range(len(vdimensions))): vdimensions[dim_idx] = eval(util.expression_to_python(dim), {}, self.constants) for i in crossproduct(vdimensions): self.channels += [vident + i] #evaluate broadcast channel array dimensions to values self.broadcast_channels = [] for (vident, vdimensions) in declvisitor.broadcast_channels: self.channel_identifiers += [vident] if len(vdimensions) == 0: self.broadcast_channels += [vident] continue for (dim, dim_idx) in zip(vdimensions, range(len(vdimensions))): vdimensions[dim_idx] = eval(util.expression_to_python(dim), {}, self.constants) for i in crossproduct(vdimensions): self.broadcast_channels += [vident + i] #import needed externs for ex in pars.externList: self._loadExtern(ex, pars) logger.info("Constants: %s", self.constants) logger.info("Variables: %s", self.variables) logger.info("Clocks: %s", self.clocks) logger.info("Externs: %s", self.externs) logger.info("Typedefs: %s", pars.typedefDict) logger.info("Channels: %s", self.channels) logger.info("Broadcast Channels: %s", self.broadcast_channels) #Calculate invariants for (t, t_idx) in zip(self.model.templates, range(len(self.model.templates))): self.invariants[t_idx] = {} for (loc, l_idx) in zip(t.locations, range(len(t.locations))): if (loc.invariant.value != None): #the invariant should have the format: # statement; ... ; statement; expression #the statements are symbolic updates, while the #expression is what determines if the invariant is satisfied #example: # dbm &= (dbm.x <= 5); not dbm.isEmpty() #this should be backwards compatible. s = loc.invariant.value.split(';') statements = ";".join(s[:-1]) expression = util.expression_str_to_python(s[-1], self) logger.debug("Invariant: '%s' ==> ('%s', '%s')", loc.invariant.value, statements, expression) self.invariants[t_idx][l_idx] = (statements, expression) else: self.invariants[t_idx][l_idx] = ("", "") #calculate transitions for (t, t_idx) in zip(self.model.templates, range(len(self.model.templates))): self.transitions[t_idx] = {} self.sync_transitions[t_idx] = {} self.dynamic_sync_transitions[t_idx] = {} self.templatename_to_idx[t.name] = t_idx for (loc, l_idx) in zip(t.locations, range(len(t.locations))): if loc.name.get_value(): self.location_labels[t_idx][l_idx] = loc.name.get_value() self.transitions[t_idx][l_idx] = [] self.sync_transitions[t_idx][l_idx] = {} self.dynamic_sync_transitions[t_idx][l_idx] = [] for chan_name in self.channels: self.sync_transitions[t_idx][l_idx][chan_name + "!"] = [] self.sync_transitions[t_idx][l_idx][chan_name + "?"] = [] for chan_name in self.broadcast_channels: self.sync_transitions[t_idx][l_idx][chan_name + "!"] = [] self.sync_transitions[t_idx][l_idx][chan_name + "?"] = [] for tr in [tr for tr in t.transitions if tr.source == loc]: target_idx = t.locations.index(tr.target) debug_info = {} guard_code = None debug_info['guard_code'] = '' if tr.guard.value != '': logger.debug("Guard: %s", tr.guard.value) logger.debug( "==> %s", util.expression_str_to_python( tr.guard.value, self)) guard_code = compile( util.expression_str_to_python( tr.guard.value, self), "<guard>", 'eval') debug_info['guard_code'] = tr.guard.value update_code = None debug_info['update_code'] = '' if tr.assignment.value != '': update_code = compile( util.statement_str_to_python(tr.assignment.value), "<update>", 'exec') debug_info['update_code'] = tr.assignment.value static_sync = False sync_chan = None sync_way = None if tr.synchronisation.value != "": logger.debug("Sync: %s", tr.synchronisation.value) sync_way = tr.synchronisation.value.strip()[-1] static_sync, sync_chan = util.channame_str_to_python_format_string( tr.synchronisation.value.strip()[:-1], self) sync_chan += sync_way logger.debug("==> (%s, %s)", static_sync, sync_chan) list_curtrans = [(target_idx, guard_code, update_code, sync_chan, debug_info)] self.transitions[t_idx][l_idx] += list_curtrans if static_sync: self.sync_transitions[t_idx][l_idx][ sync_chan] += list_curtrans else: self.dynamic_sync_transitions[t_idx][ l_idx] += list_curtrans