diff --git a/Cargo.lock b/Cargo.lock index 9622d12..0d03f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,180 @@ version = 4 [[package]] name = "archforge" version = "0.1.0" +dependencies = [ + "pest", + "pest_derive", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" diff --git a/Cargo.toml b/Cargo.toml index 95356c1..f919339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] +pest = "2.8.6" +pest_derive = "2.8.6" diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 2dc1543..b41c6aa 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,21 +1,44 @@ +#[derive(Debug)] pub struct Program { pub functions: Vec, + pub statements: Vec, } +#[derive(Debug)] pub struct Function { pub name: String, pub params: Vec, - pub body: Vec, + pub body: Vec, } +#[derive(Debug)] +pub enum Statement { + Instruction(Instruction), + PointerAssign { left: Reg, right: Reg }, + FunctionCall(FunctionCall), +} + +#[derive(Debug)] pub struct Instruction { pub opcode: String, pub operands: Vec, } +#[derive(Debug)] +pub struct FunctionCall { + pub name: String, + pub args: Vec, +} + +#[derive(Debug)] pub enum Operand { - Global(String), - Local(String), + Reg(Reg), Number(i64), Pointer(Box), -} \ No newline at end of file +} + +#[derive(Debug)] +pub enum Reg { + Global(String), + Local(String), +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 851c0bc..3a085f2 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1 +1,138 @@ pub mod ast; + +use pest::iterators::Pair; +use pest_derive::Parser; + +use ast::*; + +#[derive(Parser)] +#[grammar = "parser/grammar.pest"] // relative to src +pub struct ForgeParser; + +use pest::Parser; + +pub fn parse_program(src: &str) -> Result> { + let mut pairs = ForgeParser::parse(Rule::program, src)?; + let program = pairs.next().unwrap(); + + let mut functions = Vec::new(); + let mut statements = Vec::new(); + + for pair in program.into_inner() { + match pair.as_rule() { + Rule::function_def => functions.push(parse_function(pair)), + Rule::instruction | Rule::pointer_assign | Rule::function_call => { + statements.push(parse_statement(pair)) + } + _ => {} + } + } + + Ok(Program { + functions, + statements, + }) +} + +fn parse_function(pair: Pair) -> Function { + let mut inner = pair.into_inner(); + + let name = inner.next().unwrap().as_str().to_string(); + + let mut params = Vec::new(); + let mut body = Vec::new(); + + for p in inner { + match p.as_rule() { + Rule::param_list => { + for param in p.into_inner() { + params.push(param.as_str().to_string()); + } + } + Rule::block => { + for stmt in p.into_inner() { + body.push(parse_statement(stmt)); + } + } + _ => {} + } + } + + Function { name, params, body } +} + +fn parse_statement(pair: Pair) -> Statement { + match pair.as_rule() { + Rule::instruction => Statement::Instruction(parse_instruction(pair)), + + Rule::pointer_assign => { + let mut inner = pair.into_inner(); + + let left = parse_reg(inner.next().unwrap()); + let right = parse_reg(inner.next().unwrap()); + + Statement::PointerAssign { left, right } + } + + Rule::function_call => Statement::FunctionCall(parse_function_call(pair)), + + _ => unreachable!(), + } +} + +fn parse_instruction(pair: Pair) -> Instruction { + let mut inner = pair.into_inner(); + + let opcode = inner.next().unwrap().as_str().to_string(); + + let mut operands = Vec::new(); + + if let Some(list) = inner.next() { + for op in list.into_inner() { + operands.push(parse_operand(op)); + } + } + + Instruction { opcode, operands } +} + +fn parse_function_call(pair: Pair) -> FunctionCall { + let mut inner = pair.into_inner(); + + let name = inner.next().unwrap().as_str().to_string(); + + let mut args = Vec::new(); + + if let Some(list) = inner.next() { + for arg in list.into_inner() { + args.push(parse_operand(arg)); + } + } + + FunctionCall { name, args } +} + +fn parse_operand(pair: Pair) -> Operand { + match pair.as_rule() { + Rule::number => Operand::Number(pair.as_str().parse().unwrap()), + + Rule::global_reg | Rule::local_reg => Operand::Reg(parse_reg(pair)), + + Rule::pointer_expr => { + let inner = pair.into_inner().next().unwrap(); + Operand::Pointer(Box::new(parse_operand(inner))) + } + + _ => unreachable!(), + } +} + +fn parse_reg(pair: Pair) -> Reg { + match pair.as_rule() { + Rule::global_reg => Reg::Global(pair.as_str()[1..].to_string()), + + Rule::local_reg => Reg::Local(pair.as_str()[1..].to_string()), + + _ => unreachable!(), + } +}