import { Identifier , Terminal } from './terminal' ; import { Expr , AssignExpr , FunctionCallExpr , Args } from './expression' ; import { LexicalScope } from '../SDT/LexicalScope' ; import { ILGen } from '../SDT/ILGen' ; export abstract class Stmt { protected lexicalScope : LexicalScope ; buildLexicalScope ( parent ) { this . lexicalScope = parent ; } abstract print ( level ) ; abstract gen ( il , scopte ) ; } export class DeclareStmt extends Stmt { constructor ( private left , private right ) { super ( ) ; } buildLexicalScope ( parent ) { this . lexicalScope = parent ; this . lexicalScope . bind ( this . left . value , 'number' ) ; } print ( level ) { const pad = '' . padStart ( level * 2 ) ; console . log ( pad + '=' ) ; this . left . print ( level + 1 ) ; this . right . print ( level + 1 ) ; } gen ( il ) { let scope = this . lexicalScope ; il . add ( `declare ${ scope . getLexemeName ( this . left . lvalue ( ) ) }` ) ; if ( this . right && ( < Expr > this . right ) . gen ) { ( < Expr > this . right ) . gen ( il , scope ) ; } il . add ( `${ scope . getLexemeName ( this . left . lvalue ( ) ) }=${ this . right . rvalue ( ) }` ) ; } } export class IfStmt extends Stmt { param { * } expr param { * } ifBlock param { * } elseIfStmt param { * } elseBlock constructor ( private expr , private ifBlock , private elseIfStmt ? , private elseBlock ? ) { super ( ) ; } buildLexicalScope ( parent ) { super . buildLexicalScope ( parent ) ; ( < Expr | Identifier > this . expr ) . bindLexicalScope ( this . lexicalScope ) ; this . ifBlock . buildLexicalScope ( this . lexicalScope ) ; this . elseIfStmt && this . elseIfStmt . buildLexicalScope ( this . lexicalScope ) ; this . elseBlock && this . elseBlock . buildLexicalScope ( this . lexicalScope ) ; } print ( level ) { const pad = '' . padStart ( level * 2 ) ; console . log ( pad + 'if' ) ; this . expr . print ( level + 1 ) ; this . ifBlock . print ( ) ; } gen ( il ) { ( < Expr > this . expr ) . gen ( il , this . lexicalScope ) ; const ifCodeLine = il . add ( '' , true ) ; let ifBlockNextLineNo = null ; this . ifBlock . gen ( il , this . lexicalScope ) ; if ( this . elseIfStmt ) { if ( ! ifBlockNextLineNo ) { ifBlockNextLineNo = il . current ( ) . lineno ; } this . elseIfStmt . gen ( il , this . lexicalScope ) ; } else if ( this . elseBlock ) { if ( ! ifBlockNextLineNo ) { ifBlockNextLineNo = il . current ( ) . lineno ; } this . elseBlock . gen ( il , this . lexicalScope ) ; } const currentLine = il . currentLine ( ) ; const l1 = il . genLabel ( ) ; il . bindLabel ( currentLine . lineno + 1 , l1 ) ; ifCodeLine . code = `branch ${ this . expr . rvalue ( ) } ${ l1 }` ; } } export class ReturnStmt extends Stmt { constructor ( private expr ) { super ( ) ; this . expr = expr ; } buildLexicalScope ( parent ) { super . buildLexicalScope ( parent ) ; this . expr . bindLexicalScope ( this . lexicalScope ) ; } print ( level ) { const pad = '' . padStart ( level * 2 ) ; console . log ( pad + 'return' ) ; this . expr . print ( level + 1 ) ; } gen ( il ) { this . expr && this . expr . gen && this . expr . gen ( il , this . lexicalScope ) ; il . add ( `return ${ this . lexicalScope . getLexemeName ( this . expr . rvalue ( ) ) }` ) ; } } export class Function extends Stmt { constructor ( private id , private args , private block ) { super ( ) ; } buildLexicalScope ( parent ) { this . lexicalScope = new LexicalScope ( parent , { type : 'function' , argc : this . args . size ( ) } ) ; parent . bind ( this . id . value , 'function' ) ; this . args . bindLexicalScope ( this . lexicalScope ) ; this . block . buildLexicalScope ( this . lexicalScope , false ) ; } print ( level ) { const pad = '' . padStart ( level * 2 ) ; console . log ( pad + 'function:' + this . id ) ; this . args . print ( level + 1 ) ; this . block . print ( ) ; } gen ( il ) { il . add ( `declare function ${ this . lexicalScope . getLexemeName ( this . id . lvalue ( ) ) }` ) ; il . beginSection ( this . id . value + '@' + this . lexicalScope . id ) ; il . add ( `set %TOP% %SP%` ) ; this . args . gen ( il , this . lexicalScope ) ; this . block . gen ( il , this . lexicalScope ) ; il . endSection ( ) ; } } export class Block { protected lexicalScope : LexicalScope ; constructor ( public stmts ) { } buildLexicalScope ( parent , create = true ) { if ( create ) { this . lexicalScope = new LexicalScope ( parent ) ; } else { this . lexicalScope = parent ; } this . stmts . forEach ( ( stmt ) => { if ( stmt instanceof Stmt ) { stmt . buildLexicalScope ( this . lexicalScope ) ; } else { ( < Expr | Identifier > stmt ) . bindLexicalScope ( this . lexicalScope ) ; } } ) ; } print ( ) { for ( let i = 0 ; i < this . stmts . length ; i ++ ) { this . stmts [ i ] . print ( 0 ) ; } } gen ( il , scope = this . lexicalScope ) { for ( let i = 0 ; i < this . stmts . length ; i ++ ) { ( < Stmt | Expr > this . stmts [ i ] ) . gen ( il , scope ) ; } } } export class Program extends Block { public ilGen : ILGen ; public lexicalScope : LexicalScope ; constructor ( public stmts ) { super ( stmts ) ; this . ilGen = new ILGen ( ) ; } registerGlobals ( scope ) { scope . bind ( 'print' , 'function' ) ; } buildLexicalScope ( ) { this . lexicalScope = new LexicalScope ( ) ; this . registerGlobals ( this . lexicalScope ) ; this . stmts . forEach ( stmt => { if ( stmt instanceof Stmt ) { stmt . buildLexicalScope ( this . lexicalScope ) ; } else { ( < Expr | Identifier > stmt ) . bindLexicalScope ( this . lexicalScope ) ; } } ) ; } gen ( ) { this . ilGen . beginSection ( 'main@1' ) ; this . ilGen . add ( 'set %TOP% %SP%' ) ; for ( let i = 0 ; i < this . stmts . length ; i ++ ) { ( < Stmt | Expr > this . stmts [ i ] ) . gen ( this . ilGen , this . lexicalScope ) ; } this . ilGen . endSection ( ) ; } }