def getLine(self,debug=False): # Validate source state for getLine() method if self.fo is None: cls_str=assembler.eloc(self,"getLine",module=this_module) raise ValueError("%s file object not created for file: %s" \ % (cls_str,self.fname)) if self.eof: if self.leof: cls_str=assembler.eloc(self,"getLine",module=this_module) raise ValueError("%s text file already at end-of-file: %s" \ % (cls_str,self.fname)) else: raise SourceEmpty() # Read from queued physical lines before reading from file if len(self.queued)!=0: pline=self.queued[0] del self.queued[0] return pline # No queued lines, so read from the file line=self.fo.readline() if len(line)==0: self.fini() raise SourceEmpty() self.lineno+=1 if line[-1]=="\n": line=line[:-1] # TBD: Need to add logic for the 'guess' continuation method.... return self.pcls(Source(lineno=self.lineno,fileno=self.fileno),line)
def inject(self,lines,debug=False): if isinstance(lines,PhysLine): # Inject a single physical line self.lines.append(lines) if __debug__: if debug: print("%s injected line: %s" \ % (assembler.eloc(self,"inject",module=this_module),lines)) return elif isinstance(lines,list): # Inject a list of physcical lines for ndx,line in enumerate(lines): if not isinstance(line,PhysLine): raise ValueError("%s 'line' argument item %s not a string: %s" \ (assembler.eloc(self,"inject",module=this_module),ndx,line)) if debug: print("%s injected line: %s" \ % (assembler.eloc(self,"inject",module=this_module),line)) self.lines.extend(lines) return raise ValueError(\ "%s 'lines' argument must be a single or list of PhysLine objects: %s"\ % assembler.eloc(self,"inject",module=this_module),lines)
def fetch(self,indices=[],depth=0,debug=False): assert isinstance(indices,list),\ "%s 'indices' argument must be a list: %s" \ % (assembler.eloc(self,"fetch",module=this_module),indices) if __debug__: if debug: print("%s indices:%s depth:%s" \ % (assembler.eloc(self,"fetch",module=this_module),\ indices,depth)) if len(indices)==0: # Unsubscripted parameter or SYSLIST reference return self.cval ndxs=indices # Subscripted parameter or SYSLIST reference if depth>=len(ndxs): raise SymbolError(msg="too many sublist subscripts: %s" % depth) this=ndxs[depth] if len(self.sublists)==0: # The requested sublist does not exist, so return an empty C_Val return C_Val() val=self.sublists[this-self.minimum] if depth==len(ndxs)-1: # Last requested index so return the retrieved sublist's C_Val object return val.value() # Not the last index so reach into the next level of sublist for its entry. return val.fetch(indices=ndxs,depth=depth+1)
def __init__(self,asm,stmt,debug=False): self.asm=asm self.stmt=stmt self.debug=debug # These attributes are established during parsing operations self.label_fld=None # See parse_label() method self.oper_fld=None # See parse_operation() method self.operands=[] # See parse_operands() method self.comments=[] # See find_comment() method self.comment_pos=None # Starting position of the comment # Symbolic replacements: self.rlbl='' self.roper=None self.ropnd=[] # Handle loud comment model statements here self.loud=None logline=stmt.logline if __debug__: if debug: print("%s logline: %s" \ % (assembler.eloc(self,"__init__",module=this_module),logline)) if logline.comment and not logline.quiet: self.loud=logline.plines[0].text if __debug__: if debug: print("%s [%s] loud: %s" \ % (assembler.eloc(self,"__init__",module=this_module),\ stmt.lineno,self.loud))
def fields(self,pline,debug=False): if pline.literal: # No fields to check for a literal return text=pline.text mo=re.match(LogLine.fieldre,text) if mo is None: # If we are here there should be an non-blank operation field. If # not something unexpected happened raise ValueError("%s pline: %s\n field match failed, returned None" \ % (assembler.eloc(self,"fields",module=this_module),pline)) # match object returned groups=mo.groupdict() if __debug__: if debug: print("%s match groups: %s" \ % (assembler.eloc(self,"fields",module=this_module),groups)) end=mo.end() label=groups["label"] if label: amp= "&" in label self.label_fld=LField(label,pline.source,0,amp) oper=groups["oper"] assert oper is not None,\ "%s re failure: oper field not found by re: %s" \ % (assembler.eloc(self,"fields",module=this_module),oper) oper_start=mo.start("oper") amp= "&" in oper pline.oper_start=oper_start self.oper_fld=LField(oper,pline.source,oper_start,amp) bad_char = self.oper_fld.char_ck() if bad_char: self.error=LineError(source=pline.source,\ msg="operation field contains an invalid char: %s" % bad_char) else: self.operu=oper.upper() if __debug__: if debug: print("%s pline: %s" \ % (assembler.eloc(self,"fields",module=this_module),pline)) # Figure out if there are any operands and where they start in the first # (and required) physical line if end>=len(text): # Nothing beyond oper field except some spaces # No operands are present return pline.operand_start=end # Note where comments begin can not be determined until operands are parsed # and are sensitive to continuation convention used on the physical lines. if __debug__: if debug: print("%s pline: %s" \ % (assembler.eloc(self,"fields",module=this_module),pline))
def __init__(self,source,content,genlvl=None): assert source is None or isinstance(source,Source),\ "%s 'source' argumenet must be an instance of Source: %s" \ % (assembler.eloc(self,"__init__",module=this_module),source) assert isinstance(content,str),\ "%s 'content' argumenet must be a string: %s" \ % (assembler.eloc(self,"__init__",module=this_module),content) self.source=source # Location of source content # This attribute is the basis for the Statement column in the assembly # listing. self.content=content # a string, may be of length of 0 # This tracks the source of generated physical lines by macros or open code # If None, the input comes from a file. If 0 it comes from open code. # If 1 or more, it comes from a macro. Used to determine if a macro statement # is an inner macro call or not for listing purposes. self.genlvl=genlvl # If generated by assembler, level of generator # literal.Literal object passed along for literal creation self.literal=None # See PoolSource.__init__() method # Established by subclass init() method self.cont=False # Whether physical line is continued self.empty=False # Phyiscal line is empty self.text=None # Actual parsable content of the line # Physical line flags - set below in this __init__() method self.comment=False # Physical line is a comment self.quiet=False # Physical line is also a quiet comment # Field information - starting index of fields self.oper_start=None # Set by LogLine.fields() method self.operand_start=None # Set by Logline.fields() method self.comment_start=None # Set by asmline.cfsm.ACT_Found_Comment() method # Make sure we do not process an empty physical line if len(self.content)==0: self.empty=True self.cont=False self.text="" return # Perform subclass initialization self.init() # Also do not process a line with an empty logical content (like some spaces) if len(self.text)==0: self.empty=True self.cont=False return # Complete base class initialization # Continuation of comment lines is never recognized so no continuation forced if self.text[0]=="*": self.comment=True self.cont=False elif len(self.text)>=2 and self.text[:2]==".*": self.comment=self.quiet=True self.cont=False
def validate(self,asm,stmt,types,debug=False): istyp="U" char=self.text[0] # Get the first character for a quick sanity check for typ in types: if typ=="S": if char=="&": # call back to the statement to do a full symbolic reference parse result=stmt.validate_symbol(asm,self) if result: self.symid=result self.amp=True istyp="S" break continue else: continue elif typ=="Q" and char!=".": continue ltyp=LField.types[typ] # Use a lexical token to validate types: L, M and Q try: if __debug__: if debug: print("%s matching '%s' to typ: %s" \ % (assembler.eloc(self,"validate",module=this_module),\ self.text,typ)) self.token=ltyp.match(self.text) if __debug__: if debug: print("%s %s match succeeded" \ % (assembler.eloc(self,"validate",module=this_module),\ typ)) istyp=typ break except lexer.LexerError: if __debug__: if debug: print("%s %s match failed" \ % (assembler.eloc(self,"validate",module=this_module),\ typ)) continue if __debug__: if debug: print("%s %s match succeeded" \ % (assembler.eloc(self,"validate",module=this_module),istyp)) self.typ=istyp if typ=="M": self.amp = self.token.groups()[1] is not None return
def __getLogical(self,debug=False): try: pline=self.LB.getLine() if __debug__: if debug: print("%s pline: %s" \ % (assembler.eloc(self,"__getLogical",module=this_module),\ pline)) except asminput.SourceEmpty: return # Start a new logical line with this physical input. Regardless of whether # it is continued or not, the first physical line's operation field # dictates all of the remaining processing of the statement. Processing # of the label and operation field occurs during the instantiation of the # logical line (see the LogLine.fields() method). logical=LogLine(pline,bend=self._end) if logical.bend: self._bend=True logical.error=LineError(source=pline.source,\ msg="input beyond END directive ignored") while pline.cont: # Line is continued, so now add the next physical line try: pline=self.LB.getLine() if __debug__: if debug: print("%s pline: %s" \ % assembler.eloc(self,"__getLogical",module=this_module),\ pline) except asminput.SourceEmpty: logical.error=LineError(source=pline.source,\ msg="continuation line missing at end of file") break # If the source is empty then previously continued physical # line is missing a continuation #raise ValueError("continuation line missing at end of file") contok=logical.addCont(pline) if __debug__: if debug: print("%s contok from addCont: %s" \ % (assembler.eloc(self,"__getLogical",module=this_module),\ contok)) if not contok: logical.error=LineError(source=pline.source,\ msg="invalid continuation line, previously continued line " "rejected") self.LB.queue(pline) # Bad continue line so give up and assume it was meant to be a # new logical line and that is what follows. # Logical line is done, so process its operands self.categorize(logical) # Determine the logical line's operation type return logical
def str_cont(self, value): assert isinstance(value,StringToken),\ "%s 'value' argument must be a StringToken object: %s"\ % (assembler.eloc(self,"str_cont",module=this_module),value) assert isinstance(self._string,StringToken),\ "%s '_string' attribute must be a StringToken object: %s" \ % (assembler.eloc(self,"str_cont",module=this_module),self.string) self._string.extend(value)
def str_cont(self,value): assert isinstance(value,StringToken),\ "%s 'value' argument must be a StringToken object: %s"\ % (assembler.eloc(self,"str_cont",module=this_module),value) assert isinstance(self._string,StringToken),\ "%s '_string' attribute must be a StringToken object: %s" \ % (assembler.eloc(self,"str_cont",module=this_module),self.string) self._string.extend(value)
def __getLogical(self, debug=False): try: pline = self.LB.getLine() if __debug__: if debug: print("%s pline: %s" \ % (assembler.eloc(self,"__getLogical",module=this_module),\ pline)) except asminput.SourceEmpty: return # Start a new logical line with this physical input. Regardless of whether # it is continued or not, the first physical line's operation field # dictates all of the remaining processing of the statement. Processing # of the label and operation field occurs during the instantiation of the # logical line (see the LogLine.fields() method). logical = LogLine(pline, bend=self._end) if logical.bend: self._bend = True logical.error=LineError(source=pline.source,\ msg="input beyond END directive ignored") while pline.cont: # Line is continued, so now add the next physical line try: pline = self.LB.getLine() if __debug__: if debug: print("%s pline: %s" \ % (assembler.eloc(self,"__getLogical",\ module=this_module),pline)) except asminput.SourceEmpty: logical.error=LineError(source=pline.source,\ msg="continuation line missing at end of file") break # If the source is empty then previously continued physical # line is missing a continuation #raise ValueError("continuation line missing at end of file") contok = logical.addCont(pline) if __debug__: if debug: print("%s contok from addCont: %s" \ % (assembler.eloc(self,"__getLogical",module=this_module),\ contok)) if not contok: logical.error=LineError(source=pline.source,\ msg="invalid continuation line, previously continued line " "rejected") self.LB.queue(pline) # Bad continue line so give up and assume it was meant to be a # new logical line and that is what follows. # Logical line is done, so process its operands self.categorize(logical) # Determine the logical line's operation type return logical
def categorize(self,logical,debug=False): assert isinstance(logical,LogLine),\ "%s 'logical' argument must be a LogLine object: %s" \ % (eloc(self,"categorize",module=this_module),logical) OMF=self.asm.OMF if logical.error: oper=OMF.getError() elif logical.comment or logical.empty: oper=OMF.getComment(quiet=logical.quiet) elif logical.literal: oper=OMF.getLiteral(logical.literal) else: oper=logical.operu if __debug__: if debug: print("%s oper: %s" \ % (assembler.eloc(self,"categorize",module=this_module),oper)) try: # Get the operation infomation, defining a macro from the macro # library if necessary. oper=OMF.getOper(oper,mbstate=self.mb.state,macread=True,\ lineno=logical.source,debug=debug) if __debug__: if debug: print("%s %s" \ % (assembler.eloc(self,"categorize",module=this_module),\ oper)) except KeyError: print("%s KeyError" \ % assembler.eloc(self,"categorize",module=this_module)) # If the operation is unrecognized, categorize it as unknown logical.T="U" logical.ignore=True # Unknown operations must be ignored. source=logical.plines[0].source logical.error=LineError(source=source,\ msg="Unrecognized operation field: %s" % oper) oper=OMF.getError() except LineError as le: if __debug__: if debug: print("%s LineError: %s" \ % (assembler.eloc(self,"categorize",module=this_module),\ le)) # Failed library macro definitions must also be ignored logical.T="U" logical.ignore=True # Unknown operations must be ignored. logical.error=le oper=OMF.getError() # Update the logical line with this operation related information if __debug__: if debug: print("%s %s" \ % (assembler.eloc(self,"categorize",module=this_module),oper)) logical.category(oper)
def str_begin(self,value): assert isinstance(value,StringToken),\ "%s 'value' argument must be a StringToken object: %s"\ % (assembler.eloc(self,"str_begin",module=this_module),value) assert self._string is None,\ "%s '_string' attribute is not None when starting a compound string: %s" \ % (assembler.eloc(self,"str_begin",module=this_module),\ self._string) self._string=value
def _ck_symid(self,symid): assert isinstance(symid,SymbolID),\ "%s 'symbol' argument must be a SymbolID object: %s" \ % (assembler.eloc(self,"_ck_symid",module=this_module),symid) assert symid.var==self.symbol,\ "%s symbol's variable name ('%s') does not match symbol name being " \ "referenced: '%s'" \ % (assembler.eloc(self,"_ck_symid",module=this_module),\ self.symbol,symid.var) return
def str_begin(self, value): assert isinstance(value,StringToken),\ "%s 'value' argument must be a StringToken object: %s"\ % (assembler.eloc(self,"str_begin",module=this_module),value) assert self._string is None,\ "%s '_string' attribute is not None when starting a compound string: %s" \ % (assembler.eloc(self,"str_begin",module=this_module),\ self._string) self._string = value
def append(self, pline): assert isinstance(pline,asminput.PhysLine),\ "%s 'pline' argument must be an asminput.PhysLine object: %s" \ % (assembler.eloc(self,"__init__",module=this_module),pline) assert pline.operand_start is not None,\ "%s 'pline.operand_start' must not be None" \ % assembler.eloc(self,"__init__",module=this_module) loc = asmbase.ASMPLoc(source=pline.source, pndx=pline.operand_start) text = pline.text[pline.operand_start:] self.newloc(loc) self.text += text self.amp = self.amp or "&" in text
def append(self,pline): assert isinstance(pline,asminput.PhysLine),\ "%s 'pline' argument must be an asminput.PhysLine object: %s" \ % (assembler.eloc(self,"__init__",module=this_module),pline) assert pline.operand_start is not None,\ "%s 'pline.operand_start' must not be None" \ % assembler.eloc(self,"__init__",module=this_module) loc=asmbase.ASMPLoc(source=pline.source,pndx=pline.operand_start) text=pline.text[pline.operand_start:] self.newloc(loc) self.text+=text self.amp = self.amp or "&" in text
def __init__(self, pline): assert isinstance(pline,asminput.PhysLine),\ "%s 'pline' argument must be an asminput.PhysLine object: %s" \ % (assembler.eloc(self,"__init__",module=this_module),pline) assert pline.operand_start is not None,\ "%s 'pline.operand_start' must not be None" \ % assembler.eloc(self,"__init__",module=this_module) text = pline.text[pline.operand_start:] amp = "&" in text loc = asmbase.ASMPLoc(source=pline.source, pndx=pline.operand_start) super().__init__(text, start=loc, amp=amp)
def __init__(self,pline): assert isinstance(pline,asminput.PhysLine),\ "%s 'pline' argument must be an asminput.PhysLine object: %s" \ % (assembler.eloc(self,"__init__",module=this_module),pline) assert pline.operand_start is not None,\ "%s 'pline.operand_start' must not be None" \ % assembler.eloc(self,"__init__",module=this_module) text=pline.text[pline.operand_start:] amp="&" in text loc=asmbase.ASMPLoc(source=pline.source,pndx=pline.operand_start) super().__init__(text,start=loc,amp=amp)
def getLine(self, debug=False): # Throws a MacroError if a user error is detected # Note: Need to accept a list of physical lines and a line continuation # convention if len(self.queued) > 0: line = self.queued.pop(0) pline = StreamLine(None, line, genlvl=self.depth) if __debug__: if debug: print("%s returning queued: %s" \ % (assembler.eloc(self,"getLine",module=this_module),pline)) return pline # No previously queued physical lines so get one (or more) from the # macro. plines = self.exp.generate() if __debug__: if debug: print("%s received from macro %s Invoker: %s" \ % (assembler.eloc(self,"getLine",module=this_module),\ self.exp.name,plines)) # Determine if the macro is done generating input if plines is None: if __debug__: if debug: print("%s end of input from macro %s Invoker: " \ "raising SourceEmpty()" \ % (assembler.eloc(self,"getLine",module=this_module),\ self.exp.name)) # Tell LineBuffer object that this source is exhausted raise SourceEmpty() # Create a new physical line - eventually multiple physical lines will be # required of different continuation styles. assert isinstance(plines,list) and len(plines)>0,\ "%s macro invocation must return a non-empty list of strings: %s" \ % (assembler.eloc(self,"getLine",module=this_module),plines) if len(plines) > 1: self.queued = plines[1:] # Queue the extra lines for the next call # Return the first or only line pline = StreamLine(None, plines[0], genlvl=self.depth) if __debug__: if debug: print("%s returning: %s" \ % (assembler.eloc(self,"getLine",module=this_module),pline)) return pline
def getLine(self,debug=False): # Throws a MacroError if a user error is detected # Note: Need to accept a list of physical lines and a line continuation # convention if len(self.queued)>0: line=self.queued.pop(0) pline=StreamLine(None,line,genlvl=self.depth) if __debug__: if debug: print("%s returning queued: %s" \ % (assembler.eloc(self,"getLine",module=this_module),pline)) return pline # No previously queued physical lines so get one (or more) from the # macro. plines=self.exp.generate() if __debug__: if debug: print("%s received from macro %s Invoker: %s" \ % (assembler.eloc(self,"getLine",module=this_module),\ self.exp.name,plines)) # Determine if the macro is done generating input if plines is None: if __debug__: if debug: print("%s end of input from macro %s Invoker: " \ "raising SourceEmpty()" \ % (assembler.eloc(self,"getLine",module=this_module),\ self.exp.name)) # Tell LineBuffer object that this source is exhausted raise SourceEmpty() # Create a new physical line - eventually multiple physical lines will be # required of different continuation styles. assert isinstance(plines,list) and len(plines)>0,\ "%s macro invocation must return a non-empty list of strings: %s" \ % (assembler.eloc(self,"getLine",module=this_module),plines) if len(plines)>1: self.queued=plines[1:] # Queue the extra lines for the next call # Return the first or only line pline=StreamLine(None,plines[0],genlvl=self.depth) if __debug__: if debug: print("%s returning: %s" \ % (assembler.eloc(self,"getLine",module=this_module),pline)) return pline
def fetch(self,lit_str,debug=False): assert isinstance(lit_str,str),\ "%s 'lit_str' argument not a string: %s" \ % (assembler.eloc(self,"fetch",module=this_module),lit_str) assert len(lit_str)>1 and lit_str[0]=="=",\ "%s 'lit_str' argument is not a valid literal: '%s'" \ % (assembler.eloc(self,"fetch",module=this_module),lit_str) lit=self.literals[lit_str] if __debug__: if debug: print("%s RETURNING LITERAL OBJECT: %r" \ % (assembler.eloc(self,"fetch",module=this_module),lit)) return lit
def __init__(self,variable,indices=[],subscript=0): assert isinstance(variable,str) and len(variable)>0,\ "%s 'variable' argument must be a non-empty string: %s" \ % (assembler.eloc(self,"__init__",module=this_module),variable) assert variable[0]=='&',\ "%s 'variable' argument must start with an '&': '%s'" \ % (assembler.eloc(self,"__init__",module=this_module),variable) self.var=variable # The symbolic symbols's name (with '&') self.indices=indices # Variable number of integer indices. self.sub=None # Integer of array subscript if len(indices)==1: self.sub=indices[0]
def parse_sep(self,stmt,debug=False): parser=self.__fetch_parser(stmt.get_Operand_Parser()) if __debug__: if debug: print("%s parser: %s" \ % (assembler.eloc(self,"parse_sep",module=this_module),parser)) result=parser.parse_operands(stmt,debug=debug) if __debug__: if debug: print("%s result: %s" \ % (assembler.eloc(self,"parse_sep",module=this_module),result)) return result
def fetch(self, lit_str, debug=False): assert isinstance(lit_str,str),\ "%s 'lit_str' argument not a string: %s" \ % (assembler.eloc(self,"fetch",module=this_module),lit_str) assert len(lit_str)>1 and lit_str[0]=="=",\ "%s 'lit_str' argument is not a valid literal: '%s'" \ % (assembler.eloc(self,"fetch",module=this_module),lit_str) lit = self.literals[lit_str] if __debug__: if debug: print("%s RETURNING LITERAL OBJECT: %r" \ % (assembler.eloc(self,"fetch",module=this_module),lit)) return lit
def parse(self,logline,attrs="",spaces=False,alt=False,comma=False): self.start(logline,attrs=attrs,spaces=spaces,alt=alt,comma=comma) # If initial line has no operands then just exit isline=self.line(trace=False) self.new_operand() if not isline: return [] else: # Test for the case of a comma followed by a space indicating # comments are present on a statement without operands. opnd=self.cndx # Note: the physical line object removes trailing blanks, so we # have to treat just a comma with nothing after it as if it had a space. # We also have to check for the normal case where a comma followed by # a space indicates no operands. In this case there may be a comment. if len(self.text)==opnd+1 and self.text[opnd]==",": if __debug__: if self._trace is not None: print("%s operand field '%s' treated as without operands, "\ "returning: []"\ % (assembler.eloc(self,"parse",module=this_module),\ self.text[opnd])) return [] elif len(self.text)>=opnd+2 and self.text[opnd:opnd+2]==", ": if __debug__: if self._trace is not None: print("%s operand field '%s' treated as without operands, "\ "returning: []"\ % (assembler.eloc(self,"parse",module=this_module),\ self.text[opnd:])) return [] # Use FSM to parse operands while True: c=self.char() if c is None: break done=self.machine(c) if done: break # Make sure we add to the list the last operand if self.opno: self.check_operand() self.add_operand() return self.operands
def define(self, oper): assert isinstance(oper,asmbase.ASMOper),\ "%s 'oper' argument must be an asmbase.ASMOper object: %s" \ % (assembler.eloc(self,"define",module=this_module),oper) assert oper.info._defined is not None,\ "%s macro definition line is None: %s" \ % (assembler.eloc(self,"define",module=this_module),macro) name = oper.info.name try: entry = self.macros[name] # Macro is being redefined entry.redefine(oper) except KeyError: # First macro definition with this name self.macros[name] = MTE(oper)
def literal_new(self, lit, line, debug=False): lit.reference(line) if lit.unique: self.unique.append(lit) if __debug__: if debug: print("%s [%s] LITERAL POOL %s ADDING UNIQUE: %r" \ % (assembler.eloc(self,"literal_new",module=this_module),\ line,self.pool_id,lit)) else: self.literals[lit.name] = lit if __debug__: if debug: print("%s [%s] LITERAL POOL %s ADDING: %r" \ % (assembler.eloc(self,"literal_new",module=this_module),\ line,self.pool_id,lit))
def build(self,asm,parsers,stmt,n,length,trace=False): if length != 2: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type explicit length invalid: %s" % (n+1,length)) value=parsers.evaluate_expr(asm,stmt,self.expr,debug=False,trace=trace) if isinstance(value,int): raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type value not an address: %s" % (n+1,value)) try: base,disp=asm.bases.find(value,12,asm,trace=trace) except KeyError: # Could not resolve base register and displacement raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type constant could not resolve implied base " "register for location: %s" % (n+1,value)) from None value=(base<<12)+(0xFFF & disp) b=value.to_bytes(2,byteorder="big",signed=False) if __debug__: if trace: print("%s return bytes: %s '%s'" \ % (assembler.eloc(self,"build",module=this_module),len(b),b)) return b
def __init__(self,value=0): assert isinstance(value,int),\ "%s 'value' argument must be an integer: '%s'" \ % (assembler.eloc(self,"__init__",module=this_module),value) super().__init__(value) self["T"]="N"
def build(self, stmt, trace=False): assert isinstance(stmt,asmstmts.MachineStmt),\ "%s 'stmt' argument requires instance of assembler.Stmt: %s" \ % (assembler.eloc(self,"build",module=this_module),stmt) fmt = stmt.format # msldb.Format instance insn = stmt.insn # assembler.MSLentry instance line = stmt.lineno # Source object of statement's input location if trace: insn.dump() # Dump the MSL DB information # Marshall what we need to create the instruction i = Instruction(stmt.bin_oprs, insn, fmt, line) if trace: i.dump() # NOW!!! build the instruction barray = i.generate(self) if trace: print("%s: " % insn.mnemonic) s = "" for x in barray: s = "%s %s" % (s, hex(x)) print(" %s" % s) # Update the statenent's binary object bin = stmt.content # Get Binary object from the Stmt bin.update(barray, at=0, full=True, finalize=True, trace=trace)
def literal_new(self,lit,line,debug=False): lit.reference(line) if lit.unique: self.unique.append(lit) if __debug__: if debug: print("%s [%s] LITERAL POOL %s ADDING UNIQUE: %r" \ % (assembler.eloc(self,"literal_new",module=this_module),\ line,self.pool_id,lit)) else: self.literals[lit.name]=lit if __debug__: if debug: print("%s [%s] LITERAL POOL %s ADDING: %r" \ % (assembler.eloc(self,"literal_new",module=this_module),\ line,self.pool_id,lit))
def define(self,oper): assert isinstance(oper,asmbase.ASMOper),\ "%s 'oper' argument must be an asmbase.ASMOper object: %s" \ % (assembler.eloc(self,"define",module=this_module),oper) assert oper.info._defined is not None,\ "%s macro definition line is None: %s" \ % (assembler.eloc(self,"define",module=this_module),macro) name=oper.info.name try: entry=self.macros[name] # Macro is being redefined entry.redefine(oper) except KeyError: # First macro definition with this name self.macros[name]=MTE(oper)
def ltoken_update(self,stmt,ltok,asmstr=None): assert isinstance(asmstr,asmbase.ASMString),\ "%s 'asmstr' argument must be an instance of asmbase.ASMString: %s" \ % (assembler.eloc(self,"ltoken_update",module=this_module),asmstr) loc=asmstr.ndx2loc(ltok.linepos) ltok.update_loc(stmt.lineno,loc)
def build(self,stmt,trace=False): #cls_str="insnbldr.py - %s.build() -" % self.__class__.__name__ if __debug__: if Builder.type_check: assert isinstance(stmt,assembler.Stmt),\ "%s 'stmt' argument requires instance of assembler.Stmt: %s" \ % (assembler.eloc(self,"build",module=this_module),stmt) fmt=stmt.format # msldb.Format instance insn=stmt.insn # assembler.MSLentry instance line=stmt.lineno # Source object of statement's input location if trace: insn.dump() # Dump the MSL DB information # Marshall what we need to create the instruction i=Instruction(stmt.operands,insn,fmt,line) if trace: i.dump() # NOW!!! build the instruction barray=i.generate(self) if trace: print("%s: " % insn.mnemonic) s="" for x in barray: s="%s %s" % (s,hex(x)) print(" %s" % s) # Update the statenent's binary object bin=stmt.content # Get Binary object from the Stmt bin.update(barray,at=0,full=True,finalize=True,trace=trace)
def getLine(self): if self._end: raise ValueError("%s input statements present after END statement" \ % assembler.eloc(self,"getline")) # This while statement ends with: # - a BufferEmtpy exception being raised (to tell assembler input is done) # - an AssemblerError exception if current source can not be terminated # - has received a Line object from the source. # This while statement recycles only when a source ends and a previous # source has been made the current source. The recycle simply tries to # read from the unnested source, now the current source. while True: try: ln=self._cur_src.getLine(debug=False) # WARNING: this break is required! DO NOT DELETE break except SourceEmpty: # Current source is done # A BufferEmpty exception is raised when all input is exhausted self.__exhausted() continue # try reading from the unnested source now except asmmacs.MacroError as me: # A macro invocation will throw this error when a problem is detected # We catch it here so we can terminate the macro source. self.__exhausted() # Then we raise it again to allow the assembler to handle it raise me from None return ln
def build(self, asm, parsers, stmt, n, length, trace=False): if length != 2: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type explicit length invalid: %s" % (n+1,length)) value = parsers.evaluate_expr(asm, stmt, self.expr, debug=False, trace=trace) if isinstance(value, int): raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type value not an address: %s" % (n+1,value)) try: base, disp = asm.bases.find(value, 12, asm, trace=trace) except KeyError: # Could not resolve base register and displacement raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type constant could not resolve implied base " "register for location: %s" % (n+1,value)) from None value = (base << 12) + (0xFFF & disp) b = value.to_bytes(2, byteorder="big", signed=False) if __debug__: if trace: print("%s return bytes: %s '%s'" \ % (assembler.eloc(self,"build",module=this_module),len(b),b)) return b
def getLine(self): if self._end: raise ValueError("%s input statements present after END statement" \ % assembler.eloc(self,"getline")) # This while statement ends with: # - a BufferEmtpy exception being raised (to tell assembler input is done) # - an AssemblerError exception if current source can not be terminated # - has received a Line object from the source. # This while statement recycles only when a source ends and a previous # source has been made the current source. The recycle simply tries to # read from the unnested source, now the current source. while True: try: ln = self._cur_src.getLine(debug=False) # WARNING: this break is required! DO NOT DELETE break except SourceEmpty: # Current source is done # A BufferEmpty exception is raised when all input is exhausted self.__exhausted() continue # try reading from the unnested source now except asmmacs.MacroError as me: # A macro invocation will throw this error when a problem is detected # We catch it here so we can terminate the macro source. self.__exhausted() # Then we raise it again to allow the assembler to handle it raise me from None return ln
def extend(self,ltok): assert isinstance(ltok,StringToken),\ "%s 'ltok' argument must be another StringToken object: %s" \ % (assembler.eloc(self,"extend",module=this_module),ltok) self.string="%s%s" % (self.string,ltok.string) #print('following extend: self.string="%s"' % self.string) self.end=ltok.end
def __init__(self,typ,exp,stmtno=None,srcno=None): if not isinstance(exp,asmmacs.Invoker): cls_str=assembler.eloc(self,"__init__",module=this_module) raise ValueError("%s 'exp' argument must be an asmmacs.Expander object: " "%s" % (cls_str,exp)) self.exp=exp # asmmacs.Invoker object super().__init__(typ,exp.macro.name,stmtno=stmtno)
def parse_model(self,stmt,field,debug=False): if __debug__: if debug: print("%s debug: %s" \ % (assembler.eloc(self,"parse_model",module=this_module),debug)) parser=self.__fetch_parser("mopnd") return parser.parse_model(stmt,field,debug=debug)
def __init__(self,addrexpr): assert isinstance(addrexpr,pratt2.PExpr),\ "%s 'addrexpr' argument must be a pratt2.PExpr: %s" \ % (assembler.eloc(self,"__init__",module=this_module),addrexpr) length,align=self.__class__.attr super().__init__(addrexpr,length=length,alignment=align,signed=False) self.ivalue=SCON(addrexpr)
def parse_operation(self,asm,stmt,debug=False): if __debug__: if debug: print("%s called" % assembler.eloc(self,"parse_operation",\ module=this_module)) result=self.__parse(asm,stmt,stmt.oper_fld,debug=debug) self.oper_fld=self.prepare_result(stmt,result,"oper",debug=debug)
def parse_operation(self, asm, stmt, debug=False): if __debug__: if debug: print("%s called" % assembler.eloc(self,"parse_operation",\ module=this_module)) result = self.__parse(asm, stmt, stmt.oper_fld, debug=debug) self.oper_fld = self.prepare_result(stmt, result, "oper", debug=debug)
def extend(self, ltok): assert isinstance(ltok,StringToken),\ "%s 'ltok' argument must be another StringToken object: %s" \ % (assembler.eloc(self,"extend",module=this_module),ltok) self.string = "%s%s" % (self.string, ltok.string) #print('following extend: self.string="%s"' % self.string) self.end = ltok.end
def build(self, asm, parsers, stmt, n, length, trace=False): try: value = parsers.evaluate_expr(asm, stmt, self.expr, debug=False, trace=trace) except assembler.AddrArithError as ae: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s address arithmetic error, %s" \ % (n+1,ae)) assert isinstance(value,(int,assembler.Address)),\ "%s internal calculation of operand %s address expression resulted in an"\ "unsupported value: %s" \ % (assembler.eloc(self,"build",module=this_module),n+1,value) if isinstance(value, assembler.Address): if length not in self.lengths: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s %s-type explicit length invalid for an address "\ "nominal value: %s" % (n+1,self.typ,length)) if value.isAbsolute(): value = value.address else: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s address constant did not evaluate to an "\ "absolute address: %s" % (n+1,value)) # Convert computed address constant to bytes b = value.to_bytes((value.bit_length() // 8) + 1, byteorder="big", signed=False) # Perform left truncation/padding pad = b'\x00' * length bindata = pad + b b = bindata[len(bindata) - length:] if __debug__: if trace: print("%s return bytes: %s '%s'" % (assembler.eloc( self, "build", module=this_module), len(b), b)) return b
def normal(self): logline=self.logline logline.normal() self.text=logline.line self.empty=logline.empty assert isinstance(self.text,str),\ "%s text attribute not a string: %s" \ % (assembler.eloc(self,"normal",module=this_module),logline) self._normal=True
def addCont(self, pline, debug=False): cont = pline.isContinuation() if not cont: if __debug__: if debug: print("%s cont: %s" \ % (assembler.eloc(self,"addCont",module=this_module),cont)) return False self.plines.append(pline) if __debug__: if debug: print("%s plines: %s" \ % (assembler.eloc(self,"addCont",module=this_module),\ len(self.plines))) return True
def fini(self): if self.fo is None: raise ValueError("%s file object not created for file: %s" \ % (assembler.eloc(self,"fini",module=this_module),self.fname)) try: self.fo.close() except OSError: raise SourceError("could not close input text file: %s" % self.fname) \ from None
def get_O_attr(self, name): try: oper = self.getOper(name, macread=False, debug=False) assert isinstance(oper,asmbase.ASMOper),\ "%s getOper did not return an asmbase.ASMOper instance: %s" \ % (assembler.eloc(self,"oper",module=this_module),oper) except KeyError: return "U" return oper.O
def inject(self,lines,release=True): ln=[] if isinstance(lines,str): ln.append(lines) elif isinstance(lines,list): for ndx in range(len(lines)): line=lines[ndx] if not isinstance(line,str): cls_str=assembler.eloc(self,"inject") raise ValueError("%s 'line' argument item %s not a string: %s" \ (cls_str,ndx,line)) if len(line)!=0 and line[-1]=="\n": line=line[:-1] ln.append(line) else: cls_str=assembler.eloc(self,"inject") raise ValueError("%s 'lines' argument must be a string or list of " "strings: %s" % lines) self.lines.extend(ln)
def redefine(self, oper): assert oper.info.name==self.name,\ "%s macro entry name, '%s' does not match macro definition: '%s'" \ % (assembler.eloc(self,"redefine",module=this_module),\ self.name,oper.info.name) self.oper = oper # The ASMOper object has the macro definition! # Allow external users to update this macro refs. via the macro object oper.info._xref = self.xref self.xref.define(oper.info._defined)
def str_end(self): if self._string is None: return assert isinstance(self._string,StringToken),\ "%s '_string' attribute must be a StringToken object: %s" \ % (assembler.eloc(self,"str_end",module=this_module),self._string) accum = self._string self._string = None return accum
def value(self, external=None, debug=False, trace=False): # Need to do symbolic replacement with new searcher string = external.exp.symbol_replace(self.src.string, debug=debug) if __debug__: if trace: print('%s string: "%s"' \ % (assembler.eloc(self,"value",module=this_module))) return assembler.CPTRANS.a2e(string)
def __init__(self, typ, exp, stmtno=None, srcno=None, fixed=False): if not isinstance(exp, asmmacs.Invoker): cls_str = assembler.eloc(self, "__init__", module=this_module) raise ValueError( "%s 'exp' argument must be an asmmacs.Expander object: " "%s" % (cls_str, exp)) self.exp = exp # asmmacs.Invoker object self.depth = None # Macro level nesting depth - See init() method. super().__init__(typ, exp.macro.name, stmtno=stmtno) self.queued = []
def __init__(self, addrexpr): assert isinstance(addrexpr,pratt2.PExpr),\ "%s 'addrexpr' argument must be a pratt2.PExpr: %s" \ % (assembler.eloc(self,"__init__",module=this_module),addrexpr) length, align = self.__class__.attr super().__init__(addrexpr, length=length, alignment=align, signed=False) self.ivalue = SCON(addrexpr)
def __init__(self,line,lineno=None,source=None,typ="X",macro=False): assert isinstance(line,asmcards.LogLine),\ "%s 'line' argument must be an instance of asmcards.LogLine: %s" \ % (assembler.eloc(self,"__init__",module=this_module),line) assert (source is None) or isinstance(source,Source),\ "%s 'source' argument must be an instance of Source: %s" \ % (assembler.eloc(self,"__init__",module=this_module),source) # typ attribute controls how the line is processed by the assembler # 'B' --> This is a macro body statement # 'E' --> Expanded line (typ after expansion) # 'F' --> Text expansion failed, see self.merror for reason # 'P' --> This is a macro prototype statement # 'X' --> This is a normal input line and must be expanded by the current # asmmacs.Expander object self.typ=typ # Line type self.logline=line # asmcards.LogLine object self._normal=False # normal method() called if True # THIS ATTRIBUTE IS USED FOR LISTING SOURCE CONTENT self.text=None # Text of logical line of text self.lineno=lineno # Global line number (The statement number in the listing) self.source=source # Input source information self.psource=None # This is used for printing source lines # Macro related information self.macro=macro # If True, this line is a macro generated line self.merror=None # MacroError exception if expansion failed self.comment=line.comment # If True this is a comment statement self.silent=line.silent # If comment and True, it is a silent comment self.empty=line.empty # True if line is empty or all spaces # Validate the logical line. LineError exceptions caught and reraised as # assembler errors which must be handled by Stmt instantiator self.validate() # Early comment and empty line detection if self.empty: self.text=""