def check_declarations(self, declarations): """Checks for multiple declarations of the same pids and range of arrays. If no errors then return list with declared pids """ # Checking for multiple declarations declared = [] doubled = [] for pid in declarations: if pid[1] not in declared: declared.append(pid[1]) self.symtab.append(pid[:-1]) else: doubled.append(pid) if doubled: for pid in doubled: logging.error('Double declaration "{}" in line {}'.format( pid[1], pid[-1])) raise CompilerError() # Checkig arrays ranges for pid in declarations: if pid[0] == 'arr': if pid[2] > pid[3]: logging.error( 'Array "{}" in line {} has wrong ranges'.format( pid[1], pid[-1])) raise CompilerError() return declared
def check_pid(self, pid): if is_number(pid): return if pid[1] in self.tmp_vars: return if pid[1] not in self.declared: logging.error('Variable "{}" not declared, line {}'.format( pid[1], pid[-1])) raise CompilerError() if pid[0] == 'arr': if is_number(pid[2]): return if pid[2] in self.tmp_vars: return if pid[2] not in self.declared: logging.error('Variable "{}" not declared, line {}'.format( pid[2], pid[-1])) raise CompilerError() for iden in self.symtab: if iden[1] == pid[1]: if iden[0] != pid[0]: logging.error( 'Wrong "{}" has another type, line {}'.format( pid[1], pid[-1])) raise CompilerError()
def check_variable(self, variable): if is_int(variable): self.check_int(variable) elif is_array(variable): self.check_inttab(variable) else: raise CompilerError("Unexpected variable type")
def parse(self, source_code): if source_code: return self.parser.parse(source_code, lexer=self.lexer.lexer, debug=False) else: raise CompilerError("Input file is empty")
def operation_add(self, target, operands): x, y = operands if is_array(x) and is_array(y): pass if is_number(x): if is_number(y): self.parse('GENERATE n', n=x + y) self.parse('STORE t', t=target) return else: x, y = y, x # t := a + 1 if is_number(y): if y == 0: self.parse('LOAD x', x=x) elif y == 1: self.parse('LOAD x', x=x) self.parse('INC') else: self.parse('GENERATE n', n=y) self.parse('ADD x', x=x) # t := a + b # t := a + b[x] elif is_variable(y): self.parse('LOAD x', x=x) self.parse('ADD y', y=y) else: raise CompilerError("Unexpected symbol") self.parse('STORE a', a=target)
def operation_substract(self, target, operands): x, y = operands if is_number(x): # t := 1 - 1 if is_number(y): if x - y > 0: self.parse('GENERATE n', n=x - y) else: self.parse('ZERO') # t := 1 - a # t := 1 - a[x] elif is_variable(y): self.parse('GENERATE n', n=x) self.parse('SUB a', a=y) elif is_variable(x): # t := a - 1 if is_number(y): if y == 0: self.parse('LOAD a', a=x) elif y == 1: self.parse('LOAD a', a=x) self.parse('DEC') else: self.parse('GENERATE n', n=y) self.parse('STORE a', a=Reg.r0) self.parse('LOAD x', x=x) self.parse('SUB a', a=Reg.r0) # t := a - b # t := a - b[x] elif is_variable(y): self.parse('LOAD a', a=x) self.parse('SUB a', a=y) else: raise CompilerError("Unexpected symbol") self.parse('STORE a', a=target)
def raise_error(msg, lineno=None): error_msg = "" if lineno: error_msg += " in line {0}: ".format(lineno) error_msg += msg logging.error(error_msg) raise CompilerError()
def t_ANY_error(self, t): if t.value[0] == ')': error_msg = " In line {}: Are you trying to close unopened comment?".format( t.lexer.lineno) else: error_msg = " In line {}: Illegal character '{}'".format( t.lexer.lineno, t.value[0]) raise CompilerError(error_msg)
def test(self, data): self.lexer.input(data) while True: tok = self.lexer.token() if not tok: break else: logging.error('Lexer error') raise CompilerError()
def check_iterator(self, iterator): _, iter_symbol, iter_lineno = iterator if iter_symbol in self.scope: raise_error( msg= "trying to set previously declared variable '{0}' as iterator". format(iter_symbol), lineno=iter_lineno) raise CompilerError()
def check_initialization(self, pid): if is_number(pid): return if pid[1] in self.tmp_vars: return if pid[1] not in self.initialized: logging.error( 'Using uninitialized variable "{}" in line {}'.format( pid[1], pid[-1])) raise CompilerError()
def assign(self, target, expression): _, *value = expression if is_operation(value): self.assign_operation(target, value) else: if is_variable(value[0]): self.assign_variable(target, value[0]) elif is_number(value[0]): self.assign_number(target, value[0]) else: raise CompilerError("Unknown value type")
def check_scope(self, operand): if is_number(operand): pass elif is_int(operand): if operand[1] not in self.scope: raise_error(msg="Undeclared variable {}".format(operand[1]), lineno=operand[2]) elif is_array(operand): if is_number(operand[2]): self.check_inttab(operand) else: raise CompilerError("Unexpected operand")
def check_inttab(self, variable): _, symbol, index, lineno = variable arr_start = '#'.join([symbol, '0']) if arr_start not in self.scope: raise_error("Usage of undeclared array {}".format(symbol), lineno) if is_number(index): self.check_inttab_index(variable) elif is_int(index): self.check_variable(index) else: raise CompilerError("Unexpected array index")
def check_expression(self, cmd): _, *expression = cmd if len(expression) == 1: [var] = expression if is_variable(var): self.check_variable(var) self.check_initialized(var) elif len(expression) == 3: [_, l_var, r_var] = expression for var in [l_var, r_var]: if is_variable(var): self.check_variable(var) self.check_initialized(var) else: raise CompilerError("Unexpected expression")
def check_assign(self, cmd): _, target, expression = cmd self.check_scope(target) if is_int(target): _, symbol, lineno = target if symbol in self.iterators: raise_error( "Mutation of iterator '{symbol}'".format(symbol=symbol), lineno) elif is_array(target): _, symbol, index, _ = target symbol = '#'.join([symbol, str(index)]) else: raise CompilerError("Unexpected target type") self.check_expression(expression) self.initialized[symbol] = True
def parse_array(self, left, right): _, var, index, *_ = right if is_number(index): array = self.mem['{}#0'.format(var)] arr_addr = array['address'] cell_addr = index + arr_addr code = '{cmd} {param}'.format(cmd=left, param=cell_addr) self.code.append(code) elif is_reg(index): self.code.append('{cmd}I {reg}'.format(cmd=left, reg=index[1])) elif is_variable(index): left += 'I' array = self.mem['{}#0'.format(var)] arr_start_ptr = array['start_ptr'] if left == 'LOADI': self.code.append( 'LOAD {arr_start_ptr}'.format(arr_start_ptr=arr_start_ptr)) code = """ ADD x STORE r9 LOADI r9 """ self.parse(code, x=index, r9=Reg.r9) elif left in ['STOREI', 'ADDI', 'SUBI']: self.parse(""" STORE r8 """, r8=Reg.r8) self.code.append( 'LOAD {arr_start_ptr}'.format(arr_start_ptr=arr_start_ptr)) code = """ADD x STORE r9 LOAD r8 {cmd} r9 """.format(cmd=left, arr_size=arr_start_ptr) self.parse(code, x=index, r9=Reg.r9, r8=Reg.r8) else: raise CompilerError("Unexpected command")
def t_comment_eof(self, t): raise CompilerError(" In line %d: Unterminated comment" % t.lexer.lineno)
def read(self, target): if is_variable(target): self.read_variable(target) else: raise CompilerError("Cannot READ non-variable")
def p_error(self, p): logging.error(" in line {lineno}: unknown symbol '{value}'".format( lineno=p.lineno, value=p.value )) raise CompilerError()
def parse(self, data): if data: return self.parser.parse(data, self.lexer.lexer, 0, 0, None) else: logging.error("Input file is empty") raise CompilerError()
def t_error(self, t): logging.error(f'Illegal character {t.value[0]} in line {t.lineno}') raise CompilerError()
def p_error(self, p): logging.error(f"Syntax error '{p.value}' in line {p.lineno}") raise CompilerError()