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# 18.05.2020 jsi 

25# - start changelog 

26# 19.05.2020 jsi 

27# - changed number parsing to static methods 

28# 21.05.2020 jsi 

29# - renamed parseLiteralOp to parseLiteralDataList 

30# 22.05.2020 jsi 

31# - raise custom exception on fatal error 

32# - fixed output of short symbol table 

33# - allow comment text to follow immediately the comment sign "!" 

34# - development version 0.9.1 

35# 24.05.2020 jsi 

36# - do not invalidate arp, drp conext on EQU or DAD pseudo ops 

37# 25.05.2020 jsi 

38# - store default bin file in the local directory 

39# 26.05.2020 jsi 

40# - add return value for assemble method 

41# 30.05.2020 jsi 

42# - beta version 0.9.5 

43# - improved help text 

44# 30.06.2020 jsi 

45# - development version 0.9.6 

46# - HP86/87 compatible NAM statement 

47# - jump relative GTO 

48# - bug fixes 

49# - conditional assembly support 

50# - include and link file support 

51# 04.07.2020 jsi 

52# - allow quoted strings for INC and LNK files 

53# - use path of assembler source files for INC and LNK files, if there  

54# is only a file name specified 

55# 08.07.2020 jsi 

56# - development version 0.9.7 

57# - number parsing refactored, allow hex and bin numbers 

58# 20.07.2020 jsi 

59# - literal data list error fixes 

60# - support non octal numbers for registers 

61# - support LOC and HED statements 

62# 23.07.2020 jsi 

63# - development version 0.9.8 

64# - support for ASC/ASP statements with numeric length qualifiers 

65# - removed "'" as alternate string delimiter 

66# - do not issue page break triggered by "HED" if there is no list file 

67# 27.07.2020 jsi 

68# - removed "-m" option 

69# - added "-g" option and enhanced global symbols capabilities 

70# 31.07.2020 jsi 

71# - refactoring 

72# - allow more special characters in symbols 

73 

74import argparse,sys,os,importlib,re 

75import importlib.util 

76from pathlib import Path 

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

78 MESSAGE,clsSymDict, CAPASM_VERSION, CAPASM_VERSION_DATE, \ 

79 clsConditionalAssembly, clsGlobVar, clsToken, clsLineScanner, \ 

80 clsObjWriter, clsListWriter, clsSourceReader, clsParserInfo, \ 

81 clsParsedOperand, clsCodeInfo, clsInvalidOperand, clsParsedNumber, \ 

82 clsParsedString, clsParsedLabel, clsParsedRegister, clsCodeGeneratorBase, \ 

83 clsParserBase 

84 

85# 

86# Parser --------------------------------------------------------------- 

87# 

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

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

90# clsParserInfo 

91# 

92class clsParser(clsParserBase): 

93 

94# 

95# Initialize parser 

96# 

97 def __init__(self,globVar,infile): 

98 super().__init__(globVar,infile) 

99 return 

100# 

101# Parse ABS pseudoop 

102# Syntax is: ABS {ROM} nnnn 

103# ROM does not matter here 

104# 

105 def pAbs(self): 

106 self.__globVar__.hasAbs=True 

107 if self.__globVar__.PC !=0 or self.__globVar__.hasNam: 

108 self.addError(MESSAGE.E_NOTALLOWED_HERE) 

109 addrIndex=0 

110 if len(self.__scannedOperand__)==2: 

111 if self.__scannedOperand__[0].string.upper()== "ROM": 

112 addrIndex=1 

113 else: 

114 self.addError(MESSAGE.E_ROM_EXPECTED) 

115 return [] 

116 address=self.parseAddress(addrIndex) 

117 if address!=clsParserInfo.ILL_NUMBER: 

118 self.__globVar__.PC=address 

119 return [] 

120# 

121# Parse EQU and DAD pseudoops 

122# 

123 def pEqu(self): 

124# 

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

126# parsed by the parseLine method 

127# 

128 isDAD=False 

129 if self.__scannedOpcode__=="DAD": 

130 isDAD=True 

131 SymDict=self.__globVar__.symDict 

132 if self.__scannedLabel__ is None: 

133 self.addError(MESSAGE.E_MISSING_LABEL) 

134 return [] 

135 

136 label=self.__scannedLabel__.string 

137 address=self.parseAddress(0) 

138 

139 if address!=clsParserInfo.ILL_NUMBER: 

140 size=2 

141 if self.__scannedOpcode__.string=="EQU": 

142 if address < 256: 

143 size=1 

144 ret=SymDict.enter(label,clsSymDict.SYM_EQU,address, size,\ 

145 self.__lineInfo__) 

146 else: 

147 address+=self.__globVar__.ORG 

148 ret=SymDict.enter(label,clsSymDict.SYM_DAD,address, size,\ 

149 self.__lineInfo__) 

150 if ret is not None: 

151 self.addError(ret) 

152 return [] 

153# 

154# Parse DEF and VAL 

155# 

156 def pDef(self): 

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

158 self.__opcodeLen__=2 

159 else: 

160 self.__opcodeLen__=1 

161 return[self.parseLabelOp(0)] 

162 

163 

164# 

165# Parse ORG pseudoop 

166# 

167 def pOrg(self): 

168 address=self.parseAddress(0) 

169 if address!=clsParserInfo.ILL_NUMBER: 

170 self.__globVar__.ORG=address 

171 return [] 

172# 

173# Parse JSB instruction 

174# 

175 def pJsb(self): 

176 self.__opcodeLen__=1 

177 numBytesToStore=2 

178 parsedOperand=[] 

179# 

180# Invalidate Arp, Drp context 

181# 

182 self.__globVar__.lastStmtWasJSB=True 

183# 

184# Determine mode 

185# 

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

187# 

188# JSB literal direct 

189# 

190 self.__addressMode__=clsParserInfo.JS_LITERAL_DIRECT 

191 self.__opcodeLen__+=numBytesToStore 

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

193 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

194 parsedOperand.append(clsInvalidOperand()) 

195 else: 

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

197 else: 

198# 

199# JSB indexed 

200# 

201 self.__addressMode__=clsParserInfo.JS_INDEXED 

202 self.__opcodeLen__+=numBytesToStore 

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

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

205 else: 

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

207 parsedOperand.append(self.parseLabelOp(1)) 

208 return parsedOperand 

209# 

210# Parse AD, AN, CM and SB instructions 

211# 

212 def pAri(self): 

213 

214 parsedOperand=[] 

215 self.__opcodeLen__=1 

216 byteMode=self.getByteMode() 

217# 

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

219# bytes to store for literals or labels 

220# 

221 dRegister=self.parseDr() 

222 if dRegister.isInvalid(): 

223 self.__opcodeLen__=1 

224 return [dRegister] 

225# 

226# Now determina Address Mode and check number of opderands 

227# and parse opcodes 

228# 

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

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

231 self.__addressMode__=clsParserInfo.AM_LITERAL_IMMEDIATE 

232 if byteMode== clsParserInfo.BM_SINGLEBYTE: 

233 numberOfBytesToStore=1 

234 ret=self.parseLiteralDataList(numberOfBytesToStore) 

235 self.__opcodeLen__+= ret[0] 

236 else: 

237 numberOfBytesToStore= \ 

238 BYTESTOSTORE.numBytes(dRegister.registerNumber) 

239 if numberOfBytesToStore is None: 

240 if not self.__globVar__.allowHashRLiteral: 

241 self.addError(MESSAGE.W_RHASH_LITERAL) 

242 ret=self.parseLiteralDataList(numberOfBytesToStore) 

243 self.__opcodeLen__+= ret[0] 

244 parsedOperand.extend(ret[1]) 

245 

246 else: 

247 self.__addressMode__=clsParserInfo.AM_REGISTER_IMMEDIATE 

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

249 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

250 else: 

251 parsedOperand.append(self.parseAr()) 

252 else: # ADBD, ADMD, SBBD, ANMD 

253 

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

255 self.__addressMode__=clsParserInfo.AM_LITERAL_DIRECT 

256 self.__opcodeLen__+= 2 

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

258 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

259 else: 

260 parsedOperand.append(self.parseLabelOp(1)) 

261 else: 

262 self.__addressMode__=clsParserInfo.AM_REGISTER_DIRECT 

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

264 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

265 else: 

266 parsedOperand.append(self.parseAr()) 

267 

268 return parsedOperand 

269 

270# 

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

272# 

273 def pLdSt(self): 

274 

275 parsedOperand=[] 

276 self.__opcodeLen__=1 

277 byteMode=self.getByteMode() 

278# 

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

280# bytes to store for literals or labels 

281# 

282 dRegister=self.parseDr() 

283 if dRegister.isInvalid(): 

284 self.__opcodeLen__=1 

285 return [dRegister] 

286# 

287# Now determina Address Mode and check number of opderands 

288# and parse opcodes 

289# 

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

291 

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

293 self.__addressMode__=clsParserInfo.AM_LITERAL_IMMEDIATE 

294 if byteMode== clsParserInfo.BM_SINGLEBYTE: 

295 numberOfBytesToStore=1 

296 ret=self.parseLiteralDataList(numberOfBytesToStore) 

297 self.__opcodeLen__+= ret[0] 

298 else: 

299 numberOfBytesToStore= \ 

300 BYTESTOSTORE.numBytes(dRegister.registerNumber) 

301 if numberOfBytesToStore is None: 

302 if not self.__globVar__.allowHashRLiteral: 

303 self.addError(MESSAGE.W_RHASH_LITERAL) 

304 ret=self.parseLiteralDataList(numberOfBytesToStore) 

305 self.__opcodeLen__+= ret[0] 

306 parsedOperand.extend(ret[1]) 

307 

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

309 self.addError(MESSAGE.E_ILLADDRESSMODE) 

310 

311 else: 

312 self.__addressMode__=clsParserInfo.AM_REGISTER_IMMEDIATE 

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

314 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

315 else: 

316 parsedOperand.append(self.parseAr()) 

317 

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

319 

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

321 self.__addressMode__=clsParserInfo.AM_LITERAL_DIRECT 

322 self.__opcodeLen__+= 2 

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

324 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

325 else: 

326 parsedOperand.append(self.parseLabelOp(1)) 

327 

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

329 self.__addressMode__=clsParserInfo.AM_INDEX_DIRECT 

330 self.__opcodeLen__+= 2 

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

332 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

333 else: 

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

335 parsedOperand.append(self.parseLabelOp(2)) 

336 

337 else: 

338 self.__addressMode__=clsParserInfo.AM_REGISTER_DIRECT 

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

340 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

341 else: 

342 parsedOperand.append(self.parseAr()) 

343 

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

345 

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

347 self.__addressMode__=clsParserInfo.AM_LITERAL_INDIRECT 

348 self.__opcodeLen__+= 2 

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

350 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

351 else: 

352 parsedOperand.append(self.parseLabelOp(1)) 

353 

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

355 self.__addressMode__=clsParserInfo.AM_INDEX_INDIRECT 

356 self.__opcodeLen__+= 2 

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

358 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

359 else: 

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

361 parsedOperand.append(self.parseLabelOp(2)) 

362 

363 else: 

364 self.__addressMode__=clsParserInfo.AM_REGISTER_INDIRECT 

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

366 self.addError(MESSAGE.E_ILL_NUMOPERANDS) 

367 else: 

368 parsedOperand.append(self.parseAr()) 

369 

370 return parsedOperand 

371# 

372# Code Generator class ------------------------------------------------- 

373# 

374# Genertes code and returns an object of class clsCodeInfo 

375# 

376class clsCodeGenerator(clsCodeGeneratorBase): 

377 

378# 

379# Initialize generator 

380# 

381 def __init__(self,globVar): 

382 super().__init__(globVar) 

383 return 

384# 

385# Assembler class --------------------------------------------------------- 

386# 

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

388# 

389class clsAssembler(object): 

390 

391 def __init__(self): 

392 super().__init__() 

393# 

394# extend the OPCODES dictionary with the capasm specific OPS 

395# 

396 def extendOpcodes(self): 

397 OPCODES.extendDict( { 

398 "RTN" : ["pNoPer","gdirect",0o236,0,0,False,False,False], 

399 "ABS" : ["pAbs","gNil",0,1,2,False,False,False], 

400 "FIN" : ["pFin","gNil",0,0,0,False,False,False], 

401 "LST" : ["pNil","gNil",0,0,0,False,False,False], 

402 "UNL" : ["pNil","gNil",0,0,0,False,False,False], 

403 "GLO" : ["pNil","gNil",0,1,1,False,False,False], 

404 "ASC" : ["pAsc","gData",0,1,256,False,False,False], 

405 "ASP" : ["pAsc","gData",0,1,256,False,False,False], 

406 "NAM" : ["pNam","gNam",0,1,2,False,False,False], 

407 "BSZ" : ["pBsz","gGenZ",0,1,1,False,False,False], 

408 "BYT" : ["pByt","gData",0,1,256,False,False,False], 

409 "OCT" : ["pByt","gData",0,1,256,False,False,False], 

410 "DAD" : ["pEqu","gNil",0,1,1,False,False,False], 

411 "DEF" : ["pDef","gDef",0,1,1,False,False,False], 

412 "EQU" : ["pEqu","gNil",0,1,1,False,False,False], 

413 "GTO" : ["pGto","gGto",0,1,1,False,False,False], 

414 "VAL" : ["pDef","gDef",0,1,1,False,False,False], 

415 "ORG" : ["pOrg","gNil",0,1,1,False,False,False], 

416 "SET" : ["pCondSet","gNil",0,1,1,False,False,False], 

417 "CLR" : ["pCondClr","gNil",0,1,1,False,False,False], 

418 "AIF" : ["pCondIfSet","gNil",0,1,1,False,False,True], 

419 "DIF" : ["pCondIfDef","gNil",0,1,1,False,False,True], 

420 "EIF" : ["pCondEndif","gNil",0,0,0,False,False,True], 

421 "ELS" : ["pCondElse","gNil",0,0,0,False,False,True], 

422 "INC" : ["pInc","gNil",0,1,1,False,False,False], 

423 "LNK" : ["pInc","gNil",0,1,1,False,False,False], 

424 "HED" : ["pHed","gHed",0,1,1,False,False,False], 

425 "LOC" : ["pLoc","gGenZ",0,1,1,False,False,False], 

426 }) 

427# 

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

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

430# with different parameters. 

431# Returns: 

432# False: everything o.k. 

433# True: errors in assembly 

434# Raises capasmError on I/O error 

435#  

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

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

438 extendedChecks=False, symNamLen=6,useHex=False, definedFlags=[], \ 

439 globalSymbolFile="none"): 

440# 

441# initialize opcodes 

442# 

443 self.extendOpcodes() 

444# 

445# initialize error condition 

446# 

447 hasError=False 

448# 

449# Create global variables data object 

450# 

451 self.__globVar__=clsGlobVar() 

452 self.__globVar__.useHex=useHex 

453 self.__sourceFileName__= sourceFileName 

454 self.__globalSymbolFile__= globalSymbolFile 

455 self.__globVar__.progName="CAPASM" 

456# 

457# Initalize basic parser functions 

458# 

459 parseFunc.DELIMITER='"' 

460 parseFunc.LABELMATCHSTRING="[(^0-9)(\x20-\x7A|\|)][\x20-\x7A|\|]{0," 

461# 

462# Build file name of object file if not specified 

463# 

464 if binFileName=="": 

465 self.__binFileName__= \ 

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

467 else: 

468 self.__binFileName__=binFileName 

469 self.__listFileName__= listFileName 

470 self.__referenceOpt__= referenceOpt 

471 self.__pageSize__= pageSize 

472 self.__pageWidth__= pageWidth 

473 self.__extendedChecks__= extendedChecks 

474 self.__symNamLen__= symNamLen 

475# 

476# Create symbol table object 

477# 

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

479 self.__globalSymbolFile__, \ 

480 { clsSymDict.SYM_DAD: "DAD", \ 

481 clsSymDict.SYM_EQU: "EQU", \ 

482 clsSymDict.SYM_LCL: "LCL" }) 

483# 

484# Create conditional assembly object 

485# 

486 self.__globVar__.condAssembly=clsConditionalAssembly(definedFlags) 

487# 

488# Check if we run in regression test mode 

489# 

490 if os.getenv("CAPASMREGRESSIONTEST"): 

491 self.__globVar__.isRegressionTest=True 

492# 

493# get directory of source file 

494# 

495 self.__globVar__.sourceFileDirectory=\ 

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

497# 

498# Check extended checks mode 

499# 

500 if self.__extendedChecks__: 

501 self.__globVar__.allowHashRLiteral=False 

502# 

503# Set symbol name length 

504# 

505 self.__globVar__.symNamLen=self.__symNamLen__ 

506# 

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

508# pass1Info list 

509# 

510 pass1Info=[] 

511 infile=clsSourceReader(self.__sourceFileName__) 

512 lineScanner=clsLineScanner("!","!",'"') 

513 lineParser=clsParser(self.__globVar__,infile) 

514 

515 while not self.__globVar__.isFin: 

516 line=infile.read() 

517 if line is None: 

518 if pass1Info: 

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

520 break 

521 else: 

522 MESSAGE.fatalError("Empty source file") 

523# 

524# Scan line 

525# 

526 scannedLine=lineScanner.scanLine(line) 

527# 

528# Parse line 

529# 

530 parsedLine=lineParser.parseLine(scannedLine,line) 

531 pass1Info.append(parsedLine) 

532# 

533# Increment PC and codeLen with length of instructions 

534# 

535 self.__globVar__.PC+=parsedLine.opcodeLen 

536 self.__globVar__.codeLen+=parsedLine.opcodeLen 

537 

538 infile=None 

539 lineScanner=None 

540 lineParser=None 

541# 

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

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

544# the list file 

545# 

546 objWriter=clsObjWriter(self.__binFileName__) 

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

548 self.__pageSize__, self.__pageWidth__) 

549 codeGenerator=clsCodeGenerator(self.__globVar__) 

550 

551 for parsedLine in pass1Info: 

552# 

553# Generate code 

554# 

555 codeInfo=codeGenerator.generate(parsedLine) 

556# 

557# Write code 

558# 

559 objWriter.writeCode(codeInfo,parsedLine) 

560# 

561# Write listing 

562# 

563 listWriter.writeLine(parsedLine,codeInfo) 

564 

565 codeGenerator=None 

566 objWriter=None 

567 

568 listWriter.writeSymbols(self.__referenceOpt__) 

569 listWriter.writeStatistics() 

570 listWriter=None 

571# 

572# delete objectfile if any errors 

573# 

574 if self.__globVar__.errorCount>0: 

575 os.remove(self.__binFileName__) 

576 hasError=True 

577 self.__globVar__=None 

578# 

579# return error condition 

580# 

581 return hasError 

582# 

583# custom arg checks ---------------------------------------------------- 

584# 

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

586# 

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

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

589 if values < 40 or values> 100: 

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

591 setattr(namespace, self.dest, values) 

592 

593# 

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

595# 

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

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

598 if values < 80 or values> 132: 

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

600 setattr(namespace, self.dest, values) 

601 

602 

603 

604# 

605# Entry point capasm ------------------------------------------------------ 

606#  

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

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

609# 

610def capasm(): # pragma: no cover 

611# 

612# Command line arguments processing 

613# 

614 argparser=argparse.ArgumentParser(description=\ 

615 "An assembler for the Hewlett Packard Capricorn CPU (Series 80 and HP-75)",\ 

616 epilog=\ 

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

618 

619 

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

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

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

623 default="") 

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

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

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

627 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: none)",default="none") 

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

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

630 choices=[0,1,2]) 

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

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

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

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

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

636 action='store_true') 

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

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

639 argparser.add_argument("-x","--hex",help="use hex output", \ 

640 action='store_true') 

641 argparser.add_argument("-s","--symnamelength",\ 

642 help="maximum length of symbol names (default:6)", \ 

643 type=int,default=6,choices=[6,7,8,9,10,11,12]) 

644 args= argparser.parse_args() 

645# 

646# Create assembler object and run it 

647# 

648 capasm= clsAssembler() 

649 try: 

650 ret=capasm.assemble(args.sourcefile,listFileName=args.listfile,\ 

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

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

653 extendedChecks=args.check, \ 

654 symNamLen=args.symnamelength,useHex=args.hex,\ 

655 definedFlags=args.define, \ 

656 globalSymbolFile=args.globalsymbolfile) 

657 except capasmError as e: 

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

659 ret=True 

660 if ret: 

661 sys.exit(1) 

662# 

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

664# 

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

666 capasm() 

667