Mencipta pengkompil C dalam JavaScript ialah projek yang kompleks dan bercita-cita tinggi yang melibatkan beberapa komponen, termasuk analisis leksikal, penghuraian, analisis semantik dan penjanaan kod. Di bawah ialah contoh ringkas dan peringkat tinggi tentang cara anda boleh mula membina pengkompil sedemikian. Contoh ini akan menumpukan pada analisis leksikal (tokenisasi) dan peringkat penghuraian, yang merupakan langkah pertama dalam menyusun kod C.
Penganalisis leksikal (lexer) menukar kod input C kepada aliran token.
class Lexer { constructor(input) { this.input = input; this.tokens = []; this.current = 0; } tokenize() { while (this.current < this.input.length) { let char = this.input[this.current]; if (/\s/.test(char)) { this.current++; continue; } if (/[a-zA-Z_]/.test(char)) { let start = this.current; while (/[a-zA-Z0-9_]/.test(this.input[this.current])) { this.current++; } this.tokens.push({ type: 'IDENTIFIER', value: this.input.slice(start, this.current) }); continue; } if (/[0-9]/.test(char)) { let start = this.current; while (/[0-9]/.test(this.input[this.current])) { this.current++; } this.tokens.push({ type: 'NUMBER', value: this.input.slice(start, this.current) }); continue; } switch (char) { case '+': this.tokens.push({ type: 'PLUS', value: '+' }); this.current++; break; case '-': this.tokens.push({ type: 'MINUS', value: '-' }); this.current++; break; case '*': this.tokens.push({ type: 'STAR', value: '*' }); this.current++; break; case '/': this.tokens.push({ type: 'SLASH', value: '/' }); this.current++; break; case '=': this.tokens.push({ type: 'EQUAL', value: '=' }); this.current++; break; case ';': this.tokens.push({ type: 'SEMICOLON', value: ';' }); this.current++; break; case '(': this.tokens.push({ type: 'LPAREN', value: '(' }); this.current++; break; case ')': this.tokens.push({ type: 'RPAREN', value: ')' }); this.current++; break; default: throw new TypeError('Unexpected character: ' + char); } } return this.tokens; } }
Penghurai menukar aliran token kepada pokok sintaks abstrak (AST).
class Parser { constructor(tokens) { this.tokens = tokens; this.current = 0; } parse() { let ast = { type: 'Program', body: [] }; while (this.current < this.tokens.length) { ast.body.push(this.parseStatement()); } return ast; } parseStatement() { let token = this.tokens[this.current]; if (token.type === 'IDENTIFIER' && this.tokens[this.current + 1].type === 'EQUAL') { return this.parseAssignment(); } throw new TypeError('Unknown statement: ' + token.type); } parseAssignment() { let identifier = this.tokens[this.current]; this.current++; // skip identifier this.current++; // skip equal sign let value = this.parseExpression(); this.expect('SEMICOLON'); return { type: 'Assignment', identifier: identifier.value, value: value }; } parseExpression() { let token = this.tokens[this.current]; if (token.type === 'NUMBER') { this.current++; return { type: 'Literal', value: Number(token.value) }; } throw new TypeError('Unknown expression: ' + token.type); } expect(type) { let token = this.tokens[this.current]; if (token.type !== type) { throw new TypeError('Expected ' + type + ' but found ' + token.type); } this.current++; } }
Akhir sekali, penjana kod menukar AST ke dalam bahasa sasaran, yang boleh menjadi JavaScript atau mana-mana bahasa lain.
class CodeGenerator { generate(node) { switch (node.type) { case 'Program': return node.body.map(statement => this.generate(statement)).join('\n'); case 'Assignment': return `let ${node.identifier} = ${this.generate(node.value)};`; case 'Literal': return node.value; default: throw new TypeError('Unknown node type: ' + node.type); } } }
Berikut ialah cara anda boleh menggunakan lexer, parser dan penjana kod:
const input = `x = 42;`; const lexer = new Lexer(input); const tokens = lexer.tokenize(); console.log('Tokens:', tokens); const parser = new Parser(tokens); const ast = parser.parse(); console.log('AST:', JSON.stringify(ast, null, 2)); const generator = new CodeGenerator(); const output = generator.generate(ast); console.log('Output:', output);
Ini akan menandakan input, menghuraikannya menjadi AST dan menjana kod JavaScript daripada AST.
Contoh ini sangat dipermudahkan dan hanya mengendalikan subset kecil bahasa C. Pengkompil C yang lengkap memerlukan pengendalian set token yang lebih besar, menghuraikan ungkapan kompleks, pernyataan, pengisytiharan, jenis dan menjana kod yang lebih canggih.
Atas ialah kandungan terperinci Mencipta pengkompil C dalam JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!