The following code produces an error message (using Idle with Py 2.4 and 2.5). "There's an error in your program: EOL while scanning single-quoted string". It comes just after "s = ''" (put there to try and isolate the broken string).
It would be good if the error message pointed me to the start of said single quoted string. The colouring in IDLE does not indicate a bad string. Puzzled. Bill # # The traceback module is used to provide a stack trace to # show the user where the error occured. See Error(). # import traceback # # The math module is used to convert numbers between the Python real format # and the Keil real format. See KeilToFloatingPoint() and FloatingToKeil(). # import math LOAD_LIT = 1 LOAD_REG = 1 STORE_REG = 1 ADD_LIT_FP = 2 + 8 ADD_LIT_INT = 2 + 16 ADD_REG_FP = 2 + 32 ADD_REG_INT = 9 SUB_LIT_FP = 11 SUB_LIT_INT = 12 SUB_REG_FP = 13 SUB_REG_INT =14 MUL_LIT_FP = 11 MUL_LIT_INT = 12 MUL_REG_FP = 13 MUL_REG_INT =14 DIV_LIT_FP = 11 DIV_LIT_INT = 12 DIV_REG_FP = 13 DIV_REG_INT =14 AND_LIT_INT = 12 AND_REG_INT =14 OR_LIT_INT = 12 OR_REG_INT =14 NEGATE_FP = 11 NEGATE_INT = 12 ABSOLUTE_FP = 13 ABSOLUTE_INT = 14 INVERT_INT = 15 JUMP_OPCODE = 15 JLT_OPCODE = 15 JGT_OPCODE = 15 JLE_OPCODE = 15 JGE_OPCODE = 15 JEQ_OPCODE = 15 JNE_OPCODE = 15 BinaryOps={ "LOAD":{float:{"L":LOAD_LIT,"R":LOAD_REG},int:{"L":LOAD_LIT,"R":LOAD_REG}}, "STORE":{float:{"R":STORE_REG},int:{"R":STORE_REG}}, "ADD":{float:{"L":ADD_LIT_FP,"R":ADD_REG_FP},int:{"L":ADD_LIT_INT,"R":ADD_REG_INT}}, "SUB":{float:{"L":SUB_LIT_FP,"R":SUB_REG_FP},int:{"L":SUB_LIT_INT,"R":SUB_REG_INT}}, "MUL":{float:{"L":MUL_LIT_FP,"R":MUL_REG_FP},int:{"L":MUL_LIT_INT,"R":MUL_REG_INT}}, "DIV":{float:{"L":DIV_LIT_FP,"R":DIV_REG_FP},int:{"L":DIV_LIT_INT,"R":DIV_REG_INT}}, "AND":{int:{"L":AND_LIT_INT,"R":AND_REG_INT}}, "OR":{int:{"L":OR_LIT_INT,"R":OR_REG_INT}} } UnaryOps={ "NEGATE":{float:NEGATE_FP, int:NEGATE_INT}, "ABSOLUTE":{float:ABSOLUTE_FP, int:ABSOLUTE_INT}, "INVERT":{int:INVERT_INT} } JumpOps={ "JUMP":JUMP_OPCODE, "JLT":JLT_OPCODE, "JGT":JGT_OPCODE, "JLE":JLE_OPCODE, "JGE":JGE_OPCODE, "JEQ":JEQ_OPCODE, "JNE":JNE_OPCODE } def IsOpCode(s): if ( s in BinaryOps ): return True; if ( s in UnaryOps ): return True; if ( s in JumpOps ): return True; return False class Register: """ This class provides us with a register (say) 0..32 In addtion to a number, a register can be given a name. It allows LOAD(arg) and other opcodes to distinguish between references to a register and a literal value. """ def __init__(self,Id,Name=None): self.Number = Id if ( Name == None): self.Name = "R%d" % Id else: self.Name = Name def RegisterNumber(self): return self.Number def RegisterName(self): return self.Name R0=Register(0) R1=Register(1) R2=Register(2) Now=Register(2,"Now") def IsRegister(arg): return hasattr( arg, "RegisterNumber") assert not IsRegister(0) assert not IsRegister(1.2) assert IsRegister(R1) assert IsRegister(Now) # # ErrorCount is global as it is shared by all slaves. # ErrorCount = 0 def Error(Message): """ work back through the traceback until you find a function whose name is in one of the opcode dictionaries and trace back from there. This will keep internal implemenataion functions private but still allow the suer to define functions that generate code. """ global ErrorCount ErrorCount += 1 """ [ ('<string>', 1, '?', None), ('C:\\Python24\\lib\\idlelib\\run.py', 90, 'main', 'ret = method(*args, **kwargs)'), ('C:\\Python24\\lib\\idlelib\\run.py', 283, 'runcode', 'exec code in self.locals'), ('H:\\Husky Experiments\\Viper1\\tmp.py', 434, '?', 'STORE(1)'), ('H:\\Husky Experiments\\Viper1\\tmp.py', 147, 'STORE', 'self.BINOP("STORE",Arg,Msg)'), ('H:\\Husky Experiments\\Viper1\\tmp.py', 198, 'BINOP', 'return Error("Cannot perform %s on %s" % (Op,Arg))'), ('H:\\Husky Experiments\\Viper1\\tmp.py', 106, 'Error', 'tb = traceback.extract_stack()') ] """ tb = traceback.extract_stack() BeforePrinting = True IsPrinting = False for i in range(len(tb)-1,0,-1): frame = tb[i] if ( BeforePrinting ): # Looking to start if IsOpCode(frame[2]): # start printing IsPrinting = True BeforePrinting = False print "John: %s\nTrace back follows:" % Message elif ( IsPrinting ): print '\tFile "%s", line %u, %s' % (frame[0], frame[1], frame[3]) # Stop when we find the curious function "?" if (frame[2] == "?"): break if BeforePrinting: print "John: %s (no trace back)" % Message class Slave: "This is a slave class" Listing = "" Number = 0 Mode = 0; # Will be int or float when defined def __init__(self,Id): self.Number = Id self.Line = 0 # # The listing, built as we go along # self.Listing = "" self.Mode = None def SetMode(self, arg): self.Mode = arg def LOAD(self,Arg,Msg=""): self.BINOP("LOAD",Arg,Msg) def STORE(self,Arg,Msg=""): self.BINOP("STORE",Arg,Msg) def ADD(self,Arg,Msg=""): self.BINOP("ADD",Arg,Msg) def SUB(self,Arg,Msg=""): self.BINOP("SUB",Arg,Msg) def MUL(self,Arg,Msg=""): self.BINOP("MUL",Arg,Msg) def DIV(self,Arg,Msg=""): self.BINOP("DIV",Arg,Msg) def AND(self,Arg,Msg=""): self.BINOP("AND",Arg,Msg) def OR(self,Arg,Msg=""): selfBINOPOP("OR",Arg,Msg) def NEGATE(self,Msg=""): self.UNOP("NEGATE",Msg) def ABSOLUTE(self,Msg=""): self.UNOP("ABSOLUTE",Msg) def INVERT(self,Msg=""): self.UNOP("INVERT",Msg) def JUMP(self,Arg,Msg=""): self.JUMPOP("JUMP",Arg,Msg) def JLT(self,Arg,Msg=""): self.JUMPOP("JLT",Arg,Msg) def JGT(self,Arg,Msg=""): self.JUMPOP("JGT",Arg,Msg) def JLE(self,Arg,Msg=""): self.JUMPOP("JLE",Arg,Msg) def JGE(self,Arg,Msg=""): self.JUMPOP("JGE",Arg,Msg) def JEQ(self,Arg,Msg=""): self.JUMPOP("JEQ",Arg,Msg) def JNE(self,Arg,Msg=""): self.JUMPOP("JNE",Arg,Msg) def BINOP(self,Op,Arg,Msg): entry = BinaryOps.get(Op) assert entry != None, "Who gave me %s to look up?" % op entry = entry.get(self.Mode) if entry == None : return Error("Cannot perform %s on %s, mode=%s" % ( Op,Arg,self.Mode)) if ( IsRegister(Arg) ): ot = entry.get("R") # Register if ot == None: return Error("Cannot perform %s on %s" % (Op,Arg)) self.Listing += "%x \t \t%s\t%s\t# %s\n" % ( len(self.Memory), Op,Arg.RegisterName(), Msg) self.Memory.append(ot) self.Memory.append(Arg.RegisterNumber()) else: ot = entry.get("L") # Literal if ot == None: return Error("Cannot perform %s on %s" % (Op,Arg)) self.Listing += "%x \t \t%s\t%s\t# %s\n" % ( len(self.Memory), Op, Arg, Msg) self.Memory.append(ot) cArg = self.Mode(Arg) if self.Mode == int: try: iArg = int(Arg) except TypeError: return Error("Argument %r is not an integer" % Arg) except: return Error("Unexpected error:", sys.exc_info()[0]) if ( iArg != Arg ): return Error("Argument %r is not an integer" % Arg) self.Memory.append((iArg >> 24) & 0xFF) self.Memory.append((iArg >> 16) & 0xFF) self.Memory.append((iArg >> 8) & 0xFF) self.Memory.append((iArg >> 0) & 0xFF) elif self.Mode == float: try: fArg = float(Arg) except TypeError: return Error("Argument %r is not a float" % Arg) except: return Error("Unexpected error:", sys.exc_info()[0]) if ( fArg != Arg ): return Error("Argument %r is not a float" % Arg) FourBytes = FloatingToKeil(fArg) self.Memory.append(FourBytes[0]) self.Memory.append(FourBytes[1]) self.Memory.append(FourBytes[2]) self.Memory.append(FourBytes[3]) else: return Error("No or bad mode (%r)set for slave %u" % ( self.Mode,self.SlaveNumber)) def JUMPOP(self,Op,Name,Msg): entry = JumpOps.get(Op) assert entry != None, "Who gave me %s to look up?" % op """ Generate code for a jump to the given target May enter target into the table. """ self.Listing += "%x \t \t%s\t%s\t# %s\n" % ( len(self.Memory),Op,Name, Msg) self.Memory.append(entry) self.AddReference(Name,len(self.Memory)) # for patching up later self.Memory.append(0) # Space for destination of jump # # The memory image of this Slave. # Memory = [] def ListProgram(self): """Generate a user friendly listing of the program for this Slave. """" s = '' print "%s" % self.Number print "%s\n" % ("#" * 64) print "%s" % self.Listing pass def EmitProgram(self): """Emit a C code data structure of the program for this Slave. """ s=\ "%s\n/* C data structure for slave %d */\n"\ "struct\n"\ "\t{\n"\ "\tunsigned SlaveId;\n"\ "\tunsigned nBytes;\n"\ "\tunsigned char[%d];\n"\ "\t} Slave%d=\n"\ "\t{%u,%u\n"\ "\t{\n\t"\ % ('#'*64, self.Number, len(self.Memory), self.Number, self.Number, len(self.Memory)) for i in range(0,len(self.Memory)): if (i>0) : s+= ", " s += "0x%x" % (self.Memory[i]) if ( (i % 16) == 15 ): s += '\n\t' s+="\n\t}\n\t};\n" print s; # # Dictionary of Labels # Maps Name onto (Set of Locations, List of references)) # Users define a label using Label(Name) # Users reference a label using Jump(Name) # LabelTable = {} def AddReference(self,Name,Reference): """ Add a reference to the given Name. Name may not yet be defined """ Entry = self.LabelTable.get(Name) if ( Entry == None ): self.LabelTable[Name] = [ [] , [Reference] ] else: Entry[1].append(Reference) def AddDefinition(self,Name,Location): """ Add a definition to the given Name. Name may not yet be defined. If it is defined, it may not be given a different Location. """ Entry = self.LabelTable.get(Name) if ( Entry == None ): # Add location to a new name self.LabelTable[Name] = [ [Location] , [] ] elif len(Entry[0]) == 0: # Provide an initial location for a known name Entry[0].append(Location) elif Entry[0].count(Location) == 1: # The same location, harmless but odd pass else: # This is an additional definition but that does not matter # unless it is used and we find that out when we call FixUpLabels() # at the end. Entry[0].append(Location) def Label(self, Name, Msg=""): """ Lays down a label for the user. """ self.AddDefinition(Name,len(self.Memory)) self.Listing += "%x \t%s: \t \t \t# %s\n" % (len(self.Memory), Name, Msg) def EmitLabelTable(self): print "%s\nSymbol table for Slave %u" % ('#' * 64, self.Number) for Name in self.LabelTable.keys(): s = "Name=%s" % Name entry = self.LabelTable[Name] if ( len(entry[0])==1 and len(entry[1]) == 0): s += ", is not referenced" if ( len(entry[0])==0 and len(entry[1]) > 0): s += ", is not defined" if ( len(entry[0])>1 and len(entry[1]) > 0): s += ", is multiply-defined" if ( len(entry[0]) > 0): s += ", Location:" for i in entry[0]: s += " %x" % i if ( len(entry[1]) > 0 ): s += ", references:" for i in range(0,len(entry[1])): s += " %x" % entry[1][i] print s def FixUpLabels(self): print "%s\nFixing labels for Slave %u" % ('#' * 64, self.Number) for Name in self.LabelTable.keys(): entry = self.LabelTable[Name] if ( len(entry[0])==1 and len(entry[1]) == 0): print "Warning: %s is not referenced" % Name elif ( len(entry[0])==0 and len(entry[1]) > 0): Error("%s is not defined" % Name) elif ( len(entry[0])>1 and len(entry[1]) > 0): Error("%s is multiply-defined" % Name) else: for i in range(0,len(entry[1])): self.Memory[entry[1][i]] = entry[0][0] # # Construct a vector of Slaves # S=[(Slave(i)) for i in range(6)] def SetSlave(New): """ Make global functions generate code for a specified slave. """ # # This sets the mode for the assembler and applies in the order of # assembly, not in the execution order. The mode is embedded in the opcode. # global SetMode SetMode = S[New].SetMode # # Labels are local to a slave. # global Label Label = S[New].Label; global LOAD, STORE, ADD, SUB, MUL, DIV, AND, OR global NEGATE, ABSOLUTE, INVERT global JUMP, JLT, JGT, JLE, JGE, JEQ, JNE LOAD = S[New].LOAD JUMP = S[New].JUMP LOAD = S[New].LOAD STORE = S[New].STORE ADD = S[New].ADD SUB = S[New].SUB MUL = S[New].MUL DIV = S[New].DIV AND = S[New].AND OR = S[New].OR NEGATE = S[New].NEGATE ABSOLUTE = S[New].ABSOLUTE INVERT = S[New].INVERT JUMP = S[New].JUMP JLT = S[New].JLT JGT = S[New].JGT JLE = S[New].JLE JGE = S[New].JGE JEQ = S[New].JEQ JNE = S[New].JNE print "hi" SetSlave(1) SetMode(int) LOAD(4,"Into S1 hopefully") Label("Loop") LOAD(R1,"Comment") JUMP("Loop") LOAD(Now) JUMP("Loop") STORE(1) Label("Loop") class TemporaryLabelClass: DefaultBaseName = "TL_" Instances = {DefaultBaseName:0} def __init__(self, BaseName=None): de = self.Instances.get(BaseName) if de == None: self.Instances[BaseName] = 0 # new temporary BaseName else: self.Instances[BaseName] += 1 # using an existing BaseName again self.BaseName = BaseName; def Instance(self): return self.Instances[self.BaseName] def TemporaryLabel(BaseName=None): t = TemporaryLabelClass(BaseName) if ( BaseName == None ): BaseName = t.DefaultBaseName elif ( BaseName == t.DefaultBaseName): return Error("Do not call TemporaryLabel(%s)" % t.DefaultBaseName) return "%s%u" % (BaseName,t.Instance()) a = TemporaryLabel() b = TemporaryLabel("MY") c = TemporaryLabel() d = TemporaryLabel("MY") e = TemporaryLabel() f = TemporaryLabel("TL_") del a, b, c, d, e, f def BusyIdleLoop(Time, Register): label = TemporaryLabel() LOAD(Now) ADD(Time) STORE(Register) Label(label) LOAD(Now) SUB(Register) JLT(label) BusyIdleLoop(5000,R0) S[1].FixUpLabels() S[1].EmitProgram() S[1].EmitLabelTable() S[1].ListProgram() def KeilToFloatingPoint(Bytes): #print Bytes temp = ((((((Bytes[0]<<8)+Bytes[1])<<8)+Bytes[2])<<8)+Bytes[3]) if ( temp == 0): return 0.0 Mantissa = 0x800000 + (temp&0x7fffff) if ( temp & 0x80000000 ): Mantissa = -Mantissa temp -= 0x80000000 Exponent = (0xFF & (temp>>23)) - 127; Mantissa = float(Mantissa) / (1<<23) #print "Mantissa=%f" % Mantissa #print "Exponent=%x" % Exponent return math.ldexp(Mantissa, Exponent) def FloatingToKeil(arg): """ The flooating point format used by Keil follows the IEEE-754 standard The fields are (from MSB to LSB, and first byte to last): S (one bit) 1 is posirtive, 0 is negative E (eight bits) Exponent + 127 M (23 bits) The twenty four bit (MSB omitted) mantissa """ Mantissa, Exponent = math.frexp( arg ) Mantissa *= 2 Exponent -= 1 if ( Mantissa >= 0 ): if ( Exponent == 0 ): return (0,0,0,0) S = 0 else: S = 1 Mantissa = -Mantissa Mantissa *= (1<<23) Mantissa = int(Mantissa + 0.5) # round if ( Mantissa >> 24 ): # Renormalise Mantissa >>= 1 Exponent += 1 assert ( (Mantissa >> 24) == 0) Mantissa -= (1<<23) # Remove the "assumed" 1 before the binary point assert ( (Mantissa >> 23) == 0 ) Exponent += 127 if ( Exponent < 0 ): # Number is too small to represent; call it zero FourBytes = 0,0,0,0 temp = KeilToFloatingPoint(FourBytes) print "Truncating %r to %r" % (arg, temp) elif ( Exponent > 0xFF): # Number is too big to represent; make the maximum with the right sign FourBytes = (S<<7)+0x7F,0xFF,0xFF,0xFF temp = KeilToFloatingPoint(FourBytes) print "Truncating %r to %r" % (arg, temp) else: temp = (S<<31) + (Exponent<<23) + Mantissa FourBytes = ((temp>>24),0xFF&(temp>>16),0xFF&(temp>>8),0xFF&(temp)) temp = KeilToFloatingPoint(FourBytes) return FourBytes FloatingToKeil(-12.5) FloatingToKeil(-1e-200) ## should become zero FloatingToKeil(-1e+200) ## should saturate FloatingToKeil(math.ldexp((1<<24)-1,-24)) ## Exact conversion FloatingToKeil(math.ldexp((1<<25)-1,-25)) ## Should make renormalise happen print "Byeee" -- http://mail.python.org/mailman/listinfo/python-list