mirror of
https://github.com/Gers2017/cpp.js.git
synced 2024-11-28 09:48:42 -06:00
feat(Target): Add fasm target
- Add x86_64-fasm-linux-gnu - Update Makefile - Update parser to support '\n'
This commit is contained in:
parent
9a1ad1e7a4
commit
6fd0c48742
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,6 +1,8 @@
|
|||
/bin
|
||||
/**/*.out
|
||||
/ignore
|
||||
/**/*.out
|
||||
*.rs
|
||||
*.asm
|
||||
*.elf
|
||||
test.cpp
|
||||
test.rs
|
10
Makefile
10
Makefile
|
@ -1,14 +1,20 @@
|
|||
CC=rustc
|
||||
|
||||
ASM=fasm
|
||||
|
||||
default: build-rs
|
||||
|
||||
build-rs:
|
||||
node main.js main.cpp && $(CC) main.rs -o main.out
|
||||
node main.js main.cpp --target rust && $(CC) main.rs -o main.out
|
||||
|
||||
build-fasm:
|
||||
node main.js main.cpp --target x86_64-fasm-linux-gnu && $(ASM) main.asm main.elf && chmod +x main.elf
|
||||
|
||||
run:
|
||||
./main.out
|
||||
|
||||
run-fasm:
|
||||
./main.elf
|
||||
|
||||
clean:
|
||||
rm *.out
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { writeFileSync } from "fs";
|
|||
import { Stmt, PrintStmt, ReturnStmt } from "./stuff.js";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} filename
|
||||
* @param {Stmt[]} statements
|
||||
*/
|
||||
export function generate_rust_code(filename, statements) {
|
||||
|
@ -22,3 +22,49 @@ export function generate_rust_code(filename, statements) {
|
|||
|
||||
writeFileSync(filename, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filename
|
||||
* @param {Stmt[]} statements
|
||||
*/
|
||||
export function generate_fasm_linux(filename, statements) {
|
||||
const output = [];
|
||||
output.push("format ELF executable 3");
|
||||
output.push("entry start");
|
||||
output.push("segment readable executable");
|
||||
output.push("start:");
|
||||
|
||||
const push_syscall = () => output.push("int 0x80");
|
||||
|
||||
for (let i = 0; i < statements.length; i++) {
|
||||
const stmt = statements[i];
|
||||
|
||||
if (stmt instanceof PrintStmt) {
|
||||
output.push("mov eax, 4"); // write syscall
|
||||
output.push("mov ebx, 1"); // stdout (fd)
|
||||
output.push(`mov ecx, str${i}`);
|
||||
output.push(`mov edx, ${stmt.string.length}`);
|
||||
push_syscall();
|
||||
} else if (stmt instanceof ReturnStmt) {
|
||||
output.push("mov eax, 1"); // exit syscall
|
||||
output.push(`mov ebx, ${stmt.value}`); // return code
|
||||
push_syscall();
|
||||
}
|
||||
}
|
||||
|
||||
output.push("segment readable writeable");
|
||||
|
||||
for (let i = 0; i < statements.length; i++) {
|
||||
const stmt = statements[i];
|
||||
if (stmt instanceof PrintStmt) {
|
||||
const message = [...stmt.string]
|
||||
.map((ch) => ch.charCodeAt(0))
|
||||
.join(",");
|
||||
|
||||
output.push(`str${i} db ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const text = output.join("\n");
|
||||
writeFileSync(filename, text);
|
||||
}
|
||||
|
|
7
main.js
7
main.js
|
@ -1,6 +1,6 @@
|
|||
import { readFileSync } from "fs";
|
||||
import { Parser } from "./parser.js";
|
||||
import { generate_rust_code } from "./interpreter.js";
|
||||
import { generate_fasm_linux, generate_rust_code } from "./interpreter.js";
|
||||
|
||||
import {
|
||||
is_alpha,
|
||||
|
@ -366,7 +366,8 @@ function _main() {
|
|||
const lexer = new Lexer(source);
|
||||
const tokens = lexer.scan_tokens();
|
||||
|
||||
const parser = new Parser(tokens);
|
||||
const is_asm = target == TARGETS[1];
|
||||
const parser = new Parser(tokens, { true_newline: is_asm });
|
||||
const statements = parser.parse();
|
||||
|
||||
switch (target) {
|
||||
|
@ -377,7 +378,7 @@ function _main() {
|
|||
|
||||
case TARGETS[1]: // x86_64-fasm-linux-gnu
|
||||
filename = filename.replace(".cpp", ".asm");
|
||||
// TODO GENERATE ASM!
|
||||
generate_fasm_linux(filename, statements);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
17
parser.js
17
parser.js
|
@ -25,7 +25,8 @@ const Errors = {
|
|||
|
||||
export class Parser {
|
||||
/** @param { Token[] } tokens */
|
||||
constructor(tokens) {
|
||||
/** @param { { true_newline: boolean } | undefined } options */
|
||||
constructor(tokens, options) {
|
||||
this.tokens = tokens;
|
||||
this.index = 0;
|
||||
this.back_index = this.tokens.length - 1;
|
||||
|
@ -33,6 +34,10 @@ export class Parser {
|
|||
* @type { Stmt[] }
|
||||
*/
|
||||
this.statements = [];
|
||||
this.options = options ?? {
|
||||
// By default use '\\n'. Useful for transpiling to rust
|
||||
true_newline: false,
|
||||
};
|
||||
}
|
||||
|
||||
is_empty() {
|
||||
|
@ -135,13 +140,15 @@ export class Parser {
|
|||
if (token.token_type === TokenType.PRINTF) {
|
||||
this.expect(TokenType.PRINTF, Errors.PRINTF_ERR); // skip print
|
||||
this.expect(TokenType.LEFT_PAREN, Errors.LEFT_PAREN_ERR); // skip '('
|
||||
const value = this.expect(
|
||||
TokenType.STRING,
|
||||
Errors.STRING_ERR
|
||||
).value; // get the string!
|
||||
let value = this.expect(TokenType.STRING, Errors.STRING_ERR).value; // get the string!
|
||||
this.expect(TokenType.RIGHT_PAREN, Errors.RIGHT_PAREN_ERR); // skip ')'
|
||||
this.expect(TokenType.SEMICOLON, Errors.SEMI_COLON_ERR);
|
||||
|
||||
if (this.options.true_newline) {
|
||||
const regex = /\\n/gim;
|
||||
value = value.replace(regex, "\n");
|
||||
}
|
||||
|
||||
return new PrintStmt(value);
|
||||
} else if (token.token_type === TokenType.RETURN) {
|
||||
// console.log("current:", this.peek()?.display());
|
||||
|
|
Loading…
Reference in a new issue