Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3# 

4# This module contains the assembler for the capricorn cpu.  

5# (c) 2020 Joachim Siebold 

6# 

7# This program is free software; you can redistribute it and/or 

8# modify it under the terms of the GNU General Public License 

9# as published by the Free Software Foundation; either version 2 

10# of the License, or (at your option) any later version. 

11# 

12# This program is distributed in the hope that it will be useful, 

13# but WITHOUT ANY WARRANTY; without even the implied warranty of 

14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

15# GNU General Public License for more details. 

16# 

17# You should have received a copy of the GNU General Public License 

18# along with this program; if not, write to the Free Software 

19# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 

20# 

21#------------------------------------------------------------------- 

22# 

23# Changelog 

24 

25import argparse,sys,os,math,time 

26import importlib.util 

27from pathlib import Path 

28from .capcommon import capasmError,BYTESTOSTORE,parseFunc,OPCODES, \ 

29 MESSAGE,clsSymDict,CAPASM_VERSION, CAPASM_VERSION_DATE, \ 

30 clsConditionalAssembly, clsGlobVar, clsToken, clsLineScanner, \ 

31 clsObjWriter, clsListWriter, clsSourceReader, clsParserInfo, \ 

32 clsParsedOperand, clsParsedExpression, clsInvalidOperand, \ 

33 clsParsedLabel,clsParsedString, clsParsedRegister, clsCodeInfo, \ 

34 clsCodeGeneratorBase, clsParserBase, clsDateTime 

35 

36# 

37# Expression parser and execute class ----------------------------------- 

38# 

39class clsExpression(object): 

40 

41 EX_NUM=0 

42 EX_SYM=1 

43 EX_OP=2 

44 

45 OP_PLUS=0 

46 OP_MINUS=1 

47 OP_DIV=2 

48 OP_MULT=3 

49 OP_OR=4 

50 OP_AND=5 

51 OP_NOT=6 

52 OP_MOD=7 

53 OP_RESIZE=8 

54 OP_CHS=9 

55 OP_NONE=10 

56 

57 CH_OP=["PLUS","MINUS","DIV","MULT","OR","AND","NOT","MOD","RESIZE","CHS","NONE"] 

58 

59 

60 def __init__(self,globVar): 

61 super().__init__() 

62 self.__globVar__=globVar 

63 

64 def addError(self,errnum): 

65 self.__errors__.append(errnum) 

66# 

67# generate Bytecode 

68# 

69# number 

70# 

71 def genNumber(self,value): 

72 self.__bc__.append([clsExpression.EX_NUM,value]) 

73 self.__lastNumber__=value 

74 self.__size__=self.byteLen(value) 

75# 

76# location counter 

77# 

78 def genLoc(self,value): 

79 self.__bc__.append([clsExpression.EX_NUM,value]) 

80 self.__size__=2 

81 

82# 

83# symbol 

84# 

85 def genSymbol(self,name): 

86 self.__bc__.append([clsExpression.EX_SYM,name]) 

87 ret=self.__globVar__.symDict.get(name,noGlobStore=True) 

88 if ret is None: 

89 self.__size__= None 

90 else: 

91 self.__size__=ret[2] 

92# 

93# opcode 

94# 

95 def genOp(self,op): 

96 self.__bc__.append([clsExpression.EX_OP,op]) 

97 if op== clsExpression.OP_RESIZE: 

98 self.__size__=self.__bc__[-2][1] 

99 else: 

100 self.__size__= None 

101# 

102# returns the smallest number of bytes a integer value will occupy 

103# Note: for negative number an additional bit will be needed for the  

104# 2s representation. Therefore an additional byte could be needed. 

105# 

106 def byteLen(self,value): 

107 if value==0: 

108 return 1 

109 else: 

110 n=(1+math.floor(math.log(abs(value))/(0.69314718055994530942*8))) 

111# 

112# check if we need an additional byte for the 2's representation 

113# 

114 if (value < 0) : 

115 maxValue=(2**(8*n))/2 

116 if abs(value) > maxValue: 

117 n+=1 

118 return n 

119# 

120# convert the result into a list of byte values 

121# 

122 def makeBytes(self,value,size=None): 

123 if size is None: 

124 return None 

125 else: 

126 nBytes=size 

127 b= [0]* nBytes 

128 for i in range(0,nBytes): 

129 b[i]= value & 0xFF 

130 value=value>>8 

131 return b 

132 

133# 

134# resize a value to a given size 

135# positve integers are returned unchanged 

136# negative integers are padded with 0xFF 

137# returns None if size is too small 

138# 

139 def resize(self,value,size): 

140 nBytes= self.byteLen(value) 

141 if size < nBytes: 

142 return None 

143# 

144# 2s complement for negative numbers 

145# 

146 if value < 0 : 

147 value= (2 ** (size*8)) + value 

148 return value 

149# 

150# scan a character 

151# 

152 def getch(self): 

153 self.__getchCount__+=1 

154 if self.__getchCount__ == len (self.__exprString__): 

155 self.__GCH__= "\n" 

156 else: 

157 self.__GCH__= self.__exprString__[self.__getchCount__] 

158# 

159# location counter symbol "$" 

160# 

161 def LOC(self): 

162 self.getch() 

163 self.genLoc(self.__globVar__.PC) 

164 return 

165# 

166# number, which can be ocal, decimal, bcd or hex. Hex numbers must always 

167# begin with a digit 

168# 

169 def number(self): 

170 numString="" 

171 while True: 

172 numString+=self.__GCH__ 

173 self.getch() 

174 if "01234567890abcdefABCDEFhHoOKkQq#".find(self.__GCH__)< 0: 

175 break 

176 value=parseFunc.parseNumber(numString) 

177 if value is None: 

178 self.addError(MESSAGE.E_ILLNUMBER) 

179 bValue=0 

180 else: 

181 bValue=value 

182 self.genNumber(bValue) 

183 return 

184# 

185# ASCII string, which can be either enclosed in ",',` or ^ 

186# 

187 def asc(self): 

188 

189 value=0 

190 term=self.__GCH__ 

191 self.getch() 

192 string="" 

193 while self.__GCH__ != term: 

194 string+= self.__GCH__ 

195 self.getch() 

196 if self.__GCH__== "\n": 

197 self.addError(MESSAGE.E_ILLSTRING) 

198 return 

199 self.getch() 

200 i=0 

201 for c in string[::-1]: 

202 if i== 0 and term in "^`": 

203 c=chr(ord(c)+128) 

204 value= value*256 + ord(c) 

205 i+=1 

206 self.genNumber(value) 

207 return 

208# 

209# symbol name which always begins with a letter 

210#  

211 def symbol(self): 

212 symName="" 

213 while True: 

214 symName+=self.__GCH__ 

215 self.getch() 

216 if " )\n".find(self.__GCH__)>=0: 

217 break 

218 if parseFunc.parseLabel(symName,self.__globVar__.symNamLen) is None: 

219 self.addError(MESSAGE.E_ILL_LABELOP) 

220 return 

221 self.genSymbol(symName) 

222 return 

223# 

224# expression base 

225#  

226 def base(self): 

227 strTerm="'`^"+'"' 

228# 

229# location counter symbol 

230# 

231 if self.__GCH__== "$": 

232 self.LOC() 

233# 

234# number 

235# 

236 elif "01234567890".find(self.__GCH__) >=0: 

237 self.number() 

238# 

239# quoted string 

240# 

241 elif self.__GCH__ in strTerm: 

242 self.asc() 

243# 

244# left paranthesis, begin of a new term 

245# 

246 elif self.__GCH__=="(": 

247 self.getch() 

248 self.term() 

249 if self.__GCH__ != ")": 

250 self.addError(MESSAGE.E_MISSINGRPAREN) 

251 return 

252 self.getch() 

253# 

254# returned from term, look for a size specifier 

255# 

256 if self.__GCH__==".": 

257 self.getch() 

258 if "01234567890".find(self.__GCH__) >=0: 

259 self.number() 

260 self.genOp(clsExpression.OP_RESIZE) 

261 size=self.__lastNumber__ 

262 if size ==None: 

263 self.addError(MESSAGE.E_INVALIDSIZESPEC) 

264 return 

265 else: 

266 self.symbol() 

267 return 

268# 

269# expression unary, operators are "-" or "~" 

270# 

271 def unary(self): 

272 if self.__GCH__== "-": 

273 self.getch() 

274 self.base() 

275 self.genOp(clsExpression.OP_CHS) 

276# elif self.__GCH__=="~": 

277# self.getch() 

278# self.base() 

279# self.genOp(clsExpression.OP_NOT) 

280 else: 

281 self.base() 

282 return 

283# 

284# expression bool, operators are "&" or "|" 

285# 

286 def bool(self): 

287 first=True 

288 operator=clsExpression.OP_NONE 

289 done=False 

290 while not done: 

291 self.unary() 

292 if first: 

293 first=False 

294 else: 

295 if operator== clsExpression.OP_AND: 

296 self.genOp(operator) 

297 elif operator== clsExpression.OP_OR: 

298 self.genOp(operator) 

299 done=True 

300 if self.__GCH__=="&": 

301 operator= clsExpression.OP_AND 

302 done= False 

303 self.getch() 

304 if self.__GCH__=="|": 

305 operator= clsExpression.OP_OR 

306 done= False 

307 self.getch() 

308 

309 return 

310# 

311# expression factor, operators are "*", "/", "%" (modulo) 

312# 

313 def factor(self): 

314 

315 operator=clsExpression.OP_NONE 

316 first=True 

317 done=False 

318 while not done: 

319 self.bool() 

320 if first: 

321 first=False 

322 else: 

323 if operator== clsExpression.OP_MULT: 

324 self.genOp(operator) 

325 elif operator== clsExpression.OP_DIV: 

326 self.genOp(operator) 

327 elif operator == clsExpression.OP_MOD: 

328 self.genOp(operator) 

329 done=True 

330 if self.__GCH__=="*": 

331 operator=clsExpression.OP_MULT 

332 done= False 

333 self.getch() 

334 if self.__GCH__=="/": 

335 operator=clsExpression.OP_DIV 

336 done= False 

337 self.getch() 

338 if self.__GCH__=="%": 

339 operator=clsExpression.OP_MOD 

340 done= False 

341 self.getch() 

342 

343 return 

344# 

345# expression term, operators are "+" and "-" 

346# 

347 def term(self): 

348 

349 operator=clsExpression.OP_NONE 

350 first=True 

351 done=False 

352 while not done: 

353 self.factor() 

354 if first: 

355 first=False 

356 else: 

357 if operator== clsExpression.OP_PLUS: 

358 self.genOp(operator) 

359 elif operator== clsExpression.OP_MINUS: 

360 self.genOp(operator) 

361 done=True 

362 if self.__GCH__=="+": 

363 operator=clsExpression.OP_PLUS 

364 done= False 

365 self.getch() 

366 if self.__GCH__=="-": 

367 operator=clsExpression.OP_MINUS 

368 done= False 

369 self.getch() 

370 

371 return 

372 

373# 

374# parse expression string 

375# expr : string with expression 

376# indicatedSize: force size of result to this size if not None 

377# sizeRequired : True if the size of the expression must be determined by 

378# parsing 

379# 

380 def parse(self,expr,indicatedSize=None,sizeRequired=False): 

381 self.__exprString__=expr 

382 self.__getchCount__=-1 

383 self.__GCH__="" 

384 self.__errors__= [] 

385 self.__size__= None 

386 self.__bc__= [] 

387 self.__lastNumber__=None 

388 self.getch() 

389# 

390# parse expression 

391# 

392 self.term() 

393# 

394# no more characters? 

395# 

396 if self.__GCH__ != "\n": 

397 self.addError(MESSAGE.E_ILLEXPRESSION) 

398# 

399# do we have to resize to a determined size? 

400# 

401 if indicatedSize is not None: 

402 if self.__size__ is None or \ 

403 self.__size__ != indicatedSize: 

404 self.genNumber(indicatedSize) 

405 self.genOp(clsExpression.OP_RESIZE) 

406 self.__size__= indicatedSize 

407# 

408# no determined size, check if a size is required 

409# 

410 else: 

411 if self.__size__ is None and sizeRequired: 

412 self.addError(MESSAGE.E_UNSIZEDEXPRESSION) 

413 

414 if len(self.__errors__)==0: 

415 parsedExpression=clsParsedExpression(self.__bc__,self.__size__) 

416 else: 

417 parsedExpression=clsInvalidOperand() 

418 return parsedExpression,self.__errors__ 

419# 

420# execute the byte code of an expression 

421# 

422 def execute(self,parsedExpression,lineInfo): 

423 

424 stack=[] 

425 self.__errors__= [] 

426 size=parsedExpression.size 

427 

428 

429 for typ,op in parsedExpression.byteCode: 

430 if typ== clsExpression.EX_NUM: 

431 stack.append(op) 

432 elif typ==clsExpression.EX_SYM: 

433 ret=self.__globVar__.symDict.get(op,lineInfo) 

434 if ret is None: 

435 self.addError(MESSAGE.E_SYMNOTFOUND) 

436 return None, None, self.__errors__ 

437 value=ret[1] 

438 stack.append(value) 

439 elif typ==clsExpression.EX_OP: 

440 if op==clsExpression.OP_PLUS: 

441 stack[-2]+=stack[-1] 

442 stack.pop() 

443 elif op==clsExpression.OP_MINUS: 

444 stack[-2]-=stack[-1] 

445 stack.pop() 

446 elif op==clsExpression.OP_MULT: 

447 stack[-2]*=stack[-1] 

448 stack.pop() 

449 elif op==clsExpression.OP_DIV: 

450 if stack[-1]==0: 

451 self.addError(MESSAGE.E_DIVBYZERO) 

452 return None, None, self.__errors__ 

453 stack[-2]//=stack[-1] 

454 stack.pop() 

455 elif op==clsExpression.OP_MOD: 

456 if stack[-1]==0: 

457 self.addError(MESSAGE.E_DIVBYZERO) 

458 return None, None, self.__errors__ 

459 stack[-2]%=stack[-1] 

460 stack.pop() 

461 elif op==clsExpression.OP_AND: 

462 stack[-2]&=stack[-1] 

463 stack.pop() 

464 elif op==clsExpression.OP_OR: 

465 stack[-2]|=stack[-1] 

466 stack.pop() 

467 elif op==clsExpression.OP_CHS: 

468 stack[-1]=-stack[-1] 

469# elif op==clsExpression.OP_NOT: 

470# stack[-1]= ~ stack[-1] 

471 elif op==clsExpression.OP_RESIZE: 

472 value=self.resize(stack[-2],stack[-1]) 

473 if value== None: 

474 self.addError(MESSAGE.E_VALTOOLARGE) 

475 return None, None,self.__errors__ 

476 else: 

477 stack[-2]=value 

478 stack.pop() 

479 

480 result=stack [0] 

481 byteResult=self.makeBytes(result,size) 

482 return result,byteResult,self.__errors__ 

483 

484 def immediate(self,expression,indicatedSize,lineInfo): 

485 parsedExpression,errors=self.parse(expression,indicatedSize,False) 

486 if len(errors)!=0: 

487 return None, None,errors 

488 result,byteResult, errors=self.execute(parsedExpression,lineInfo) 

489 return result,byteResult,errors 

490# 

491# Struct context ------------------------------------------------------ 

492# 

493class clsStructContext(object): 

494 

495 CTX_IF=0 

496 CTX_LOOP=1 

497 CTX_RTN=2 

498 CTX_DISABLED=3 

499 

500 def __init__(self): 

501 super().__init__() 

502 self.__lblCount__=0 

503 self.__ctxStack__= [ ] 

504 self.__rtnDest__= None 

505 

506 def isEmpty(self): 

507 return len(self.__ctxStack__)==0 

508 

509 def push(self,ctxInfo): 

510 if not self.__ctxStack__: 

511 self.__ctxStack__=[ctxInfo] 

512 else: 

513 self.__ctxStack__.append(ctxInfo) 

514 

515 def pop(self): 

516 self.__ctxStack__.pop() 

517 

518 def newLabel(self): 

519 self.__lblCount__+=1 

520 return("{:06d}".format(self.__lblCount__)) 

521 

522 def structR(self): 

523 if self.__rtnDest__ is None: 

524 self.__rtnDest__= self.newLabel() 

525 return(self.__rtnDest__) 

526 

527 def getRtnDest(self): 

528 d=self.__rtnDest__ 

529 self.__rtnDest__= None 

530 return(d) 

531 

532 def structIf(self,arpReg,drpReg): 

533 lbl=self.newLabel() 

534 self.push([clsStructContext.CTX_IF,lbl,None,arpReg,drpReg,False,False,-1,-1]) 

535 return(lbl) 

536 

537 def structElse(self,arpReg,drpReg): 

538 if not self.__ctxStack__: 

539 return None 

540 if self.__ctxStack__[-1][0]!= clsStructContext.CTX_IF: 

541 return None 

542 if self.__ctxStack__[-1][2]!= None: 

543 return None 

544 lbl1=self.__ctxStack__[-1][1] 

545 lbl2=self.newLabel() 

546 self.__ctxStack__[-1][2]=lbl2 

547# 

548# check, if arp or drp were changed in the if clause, if so then 

549# set the invalidate flag to True 

550# 

551 oldArpReg=self.__ctxStack__[-1][3] 

552 if oldArpReg != arpReg: 

553 self.__ctxStack__[-1][5]=True 

554 oldDrpReg=self.__ctxStack__[-1][4] 

555 if oldDrpReg != drpReg: 

556 self.__ctxStack__[-1][6]=True 

557# 

558# store last adp, drp if the IF part 

559# 

560 self.__ctxStack__[-1][7]=arpReg 

561 self.__ctxStack__[-1][8]=drpReg 

562 return (lbl1,lbl2,oldArpReg,oldDrpReg) 

563# 

564# handle removed ELSE clause, return arp/drp status and invalidate entry 

565# 

566 def removeElse(self): 

567 

568 self.__ctxStack__[-1][0]= clsStructContext.CTX_DISABLED 

569 return self.__ctxStack__[-1][5],self.__ctxStack__[-1][6] 

570 

571 def structEndif(self,arpReg,drpReg): 

572 if not self.__ctxStack__: 

573 return None 

574 if self.__ctxStack__[-1][0]== clsStructContext.CTX_DISABLED: 

575 self.pop() 

576 return "",-1,-1,False,False 

577 if self.__ctxStack__[-1][0]!= clsStructContext.CTX_IF: 

578 return None 

579 if self.__ctxStack__[-1][2]!= None: 

580 lbl=self.__ctxStack__[-1][2] 

581 else: 

582 lbl=self.__ctxStack__[-1][1] 

583# 

584# check, if arp or drp were changed in the if clause, if so then 

585# set the invalidate flag to True 

586# 

587 oldArpReg=self.__ctxStack__[-1][3] 

588 if oldArpReg != arpReg: 

589 self.__ctxStack__[-1][5]=True 

590# 

591# but not if drp was the same in the if and the else clause 

592# 

593 if arpReg == self.__ctxStack__[-1][7]: 

594 if arpReg != -1: 

595 self.__ctxStack__[-1][5]=False 

596 oldDrpReg=self.__ctxStack__[-1][4] 

597 if oldDrpReg != drpReg: 

598 self.__ctxStack__[-1][6]=True 

599# 

600# but not if drp was the same in the if and the else clause 

601# 

602 if drpReg == self.__ctxStack__[-1][8]: 

603 if drpReg != -1: 

604 self.__ctxStack__[-1][6]=False 

605 invalidateArp= self.__ctxStack__[-1][5] 

606 invalidateDrp= self.__ctxStack__[-1][6] 

607 self.pop() 

608 return(lbl,oldArpReg,oldDrpReg,invalidateArp,invalidateDrp) 

609 

610 def structLoop(self): 

611 lbl=self.newLabel() 

612 self.push([clsStructContext.CTX_LOOP,lbl,None]) 

613 return(lbl) 

614 

615 def structEx(self): 

616 if not self.__ctxStack__: 

617 return None 

618 if self.__ctxStack__[-1][0]!= clsStructContext.CTX_LOOP: 

619 return None 

620 lbl2=self.newLabel() 

621 self.__ctxStack__[-1][2]=lbl2 

622 return(lbl2) 

623 

624 def structWhile(self): 

625 if not self.__ctxStack__: 

626 return None 

627 if self.__ctxStack__[-1][0]!= clsStructContext.CTX_LOOP: 

628 return None 

629 lbl1=self.__ctxStack__[-1][1] 

630 lbl2=self.__ctxStack__[-1][2] 

631 self.pop() 

632 return(lbl1,lbl2) 

633 

634# 

635# Parser --------------------------------------------------------------- 

636# 

637# The parseLine method takes the Program Counter, the list of scanned token 

638# and the original source line as arguments and returns an object of type 

639# clsParserInfo 

640# 

641class clsParser(clsParserBase): 

642 

643# 

644# Initialize parser 

645# 

646 def __init__(self,globVar,infile): 

647 super().__init__(globVar,infile) 

648 self.__expression__=clsExpression(globVar) 

649 self.__structCtx__= clsStructContext() 

650 return 

651# 

652# Parse EQU, Addr pseudoop 

653# 

654 def pEqu(self): 

655# 

656# The label in the self.__scannedLabel__ field has already been 

657# parsed by the parseLine method 

658# 

659 isAddr=False 

660 indicatedSize=None 

661 if self.__scannedOpcode__.string=="ADDR": 

662 isAddr=True 

663 indicatedSize=2 

664 SymDict=self.__globVar__.symDict 

665 if self.__scannedLabel__ is None: 

666 self.addError(MESSAGE.E_MISSING_LABEL) 

667 return [] 

668 

669 label=self.__scannedLabel__.string 

670 opstring= self.__scannedOperand__[0].string 

671# 

672# evaluate expression immediately 

673# 

674 result,byteResult,errors=self.__expression__.immediate(opstring,\ 

675 indicatedSize, self.__lineInfo__) 

676 

677 if result is not None: 

678 if isAddr: 

679 if result < 0 or result > 0xFFFF: 

680 self.addError(MESSAGE.E_ILL_ADDRESS) 

681 return [] 

682 size=len(byteResult) 

683 ret=SymDict.enter(label,clsSymDict.SYM_DAD,result,size, \ 

684 self.__lineInfo__) 

685 else: 

686 if byteResult is None: 

687 size=None 

688 else: 

689 size=len(byteResult) 

690 ret=SymDict.enter(label,clsSymDict.SYM_EQU,result,size, \ 

691 self.__lineInfo__) 

692 if ret is not None: 

693 self.addError(ret) 

694 else: 

695 self.addError(errors) 

696 return [] 

697# 

698# Parse ABS pseudoop 

699# 

700 def pAbs(self): 

701 self.__globVar__.hasAbs=True 

702 if self.__globVar__.PC !=0: 

703 self.addError(MESSAGE.E_NOTALLOWED_HERE) 

704 return [] 

705# 

706# Parse ORG pseudoop 

707# 

708 def pOrg(self): 

709 opstring= self.__scannedOperand__[0].string 

710 result,byteResult,errors=self.__expression__.immediate(opstring,2, \ 

711 self.__lineInfo__) 

712 if result is not None: 

713 if result >= 0 and result <= 0xFFFF: 

714 self.__globVar__.PC=result 

715 else: 

716 self.addError(MESSAGE.E_ILL_ADDRESS) 

717 else: 

718 self.addError(errors) 

719 return [] 

720# 

721# parse DEF, VAL 

722# 

723 def pDef(self): 

724 if self.__scannedOpcode__.string== "DEF": 

725 self.__opcodeLen__=2 

726 return [self.parseSingleExpression(0,2)] 

727 else: 

728 self.__opcodeLen__=1 

729 return [self.parseSingleExpression(0,1)] 

730# 

731# Parse RTN statement 

732# 

733 def pRtn(self): 

734 self.__globVar__.lastRtnAddr=self.__globVar__.PC 

735 self.__opcodeLen__=1 

736 SymDict=self.__globVar__.symDict 

737 label=self.__structCtx__.getRtnDest() 

738 if label is not None: 

739 ret=SymDict.enter(label,clsSymDict.SYM_LCL,self.__globVar__.PC,2, \ 

740 self.__lineInfo__) 

741 return 

742 

743# 

744# Parse JSB instruction 

745# 

746 def pJsb(self): 

747 self.__opcodeLen__=1 

748 numBytesToStore=2 

749 parsedOperand=[] 

750# 

751# Invalidate Arp, Drp context 

752# 

753 if self.__scannedOpcode__.string!="JSBN": 

754 self.__globVar__.lastStmtWasJSB=True 

755# 

756# Determine mode 

757# 

758 if self.__scannedOperand__[0].string[0]=="=": 

759# 

760# JSB literal direct 

761# 

762 self.__addressMode__=clsParserInfo.JS_LITERAL_DIRECT 

763 self.__opcodeLen__+=numBytesToStore 

764 if len(self.__scannedOperand__)!=1: 

765 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

766 parsedOperand.append(clsInvalidOperand()) 

767 else: 

768 parsedOperand.append(self.parseLabelOp(0)) 

769 else: 

770# 

771# JSB indexed 

772# 

773 self.__addressMode__=clsParserInfo.JS_INDEXED 

774 self.__opcodeLen__+=numBytesToStore 

775 if len(self.__scannedOperand__)!=2: 

776 self.addError(MESSAGE.E_ILL_NUMOPERANDS) # dead code ?? 

777 else: 

778 parsedOperand.append(self.parseXr(0)) 

779 parsedOperand.append(self.parseSingleExpression(1,2)) 

780 return parsedOperand 

781 

782# 

783# Parse AD, AN, CM and SB instructions 

784# 

785 def pAri(self): 

786 

787 parsedOperand=[] 

788 self.__opcodeLen__=1 

789 byteMode=self.getByteMode() 

790# 

791# Parse DR, if we have a valid register then determine the number of 

792# bytes to store for literals or labels 

793# 

794 dRegister=self.parseDr() 

795 if dRegister.isInvalid(): 

796 self.__opcodeLen__=1 

797 return [dRegister] 

798# 

799# Now determina Address Mode and check number of opderands 

800# and parse opcodes 

801# 

802 if len(self.__opcode__)==3: # ADB, ADM, SBB, SBM, CMB, CMM, ANM 

803 if self.__scannedOperand__[1].string[0]== "=": 

804 self.__addressMode__=clsParserInfo.AM_LITERAL_IMMEDIATE 

805 self.__scannedOperand__[1].string= \ 

806 self.__scannedOperand__[1].string[1:] 

807 if byteMode== clsParserInfo.BM_SINGLEBYTE: 

808 if len(self.__scannedOperand__[1].string) > 0: 

809 self.__opcodeLen__+= 1 

810 parsedOperand.append(self.parseSingleExpression(1,1)) 

811 else: 

812 self.addError(MESSAGE.W_LITDATADOESNOTFILL) 

813 

814 else: 

815 numberOfBytesToStore= \ 

816 BYTESTOSTORE.numBytes(dRegister.registerNumber) 

817 if numberOfBytesToStore is None: 

818 if not self.__globVar__.allowHashRLiteral: 

819 self.addError(MESSAGE.W_RHASH_LITERAL) 

820 opLen,parsedExpressions=self.parseExpressionList(1,\ 

821 numberOfBytesToStore) 

822 if opLen is not None: 

823 if numberOfBytesToStore is not None: 

824 if numberOfBytesToStore != opLen: 

825 self.addError(MESSAGE.W_LITDATADOESNOTFILL) 

826 self.__opcodeLen__+= opLen 

827 parsedOperand.extend(parsedExpressions) 

828 

829 else: 

830 self.__addressMode__=clsParserInfo.AM_REGISTER_IMMEDIATE 

831 if len(self.__scannedOperand__)!=2: 

832 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

833 else: 

834 parsedOperand.append(self.parseAr()) 

835 else: # ADBD, ADMD, SBBD, ANMD 

836 

837 if self.__scannedOperand__[1].string[0]== "=": 

838 self.__addressMode__=clsParserInfo.AM_LITERAL_DIRECT 

839 self.__scannedOperand__[1].string= \ 

840 self.__scannedOperand__[1].string[1:] 

841 self.__opcodeLen__+= 2 

842 if len(self.__scannedOperand__)!=2: 

843 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

844 else: 

845 parsedOperand.append(self.parseSingleExpression(1,2)) 

846 else: 

847 self.__addressMode__=clsParserInfo.AM_REGISTER_DIRECT 

848 if len(self.__scannedOperand__)!=2: 

849 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

850 else: 

851 parsedOperand.append(self.parseAr()) 

852 

853 return parsedOperand 

854 

855# 

856# Parse LD / ST instructions: full to bursting of address modes 

857# 

858 def pLdSt(self): 

859 

860 parsedOperand=[] 

861 self.__opcodeLen__=1 

862 byteMode=self.getByteMode() 

863# 

864# Parse DR, if we have a valid register then determine the number of 

865# bytes to store for literals or labels 

866# 

867 dRegister=self.parseDr() 

868 if dRegister.isInvalid(): 

869 self.__opcodeLen__=1 

870 return [dRegister] 

871# 

872# Now determina Address Mode and check number of opderands 

873# and parse opcodes 

874# 

875 if len(self.__opcode__)==3: # LDB, STB, LDM, STM 

876 

877 if self.__scannedOperand__[1].string[0]== "=": 

878 self.__addressMode__=clsParserInfo.AM_LITERAL_IMMEDIATE 

879 self.__scannedOperand__[1].string= \ 

880 self.__scannedOperand__[1].string[1:] 

881 if byteMode== clsParserInfo.BM_SINGLEBYTE: 

882 if len(self.__scannedOperand__[1].string) > 0: 

883 self.__opcodeLen__+= 1 

884 parsedOperand.append(self.parseSingleExpression(1,1)) 

885 else: 

886 self.addError(MESSAGE.W_LITDATADOESNOTFILL) 

887 else: 

888 numberOfBytesToStore= \ 

889 BYTESTOSTORE.numBytes(dRegister.registerNumber) 

890 if numberOfBytesToStore is None: 

891 if not self.__globVar__.allowHashRLiteral: 

892 self.addError(MESSAGE.W_RHASH_LITERAL) 

893 opLen,parsedExpressions=self.parseExpressionList(1,\ 

894 numberOfBytesToStore) 

895 if opLen is not None: 

896 if numberOfBytesToStore is not None: 

897 if numberOfBytesToStore != opLen: 

898 self.addError(MESSAGE.W_LITDATADOESNOTFILL) 

899 self.__opcodeLen__+= opLen 

900 parsedOperand.extend(parsedExpressions) 

901 

902 elif self.__scannedOperand__[1].string[0] in "xX": 

903 self.addError(MESSAGE.E_ILLADDRESSMODE) 

904 

905 else: 

906 self.__addressMode__=clsParserInfo.AM_REGISTER_IMMEDIATE 

907 if len(self.__scannedOperand__)!=2: 

908 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

909 else: 

910 parsedOperand.append(self.parseAr()) 

911 

912 elif self.__opcode__[-1]=="D": # LDBD, STBD, LDMD, STMD 

913 

914 if self.__scannedOperand__[1].string[0]== "=": 

915 self.__addressMode__=clsParserInfo.AM_LITERAL_DIRECT 

916 self.__scannedOperand__[1].string= \ 

917 self.__scannedOperand__[1].string[1:] 

918 self.__opcodeLen__+= 2 

919 if len(self.__scannedOperand__)!=2: 

920 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

921 else: 

922 parsedOperand.append(self.parseSingleExpression(1,2)) 

923 

924 elif self.__scannedOperand__[1].string[0] in "xX": 

925 self.__addressMode__=clsParserInfo.AM_INDEX_DIRECT 

926 self.__opcodeLen__+= 2 

927 if len(self.__scannedOperand__)!=3: 

928 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

929 else: 

930 parsedOperand.append(self.parseXr(1)) 

931 parsedOperand.append(self.parseSingleExpression(2,2)) 

932 

933 else: 

934 self.__addressMode__=clsParserInfo.AM_REGISTER_DIRECT 

935 if len(self.__scannedOperand__)!=2: 

936 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

937 else: 

938 parsedOperand.append(self.parseAr()) 

939 

940 elif self.__opcode__[-1]=="I": # LDBI, STBI, LDMI, STMI 

941 

942 if self.__scannedOperand__[1].string[0]== "=": 

943 self.__addressMode__=clsParserInfo.AM_LITERAL_INDIRECT 

944 self.__scannedOperand__[1].string= \ 

945 self.__scannedOperand__[1].string[1:] 

946 self.__opcodeLen__+= 2 

947 if len(self.__scannedOperand__)!=2: 

948 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

949 else: 

950 parsedOperand.append(self.parseSingleExpression(1,2)) 

951 

952 elif self.__scannedOperand__[1].string[0] in "xX": 

953 self.__addressMode__=clsParserInfo.AM_INDEX_INDIRECT 

954 self.__opcodeLen__+= 2 

955 if len(self.__scannedOperand__)!=3: 

956 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

957 else: 

958 parsedOperand.append(self.parseXr(1)) 

959 parsedOperand.append(self.parseSingleExpression(2,2)) 

960 

961 else: 

962 self.__addressMode__=clsParserInfo.AM_REGISTER_INDIRECT 

963 if len(self.__scannedOperand__)!=2: 

964 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

965 else: 

966 parsedOperand.append(self.parseAr()) 

967 

968 return parsedOperand 

969# 

970# Code Generator class ------------------------------------------------- 

971# 

972# Genertes code and returns an object of class clsCodeInfo 

973# 

974class clsCodeGenerator(clsCodeGeneratorBase): 

975 

976# 

977# Initialize generator 

978# 

979 def __init__(self,globVar): 

980 super().__init__(globVar) 

981 self.__expression__=clsExpression(self.__globVar__) 

982 return 

983# 

984# Generate ARP, DRP instructions. Overwrite superclass method 

985# 

986 def gdarp(self): 

987 if self.__opcodeLen__==0: 

988 return 

989 super().gdarp() 

990 return 

991# 

992# NCAS Assembler class --------------------------------------------------------- 

993# 

994# This is the top level class for the entire assembler 

995# 

996class clsNcas(object): 

997 

998 def __init__(self): 

999 super().__init__() 

1000# 

1001# extend the OPCODES dictionary with the ncas specific OPS 

1002# 

1003 def extendOpcodes(self): 

1004 OPCODES.extendDict( { 

1005# 

1006# ncas specific ops 

1007# 

1008 "RTN" : ["pRtn","gdirect",0o236,0,0,True,False,False], 

1009# 

1010# This is a karma "special" and it means a JSB without return 

1011# Therefore this instruction is handled the same way as a RTN or GTO 

1012# at the end of IF-ELSE clauses in optimizing ARP/DRP elimination 

1013# 

1014 "JSBN" : ["pJsb","gJsb",0o306,1,2,True,False,False], 

1015# 

1016# conditional jump alias 

1017# 

1018 "JEQ" : ["pJrel","gJrel",0o367,1,1,False,False,False], # alias of JZR 

1019 "JNE" : ["pJrel","gJrel",0o366,1,1,False,False,False], # alias of JNZ 

1020 "JGE" : ["pJrel","gJrel",0o365,1,1,False,False,False], # alias of JPS 

1021 "JLT" : ["pJrel","gJrel",0o364,1,1,False,False,False], # alias of JNG 

1022 "JHS" : ["pJrel","gJrel",0o373,1,1,False,False,False], # alias of JCY 

1023 "JLO" : ["pJrel","gJrel",0o372,1,1,False,False,False], # alias of JNC 

1024# 

1025# IF pseudo op (we have to take the opposite condition there) 

1026# 

1027 "IFOV" : ["pIf","gJrel",0o361,0,0,False,False,False], # is JNO 

1028 "IFEV" : ["pIf","gJrel",0o362,0,0,False,False,False], # is JOD 

1029 "IFOD" : ["pIf","gJrel",0o363,0,0,False,False,False], # is JEV 

1030 "IFPS" : ["pIf","gJrel",0o364,0,0,False,False,False], # is JNG 

1031 "IFNG" : ["pIf","gJrel",0o365,0,0,False,False,False], # is JPS 

1032 "IFZR" : ["pIf","gJrel",0o366,0,0,False,False,False], # is JNZ 

1033 "IFNZ" : ["pIf","gJrel",0o367,0,0,False,False,False], # is JZR 

1034 "IFEZ" : ["pIf","gJrel",0o370,0,0,False,False,False], # is JEN 

1035 "IFEN" : ["pIf","gJrel",0o371,0,0,False,False,False], # is JEZ 

1036 "IFCY" : ["pIf","gJrel",0o372,0,0,False,False,False], # is JNC 

1037 "IFNC" : ["pIf","gJrel",0o373,0,0,False,False,False], # is JCY 

1038 "IFLN" : ["pIf","gJrel",0o374,0,0,False,False,False], # is JLZ 

1039 "IFLZ" : ["pIf","gJrel",0o375,0,0,False,False,False], # IS JLN 

1040 "IFRN" : ["pIf","gJrel",0o376,0,0,False,False,False], # is JRZ 

1041 "IFRZ" : ["pIf","gJrel",0o377,0,0,False,False,False], # is JRN 

1042 "IFNE" : ["pIf","gJrel",0o367,0,0,False,False,False], # alias of JZR 

1043 "IFEQ" : ["pIf","gJrel",0o366,0,0,False,False,False], # alias of JNZ 

1044 "IFLT" : ["pIf","gJrel",0o365,0,0,False,False,False], # alias of JPS 

1045 "IFLE" : ["pIf","gJrel",0o364,0,0,False,False,False], # alias of JNG 

1046 "IFLO" : ["pIf","gJrel",0o373,0,0,False,False,False], # alias of JCY 

1047 "IFHS" : ["pIf","gJrel",0o372,0,0,False,False,False], # alias of JNC 

1048# 

1049# While pseudo op 

1050# 

1051 "WHMP" : ["pWh","gJrel",0o360,0,0,False,False,False], 

1052 "WHNO" : ["pWh","gJrel",0o361,0,0,False,False,False], 

1053 "WHOD" : ["pWh","gJrel",0o362,0,0,False,False,False], 

1054 "WHEV" : ["pWh","gJrel",0o363,0,0,False,False,False], 

1055 "WHNG" : ["pWh","gJrel",0o364,0,0,False,False,False], 

1056 "WHPS" : ["pWh","gJrel",0o365,0,0,False,False,False], 

1057 "WHNZ" : ["pWh","gJrel",0o366,0,0,False,False,False], 

1058 "WHZR" : ["pWh","gJrel",0o367,0,0,False,False,False], 

1059 "WHEN" : ["pWh","gJrel",0o370,0,0,False,False,False], 

1060 "WHEZ" : ["pWh","gJrel",0o371,0,0,False,False,False], 

1061 "WHNC" : ["pWh","gJrel",0o372,0,0,False,False,False], 

1062 "WHCY" : ["pWh","gJrel",0o373,0,0,False,False,False], 

1063 "WHLZ" : ["pWh","gJrel",0o374,0,0,False,False,False], 

1064 "WHLN" : ["pWh","gJrel",0o375,0,0,False,False,False], 

1065 "WHRZ" : ["pWh","gJrel",0o376,0,0,False,False,False], 

1066 "WHRN" : ["pWh","gJrel",0o377,0,0,False,False,False], 

1067 "WHEQ" : ["pWh","gJrel",0o367,0,0,False,False,False], # alias of WHZR 

1068 "WHNE" : ["pWh","gJrel",0o366,0,0,False,False,False], # alias of WHNZ 

1069 "WHGE" : ["pWh","gJrel",0o365,0,0,False,False,False], # alias of WHPS 

1070 "WHLT" : ["pWh","gJrel",0o364,0,0,False,False,False], # alias of WHNG 

1071 "WHHS" : ["pWh","gJrel",0o373,0,0,False,False,False], # alias of WHCY 

1072 "WHLO" : ["pWh","gJrel",0o372,0,0,False,False,False], # alias of WHNC 

1073# 

1074# conditional return pseudo op 

1075# 

1076 "RNO" : ["pR","gJrel",0o361,0,0,False,False,False], 

1077 "ROD" : ["pR","gJrel",0o362,0,0,False,False,False], 

1078 "REV" : ["pR","gJrel",0o363,0,0,False,False,False], 

1079 "RNG" : ["pR","gJrel",0o364,0,0,False,False,False], 

1080 "RPS" : ["pR","gJrel",0o365,0,0,False,False,False], 

1081 "RNZ" : ["pR","gJrel",0o366,0,0,False,False,False], 

1082 "RZR" : ["pR","gJrel",0o367,0,0,False,False,False], 

1083 "REN" : ["pR","gJrel",0o370,0,0,False,False,False], 

1084 "REZ" : ["pR","gJrel",0o371,0,0,False,False,False], 

1085 "RNC" : ["pR","gJrel",0o372,0,0,False,False,False], 

1086 "RCY" : ["pR","gJrel",0o373,0,0,False,False,False], 

1087 "RLZ" : ["pR","gJrel",0o374,0,0,False,False,False], 

1088 "RLN" : ["pR","gJrel",0o375,0,0,False,False,False], 

1089 "RRZ" : ["pR","gJrel",0o376,0,0,False,False,False], 

1090 "RRN" : ["pR","gJrel",0o377,0,0,False,False,False], 

1091 "REQ" : ["pR","gJrel",0o367,0,0,False,False,False], # alias of RZR 

1092 "RNE" : ["pR","gJrel",0o366,0,0,False,False,False], # alias of RNZ 

1093 "RGE" : ["pR","gJrel",0o365,0,0,False,False,False], # alias of RPS 

1094 "RLT" : ["pR","gJrel",0o364,0,0,False,False,False], # alias of RNG 

1095 "RHS" : ["pR","gJrel",0o373,0,0,False,False,False], # alias of RCY 

1096 "RLO" : ["pR","gJrel",0o372,0,0,False,False,False], # alias of RNC 

1097# 

1098# conditional exit pseudo op 

1099# 

1100 "EXNO" : ["pEx","gJrel",0o361,0,0,False,False,False], 

1101 "EXOD" : ["pEx","gJrel",0o362,0,0,False,False,False], 

1102 "EXEV" : ["pEx","gJrel",0o363,0,0,False,False,False], 

1103 "EXNG" : ["pEx","gJrel",0o364,0,0,False,False,False], 

1104 "EXPS" : ["pEx","gJrel",0o365,0,0,False,False,False], 

1105 "EXNZ" : ["pEx","gJrel",0o366,0,0,False,False,False], 

1106 "EXZR" : ["pEx","gJrel",0o367,0,0,False,False,False], 

1107 "EXEN" : ["pEx","gJrel",0o370,0,0,False,False,False], 

1108 "EXEZ" : ["pEx","gJrel",0o371,0,0,False,False,False], 

1109 "EXNC" : ["pEx","gJrel",0o372,0,0,False,False,False], 

1110 "EXCY" : ["pEx","gJrel",0o373,0,0,False,False,False], 

1111 "EXLZ" : ["pEx","gJrel",0o374,0,0,False,False,False], 

1112 "EXLN" : ["pEx","gJrel",0o375,0,0,False,False,False], 

1113 "EXRZ" : ["pEx","gJrel",0o376,0,0,False,False,False], 

1114 "EXRN" : ["pEx","gJrel",0o377,0,0,False,False,False], 

1115 "EXEQ" : ["pEx","gJrel",0o367,0,0,False,False,False], # alias of RZR 

1116 "EXNE" : ["pEx","gJrel",0o366,0,0,False,False,False], # alias of RNZ 

1117 "EXGE" : ["pEx","gJrel",0o365,0,0,False,False,False], # alias of RPS 

1118 "EXLT" : ["pEx","gJrel",0o364,0,0,False,False,False], # alias of RNG 

1119 "EXHS" : ["pEx","gJrel",0o373,0,0,False,False,False], # alias of RCY 

1120 "EXLO" : ["pEx","gJrel",0o372,0,0,False,False,False], # alias of RNC 

1121 "LOOP" : ["pLoop","gNil",0,0,0,False,False,False], 

1122 "ENDIF" : ["pEndif","gNil",0,0,0,False,False,False], 

1123 "ELSE" : ["pElse","gJrel",0o360,0,0,False,False,False], 

1124# 

1125# compatibility pseudo ops 

1126# 

1127 "DEF" : ["pDef","gData",0,1,1,False,True,False], 

1128 "VAL" : ["pDef","gData",0,1,1,False,True,False], 

1129# 

1130# ncas pseudo ops 

1131# 

1132 "END" : ["pEnd","gNil",0,0,0,False,False,False], 

1133 "BSS" : ["pBss","gGenZ",0,1,1,False,True,False], 

1134 "ADDR" : ["pEqu","gNil",0,1,1,False,True,False], 

1135 "EQU" : ["pEqu","gNil",0,1,1,False,True,False], 

1136 "GTO" : ["pGto","gGto",0,1,1,True,False,False], 

1137 "ORG" : ["pOrg","gNil",0,1,1,False,True,False], 

1138 "ABS" : ["pAbs","gNil",0,0,0,False,True,False], 

1139 ".SET" : ["pCondSet","gNil",0,1,1,False,True,False], 

1140 ".CLR" : ["pCondClr","gNil",0,1,1,False,True,False], 

1141 ".IFSET" : ["pCondIfSet","gNil",0,1,1,False,True,True], 

1142 ".IFNSET" : ["pCondIfNotSet","gNil",0,1,1,False,True,True], 

1143 ".IFDEF" : ["pCondIfDef","gNil",0,1,1,False,True,True], 

1144 ".IFNDEF" : ["pCondIfNotDef","gNil",0,1,1,False,True,True], 

1145 ".ENDIF" : ["pCondEndif","gNil",0,0,0,False,True,True], 

1146 ".ELSE" : ["pCondElse","gNil",0,0,0,False,True,True], 

1147 "INCLUDE" : ["pInc","gNil",0,1,1,False,True,False], 

1148 "DATA" : ["pData","gData",0,1,OPCODES.NUM_OPERANDS_ANY,False,True,False], 

1149 "TITLE" : ["pHed","gHed",0,1,1,False,True,False], 

1150 "STE" : ["pSte","gSte",0o235,0,0,False,False,False], 

1151# "NOP" : ["pNoPer","gdirect",0o235,0,0,False,False,False], 

1152 "NOP" : ["pNoPer","gdirect",0o220,0,0,False,False,False], # Karma NOP 

1153 "NOP1" : ["pNoPer","gdirect",0o336,0,0,False,False,False], # see Series 80 wiki 

1154 }) 

1155 

1156 def addTimeDateSyms(self,isRegressiontest): 

1157# 

1158# Add predefined symbols to global dictionary 

1159# 

1160 if (isRegressiontest): 

1161 bcdYear=0 

1162 bcdMonth=0 

1163 bcdDay=0 

1164 bcdHour=0 

1165 bcdMin=0 

1166 bcdSec=0 

1167 seconds1900=2208988800 

1168 else: 

1169 dt=clsDateTime() 

1170 bcdYear=dt.bcdYear 

1171 bcdMonth=dt.bcdMonth 

1172 bcdDay=dt.bcdDay 

1173 bcdHour=dt.bcdHour 

1174 bcdMin=dt.bcdMin 

1175 bcdSec=dt.bcdSec 

1176 seconds1970=int(time.time()) 

1177 seconds1900=seconds1970+2208988800 

1178 

1179 self.__globVar__.symDict.extendGlobalSymbols('BCD_YEAR',[1,bcdYear]) 

1180 self.__globVar__.symDict.extendGlobalSymbols('BCD_MONTH',[1,bcdMonth]) 

1181 self.__globVar__.symDict.extendGlobalSymbols('BCD_DAY',[1,bcdDay]) 

1182 self.__globVar__.symDict.extendGlobalSymbols('BCD_HOUR',[1,bcdHour]) 

1183 self.__globVar__.symDict.extendGlobalSymbols('BCD_MIN',[1,bcdMin]) 

1184 self.__globVar__.symDict.extendGlobalSymbols('BCD_SEC',[1,bcdSec]) 

1185 self.__globVar__.symDict.extendGlobalSymbols('SECONDS1900',[1,seconds1900]) 

1186 return 

1187 

1188# 

1189# Assemble method. The method takes the values of the command line 

1190# switches and parameters. This method may be called multiple times 

1191# with different parameters. 

1192# Returns: 

1193# False: everything o.k. 

1194# True: errors in assembly 

1195# Raises capasmError on I/O error 

1196#  

1197 def assemble(self,sourceFileName,binFileName="",listFileName="", \ 

1198 referenceOpt=1, pageSize=66, pageWidth=80, \ 

1199 extendedChecks=False,useOct=False, definedFlags=[], \ 

1200 globalSymbolFile="none"): 

1201# 

1202# initialize opcode 

1203# 

1204 self.extendOpcodes() 

1205# 

1206# initialize error condition 

1207# 

1208 hasError=False 

1209# 

1210# Create global variables data object 

1211# 

1212 self.__globVar__=clsGlobVar() 

1213 self.__globVar__.useHex= not useOct 

1214 self.__sourceFileName__= sourceFileName 

1215 self.__globalSymbolFile__= globalSymbolFile 

1216 self.__globVar__.progName="NCAS" 

1217# 

1218# initialize basic parser functions 

1219# 

1220 parseFunc.DELIMITER="'"+'"' 

1221 parseFunc.LABELMATCHSTRING=\ 

1222 "[A-Za-z][A-Za-z0-9_$\+\-\.#/?\(\!\&)=:<>\|@*^]{0," 

1223# 

1224# Build file name of object file if not specified 

1225# 

1226 if binFileName=="": 

1227 self.__binFileName__= \ 

1228 Path(self.__sourceFileName__).with_suffix(".bin").name 

1229 else: 

1230 self.__binFileName__=binFileName 

1231 self.__listFileName__= listFileName 

1232 self.__referenceOpt__= referenceOpt 

1233 self.__pageSize__= pageSize 

1234 self.__pageWidth__= pageWidth 

1235 self.__extendedChecks__= extendedChecks 

1236 self.__symNamLen__= 32 

1237# 

1238# Check if we run in regression test mode 

1239# 

1240 if os.getenv("CAPASMREGRESSIONTEST"): 

1241 self.__globVar__.isRegressionTest=True 

1242# 

1243# Create symbol table object 

1244# 

1245 self.__globVar__.symDict=clsSymDict( self.__extendedChecks__, \ 

1246 self.__globalSymbolFile__, \ 

1247 { clsSymDict.SYM_DAD: "ADR", \ 

1248 clsSymDict.SYM_EQU: "EQU", \ 

1249 clsSymDict.SYM_LCL: "LCL" }) 

1250# 

1251# add time and date global symbols 

1252# 

1253 self.addTimeDateSyms(self.__globVar__.isRegressionTest) 

1254# 

1255# Create conditional assembly object 

1256# 

1257 self.__globVar__.condAssembly=clsConditionalAssembly(definedFlags) 

1258# 

1259# get directory of source file 

1260# 

1261 self.__globVar__.sourceFileDirectory=\ 

1262 str(Path(self.__sourceFileName__).parent) 

1263# 

1264# Check extended checks mode 

1265# 

1266 if self.__extendedChecks__: 

1267 self.__globVar__.allowHashRLiteral=False 

1268# 

1269# Set symbol name length 

1270# 

1271 self.__globVar__.symNamLen=self.__symNamLen__ 

1272# 

1273# Pass 1: scan and parse lines, accumulate results in the 

1274# pass1Info list 

1275# 

1276 pass1Info=[] 

1277 infile=clsSourceReader(self.__sourceFileName__) 

1278 lineScanner=clsLineScanner("*",";","'`^"+'"') 

1279 lineParser=clsParser(self.__globVar__,infile) 

1280 

1281 while not self.__globVar__.isFin: 

1282 line=infile.read() 

1283 if line is None: 

1284 if pass1Info: 

1285 pass1Info[-1].messages.append(MESSAGE.E_MISSING_FIN) 

1286 break 

1287 else: 

1288 MESSAGE.fatalError("Empty source file") 

1289# 

1290# Scan line 

1291# 

1292 scannedLine=lineScanner.scanLine(line) 

1293# 

1294# Parse line 

1295# 

1296 parsedLine=lineParser.parseLine(scannedLine,line) 

1297 pass1Info.append(parsedLine) 

1298# 

1299# Increment PC and codeLen with length of instructions 

1300# 

1301 self.__globVar__.PC+=parsedLine.opcodeLen 

1302 self.__globVar__.codeLen+=parsedLine.opcodeLen 

1303 

1304 infile=None 

1305 lineScanner=None 

1306 lineParser=None 

1307# 

1308# Passe 2: process content of pass1Info list, generate code, 

1309# write code to binary output file and output information to  

1310# the list file 

1311# 

1312 objWriter=clsObjWriter(self.__binFileName__) 

1313 listWriter=clsListWriter(self.__globVar__,self.__listFileName__, \ 

1314 self.__pageSize__, self.__pageWidth__) 

1315 codeGenerator=clsCodeGenerator(self.__globVar__) 

1316 

1317 for parsedLine in pass1Info: 

1318# 

1319# Generate code 

1320# 

1321 codeInfo=codeGenerator.generate(parsedLine) 

1322# 

1323# Write code 

1324# 

1325 objWriter.writeCode(codeInfo,parsedLine) 

1326# 

1327# Write listing 

1328# 

1329 listWriter.writeLine(parsedLine,codeInfo) 

1330 

1331 codeGenerator=None 

1332 objWriter=None 

1333 

1334 listWriter.writeSymbols(self.__referenceOpt__) 

1335 listWriter.writeStatistics() 

1336 listWriter=None 

1337# 

1338# delete objectfile if any errors 

1339# 

1340 if self.__globVar__.errorCount>0: 

1341 os.remove(self.__binFileName__) 

1342 hasError=True 

1343 self.__globVar__=None 

1344# 

1345# return error condition 

1346# 

1347 return hasError 

1348# 

1349# custom arg checks ---------------------------------------------------- 

1350# 

1351# Helper function to check the range for the page size parameter 

1352# 

1353class argPageSizeCheck(argparse.Action): # pragma: no cover 

1354 def __call__(self, parser, namespace, values, option_string=None): 

1355 if values < 40 or values> 100: 

1356 parser.error("Valid range for {0} is 40 to 100".format(option_string)) 

1357 setattr(namespace, self.dest, values) 

1358 

1359# 

1360# Helper function to check the range for the line width parameter 

1361# 

1362class argWidthCheck(argparse.Action): # pragma: no cover 

1363 def __call__(self, parser, namespace, values, option_string=None): 

1364 if values < 80 or values> 132: 

1365 parser.error("Valid range for {0} is 80 to 132".format(option_string)) 

1366 setattr(namespace, self.dest, values) 

1367 

1368 

1369 

1370# 

1371# Entry point ncas -------------------------------------------------------- 

1372#  

1373# This entry point parses the command line parameters, creates an 

1374# assembler object and executes it with the parsed command line parameters 

1375# 

1376def ncas(): # pragma: no cover 

1377# 

1378# Command line arguments processing 

1379# 

1380 argparser=argparse.ArgumentParser(description=\ 

1381 "An assembler for the Hewlett Packard HP-75",\ 

1382 epilog=\ 

1383 "See https://github.com/bug400/capasm for details. "+CAPASM_VERSION) 

1384 

1385 

1386 argparser.add_argument("sourcefile",help="source code file (required)") 

1387 argparser.add_argument("-b","--binfile",\ 

1388 help="binary object code file (default: sourcefilename with suffix .bin",\ 

1389 default="") 

1390 argparser.add_argument("-l","--listfile",\ 

1391 help="list file (default: no list file)",default="") 

1392 argparser.add_argument("-g","--globalsymbolfile",\ 

1393 help="global symbol file. Use either the built-in symbol table names {\"85\",\"87\",\"75\",\"none\"} or specify a file name for a custom table (default: 75)",default="75") 

1394 argparser.add_argument("-r","--reference",type=int,default=1,\ 

1395 help="symbol reference 0:none, 1:short, 2:full (default:1)",\ 

1396 choices=[0,1,2]) 

1397 argparser.add_argument("-p","--pagesize",type=int,default=66, \ 

1398 help="lines per page (default: 66)",action=argPageSizeCheck) 

1399 argparser.add_argument("-w","--width",type=int,default=80, \ 

1400 help="page width (default:80)",action=argWidthCheck) 

1401 argparser.add_argument("-c","--check",help="activate additional checks", \ 

1402 action='store_true') 

1403 argparser.add_argument("-d","--define",action='append',default=[],\ 

1404 help="define conditional flag with value True") 

1405 argparser.add_argument("-o","--oct",help="use octal output", \ 

1406 action='store_true') 

1407 args= argparser.parse_args() 

1408# 

1409# Create assembler object and run it 

1410# 

1411 ncas= clsNcas() 

1412 try: 

1413 ret=ncas.assemble(args.sourcefile,listFileName=args.listfile,\ 

1414 binFileName=args.binfile, referenceOpt=args.reference, \ 

1415 pageSize=args.pagesize,pageWidth=args.width, \ 

1416 extendedChecks=args.check, \ 

1417 useOct=args.oct,\ 

1418 definedFlags=args.define, \ 

1419 globalSymbolFile=args.globalsymbolfile) 

1420 except capasmError as e: 

1421 print(e.msg+" -- Assembler terminated") 

1422 ret=True 

1423 if ret: 

1424 sys.exit(1) 

1425# 

1426# Run the capasm procedure, if this file is called as top level script 

1427# 

1428if __name__ == '__main__': # pragma: no cover 

1429 ncas() 

1430