Commit bc48349a authored by Michael Büsch's avatar Michael Büsch

Add ID number to source object

Signed-off-by: Michael Büsch's avatarMichael Buesch <m@bues.ch>
parent 921963cf
......@@ -158,7 +158,6 @@ class S7CPU(object):
try:
insn = AwlInsnTranslator.fromRawInsn(self, rawInsn)
insn.setIP(ip)
insn.setFileNr(self.__currentAwlFileNr)
except AwlSimError as e:
if e.getRawInsn() is None:
e.setRawInsn(rawInsn)
......@@ -541,8 +540,6 @@ class S7CPU(object):
db = self.__translateDB(rawDB)
self.dbs[dbNumber] = db
self.__currentAwlFileNr += 1
def loadSymbolTable(self, symbolTable):
self.symbolTable.merge(symbolTable)
......@@ -566,7 +563,6 @@ class S7CPU(object):
CallStackElem.resetCache()
def reset(self):
self.__currentAwlFileNr = 0
self.dbs = {
# DBs
0 : DB(0, permissions = 0), # read/write-protected system-DB
......
......@@ -28,13 +28,14 @@ from awlsim.core.enumeration import *
class AwlSimError(Exception):
def __init__(self, message, cpu=None,
rawInsn=None, insn=None, lineNr=None,
fileId=None):
sourceId=None, sourceName=None):
Exception.__init__(self, message)
self.cpu = cpu
self.rawInsn = rawInsn
self.insn = insn
self.lineNr = lineNr
self.fileId = fileId
self.sourceId = sourceId
self.sourceName = sourceName
def setCpu(self, cpu):
self.cpu = cpu
......@@ -54,11 +55,17 @@ class AwlSimError(Exception):
def getInsn(self):
return self.insn
def setFileId(self, fileId):
self.fileId = fileId
def setSourceId(self, sourceId):
self.sourceId = sourceId
def getFileId(self):
return self.fileId
def getSourceId(self):
return self.sourceId
def setSourceName(self, sourceName):
self.sourceName = sourceName
def getSourceName(self):
return self.sourceName
def setLineNr(self, lineNr):
self.lineNr = lineNr
......@@ -96,14 +103,14 @@ class AwlSimError(Exception):
return errorStr
def doGetReport(self, title):
fileId = self.getFileId()
if fileId:
fileId += " "
sourceName = self.getSourceName()
if sourceName:
sourceName += " "
else:
fileId = ""
sourceName = ""
ret = [ "-- %s --\n" % title ]
ret.append("ERROR at %sline %s:\n" %\
(fileId, self.getLineNrStr()))
(sourceName, self.getLineNrStr()))
ret.append(" \n%s\n" % str(self))
cpu = self.getCpu()
if cpu:
......
......@@ -433,7 +433,6 @@ class AwlInsn(object):
self.cpu = cpu
self.type = type
self.rawInsn = rawInsn
self.fileNr = -1 # AWL file number
self.ip = None # Instruction pointer (IP)
self.ops = [] # Operators
self.params = [] # Parameter assignments (for CALL)
......@@ -462,12 +461,14 @@ class AwlInsn(object):
def setIP(self, newIp):
self.ip = newIp
def setFileNr(self, newFileNr):
self.fileNr = newFileNr
def getCpu(self):
return self.cpu
def getSourceId(self):
if not self.rawInsn:
return None
return self.rawInsn.getSourceId()
def getLineNr(self):
if not self.rawInsn:
return -1
......
......@@ -33,6 +33,7 @@ from awlsim.core.project import *
class RawAwlInsn(object):
def __init__(self, block):
self.block = block
self.sourceId = None
self.lineNr = 0
self.label = None
self.name = None
......@@ -54,6 +55,12 @@ class RawAwlInsn(object):
ret.extend(self.getOperators())
return " ".join(ret)
def setSourceId(self, sourceId):
self.sourceId = sourceId
def getSourceId(self):
return self.sourceId
def setLineNr(self, newLineNr):
self.lineNr = newLineNr
......@@ -266,7 +273,8 @@ class AwlParseTree(object):
self.curBlock = None
self.fileId = ""
self.sourceId = None
self.sourceName = None
class AwlParser(object):
EnumGen.start
......@@ -352,9 +360,10 @@ class AwlParser(object):
return self.__inAnyHeader() or\
self.state == self.STATE_GLOBAL
def __tokenize(self, data, fileId):
def __tokenize(self, data, sourceId, sourceName):
self.reset()
self.tree.fileId = fileId
self.tree.sourceId = sourceId
self.tree.sourceName = sourceName
self.lineNr = 1
t = self.TokenizerState(self)
......@@ -607,6 +616,7 @@ class AwlParser(object):
def __parseInstruction(self, t):
insn = RawAwlInsn(self.tree.curBlock)
insn.setLineNr(t.tokensLineNr)
insn.setSourceId(self.tree.sourceId)
if t.tokens[0].endswith(":"):
# First token is a label
if len(t.tokens) <= 1:
......@@ -975,9 +985,11 @@ class AwlParser(object):
def parseSource(self, awlSource):
"""Parse an AWL source.
awlSource is an AwlSource instance."""
self.parseData(awlSource.sourceBytes, str(awlSource))
self.parseData(awlSource.sourceBytes,
sourceId = awlSource.identNr,
sourceName = awlSource.name)
def parseData(self, dataBytes, fileId=""):
def parseData(self, dataBytes, sourceId=None, sourceName=None):
try:
data = dataBytes.decode(self.TEXT_ENCODING)
except UnicodeError as e:
......@@ -987,10 +999,11 @@ class AwlParser(object):
self.flatLayout = not re.match(r'.*^\s*ORGANIZATION_BLOCK\s+.*',
data, re.DOTALL | re.MULTILINE)
try:
self.__tokenize(data, fileId)
self.__tokenize(data, sourceId, sourceName)
except AwlParserError as e:
e.setLineNr(self.lineNr)
e.setFileId(fileId)
e.setSourceId(sourceId)
e.setSourceName(sourceName)
raise e
def getParseTree(self):
......
......@@ -40,12 +40,20 @@ else:
class GenericSource(object):
SRCTYPE = "<generic>"
def __init__(self, identifier, filepath="", sourceBytes=b""):
assert(identifier)
self.identifier = identifier
__nextIdentNr = 0
def __init__(self, identNr, name="", filepath="", sourceBytes=b""):
self.identNr = identNr
self.name = name
self.filepath = filepath
self.sourceBytes = sourceBytes
@staticmethod
def newIdentNr():
identNr = GenericSource.__nextIdentNr
GenericSource.__nextIdentNr = (GenericSource.__nextIdentNr + 1) & 0x7FFFFFFF
return identNr
def dup(self):
raise NotImplementedError
......@@ -58,51 +66,51 @@ class GenericSource(object):
return
awlFileWrite(self.filepath, self.sourceBytes, encoding="binary")
def forceNonFileBacked(self, newIdentifier):
def forceNonFileBacked(self, newName):
"Convert this source to a non-file-backed source."
if self.isFileBacked():
self.filepath = ""
self.identifier = newIdentifier
self.name = newName
def toBase64(self):
return base64.b64encode(self.sourceBytes).decode("ascii")
@classmethod
def fromFile(cls, identifier, filepath):
def fromFile(cls, identNr, name, filepath):
try:
data = awlFileRead(filepath, encoding="binary")
except AwlSimError as e:
raise AwlSimError("Project: Could not read %s "
"source file '%s':\n%s" %\
(cls.SRCTYPE, filepath, str(e)))
return cls(identifier, filepath, data)
return cls(identNr, name, filepath, data)
@classmethod
def fromBase64(cls, identifier, b64):
def fromBase64(cls, identNr, name, b64):
try:
data = base64.b64decode(b64, validate=True)
except (TypeError, binascii.Error) as e:
raise AwlSimError("Project: %s source '%s' "
"has invalid base64 encoding." %\
(cls.SRCTYPE, identifier))
return cls(identifier, None, data)
(cls.SRCTYPE, identNr))
return cls(identNr, name, None, data)
def __repr__(self):
return "%s%s %s" % ("" if self.isFileBacked() else "project ",
self.SRCTYPE, self.identifier)
return "%s%s %d %s" % ("" if self.isFileBacked() else "project ",
self.SRCTYPE, self.identNr, self.name)
class AwlSource(GenericSource):
SRCTYPE = "AWL/STL"
def dup(self):
return AwlSource(self.identifier, self.filepath,
return AwlSource(self.identNr, self.name, self.filepath,
self.sourceBytes[:])
class SymTabSource(GenericSource):
SRCTYPE = "symbol table"
def dup(self):
return SymTabSource(self.identifier, self.filepath,
return SymTabSource(self.identNr, self.name, self.filepath,
self.sourceBytes[:])
class Project(object):
......@@ -196,14 +204,16 @@ class Project(object):
if not p.has_option("CPU", option):
break
path = p.get("CPU", option)
src = AwlSource.fromFile(path, cls.__generic2path(path, projectDir))
sourceId = AwlSource.newIdentNr()
src = AwlSource.fromFile(sourceId, path, cls.__generic2path(path, projectDir))
awlSources.append(src)
for i in range(0xFFFF):
option = "awl_%d" % i
if not p.has_option("CPU", option):
break
awlBase64 = p.get("CPU", option)
src = AwlSource.fromBase64("#%d" % i, awlBase64)
sourceId = AwlSource.newIdentNr()
src = AwlSource.fromBase64(sourceId, "#%d" % sourceId, awlBase64)
awlSources.append(src)
if p.has_option("CPU", "mnemonics"):
mnemonics = p.getint("CPU", "mnemonics")
......@@ -222,14 +232,16 @@ class Project(object):
if not p.has_option("SYMBOLS", option):
break
path = p.get("SYMBOLS", option)
src = SymTabSource.fromFile(path, cls.__generic2path(path, projectDir))
sourceId = SymTabSource.newIdentNr()
src = SymTabSource.fromFile(sourceId, path, cls.__generic2path(path, projectDir))
symTabSources.append(src)
for i in range(0xFFFF):
option = "sym_tab_%d" % i
if not p.has_option("SYMBOLS", option):
break
symTabBase64 = p.get("SYMBOLS", option)
src = SymTabSource.fromBase64("#%d" % i, symTabBase64)
sourceId = SymTabSource.newIdentNr()
src = SymTabSource.fromBase64(sourceId, "#%d" % sourceId, symTabBase64)
symTabSources.append(src)
except _ConfigParserError as e:
......
......@@ -356,13 +356,13 @@ class AwlSimClient(object):
# fromLine, toLine is the range of AWL line numbers for which
# dumping is enabled.
def setInsnStateDump(self, enable=True,
fileNr=0, fromLine=1, toLine=0x7FFFFFFF,
sourceId=0, fromLine=1, toLine=0x7FFFFFFF,
sync=True):
if not self.transceiver:
return None
msg = AwlSimMessage_INSNSTATE_CONFIG(
flags = 0,
fileNr = fileNr,
sourceId = sourceId,
fromLine = fromLine,
toLine = toLine)
if enable:
......
......@@ -224,13 +224,18 @@ class AwlSimMessage_EXCEPTION(AwlSimMessage):
class _AwlSimMessage_source(AwlSimMessage):
sourceClass = None
# Payload header struct:
# Source identifier (32 bit)
plStruct = struct.Struct(str(">I"))
def __init__(self, msgId, source):
AwlSimMessage.__init__(self, msgId)
self.source = source
def toBytes(self):
try:
pl = self.packString(self.source.identifier) +\
pl = self.plStruct.pack(self.source.identNr) +\
self.packString(self.source.name) +\
self.packString(self.source.filepath) +\
self.packBytes(self.source.sourceBytes)
return AwlSimMessage.toBytes(self, len(pl)) + pl
......@@ -240,13 +245,16 @@ class _AwlSimMessage_source(AwlSimMessage):
@classmethod
def fromBytes(cls, payload):
try:
identifier, count = cls.unpackString(payload)
(identNr, ) = cls.plStruct.unpack_from(payload, 0)
count = cls.plStruct.size
name, cnt = cls.unpackString(payload, count)
count += cnt
filepath, cnt = cls.unpackString(payload, count)
count += cnt
sourceBytes, cnt = cls.unpackBytes(payload, count)
except ValueError:
except (ValueError, struct.error) as e:
raise TransferError("SOURCE: Data format error")
return cls(cls.sourceClass(identifier, filepath, sourceBytes))
return cls(cls.sourceClass(identNr, name, filepath, sourceBytes))
class AwlSimMessage_LOAD_SYMTAB(_AwlSimMessage_source):
sourceClass = SymTabSource
......@@ -537,7 +545,7 @@ class AwlSimMessage_MEMORY(AwlSimMessage):
class AwlSimMessage_INSNSTATE(AwlSimMessage):
# Payload data struct:
# AWL file ident number (32 bit)
# AWL source ident number (32 bit)
# AWL line number (32 bit)
# Serial number. Reset to 0 on cycle exit. (32 bit)
# Flags (16 bit) (currently unused. Set to 0)
......@@ -552,9 +560,9 @@ class AwlSimMessage_INSNSTATE(AwlSimMessage):
# CPU DI register (16 bit)
plDataStruct = struct.Struct(str(">IIIHHIIIIIIHH"))
def __init__(self, fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di):
def __init__(self, sourceId, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di):
AwlSimMessage.__init__(self, AwlSimMessage.MSG_ID_INSNSTATE)
self.fileNr = fileNr
self.sourceId = sourceId
self.lineNr = lineNr
self.serial = serial
self.flags = flags
......@@ -570,7 +578,7 @@ class AwlSimMessage_INSNSTATE(AwlSimMessage):
def toBytes(self):
pl = self.plDataStruct.pack(
self.fileNr, self.lineNr, self.serial,
self.sourceId, self.lineNr, self.serial,
self.flags, self.stw, self.accu1, self.accu2,
self.accu3, self.accu4, self.ar1, self.ar2,
self.db, self.di)
......@@ -579,16 +587,16 @@ class AwlSimMessage_INSNSTATE(AwlSimMessage):
@classmethod
def fromBytes(cls, payload):
try:
fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di =\
sourceId, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di =\
cls.plDataStruct.unpack_from(payload, 0)
except (struct.error, IndexError) as e:
raise TransferError("INSNSTATE: Invalid data format")
return cls(fileNr, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di)
return cls(sourceId, lineNr, serial, flags, stw, accu1, accu2, accu3, accu4, ar1, ar2, db, di)
class AwlSimMessage_INSNSTATE_CONFIG(AwlSimMessage):
# Payload data struct:
# Flags (32 bit)
# AWL file ident number (32 bit)
# AWL source ident number (32 bit)
# From AWL line (32 bit)
# To AWL line (32 bit)
plDataStruct = struct.Struct(str(">IIII"))
......@@ -598,27 +606,27 @@ class AwlSimMessage_INSNSTATE_CONFIG(AwlSimMessage):
FLG_CLEAR_ONLY = 1 << 1 # Just clear current settings.
FLG_CLEAR = 1 << 2 # Clear, then apply settings.
def __init__(self, flags, fileNr, fromLine, toLine):
def __init__(self, flags, sourceId, fromLine, toLine):
AwlSimMessage.__init__(self, AwlSimMessage.MSG_ID_INSNSTATE_CONFIG)
self.flags = flags
self.fileNr = fileNr
self.sourceId = sourceId
self.fromLine = fromLine
self.toLine = toLine
def toBytes(self):
pl = self.plDataStruct.pack(
self.flags, self.fileNr,
self.flags, self.sourceId,
self.fromLine, self.toLine)
return AwlSimMessage.toBytes(self, len(pl)) + pl
@classmethod
def fromBytes(cls, payload):
try:
flags, fileNr, fromLine, toLine =\
flags, sourceId, fromLine, toLine =\
cls.plDataStruct.unpack_from(payload, 0)
except (struct.error, IndexError) as e:
raise TransferError("INSNSTATE_CONFIG: Invalid data format")
return cls(flags, fileNr, fromLine, toLine)
return cls(flags, sourceId, fromLine, toLine)
class AwlSimMessageTransceiver(object):
class RemoteEndDied(Exception): pass
......
......@@ -72,7 +72,7 @@ class AwlSimServer(object):
self.nextDump = 0
# Instruction state dump: Enabled lines.
# dict key: AWL file number.
# dict key: AWL source ID number.
# dict values: range() of AWL line numbers.
self.insnStateDump_enabledLines = {}
......@@ -264,16 +264,16 @@ class AwlSimServer(object):
insn = cpu.getCurrentInsn()
if not insn:
return
fileNr, lineNr, msg = insn.fileNr, insn.getLineNr(), None
sourceId, lineNr, msg = insn.getSourceId(), insn.getLineNr(), None
for client in self.clients:
try:
if lineNr not in client.insnStateDump_enabledLines[fileNr]:
if lineNr not in client.insnStateDump_enabledLines[sourceId]:
continue
except KeyError:
continue
if not msg:
msg = AwlSimMessage_INSNSTATE(
fileNr & 0xFFFFFFFF,
sourceId & 0xFFFFFFFF,
lineNr & 0xFFFFFFFF,
self.__insnSerial,
0,
......@@ -431,7 +431,7 @@ class AwlSimServer(object):
client.insnStateDump_enabledLines = {}
if not (msg.flags & msg.FLG_CLEAR_ONLY):
rnge = range(msg.fromLine, msg.toLine + 1)
client.insnStateDump_enabledLines[msg.fileNr] = rnge
client.insnStateDump_enabledLines[msg.sourceId] = rnge
self.__updateCpuPostInsnCallback()
self.__updateCpuCycleExitCallback()
if msg.flags & msg.FLG_SYNC:
......
......@@ -311,7 +311,7 @@ class CpuWidget(QWidget):
client = self.mainWidget.getSimClient()
if onlineDiagEn and source:
client.setInsnStateDump(enable=True,
fileNr=0,#TODO
sourceId=source.identNr,
fromLine=fromLine, toLine=toLine,
sync=False)
else:
......
......@@ -124,7 +124,7 @@ class EditWidget(QPlainTextEdit):
self.lineNumWidget = LineNumSubWidget(self)
self.cpuStatsWidget = CpuStatsSubWidget(self)
self.__source = AwlSource("<gui>")
self.__source = AwlSource(AwlSource.newIdentNr())
self.__runStateCopy = CpuWidget.STATE_STOP
self.__nextHdrUpdate = 0
self.__hdrAniStat = 0
......
......@@ -105,7 +105,9 @@ class ProjectWidget(QWidget):
def __loadPlainAwlSource(self, filename):
project = Project(None) # Create an ad-hoc project
srcs = [ AwlSource.fromFile(filename, filename), ]
srcs = [ AwlSource.fromFile(identNr = AwlSource.newIdentNr(),
name = filename,
filepath = filename), ]
project.setAwlSources(srcs)
self.__loadProject(project)
QMessageBox.information(self,
......
......@@ -155,7 +155,7 @@ class AwlSourceTabWidget(SourceTabWidget):
return
self.clear()
for awlSource in awlSources:
editWidget = self.addEditWidget(awlSource.identifier)
editWidget = self.addEditWidget(awlSource.name)
editWidget.setSource(awlSource)
def addNewEditWidget(self):
......
......@@ -142,7 +142,9 @@ def readInputFile(inputFile):
project = Project.fromFile(inputFile)
else:
# make a fake project
awlSrc = AwlSource.fromFile(inputFile, inputFile)
awlSrc = AwlSource.fromFile(identNr = AwlSource.newIdentNr(),
name = inputFile,
filepath = inputFile)
project = Project(projectFile = None,
awlSources = [ awlSrc, ])
return project
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment