def update_symbol(self, symbol: Symbol) -> Symbol: self.current_scope.locals[symbol.name] = symbol #if symbol.value == None and symbol.scope is not 'main' and next(iter(self.scope_map[symbol.scope].locals)) == symbol.name: #symbol.value = Reagent(symbol.name, 1, 10.0, BSVolume.MICROLITRE) #add a pseudo value if symbol.value == None and symbol.scope is not 'main' and symbol.name in self.scope_map[symbol.scope].locals: symbol.value = Reagent(symbol.name, 1, 10.0, BSVolume.MICROLITRE) # add a pseudo value elif symbol.value == None and len(symbol.types) == 2: symbol.value = Reagent(symbol.name, 1, 10.0, BSVolume.MICROLITRE) # add a pseudo value return symbol
def visitRepeat(self, ctx: BSParser.RepeatContext): # 'repeat value times' is translated in the IR as while (value > 0), with a decrement # appended to the end of the expression block; hence, # to ease translation later, we add a global for const(0) and const(1) if not self.symbol_table.get_global('CONST_0'): globalz = Symbol('CONST_0', 'global', ChemTypeResolver.numbers()) globalz.value = Number('CONST_0', 1, 0) self.symbol_table.add_global(globalz) if not self.symbol_table.get_global('CONST_1'): globalz = Symbol('CONST_1', 'global', ChemTypeResolver.numbers()) globalz.value = Number('CONST_1', 1, 1) self.symbol_table.add_global(globalz) self.visitChildren(ctx)
def visitMath(self, ctx: BSParser.MathContext): deff = self.visitVariableDefinition(ctx.variableDefinition()) symbol = Symbol(deff['name'], self.scope_stack[-1], ChemTypeResolver.numbers()) for use in ctx.primary(): var = self.visitPrimary(use) # This places any constants into the global symbol table. # By doing this, it makes it significantly easier to handle # arithmetic later in the compilation process. if 'value' in var.keys() and not self.symbol_table.get_global( var['name']): globalz = Symbol(var['name'], 'global', ChemTypeResolver.numbers()) globalz.value = Number(var['name'], 1, var['value']) self.symbol_table.add_global(globalz) if not ChemTypeResolver.is_number_in_set(var['types']): local = self.symbol_table.get_local(var['name']) if not local: raise UndefinedVariable("{} is not defined.".format( var['name'])) local.types.update(ChemTypeResolver.numbers()) if ChemTypes.UNKNOWN in local.types: local.types.remove(ChemTypes.UNKNOWN) self.symbol_table.update_symbol(local) self.symbol_table.add_local(symbol) return None
def visitBinops(self, ctx: BSParser.BinopsContext): op1 = self.visitPrimary(ctx.primary(0)) op2 = self.visitPrimary(ctx.primary(1)) # This places any constants into the global symbol table. # By doing this, it makes it significantly easier to handle # arithmetic later in the compilation process. if 'value' in op1.keys() and not self.symbol_table.get_global( op1['name']): globalz = Symbol(op1['name'], 'global', ChemTypeResolver.numbers()) globalz.value = Number(op1['name'], 1, op1['value']) self.symbol_table.add_global(globalz) if 'value' in op2.keys() and not self.symbol_table.get_global( op2['name']): globalz = Symbol(op2['name'], 'global', ChemTypeResolver.numbers()) globalz.value = Number(op2['name'], 1, op2['value']) self.symbol_table.add_global(globalz)
def visitExpressionList(self, ctx: BSParser.ExpressionListContext): args = list() for primary in ctx.primary(): arg = self.visitPrimary(primary) if 'value' in arg.keys() and self.symbol_table.get_global( "CONST_{}".format(arg['value'])) is None: const = Symbol('CONST_{}'.format(arg['value']), 'global', arg['value']) const.value = Number(const.name, 1, arg['value']) self.symbol_table.add_global(const) args.append(self.visitPrimary(primary)) return args
def visitNumberAssignment(self, ctx: BSParser.NumberAssignmentContext): deff = self.visitVariableDefinition(ctx.variableDefinition()) symbol = Symbol(deff['name'], self.scope_stack[-1], ChemTypeResolver.numbers()) self.symbol_table.add_local(symbol) # Yes, this is assigning value to something, # But this is a constant. So we know all # of the values up front. This also makes # the IRVisitor easier to work with. value = self.visitLiteral(ctx.literal()) const = Symbol('CONST_{}'.format(value), 'global', ChemTypeResolver.numbers()) const.value = Number('CONST_{}'.format(value), 1, value) self.symbol_table.add_global(const)
def visitRepeat(self, ctx: BSParser.RepeatContext): # get the (statically defined!) repeat value and add to local symbol table value = self.visitLiteral(ctx) val = { 'name': "REPEAT_{}".format(value), "index": 0, 'value': value, 'types': ChemTypeResolver.numbers() } if 'value' in val.keys() and not self.symbol_table.get_local( val['name']): localz = Symbol(val['name'], 'global', ChemTypeResolver.numbers()) localz.value = Number(val['name'], 1, val['value']) self.symbol_table.add_local(localz) # finished with this block self.functions[self.scope_stack[-1]]['blocks'][ self.current_block.nid] = self.current_block # insert header block for the conditional header_block = BasicBlock() header_label = Label("bsbbr_{}_h".format(header_block.nid)) self.labels[header_label.name] = header_block.nid header_block.add(header_label) self.graph.add_node(header_block.nid, function=self.scope_stack[-1], label=header_label.label) self.functions[self.scope_stack[-1]]['blocks'][ header_block.nid] = header_block self.graph.add_edge(self.current_block.nid, header_block.nid) zero = self.symbol_table.get_global('CONST_0') op = BinaryOp(left={ 'name': val['name'], 'offset': 0, 'size': 1, 'var': self.symbol_table.get_local(val['name']) }, right={ 'name': zero.name, 'offset': 0, 'size': 1, 'var': zero }, op=RelationalOps.GT) condition = Conditional( RelationalOps.GT, op.left, op.right) # Number('Constant_{}'.format(0), 1, 0)) header_block.add(condition) self.control_stack.append(header_block) # set up the true block true_block = BasicBlock() true_label = Label("bsbbr_{}_t".format(true_block.nid)) self.labels[true_label.name] = true_block.nid true_block.add(true_label) self.graph.add_node(true_block.nid, function=self.scope_stack[-1]) self.functions[self.scope_stack[-1]]['blocks'][ true_block.nid] = true_block condition.true_branch = true_label self.graph.add_edge(header_block.nid, true_block.nid) self.current_block = true_block self.visitBlockStatement(ctx.blockStatement()) # repeat is translated to a while loop as: while (exp > 0); # hence, we update exp by decrementing. one = self.symbol_table.get_global('CONST_1') ir = Math( { 'name': val['name'], 'offset': 0, 'size': 1, 'var': self.symbol_table.get_local(val['name']) }, { 'name': val['name'], 'offset': 0, 'size': 1, 'var': self.symbol_table.get_local(val['name']) }, { 'name': one.name, 'offset': 0, 'size': 1, 'var': one }, BinaryOps.SUBTRACT) self.current_block.add(ir) # the block statement may contain nested loops # If so, the current block is the last false block created for the inner-most loop # otherwise, the current block is the true_block created above # Either way, we can pop the control stack to find where to place the back edge # and immediately make the back edge (from 'current block' to the parent parent_block = self.control_stack.pop() self.graph.add_edge(self.current_block.nid, parent_block.nid) # we now deal with the false branch false_block = BasicBlock() false_label = Label("bsbbr_{}_f".format(false_block.nid)) self.labels[false_label.name] = false_block.nid false_block.add(false_label) condition.false_branch = false_label self.graph.add_edge(header_block.nid, false_block.nid) # We are done, so we need to handle the book keeping for # next basic block generation. self.graph.add_node(false_block.nid, function=self.scope_stack[-1]) self.functions[self.scope_stack[-1]]['blocks'][ false_block.nid] = false_block self.current_block = false_block return NOP()