├── src ├── common │ ├── utils.ts │ └── LexicalError.ts ├── demo │ ├── tokenizer.ts │ ├── parser.ts │ ├── ILGen.ts │ └── opcodeCompiler.ts ├── parser │ ├── terminal.ts │ ├── expression.ts │ ├── exprParser.ts │ ├── parser.ts │ └── statement.ts ├── SDT │ ├── LexicalScope.ts │ └── ILGen.ts ├── opcodeCompiler │ └── opcodeCompiler.ts └── tokenizer │ └── tokenizer.ts ├── .gitignore ├── dist ├── common │ ├── utils.js │ ├── utils.js.map │ ├── LexicalError.js.map │ └── LexicalError.js ├── demo │ ├── tokenizer.js.map │ ├── parser.js.map │ ├── ILGen.js.map │ ├── tokenizer.js │ ├── opcodeCompiler.js.map │ ├── parser.js │ ├── ILGen.js │ └── opcodeCompiler.js ├── parser │ ├── terminal.js.map │ ├── terminal.js │ ├── expression.js.map │ ├── exprParser.js.map │ ├── expression.js │ ├── parser.js.map │ ├── exprParser.js │ ├── statement.js.map │ ├── statement.js │ └── parser.js ├── SDT │ ├── ILGen.js.map │ ├── LexicalScope.js.map │ ├── ILGen.js │ └── LexicalScope.js ├── tokenizer │ ├── tokenizer.js.map │ └── tokenizer.js └── opcodeCompiler │ ├── opcodeCompiler.js.map │ └── opcodeCompiler.js ├── 专题 ├── 正则表达式引擎 │ ├── 原文地址.txt │ ├── 正则表达式.doc │ └── 词法分析.doc ├── 内存的分段.jpg ├── 内存的分页.jpg ├── 内存的段页式.jpg ├── 编译原理总览.png ├── 编译原理教案.doc ├── cpu的工作原理.jpg ├── 操作系统对内存的管理.png ├── 第8章-语法制导翻译和中间代码生成.ppt ├── V8引擎介绍(httpszhuanlan.zhihu.comp27628685).png ├── V8如何生成机器码(httpswww.zhihu.comquestion57532509).png └── 汇编.txt ├── README └── imgs │ ├── v8.jpg │ └── automat.jpg ├── 03_中间代码生成 ├── imgs │ └── ir.jpg └── README.txt ├── 04_运行时刻环境 ├── imgs │ └── 递归语言的运行时内存划分.jpg └── README.txt ├── 02_语法分析 └── imgs │ └── LL(k)和LR(k)的解析范围.jpg ├── demo └── escodegen-test │ ├── package.json │ └── src │ ├── style.css │ └── index.html ├── tsconfig.json ├── .vscode └── launch.json ├── 05_目标代码生成 └── README.txt ├── 01_词法分析 └── README.md ├── LICENSE └── README.md /src/common/utils.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /dist/common/utils.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=utils.js.map -------------------------------------------------------------------------------- /专题/正则表达式引擎/原文地址.txt: -------------------------------------------------------------------------------- 1 | http://www.cppblog.com/vczh/archive/2008/05/22/50763.html -------------------------------------------------------------------------------- /专题/内存的分段.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/内存的分段.jpg -------------------------------------------------------------------------------- /专题/内存的分页.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/内存的分页.jpg -------------------------------------------------------------------------------- /专题/内存的段页式.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/内存的段页式.jpg -------------------------------------------------------------------------------- /专题/编译原理总览.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/编译原理总览.png -------------------------------------------------------------------------------- /专题/编译原理教案.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/编译原理教案.doc -------------------------------------------------------------------------------- /专题/cpu的工作原理.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/cpu的工作原理.jpg -------------------------------------------------------------------------------- /README/imgs/v8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/README/imgs/v8.jpg -------------------------------------------------------------------------------- /专题/操作系统对内存的管理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/操作系统对内存的管理.png -------------------------------------------------------------------------------- /03_中间代码生成/imgs/ir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/03_中间代码生成/imgs/ir.jpg -------------------------------------------------------------------------------- /专题/正则表达式引擎/正则表达式.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/正则表达式引擎/正则表达式.doc -------------------------------------------------------------------------------- /专题/正则表达式引擎/词法分析.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/正则表达式引擎/词法分析.doc -------------------------------------------------------------------------------- /README/imgs/automat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/README/imgs/automat.jpg -------------------------------------------------------------------------------- /专题/第8章-语法制导翻译和中间代码生成.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/第8章-语法制导翻译和中间代码生成.ppt -------------------------------------------------------------------------------- /04_运行时刻环境/imgs/递归语言的运行时内存划分.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/04_运行时刻环境/imgs/递归语言的运行时内存划分.jpg -------------------------------------------------------------------------------- /02_语法分析/imgs/LL(k)和LR(k)的解析范围.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/02_语法分析/imgs/LL(k)和LR(k)的解析范围.jpg -------------------------------------------------------------------------------- /src/common/LexicalError.ts: -------------------------------------------------------------------------------- 1 | export class LexicalError extends Error { 2 | constructor(msg) { 3 | super(msg) 4 | } 5 | } -------------------------------------------------------------------------------- /dist/common/utils.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/common/utils.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /专题/V8引擎介绍(httpszhuanlan.zhihu.comp27628685).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/V8引擎介绍(httpszhuanlan.zhihu.comp27628685).png -------------------------------------------------------------------------------- /专题/V8如何生成机器码(httpswww.zhihu.comquestion57532509).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksplwxy/JavaScript-compiler/HEAD/专题/V8如何生成机器码(httpswww.zhihu.comquestion57532509).png -------------------------------------------------------------------------------- /src/demo/tokenizer.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Tokenizer } from '../tokenizer/tokenizer' 3 | let tokenizer = new Tokenizer('var myName = jacksplwxy + test') 4 | console.log('结果:', JSON.stringify(tokenizer.tokens,null,2)) -------------------------------------------------------------------------------- /dist/common/LexicalError.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LexicalError.js","sourceRoot":"","sources":["../../src/common/LexicalError.ts"],"names":[],"mappings":";;;;;;;;;;;;IAAA,MAAa,YAAa,SAAQ,KAAK;QACnC,YAAY,GAAG;YACX,KAAK,CAAC,GAAG,CAAC,CAAA;QACd,CAAC;KACJ;IAJD,oCAIC"} -------------------------------------------------------------------------------- /demo/escodegen-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "escodegen-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /dist/demo/tokenizer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../src/demo/tokenizer.ts"],"names":[],"mappings":";;;;;;;;;;;IACA,sDAAkD;IAClD,IAAI,SAAS,GAAG,IAAI,qBAAS,CAAC,gCAAgC,CAAC,CAAA;IAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAC,IAAI,EAAC,CAAC,CAAC,CAAC,CAAA"} -------------------------------------------------------------------------------- /dist/demo/parser.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/demo/parser.ts"],"names":[],"mappings":";;;;;;;;;;;IAAA,6CAAyC;IAEzC,MAAM,GAAG,GAAG,IAAI,eAAM,EAAE,CAAC,KAAK,CAAC;;;;;;;;;;;CAW9B,CAAC,CAAA;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA"} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "noImplicitAny": false, 5 | "module": "umd", 6 | "removeComments": false, 7 | "sourceMap": true, 8 | "outDir": "dist", 9 | "lib": [ 10 | "ES2017", 11 | "DOM", 12 | "DOM.Iterable" 13 | ] 14 | } 15 | } -------------------------------------------------------------------------------- /src/demo/parser.ts: -------------------------------------------------------------------------------- 1 | import { Parser } from '../parser/parser' 2 | 3 | const ast = new Parser().parse(` 4 | function febonacci(n) { 5 | if(n == 1 || n == 2) { 6 | return n 7 | } 8 | return febonacci(n-1) + febonacci(n-2) 9 | } 10 | var feb = febonacci(n) 11 | var x=y+3*(y-z) 12 | var xx=x+y*(5+6) 13 | 14 | `) 15 | console.log('ast', JSON.stringify(ast.stmts, null, 4)) -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 |   // Use IntelliSense to learn about possible attributes. 3 |   // Hover to view descriptions of existing attributes. 4 |   // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 |   "version": "0.2.0", 6 |   "configurations": [ 7 |     { 8 |       "type": "node", 9 |       "request": "launch", 10 |       "name": "Launch Program", 11 |       "program": "${file}" 12 |     } 13 |   ] 14 | } -------------------------------------------------------------------------------- /dist/demo/ILGen.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ILGen.js","sourceRoot":"","sources":["../../src/demo/ILGen.ts"],"names":[],"mappings":";;;;;;;;;;;IACA,6CAAyC;IACzC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;CAkBlB,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAA;IAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACpC,GAAG,CAAC,KAAK,EAAE,CAAA;IACX,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;IACxC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,CAAA;IACxB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC5B,GAAG,CAAC,GAAG,EAAE,CAAA;IACT,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA"} -------------------------------------------------------------------------------- /src/demo/ILGen.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Parser } from '../parser/parser' 3 | const sourceCode = ` 4 | var b = 2 5 | function closureFn(){ 6 | var c = 3 7 | var d = 4 8 | var a = b/(c+d) 9 | return a 10 | } 11 | 12 | function febonacci(n) { 13 | if(n == 1 || n == 2) { 14 | return n 15 | } 16 | return febonacci(n-1) + febonacci(n-2) 17 | } 18 | 19 | print( febonacci(5) ) 20 | 21 | ` 22 | 23 | const parser = new Parser() 24 | const ast = parser.parse(sourceCode) 25 | ast.print() 26 | console.log('-----SYMBOL TABLE--------') 27 | ast.lexicalScope.print() 28 | console.log('-----il------') 29 | ast.gen() 30 | ast.ilGen.print() 31 | -------------------------------------------------------------------------------- /dist/common/LexicalError.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.LexicalError = void 0; 13 | class LexicalError extends Error { 14 | constructor(msg) { 15 | super(msg); 16 | } 17 | } 18 | exports.LexicalError = LexicalError; 19 | }); 20 | //# sourceMappingURL=LexicalError.js.map -------------------------------------------------------------------------------- /dist/demo/tokenizer.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../tokenizer/tokenizer"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const tokenizer_1 = require("../tokenizer/tokenizer"); 13 | let tokenizer = new tokenizer_1.Tokenizer('var myName = jacksplwxy + test'); 14 | console.log('结果:', JSON.stringify(tokenizer.tokens, null, 2)); 15 | }); 16 | //# sourceMappingURL=tokenizer.js.map -------------------------------------------------------------------------------- /src/demo/opcodeCompiler.ts: -------------------------------------------------------------------------------- 1 | import { Parser } from '../parser/parser' 2 | import { OpcodeCompiler } from '../opcodeCompiler/opcodeCompiler' 3 | 4 | const sourceCode = ` 5 | function febonacci(n) { 6 | if(n == 1 || n == 2) { 7 | return n 8 | } 9 | return febonacci(n-1) + febonacci(n-2) 10 | } 11 | 12 | print( febonacci(5) ) 13 | 14 | ` 15 | 16 | const parser = new Parser() 17 | const ast = parser.parse(sourceCode) 18 | console.log('-----AST------') 19 | ast.print() 20 | console.log('-----SYMBOL TABLE--------') 21 | ast.lexicalScope.print() 22 | console.log('-----IR------') 23 | ast.gen() 24 | ast.ilGen.print() 25 | const compiler = new OpcodeCompiler() 26 | compiler.parse(ast.ilGen.toText(), ast.lexicalScope.toJSON()) 27 | console.log('-----OPcode------') 28 | compiler.print() -------------------------------------------------------------------------------- /dist/demo/opcodeCompiler.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"opcodeCompiler.js","sourceRoot":"","sources":["../../src/demo/opcodeCompiler.ts"],"names":[],"mappings":";;;;;;;;;;;IAAA,6CAAyC;IACzC,qEAAiE;IAEjE,MAAM,UAAU,GAAG;;;;;;;;;;CAUlB,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAA;IAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACpC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IAC7B,GAAG,CAAC,KAAK,EAAE,CAAA;IACX,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;IACxC,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,CAAA;IACxB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC5B,GAAG,CAAC,GAAG,EAAE,CAAA;IACT,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACjB,MAAM,QAAQ,GAAG,IAAI,+BAAc,EAAE,CAAA;IACrC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7D,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAA"} -------------------------------------------------------------------------------- /dist/parser/terminal.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/parser/terminal.ts"],"names":[],"mappings":";;;;;;;;;;;;IAEA,MAAa,QAAQ;QACnB,YAAmB,KAAsB;YAAtB,UAAK,GAAL,KAAK,CAAiB;YACvC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QACpB,CAAC;QAED,IAAI;QACG,MAAM;YACX,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,CAAC;QAED,IAAI;QACG,MAAM;YACX,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,CAAC;QAED,KAAK;QACE,KAAK,CAAC,KAAK;YAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAClD,CAAC;KAEF;IApBD,4BAoBC;IAED,KAAK;IACL,MAAa,UAAW,SAAQ,QAAQ;QAE/B,gBAAgB,CAAC,KAAmB;YACzC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACrC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE;gBACvB,MAAM,iBAAiB,IAAI,CAAC,KAAK,iBAAiB,CAAA;aACnD;QACH,CAAC;KACF;IARD,gCAQC;IAED,IAAI;IACJ,MAAa,OAAQ,SAAQ,QAAQ;KAAI;IAAzC,0BAAyC"} -------------------------------------------------------------------------------- /src/parser/terminal.ts: -------------------------------------------------------------------------------- 1 | import { LexicalScope } from '../SDT/LexicalScope' 2 | 3 | export class Terminal { 4 | constructor(public value: string | number) { 5 | this.value = value 6 | } 7 | 8 | //左值 9 | public lvalue(): string | number { 10 | return this.value 11 | } 12 | 13 | //右值 14 | public rvalue(): string | number { 15 | return this.value 16 | } 17 | 18 | //打印值 19 | public print(level): void { 20 | console.log(''.padStart(level * 2) + this.value) 21 | } 22 | 23 | } 24 | 25 | //标识符 26 | export class Identifier extends Terminal { 27 | private scope: LexicalScope 28 | public bindLexicalScope(scope: LexicalScope) { 29 | this.scope = scope.lookup(this.value) 30 | if (this.scope === null) { 31 | throw `sytnax error: ${this.value} is not defined` 32 | } 33 | } 34 | } 35 | 36 | //数字 37 | export class Numeral extends Terminal { } 38 | 39 | -------------------------------------------------------------------------------- /dist/demo/parser.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../parser/parser"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const parser_1 = require("../parser/parser"); 13 | const ast = new parser_1.Parser().parse(` 14 | function febonacci(n) { 15 | if(n == 1 || n == 2) { 16 | return n 17 | } 18 | return febonacci(n-1) + febonacci(n-2) 19 | } 20 | var feb = febonacci(n) 21 | var x=y+3*(y-z) 22 | var xx=x+y*(5+6) 23 | 24 | `); 25 | console.log('ast', JSON.stringify(ast.stmts, null, 4)); 26 | }); 27 | //# sourceMappingURL=parser.js.map -------------------------------------------------------------------------------- /dist/demo/ILGen.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../parser/parser"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const parser_1 = require("../parser/parser"); 13 | const sourceCode = ` 14 | var b = 2 15 | function closureFn(){ 16 | var c = 3 17 | var d = 4 18 | var a = b/(c+d) 19 | return a 20 | } 21 | 22 | function febonacci(n) { 23 | if(n == 1 || n == 2) { 24 | return n 25 | } 26 | return febonacci(n-1) + febonacci(n-2) 27 | } 28 | 29 | print( febonacci(5) ) 30 | 31 | `; 32 | const parser = new parser_1.Parser(); 33 | const ast = parser.parse(sourceCode); 34 | ast.print(); 35 | console.log('-----SYMBOL TABLE--------'); 36 | ast.lexicalScope.print(); 37 | console.log('-----il------'); 38 | ast.gen(); 39 | ast.ilGen.print(); 40 | }); 41 | //# sourceMappingURL=ILGen.js.map -------------------------------------------------------------------------------- /demo/escodegen-test/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-size 12px; 3 | font-family:'Trebuchet MS', Arial, Helvetica, sans-serif; 4 | } 5 | 6 | pre { 7 | font-family:'Bitstream Vera Sans Mono', Courier, monospace; 8 | font-size: 12px; 9 | background-color: #EEE; 10 | padding:10px; 11 | overflow: auto; 12 | } 13 | 14 | #console { 15 | -webkit-border-radius: 5px; 16 | -moz-border-radius : 5px; 17 | -o-border-radius : 5px; 18 | border-radius : 5px; 19 | border : 1px solid #C6C6C6; 20 | outline: none; 21 | padding:10px; 22 | display: block; 23 | width : 80%; 24 | margin: 10px auto 10px auto; 25 | } 26 | 27 | .invalid { 28 | border-color: #fbc2c4 !important; 29 | } 30 | 31 | #output { 32 | -webkit-border-radius: 5px; 33 | -moz-border-radius : 5px; 34 | -o-border-radius : 5px; 35 | border-radius : 5px; 36 | border : 1px solid #C6C6C6; 37 | width : 80%; 38 | margin : 10px auto 10px auto; 39 | } 40 | 41 | h1, h2, h3, h4, h5, p { 42 | text-align: center; 43 | } 44 | 45 | p { 46 | color: #849EAA; 47 | } 48 | a { 49 | text-decoration: none; 50 | color: #4183C4; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /dist/demo/opcodeCompiler.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../parser/parser", "../opcodeCompiler/opcodeCompiler"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | const parser_1 = require("../parser/parser"); 13 | const opcodeCompiler_1 = require("../opcodeCompiler/opcodeCompiler"); 14 | const sourceCode = ` 15 | function febonacci(n) { 16 | if(n == 1 || n == 2) { 17 | return n 18 | } 19 | return febonacci(n-1) + febonacci(n-2) 20 | } 21 | 22 | print( febonacci(5) ) 23 | 24 | `; 25 | const parser = new parser_1.Parser(); 26 | const ast = parser.parse(sourceCode); 27 | console.log('-----AST------'); 28 | ast.print(); 29 | console.log('-----SYMBOL TABLE--------'); 30 | ast.lexicalScope.print(); 31 | console.log('-----IR------'); 32 | ast.gen(); 33 | ast.ilGen.print(); 34 | const compiler = new opcodeCompiler_1.OpcodeCompiler(); 35 | compiler.parse(ast.ilGen.toText(), ast.lexicalScope.toJSON()); 36 | console.log('-----OPcode------'); 37 | compiler.print(); 38 | }); 39 | //# sourceMappingURL=opcodeCompiler.js.map -------------------------------------------------------------------------------- /dist/parser/terminal.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Numeral = exports.Identifier = exports.Terminal = void 0; 13 | class Terminal { 14 | constructor(value) { 15 | this.value = value; 16 | this.value = value; 17 | } 18 | //左值 19 | lvalue() { 20 | return this.value; 21 | } 22 | //右值 23 | rvalue() { 24 | return this.value; 25 | } 26 | //打印值 27 | print(level) { 28 | console.log(''.padStart(level * 2) + this.value); 29 | } 30 | } 31 | exports.Terminal = Terminal; 32 | //标识符 33 | class Identifier extends Terminal { 34 | bindLexicalScope(scope) { 35 | this.scope = scope.lookup(this.value); 36 | if (this.scope === null) { 37 | throw `sytnax error: ${this.value} is not defined`; 38 | } 39 | } 40 | } 41 | exports.Identifier = Identifier; 42 | //数字 43 | class Numeral extends Terminal { 44 | } 45 | exports.Numeral = Numeral; 46 | }); 47 | //# sourceMappingURL=terminal.js.map -------------------------------------------------------------------------------- /05_目标代码生成/README.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | *代码生成基本概念: 4 | ·代码生成器:将优化后的三地址码转化为目标码的翻译程序 5 | ·目标码的三种形式: 6 | -- 绝对指令代码:能够立即执行的二进制代码,所有地址已经定位 7 | -- 可重新定位指令代码:待装配的机器语言模块,执行时由链接器把他们和某些程序连接起来,转换为可执行的二进制机器语言代码 8 | -- 汇编指令代码:尚未经过汇编器汇编成二进制的汇编代码 9 | ·代码生成主要考虑的问题: 10 | -- 如何使生成目标代码较短 11 | -- 如何充分利用寄存器,减少目标代码中访问存储单元次数 12 | -- 如何充分利用不同cpu指令系统的特点 13 | ·代码生成器的主要任务: 14 | -- 指令选择:代码生成器将中间码转换成目标机器码。一个中间码可以有多种机器码转换,所以代码生成器负责选择指令。 15 | -- 寄存器申请:程序执行过程中可能需要保存一系列值。目标机器架构可能不允许所有的值都保存在CPU内存或寄存器。代码生成器决定寄存器保存哪些值。同样,也决定寄存器保存哪些值。 16 | -- 指令顺序:一个代码生成器决定指令执行的顺序,它创建指令调度来执行它。 17 | ·一个目标原型非常复杂,我们不可能描述出全部细节,所以我们通常会将其简化为一个简单目标机原型。 18 | ·一个简单目标机原型: 19 | -- 加载、保存、运算、跳转等操作 20 | -- 内存按字节、寄存器、指针指向寻址或其他间接寻址 21 | -- n个通用寄存器R0,R1,....,Rn-1 22 | -- 所以运算分量都是整数 23 | -- 指令之间可能有一个标号 24 | ·寄存器: 25 | -- TOP:存放作用域的基址 26 | -- ZF:零标志ZF(Zero Flag)用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。 27 | ·目标通常一个机器指令有几十上百个指令,为了简化通常只选取一些典型指令: 28 | -- 加载指令:LD r, x 29 | -- 保存指令:ST x,r 30 | -- 运算指令:OP dst,src1,src2 31 | SUB R1,R1,R2 // R1=R1-R2 32 | -- 无条件跳转指令:BR L 33 | -- 条件跳转指令:Bcond r,L 34 | -- 压栈操作指令: 35 | push #1 将数字1压栈 36 | push TOP 将寄存器TOP压栈 37 | push @sp 将指针sp指向的值压栈 38 | -- 移动指令: 39 | MOVE R0,R1 将寄存器R0的值移入到R1中 40 | MOVE #1 R0 将数字1移入寄存器R0中 41 | MOVE #1 @TOP 将数字1移到寄存器指向的位置 42 | MOVE #1 @(TOP+4) 将数字1移到寄存器指向的位置基础上再加4位的位置 43 | -- 比较指令:CMP R0,R1 比较两个寄存器中值的大小 44 | -- 代码段行号跳转:JMP @(TOP-8) 45 | ·运算语句的三地址转目标代码: 46 | 三地址码: 47 | x=y-z 48 | 目标代码: 49 | LD R1,y //R1=Y 50 | LD R2,z //R2=Z 51 | SUB R1,R1,R2 //R1=R1-R2 52 | ST X,R1 //X=R1 53 | 解析:优秀的代码生成器应该避免使用上面的全部4个指令,如果: 54 | ①所需的分量已经在寄存器中了 55 | ②运算结果不需要存放内存 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /专题/汇编.txt: -------------------------------------------------------------------------------- 1 | *汇编编译器: 2 | ·汇编语言的编译器 3 | ·汇编语言的大部分命令都和机器码一一对应,而高级语言和汇编的伪指令是不和机器码一一对应的 ,因此从某种意义上说,汇编码就相当于机器码。所以汇编器实现起来非常简单 4 | ·编译器的作用是,将源文件(.c/.cpp/.pas等)转换为目标代码(.obj/.dcu等)。这是已经是二进制代码了。 最后由连接器(Linker),将目标代码连接起来,这样就形成了可执行文件 5 | ·机器码和汇编语言之间是一一对应的关系。汇编程序中存有汇编指令(助记符)和机器码(机器指令)之间一一对应关系的对照表。通过扫描查找对照表可以将汇编指令序列快速地翻译为机器码序列,这样就把你的汇编源程序翻译为目标程序,进而通过链接后生成可执行的机器码文件(如exe文件)。 6 | ·《汇编指令与机器码的相互转换【转】》:https://blog.csdn.net/p312011150/article/details/79612379 7 | 8 | 9 | *汇编语言分类: 10 | 汇编语言和CPU息息相关,但是不能把汇编语言完全等同于CPU的机器指令。不同架构的CPU指令并不相同,如x86,powerpc,arm各有各的指令系统;甚至同一种架构的CPU有几套指令集,典型的如arm除了有32位的指令集外,还有一套16位的thumb指令集。但是作为开发语言的汇编,本质上是一套语法规则和助记符的集合,它可以包容不同的指令集。如果从CPU体系来划分,常见的汇编有两种:IBM PC汇编和ARM汇编。 11 | IBM PC汇编也就是Intel的汇编,因为IBM 最早推出PC机,后来的体系很多都要和它兼容,所以也使用了相同的汇编语言。ARM压根没考虑过兼容,它的指令集和x86完全是两个体系,所以汇编语言也独立发展出一套。 12 | CPU只是限定了机器码,作为开发语言的汇编,其实还和编译器息息相关。汇编语言出现的早,没有像C语言一样定义出标准,所以编译器的厂商各搞一套。到现在,最有名的也是两家:MASM和GNU ASM。前者是微软的,只支持x86,用在DOS/Windows平台中;后者是开源产品,主要用在Linux中,基本上支持大部分的CPU架构。这两者的区别在于伪指令的不同,伪指令是用来告诉编译器如何工作的,和编译器相关,和CPU无关。其实汇编的编译相当简单,这两套伪指令只是符号不相同,含义是大同小异,明白了一种,看另一种就很容易了。 13 | 从汇编格式分,还有Intel格式和AT&T格式的区别,前者是Intel的,windows平台常见,后者最早由贝尔实验室推出,用于Unix中,GUN汇编器的缺省格式就是AT&T。不过GNU的汇编器和调试器gdb对这两种格式都支持,可以随便切换。MASM只支持Intel格式。Intel格式和AT&T格式的区别只是符号系统的区别,这与x86和arm的区别可不一样,后者是CPU体系的区别。 14 | 所谓 内嵌汇编,它是用于C语言和汇编语言混合编程的,所以和编译器也关系紧密,目前也是有两种,GNU的内嵌汇编和MASM的内嵌汇编,它们的语法和普通汇编是有区别的,特别是GNU的内嵌汇编不是很容易看懂,需要专门学习才行。MASM的内嵌汇编和普通汇编的区别则不大。 15 | 关于汇编语言的种类,可以说有多少种不同内核的CPU,就有多少种汇编语言。汇编并不是只有8086/8088汇编,还有8051,ARM,Alpha,MIPS汇编等等... 16 | 如你所知, 汇编是一种面向机器的编程语言,之所以说面向机器是指它的指令系统与具体的CPU芯片相关联,通常不同CPU硬件有不同的汇编系统。8086&8088分别是Intel公司的16位和准16位的CPU,通常使用它作为教材讲解微机机系统原理,是因为80x86系列CPU应用广泛,具有代表性。 17 | 8051主要应用在单片机,ARM汇编用于ARM处理器...不需要解释。 18 | 8086是INTEL公司推出的最早实际应用到微型个人计算机上CPU芯片型号;80x86是在8086基础上的增强型,包括80286,80386,80486,其后就改称奔腾了。大的区别上:8086和80286是16位的CPU,80386和80486是32位CPU;80486还多了数学辅助处理器,增强了复杂的数学运算能力。小的区别上就比较多了,如频率越来越快,包括寄存器的增加等。 19 | 和C语言不同,汇编语言更多的针对特定CPU内核,因此,不同内核的CPU,必须有对应的汇编语言编译器将汇编语言别写的程序编译成对应CPU的机器语言代码,CPU才能正确识别和执行这些代码。 20 | 21 | 22 | -------------------------------------------------------------------------------- /dist/SDT/ILGen.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ILGen.js","sourceRoot":"","sources":["../../src/SDT/ILGen.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/SDT/LexicalScope.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"LexicalScope.js","sourceRoot":"","sources":["../../src/SDT/LexicalScope.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /src/SDT/LexicalScope.ts: -------------------------------------------------------------------------------- 1 | 2 | export class LexicalScope { 3 | private static scopeId: number = 1 4 | private globalHash = null //存放标识符的全局hash 5 | public id = null //本作用域id索引 6 | private table = null //存储标识符属性的符号表 7 | private children = null //子作用域列表 8 | private index = null //临时标识符索引 9 | constructor(private parent?, private others?: object) { 10 | //父作用域 11 | this.parent = parent 12 | //其他数据,例如函数的实参 13 | this.others = others 14 | //不存在父作用域时,初始化标识符全局hash 15 | if (!this.parent) { 16 | this.globalHash = {} 17 | } else { 18 | //存在父作用域时,globalHash就是指向父作用域的globalHash地址 19 | this.globalHash = parent.globalHash 20 | //将本作用域加入到父作用域的children中 21 | this.parent.add(this) 22 | } 23 | this.id = LexicalScope.scopeId++ 24 | this.table = {} 25 | this.children = [] 26 | this.index = 0; 27 | } 28 | //添加子作用域 29 | add(subScope): void { 30 | this.children.push(subScope) 31 | } 32 | //向上寻找id的作用域 33 | public lookup(id): LexicalScope { 34 | if (id.indexOf('$') !== -1) { 35 | return this.globalHash[id] 36 | } 37 | let p:LexicalScope = this 38 | while (p) { 39 | if (p.table[id]) { 40 | return p 41 | } 42 | p = p.parent 43 | } 44 | return null 45 | } 46 | //定义临时标识符名,带上作用域id 47 | bindTempVar(type = 'number'):string { 48 | const varName = `$t` + this.index 49 | this.bind(varName, type) 50 | return varName + '@' + this.id 51 | } 52 | //标识符加入全局hash中,并指向它的作用域 53 | bind(id, type = 'number', others?) { 54 | this.globalHash[id + '@' + this.id] = this 55 | this.table[id] = { 56 | type, 57 | index: this.index++, 58 | ...others 59 | } 60 | } 61 | //给词法带上作用域id 62 | getLexemeName(id) { 63 | const scope = this.lookup(id) 64 | if (scope) { 65 | return id + '@' + scope.id 66 | } else { 67 | throw `syntax error: lexeme ${id} not found.` 68 | } 69 | } 70 | //将作用域状态打印出来 71 | print(level = 0) { 72 | const pad = ''.padStart(level * 2) 73 | console.log(`${pad}scope ${this.id}\n${pad}{`) 74 | for (let key in this.table) { 75 | console.log(`${pad} ${key} : ${this.table[key].type}`) 76 | } 77 | this.children.forEach(child => { 78 | child.print(level + 1) 79 | }) 80 | console.log(`${pad}}`) 81 | } 82 | //格式化数据为json 83 | toJSON() { 84 | const obj = { 85 | id: this.id, 86 | table: this.table, 87 | children: this.children.map(child => child.toJSON()), 88 | ...this.others 89 | } 90 | return obj 91 | } 92 | 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/SDT/ILGen.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ILGen { 3 | private static labelCounter = 1 4 | private stack: Array
//section存放栈,栈顶为当前作用域 5 | private sections: Array
// section列表 6 | constructor() { 7 | this.stack = [] 8 | this.sections = [] 9 | } 10 | //为每个作用域单独创建一个section 11 | beginSection(mark): void { 12 | const section = new Section(mark) 13 | this.sections.push(section) 14 | this.stack.push(section) 15 | } 16 | 17 | //生成LB标签 18 | genLabel() { 19 | return `LB${ILGen.labelCounter++}` 20 | } 21 | 22 | //解析完成时出栈 23 | endSection() { 24 | this.stack.pop() 25 | } 26 | 27 | //在当前section中添加中间码数据 28 | add(code) { 29 | return this.current().add(code) 30 | } 31 | 32 | //获取当前section 33 | current() { 34 | return this.stack[this.stack.length - 1] 35 | } 36 | 37 | //获取当前section中栈顶中间码数据 38 | currentLine() { 39 | const section = this.current() 40 | return section.lines[section.lines.length - 1] 41 | } 42 | 43 | //LB与代码行数绑定 44 | bindLabel(index, label) { 45 | const section = this.current() 46 | section.bindLabel(index, label) 47 | } 48 | 49 | //将所有中间码结果打印出来,带上行号 50 | print() { 51 | for (let i = this.sections.length - 1; i >= 0; i--) { 52 | const section = this.sections[i] 53 | console.log('section:' + section.mark) 54 | for (let line of section.lines) { 55 | console.log(`${line.lineno}:${line.code}`) 56 | } 57 | } 58 | } 59 | 60 | //将数组中的中间码格式化成string,带换行 61 | toText() { 62 | let text = '' 63 | for (let i = this.sections.length - 1; i >= 0; i--) { 64 | const section = this.sections[i] 65 | text += 'section ' + section.mark + '\n' 66 | for (let line of section.lines) { 67 | if (section.labels[line.lineno]) { 68 | text += section.labels[line.lineno] + ":" + line.code + '\n' 69 | } else { 70 | text += line.code + '\n' 71 | } 72 | } 73 | } 74 | return text 75 | } 76 | 77 | } 78 | 79 | 80 | //片段 81 | class Section { 82 | private lineno //记录当前作用域中中间码代码行数 83 | public mark //作用域标识 84 | public lines //当前域的中间码 85 | public labels //LB列表 86 | constructor(mark) { 87 | this.mark = mark 88 | this.lines = [] 89 | this.lineno = 0 90 | this.labels = [] 91 | } 92 | 93 | //LB与代码行数绑定 94 | bindLabel(index, label) { 95 | this.labels[index] = label 96 | } 97 | //将生成的中间码加入lines列表,并返回 98 | add(code) { 99 | const line = { 100 | code, 101 | lineno: this.lineno++ 102 | } 103 | this.lines.push(line) 104 | return line 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /demo/escodegen-test/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JS code generator demo: JS → AST → JS 7 | 8 | 9 | 10 | 64 | 65 | 66 | 67 |

JS code generator demo: JS → AST → JS

68 |

using esprima as parser

69 |

and using escodegen as code generator

70 | 71 |

72 | 
73 | 
74 | 


--------------------------------------------------------------------------------
/src/parser/expression.ts:
--------------------------------------------------------------------------------
  1 | import { Terminal, Identifier } from './terminal'
  2 | import { ILGen } from '../SDT/ILGen'
  3 | import { LexicalScope } from '../SDT/LexicalScope'
  4 | 
  5 | export class Expr {
  6 |   protected _rval: string
  7 |   constructor(private op: string, protected left: (Expr | Terminal | Args), protected right: (Expr | Terminal | Args)) { }
  8 | 
  9 |   public print(level: number = 0): void {
 10 |     const pad: string = ''.padStart(level * 2)
 11 |     console.log(pad + this.op)
 12 |     this.left && this.left.print(level + 1)
 13 |     this.right && this.right.print(level + 1)
 14 |   }
 15 | 
 16 |   //代码生成
 17 |   public gen(il: ILGen, scope: LexicalScope) {
 18 |     if (this.left && (this.left).gen) {
 19 |       (this.left).gen(il, scope)
 20 |     }
 21 |     if (this.right && (this.right).gen) {
 22 |       (this.right).gen(il, scope)
 23 |     }
 24 |     const tempVar: string = scope.bindTempVar()
 25 |     il.add(`set ${tempVar} ${(this.left).rvalue()} ${this.op} ${(this.right).rvalue()}`)
 26 |     this._rval = tempVar;
 27 |   }
 28 | 
 29 |   //获取临时标识符名
 30 |   public rvalue(): string {
 31 |     return this._rval;
 32 |   }
 33 | 
 34 |   //绑定词法作用域
 35 |   public bindLexicalScope(scope) {
 36 |     if (this.left && (this.left).bindLexicalScope) {
 37 |       (this.left).bindLexicalScope(scope)
 38 |     }
 39 |     if (this.right && (this.right).bindLexicalScope) {
 40 |       (this.right).bindLexicalScope(scope)
 41 |     }
 42 |   }
 43 | }
 44 | 
 45 | //函数调用表达式
 46 | export class FunctionCallExpr extends Expr {
 47 |   constructor(private id: Identifier, private args: Args) {
 48 |     super('call', id, args)
 49 |   }
 50 | 
 51 |   gen(il: ILGen, scope: LexicalScope) {
 52 |     (this.right).gen(il, scope)
 53 |     const tempVar = scope.bindTempVar()
 54 |     il.add(`call ${scope.getLexemeName((this.left).lvalue())}`)
 55 |     this._rval = tempVar
 56 |   }
 57 | }
 58 | 
 59 | export class AssignExpr extends Expr {
 60 |   constructor(private id: Identifier, private expr: Expr | Terminal) {
 61 |     super('=', id, expr)
 62 |   }
 63 | 
 64 |   gen(il: ILGen, scope: LexicalScope): void {
 65 |     il.add(`declare ${scope.getLexemeName(this.id.lvalue())}`);
 66 |     (this.expr).gen(il, scope)
 67 |     il.add(`${scope.getLexemeName(this.id.lvalue())}=${this.expr.rvalue()}`)
 68 |   }
 69 | }
 70 | 
 71 | export class Args {
 72 |   constructor(private args: Array, private type = 'call') { }
 73 | 
 74 |   print(level): void {
 75 |     this.args.forEach(x => {
 76 |       x.print(level)
 77 |     })
 78 |   }
 79 | 
 80 |   size(): number {
 81 |     return this.args.length
 82 |   }
 83 | 
 84 |   bindLexicalScope(scope: LexicalScope): void {
 85 |     for (let i = 0; i < this.args.length; i++) {
 86 |       if (this.type === 'function') {
 87 |         scope.bind((this.args[i]).value)
 88 |         this.args[i].bindLexicalScope(scope)
 89 |       } else {
 90 |         this.args[i].bindLexicalScope && this.args[i].bindLexicalScope(scope)
 91 |       }
 92 |     }
 93 |   }
 94 | 
 95 |   gen(il: ILGen, scope: LexicalScope): void {
 96 |     if (this.type == 'call') {
 97 |       for (let i = 0; i < this.args.length; i++) {
 98 |         const expr = this.args[i]
 99 |         if ((expr).gen) {
100 |           (expr).gen(il, scope)
101 |         }
102 |         il.add(`pass ${expr.rvalue()}`)
103 |       }
104 |     }
105 |   }
106 | 
107 | }
108 | 
109 | 


--------------------------------------------------------------------------------
/dist/parser/expression.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"expression.js","sourceRoot":"","sources":["../../src/parser/expression.ts"],"names":[],"mappings":"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"}


--------------------------------------------------------------------------------
/dist/SDT/ILGen.js:
--------------------------------------------------------------------------------
  1 | (function (factory) {
  2 |     if (typeof module === "object" && typeof module.exports === "object") {
  3 |         var v = factory(require, exports);
  4 |         if (v !== undefined) module.exports = v;
  5 |     }
  6 |     else if (typeof define === "function" && define.amd) {
  7 |         define(["require", "exports"], factory);
  8 |     }
  9 | })(function (require, exports) {
 10 |     "use strict";
 11 |     Object.defineProperty(exports, "__esModule", { value: true });
 12 |     exports.ILGen = void 0;
 13 |     class ILGen {
 14 |         constructor() {
 15 |             this.stack = [];
 16 |             this.sections = [];
 17 |         }
 18 |         //为每个作用域单独创建一个section
 19 |         beginSection(mark) {
 20 |             const section = new Section(mark);
 21 |             this.sections.push(section);
 22 |             this.stack.push(section);
 23 |         }
 24 |         //生成LB标签
 25 |         genLabel() {
 26 |             return `LB${ILGen.labelCounter++}`;
 27 |         }
 28 |         //解析完成时出栈
 29 |         endSection() {
 30 |             this.stack.pop();
 31 |         }
 32 |         //在当前section中添加中间码数据
 33 |         add(code) {
 34 |             return this.current().add(code);
 35 |         }
 36 |         //获取当前section
 37 |         current() {
 38 |             return this.stack[this.stack.length - 1];
 39 |         }
 40 |         //获取当前section中栈顶中间码数据
 41 |         currentLine() {
 42 |             const section = this.current();
 43 |             return section.lines[section.lines.length - 1];
 44 |         }
 45 |         //LB与代码行数绑定
 46 |         bindLabel(index, label) {
 47 |             const section = this.current();
 48 |             section.bindLabel(index, label);
 49 |         }
 50 |         //将所有中间码结果打印出来,带上行号
 51 |         print() {
 52 |             for (let i = this.sections.length - 1; i >= 0; i--) {
 53 |                 const section = this.sections[i];
 54 |                 console.log('section:' + section.mark);
 55 |                 for (let line of section.lines) {
 56 |                     console.log(`${line.lineno}:${line.code}`);
 57 |                 }
 58 |             }
 59 |         }
 60 |         //将数组中的中间码格式化成string,带换行
 61 |         toText() {
 62 |             let text = '';
 63 |             for (let i = this.sections.length - 1; i >= 0; i--) {
 64 |                 const section = this.sections[i];
 65 |                 text += 'section ' + section.mark + '\n';
 66 |                 for (let line of section.lines) {
 67 |                     if (section.labels[line.lineno]) {
 68 |                         text += section.labels[line.lineno] + ":" + line.code + '\n';
 69 |                     }
 70 |                     else {
 71 |                         text += line.code + '\n';
 72 |                     }
 73 |                 }
 74 |             }
 75 |             return text;
 76 |         }
 77 |     }
 78 |     exports.ILGen = ILGen;
 79 |     ILGen.labelCounter = 1;
 80 |     //片段
 81 |     class Section {
 82 |         constructor(mark) {
 83 |             this.mark = mark;
 84 |             this.lines = [];
 85 |             this.lineno = 0;
 86 |             this.labels = [];
 87 |         }
 88 |         //LB与代码行数绑定
 89 |         bindLabel(index, label) {
 90 |             this.labels[index] = label;
 91 |         }
 92 |         //将生成的中间码加入lines列表,并返回
 93 |         add(code) {
 94 |             const line = {
 95 |                 code,
 96 |                 lineno: this.lineno++
 97 |             };
 98 |             this.lines.push(line);
 99 |             return line;
100 |         }
101 |     }
102 | });
103 | //# sourceMappingURL=ILGen.js.map


--------------------------------------------------------------------------------
/dist/parser/exprParser.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"exprParser.js","sourceRoot":"","sources":["../../src/parser/exprParser.ts"],"names":[],"mappings":"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"}


--------------------------------------------------------------------------------
/dist/SDT/LexicalScope.js:
--------------------------------------------------------------------------------
  1 | (function (factory) {
  2 |     if (typeof module === "object" && typeof module.exports === "object") {
  3 |         var v = factory(require, exports);
  4 |         if (v !== undefined) module.exports = v;
  5 |     }
  6 |     else if (typeof define === "function" && define.amd) {
  7 |         define(["require", "exports"], factory);
  8 |     }
  9 | })(function (require, exports) {
 10 |     "use strict";
 11 |     Object.defineProperty(exports, "__esModule", { value: true });
 12 |     exports.LexicalScope = void 0;
 13 |     class LexicalScope {
 14 |         constructor(parent, others) {
 15 |             this.parent = parent;
 16 |             this.others = others;
 17 |             this.globalHash = null; //存放标识符的全局hash
 18 |             this.id = null; //本作用域id索引
 19 |             this.table = null; //存储标识符属性的符号表
 20 |             this.children = null; //子作用域列表
 21 |             this.index = null; //临时标识符索引
 22 |             //父作用域
 23 |             this.parent = parent;
 24 |             //其他数据,例如函数的实参
 25 |             this.others = others;
 26 |             //不存在父作用域时,初始化标识符全局hash
 27 |             if (!this.parent) {
 28 |                 this.globalHash = {};
 29 |             }
 30 |             else {
 31 |                 //存在父作用域时,globalHash就是指向父作用域的globalHash地址
 32 |                 this.globalHash = parent.globalHash;
 33 |                 //将本作用域加入到父作用域的children中
 34 |                 this.parent.add(this);
 35 |             }
 36 |             this.id = LexicalScope.scopeId++;
 37 |             this.table = {};
 38 |             this.children = [];
 39 |             this.index = 0;
 40 |         }
 41 |         //添加子作用域
 42 |         add(subScope) {
 43 |             this.children.push(subScope);
 44 |         }
 45 |         //向上寻找id的作用域
 46 |         lookup(id) {
 47 |             if (id.indexOf('$') !== -1) {
 48 |                 return this.globalHash[id];
 49 |             }
 50 |             let p = this;
 51 |             while (p) {
 52 |                 if (p.table[id]) {
 53 |                     return p;
 54 |                 }
 55 |                 p = p.parent;
 56 |             }
 57 |             return null;
 58 |         }
 59 |         //定义临时标识符名,带上作用域id
 60 |         bindTempVar(type = 'number') {
 61 |             const varName = `$t` + this.index;
 62 |             this.bind(varName, type);
 63 |             return varName + '@' + this.id;
 64 |         }
 65 |         //标识符加入全局hash中,并指向它的作用域
 66 |         bind(id, type = 'number', others) {
 67 |             this.globalHash[id + '@' + this.id] = this;
 68 |             this.table[id] = Object.assign({ type, index: this.index++ }, others);
 69 |         }
 70 |         //给词法带上作用域id
 71 |         getLexemeName(id) {
 72 |             const scope = this.lookup(id);
 73 |             if (scope) {
 74 |                 return id + '@' + scope.id;
 75 |             }
 76 |             else {
 77 |                 throw `syntax error: lexeme ${id} not found.`;
 78 |             }
 79 |         }
 80 |         //将作用域状态打印出来
 81 |         print(level = 0) {
 82 |             const pad = ''.padStart(level * 2);
 83 |             console.log(`${pad}scope ${this.id}\n${pad}{`);
 84 |             for (let key in this.table) {
 85 |                 console.log(`${pad}  ${key} : ${this.table[key].type}`);
 86 |             }
 87 |             this.children.forEach(child => {
 88 |                 child.print(level + 1);
 89 |             });
 90 |             console.log(`${pad}}`);
 91 |         }
 92 |         //格式化数据为json
 93 |         toJSON() {
 94 |             const obj = Object.assign({ id: this.id, table: this.table, children: this.children.map(child => child.toJSON()) }, this.others);
 95 |             return obj;
 96 |         }
 97 |     }
 98 |     exports.LexicalScope = LexicalScope;
 99 |     LexicalScope.scopeId = 1;
100 | });
101 | //# sourceMappingURL=LexicalScope.js.map


--------------------------------------------------------------------------------
/01_词法分析/README.md:
--------------------------------------------------------------------------------
 1 | * 词法分析的目标:词法分析的目标是将文本分割成一个个的“token”,例如:init、main、init、x、;、x、=、3、;、}等等。同时它可以去掉一些注释、空格、回车等等无效字符
 2 | * 词法分析生成token的办法有2种:
 3 |   
4 | ~ 使用正则进行词法分析:需要写大量的正则表达式,正则之间还有冲突需要处理,不容易维护,性能不高,所以正则只适合一些简单的模板语法,真正复杂的语言并不合适。并且有的语言并不一定自带正则引擎。 5 |
6 | ~ 使用自动机进行词法分析:自动机可以很好的生成token 7 | * 有穷状态自动机(finite state machine):在有限个输入的情况下,在这些状态中转移并期望最终达到终止状态。 8 | * 有穷状态自动机根据确定性可以分为: 9 |
10 | ~ “确定有穷状态自动机”(DFA - Deterministic finite automaton) 11 |
12 | ~ “非确定有穷自动机”(NFA - Non-deterministic finite automaton)。 13 | * DFA:在输入一个状态时,只得到一个固定的状态。DFA 可以认为是一种特殊的 NFA。 14 | * NFA:当输入一个字符或者条件得到一个状态机的集合。JavaScript 正则采用的是 NFA 引擎 15 | * ε-NFA:NFA的一个小分支。我们用ε边来表示一个状态可以不读入字符就跳转到另一个状态 上,ε-NFA就是在NFA中存在这种边的情况 16 | * 示例:实现一个正则为(a|b)*abb的自动机(https://www.bilibili.com/video/BV1zW411t7YE?p=15,07:05) 17 |
18 | ~ NFA的实现(状态0遇到a有0和1两种状态,无法确定) 19 | ``` 20 | →state:0 -a→ state:0 21 | -b→ state:0 22 | -a→ state:1 -b→ state:2 -b→ state:3 makeToken 23 | ``` 24 | ~ DFA的实现(状态0遇到a只有state1一种状态) 25 | ``` 26 | →state:0 -b→ state:0 27 | -a→ state:1 -b→ state:2 -b→ state:3 makeToken -a→ state:1 28 | -b→ state:0 29 | -a→ state:1 30 | -a→ state:1 31 | ``` 32 | * 正则表达式可以等价的转为一个有穷自动机。 33 | * 正则引擎实际上就是使用自动计算法实现的。 34 | * DFA和NFA的关系: 35 |
36 | ~ DFA和NFA之间可以相互转换 37 |
38 | ~ NFA比DFA更加直观的看出它的匹配状态 39 |
40 | ~ DFA比NFA更加容易使用计算机进行实现 41 | * 正则表达式的自动机实现(自动化词法生成器的实现): 42 | 因为NFA更直观,所以先将正则表达式转换为NFA。而DFA更容易使用代码实现,所以再将NFA转换为DFA。简而言之就是:正则表达式 → NFA → DFA 43 | * 正则表达式虽然可以等价转换为DFA,但为了简化代码,我们完全可以直接使用DFA实现一个词法分析器。 44 | * 关系运算符DFA(部分): 45 |
第一行解析:→state:0 ->→ state:1 -=→ state:5 makeToken(op,≥): 46 |
表示开始状态0,当遇到>符号时进入状态1,当遇到=符号时进入状态5,此时结束匹配,生成token为操作符≥ 47 | ``` 48 | →state:0 -+→ state:1 -+→ makeToken(op,++) 49 | -others→ makeToken(op,+) 50 | --→ state:2 --→ makeToken(op,--) 51 | -others→ makeToken(op,-) 52 | -*→ makeToken(op,*) 53 | -/→ makeToken(op,/) 54 | -=→ state:4 -=→ makeToken(op,==) 55 | -others→ makeToken(op,=) 56 | -&→ state:5 -&→ makeToken(op,&&) 57 | -others→ makeToken(op,&) 58 | -|→ state:6 -|→ makeToken(op,||) 59 | -others→ makeToken(op,|) 60 | ->→ state:7 -=→ makeToken(op,>=) 61 | -others→ makeToken(op,>) 62 | -<→ state:8 -=→ makeToken(op,<>=) 63 | -others→ makeToken(op,<) 64 | -!→ state:9 -=→ makeToken(op,!=) 65 | -others→ makeToken(op,!) 66 | -(→ makeToken(op,() 67 | -)→ makeToken(op,)) 68 | -others→ err 69 | ``` 70 | * 变量名DFA: 71 | ``` 72 | →state:0 -a-z||A-Z→ state:1 -a-z||A-Z||0-9||_→ state:1 73 | -others→ state:2 makeToken(接着判断该tokens是否属于keywords) 74 | -others→ err 75 | ``` 76 | * 数字DFA(不含二进制和科学计算法): 77 | ``` 78 | →state:0 -1-9→ state:1 -0-9→ state:1 79 | -others→ state:6 makeToken 80 | -.→ state:4 -other→ state:6 makeToken 81 | -0-9→ state:5 -0-9→ state:5 82 | -others→ state:6 makeToken 83 | -0→ state:2 -0-9→ state:1 84 | -other→ state:6 makeToken 85 | -.→ state:4 86 | -.→ state:3 -0-9→ state:5 87 | -others→ err 88 | ``` 89 | 替代文本 90 | 91 | * [词法分析器代码入口](../src/tokenizer/tokenizer.ts) 92 | -------------------------------------------------------------------------------- /dist/parser/expression.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Args = exports.AssignExpr = exports.FunctionCallExpr = exports.Expr = void 0; 13 | class Expr { 14 | constructor(op, left, right) { 15 | this.op = op; 16 | this.left = left; 17 | this.right = right; 18 | } 19 | print(level = 0) { 20 | const pad = ''.padStart(level * 2); 21 | console.log(pad + this.op); 22 | this.left && this.left.print(level + 1); 23 | this.right && this.right.print(level + 1); 24 | } 25 | //代码生成 26 | gen(il, scope) { 27 | if (this.left && this.left.gen) { 28 | this.left.gen(il, scope); 29 | } 30 | if (this.right && this.right.gen) { 31 | this.right.gen(il, scope); 32 | } 33 | const tempVar = scope.bindTempVar(); 34 | il.add(`set ${tempVar} ${this.left.rvalue()} ${this.op} ${this.right.rvalue()}`); 35 | this._rval = tempVar; 36 | } 37 | //获取临时标识符名 38 | rvalue() { 39 | return this._rval; 40 | } 41 | //绑定词法作用域 42 | bindLexicalScope(scope) { 43 | if (this.left && this.left.bindLexicalScope) { 44 | this.left.bindLexicalScope(scope); 45 | } 46 | if (this.right && this.right.bindLexicalScope) { 47 | this.right.bindLexicalScope(scope); 48 | } 49 | } 50 | } 51 | exports.Expr = Expr; 52 | //函数调用表达式 53 | class FunctionCallExpr extends Expr { 54 | constructor(id, args) { 55 | super('call', id, args); 56 | this.id = id; 57 | this.args = args; 58 | } 59 | gen(il, scope) { 60 | this.right.gen(il, scope); 61 | const tempVar = scope.bindTempVar(); 62 | il.add(`call ${scope.getLexemeName(this.left.lvalue())}`); 63 | this._rval = tempVar; 64 | } 65 | } 66 | exports.FunctionCallExpr = FunctionCallExpr; 67 | class AssignExpr extends Expr { 68 | constructor(id, expr) { 69 | super('=', id, expr); 70 | this.id = id; 71 | this.expr = expr; 72 | } 73 | gen(il, scope) { 74 | il.add(`declare ${scope.getLexemeName(this.id.lvalue())}`); 75 | this.expr.gen(il, scope); 76 | il.add(`${scope.getLexemeName(this.id.lvalue())}=${this.expr.rvalue()}`); 77 | } 78 | } 79 | exports.AssignExpr = AssignExpr; 80 | class Args { 81 | constructor(args, type = 'call') { 82 | this.args = args; 83 | this.type = type; 84 | } 85 | print(level) { 86 | this.args.forEach(x => { 87 | x.print(level); 88 | }); 89 | } 90 | size() { 91 | return this.args.length; 92 | } 93 | bindLexicalScope(scope) { 94 | for (let i = 0; i < this.args.length; i++) { 95 | if (this.type === 'function') { 96 | scope.bind(this.args[i].value); 97 | this.args[i].bindLexicalScope(scope); 98 | } 99 | else { 100 | this.args[i].bindLexicalScope && this.args[i].bindLexicalScope(scope); 101 | } 102 | } 103 | } 104 | gen(il, scope) { 105 | if (this.type == 'call') { 106 | for (let i = 0; i < this.args.length; i++) { 107 | const expr = this.args[i]; 108 | if (expr.gen) { 109 | expr.gen(il, scope); 110 | } 111 | il.add(`pass ${expr.rvalue()}`); 112 | } 113 | } 114 | } 115 | } 116 | exports.Args = Args; 117 | }); 118 | //# sourceMappingURL=expression.js.map -------------------------------------------------------------------------------- /03_中间代码生成/README.txt: -------------------------------------------------------------------------------- 1 | *中间代码: 2 | ·基本概念: 3 | -- IR:中间代码。它独立于机器,复杂性介于源码与机器码之间 4 | -- ILGen:(Intermediate Code/Language Generator)中间代码生成 5 | ·解释器通常不生成中间码,而是直接计算结果。编译器会生成中间码,例如Java字节码 6 | ·中间代码的设计要求: 7 | -- 与机器无关 8 | -- 利于优化 9 | -- 利于目标代码的生成 10 | ·中间码的作用:主要是产生工程上的意义 11 | -- 易移植:与机器无关,所以它作为中间语言可以为生成多种不同型号的目标机器码服务 12 | -- 机器无关优化:对中间码进行机器无关优化,利于提高代码质量 13 | -- 层次清晰:将AST映射成中间代码表示,再映射成目标代码的工作分层进行,使编译算法更加清晰 14 | ·编译器所使用的IR可以有很多种形式。就其“形状”而言,可以分为: 15 | -- 基于图 16 | -- 基于树 17 | -- 基于DAG(有向无环图) 18 | -- 基于一般图 19 | -- 基于线性代码 20 | -- 三地址代码(四元组) 21 | -- 二地址代码(三元组) 22 | -- 零地址代码 23 | -- 基于图与线性代码混合 24 | -- 最常见的情况是控制流图(CFG)用图表示 25 | -- 而CFG的每个节点是基本块,每个基本块里的代码是线性代码 26 | ·中间代码生成方法:语法制导翻译 27 | 28 | 29 | *语法制导翻译: 30 | ·什么是语法制导翻译:语法分析过程中,边分析(语法分析),边翻译(语义分析和中间码生成)。即语法分析、语义分析、中间代码生成经常是在语法分析时候一起进行的 31 | ·语义分析:是对经语法分析器处理过后的在结构上正确的源程序进行上下文有关性质的审查,是编译程序最实质的过程 32 | ·语义属性文法:是在上下文无关文法的基础上为每个文法符号(终结符或非终结符)配备若干个相关的“值”(称为语义属性) 33 | -- 语义属性:代表与文法符号相关的信息,和变量一样,可以进行计算和传递,常用于存储结果和中间值。例:类型、值、代码序列、符号表内容等 34 | -- 语义规则:也称语法制导定义(Syntax Directed Definition),对于文法的每一个产生式配备一组属性的计算规则, 属性计算的过程即是语义处理的过程,常用于描述属性如何被计算。例如定义AST如何被翻译:如想将AST翻译为Java,则定义Java语法制导规则;想将AST翻译为三地址码,则定义三地址码语法制导规则。使AST与目标代码解耦。 35 | ·语义与语法:语义跟文法不一样。例如文法E → E + E,表示一个表达式可以推导出另一个表达式加另另一个表达式,如表达式2+3*4可以拆成表达式2加上表达式3*4,虽然表达式都是E表示,但每个E的语义值不同,例如第一个E的语义值为14,第二个E的语义值为2,第三个E的语义值为12。 36 | ·语法制导翻译具体实现:为每个产生式配置一个语义子程序(子程序用于实现语法制导规则),当语法分析进行规约或推导时,调用语义子程序完成一部分翻译任务。 37 | ·语义子程序的主要任务:语义分析(改变某些变量的值、查填各种符号表、发现并报告源程序错误等)和产生中间代码 38 | ·语义子程序相关属性和规则存储于符号表中 39 | 40 | 41 | *符号表: 42 | ·语法制导翻译时,为每个产生式配置一个语义子程序,为了获取子程序相关信息,我们通常需要一种中间的记录来描述符号之间的关系,特别是作用域关系(04_运行时刻环境中将会体现),这种记录的容器就是符号表。 43 | ·编译器各种阶段都可能跟表格产生联系 44 | ·符号表的作用: 45 | -- 用于存储符号(变量、常量、标签)在源代码中的位置、数据类型、位置信息决定的词法作用域和运行时的相对内存地址 46 | -- 一致性检查:查符号表检查标示符是否为标号(label) 47 | -- 作用域分析:同一个名字在不同函数嵌套中代表的地址不一样 48 | -- 辅助代码生成:为目标代码生成进行优化提供信息 49 | ·符号表实例: 50 | NAME INFORMATION 51 | index 整型,变量 52 | socre 实型,变量 53 | p 数组,形式参数 54 | ·常见符号表: 55 | -- 名字表(nametab) 56 | -- 程序体表(btab) 57 | -- 层次显示表(display) 58 | -- 数组信息表(atab) 59 | -- 中间代码表(code) 60 | 61 | 62 | *三地址码: 63 | ·三地址码是中间码中常用的一种 64 | ·三地址表达式:表达式中最多只能出现3个地址,因为cpu无法处理4个及其以上地址的操作。可以看成是抽象语法树的一种线性表示。 65 | ·三地址代码基于两个基本的概念:地址和指令。简单地说,地址就是运算分量,指令就是运算符,一个地址的表现形式可以是变量名、常量或者编译器生成的临时变量。几种常见的三地址指令形式:《ir指令行事》:./imgs/ir.jpg 66 | ·为什么选择三地址的中间形式: 67 | -- 三地址代码是一种线性IR。由于输入源程序及输出目标程序都是线性的,因此,线性IR有着其他形式无法比拟的优势。 68 | -- 相对于其他表示形式而言,程序员对于线性表示形式通常会有一种莫名的亲切感,编译器设计者当然也不例外。早期编译器设计者往往都是汇编语言程序设计的高手,可以非常自然、流畅地阅读线性的三地址代码形式。同时,线性表示形式也会降低输入输出的实现难度。 69 | * 三地址码生成:按深度优先遍历AST,每个节点生成一个临时变量。等价如下递归算法: 70 | func eval(expr){ 71 | if(expr is Factor){ 72 | return expr.value 73 | } 74 | return eval(expr.left) expr.op eval(expr.right) 75 | } 76 | -- 左值和右值:等号左边和右边的区别。数字1只有右值,变量可以有左值和右值 77 | -- BinaryExpr:op左右都有值的称为BinaryExpr 78 | -- UaryExpr:op只有右值,没有左值的称为UnaryExpr。例如一个表达式 79 | -- 任何一个非叶子节点都能生成一个左值和一个右值,右值是一个表达式例如100+200,左值是一个临时变量例如t1,完整:t1=100+200 80 | ·Duck Type:鸭子类型。非鸭子类型语言生成左值时需要判定左值类型是否支持生成左值 81 | ·三地址代码实例1: 82 | 源码: 83 | var a=1 84 | var b=5 85 | var c=(a+b)*5 86 | 转换为三地址码如下: 87 | declare a 88 | declare b 89 | declare c 90 | a=1 91 | b=5 92 | t1=a+b 93 | t2=t1*5 94 | c=t2 95 | 分析:实例展示了从js源码到三地址码,再到机器码的过程,可以看到三地址码的每行代码永远只存在三个变量。以上只需要按深度优先遍历AST,每个节点生成一个临时变量即可生成。 96 | ·三地址表达式实例2: 97 | 源码: 98 | function f(n){ 99 | if(n==1 || n==2){ 100 | return n 101 | } 102 | return f(n-1)+f(n-2) 103 | } 104 | f(5) 105 | 转换为三地址码如下: 106 | declare f 107 | declare n 108 | t1=n==1 109 | t2=n==2 110 | t3=t1 or t2 111 | branch t3==true 112 | goto (return n)行 or (return f(n-1)+f(n-2))行 //return怎么处理? 113 | t4=n-1 114 | t5=f(t4) //如何递归调用? 115 | t6=n-2 116 | t7=f(t6) //如何递归调用? 117 | t8=t5+t7 118 | call f //如何调用函数? 119 | 分析:在三地址代码实例1中,生成的中间码在运行时按顺序之上而下执行就能很好的执行。但该例中会遇到一些问题,例如如何处理return?如何处理递归调用?函数如何调用?要解决这些问题,首先是要了解运行时刻环境 120 | ·三地址表达式实例2的分析: 121 | -- 无论return还是递归,解决问题的关键就是要给函数打一个标签,该标签记录着函数的位置,标签可以存放到符号表中,这样return或递归时将指针移动到该函数的位置即可。 122 | 123 | 124 | *文档: 125 | ·中间码简介:https://www.jianshu.com/p/2862623af39e 126 | ·中间码的形式:https://www.hashcoding.net/2015/12/10/%E5%85%AD%E3%80%81%E4%B8%AD%E9%97%B4%E4%BB%A3%E7%A0%81-IR/ 127 | ·中间码的设计:https://book.51cto.com/art/201206/340208.htm 128 | ·图解各种三地址码的特点1:https://blog.csdn.net/SHU15121856/article/details/104711426/ 129 | ·图解各种三地址码的特点2:https://blog.csdn.net/raojun/article/details/103605349 130 | 131 | 132 | *要使目标代码正确执行,由上面的三地址码直接转为的目标代码还是不够的,例如在三地址代码实例2提到的一些问题,另外还有不同作用域中存在同样变量名,我们如何在运行时确定变量的存储单元。所以我们还需要知道程序在内存中的位置、程序执行时的上下文环境、变量的作用域等信息才能生成准确的中间码。这些知识我们将在《04_运行时刻环境》:../04_运行时刻环境/README.txt中学习到 -------------------------------------------------------------------------------- /src/parser/exprParser.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { Expr, FunctionCallExpr, AssignExpr } from './expression' 4 | import { Parser } from './parser' 5 | import { IToken } from '../tokenizer/tokenizer' 6 | import { Terminal, Identifier } from './terminal' 7 | 8 | //表达式parser 9 | export class expressionParser { 10 | //优先级序列表 11 | readonly PRIORITY_TABLE = { 12 | '+': 60, 13 | '-': 60, 14 | '*': 70, 15 | '/': 70, 16 | '>=': 80, 17 | '<=': 80, 18 | '>': 80, 19 | '<': 80, 20 | '&&': 90, 21 | '||': 90, 22 | '==': 100, 23 | '!=': 100, 24 | '(': 1000, 25 | ')': 1000 26 | } 27 | 28 | constructor(private parser: Parser) { } 29 | 30 | //表达式解析方法 31 | public exprParser(): (Expr | Terminal) { 32 | if (this.parser.lookahead.value === ')') { 33 | return null 34 | } 35 | // PreOrder : 前序 36 | // inOrder : 中序 37 | // PostOrder : 后序 38 | return this.constructAST(this.inOrderToPostOrder()) 39 | } 40 | 41 | //构建AST:abcd+*+ → ab(c+d)*+ → ab*(c+d)+ → a+b*(c+d) 42 | private constructAST(postOrderOutput: Array): (Expr | Terminal) { 43 | const stack = [] 44 | for (let i = 0; i < postOrderOutput.length; i++) { 45 | const current: (IToken | Terminal | Expr) = postOrderOutput[i] 46 | if ((current).type === 'operator') { 47 | const r: (Terminal | Expr) = stack.pop() 48 | const l: Identifier = stack.pop() 49 | const expr: Expr = new Expr((current).value, l, r) 50 | stack.push(expr) 51 | } else { 52 | stack.push(current) 53 | } 54 | } 55 | return stack[0] 56 | } 57 | 58 | /** 59 | * 帮助Pop Stack直到Prediction满足 60 | * @param {*} stack 61 | * @param {Lambda} prediction 62 | * @param {*} callback 63 | */ 64 | private popUntil(stack: Array, prediction: (token?: IToken) => boolean, callback: (token?: IToken) => void): void { 65 | let token: IToken = null 66 | while (token = stack.pop()) { 67 | if (prediction(token)) { 68 | stack.push(token) 69 | break 70 | } 71 | callback(token) 72 | } 73 | } 74 | 75 | /** 76 | * 后序遍历实现表达式优先级算法:中序表达式a+b*(c+d)的转换后序表达式abcd+*+ 77 | */ 78 | private inOrderToPostOrder(): Array { 79 | const opStack: Array = [] 80 | const output: Array = [] 81 | while (this.parser.lookahead.value != 'eof' && this.parser.lookahead.value !== '}') { 82 | if (this.parser.lookahead.value === '(') { 83 | opStack.push(this.parser.lookahead) 84 | this.parser.match('(') 85 | } else if (this.parser.lookahead.value === ')') { 86 | this.popUntil(opStack, (token: IToken) => token.value === '(', (token: IToken) => { 87 | output.push(token) 88 | }) 89 | const op: IToken = opStack.pop() 90 | // 遇到没有左括号匹配的情况意味着需要停止处理 91 | if (!op || op.value !== '(') { 92 | break 93 | } 94 | this.parser.match(')') 95 | if (this.parser.lookahead.type != 'operator') { 96 | break 97 | } 98 | } else if (this.parser.lookahead.type === 'operator') { 99 | const op: IToken = this.parser.lookahead 100 | if (!(op.value in this.PRIORITY_TABLE)) { 101 | throw `An operator expected in @line ${this.parser.lookahead.lineNo} but ${this.parser.lookahead.value} found` 102 | } 103 | this.parser.match(op.value) 104 | const lastOp: IToken = opStack[opStack.length - 1] 105 | if (!lastOp) { // opStack是空的 106 | opStack.push(op) 107 | } else { 108 | if (this.PRIORITY_TABLE[op.value] <= this.PRIORITY_TABLE[lastOp.value]) { 109 | this.popUntil(opStack, (token: IToken) => !token || token.value === '(', (token: IToken) => { 110 | output.push(token) 111 | }) 112 | } 113 | opStack.push(op) 114 | } 115 | } else { 116 | const factor: (Terminal | Expr) = this.parser.parseFactor() 117 | output.push(factor) 118 | if (this.parser.lookahead.type != 'operator' || this.parser.lookahead.value === '=') { 119 | break 120 | } 121 | } 122 | } 123 | //op栈出栈存入结果栈中 124 | if (opStack.length > 0) { 125 | while (opStack.length > 0) { 126 | output.push(opStack.pop()) 127 | } 128 | } 129 | return output 130 | } 131 | } -------------------------------------------------------------------------------- /dist/parser/parser.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/parser/exprParser.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "./expression"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.expressionParser = void 0; 13 | const expression_1 = require("./expression"); 14 | //表达式parser 15 | class expressionParser { 16 | constructor(parser) { 17 | this.parser = parser; 18 | //优先级序列表 19 | this.PRIORITY_TABLE = { 20 | '+': 60, 21 | '-': 60, 22 | '*': 70, 23 | '/': 70, 24 | '>=': 80, 25 | '<=': 80, 26 | '>': 80, 27 | '<': 80, 28 | '&&': 90, 29 | '||': 90, 30 | '==': 100, 31 | '!=': 100, 32 | '(': 1000, 33 | ')': 1000 34 | }; 35 | } 36 | //表达式解析方法 37 | exprParser() { 38 | if (this.parser.lookahead.value === ')') { 39 | return null; 40 | } 41 | // PreOrder : 前序 42 | // inOrder : 中序 43 | // PostOrder : 后序 44 | return this.constructAST(this.inOrderToPostOrder()); 45 | } 46 | //构建AST:abcd+*+ → ab(c+d)*+ → ab*(c+d)+ → a+b*(c+d) 47 | constructAST(postOrderOutput) { 48 | const stack = []; 49 | for (let i = 0; i < postOrderOutput.length; i++) { 50 | const current = postOrderOutput[i]; 51 | if (current.type === 'operator') { 52 | const r = stack.pop(); 53 | const l = stack.pop(); 54 | const expr = new expression_1.Expr(current.value, l, r); 55 | stack.push(expr); 56 | } 57 | else { 58 | stack.push(current); 59 | } 60 | } 61 | return stack[0]; 62 | } 63 | /** 64 | * 帮助Pop Stack直到Prediction满足 65 | * @param {*} stack 66 | * @param {Lambda} prediction 67 | * @param {*} callback 68 | */ 69 | popUntil(stack, prediction, callback) { 70 | let token = null; 71 | while (token = stack.pop()) { 72 | if (prediction(token)) { 73 | stack.push(token); 74 | break; 75 | } 76 | callback(token); 77 | } 78 | } 79 | /** 80 | * 后序遍历实现表达式优先级算法:中序表达式a+b*(c+d)的转换后序表达式abcd+*+ 81 | */ 82 | inOrderToPostOrder() { 83 | const opStack = []; 84 | const output = []; 85 | while (this.parser.lookahead.value != 'eof' && this.parser.lookahead.value !== '}') { 86 | if (this.parser.lookahead.value === '(') { 87 | opStack.push(this.parser.lookahead); 88 | this.parser.match('('); 89 | } 90 | else if (this.parser.lookahead.value === ')') { 91 | this.popUntil(opStack, (token) => token.value === '(', (token) => { 92 | output.push(token); 93 | }); 94 | const op = opStack.pop(); 95 | // 遇到没有左括号匹配的情况意味着需要停止处理 96 | if (!op || op.value !== '(') { 97 | break; 98 | } 99 | this.parser.match(')'); 100 | if (this.parser.lookahead.type != 'operator') { 101 | break; 102 | } 103 | } 104 | else if (this.parser.lookahead.type === 'operator') { 105 | const op = this.parser.lookahead; 106 | if (!(op.value in this.PRIORITY_TABLE)) { 107 | throw `An operator expected in @line ${this.parser.lookahead.lineNo} but ${this.parser.lookahead.value} found`; 108 | } 109 | this.parser.match(op.value); 110 | const lastOp = opStack[opStack.length - 1]; 111 | if (!lastOp) { // opStack是空的 112 | opStack.push(op); 113 | } 114 | else { 115 | if (this.PRIORITY_TABLE[op.value] <= this.PRIORITY_TABLE[lastOp.value]) { 116 | this.popUntil(opStack, (token) => !token || token.value === '(', (token) => { 117 | output.push(token); 118 | }); 119 | } 120 | opStack.push(op); 121 | } 122 | } 123 | else { 124 | const factor = this.parser.parseFactor(); 125 | output.push(factor); 126 | if (this.parser.lookahead.type != 'operator' || this.parser.lookahead.value === '=') { 127 | break; 128 | } 129 | } 130 | } 131 | //op栈出栈存入结果栈中 132 | if (opStack.length > 0) { 133 | while (opStack.length > 0) { 134 | output.push(opStack.pop()); 135 | } 136 | } 137 | return output; 138 | } 139 | } 140 | exports.expressionParser = expressionParser; 141 | }); 142 | //# sourceMappingURL=exprParser.js.map -------------------------------------------------------------------------------- /dist/parser/statement.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"statement.js","sourceRoot":"","sources":["../../src/parser/statement.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/tokenizer/tokenizer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../src/tokenizer/tokenizer.ts"],"names":[],"mappings":"AAAA;;GAEG;;;;;;;;;;;;;IAEH,yDAAqD;IASrD,MAAa,SAAS;QAelB,YAAY,UAAkB;YAdvB,WAAM,GAAkB,EAAE,CAAA;YACzB,cAAS,GAAW,CAAC,CAAA,CAAG,uBAAuB;YAC/C,WAAM,GAAW,CAAC,CAAA,CAAE,IAAI;YACvB,aAAQ,GAAkB;gBAC/B,KAAK;gBACL,IAAI;gBACJ,MAAM;gBACN,OAAO;gBACP,KAAK;gBACL,OAAO;gBACP,UAAU;gBACV,UAAU;gBACV,QAAQ;aACX,CAAA;YAEG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC5B,CAAC;QACD,UAAU;QACF,SAAS,CAAC,IAAY,EAAE,KAAa,EAAE,MAAe;YAC1D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;QAClC,CAAC;QACD,QAAQ;QACA,SAAS,CAAC,eAAe;YAC7B,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE;gBACf,MAAM,KAAK,GAAW,eAAe,CAAC,GAAG,IAAI,CAAC,CAAA;gBAC9C,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAA;gBACpC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;gBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC3B,CAAC,CAAA;QACL,CAAC;QACD,OAAO;QACC,OAAO,CAAC,UAAkB;YAC9B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;YAChB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;YAClB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;YACf,MAAM,eAAe,GAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YAChF,MAAM,cAAc,GAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YAC9E,MAAM,UAAU,GAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YAC5E,OAAO,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE;gBACvC,MAAM,WAAW,GAAW,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBACtD,IAAI,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;oBAC/B,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;iBAC9C;qBAAM,IAAI,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;oBACpC,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;iBAC7C;qBAAM,IAAI,WAAW,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;oBAC7C,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;iBACzC;qBAAM,IAAI,WAAW,KAAK,GAAG,IAAI,WAAW,KAAK,GAAG,EAAE;oBACnD,IAAI,CAAC,SAAS,EAAE,CAAA;oBAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;iBACtE;qBAAM,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,IAAI,EAAE;oBACrD,IAAI,CAAC,SAAS,EAAE,CAAA;oBAChB,IAAI,CAAC,MAAM,EAAE,CAAA;oBACb,SAAQ;iBACX;qBAAM,IAAI,WAAW,KAAK,GAAG,IAAI,WAAW,KAAK,IAAI,EAAE;oBACpD,IAAI,CAAC,SAAS,EAAE,CAAA;oBAChB,SAAQ;iBACX;qBAAM;oBACH,MAAM,IAAI,2BAAY,CAAC,iCAAiC,WAAW,YAAY,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;iBACjG;aACJ;QACL,CAAC;QAED,OAAO;QACC,cAAc,CAAC,UAAkB,EAAE,KAAa;YACpD,IAAI,KAAK,GAAW,CAAC,CAAA;YACrB,IAAI,GAAG,GAAW,EAAE,CAAA;YACpB,SAAS,WAAW;gBAChB,OAAO,UAAU,CAAC,KAAK,EAAE,CAAC,CAAA;YAC9B,CAAC;YACD,OAAO,IAAI,EAAE;gBACT,QAAQ,KAAK,EAAE;oBACX,KAAK,CAAC,CAAC,CAAC;wBACJ,MAAM,QAAQ,GAAW,WAAW,EAAE,CAAA;wBACtC,IAAI,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;4BAC5B,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM;4BACH,MAAM,IAAI,2BAAY,CAAC,wBAAwB,CAAC,CAAA;yBACnD;wBACD,MAAK;qBACR;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,MAAM,QAAQ,GAAW,WAAW,EAAE,CAAA;wBACtC,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;4BAC3C,GAAG,IAAI,QAAQ,CAAA;yBAClB;6BAAM;4BACH,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE;gCACjC,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;6BACxC;iCAAM;gCACH,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;6BACnC;yBACJ;wBACD,MAAK;qBACR;iBACJ;aACJ;QACL,CAAC;QAED,OAAO;QACC,aAAa,CAAC,UAAkB,EAAE,KAAa;YACnD,IAAI,KAAK,GAAW,CAAC,CAAA;YACrB,IAAI,GAAG,GAAW,EAAE,CAAA;YACpB,OAAO,IAAI,EAAE;gBACT,MAAM,QAAQ,GAAW,UAAU,CAAC,KAAK,EAAE,CAAC,CAAA;gBAC5C,QAAQ,KAAK,EAAE;oBACX,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;4BAClC,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM,IAAI,QAAQ,KAAK,GAAG,EAAE;4BACzB,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM;4BACH,MAAM,IAAI,2BAAY,CAAC,cAAc,CAAC,CAAA;yBACzC;wBACD,MAAK;qBACR;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,GAAG,IAAI,QAAQ,CAAA;yBAClB;6BAAM;4BACH,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;yBACvC;wBACD,MAAK;qBACR;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM,IAAI,QAAQ,KAAK,GAAG,EAAE;4BACzB,GAAG,IAAI,QAAQ,CAAA;4BACf,KAAK,GAAG,CAAC,CAAA;yBACZ;6BAAM;4BACH,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;yBACvC;wBACD,MAAK;qBACR;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,KAAK,GAAG,CAAC,CAAA;4BACT,GAAG,IAAI,QAAQ,CAAA;yBAClB;6BAAM;4BACH,MAAM,IAAI,2BAAY,CAAC,cAAc,CAAC,CAAA;yBACzC;qBACJ;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,KAAK,GAAG,CAAC,CAAA;4BACT,GAAG,IAAI,QAAQ,CAAA;yBAClB;6BAAM;4BACH,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;yBACvC;wBACD,MAAK;qBACR;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;4BACzB,GAAG,IAAI,QAAQ,CAAA;yBAClB;6BAAM;4BACH,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;yBACvC;qBACJ;iBACJ;aACJ;QACL,CAAC;QAED,QAAQ;QACA,eAAe,CAAC,UAAkB,EAAE,KAAa;YACrD,IAAI,KAAK,GAAW,CAAC,CAAA;YACrB,IAAI,QAAQ,GAAW,EAAE,CAAA;YACzB,OAAO,IAAI,EAAE;gBACT,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAA;gBACpC,QAAQ,IAAI,QAAQ,CAAA;gBACpB,QAAQ,KAAK,EAAE;oBACX,KAAK,CAAC,CAAC,CAAC;wBACJ,QAAQ,QAAQ,EAAE;4BACd,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG,CAAC;4BACT,KAAK,GAAG;gCACJ,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;4BAC/C,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,CAAC,CAAA;gCACT,MAAK;4BACT,KAAK,GAAG;gCACJ,KAAK,GAAG,EAAE,CAAA;gCACV,MAAK;4BACT,KAAK,GAAG,CAAC;4BACT,KAAK,GAAG,CAAC;4BACT,KAAK,GAAG;gCACJ,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;4BAC/C;gCACI,MAAM,IAAI,2BAAY,CAAC,iBAAiB,CAAC,CAAA;yBAChD;wBACD,MAAK;qBAER;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBAED,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBAEzC;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD,KAAK,CAAC,CAAC,CAAC;wBACJ,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD,KAAK,EAAE,CAAC,CAAC;wBACL,IAAI,QAAQ,KAAK,GAAG,EAAE;4BAClB,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;yBAC1C;wBACD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;qBACzC;oBACD;wBACI,MAAM,IAAI,2BAAY,CAAC,iBAAiB,CAAC,CAAA;iBAChD;aAEJ;QACL,CAAC;KACJ;IAhRD,8BAgRC"} -------------------------------------------------------------------------------- /src/parser/parser.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Tokenizer, IToken } from '../tokenizer/tokenizer' 3 | import { Stmt, DeclareStmt, Program, Function, Block, IfStmt, ReturnStmt } from './statement' 4 | import { Expr, FunctionCallExpr, AssignExpr, Args } from './expression' 5 | import { Terminal, Identifier, Numeral } from './terminal' 6 | import { expressionParser } from './exprParser' 7 | 8 | /** 9 | * 自顶部向下递归+lookahead一个token的parser 10 | * Program -> Stmts 11 | * Stmts -> Stmt Stmts | ϵ 12 | * Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ... 13 | * xxStmt -> Expr | Stmt | Terminal 14 | * Expr -> Terminal 15 | */ 16 | export class Parser { 17 | public tokens: Array //token流 18 | public lookahead: IToken //下一个token 19 | private index: number //第index个token 20 | //语法分析函数 21 | parse(sourceCode): Program { 22 | //从词法分析器拿到tokens 23 | this.tokens = new Tokenizer(sourceCode).tokens 24 | // 增加一个哨兵,用于判断结尾 25 | this.tokens.push({ type: 'eof', value: null }) 26 | this.index = 0 27 | this.lookahead = this.tokens[this.index++] 28 | const program: Program = this.parseProgram() 29 | program.buildLexicalScope() 30 | return program 31 | } 32 | 33 | //向前读一个token:封装index,避免危险操作 34 | read(): void { 35 | if (this.lookahead.type !== 'eof') { 36 | this.lookahead = this.tokens[this.index++] 37 | } 38 | } 39 | //校验token,并向前读一个 40 | match(value): string { 41 | if (this.lookahead.value === value) { 42 | this.read() 43 | return value 44 | } 45 | throw `syntax error @line ${this.lookahead.lineNo} : expect ${value} here but ${this.lookahead.value} found.` 46 | } 47 | //校验类型(静态语言),并向前读一个 48 | matchType(type): void { 49 | if (this.lookahead.type === type) { 50 | this.read() 51 | } 52 | throw 'syntax error' 53 | } 54 | //解析表达式 55 | parseExpr(): Expr | Terminal { 56 | return new expressionParser(this).exprParser() 57 | } 58 | /** 59 | * Stmts -> Stmt Stmts | ϵ 60 | */ 61 | parseStmts(): Array { 62 | const stmts = [] 63 | while (this.lookahead.type !== 'eof' && this.lookahead.value !== '}') { 64 | stmts.push(this.parseStmt()) 65 | } 66 | return stmts 67 | } 68 | 69 | /** 70 | * Program -> Stmts 71 | */ 72 | parseProgram(): Program { 73 | return new Program(this.parseStmts()) 74 | } 75 | 76 | /** 77 | * Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ... 78 | * AssignExpr -> var = Expr 79 | * IfStmt -> if Expr Block else IfStmt | if Expr Block | Stmt 80 | */ 81 | parseStmt(): Stmt | Expr | Terminal { 82 | if (this.lookahead.type === 'id' || this.lookahead.type === 'number') { 83 | return this.parseExpr() 84 | } 85 | switch (this.lookahead.value) { 86 | case 'var': 87 | return this.parseDeclareStmt() 88 | case 'function': 89 | return this.parseFunctionStmt() 90 | case 'if': 91 | return this.parseIfStmt() 92 | case 'return': 93 | return this.parseReturnStmt() 94 | default: 95 | console.log(this.lookahead) 96 | throw `syntax error @line ${this.lookahead.lineNo} : not impl. ${this.lookahead.value}` 97 | } 98 | } 99 | 100 | parseBlock(): Block { 101 | this.match('{') 102 | const stmts = this.parseStmts() 103 | this.match('}') 104 | return new Block(stmts) 105 | } 106 | 107 | 108 | 109 | 110 | /** 111 | * FunctionStmt -> function {id}(...ARGS) BLOCK 112 | */ 113 | parseFunctionStmt(): Function { 114 | this.match('function') 115 | if (this.lookahead.type !== 'id') { 116 | throw 'syntax error' 117 | } 118 | const id = this.lookahead.value 119 | this.match(id) 120 | this.match('(') 121 | const args = this.parseFuncArguments() 122 | this.match(')') 123 | const block: Block = this.parseBlock() 124 | return new Function(new Identifier(id), args, block) 125 | } 126 | 127 | /** 128 | * ReturnStmt -> return Expr 129 | */ 130 | parseReturnStmt(): ReturnStmt { 131 | this.match('return') 132 | const expr = this.parseExpr() 133 | return new ReturnStmt(expr) 134 | } 135 | 136 | /** 137 | * Args -> | ,Args | ϵ 138 | */ 139 | parseFuncArguments(): Args { 140 | let list = [] 141 | if (this.lookahead.type === 'id') { 142 | const id = this.lookahead.value 143 | this.match(id) 144 | list.push(new Identifier(id)) 145 | if (this.lookahead.value === ',') { 146 | this.match(',') 147 | list = list.concat(this.parseFuncArguments()) 148 | } 149 | } 150 | // else { 151 | // return [] 152 | // } 153 | return new Args(list, 'function') 154 | } 155 | 156 | /** 157 | * fn(args)函数调用的参数解析 158 | */ 159 | parseArguments(): Args { 160 | let list = [] 161 | let expr: Expr | Terminal = null 162 | while ((expr = this.parseExpr())) { 163 | list.push(expr) 164 | } 165 | return new Args(list) 166 | } 167 | 168 | /** 169 | * IfStmt -> if Expr Block | if Expr Block else IfStmt | if Expr Block else Block 170 | */ 171 | parseIfStmt(): IfStmt { 172 | this.match('if') 173 | const expr = this.parseExpr() 174 | const ifBlock = this.parseBlock() 175 | if (this.lookahead.value === 'else') { 176 | this.match('else') 177 | // @ts-ignore 178 | if (this.lookahead.value === 'if') { 179 | const ifStmt = this.parseIfStmt() 180 | return new IfStmt(expr, ifBlock, ifStmt) 181 | } 182 | else { 183 | const elseBlock = this.parseBlock() 184 | return new IfStmt(expr, ifBlock, null, elseBlock) 185 | } 186 | } else { 187 | return new IfStmt(expr, ifBlock) 188 | } 189 | } 190 | 191 | /** 192 | * DeclareStmt -> var id = expr 193 | */ 194 | parseDeclareStmt(): DeclareStmt { 195 | this.match('var') 196 | if (this.lookahead.type !== 'id') { 197 | throw 'syntax error' 198 | } 199 | const id = new Identifier(this.lookahead.value) 200 | this.match(this.lookahead.value) 201 | this.match('=') 202 | const right = this.parseExpr() 203 | return new DeclareStmt(id, right) 204 | } 205 | 206 | 207 | 208 | /** 209 | * factor -> number | string | id 210 | */ 211 | parseFactor(): Terminal | Expr { 212 | if (this.lookahead.type === 'number') { 213 | const value = this.match(this.lookahead.value) 214 | return new Numeral(value) 215 | } 216 | else if (this.lookahead.type === 'id') { 217 | const value = this.match(this.lookahead.value) 218 | if (this.lookahead.value === '(') { 219 | this.match('(') 220 | const args = this.parseArguments() 221 | this.match(')') 222 | return new FunctionCallExpr(new Identifier(value), args) 223 | } 224 | else if (this.lookahead.value === '=') { 225 | this.match('=') 226 | const expr = this.parseExpr() 227 | return new AssignExpr(new Identifier(value), expr) 228 | } 229 | return new Identifier(value) 230 | } else if (this.lookahead.type === 'string') { 231 | throw 'not impl.' 232 | } else { 233 | throw `syntax error, expect a factor but ${this.lookahead.value} found` 234 | } 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /src/parser/statement.ts: -------------------------------------------------------------------------------- 1 | import { Identifier, Terminal } from './terminal' 2 | import { Expr, AssignExpr, FunctionCallExpr, Args } from './expression' 3 | import { LexicalScope } from '../SDT/LexicalScope' 4 | import { ILGen } from '../SDT/ILGen' 5 | 6 | 7 | //定义陈述语言抽象类 8 | export abstract class Stmt { 9 | protected lexicalScope: LexicalScope 10 | //每个陈述语句都需要构建一次作用域 11 | buildLexicalScope(parent: LexicalScope): void { 12 | this.lexicalScope = parent 13 | } 14 | abstract print(level: number): void; 15 | abstract gen(il: ILGen, scopte: LexicalScope): void; 16 | } 17 | 18 | //声明语句 19 | export class DeclareStmt extends Stmt { 20 | constructor(private left: Identifier, private right: Expr | Terminal) { 21 | super() 22 | } 23 | 24 | buildLexicalScope(parent: LexicalScope): void { 25 | this.lexicalScope = parent 26 | this.lexicalScope.bind(this.left.value, 'number') 27 | } 28 | 29 | 30 | print(level: number): void { 31 | const pad = ''.padStart(level * 2) 32 | console.log(pad + '=') 33 | this.left.print(level + 1) 34 | this.right.print(level + 1) 35 | } 36 | 37 | gen(il: ILGen): void { 38 | let scope: LexicalScope = this.lexicalScope 39 | il.add(`declare ${scope.getLexemeName(this.left.lvalue())}`); 40 | if (this.right && (this.right).gen) { 41 | (this.right).gen(il, scope) 42 | } 43 | il.add(`${scope.getLexemeName(this.left.lvalue())}=${this.right.rvalue()}`) 44 | } 45 | } 46 | 47 | export class IfStmt extends Stmt { 48 | /** 49 | * @param {*} expr if 后面的表达式 50 | * @param {*} ifBlock if 后面的紧跟着的 Block 51 | * @param {*} elseIfStmt 如果有else if, 相当于else后面跟着的If语句 52 | * @param {*} elseBlock 如果没有else if 相当于else后面跟着的Block 53 | */ 54 | constructor(private expr: Expr | Terminal, private ifBlock: Block, private elseIfStmt?: Stmt, private elseBlock?: Block) { 55 | super() 56 | } 57 | 58 | buildLexicalScope(parent: LexicalScope): void { 59 | super.buildLexicalScope(parent); 60 | (this.expr).bindLexicalScope(this.lexicalScope) 61 | this.ifBlock.buildLexicalScope(this.lexicalScope) 62 | this.elseIfStmt && this.elseIfStmt.buildLexicalScope(this.lexicalScope) 63 | this.elseBlock && this.elseBlock.buildLexicalScope(this.lexicalScope) 64 | } 65 | 66 | print(level: number): void { 67 | const pad = ''.padStart(level * 2) 68 | console.log(pad + 'if') 69 | this.expr.print(level + 1) 70 | this.ifBlock.print() 71 | } 72 | 73 | gen(il): void { 74 | (this.expr).gen(il, this.lexicalScope) 75 | const ifCodeLine = il.add('', true) 76 | let ifBlockNextLineNo = null 77 | this.ifBlock.gen(il, this.lexicalScope) 78 | 79 | if (this.elseIfStmt) { 80 | if (!ifBlockNextLineNo) { 81 | ifBlockNextLineNo = il.current().lineno 82 | } 83 | this.elseIfStmt.gen(il, this.lexicalScope) 84 | } else if (this.elseBlock) { 85 | if (!ifBlockNextLineNo) { 86 | ifBlockNextLineNo = il.current().lineno 87 | } 88 | this.elseBlock.gen(il, this.lexicalScope) 89 | } 90 | 91 | // const nextLine = il.current().lines[ifCodeLine.lineno+1] 92 | const currentLine = il.currentLine() 93 | const l1 = il.genLabel() 94 | // il.bindLabel(nextLine.lineno, l1) 95 | il.bindLabel(currentLine.lineno + 1, l1) 96 | // currentLine.label = l2 97 | // nextLine.label = l1 98 | 99 | ifCodeLine.code = `branch ${this.expr.rvalue()} ${l1}` 100 | } 101 | } 102 | 103 | export class ReturnStmt extends Stmt { 104 | constructor(private expr) { 105 | super() 106 | this.expr = expr 107 | } 108 | 109 | buildLexicalScope(parent): void { 110 | super.buildLexicalScope(parent) 111 | this.expr.bindLexicalScope(this.lexicalScope) 112 | } 113 | 114 | print(level): void { 115 | const pad = ''.padStart(level * 2) 116 | console.log(pad + 'return') 117 | this.expr.print(level + 1) 118 | } 119 | 120 | gen(il): void { 121 | this.expr && this.expr.gen && this.expr.gen(il, this.lexicalScope) 122 | il.add(`return ${this.lexicalScope.getLexemeName(this.expr.rvalue())}`) 123 | } 124 | } 125 | 126 | export class Function extends Stmt { 127 | constructor(private id: Identifier, private args: Args, private block: Block) { 128 | super() 129 | } 130 | 131 | buildLexicalScope(parent): void { 132 | this.lexicalScope = new LexicalScope(parent, { 133 | type: 'function', 134 | argc: this.args.size() 135 | }) 136 | parent.bind(this.id.value, 'function') 137 | this.args.bindLexicalScope(this.lexicalScope) 138 | this.block.buildLexicalScope(this.lexicalScope, false) 139 | } 140 | 141 | print(level): void { 142 | const pad = ''.padStart(level * 2) 143 | console.log(pad + 'function:' + this.id) 144 | this.args.print(level + 1) 145 | // this.block.print(level + 1) 146 | this.block.print() 147 | } 148 | 149 | gen(il): void { 150 | il.add(`declare function ${this.lexicalScope.getLexemeName(this.id.lvalue())}`) 151 | il.beginSection(this.id.value + '@' + this.lexicalScope.id) 152 | il.add(`set %TOP% %SP%`) 153 | this.args.gen(il, this.lexicalScope) 154 | this.block.gen(il, this.lexicalScope) 155 | il.endSection() 156 | } 157 | } 158 | 159 | 160 | export class Block { 161 | protected lexicalScope: LexicalScope 162 | constructor(public stmts: Array) { } 163 | 164 | buildLexicalScope(parent: LexicalScope, create = true): void { 165 | if (create) { 166 | this.lexicalScope = new LexicalScope(parent) 167 | } else { 168 | this.lexicalScope = parent 169 | } 170 | 171 | this.stmts.forEach((stmt: (Stmt | Expr | Terminal)) => { 172 | if (stmt instanceof Stmt) { 173 | stmt.buildLexicalScope(this.lexicalScope) 174 | } else { 175 | (stmt).bindLexicalScope(this.lexicalScope) 176 | } 177 | }) 178 | } 179 | 180 | print(): void { 181 | for (let i = 0; i < this.stmts.length; i++) { 182 | this.stmts[i].print(0) 183 | } 184 | } 185 | gen(il: ILGen, scope: LexicalScope = this.lexicalScope): void { 186 | for (let i = 0; i < this.stmts.length; i++) { 187 | (this.stmts[i]).gen(il, scope) 188 | } 189 | } 190 | } 191 | 192 | export class Program extends Block { 193 | public ilGen: ILGen 194 | public lexicalScope: LexicalScope 195 | constructor(public stmts: Array) { 196 | super(stmts) 197 | this.ilGen = new ILGen() 198 | } 199 | 200 | registerGlobals(scope): void { 201 | scope.bind('print', 'function') 202 | } 203 | 204 | buildLexicalScope(): void { 205 | this.lexicalScope = new LexicalScope() 206 | this.registerGlobals(this.lexicalScope) 207 | this.stmts.forEach(stmt => { 208 | if (stmt instanceof Stmt) { 209 | stmt.buildLexicalScope(this.lexicalScope) 210 | } else { 211 | (stmt).bindLexicalScope(this.lexicalScope) 212 | } 213 | }) 214 | } 215 | 216 | gen(): void { 217 | this.ilGen.beginSection('main@1') 218 | this.ilGen.add('set %TOP% %SP%') 219 | for (let i = 0; i < this.stmts.length; i++) { 220 | (this.stmts[i]).gen(this.ilGen, this.lexicalScope) 221 | } 222 | this.ilGen.endSection() 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /dist/opcodeCompiler/opcodeCompiler.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"opcodeCompiler.js","sourceRoot":"","sources":["../../src/opcodeCompiler/opcodeCompiler.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/parser/statement.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../SDT/LexicalScope", "../SDT/ILGen"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Program = exports.Block = exports.Function = exports.ReturnStmt = exports.IfStmt = exports.DeclareStmt = exports.Stmt = void 0; 13 | const LexicalScope_1 = require("../SDT/LexicalScope"); 14 | const ILGen_1 = require("../SDT/ILGen"); 15 | //定义陈述语言抽象类 16 | class Stmt { 17 | //每个陈述语句都需要构建一次作用域 18 | buildLexicalScope(parent) { 19 | this.lexicalScope = parent; 20 | } 21 | } 22 | exports.Stmt = Stmt; 23 | //声明语句 24 | class DeclareStmt extends Stmt { 25 | constructor(left, right) { 26 | super(); 27 | this.left = left; 28 | this.right = right; 29 | } 30 | buildLexicalScope(parent) { 31 | this.lexicalScope = parent; 32 | this.lexicalScope.bind(this.left.value, 'number'); 33 | } 34 | print(level) { 35 | const pad = ''.padStart(level * 2); 36 | console.log(pad + '='); 37 | this.left.print(level + 1); 38 | this.right.print(level + 1); 39 | } 40 | gen(il) { 41 | let scope = this.lexicalScope; 42 | il.add(`declare ${scope.getLexemeName(this.left.lvalue())}`); 43 | if (this.right && this.right.gen) { 44 | this.right.gen(il, scope); 45 | } 46 | il.add(`${scope.getLexemeName(this.left.lvalue())}=${this.right.rvalue()}`); 47 | } 48 | } 49 | exports.DeclareStmt = DeclareStmt; 50 | class IfStmt extends Stmt { 51 | /** 52 | * @param {*} expr if 后面的表达式 53 | * @param {*} ifBlock if 后面的紧跟着的 Block 54 | * @param {*} elseIfStmt 如果有else if, 相当于else后面跟着的If语句 55 | * @param {*} elseBlock 如果没有else if 相当于else后面跟着的Block 56 | */ 57 | constructor(expr, ifBlock, elseIfStmt, elseBlock) { 58 | super(); 59 | this.expr = expr; 60 | this.ifBlock = ifBlock; 61 | this.elseIfStmt = elseIfStmt; 62 | this.elseBlock = elseBlock; 63 | } 64 | buildLexicalScope(parent) { 65 | super.buildLexicalScope(parent); 66 | this.expr.bindLexicalScope(this.lexicalScope); 67 | this.ifBlock.buildLexicalScope(this.lexicalScope); 68 | this.elseIfStmt && this.elseIfStmt.buildLexicalScope(this.lexicalScope); 69 | this.elseBlock && this.elseBlock.buildLexicalScope(this.lexicalScope); 70 | } 71 | print(level) { 72 | const pad = ''.padStart(level * 2); 73 | console.log(pad + 'if'); 74 | this.expr.print(level + 1); 75 | this.ifBlock.print(); 76 | } 77 | gen(il) { 78 | this.expr.gen(il, this.lexicalScope); 79 | const ifCodeLine = il.add('', true); 80 | let ifBlockNextLineNo = null; 81 | this.ifBlock.gen(il, this.lexicalScope); 82 | if (this.elseIfStmt) { 83 | if (!ifBlockNextLineNo) { 84 | ifBlockNextLineNo = il.current().lineno; 85 | } 86 | this.elseIfStmt.gen(il, this.lexicalScope); 87 | } 88 | else if (this.elseBlock) { 89 | if (!ifBlockNextLineNo) { 90 | ifBlockNextLineNo = il.current().lineno; 91 | } 92 | this.elseBlock.gen(il, this.lexicalScope); 93 | } 94 | // const nextLine = il.current().lines[ifCodeLine.lineno+1] 95 | const currentLine = il.currentLine(); 96 | const l1 = il.genLabel(); 97 | // il.bindLabel(nextLine.lineno, l1) 98 | il.bindLabel(currentLine.lineno + 1, l1); 99 | // currentLine.label = l2 100 | // nextLine.label = l1 101 | ifCodeLine.code = `branch ${this.expr.rvalue()} ${l1}`; 102 | } 103 | } 104 | exports.IfStmt = IfStmt; 105 | class ReturnStmt extends Stmt { 106 | constructor(expr) { 107 | super(); 108 | this.expr = expr; 109 | this.expr = expr; 110 | } 111 | buildLexicalScope(parent) { 112 | super.buildLexicalScope(parent); 113 | this.expr.bindLexicalScope(this.lexicalScope); 114 | } 115 | print(level) { 116 | const pad = ''.padStart(level * 2); 117 | console.log(pad + 'return'); 118 | this.expr.print(level + 1); 119 | } 120 | gen(il) { 121 | this.expr && this.expr.gen && this.expr.gen(il, this.lexicalScope); 122 | il.add(`return ${this.lexicalScope.getLexemeName(this.expr.rvalue())}`); 123 | } 124 | } 125 | exports.ReturnStmt = ReturnStmt; 126 | class Function extends Stmt { 127 | constructor(id, args, block) { 128 | super(); 129 | this.id = id; 130 | this.args = args; 131 | this.block = block; 132 | } 133 | buildLexicalScope(parent) { 134 | this.lexicalScope = new LexicalScope_1.LexicalScope(parent, { 135 | type: 'function', 136 | argc: this.args.size() 137 | }); 138 | parent.bind(this.id.value, 'function'); 139 | this.args.bindLexicalScope(this.lexicalScope); 140 | this.block.buildLexicalScope(this.lexicalScope, false); 141 | } 142 | print(level) { 143 | const pad = ''.padStart(level * 2); 144 | console.log(pad + 'function:' + this.id); 145 | this.args.print(level + 1); 146 | // this.block.print(level + 1) 147 | this.block.print(); 148 | } 149 | gen(il) { 150 | il.add(`declare function ${this.lexicalScope.getLexemeName(this.id.lvalue())}`); 151 | il.beginSection(this.id.value + '@' + this.lexicalScope.id); 152 | il.add(`set %TOP% %SP%`); 153 | this.args.gen(il, this.lexicalScope); 154 | this.block.gen(il, this.lexicalScope); 155 | il.endSection(); 156 | } 157 | } 158 | exports.Function = Function; 159 | class Block { 160 | constructor(stmts) { 161 | this.stmts = stmts; 162 | } 163 | buildLexicalScope(parent, create = true) { 164 | if (create) { 165 | this.lexicalScope = new LexicalScope_1.LexicalScope(parent); 166 | } 167 | else { 168 | this.lexicalScope = parent; 169 | } 170 | this.stmts.forEach((stmt) => { 171 | if (stmt instanceof Stmt) { 172 | stmt.buildLexicalScope(this.lexicalScope); 173 | } 174 | else { 175 | stmt.bindLexicalScope(this.lexicalScope); 176 | } 177 | }); 178 | } 179 | print() { 180 | for (let i = 0; i < this.stmts.length; i++) { 181 | this.stmts[i].print(0); 182 | } 183 | } 184 | gen(il, scope = this.lexicalScope) { 185 | for (let i = 0; i < this.stmts.length; i++) { 186 | this.stmts[i].gen(il, scope); 187 | } 188 | } 189 | } 190 | exports.Block = Block; 191 | class Program extends Block { 192 | constructor(stmts) { 193 | super(stmts); 194 | this.stmts = stmts; 195 | this.ilGen = new ILGen_1.ILGen(); 196 | } 197 | registerGlobals(scope) { 198 | scope.bind('print', 'function'); 199 | } 200 | buildLexicalScope() { 201 | this.lexicalScope = new LexicalScope_1.LexicalScope(); 202 | this.registerGlobals(this.lexicalScope); 203 | this.stmts.forEach(stmt => { 204 | if (stmt instanceof Stmt) { 205 | stmt.buildLexicalScope(this.lexicalScope); 206 | } 207 | else { 208 | stmt.bindLexicalScope(this.lexicalScope); 209 | } 210 | }); 211 | } 212 | gen() { 213 | this.ilGen.beginSection('main@1'); 214 | this.ilGen.add('set %TOP% %SP%'); 215 | for (let i = 0; i < this.stmts.length; i++) { 216 | this.stmts[i].gen(this.ilGen, this.lexicalScope); 217 | } 218 | this.ilGen.endSection(); 219 | } 220 | } 221 | exports.Program = Program; 222 | }); 223 | //# sourceMappingURL=statement.js.map -------------------------------------------------------------------------------- /dist/parser/parser.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports", "../tokenizer/tokenizer", "./statement", "./expression", "./terminal", "./exprParser"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.Parser = void 0; 13 | const tokenizer_1 = require("../tokenizer/tokenizer"); 14 | const statement_1 = require("./statement"); 15 | const expression_1 = require("./expression"); 16 | const terminal_1 = require("./terminal"); 17 | const exprParser_1 = require("./exprParser"); 18 | /** 19 | * 自顶部向下递归+lookahead一个token的parser 20 | * Program -> Stmts 21 | * Stmts -> Stmt Stmts | ϵ 22 | * Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ... 23 | * xxStmt -> Expr | Stmt | Terminal 24 | * Expr -> Terminal 25 | */ 26 | class Parser { 27 | //语法分析函数 28 | parse(sourceCode) { 29 | //从词法分析器拿到tokens 30 | this.tokens = new tokenizer_1.Tokenizer(sourceCode).tokens; 31 | // 增加一个哨兵,用于判断结尾 32 | this.tokens.push({ type: 'eof', value: null }); 33 | this.index = 0; 34 | this.lookahead = this.tokens[this.index++]; 35 | const program = this.parseProgram(); 36 | program.buildLexicalScope(); 37 | return program; 38 | } 39 | //向前读一个token:封装index,避免危险操作 40 | read() { 41 | if (this.lookahead.type !== 'eof') { 42 | this.lookahead = this.tokens[this.index++]; 43 | } 44 | } 45 | //校验token,并向前读一个 46 | match(value) { 47 | if (this.lookahead.value === value) { 48 | this.read(); 49 | return value; 50 | } 51 | throw `syntax error @line ${this.lookahead.lineNo} : expect ${value} here but ${this.lookahead.value} found.`; 52 | } 53 | //校验类型(静态语言),并向前读一个 54 | matchType(type) { 55 | if (this.lookahead.type === type) { 56 | this.read(); 57 | } 58 | throw 'syntax error'; 59 | } 60 | //解析表达式 61 | parseExpr() { 62 | return new exprParser_1.expressionParser(this).exprParser(); 63 | } 64 | /** 65 | * Stmts -> Stmt Stmts | ϵ 66 | */ 67 | parseStmts() { 68 | const stmts = []; 69 | while (this.lookahead.type !== 'eof' && this.lookahead.value !== '}') { 70 | stmts.push(this.parseStmt()); 71 | } 72 | return stmts; 73 | } 74 | /** 75 | * Program -> Stmts 76 | */ 77 | parseProgram() { 78 | return new statement_1.Program(this.parseStmts()); 79 | } 80 | /** 81 | * Stmt -> AssignExpr | IfStmt | WhileStmt | Function | Block | ... 82 | * AssignExpr -> var = Expr 83 | * IfStmt -> if Expr Block else IfStmt | if Expr Block | Stmt 84 | */ 85 | parseStmt() { 86 | if (this.lookahead.type === 'id' || this.lookahead.type === 'number') { 87 | return this.parseExpr(); 88 | } 89 | switch (this.lookahead.value) { 90 | case 'var': 91 | return this.parseDeclareStmt(); 92 | case 'function': 93 | return this.parseFunctionStmt(); 94 | case 'if': 95 | return this.parseIfStmt(); 96 | case 'return': 97 | return this.parseReturnStmt(); 98 | default: 99 | console.log(this.lookahead); 100 | throw `syntax error @line ${this.lookahead.lineNo} : not impl. ${this.lookahead.value}`; 101 | } 102 | } 103 | parseBlock() { 104 | this.match('{'); 105 | const stmts = this.parseStmts(); 106 | this.match('}'); 107 | return new statement_1.Block(stmts); 108 | } 109 | /** 110 | * FunctionStmt -> function {id}(...ARGS) BLOCK 111 | */ 112 | parseFunctionStmt() { 113 | this.match('function'); 114 | if (this.lookahead.type !== 'id') { 115 | throw 'syntax error'; 116 | } 117 | const id = this.lookahead.value; 118 | this.match(id); 119 | this.match('('); 120 | const args = this.parseFuncArguments(); 121 | this.match(')'); 122 | const block = this.parseBlock(); 123 | return new statement_1.Function(new terminal_1.Identifier(id), args, block); 124 | } 125 | /** 126 | * ReturnStmt -> return Expr 127 | */ 128 | parseReturnStmt() { 129 | this.match('return'); 130 | const expr = this.parseExpr(); 131 | return new statement_1.ReturnStmt(expr); 132 | } 133 | /** 134 | * Args -> | ,Args | ϵ 135 | */ 136 | parseFuncArguments() { 137 | let list = []; 138 | if (this.lookahead.type === 'id') { 139 | const id = this.lookahead.value; 140 | this.match(id); 141 | list.push(new terminal_1.Identifier(id)); 142 | if (this.lookahead.value === ',') { 143 | this.match(','); 144 | list = list.concat(this.parseFuncArguments()); 145 | } 146 | } 147 | // else { 148 | // return [] 149 | // } 150 | return new expression_1.Args(list, 'function'); 151 | } 152 | /** 153 | * fn(args)函数调用的参数解析 154 | */ 155 | parseArguments() { 156 | let list = []; 157 | let expr = null; 158 | while ((expr = this.parseExpr())) { 159 | list.push(expr); 160 | } 161 | return new expression_1.Args(list); 162 | } 163 | /** 164 | * IfStmt -> if Expr Block | if Expr Block else IfStmt | if Expr Block else Block 165 | */ 166 | parseIfStmt() { 167 | this.match('if'); 168 | const expr = this.parseExpr(); 169 | const ifBlock = this.parseBlock(); 170 | if (this.lookahead.value === 'else') { 171 | this.match('else'); 172 | // @ts-ignore 173 | if (this.lookahead.value === 'if') { 174 | const ifStmt = this.parseIfStmt(); 175 | return new statement_1.IfStmt(expr, ifBlock, ifStmt); 176 | } 177 | else { 178 | const elseBlock = this.parseBlock(); 179 | return new statement_1.IfStmt(expr, ifBlock, null, elseBlock); 180 | } 181 | } 182 | else { 183 | return new statement_1.IfStmt(expr, ifBlock); 184 | } 185 | } 186 | /** 187 | * DeclareStmt -> var id = expr 188 | */ 189 | parseDeclareStmt() { 190 | this.match('var'); 191 | if (this.lookahead.type !== 'id') { 192 | throw 'syntax error'; 193 | } 194 | const id = new terminal_1.Identifier(this.lookahead.value); 195 | this.match(this.lookahead.value); 196 | this.match('='); 197 | const right = this.parseExpr(); 198 | return new statement_1.DeclareStmt(id, right); 199 | } 200 | /** 201 | * factor -> number | string | id 202 | */ 203 | parseFactor() { 204 | if (this.lookahead.type === 'number') { 205 | const value = this.match(this.lookahead.value); 206 | return new terminal_1.Numeral(value); 207 | } 208 | else if (this.lookahead.type === 'id') { 209 | const value = this.match(this.lookahead.value); 210 | if (this.lookahead.value === '(') { 211 | this.match('('); 212 | const args = this.parseArguments(); 213 | this.match(')'); 214 | return new expression_1.FunctionCallExpr(new terminal_1.Identifier(value), args); 215 | } 216 | else if (this.lookahead.value === '=') { 217 | this.match('='); 218 | const expr = this.parseExpr(); 219 | return new expression_1.AssignExpr(new terminal_1.Identifier(value), expr); 220 | } 221 | return new terminal_1.Identifier(value); 222 | } 223 | else if (this.lookahead.type === 'string') { 224 | throw 'not impl.'; 225 | } 226 | else { 227 | throw `syntax error, expect a factor but ${this.lookahead.value} found`; 228 | } 229 | } 230 | } 231 | exports.Parser = Parser; 232 | }); 233 | //# sourceMappingURL=parser.js.map -------------------------------------------------------------------------------- /src/opcodeCompiler/opcodeCompiler.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export class OpcodeCompiler { 4 | private lines: Array //opcode机器码列表 5 | private symbolTable: SymbolTable //对应的符号表 6 | constructor() { } 7 | 8 | //通过寄存器+偏移量寻址 9 | private offset(register: string, lexeme: ITable, argc: number = 0): string { 10 | if (lexeme.index < argc) { 11 | return `${register}+${4 * (argc - lexeme.index + 1)}` 12 | } else if (lexeme.index > argc) { 13 | return `${register}-${4 * (lexeme.index - 1)}` 14 | } else { 15 | return `${register}` 16 | } 17 | } 18 | 19 | //获取地址 20 | private addr(curScope: SymbolTable, x: string, register = 'R0'): string { 21 | // 数字 22 | if (x[0].match(/[0-9]/)) { 23 | return '#' + x 24 | } 25 | //消除% 26 | else if (x.indexOf('%') !== -1) { 27 | return x.replace(/%/g, '') 28 | } 29 | // 30 | else { 31 | // const argc = currentScop 32 | // console.log(curScope, curScope.children[0].table) 33 | const argc = curScope.type === 'function' ? curScope.argc : 0 34 | const lexeme = curScope.find(x) 35 | // 分case讨论 36 | // case1: 变量在当前作用域 37 | // case2:变量不在当前作用域 38 | // case3: 当前作用域是变量作用域的子节点 39 | // case4: 当前作用域不是变量作用域的子节点 40 | if (curScope.id === lexeme.scopeId) { 41 | return `${this.offset('TOP', lexeme, argc)}` 42 | } else { 43 | if (curScope.isParent(lexeme.scopeId)) { 44 | const levelDiff = curScope.level - lexeme.level 45 | this.lines.push(`mov TOP ${register}`) 46 | for (let i = 0; i < levelDiff; i++) { 47 | this.lines.push(`mov @${register} ${register}`) 48 | } 49 | this.lines.push(`mov ${this.offset(register, lexeme, argc)} ${register}`) 50 | } else { 51 | // 这种情况下TOP肯定指向父作用域 52 | this.lines.push(`mov TOP ${register}`) 53 | this.lines.push(`mov @${register} ${register}`) 54 | this.lines.push(`mov ${this.offset(register, lexeme, argc)} ${register}`) 55 | } 56 | } 57 | } 58 | } 59 | //翻译Pass 60 | private translatePass(curScope: SymbolTable, params: Array): void { 61 | const v = params[0] 62 | this.lines.push(`push ${this.addr(curScope, v, 'TOP')}`) 63 | } 64 | 65 | //翻译Branch 66 | private translateBranch(curScope: SymbolTable, params: Array): void { 67 | const v = params[0] 68 | const lb1 = params[1] 69 | this.lines.push(`jz ${lb1}`) 70 | } 71 | //翻译Call 72 | private translateCall(curScope: SymbolTable, params: Array): void { 73 | const func = params[0] 74 | this.lines.push(`push PC`) 75 | this.lines.push(`jump ${func}`) 76 | } 77 | //翻译set 78 | private translateSet(curScope: SymbolTable, params: Array): void { 79 | const assignee: string = params[0] //临时变量 80 | const op: string = params[2]//操作符 81 | const l: string = params[1] //左值 82 | const r: string = params[3]//右值 83 | //存在操作符时 84 | if (op) { 85 | //拿到左值的地址 86 | const a = this.addr(curScope, l, 'R0') 87 | //拿到右值的地址 88 | const b = this.addr(curScope, r, 'R1') 89 | switch (op) { 90 | case "==": { 91 | this.lines.push(`cmp ${a} ${b}`) 92 | this.lines.push(`mov ZF ${this.addr(curScope, assignee, 'TOP')}`) 93 | break 94 | } 95 | case "||": { 96 | this.lines.push(`mov ${a} R0`) 97 | this.lines.push(`or R0 ${b}`) 98 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`) 99 | break 100 | } 101 | case '-': { 102 | this.lines.push(`mov ${a} R0`) 103 | this.lines.push(`sub R0 ${b}`) 104 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`) 105 | break 106 | } 107 | case '+': { 108 | this.lines.push(`mov ${a} R0`) 109 | this.lines.push(`add R0 ${b}`) 110 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`) 111 | } 112 | } 113 | } else { 114 | const a: string = this.addr(curScope, assignee, 'R0') 115 | const b: string = this.addr(curScope, l, 'R1') 116 | this.lines.push(`mov ${b} ${a}`) 117 | if (assignee.indexOf('%') === -1) { 118 | this.lines.push(`sub #-4 SP`) 119 | } 120 | } 121 | } 122 | 123 | //根据中间码和词法作用域符号表解析出opcode 124 | public parse(sourceCode: string, symbols: ISymbols): void { 125 | this.lines = [] //初始化结果列表 126 | this.symbolTable = new SymbolTable(symbols) //创建符号表 127 | const ilLines: Array = sourceCode.split('\n') //将每行中间码数据拆成单个数组元素 128 | let sectionScope: SymbolTable = null //当前section作用域下的符号表 129 | //逐条解析单个三地址码 130 | for (let iline of ilLines) { 131 | if (iline.trim()) { 132 | let label = '' 133 | if (iline.indexOf(':') !== -1) { 134 | [label, iline] = iline.split(':') 135 | } 136 | const prts: Array = iline.split(' ').filter(x => x) 137 | /** 138 | * codeName:指令名称 139 | * params:指令参数列表 140 | */ 141 | const [codeName, ...params] = prts 142 | switch (codeName) { 143 | case 'section': { 144 | const [name, id] = params[0].split('@') 145 | sectionScope = this.symbolTable.findScope(id) 146 | break 147 | } 148 | case 'set': { 149 | this.translateSet(sectionScope, params) 150 | break 151 | } 152 | case 'branch': { 153 | this.translateBranch(sectionScope, params) 154 | break 155 | } 156 | case 'pass': { 157 | this.translatePass(sectionScope, params) 158 | break 159 | } 160 | case 'call': { 161 | this.translateCall(sectionScope, params) 162 | break 163 | } 164 | } 165 | } 166 | } 167 | } 168 | 169 | public print(): void { 170 | for (let line of this.lines) { 171 | console.log(line) 172 | } 173 | } 174 | } 175 | 176 | //词法作用域关键信息符号表 177 | interface ISymbols { 178 | id: number 179 | table: object 180 | children: Array 181 | type?: string 182 | argc?: number 183 | } 184 | //全局hash,存放各级符号表 185 | interface IHash { 186 | id?: SymbolTable 187 | } 188 | //本级符号表 189 | interface ITable { 190 | index: number //在table中的索引位置 191 | level: number //层级 192 | scopeId: number //作用域ID 193 | type: string //数据类型 194 | } 195 | //关联各个作用域符号表的符号表汇总 196 | class SymbolTable { 197 | private hash: IHash //全局hash,存放各级符号表 198 | private table: ITable //本级符号表 199 | public children: Array //子符号表 200 | public id: number //本级符号表id 201 | public type: string //类型 202 | public argc: number //type为function时,参数个数 203 | constructor(private symbols: ISymbols, private parent?: SymbolTable, public level: number = 0) { 204 | if (this.level === 0) { 205 | this.hash = {} 206 | } 207 | if (this.parent) { 208 | this.hash = this.parent.hash 209 | } 210 | for (let key in this.symbols) { 211 | this[key] = this.symbols[key] 212 | } 213 | this.hash[this.id] = this 214 | //本机符号表中补充层级和作用域信息 215 | for (let key in this.table) { 216 | this.table[key].level = this.level 217 | this.table[key].scopeId = this.id 218 | } 219 | //子符号表 220 | this.children = symbols.children ? symbols.children.map(x => new SymbolTable(x, this, level + 1)) : null 221 | } 222 | 223 | //根据id寻找符号表 224 | findScope(id): SymbolTable { 225 | return this.hash[id] 226 | } 227 | //根据id查找详情信息 228 | find(id) { 229 | //判断id是否带作用域 230 | if (id.indexOf('@') !== -1) { 231 | const [vid, scopeId] = id.split('@') 232 | const scope = this.hash[scopeId] 233 | return scope.table[vid] 234 | } else { 235 | //判断本级符号表是否存在id,没有的话则去父表中找 236 | if (this.table[id]) { 237 | return this.table[id] 238 | } 239 | return this.parent.find(id) 240 | } 241 | } 242 | //判断当前符号表是不是scopeId表的父表 243 | isParent(scopeId: string): boolean { 244 | if (this.findScope(scopeId).parent.id === this.id) { 245 | return true 246 | } else { 247 | return false 248 | } 249 | } 250 | } -------------------------------------------------------------------------------- /dist/opcodeCompiler/opcodeCompiler.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof module === "object" && typeof module.exports === "object") { 3 | var v = factory(require, exports); 4 | if (v !== undefined) module.exports = v; 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | define(["require", "exports"], factory); 8 | } 9 | })(function (require, exports) { 10 | "use strict"; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.OpcodeCompiler = void 0; 13 | class OpcodeCompiler { 14 | constructor() { } 15 | //通过寄存器+偏移量寻址 16 | offset(register, lexeme, argc = 0) { 17 | if (lexeme.index < argc) { 18 | return `${register}+${4 * (argc - lexeme.index + 1)}`; 19 | } 20 | else if (lexeme.index > argc) { 21 | return `${register}-${4 * (lexeme.index - 1)}`; 22 | } 23 | else { 24 | return `${register}`; 25 | } 26 | } 27 | //获取地址 28 | addr(curScope, x, register = 'R0') { 29 | // 数字 30 | if (x[0].match(/[0-9]/)) { 31 | return '#' + x; 32 | } 33 | //消除% 34 | else if (x.indexOf('%') !== -1) { 35 | return x.replace(/%/g, ''); 36 | } 37 | // 38 | else { 39 | // const argc = currentScop 40 | // console.log(curScope, curScope.children[0].table) 41 | const argc = curScope.type === 'function' ? curScope.argc : 0; 42 | const lexeme = curScope.find(x); 43 | // 分case讨论 44 | // case1: 变量在当前作用域 45 | // case2:变量不在当前作用域 46 | // case3: 当前作用域是变量作用域的子节点 47 | // case4: 当前作用域不是变量作用域的子节点 48 | if (curScope.id === lexeme.scopeId) { 49 | return `${this.offset('TOP', lexeme, argc)}`; 50 | } 51 | else { 52 | if (curScope.isParent(lexeme.scopeId)) { 53 | const levelDiff = curScope.level - lexeme.level; 54 | this.lines.push(`mov TOP ${register}`); 55 | for (let i = 0; i < levelDiff; i++) { 56 | this.lines.push(`mov @${register} ${register}`); 57 | } 58 | this.lines.push(`mov ${this.offset(register, lexeme, argc)} ${register}`); 59 | } 60 | else { 61 | // 这种情况下TOP肯定指向父作用域 62 | this.lines.push(`mov TOP ${register}`); 63 | this.lines.push(`mov @${register} ${register}`); 64 | this.lines.push(`mov ${this.offset(register, lexeme, argc)} ${register}`); 65 | } 66 | } 67 | } 68 | } 69 | //翻译Pass 70 | translatePass(curScope, params) { 71 | const v = params[0]; 72 | this.lines.push(`push ${this.addr(curScope, v, 'TOP')}`); 73 | } 74 | //翻译Branch 75 | translateBranch(curScope, params) { 76 | const v = params[0]; 77 | const lb1 = params[1]; 78 | this.lines.push(`jz ${lb1}`); 79 | } 80 | //翻译Call 81 | translateCall(curScope, params) { 82 | const func = params[0]; 83 | this.lines.push(`push PC`); 84 | this.lines.push(`jump ${func}`); 85 | } 86 | //翻译set 87 | translateSet(curScope, params) { 88 | const assignee = params[0]; //临时变量 89 | const op = params[2]; //操作符 90 | const l = params[1]; //左值 91 | const r = params[3]; //右值 92 | //存在操作符时 93 | if (op) { 94 | //拿到左值的地址 95 | const a = this.addr(curScope, l, 'R0'); 96 | //拿到右值的地址 97 | const b = this.addr(curScope, r, 'R1'); 98 | switch (op) { 99 | case "==": { 100 | this.lines.push(`cmp ${a} ${b}`); 101 | this.lines.push(`mov ZF ${this.addr(curScope, assignee, 'TOP')}`); 102 | break; 103 | } 104 | case "||": { 105 | this.lines.push(`mov ${a} R0`); 106 | this.lines.push(`or R0 ${b}`); 107 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`); 108 | break; 109 | } 110 | case '-': { 111 | this.lines.push(`mov ${a} R0`); 112 | this.lines.push(`sub R0 ${b}`); 113 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`); 114 | break; 115 | } 116 | case '+': { 117 | this.lines.push(`mov ${a} R0`); 118 | this.lines.push(`add R0 ${b}`); 119 | this.lines.push(`mov R0 ${this.addr(curScope, assignee, 'TOP')}`); 120 | } 121 | } 122 | } 123 | else { 124 | const a = this.addr(curScope, assignee, 'R0'); 125 | const b = this.addr(curScope, l, 'R1'); 126 | this.lines.push(`mov ${b} ${a}`); 127 | if (assignee.indexOf('%') === -1) { 128 | this.lines.push(`sub #-4 SP`); 129 | } 130 | } 131 | } 132 | //根据中间码和词法作用域符号表解析出opcode 133 | parse(sourceCode, symbols) { 134 | this.lines = []; //初始化结果列表 135 | this.symbolTable = new SymbolTable(symbols); //创建符号表 136 | const ilLines = sourceCode.split('\n'); //将每行中间码数据拆成单个数组元素 137 | let sectionScope = null; //当前section作用域下的符号表 138 | //逐条解析单个三地址码 139 | for (let iline of ilLines) { 140 | if (iline.trim()) { 141 | let label = ''; 142 | if (iline.indexOf(':') !== -1) { 143 | [label, iline] = iline.split(':'); 144 | } 145 | const prts = iline.split(' ').filter(x => x); 146 | /** 147 | * codeName:指令名称 148 | * params:指令参数列表 149 | */ 150 | const [codeName, ...params] = prts; 151 | switch (codeName) { 152 | case 'section': { 153 | const [name, id] = params[0].split('@'); 154 | sectionScope = this.symbolTable.findScope(id); 155 | break; 156 | } 157 | case 'set': { 158 | this.translateSet(sectionScope, params); 159 | break; 160 | } 161 | case 'branch': { 162 | this.translateBranch(sectionScope, params); 163 | break; 164 | } 165 | case 'pass': { 166 | this.translatePass(sectionScope, params); 167 | break; 168 | } 169 | case 'call': { 170 | this.translateCall(sectionScope, params); 171 | break; 172 | } 173 | } 174 | } 175 | } 176 | } 177 | print() { 178 | for (let line of this.lines) { 179 | console.log(line); 180 | } 181 | } 182 | } 183 | exports.OpcodeCompiler = OpcodeCompiler; 184 | //关联各个作用域符号表的符号表汇总 185 | class SymbolTable { 186 | constructor(symbols, parent, level = 0) { 187 | this.symbols = symbols; 188 | this.parent = parent; 189 | this.level = level; 190 | if (this.level === 0) { 191 | this.hash = {}; 192 | } 193 | if (this.parent) { 194 | this.hash = this.parent.hash; 195 | } 196 | for (let key in this.symbols) { 197 | this[key] = this.symbols[key]; 198 | } 199 | this.hash[this.id] = this; 200 | //本机符号表中补充层级和作用域信息 201 | for (let key in this.table) { 202 | this.table[key].level = this.level; 203 | this.table[key].scopeId = this.id; 204 | } 205 | //子符号表 206 | this.children = symbols.children ? symbols.children.map(x => new SymbolTable(x, this, level + 1)) : null; 207 | } 208 | //根据id寻找符号表 209 | findScope(id) { 210 | return this.hash[id]; 211 | } 212 | //根据id查找详情信息 213 | find(id) { 214 | //判断id是否带作用域 215 | if (id.indexOf('@') !== -1) { 216 | const [vid, scopeId] = id.split('@'); 217 | const scope = this.hash[scopeId]; 218 | return scope.table[vid]; 219 | } 220 | else { 221 | //判断本级符号表是否存在id,没有的话则去父表中找 222 | if (this.table[id]) { 223 | return this.table[id]; 224 | } 225 | return this.parent.find(id); 226 | } 227 | } 228 | //判断当前符号表是不是scopeId表的父表 229 | isParent(scopeId) { 230 | if (this.findScope(scopeId).parent.id === this.id) { 231 | return true; 232 | } 233 | else { 234 | return false; 235 | } 236 | } 237 | } 238 | }); 239 | //# sourceMappingURL=opcodeCompiler.js.map -------------------------------------------------------------------------------- /04_运行时刻环境/README.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | *前言: 4 | 从词法分析,到语法分析,到三地址代码生成,这个几个阶段的本质还只是对字符串的转换,是静态编译阶段。而运行时指的是程序执行顺序、执行环境、内存动态分配等内容。 5 | 运行时刻跟编译时刻虽然是两个不同的阶段,但是由于运行时刻用到的指令是由编译器生成的,要使编译器生成正确指令,必需对程序运行时有足够的了解。如此才能解决在前面一节《03_中间代码生成》的三地址表达式实例2中提出的问题,才能生成能够精确翻译为机器码的中间码。 6 | 总而言之,要使机器码执行时符合ECMA-262标准(https://www.ecma-international.org/publications-and-standards/standards/ecma-262/),就必须先了解该标准,并想法设法使生成的线性代码在运行时符合该标准。 7 | 8 | 9 | *运行存储分配: 10 | ·操作系统对内存的划分: 11 | -- 操作系统给内存进行规划,将内存大概分成操作系统内核内存和给程序员使用的内存2大部分 12 | -- 这样的好处是:操作系统的内存不会被大量占用,避免机器卡住、卡死、死机等状态,可通过操作系统把应用程序关闭,使得操作系统更安全 13 | ·程序运行存储分配策略: 14 | -- 静态存储分配: 15 | -- 数据对象大小确定,编译器在编译时刻就可以做出存储分配决定,不需要考虑程序运行时刻的情形 16 | -- 例如全局常量、全局变量就可以采用静态存储分配 17 | -- 这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求 18 | -- 常用的静态存储分配方法: 19 | -- 顺序分配法: 20 | 假设一个程序生成了6个过程,树表示过程间的调用关系: 21 | 1/22 22 | / \ 23 | 2/15 3/18 24 | / \ / \ 25 | 4/17 6/10 5/23 26 | 过程 存储区域 27 | 1 0~21 28 | 2 22~36 29 | 3 37~54 30 | 4 55~71 31 | 5 72~94 32 | 6 95~104 33 | 特点:按照过程出现的先后顺序逐段分配存储空间;各过程的活动记录占用互不相交的存储空间 34 | 优点:处理上简单 35 | 缺点:对内存空间的使用不够经济合理 36 | -- 层次分配法:https://www.pianshen.com/article/13011737518/ 37 | -- 实现静态存储分配: 38 | -- 编译程序对源程序进行处理时,对每个变量在符号表中创建一个记录,保存该变量的属性,其中包括为变量分配的存储空间地址即目标地址 39 | -- 由于每个变量需要的空间大小已知,则可将数据区开始位置的地址A分配给第一个变量,设第一个变量占n1个字节,则A + n1分配给第二个变量。同理,A + n1 + n2分配给第三个变量等等 40 | -- 静态存储分配把内存看成一个一维数组。 编译时分配存储单元,运行时才被占用 。一旦分配,运行期间就一直被某个变量占用 41 | -- 目标地址可以是绝对地址,也可以是相对地址 42 | -- 开始如果编写的编译程序是用于单任务环境,那么,通常采用绝对地址作为目标地址。 程序和数据区 (开始地址A) 可以放在操作系统的长驻区以外的存储区中 43 | -- 如果编译程序是在多任务环境中,那么目标地址可采用相对地址,也就是相对于程序数据区的基地址。加载器通过设置一个寄存器,并将数据区的头地址送入该寄存器内以完成数据区的定位 44 | -- 动态存储分配: 45 | -- 数据对象大小不确定,在运行时才能进行内存分配 46 | -- 分为栈式和堆式2种: 47 | -- 栈式存储分配:用后进先出(LIFO)的动态分配预留的内存空间 48 | -- 堆式存储分配:没有固定模式的动态分配预留的内存空间 49 | ·常见语言的运行存储分配策略: 50 | -- 早期的FORTRAN语言及COBOL语言等,其存储分配是完全静态的,程序的数据对象与其存储的绑定是在编译期间进行的。而 51 | -- 另一些语言,所有数据对象与其存储的绑定只能发生在运行期间,完全采用动态存储分配,如Lisp、ML、Perl等。 52 | -- 多数语言(如Js、C/C++、Java、Pascal等)采取的存储分配策略是结合静态和动态两者的 53 | ·栈内存和堆内存的本质区别: 54 | -- 栈内存和堆内存在物理上都是一样的,都是物理内存的一部分,只不过是操作系统根据程序运行特点将虚拟内存进行了抽象分类 55 | -- 操作系统为何要将内存分为栈内存和堆内存呢? 56 | -- 栈是函数调用最方便的实现方式:在汇编里,变量的概念几乎没有了,有的只是各种内存地址,不管是实地址还是虚地址,你访问一个变量就是靠地址,所以如果你不记住一个变量的地址,你就没办法去操作它,这就产生了问题,如果你的程序要1000个变量,你就把他们的地址全记下来吗?这显然是不现实的,首先这会浪费很多空间,因为几乎任何操作都离不开操作变量,也就是地址,那么就相当于你要用两倍甚至更多的空间来表示你的程序,而一半浪费在地址上,其次这样写程序也是没有效率的,1000个变量,难道你能把他们的地址全背下来吗?或者说当你看到地址0x1234的值赋值给地址0x2345时,你如何记得起0x1234和0x2345是两个干什么用的变量?所以以一种系统的方法管理内存就显得尤为重要。而栈具有先进后出和内存连续性的特点,能够很好的描述函数运行时的状态,并且通过指针偏移方便计算出变量的内存位置。 57 | -- 因为结构化语言里函数调用最方便的实现方式就是用栈,以至于现在绝大部分芯片都对栈提供芯片级的硬件支持,一条指令即可搞定栈的pop操作。栈的好处是:方便、快、有效避免内存碎片化。栈的问题是:不利于管理大内存(尤其在16位和32位时代)、数据的生命周期难于控制(栈内的有效数据通常是连续存储的,所以pop时后申请的内存必须早于先申请的内存失效),所以栈不利于动态地管理并且有效地利用宝贵的内存资源。于是我们有了堆 58 | -- 从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。 59 | -- 堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。 60 | -- 栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。 61 | -- 出于程序运行特点,操作系统对堆和栈做了划分,并使其具备各自特点: 62 | -- Stack: 63 | -- 和堆一样存储在计算机RAM中 64 | -- 在栈上创建变量的时候会扩展,并且会自动回收 65 | -- 相比堆而言在栈上分配要快的多 66 | -- 用数据结构中的栈实现 67 | -- 存储局部数据,返回地址,用做参数传递 68 | -- 当用栈过多时可导致栈溢出(无穷次(大量的)的递归调用,或者大量的内存分配) 69 | -- 在栈上的数据可以直接访问(不是非要使用指针访问) 70 | -- 如果你在编译之前精确的知道你需要分配数据的大小并且不是太大的时候,可以使用栈 71 | -- 当你程序启动时决定栈的容量上限 72 | -- Heap: 73 | -- 和栈一样存储在计算机RAM 74 | -- 在堆上的变量必须要手动释放,不存在作用域的问题 75 | -- 相比在栈上分配内存要慢 76 | -- 通过程序按需分配 77 | -- 大量的分配和释放可造成内存碎片 78 | -- 在C++中,在堆上创建数的据使用指针访问,用new或者malloc分配内存;JS中,自带垃圾回收器进行堆对象回收 79 | -- 如果申请的缓冲区过大的话,可能申请失败 80 | -- 在运行期间你不知道会需要多大的数据或者你需要分配大量的内存的时候,建议你使用堆 81 | -- 可能造成内存泄露 82 | ·对于支持递归进程的内存具体规划,从低位到高位分别是:可参考图《递归语言的运行时内存划分.jpg》 83 | -- 代码段(文本段):函数编译成opcode(二进制)后存到磁盘,运行时将二进制从磁盘加载到内存中 84 | -- 数据段(静态空间):全局变量、常量、静态变量存数据段 85 | -- 堆:比栈内存大得多,一般有几G大小 86 | -- 自由可分配内存:运行时逐渐被堆栈占据,运行完后数据释放空间恢复 87 | -- 栈:第一个函数运行时压入栈底,函数调新函数时再往栈里压入该新函数,新函数运行完即出栈,第一个函数运行完再出栈,栈为空 88 | -- 内核:内核区是所有进程共享的 89 | 90 | 91 | 92 | *栈式存储分配: 93 | ·活动记录 94 | -- 使用过程(或函数、方法)作为用户自定义动作的单元的语言,其编译器通常以过程为单位分配存储空间 95 | -- 活动:activation,过程体的每次执行称为该过程的一个活动 96 | -- 过程每执行一次,就为它分配一块连续存储区,用来管理过程一次执行所需的信息,这块连续存储区称为活动记录 97 | ·栈式存储分配特点: 98 | -- 当一个过程被调用时,该过程的活动记录被压入栈;当过程结束时,该活动记录被弹出栈。 99 | -- 栈式存储不仅允许活跃时段不交叠的多个过程调用之间共享空间,而且允许以如下方式为一个过程编译代码:它的非局部变量的相对地址总是固定的 100 | ·寄存器与函数栈帧 101 | -- 栈帧:函数调用经常是嵌套的,在同一时刻,堆栈中会有多个函数的信息。每个未完成运行的函数占用一个独立的连续区域,称作栈帧(Stack Frame) 102 | -- 每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。Win32系统提供两个特殊的寄存器用于标识位于系统栈顶端的栈帧。 103 | -- ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶,当我们往栈内添加数据时,ESP就会往上移动该数据的大小。 104 | -- EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部 105 | -- 图例:《寄存器对栈的标识作用.png》 106 | ·嵌套函数在栈中的调用过程:当函数A执行到第2行时,开始运行函数B,此时A停止开始运行B,并向系统栈中压入A2(表示函数A的第2行),当B执行到第2行时开始运行函数C,并在系统栈中压入B2,当C运行完时再查看系统栈,发现了B2,系统开始继续执行B的第2行,B执行完后查看系统栈,发现A2,则继续执行A直到完成。 107 | ·JavaScript的语言特点: 108 | -- 函数允许嵌套、支持递归 109 | -- 传参:所有函数的参数都是按值传递的,也就是说把函数外部的值复制给函数内部的参数 110 | 例子1: 111 | var person = { 112 | name : "Tom" 113 | }; 114 | function obj(peo){ 115 | peo.name = "Jerry"; 116 | return peo; 117 | } 118 | var result = obj(person); 119 | console.log(result.name);// Jerry 120 | console.log(person.name);// Jerry 121 | 例子2: 122 | var person = { 123 | name : "Tom" 124 | }; 125 | function obj(peo){ 126 | peo = { 127 | name : "Jerry" 128 | }; 129 | return peo; 130 | } 131 | var result = obj(person); 132 | console.log(result.name);// Jerry 133 | console.log(person.name);// Tom 134 | -- 遵循静态作用域 135 | 所谓的词法作用域其实是指作用域在词法解析阶段既确定了,不会改变。例子: 136 | var foo=1; 137 | function static(){ 138 | alert(foo); 139 | } 140 | !function(){ 141 | var foo=2; 142 | static(); 143 | }(); 144 | 在js中,会弹出1而非2,因为static的scope在创建时,记录的foo是1。如果js是动态作用域,那么他应该弹出2 145 | -- 数据类型: 146 | -- 基本类型:基本数据类型都储存在栈中 147 | -- 引用类型:引用类型的值是储存在堆中,栈内存中保存着一个堆内存的对象的引用 148 | ·作用域 149 | -- 作用域分为:词法作用域(也叫静态作用域)和环境作用域(也叫执行时作用域/动态作用域)。 150 | -- js遵循词法作用域 151 | -- 词法作用域:在词法分析时就可以知道一个变量的作用域,如果是有一个作用域,则创建一个block,满足“最近嵌套原则”,并形成一个作用域链。作用域在你写代码时将变量和块作用域写在哪里时就已经决定 152 | -- 子作用域:js在调用函数时会创建一个子环境,并且,父环境对象作为一个参数传入这个子环境对象创建当中,这个子环境就是一个子作用域 153 | -- 词法闭包:在词法分析时就可以知道闭包的存在 154 | -- 定义作用域: 155 | LexicalSope 156 | -- add:为当前作用域添加子作用域 157 | -- bind:添加变量进入词法作用域 158 | -- find:在词法作用域中查找变量 159 | -- table:存数据的哈希表 160 | -- id:int索引 161 | ·全局运行环境: 162 | -- 除了程序员自身写的代码外,程序自身会自带一个全局运行环境,例如js中在浏览器中的window对象,在node环境中的global对象 163 | -- 全局运行环境的组成: 164 | -- hashmap:{} 165 | -- level:0 //环境当前的嵌套层级,初始为0 166 | -- parent:sp //子环境(字作用域)指向父环境的指针 167 | ·源码到运行时的内存分配分析: 168 | 源码: 三地址码: 符号表的设计 翻转符号表 映射到运行时的地址 169 | var a=2*3+1 p0=2*3 p0 b sp+0 170 | var b=a+1 p1=p0+1 p1 a sp+4 171 | a=p1 a p1 sp+8 172 | b=a+1 b p2 sp+12 173 | ·三地址表达式实例2(斐波那契函数)栈的活动记录图示: 174 | 栈空间(通过指针偏移拿到数据) 代码段(通过行号值拿到数据) 175 | | link7 | 176 | //link7会指向数字2 | f | 177 | | 2 | | t1=n==1 | 178 | | link6 | | t2=n==2 | 179 | | link5 | |t3=t1 or t2| 180 | |其他临时变量| | | 181 | | 返回值3 | |branch goto| 182 | | 3 | | ... | 183 | | link4 | | | 184 | | link3 | | | 185 | |其他临时变量| | | 186 | | 返回值2 | | | 187 | | 4 | | | 188 | | link2 | | | 189 | //link2会指向数字5(即上一个栈帧 ) | | 190 | | link1 | | | 191 | //link1会指向代码call f | | 192 | |其他临时变量| | | 193 | | 返回值1 | | | 194 | //返回值可根据5的偏移量计算拿到 | | 195 | //通过push空为返回值1占位 | call f | 196 | | 5 | //call f将指向f函数体的第一行 197 | ------------ -------------- 198 | 运行时分析: 199 | 程序执行时,操作系统首先会开辟一个内存空间(具体参考《递归语言的运行时内存划分.jpg》),并将二进制机器码(为了易于理解,我们这里讨论的机器码用三地址码表示)载入存到开辟的内存的代码段,此时CS(Code Segment,代码段寄存器)指向该代码段的基址。 200 | 通过CS:IP(即Instruction Pointer,指令指针寄存器,即代码段CS对应的偏移指针)的指向从内存中取出下一条执行的指令,产生如下流程:取出的指令装入CPU的指令寄存器 → 执行指令 → IP++(即指向下一条指令了)或 通过JMP等跳转指令重新修改CS:IP而该表下一条指令的位置 → 重复第一步(循环)。 201 | 当然,在前面运行存储分配讲到,对于JS这种复杂的语言不会这么简单执行,而是要依赖栈进行临时数据和执行流程进行管理。根据ecma-262标准,JS引擎会先创建一个全局环境,并将全局上下文压入栈底。当遇到函数执行时,会创建函数执行上下文,并将该上下文压入栈顶。而栈中的指令可以根据EBP:ESP(ESP是堆栈指针寄存器,存放执行函数对应栈帧的栈顶地址(也是系统栈的顶部),且始终指向栈顶;EBP是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址)获取当前的内存地址空间,以指导生成准确操作数的机器码。 202 | 通过栈的指针偏移和代码段的指针偏移,两者配合就可以完成运行时的内存分配,并记录下各个数据的地址。 203 | ·设计一个三地址码生成规则: 204 | -- @:表示作用域 205 | -- section:执行上下文 206 | -- set:赋值 207 | -- branch:if语句判断 208 | -- $:临时变量 209 | -- call:调用函数 210 | -- %:寄存器,%TOP%表示TOP寄存器 211 | -- SP:指针 212 | -- call:函数调用 213 | -- pass:表示传参 214 | ·源码 → 三地址 215 | function fibonacci(n){ 216 | if(n==1 || n==2){ 217 | return n 218 | } 219 | return fibonacci(n-1)+fibonacci(n-2) 220 | } 221 | print(fibonacci(5)) 222 | 转换后的三地址码: 223 | section fibonacci@2 224 | set %TOP% %SP% 225 | set $t1@2 n==1 226 | set $t2@2 n==2 227 | set $t3@2 $t1@2 || $t2@2 228 | branch $t3@2 LB1 //$t3@2为true时继续,否则跳转到LB1行 229 | return n@2 230 | LB1:set $t4@2 n-1 231 | pass $t4@2 //pass表示传参,压栈 232 | call fibonacci@1 233 | set $6@2 n-2 234 | pass $t6@2 //pass表示传参,压栈 235 | call fibonacci@1 236 | set $t8@2 $t5@2 + $t7@2 237 | return $t8@2@2 238 | section main@1 239 | set %TOP% %SP% 240 | declare function fibonacci@1 241 | pass 5 242 | call fibonacci@1 243 | pass $t2@1 244 | call print@1 245 | -------------------------------------------------------------------------------- /src/tokenizer/tokenizer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 词法分析器,核心算法是DFA,参考:../../01_词法分析/README.md 3 | */ 4 | 5 | import { LexicalError } from '../common/LexicalError' 6 | 7 | 8 | export interface IToken { 9 | type: string 10 | value: string 11 | lineNo?: number 12 | } 13 | 14 | export class Tokenizer { 15 | public tokens: Array = [] 16 | private codeIndex: number = 0 //当前扫描到源码的第codeIndex个字符 17 | private lineNo: number = 0 //行号 18 | readonly KEYWORDS: Array = [ 19 | 'var', 20 | 'if', 21 | 'else', 22 | 'while', 23 | 'for', 24 | 'break', 25 | 'continue', 26 | 'function', 27 | 'return', 28 | ] 29 | constructor(sourceCode: string) { 30 | this.scanner(sourceCode) 31 | } 32 | //token生成器 33 | private makeToken(type: string, value: string, lineNo?: number): IToken { 34 | return { type, value, lineNo } 35 | } 36 | //自动机装饰器 37 | private decorator(automation_func): Function { 38 | return (...args) => { 39 | const token: IToken = automation_func(...args) 40 | this.codeIndex += token.value.length 41 | token.lineNo = this.lineNo 42 | this.tokens.push(token) 43 | } 44 | } 45 | //源码扫描器 46 | private scanner(sourceCode: string): void { 47 | this.tokens = [] 48 | this.codeIndex = 0 49 | this.lineNo = 0 50 | const getTokenLiteral: Function = this.decorator(this.literalAutomat.bind(this)) 51 | const getTokenNumber: Function = this.decorator(this.numberAutomat.bind(this)) 52 | const getTokenOp: Function = this.decorator(this.operatorAutomat.bind(this)) 53 | while (this.codeIndex < sourceCode.length) { 54 | const currentChar: string = sourceCode[this.codeIndex] 55 | if (currentChar.match(/[A-Za-z]/)) { 56 | getTokenLiteral(sourceCode, this.codeIndex) 57 | } else if (currentChar.match(/[0-9.]/)) { 58 | getTokenNumber(sourceCode, this.codeIndex) 59 | } else if (currentChar.match(/[+-\\*/&|=!;()]/)) { 60 | getTokenOp(sourceCode, this.codeIndex) 61 | } else if (currentChar === '{' || currentChar === '}') { 62 | this.codeIndex++ 63 | this.tokens.push(this.makeToken('block', currentChar, this.lineNo)) 64 | } else if (currentChar === '\n' || currentChar === '\r') { 65 | this.codeIndex++ 66 | this.lineNo++ 67 | continue 68 | } else if (currentChar === ' ' || currentChar === '\t') { 69 | this.codeIndex++ 70 | continue 71 | } else { 72 | throw new LexicalError(`lexical error:unexpected char ${currentChar} in line ${this.lineNo} `) 73 | } 74 | } 75 | } 76 | 77 | //变量自动机 78 | private literalAutomat(sourceCode: string, index: number): IToken { 79 | let state: number = 0 80 | let str: string = '' 81 | function getNextChar(): string { 82 | return sourceCode[index++] 83 | } 84 | while (true) { 85 | switch (state) { 86 | case 0: { 87 | const nextChar: string = getNextChar() 88 | if (nextChar.match(/[A-Za-z]/)) { 89 | str += nextChar 90 | state = 1 91 | } else { 92 | throw new LexicalError('not a illegal operator') 93 | } 94 | break 95 | } 96 | case 1: { 97 | const nextChar: string = getNextChar() 98 | if (nextChar && nextChar.match(/[A-Za-z0-9]/)) { 99 | str += nextChar 100 | } else { 101 | if (this.KEYWORDS.indexOf(str) > -1) { 102 | return this.makeToken('keyword', str) 103 | } else { 104 | return this.makeToken('id', str) 105 | } 106 | } 107 | break 108 | } 109 | } 110 | } 111 | } 112 | 113 | //数字自动机 114 | private numberAutomat(sourceCode: string, index: number): IToken { 115 | let state: number = 0 116 | let num: string = '' 117 | while (true) { 118 | const nextChar: string = sourceCode[index++] 119 | switch (state) { 120 | case 0: { 121 | if (nextChar === '0') { 122 | num += nextChar 123 | state = 2 124 | } else if (nextChar.match(/^[0-9]$/)) { 125 | num += nextChar 126 | state = 1 127 | } else if (nextChar === '.') { 128 | num += nextChar 129 | state = 3 130 | } else { 131 | throw new LexicalError('not a number') 132 | } 133 | break 134 | } 135 | case 1: { 136 | if (nextChar.match(/[0-9]/)) { 137 | num += nextChar 138 | } else { 139 | return this.makeToken('number', num) 140 | } 141 | break 142 | } 143 | case 2: { 144 | if (nextChar.match(/[1-9]/)) { 145 | num += nextChar 146 | state = 1 147 | } else if (nextChar === '.') { 148 | num += nextChar 149 | state = 4 150 | } else { 151 | return this.makeToken('number', num) 152 | } 153 | break 154 | } 155 | case 3: { 156 | if (nextChar.match(/[0-9]/)) { 157 | state = 5 158 | num += nextChar 159 | } else { 160 | throw new LexicalError('not a number') 161 | } 162 | } 163 | case 4: { 164 | if (nextChar.match(/[0-9]/)) { 165 | state = 5 166 | num += nextChar 167 | } else { 168 | return this.makeToken('number', num) 169 | } 170 | break 171 | } 172 | case 5: { 173 | if (nextChar.match(/[0-9]/)) { 174 | num += nextChar 175 | } else { 176 | return this.makeToken('number', num) 177 | } 178 | } 179 | } 180 | } 181 | } 182 | 183 | //运算符自动机 184 | private operatorAutomat(sourceCode: string, index: number): IToken { 185 | let state: number = 0 186 | let operator: string = '' 187 | while (true) { 188 | const nextChar = sourceCode[index++] 189 | operator += nextChar 190 | switch (state) { 191 | case 0: { 192 | switch (nextChar) { 193 | case '+': 194 | state = 1 195 | break 196 | case '-': 197 | state = 2 198 | break 199 | case '*': 200 | case '/': 201 | return this.makeToken('operator', operator) 202 | case '=': 203 | state = 5 204 | break 205 | case '&': 206 | state = 6 207 | break 208 | case '|': 209 | state = 7 210 | break 211 | case '>': 212 | state = 8 213 | break 214 | case '<': 215 | state = 9 216 | break 217 | case '!': 218 | state = 10 219 | break 220 | case '(': 221 | case ')': 222 | case ';': 223 | return this.makeToken('operator', operator) 224 | default: 225 | throw new LexicalError('not an operator') 226 | } 227 | break 228 | 229 | } 230 | case 1: { 231 | if (nextChar === '+') { 232 | return this.makeToken('operator', '++') 233 | } 234 | return this.makeToken('operator', '+') 235 | } 236 | case 2: { 237 | if (nextChar === '-') { 238 | return this.makeToken('operator', '--') 239 | } 240 | return this.makeToken('operator', '-') 241 | } 242 | 243 | case 5: { 244 | if (nextChar === '=') { 245 | return this.makeToken('operator', '==') 246 | } 247 | return this.makeToken('operator', '=') 248 | } 249 | case 6: { 250 | if (nextChar === '&') { 251 | return this.makeToken('operator', '&&') 252 | } 253 | return this.makeToken('operator', '&') 254 | 255 | } 256 | case 7: { 257 | if (nextChar === '|') { 258 | return this.makeToken('operator', '||') 259 | } 260 | return this.makeToken('operator', '|') 261 | } 262 | case 8: { 263 | if (nextChar === '=') { 264 | return this.makeToken('operator', '>=') 265 | } 266 | return this.makeToken('operator', '>') 267 | } 268 | case 9: { 269 | if (nextChar === '=') { 270 | return this.makeToken('operator', '<=') 271 | } 272 | return this.makeToken('operator', '<') 273 | } 274 | case 10: { 275 | if (nextChar === '=') { 276 | return this.makeToken('operator', '!=') 277 | } 278 | return this.makeToken('operator', '!') 279 | } 280 | default: 281 | throw new LexicalError('not an operator') 282 | } 283 | 284 | } 285 | } 286 | } 287 | 288 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /dist/tokenizer/tokenizer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 词法分析器,核心算法是DFA,参考:../../01_词法分析/README.md 3 | */ 4 | (function (factory) { 5 | if (typeof module === "object" && typeof module.exports === "object") { 6 | var v = factory(require, exports); 7 | if (v !== undefined) module.exports = v; 8 | } 9 | else if (typeof define === "function" && define.amd) { 10 | define(["require", "exports", "../common/LexicalError"], factory); 11 | } 12 | })(function (require, exports) { 13 | "use strict"; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.Tokenizer = void 0; 16 | const LexicalError_1 = require("../common/LexicalError"); 17 | class Tokenizer { 18 | constructor(sourceCode) { 19 | this.tokens = []; 20 | this.codeIndex = 0; //当前扫描到源码的第codeIndex个字符 21 | this.lineNo = 0; //行号 22 | this.KEYWORDS = [ 23 | 'var', 24 | 'if', 25 | 'else', 26 | 'while', 27 | 'for', 28 | 'break', 29 | 'continue', 30 | 'function', 31 | 'return', 32 | ]; 33 | this.scanner(sourceCode); 34 | } 35 | //token生成器 36 | makeToken(type, value, lineNo) { 37 | return { type, value, lineNo }; 38 | } 39 | //自动机装饰器 40 | decorator(automation_func) { 41 | return (...args) => { 42 | const token = automation_func(...args); 43 | this.codeIndex += token.value.length; 44 | token.lineNo = this.lineNo; 45 | this.tokens.push(token); 46 | }; 47 | } 48 | //源码扫描器 49 | scanner(sourceCode) { 50 | this.tokens = []; 51 | this.codeIndex = 0; 52 | this.lineNo = 0; 53 | const getTokenLiteral = this.decorator(this.literalAutomat.bind(this)); 54 | const getTokenNumber = this.decorator(this.numberAutomat.bind(this)); 55 | const getTokenOp = this.decorator(this.operatorAutomat.bind(this)); 56 | while (this.codeIndex < sourceCode.length) { 57 | const currentChar = sourceCode[this.codeIndex]; 58 | if (currentChar.match(/[A-Za-z]/)) { 59 | getTokenLiteral(sourceCode, this.codeIndex); 60 | } 61 | else if (currentChar.match(/[0-9.]/)) { 62 | getTokenNumber(sourceCode, this.codeIndex); 63 | } 64 | else if (currentChar.match(/[+-\\*/&|=!;()]/)) { 65 | getTokenOp(sourceCode, this.codeIndex); 66 | } 67 | else if (currentChar === '{' || currentChar === '}') { 68 | this.codeIndex++; 69 | this.tokens.push(this.makeToken('block', currentChar, this.lineNo)); 70 | } 71 | else if (currentChar === '\n' || currentChar === '\r') { 72 | this.codeIndex++; 73 | this.lineNo++; 74 | continue; 75 | } 76 | else if (currentChar === ' ' || currentChar === '\t') { 77 | this.codeIndex++; 78 | continue; 79 | } 80 | else { 81 | throw new LexicalError_1.LexicalError(`lexical error:unexpected char ${currentChar} in line ${this.lineNo} `); 82 | } 83 | } 84 | } 85 | //变量自动机 86 | literalAutomat(sourceCode, index) { 87 | let state = 0; 88 | let str = ''; 89 | function getNextChar() { 90 | return sourceCode[index++]; 91 | } 92 | while (true) { 93 | switch (state) { 94 | case 0: { 95 | const nextChar = getNextChar(); 96 | if (nextChar.match(/[A-Za-z]/)) { 97 | str += nextChar; 98 | state = 1; 99 | } 100 | else { 101 | throw new LexicalError_1.LexicalError('not a illegal operator'); 102 | } 103 | break; 104 | } 105 | case 1: { 106 | const nextChar = getNextChar(); 107 | if (nextChar && nextChar.match(/[A-Za-z0-9]/)) { 108 | str += nextChar; 109 | } 110 | else { 111 | if (this.KEYWORDS.indexOf(str) > -1) { 112 | return this.makeToken('keyword', str); 113 | } 114 | else { 115 | return this.makeToken('id', str); 116 | } 117 | } 118 | break; 119 | } 120 | } 121 | } 122 | } 123 | //数字自动机 124 | numberAutomat(sourceCode, index) { 125 | let state = 0; 126 | let num = ''; 127 | while (true) { 128 | const nextChar = sourceCode[index++]; 129 | switch (state) { 130 | case 0: { 131 | if (nextChar === '0') { 132 | num += nextChar; 133 | state = 2; 134 | } 135 | else if (nextChar.match(/^[0-9]$/)) { 136 | num += nextChar; 137 | state = 1; 138 | } 139 | else if (nextChar === '.') { 140 | num += nextChar; 141 | state = 3; 142 | } 143 | else { 144 | throw new LexicalError_1.LexicalError('not a number'); 145 | } 146 | break; 147 | } 148 | case 1: { 149 | if (nextChar.match(/[0-9]/)) { 150 | num += nextChar; 151 | } 152 | else { 153 | return this.makeToken('number', num); 154 | } 155 | break; 156 | } 157 | case 2: { 158 | if (nextChar.match(/[1-9]/)) { 159 | num += nextChar; 160 | state = 1; 161 | } 162 | else if (nextChar === '.') { 163 | num += nextChar; 164 | state = 4; 165 | } 166 | else { 167 | return this.makeToken('number', num); 168 | } 169 | break; 170 | } 171 | case 3: { 172 | if (nextChar.match(/[0-9]/)) { 173 | state = 5; 174 | num += nextChar; 175 | } 176 | else { 177 | throw new LexicalError_1.LexicalError('not a number'); 178 | } 179 | } 180 | case 4: { 181 | if (nextChar.match(/[0-9]/)) { 182 | state = 5; 183 | num += nextChar; 184 | } 185 | else { 186 | return this.makeToken('number', num); 187 | } 188 | break; 189 | } 190 | case 5: { 191 | if (nextChar.match(/[0-9]/)) { 192 | num += nextChar; 193 | } 194 | else { 195 | return this.makeToken('number', num); 196 | } 197 | } 198 | } 199 | } 200 | } 201 | //运算符自动机 202 | operatorAutomat(sourceCode, index) { 203 | let state = 0; 204 | let operator = ''; 205 | while (true) { 206 | const nextChar = sourceCode[index++]; 207 | operator += nextChar; 208 | switch (state) { 209 | case 0: { 210 | switch (nextChar) { 211 | case '+': 212 | state = 1; 213 | break; 214 | case '-': 215 | state = 2; 216 | break; 217 | case '*': 218 | case '/': 219 | return this.makeToken('operator', operator); 220 | case '=': 221 | state = 5; 222 | break; 223 | case '&': 224 | state = 6; 225 | break; 226 | case '|': 227 | state = 7; 228 | break; 229 | case '>': 230 | state = 8; 231 | break; 232 | case '<': 233 | state = 9; 234 | break; 235 | case '!': 236 | state = 10; 237 | break; 238 | case '(': 239 | case ')': 240 | case ';': 241 | return this.makeToken('operator', operator); 242 | default: 243 | throw new LexicalError_1.LexicalError('not an operator'); 244 | } 245 | break; 246 | } 247 | case 1: { 248 | if (nextChar === '+') { 249 | return this.makeToken('operator', '++'); 250 | } 251 | return this.makeToken('operator', '+'); 252 | } 253 | case 2: { 254 | if (nextChar === '-') { 255 | return this.makeToken('operator', '--'); 256 | } 257 | return this.makeToken('operator', '-'); 258 | } 259 | case 5: { 260 | if (nextChar === '=') { 261 | return this.makeToken('operator', '=='); 262 | } 263 | return this.makeToken('operator', '='); 264 | } 265 | case 6: { 266 | if (nextChar === '&') { 267 | return this.makeToken('operator', '&&'); 268 | } 269 | return this.makeToken('operator', '&'); 270 | } 271 | case 7: { 272 | if (nextChar === '|') { 273 | return this.makeToken('operator', '||'); 274 | } 275 | return this.makeToken('operator', '|'); 276 | } 277 | case 8: { 278 | if (nextChar === '=') { 279 | return this.makeToken('operator', '>='); 280 | } 281 | return this.makeToken('operator', '>'); 282 | } 283 | case 9: { 284 | if (nextChar === '=') { 285 | return this.makeToken('operator', '<='); 286 | } 287 | return this.makeToken('operator', '<'); 288 | } 289 | case 10: { 290 | if (nextChar === '=') { 291 | return this.makeToken('operator', '!='); 292 | } 293 | return this.makeToken('operator', '!'); 294 | } 295 | default: 296 | throw new LexicalError_1.LexicalError('not an operator'); 297 | } 298 | } 299 | } 300 | } 301 | exports.Tokenizer = Tokenizer; 302 | }); 303 | //# sourceMappingURL=tokenizer.js.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## JavaScript-compiler项目简介: 2 |   编译原理在编程世界中无处不在,是我们向高级或底层开发路上不得不要逾越的一道坎。编译原理比较复杂,我们不求写出一个完整的编译器,但掌握基本原理还是很有必要的。 3 |
4 |   核心内容:自动机、上下文无关文法、自顶向下语法分析、中序转换为后序算法解决语法优先级问题、中间代码生成、运行时内存分配分析、opcode生成、计算机原理等。 5 |
6 |   理解不到位的地方还望斧正。 7 | 8 | 9 | ## 目录 10 | ### [01 词法分析](./01_词法分析/README.md) 11 | ### [02 语法分析](./02_语法分析/README.md) 12 | ### [03 中间代码生成](./03_中间代码生成/README.txt) 13 | ### [04 运行时刻环境](./04_运行时刻环境/README.txt) 14 | ### [05 目标代码生成](./05_目标代码生成/README.txt) 15 | 16 | 17 | ## 源码目录结构: 18 | ``` 19 | src 20 | ├─common 公共库 21 | ├─demo 22 | │ │─tokenizer.ts 词法解析器demo 23 | │ │─parser.ts 语法解析器demo 24 | │ ├─ILGen.ts 中间码生成demo 25 | │ └─opcodeCompiler.ts 机器码生成demo 26 | ├─parse 语法分析 27 | │ ├─expression.ts 表达式 28 | │ ├─exprParser.ts 表达式解析器 29 | │ │─parser.ts 语法解析器 30 | │ ├─statement.ts 陈述语句 31 | │ └─terminal.ts 终结符 32 | ├─tokenizer 词法分析 33 | │ └─tokenizer.ts 词法解析器 34 | ├─opcodeCompiler 机器码生成 35 | │ └─opcodeCompiler.ts opcode翻译 36 | ├─SDT 语法制导翻译 37 | │ ├─ILGen.ts 中间码生成 38 | │ └─LexicalScope.ts 词法作用域 39 | └─tsconfig.json ts项目配置 40 | ``` 41 | 42 | 43 | ## 编译器简介: 44 | ### 什么是编译器: 45 |   编译器就是将一种编程语言转换为另一种编程语言的程序 46 | ### 编译器的使用场景: 47 | * 将高级代码编译成浏览器能识别的代码:例如vue中的.vue文件是无法被浏览器识别的,这时需要编译器将其编译成html文件才能正常显示。又如typescript编译成javascript,类似的还有Babel、ESLint、Stylus等等 48 | * 热更新:接触过小程序开发的同学应该知道,小程序运行的环境禁止new Function,eval等方法的使用,导致我们无法直接执行字符串形式的动态代码。此外,许多平台也对这些JS自带的可执行动态代码的方法进行了限制,那么我们是没有任何办法了吗?既然如此,我们便可以用JS写一个解析器,让JS自己去运行自己。 49 | * 开发跨平台工具:例如京东开源框架Taro,可以只书写一套代码,再通过Taro的编译工具,将源代码分别编译出可以在不同端(微信小程序、H5、App端等)运行的代码。类似的还有Egret、Weex等等 50 | * 其他常用工具:代码压缩、混淆等 51 | * 用JavaScript写成的JavaScript解释器,意义是什么? - caoglish的回答 - 知乎 52 | https://www.zhihu.com/question/20004379/answer/20123641 53 | ### 编译流程: 54 | * 常规编译过程: 55 | 源码(source code) → 词法分析器(Lexical Analyzer) → 符号流(tokens) → 语法分析器(Syntax Analyzer) → 抽象语法树 → 语义分析(Semantics Analyzer) → 抽象语法树 → 中间代码生成(Intermediate Code/Language Generator) → 中间表现形式 → 代码优化器(Code Optimizer) → 中间表现形式 → 代码生成(Code Generator) → 目标机器语言 56 | * C语言的编译过程: 57 | .c文件(源代码) → 预处理器(preprocessor) → .i文件 → 编译器(compiler) → .s文件(汇编码) → 汇编程序(assembler) → .o文件(可重定位机器码) → 链接器(Linker)/加载器 → .exe文件 58 | * 早期Java的编译和解释执行过程: 59 | .java文件(源代码) → javac.exe进行编译 → .class字节码文件(中间码) → java.exe加载到虚拟机中 → 在虚拟机中解释执行字节码 60 | * babel的编译过程: 61 | es6代码 → Babylon.parse → AST → babel-traverse → 新的AST → es5代码 62 | * TypeScript的编译过程: 63 | .ts文件(源程序) → ts编译器 → .js文件*(目标程序) 64 | * vue模板编译过程: 65 | → parse(template.trim()) → AST → Optimize(ast) → 新的AST → generate(ast) → render函数 66 | ### 编译器和解释器: 67 | * 编译器: 68 |
69 | ~ 源程序 → 编译器 → 目标程序 70 |
71 | ~ 编译器是将一种语言转换为另一种语言,不包括执行过程。 72 | * 解释器: 73 |
74 | ~ 源程序 + 数据 → 解释器 → 输出 75 |
76 | ~ 解释器是逐行或逐段的编译成机器语言并执行,不生成可存储的目标代码。 77 | * 例如: 78 |
79 |   早期java,通过javac.exe编译器进行编译,将.java文件编译成 .class字节码文件,这个过程是编译,但没有执行代码,这是编译过程。
80 |   .class+数据放入jvm虚拟机中,虚拟机将字节码再一行一行的编译成机器码并执行,这个过程是解释。 81 |
82 |   由于一行一行的解释执行较慢,jvm后面还引入了jit,可以将常用的机器码直接保存下来,提升效率,这里就包含和编译和解释两个过程。 83 | ### 编译流程解析: 84 | * 编译器通常分为编译器前端、中间代码和编译器后端 85 | * 编译器前端包括:词法分析、语法分析和语义分析 86 | * 词法分析:词法分析的目标是将字符串文本分割成一个个的“token”,例如:init、main、init、x、;、x、=、3、;、}等等。同时它可以去掉一些注释、空格、回车等等无效字符 87 | * 语法分析:将tokens解析分配在解析树的层次结构中,生成AST(抽象语法树),AST使tokens形成关联树结构。总而言之,语法分析的本质就是:程序员书写的代码本质是一串字符串,但给字符串添加语法规则后,便有可能产生token,以及token之间产生关系。 88 | * 语义分析:检查每个节点含义对每个节点进行修饰,例如cpu不能做整数乘以浮点数操作,需要将整数转换成浮点数,以满足计算机能够进行的浮点数乘以浮点数的操作 89 | * 编译器前端的目标是生成AST(抽象语法树) 90 | * AST: 91 |
92 | ~ 不依赖源语言文法:如果按bnf文法解析源代码,解析为一个自定义的结构,那在解释这个自定义结构的时候,肯定是为bnf文法量身定制的。一旦这个语言有了升级,bnf文法发生变动,相应的,后端解释器也会做相应的改动,十分麻烦。抽象语法树,相当于一个后端解释器给前端定制的一个规范,无论语言规范怎么变动,只需要改变将源代码解析为抽象语法树的解析器就行了,解析抽象语法树的解释器并不用改动。 93 |
94 | ~ 不依赖语言的细节:比如说,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。 95 | * 中间代码生成:将AST中的表达式转换为三地址表达式(或其他中间码形式) 96 | * 中间代码的意义: 97 |
98 |   既然已经拿到AST,机器运行需要的又是二进制。为什么不直接翻译成二进制呢?其实到目前为止从技术上来说已经完全没有问题了。但是,我们有各种各样的操作系统,有不同的CPU类型,每一种的位数可能不同;寄存器能够使用的指令也不同,像是复杂指令集与精简指令集等;在进行各个平台的兼容之前,我们还需要替换一些底层函数。因为不同平台的汇编处理都是不一样的,AST并不能完美运行在各个硬件平台上,于是便在 AST 和多个平台的汇编代码中间,抽象出了一个中间码(Intermediate Representation),在中间码的设计里抹平了硬件平台造成的差异。中间码的强大之处在于跨平台,与语言无关。 99 |
100 |   中间码存在的另外一个价值是提升后端编译的重用,比如我们定义好了一套中间码应该是长什么样子,那么后端机器码生成就是相对固定的。每一种语言只需要完成自己的编译器前端工作即可。这也是大家可以看到现在开发一门新语言速度比较快的原因。编译是绝大部分都可以重复使用的。 101 |
102 |   而且为了接下来的优化工作,中间代码存在具有非凡的意义。因为有那么多的平台,如果有中间码我们可以把一些共性的优化都放到这里,可使程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现中间代码,即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。 103 | * 代码优化: 104 |
105 |   对三地表达式进行优化,提高用户的执行速度。例如: 106 | ``` 107 | t1=inttofloat(60) 108 | t2=id3*t1 109 | t3=id2+t2 110 | id1=t3 111 | ``` 112 |   可以优化为: 113 | ``` 114 | t1=id3*60.0 115 | di1=id2+t1 116 | ``` 117 | * 编译器后端:将中间代码翻译为机器码的程序,也叫代码生成器 118 | * 代码生成: 119 |
120 |   将优化后的中间码生成汇编或二进制指令,cpu可以直接执行指令 121 | ``` 122 | t1=id3*60.0 123 | di1=id2+t1 124 | ``` 125 |   生成汇编指令为: 126 | ``` 127 | LD R2, id3 128 | MUL R2, R2, #60.0 129 | LD R1, id2 130 | ADD R1, R1, R2 131 | ST id1, R1 132 | ``` 133 | * 源码转换成汇编指令的实例过程: 134 | ``` 135 | 源码: 中间码: 汇编码: 136 | var x=1 0:x=1 0:set sp #1 137 | function(foo(y)){ foo 1:r=nil 1:inc sp #4 138 | return x+y 2:r=x+y 2:set sp #nil 139 | } 3:return 3:inc sp #4 140 | foo(100) 4:pass 100 4:add x y R 141 | 5:call foo 1 5:load R (sp-4) 142 | 6:goto (sp-8) 143 | 7:set sp #100 144 | 8:inc sp #4 145 | 9:set sp #11 (sp+4) 146 | 10:goto #1 147 | ``` 148 | 149 | 150 | ## 计算机原理概述: 151 | ### 概述: 152 |   编译器前端主要用于通过词法语法规则对语言的定义的翻译,是跟机器无关的。例如JS的语法规则在ecma-262中有详细的定义,我们便可以利用相关规则和算法进行转换。 153 |
154 |   而中间代码和机器码的生成通常是跟机器相关的,为此,掌握基本的计算机原理知识是十分必要的。本节对计算机基本知识进行了简介,并在[计算机的工作原理](./计算机的工作原理.txt)一文中进行原理的系统介绍,它向我们展示了从人脑计算到冯诺依曼机、从晶体管到逻辑门、从物理内存到虚拟内存、从二进制到汇编码,人们是如何一步一步将人脑计算抽象到汇编码。 155 |
156 |   而我们的编译器的作用就是将代码文本一步一步编译为汇编码。 157 |
158 |   通过汇编码这个节点,便可以知道程序员编写的代码是如何被计算机理解并执行的。如此,我们的计算机知识孤岛将能够被真正连接起来。 159 | 160 | ### cpu: 161 | * cpu主要由运算器、控制器、寄存器组成 162 | * 运算器:信息处理 163 | * 控制器:控制各种器件进行工作 164 | * 寄存器:信息存储,比内存更快 165 | ### 机器码: 166 | * cpu只能识别由0和1组成机器码 167 | * 机器码由cpu直接运行,是执行速度最快的代码 168 | * 机器码分2种: 169 |
170 | ~ 数据:存放图片、数字、音频等数据类型等的数据最终编译链接成的机器码 171 |
172 | ~ [指令](https://www.zhihu.com/question/65385471/answer/231486020):告诉计算机执行何种操作 173 |
174 |   ~~ 操作码(opcode) 175 |
176 |   ~~ 操作数 (operand) 177 | * 什么是指令和数据? 指令和数据是应用上的概念,同一串二进制代码,可以是指令,也可以是数据,这决定于我们的程序设计。例:1000100111011000,当被应用为数据时,它等于 89D8H,H 表示是十六进制。当被应用为指令时,它指的是 MOV AX, BX。不难看出,同一串二进制代码,应用不同,既可以作为指令使用,也可以作为数据来使用。在存储器中,指令和数据是没有任何区别的,它们都是二进制信息。唯一区分它们的方式就是,这些信息是通过哪种类型的总线来传输的,使用地址总线传输的信息是地址信息,使用数据总线传输的信息是数据信息,使用控制总线传输的信息是控制信息。 178 | * 机器码难编写、难读懂、易出错 179 | * cup不同,对二进制码的要求也不同。一套机器码在不同cpu中运行结果不同 180 | * c、c++经由编译器直接生成机器码,但不能跨机器运行 181 | ### cpu与指令集的关系: 182 | * 每种型号的CPU,都有自己特有的指令集。 183 | * cpu依靠(机器)指令来计算和控制系统,每款CPU在设计时就规定了一些列与其硬件电路相配合的指令系统,或者说某款cpu的硬件设计其实就是针对某个指令集的一种硬件实现。 184 | * 指令集也就是所谓的目标代码(或称为机器代码,是可以直接在CPU上运行的代码)可以看作是要求cpu对外提供的功能,某款CPU的设计肯定是朝着某个指令集来的。所以,不同的cpu架构,也表示这他的指令集要么较之前的指令集有所拓展或者就是实现了一种全新的指令集。指令集中的一条指令,就是让cpu完成一系列的动作,而该动作的完成则表明了某种运算的完成。一个功能可能需要一条或几条指令来实现。比如汇编的MOV或者LD语句就可能对应着几条cpu指令。 185 | ### 汇编码: 186 | * 机器码是0和1组成的二进制序列,可读性极差,而汇编码是比机器码更容易被人理解的代码 187 | 例如(1+4)*2+3的二进制计算为: 188 | 0100 0001 ;寄存器存入1 189 | 0001 0100 ;寄存器的数字加4 190 | 0010 0000 ;乘2 191 | 0001 0011 ;再加三 192 | 汇编码计算为: 193 | MOV 1 ;寄存器存入1 194 | ADD 4 ;寄存器的数字加4 195 | SHL 0 ;乘2(介于我们设计的乘法器暂时只能乘2,这个0是占位的) 196 | ADD 3 ;再加三 197 | * 汇编语言由以下3类指令组成: 198 |
199 | ~ 汇编指令:就是把特定的0和1序列,简化成对应的指令(一般为英文简写,如mov,inc等),可读性稍好 200 |
201 | ~ 伪指令:为了编程方便,对部分汇编指令做的封装就是伪指令 202 |
203 | ~ 其它符号 204 | * 汇编指令栗子: 205 |
206 | ~ move指令:move ax,19; //将数字19送入寄存器ax中,即ax=19 207 |
208 | ~ add指令:add ax,18; //将寄存器ax的只加18,即ax=19+18 209 | * 下面的机器指令和汇编指令是一一对应的,它们操作的含义都是:把寄存器BX中的内容送到AX中。 210 |
211 | 机器指令: 1000100111011000 212 |
213 | 汇编指令: MOV AX, BX 214 | * [更多汇编>>](./专题/汇编.txt) 215 | ### 操作系统与编译的关系: 216 | * 程序编译成机器码可以不需要依赖操作系统:https://www.zhihu.com/question/49580321 217 | * 只要是运行在某操作系统之上的程序都会烙上该操作系统的印,对操作系统有依赖,包括编译程序。不过这些程序对操作系统的依赖程度和依赖的内容确实有很多区别。例如一支最简单的【Hello world程序】都会对【操作系统的C库】产生依赖,如果去掉【Hello world程序】的输入输出功能,只作加减或逻辑运算,【Hello world程序】依然会对操作系统有少量依赖,因为【Hello world程序】由运行在该【操作系统上的编译程序】编译的,有特定的目标文件格式,并由该【操作系统的载入程序】载入内存运行。这种只【在形式上】对OS存在依赖的“无用”程序可谓是最独立于OS的程序。在此基础之上,其它程序都对OS有不同程度的依赖,依赖表现在对OS内的各种程序库的依赖,比如C标准库,POSIX系统库,线程库、网络库和其它基于这些基础库的第三方应用代码库。 218 | * 例如:java是通过虚拟机实现的跨平台的,也就是只编写一个程序,但是它去不同平台上运行的时候,其实带了对应的jvm,不同的操作系统由对应不同的jvm,去帮这一个程序去解释,而不同的jvm由sum公司去实现和更新,而且它会把对不同操作系统的底层调用(API)进行封装,对开发者却提供了统一的Java API,这样就减少程序员去了解操作系统API的差异性 219 | * 《JavaScript的功能是不是都是靠C或者C++这种编译语言提供的?》:https://www.zhihu.com/question/49176184/answer/116675413 220 | * 编译依赖操作系统(的库)发生在链接阶段 221 | ### 链接器(Linker): 222 | * 链接器是一个程序,将一个或多个由编译器或汇编器生成的目标文件外加库链接为一个可执行文件。 223 | * 例如,hello程序中调用了printf函数,它是每个C编译器都会提供的标准C库中的一个函数。printf函数存在于一个名为printf.o的单独的编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器(ld)就负责处理这种合并。结果就得到hello文件,它是一个可执行目标文件,可以被加载到内存中。由系统执行。 224 | ### 代码执行的完整过程: 225 | * 以文本形式存在的源代码 → 编译器将源代码转换成与特定CPU架构兼容的汇编代码或机器码目标文件 → 链接器将目标文件与库文件(如标准C库)和其他必要的代码连接在一起生成最终包含了程序的全部代码和数据的可执行文件并以二进制形式存储 → 操作系统负责加载可执行文件到内存中 → 一旦程序被加载到内存中,CPU开始逐条执行程序指令 226 | ### 为什么有的语言执行更快: 227 | * 从编程语言层面上看,取决于编译后的产物在运行时有多少"动态决议"。例如,弱类型语言比强类型语言慢,是因为编译时类型是不确定的,需要运行时进行额外的型别推导,这就是"动态决议";例如,C++里虚函数比普通函数开销大,是因为编译时函数地址是不确定的。普通函数编译后生成的跳转目的地是一串固定的地址,而虚函数的跳转地址是在运行时从CPU的寄存器里读取的,这也是"动态决议",编译后的机器码多了一条寄存器取值指令;类似的场景还有GC机制、模板编程、JIT优化等等,归根结底就是如果在编译时候能完成更多事情,那么生成的机器码运行周期就越短,代码也就运行地越快。 228 | ### CPU的工作原理详情: 229 | [《计算机的工作原理》](./计算机的工作原理.txt) 230 | 231 | 232 | ## 编译器相关常识补充: 233 | ### LLVM: 234 | * 广义的LLVM其实就是指整个LLVM编译器架构,包括了前端、后端、优化器、众多的库函数以及很多的模块 235 | * 狭义的LLVM其实就是聚焦于编译器后端功能(代码生成、代码优化、JIT等)的一系列模块和库。 236 | * LLVM IR:假如有N种语言(C、OC、C++、Swift...)的前端,同时也有M个架构(模拟器、arm64、x86...)的target,是否就需要N*M个编译器?LLVM编译器架构的好处是将所有语言转换为同一种IR,即LLVM IR,这样后端共用一种即可,只需要N个编译器了 237 | * Clang:LLVM项目下的一个高性能前段工具,它能把C/C++代码转为LLVM IR,它可以取代GCC编译器 238 | * 完全需要我们手工,或者依靠其他工具如lex, yacc来做的事情,是从源代码到token的词法分析和从token到AST的语法分析。AST生成LLVM IR也可以简单(见:https://hacpai.com/article/1570000872211)。 LLVM有完善的后端将IR转换为机器码 239 | * 《利用LLVM实现JS的编译器,创造属于自己的语言》:https://juejin.im/post/5b88d5ef51882542d733765c 240 | * 《LLVM架构-编译原理》:https://www.jianshu.com/p/b51345a323e2 241 | ### V8引擎: 242 | * 老的JS引擎, 生成的是字节码, 通过字节码编译器来运行 243 | * 字节码的执行效率要低于直接在CPU上运行的机器码。于是Java做出了改进, 将字节码编译成机器码执行 244 | * v8直接将js代码编译成机器码,不产生中间代码。然而, 这样会拉长编译时间, 并且生成的机器码占用了更多的内存,不利于缓存。于是在2017年4月改进了编译方法, Ignition新架构, 是支持混合模式的。混合的方式是将第一层调用编译成机器码, 第一层以上的调用编译成字节码。 245 | * 其实,Ignition + TurboFan 的组合,就是字节码解释器 + JIT 编译器的黄金组合。这一黄金组合在很多 JS 引擎中都有所使用,例如微软的 Chakra,它首先解释执行字节码,然后观察执行情况,如果发现热点代码,那么后台的 JIT 就把字节码编译成高效代码,之后便只执行高效代码而不再解释执行字节码。 246 | * 对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节码生成。 247 | * 编译过程包含了非常重要的一步,就是代码优化;而且编译过程完成了对代码的解析,所以会比解释型语言快。而jit是对代码不断编译优化的过程,例如提前确定数据类型,所以jit对于重复执行代码速度更快 248 | * 《JavaScript 语法解析、AST、V8、JIT》:https://cheogo.github.io/learn-javascript/201709/runtime.html 249 | * V8 是一个用C++编写的开源运行时引擎。 250 | * JavaScript => V8(C ++)=> 机器码 251 | * V8 实现了 ECMA-262 中指定的名为 ECMAScript 的脚本。 ECMAScript 由 Ecma International 创建,用于标准化JavaScript。 252 | * V8 可以独立运行,也可以嵌入到任何 C++ 程序中。它有一些钩子,允许你编写自己的C++代码供 JavaScript 使用。这实际上允许你通过将 V8 嵌入到 C++ 代码中来向 JavaScript 添加功能,以便使你的 C++ 代码实现比 ECMAScript 标准更多的功能。 253 | * [V8引擎介绍](./专题/V8引擎介绍(httpszhuanlan.zhihu.comp27628685).png) 254 | * [V8如何生成机器码](./专题/V8如何生成机器码(httpswww.zhihu.comquestion57532509).png) 255 | ### 字节码: 256 | * Bytecode(字节码)是一种IR(中间表示)的形式。 257 | * 通常说的“字节码”其实就是一种线性代码,它最重要的特征是: 258 |
259 | ~ 为存储、传输或直接解释执行而设计,因而指令格式一般比较紧凑 260 |
261 | ~ 只使用1字节或者2字节来编码指令的操作码(opcode)。“字节码”因此而得名。 262 |
263 | * LLVM IR的二进制序列化形式叫做bitcode(比特码),原因是这种序列化格式更倾向最大限度的紧凑,里面可能会有窄于1字节的数据类型,所以特意不叫字节码而叫比特码。本质上并没啥特别的。 264 | * 字节码中常常涉及的、但并非本质的一些点: 265 |
266 | ~ 指令既可能是固定长度的(例如Android的dex字节码、Lua的字节码),也可能是可变长度的(例如JVM的Java字节码、CPython的字节码) 267 |
268 | ~ 指令既可能是“基于寄存器”形式的(上面说的四地址、三地址代码),也可能是“基于栈”形式的(上面说的零地址代码) 269 | * java字节码: 270 |
271 | ~ java文件通过编译器编译成.class文件,就是java字节码文件 272 |
273 | ~ java字节码的运行和软件环境、硬件环境无关 274 |
275 | ~ java字节码是一种抹平了不同cpu架构的机器码,字节码不能直接在任何一种cpu架构上运行,但由于非常接近机器码,可以非常快的被翻译为对应架构的机器码 276 |
277 | ~ .class字节码文件不能被cpu直接运行,需要java虚拟机直译成机器码才能被cpu运行 278 |
279 | ~ java一次编写,到处运行的原理:将java文件编译成字节码文件,再通过不同平台的不同java虚拟机(JVM)可以快速的转换为各个机器所需要的机器码。 280 |
281 | ~ 因为java需要经过一次JVM转机器码才能运行,所以比c、c++直接编译机器码多一道流程,所以更慢一些 282 | 283 | 284 | ## 参考文档: 285 | * 《编译原理》:Alfred V.Aho,机械工业出版社 286 | * 《编译原理》:哈工大·陈鄞,https://www.bilibili.com/video/BV1zW411t7YE 287 | * 《编译器实现Category》:https://www.hashcoding.net/categories/%E7%BC%96%E8%AF%91%E5%99%A8%E5%AE%9E%E7%8E%B0/ 288 | * 《博客园·dejavudwh的博客》:https://www.cnblogs.com/secoding/p/11193700.html 289 | * 《RednaxelaFX写的文章/回答的导航帖》:https://zhuanlan.zhihu.com/p/25042028 290 | * 《kyjm/compiler-in-js》:https://github.com/kyjm/compiler-in-js 291 | * 《jquery/esprima》:https://github.com/jquery/esprima 292 | * 《estools/escodegen》:https://github.com/estools/escodegen 293 | --------------------------------------------------------------------------------