diff --git a/interpreter.js b/interpreter.js new file mode 100644 index 0000000..f000b4f --- /dev/null +++ b/interpreter.js @@ -0,0 +1,24 @@ +import { writeFileSync } from "fs"; +import { Stmt, PrintStmt, ReturnStmt } from "./stuff.js"; + +/** + * + * @param {Stmt[]} statements + */ +export function generate_rust_code(filename, statements) { + const output = []; + output.push("fn main() {"); + + for (const stmt of statements) { + if (stmt instanceof PrintStmt) { + output.push(`\tprint!("${stmt.string}");`); + } else if (stmt instanceof ReturnStmt) { + output.push(`\tstd::process::exit(${stmt.value});`); + } + } + + output.push("}\n"); + const text = output.join("\n"); + + writeFileSync(filename, text); +} diff --git a/main.js b/main.js index 6949e4a..4960734 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,7 @@ -import { readFileSync, writeFileSync } from "fs"; +import { readFileSync } from "fs"; import { Parser } from "./parser.js"; -import { PrintStmt, ReturnStmt } from "./stuff.js"; +import { generate_rust_code } from "./interpreter.js"; + import { is_alpha, is_alphanum, @@ -8,6 +9,7 @@ import { is_whitespace, pretty_error, panic, + exit_rand, } from "./utils.js"; // Javascript enums at home @@ -287,46 +289,96 @@ class Lexer { } } +const TARGETS = [ + "rust", + "x86_64-fasm-linux-gnu", + // "x86_64-fasm-windows" +]; + try { _main(); } catch (e) { console.error(e); } +function check_next_arg(arg, next_arg) { + if (next_arg === null && !next_arg.startsWith("-")) { + console.error(`Missing or invalid value for flag "${arg}"`); + exit_rand(); + } + + return true; +} + +function print_usage() { + console.log("Cpp.js"); + console.log("USAGE:"); + console.log(" node cpp.js "); + console.log(" node cpp.js --target "); + console.log(" node cpp.js --target list"); + console.log(" node cpp.js --help"); + console.log(); + console.log(" : The cpp file to compile"); + console.log(" : The target platform"); +} + function _main() { const CPP_REGEX = /.\.cpp/i; const args = process.argv; - let filename = "main.cpp"; - for (const arg of args) { + let filename = "main.cpp"; + let target = TARGETS[0]; // default target is rust + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + const next_arg = i + 1 < args.length ? args[i + 1] : null; + + if (arg === "--help") { + print_usage(); + process.exit(0); + } + if (CPP_REGEX.test(arg)) { filename = arg; } + + if (arg === "--target" && check_next_arg(arg, next_arg)) { + if (next_arg === "list") { + console.log("Valid targets:"); + for (const target of TARGETS) { + console.log(target); + } + process.exit(0); + } + + if (!TARGETS.includes(next_arg)) { + console.error( + `Unknown target "${next_arg}\nMaybe try: --target list` + ); + exit_rand(); + } + + target = next_arg; + } } const source = readFileSync(filename, "utf8"); const lexer = new Lexer(source); const tokens = lexer.scan_tokens(); - // console.log(lexer.tokens); - const parser = new Parser(tokens); const statements = parser.parse(); - const output = []; - output.push("fn main() {"); + switch (target) { + case TARGETS[0]: // rust + filename = filename.replace(".cpp", ".rs"); + generate_rust_code(filename, statements); + break; - for (const stmt of statements) { - if (stmt instanceof PrintStmt) { - output.push(`\tprint!("${stmt.string}");`); - } else if (stmt instanceof ReturnStmt) { - output.push(`\tstd::process::exit(${stmt.value});`); - } + case TARGETS[1]: // x86_64-fasm-linux-gnu + filename = filename.replace(".cpp", ".asm"); + // TODO GENERATE ASM! + default: + break; } - - output.push("}\n"); - const text = output.join("\n"); - - filename = filename.replace("cpp", "rs"); - writeFileSync(filename, text); } diff --git a/parser.js b/parser.js index 3378465..d7e70a7 100644 --- a/parser.js +++ b/parser.js @@ -1,7 +1,7 @@ // ------- Parser -------- import { Token, TokenType } from "./main.js"; -import { PrintStmt, ReturnStmt } from "./stuff.js"; +import { PrintStmt, ReturnStmt, Stmt } from "./stuff.js"; import { panic } from "./utils.js"; const Errors = { diff --git a/stuff.js b/stuff.js index 1c55053..9865eb9 100644 --- a/stuff.js +++ b/stuff.js @@ -1,13 +1,5 @@ -export class AST {} export class Stmt {} -export class Block extends AST { - constructor(stmts) { - super(); - this.stmts = stmts; - } -} - export class PrintStmt extends Stmt { /** * @@ -37,23 +29,26 @@ export class IfStmt extends Stmt {} export class ElseStmt extends Stmt {} -export class Expr {} +export class AST {} -export class EqualsExpr { - constructor(a, b) { - this.a = a; - this.b = b; +export class Block extends AST { + constructor(stmts) { + super(); + this.stmts = stmts; } } -export class Num { +export class NumberNode extends AST { constructor(value) { + super(); this.value = value; } } -export class FunctionDeclaration extends Stmt { - constructor(name, params, body) { +export class BinaryExpr extends AST { + constructor(left, right) { super(); + this.left = left; + this.right = right; } }