export class OpcodeCompiler { private lines : Array < string > ; private symbolTable : SymbolTable ; constructor ( ) { } private offset ( register , lexeme , argc = 0 ) { if ( lexeme . index < argc ) { return `${ register }+${ 4 * ( argc - lexeme . index + 1 ) }` ; } else if ( lexeme . index > argc ) { return `${ register }-${ 4 * ( lexeme . index - 1 ) }` ; } else { return `${ register }` ; } } private addr ( curScope , x , register = 'R0' ) { if ( x [ 0 ] . match ( /[0-9]/ ) ) { return '#' + x ; } else if ( x . indexOf ( '%' ) !== - 1 ) { return x . replace ( /%/g , '' ) ; } else { const argc = curScope . type === 'function' ? curScope . argc : 0 ; const lexeme = curScope . find ( x ) ; if ( curScope . id === lexeme . scopeId ) { return `${ this . offset ( 'TOP' , lexeme , argc ) }` ; } else { if ( curScope . isParent ( lexeme . scopeId ) ) { const levelDiff = curScope . level - lexeme . level ; this . lines . push ( `mov TOP ${ register }` ) ; for ( let i = 0 ; i < levelDiff ; i ++ ) { this . lines . push ( `mov @${ register } ${ register }` ) ; } this . lines . push ( `mov ${ this . offset ( register , lexeme , argc ) } ${ register }` ) ; } else { this . lines . push ( `mov TOP ${ register }` ) ; this . lines . push ( `mov @${ register } ${ register }` ) ; this . lines . push ( `mov ${ this . offset ( register , lexeme , argc ) } ${ register }` ) ; } } } } private translatePass ( curScope , params ) { const v = params [ 0 ] ; this . lines . push ( `push ${ this . addr ( curScope , v , 'TOP' ) }` ) ; } private translateBranch ( curScope , params ) { const v = params [ 0 ] ; const lb1 = params [ 1 ] ; this . lines . push ( `jz ${ lb1 }` ) ; } private translateCall ( curScope , params ) { const func = params [ 0 ] ; this . lines . push ( `push PC` ) ; this . lines . push ( `jump ${ func }` ) ; } private translateSet ( curScope , params ) { const assignee = params [ 0 ] ; const op = params [ 2 ] ; const l = params [ 1 ] ; const r = params [ 3 ] ; if ( op ) { const a = this . addr ( curScope , l , 'R0' ) ; const b = this . addr ( curScope , r , 'R1' ) ; switch ( op ) { case "==" : { this . lines . push ( `cmp ${ a } ${ b }` ) ; this . lines . push ( `mov ZF ${ this . addr ( curScope , assignee , 'TOP' ) }` ) ; break ; } case "||" : { this . lines . push ( `mov ${ a } R0` ) ; this . lines . push ( `or R0 ${ b }` ) ; this . lines . push ( `mov R0 ${ this . addr ( curScope , assignee , 'TOP' ) }` ) ; break ; } case '-' : { this . lines . push ( `mov ${ a } R0` ) ; this . lines . push ( `sub R0 ${ b }` ) ; this . lines . push ( `mov R0 ${ this . addr ( curScope , assignee , 'TOP' ) }` ) ; break ; } case '+' : { this . lines . push ( `mov ${ a } R0` ) ; this . lines . push ( `add R0 ${ b }` ) ; this . lines . push ( `mov R0 ${ this . addr ( curScope , assignee , 'TOP' ) }` ) ; } } } else { const a = this . addr ( curScope , assignee , 'R0' ) ; const b = this . addr ( curScope , l , 'R1' ) ; this . lines . push ( `mov ${ b } ${ a }` ) ; if ( assignee . indexOf ( '%' ) === - 1 ) { this . lines . push ( `sub #-4 SP` ) ; } } } public parse ( sourceCode , symbols ) { this . lines = [ ] ; this . symbolTable = new SymbolTable ( symbols ) ; const ilLines = sourceCode . split ( '\n' ) ; let sectionScope = null ; for ( let iline of ilLines ) { if ( iline . trim ( ) ) { let label = '' ; if ( iline . indexOf ( ':' ) !== - 1 ) { [ label , iline ] = iline . split ( ':' ) ; } const prts = iline . split ( ' ' ) . filter ( x => x ) ; /**
                 * codeName：指令名称
                 * params：指令参数列表
                 */ const [ codeName , ... params ] = prts ; switch ( codeName ) { case 'section' : { const [ name , id ] = params [ 0 ] . split ( '@' ) ; sectionScope = this . symbolTable . findScope ( id ) ; break ; } case 'set' : { this . translateSet ( sectionScope , params ) ; break ; } case 'branch' : { this . translateBranch ( sectionScope , params ) ; break ; } case 'pass' : { this . translatePass ( sectionScope , params ) ; break ; } case 'call' : { this . translateCall ( sectionScope , params ) ; break ; } } } } } public print ( ) { for ( let line of this . lines ) { console . log ( line ) ; } } } interface ISymbols { id : number ; table : object ; children : Array < ISymbols > ; type ? : string ; argc ? : number ; } interface IHash { id ? : SymbolTable ; } interface ITable { index : number ; level : number ; scopeId : number ; type : string ; } class SymbolTable { private hash : IHash ; private table : ITable ; public children : Array < SymbolTable > ; public id : number ; public type : string ; public argc : number ; constructor ( private symbols , private parent ? , public level = 0 ) { if ( this . level === 0 ) { this . hash = { } ; } if ( this . parent ) { this . hash = this . parent . hash ; } for ( let key in this . symbols ) { this [ key ] = this . symbols [ key ] ; } this . hash [ this . id ] = this ; for ( let key in this . table ) { this . table [ key ] . level = this . level ; this . table [ key ] . scopeId = this . id ; } this . children = symbols . children ? symbols . children . map ( x => new SymbolTable ( x , this , level + 1 ) ) : null ; } findScope ( id ) { return this . hash [ id ] ; } find ( id ) { if ( id . indexOf ( '@' ) !== - 1 ) { const [ vid , scopeId ] = id . split ( '@' ) ; const scope = this . hash [ scopeId ] ; return scope . table [ vid ] ; } else { if ( this . table [ id ] ) { return this . table [ id ] ; } return this . parent . find ( id ) ; } } isParent ( scopeId ) { if ( this . findScope ( scopeId ) . parent . id === this . id ) { return true ; } else { return false ; } } }