import { Utility } from '../misc/utility' ; import { LabelParserBase } from './labelparserbase' ; /**
 * This class parses sjasmplus list files.
 */ export class Z80asmLabelParser extends LabelParserBase { 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]+((\s[\.0-9a-f]+)+)/i ; protected matchMacroEndRegEx = /^# End of macro\s+(.*)/ ; protected matchFileEndRegEx = /^# End of file\s+(.*)/ ; protected matchInclStartRegEx = /^[0-9a-f]+\s+include\s+\"([^\s]*)\"/i ; protected lineNr = 0 ; param line protected parseLabelAndAddress ( line ) { let countBytes = 0 ; const address = parseInt ( line . substr ( 0 , 4 ) , 16 ) ; if ( ! isNaN ( address ) ) { 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 { this . addLabelForNumber ( address , label ) ; } } const matchBytes = this . matchBytesRegEx . exec ( line ) ; if ( matchBytes ) { const bytes = matchBytes [ 1 ] . trim ( ) ; const lenBytes = bytes . length ; for ( let k = 0 ; k < lenBytes ; k ++ ) { if ( bytes . charCodeAt ( k ) > 32 ) countBytes ++ ; } countBytes /= 2 ; } } this . addAddressLine ( address , countBytes ) ; } param line protected parseFileAndLineNumber ( line ) { const matchFileEnd = this . matchFileEndRegEx . exec ( line ) ; if ( matchFileEnd ) { const fileName = matchFileEnd [ 1 ] ; this . includeStart ( fileName ) ; return ; } let index = this . includeFileStack . length - 1 ; if ( index < 0 ) return ; const matchInclStart = this . matchInclStartRegEx . exec ( line ) ; if ( matchInclStart ) { const fileName = matchInclStart [ 1 ] ; if ( fileName . valueOf ( ) == this . includeFileStack [ index ] . fileName . valueOf ( ) ) { this . includeEnd ( ) ; index = this . includeFileStack . length - 1 ; } } const matchMacroEnd = this . matchMacroEndRegEx . exec ( line ) ; if ( matchMacroEnd ) { const macroName = matchMacroEnd [ 1 ] ; const startLine = this . searchStartOfMacro ( macroName ) ; const stackItem = this . includeFileStack [ index ] ; for ( let i = startLine ; i < this . lineNr ; i ++ ) { const entry = this . listFile [ i ] ; entry . fileName = stackItem . fileName ; entry . lineNr = stackItem . lineNr ; } this . lineNr = startLine ; stackItem . lineNr -- ; return ; } let sourceLineNr = this . includeFileStack [ index ] . lineNr ; this . setLineNumber ( sourceLineNr ) ; this . includeFileStack [ index ] . lineNr -- ; } param startLineNr protected parseAllFilesAndLineNumbers ( startLineNr = 0 ) { this . lineNr = this . listFile . length - 1 ; for ( ; this . lineNr > 0 ; this . lineNr -- ) { const entry = this . listFile [ this . lineNr ] ; const line = entry . line ; this . currentFileEntry = entry ; this . parseFileAndLineNumber ( line ) ; this . associateSourceFileName ( ) ; } let lastFileName = '' ; let lastFileLength = 0 ; const fileLength = new Map < string , number > ( ) ; for ( const entry of this . listFile ) { if ( lastFileName . valueOf ( ) != entry . fileName . valueOf ( ) ) { lastFileName = entry . fileName ; if ( ! fileLength [ lastFileName ] ) { fileLength [ lastFileName ] = - entry . lineNr ; } lastFileLength = fileLength [ lastFileName ] ; } entry . lineNr += lastFileLength ; } } param macroName return protected searchStartOfMacro ( macroName ) { const macroRegex = new RegExp ( "[0-9a-fA-F]+\\s+(.*:\\s*)?" + macroName + "\\b" ) ; let k = this . lineNr - 1 ; for ( ; k > 0 ; -- k ) { const line2 = this . listFile [ k ] . line ; const matchMacroStart = macroRegex . exec ( line2 ) ; if ( matchMacroStart ) return k ; } Utility . assert ( false ) ; return this . lineNr ; } }