import { LabelParserBase } from './labelparserbase' ; import { Utility } from '../misc/utility' ; import { readFileSync } from 'fs' ; import { AsmConfigBase , Z88dkConfig } from '../settings' ; /**
 * This class parses sjasmplus list files.
 */ export class Z88dkLabelParser extends LabelParserBase { protected z88dkMappings = new Map < string , number > ( ) ; protected z88dkRegEx = /^[0-9]+\s+/ ; protected labelRegEx = /^[0-9a-f]+[\s0-9a-f]*\s+>?([^;\s0-9][^;\s]*):\s*(equ\s|macro\s)?\s*([^;\n]*)/i ; protected matchBytesRegEx = /[0-9a-f]{4}\s\s(([0-9a-f][0-9a-f]\s)+)/i ; protected matchLineNumberRegEx = /^\s*([0-9]+)[\s\+]+(.*)/ ; protected matchInclStartRegEx = /^[0-9a-f]+\s+include\s+\"([^\s]*)\"/i ; protected z88dkMapOffset : number ; protected expectedLineNr : number ; /**
     * Reads the given file (an assembler .list file) and extracts all PC
     * values (the first 4 digits), so that each line can be associated with a
     * PC value.
     */ public loadAsmListFile ( config ) { const mapFile = ( config as Z88dkConfig ) . mapFile ; this . readmapFile ( mapFile ) ; super . loadAsmListFile ( config ) ; } param startLineNr protected parseAllFilesAndLineNumbers ( startLineNr = 0 ) { const config = this . config as Z88dkConfig ; if ( config . mainFile ) { const fileName = Utility . getRelFilePath ( config . mainFile ) ; this . includeStart ( fileName ) ; } this . expectedLineNr = 1 ; super . parseAllFilesAndLineNumbers ( startLineNr ) ; } param line protected parseLabelAndAddress ( line ) { let countBytes = 0 ; line = line . replace ( this . z88dkRegEx , '' ) ; let address = parseInt ( line . substr ( 0 , 4 ) , 16 ) ; if ( isNaN ( address ) ) address = undefined ! ; if ( address != undefined ) { const readAddress = address ; address += this . z88dkMapOffset ; const match = this . labelRegEx . exec ( line ) ; if ( match ) { let label = match [ 1 ] ; const equ = match [ 2 ] ; if ( equ ) { if ( equ . toLowerCase ( ) . startsWith ( 'equ' ) ) { let valueString = match [ 3 ] ; try { if ( valueString . indexOf ( '$' ) >= 0 ) { const addressString = address . toString ( ) ; const cAddrString = valueString . replace ( /(?<![a-z_0-9\$])\$(?![a-z_0-9\$])/i , addressString ) ; valueString = cAddrString ; } let value = Utility . evalExpression ( valueString , false ) ; value &= 0xFFFF ; this . addLabelForNumber ( value , label ) ; } catch { } ; } } else { const realAddress = this . z88dkMappings . get ( label ) ; if ( realAddress != undefined ) { this . z88dkMapOffset = realAddress - readAddress ; address = realAddress ; } this . addLabelForNumber ( address , label ) ; } } const matchBytes = this . matchBytesRegEx . exec ( line ) ; if ( matchBytes ) { countBytes = matchBytes [ 1 ] . length / 3 ; } } this . addAddressLine ( address , countBytes ) ; } param line protected parseFileAndLineNumber ( line ) { const matchLineNumber = this . matchLineNumberRegEx . exec ( line ) ; if ( ! matchLineNumber ) return ; const lineNumber = parseInt ( matchLineNumber [ 1 ] ) ; if ( lineNumber != this . expectedLineNr && lineNumber != this . expectedLineNr + 1 ) { this . includeEnd ( ) ; } const remainingLine = matchLineNumber [ 2 ] ; const matchInclStart = this . matchInclStartRegEx . exec ( remainingLine ) ; if ( matchInclStart ) { const fName = matchInclStart [ 1 ] ; this . includeStart ( fName ) ; this . expectedLineNr = 1 ; return ; } this . expectedLineNr = lineNumber ; this . setLineNumber ( lineNumber - 1 ) ; } /**
     * Called by the parser if the end of an include file is found.
     * Does not produce an error because of speccytron MODULE problem (see above).
     */ protected includeEnd ( ) { if ( this . includeFileStack . length > 1 ) this . includeFileStack . pop ( ) ; } param mapFile protected readmapFile ( mapFile ) { this . z88dkMapOffset = 0 ; Utility . assert ( mapFile ) ; const regex = new RegExp ( /^(\w*)\b\s*=\s*\$([0-9a-f]+)/i ) ; let lines = readFileSync ( mapFile ) . toString ( ) . split ( '\n' ) ; for ( const line of lines ) { const match = regex . exec ( line ) ; if ( match ) { const label = match [ 1 ] ; const addr = parseInt ( match [ 2 ] , 16 ) ; this . z88dkMappings . set ( label , addr ) ; } } } }