def load(filename, obj=None): parser = xml.sax.make_parser() nh = NodeHandler() parser.setContentHandler(nh) if not os.path.exists(filename): # try looking in the predefined library base = os.path.basename(filename) libfilename = string.join( [os.environ['M3_HOME'], 'lib', 'm3lib', base], os.sep) if not os.path.exists(libfilename): error("%s does not exist" % filename, catastrophic=True, obj=obj, code="CAT001") else: #print "got library file %s" % libfilename filename = libfilename parser.parse(filename) tn = nh.topNode # tn.resolveRefs() tn.visit(lambda x: x.restoreSlots()) if os.path.exists(tn.source): sourcetime = os.stat(tn.source)[stat.ST_MTIME] objtime = os.stat(filename)[stat.ST_MTIME] if sourcetime > objtime: import LoadSrc print "Recompiling %s from %s" % ( filename, relpath.relcwd(tn.source)) #OK tn = LoadSrc.load(fileName=tn.source) return tn
def generateC(self, saveOutput): if saveOutput: s = open(self.getCFileBaseName() + ".c", "w") else: s = FakeFile() s.write('#include "M3Predef.h"\n') exps = self.getExports() if exps != []: s.write('#include "%s.h"\n' % self.modname.idname) for imp in self.imports.kids: imp.genC(s) if not self.exportIds.isNULL(): error("%s for explicit exports" % nocando, self) else: # Variables in interfaces need to be shifted down into the body (extern left in the header) if len(exps) == 1: expXML = m3.compile(fileName=exps[0] + "." + CompilationUnit.unitTypeNames["Interface"], saveOutput=saveOutput) expXML.generateCBody(s) self.block.genC(s, 0, module=True) if Options.options.mainProgram and saveOutput: mp = open(self.getCFileBaseName() + "__main.c", "w") myname = self.modname.idname mods = CompOrder.getCClosure(myname) mp.write("int main() { \n") for mod in mods: if mod != myname: mp.write(" %s__elaboration();\n" % mod) mp.write(" %s__elaboration();\n};\n" % myname) mp.close()
def genCRecord(self, tipe): # start with a row of empty boxes fields = [None] * len(tipe.fields) # populate boxes with defaults for ctr, field in enumerate(tipe.fields): if field.default: fields[ctr] = field.defaultNode.genC() positional = True # start processing constructor in positional mode for ctr, kid in enumerate(self.kidsNoSep()): if positional: if kid.__class__.__name__ == "ConsEltExprNode": fields[ctr] = kid.genC() else: positional = False if not positional: # place the named field into the right box fields[tipe.offsetForFieldName( kid.id.idname)] = kid.expr.genC() for ctr, field in enumerate(fields): # catch incomplete case (box will still be empty) if field == None: error( "C Code - incomplete constructor, missing value for field %s" % tipe.fields[ctr].name) return "" # finally generate the completed aggregate return string.join(fields, ",")
def load(fileName=None, src=None, patchFileName=None): if not (fileName or src): raise "Catastrophic problem with load - neither a fileName nor a sourcefile" p = m3parser.Parser() p.verbose = int(Options.options.verbosity) if fileName: if not os.path.exists(fileName): error("File %s does not exist" % fileName) return f = open(fileName) txt = f.read() else: txt = src txt = compro.commentkiller(txt) txt = compro.umlautkiller(txt) if Options.options.errorTest: Errors.findDirective(txt) try: topNode = p(txt) except tpg.SyntacticError, e: error(e.msg, None, fileName or patchFileName, e.line, catastrophic=True, code="CAT002") raise
def check(actuals,obj): tipe1 = actuals[0]['tipe'] tipe2 = actuals[1]['tipe'] if not tipe1.fits(tipe2): error("Arguments to %s must be identical type" % functionName, obj, code="027") if not (tipe1.isOrdinal or tipe1.isReal): error("Arguments to %s must be ordinal or real" % functionName, obj, code="028") return tipe1
def doVAL(actuals, obj): val = actuals[0]['tipe'] if not val.isInteger: error("VAL called with first argument of non-integer type %s" % val, obj,code="019") tipe = actuals[1]['tipe'] if not tipe.isOrdinal: error("VAL called with second argument of non-ordinal type %s" % tipe, obj,code="018") return tipe
def doAPPEND(actuals, obj): listType = actuals[0]['tipe'] if not listType.isList: error("APPEND called with non-list as first argument", obj) else: eltType = actuals[1]['tipe'] if eltType != listType.elementType: error("Attempted APPEND of type %s to LIST of type %s" % (eltType,listType), obj) return M3Types.M3ProcedureNullReturn
def genC(self): tipe = self.tipe.getType() if tipe.isArray: return "{ %s }" % self.consEltList.genCArray(tipe.length()) elif tipe.isRecord: return "{ %s }" % self.consEltList.genCRecord(tipe) else: error("%s constructor not supported for this type (yet)" % nocando, self)
def genCNEW(self, res): # only handle the first item in the selector list (LIMITATION) param = self.selectorList.kids[0].actualList.kids[0].expr.expr nodename = param.__class__.__name__ if nodename == "RefNode": return "%s(%s)" % (res, param.tipe.genC()) elif nodename == "TypeNameNode": return "%s(%s__REFERENT)" % (res, param.genC()) else: error("%s NEW parameter too complex (%s)" % (nocando, nodename), self)
def enterOver(self, name, entry, obj): import Lexis if name in Lexis.reservedWords: error("%s is a reserved word" % name, obj, code="001") if name in self.table: if self.table[name].declarer != "TYPE": error("Procedure %s declared more than once" % name, obj, code="002") entry.spec = self.table[name] # TBD squirrel the spec away so you can check the match once everything is ready (but not yet) self.table[name] = entry
def doNUMBER(actuals,obj): val = actuals[0]['val'] tipe = actuals[0]['tipe'] if tipe.isOrdinal and hasattr(val,"isType"): pass elif tipe.isList and not hasattr(val,"isType"): pass elif tipe.isArray: pass else: error("NUMBER can only be called on Ordinal and ARRAY types or ARRAY and LIST values", obj, code="023") return M3Types.M3IntegerBase
def getCCodeName(tipe, self): if hasattr(tipe, "CCodeName"): tipestr = tipe.CCodeName elif tipe.isBoolean: tipestr = "M3Predef__BOOLEAN" elif tipe.isInteger or tipe.isEnum: tipestr = "M3Predef__INTEGER" elif tipe.isReal: tipestr = "M3Predef__REAL" else: error("%s deriving C name for type '%s'" % (nocando, self.regen()), self) tipestr = "ERROR" return tipestr
def doLimit(actuals, obj, name): val = actuals[0]['val'] tipe = actuals[0]['tipe'] if tipe.isArray: return tipe.indexType or M3Types.M3IntegerBase elif tipe.isList: if hasattr(val,"isType"): error("LAST not allowed on LIST types", obj) return M3Types.M3IntegerBase elif tipe.isOrdinal: return tipe else: error("Cannot use %s on type %s" % (name, tipe), obj, code="021") return tipe
def doINDEX(actuals, obj): def checkElement(container,containerName, elementType): if not container.elementType.fits(elementType): error("2nd Argument of INDEX for this %s must be %s" % (containerName,container.elementType), obj) containerType = actuals[0]['tipe'] elementType = actuals[1]['tipe'] if containerType.isList: checkElement(containerType, "LIST", elementType) return M3Types.M3IntegerBase elif containerType.isDict: checkElement(containerType, "DICT", elementType) return containerType.indexType else: error("INDEX only allowed with LIST or DICT as 1st argument", obj) return M3Types.M3ProcedureNullReturn
def getTipe(self, root=None): #print "root", root if not self.finalTipe: if self.findingType: self.finalTipe = M3Types.M3ErrorType( error("Recursive type definition (ask FJG for coaching)", self.node)) else: self.findingType = True # detects recursive type definitions self.finalTipe = self.node.getType() self.findingType = False return self.finalTipe
def lookupEntry(self, name, obj=None, errorOnMissing=True): import Lexis import M3Reserved #print "looking up %s" % name res = None if name in Lexis.reservedWords: res = M3Reserved.getEntry(name, obj) elif name in self.table: res = self.table[name] else: enclut = self.getEnclosingLUT() if enclut: res = enclut.lookupEntry(name, obj, errorOnMissing) if not res and errorOnMissing: err = error("Unknown Identifier %s" % name, obj, code="005") res = LUTEntry(tipe=M3Types.M3ErrorType(err)) return res
def doDEL(actuals, obj): listType = actuals[0]['tipe'] toDel = actuals[1]['tipe'] if listType.isList: if not toDel.isInteger: error("2nd Argument of DEL for a LIST must be an INTEGER") elif listType.isDict: if not listType.indexType.fits(toDel): error("2nd Argument of DEL for a DICT should be %s and not %s" % (listType.indexType,toDel)) else: error("DEL only allowed with LIST or DICT as 1st argument", obj) return M3Types.M3ProcedureNullReturn
def genC(self): myOp = self.token unchanged = ("+", "-", "*", "/", ">", "<", ">=", "<=") opDict = { "=": "==", "#": "!=", "AND": "&&", "OR": "||", "NOT": "!", "DIV": "/", } if myOp in unchanged: return myOp elif myOp in opDict: return opDict[myOp] else: return error("%s for operator %s" % (nocando, myOp), self)
def enter(self, name, entry, obj=None): import Lexis #print "Enter %s with entry %s" % (name, entry.image()) if name in Lexis.reservedWords: error("%s is a reserved word" % name, obj, code="001") if name in Lexis.pythonReservedWords: error("%s is a python reserved word" % name, obj) if name in self.table: #self.dump() error("%s already declared" % name, obj, code="004") if entry.__class__.__name__ != "LUTEntry": raise "Only LUTEntries allowed" entry.name = name self.table[name] = entry
def doSUBARRAY(actuals, obj): failed = False arrayBase = actuals[0]['tipe'] start = actuals[1]['tipe'] length = actuals[2]['tipe'] if not arrayBase.isArray: error("SUBARRAY first parameter must be an array",obj, code="032") failed = True if not start.isInteger: error("SUBARRAY second parameter must be an integer",obj, code="033") failed = True if not length.isInteger: error("SUBARRAY third parameter must be an integer",obj, code="034") failed = True if failed: return M3Types.M3ErrorType("Subarray Error") else: return M3Types.M3SubArrayType(arrayBase)
def doISTYPE(actuals, obj): ref = actuals[0]['tipe'] tipe = actuals[0]['tipe'] if not ((ref.isRef or ref.isObject) and (tipe.isRef or tipe.isObject)): error("ISTYPE can only be called with references or objects", obj, code="030") return M3Types.M3Boolean
def doKEYS(actuals, obj): dictType = actuals[0]['tipe'] if not dictType.isDict: error("KEYS called with non-dict argument", obj) return M3Types.M3ListType(dictType.indexType)
def doNEW(actuals,obj): tipe = actuals[0]['tipe'] if not (tipe.isRef or tipe.isObject): error("NEW called on non-reference/object type %s" % tipe, obj, code="006") elif tipe.isObject: for actual in actuals[1:]: actname = actual['name'] if not actname: error("Arguments to NEW for object must be named",obj, code="007") break #print "name is", name acttipe = actual['tipe'] field = tipe.getFieldNewCheck(actname) # print field.name, field.tipe, field.default if acttipe.isProcedure: tipe.checkOverride(actname, acttipe, obj) else: if not field.tipe.fits(acttipe): error("Type conflict for field '%s' in NEW : actual: %s, formal: %s" % ( actname, acttipe, field.tipe), obj, code="010") elif tipe.referent.isOpen: if len(actuals) <= 1: error("Length not supplied for open array", obj,code="011") level = tipe.referent for dim in actuals[1:]: if dim['name']: error("Arguments to NEW for array may not be named", obj,code="012") if not dim['tipe'].isInteger: error("Arguments to NEW for array must be INTEGERs", obj, code="013") if level.isOpen: level = level.elementType else: error("Dimension of array is not open", obj, code="014") elif tipe.referent.isObject: error("Ref to object currently unsupported (you probably do not mean this anyway!)", obj,code="008") elif tipe.referent.isRecord: for field in actuals[1:]: if not field['name']: error("Arguments to NEW for record must be named", obj, code="015") if field['name'] not in tipe.referent.fieldnames: error("Record does not have field %s" % field['name'], obj, code="016") else: if not field['tipe'].fits(tipe.referent.fielddict[field['name']].tipe): error("Type mismatch for field %s in allocator" % field['name'], obj, code="009") return tipe
def doPOP(actuals, obj): listType = actuals[0]['tipe'] if not listType.isList: error("POP called with non-list argument", obj) return listType.elementType
def doDISPOSE(actuals, obj): ref = actuals[0]['tipe'] if not (ref.isRef or ref.isObject): error("DISPOSE can only be called with references or objects", obj, code="031") return M3Types.M3ProcedureNullReturn
def doTYPECODE(actuals, obj): tipe = actuals[0]['tipe'] if not (tipe.isRef or tipe.isObject): error("TYPECODE can only be called with references or objects", obj, code="029") return M3Types.M3Cardinal
def checkElement(container,containerName, elementType): if not container.elementType.fits(elementType): error("2nd Argument of INDEX for this %s must be %s" % (containerName,container.elementType), obj)
def doABS(actuals, obj): tipe = actuals[0]['tipe'] if not tipe.isNumeric: error("ABS can only be called on numeric types", obj, code="026") return tipe
def doORD(actuals, obj): ord = actuals[0]['tipe'] if not ord.isOrdinal: error("ORD called on object of non-ordinal type %s" % ord, obj, code="017") return M3Types.M3IntegerBase
def check (actuals, obj): tipe = actuals[0]['tipe'] if not tipe.fits(M3Types.M3RealBase): error("%s can only be called on reals" % functionName, obj, code="025") return M3Types.M3IntegerBase