예제 #1
0
    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)
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
 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
예제 #5
0
 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)
예제 #6
0
    def visitNumberAssignment(self, ctx: BSParser.NumberAssignmentContext):
        deff = self.visitVariableDefinition(ctx.variableDefinition())
        value = self.visitLiteral(ctx.literal())
        size = 1 if deff['index'] == -1 else deff['index']
        offset = deff['index'] if deff['index'] != size else -1

        variable = Number(deff['name'], size, value)
        self.symbol_table.get_local(deff['name'], self.scope_stack[-1]).value = variable

        ir = Constant({'name': deff['name'], 'offset': offset, 'size': size, 'var': variable},
                      variable.value)
        self.current_block.add(ir)

        return None
예제 #7
0
    def visitDetect(self, ctx: BSParser.DetectContext):
        """
        Cases to consider:
        1) a = dispense aaa
            x = detect mod on a
        2) a[n] = dispense aaa
            x = detect mod on a[m]
        3) a[n] = dispense aaa
            x = detect mod on a
        :param ctx:
        :return:
        """
        deff = self.visitVariableDefinition(ctx.variableDefinition())
        symbol = self.symbol_table.get_local(deff['name'], self.scope_stack[-1])

        time_meta = None
        if ctx.timeIdentifier():
            time = self.visitTimeIdentifier(ctx.timeIdentifier())
            time_meta = TimeConstraint(IRInstruction.DETECT, time['quantity'], time['units'])

        module = self.symbol_table.get_global(ctx.IDENTIFIER().__str__())
        use = self.visitVariable(ctx.variable())
        use_var = self.symbol_table.get_local(use['name'], self.scope_stack[-1])

        if symbol.value is None:
            symbol.value = Number(deff['name'], use_var.value.size)

        self.check_bounds({'index': use['index'], 'name': use_var.name, 'var': use_var.value})

        # if use['index'] == -1:
        #     use['index'] = use_var.value.size
        # if use['index'] == 0:
        #     use['index'] = 1
        # use_indices = list(use_var.value.value.keys())
        ir = Detect({'name': deff['name'], 'offset': use['index'], 'size': symbol.value.size, 'var': symbol.value},
                    {'name': module.name, 'offset': 0, 'size': float("inf"), 'var': module},
                    {'name': use['name'], 'offset': use['index'], 'size': use_var.value.size, 'var': use_var.value})
        if time_meta is not None:
            ir.meta.append(time_meta)
        self.current_block.add(ir)

        # for x in range(use['index']):
        #     ir = Detect({"name": deff['name'], 'offset': x},
        #                 {'name': module.name, 'offset': 0},
        #                 {'name': use['name'], 'offset': use_indices[x]})
        #     if time_meta is not None:
        #         ir.meta.append(time_meta)
        #     self.current_block.add(ir)
        return None
예제 #8
0
    def visitMath(self, ctx: BSParser.MathContext):
        deff = self.visitVariableDefinition(ctx.variableDefinition())
        deff_var = self.symbol_table.get_local(deff['name'],
                                               self.scope_stack[-1])
        deff_offset = 0 if deff['index'] == -1 else deff['index']
        size = 1 if deff['index'] == -1 else deff['index']
        # Has this variable been declared before?
        if deff_var.value is not None:
            self.check_bounds({
                'name': deff['name'],
                'index': deff['index'],
                'var': deff_var.value
            })
            deff_var = deff_var.value
        else:
            deff_var = Number(deff['name'], size)
            self.symbol_table.get_local(deff['name'],
                                        self.scope_stack[-1]).value = deff_var

        # Check to see if this is a constant or a variable
        op1 = self.visitPrimary(ctx.primary(0))
        if 'value' in op1.keys():
            op1_var = self.symbol_table.get_global('CONST_{}'.format(
                op1['value'])).value
        else:
            op1_var = self.symbol_table.get_local(op1['name'],
                                                  self.scope_stack[-1]).value
        self.check_bounds({
            'name': op1['name'],
            'index': op1['index'],
            'var': op1_var
        })

        # Check to see if this is a constant or a variable
        op2 = self.visitPrimary(ctx.primary(1))
        if 'value' in op2.keys():
            op2_var = self.symbol_table.get_global('CONST_{}'.format(
                op2['value'])).value
        else:
            op2_var = self.symbol_table.get_local(op2['name'],
                                                  self.scope_stack[-1]).value
        self.check_bounds({
            'name': op2['name'],
            'index': op2['index'],
            'var': op2_var
        })

        # Set the offsets for everything.
        op1_offset = 0 if op1['index'] == -1 else op1['index']
        op2_offset = 0 if op2['index'] == -1 else op2['index']

        # Grab the operand.
        outcome = 0
        if ctx.ADDITION():
            operand = BinaryOps.ADD
            outcome = op1_var.value[op1_offset] + op2_var.value[op2_offset]
        elif ctx.SUBTRACT():
            operand = BinaryOps.SUBTRACT
            outcome = op1_var.value[op1_offset] - op2_var.value[op2_offset]
        elif ctx.DIVIDE():
            operand = BinaryOps.DIVIDE
            outcome = op1_var.value[op1_offset] / op2_var.value[op2_offset]
        elif ctx.MULTIPLY():
            operand = BinaryOps.MULTIPLE
            outcome = op1_var.value[op1_offset] * op2_var.value[op2_offset]
        else:
            operand = BinaryOps.ADD
            outcome = op1_var.value[op1_offset] + op2_var.value[op2_offset]

        ir = Math(
            {
                'name': deff['name'],
                'offset': deff_offset,
                'size': deff_var.size,
                'var': deff_var
            }, {
                'name': op1_var.name,
                'offset': op1_offset,
                'size': op1_var.size,
                'var': op1_var
            }, {
                'name': op2_var.name,
                'offset': op2_offset,
                'size': op2_var.size,
                'var': op2_var
            }, operand)
        self.current_block.add(ir)

        if deff_var.value is None:
            deff_var.value = Number(deff['name'], value=outcome)

        return None
예제 #9
0
    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()