Cannot understand error message

Bill Davy Bill at SynectixLtd.com
Wed Feb 13 12:29:59 EST 2008


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"





More information about the Python-list mailing list