summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock154
-rw-r--r--Cargo.toml2
-rw-r--r--src/bin/br-asm.rs21
-rw-r--r--src/lib.rs32
-rw-r--r--src/stages/bytecode.rs14
-rw-r--r--src/stages/syntactic.rs21
-rw-r--r--src/stages/syntactic_tokens.rs2
8 files changed, 189 insertions, 58 deletions
diff --git a/.gitignore b/.gitignore
index 4fffb2f..ea8c4bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1 @@
/target
-/Cargo.lock
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..c81c072
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,154 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "assembler"
+version = "2.3.0"
+source = "git+git://benbridle.com/assembler?tag=v2.3.0#a9640fce1aaa5e80170ce4d2ac700f66cfffbb4b"
+dependencies = [
+ "inked",
+ "log 2.0.0",
+ "vagabond",
+]
+
+[[package]]
+name = "bedrock-asm"
+version = "1.0.0"
+dependencies = [
+ "assembler",
+ "log 2.0.0",
+ "switchboard",
+]
+
+[[package]]
+name = "inked"
+version = "1.0.0"
+source = "git+git://benbridle.com/inked?tag=v1.0.0#2954d37b638fa2c1dd3d51ff53f08f475aea6ea3"
+dependencies = [
+ "termcolor",
+]
+
+[[package]]
+name = "log"
+version = "1.1.1"
+source = "git+git://benbridle.com/log?tag=v1.1.1#930f3d0e2b82df1243f423c092a38546ea7533c3"
+
+[[package]]
+name = "log"
+version = "2.0.0"
+source = "git+git://benbridle.com/log?tag=v2.0.0#a38d3dd487594f41151db57625410d1b786bebe4"
+dependencies = [
+ "inked",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "switchboard"
+version = "2.1.0"
+source = "git+git://benbridle.com/switchboard?tag=v2.1.0#e6435712ba5b3ca36e99fc8cbe7755940f8b1f3f"
+dependencies = [
+ "log 1.1.1",
+ "paste",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "vagabond"
+version = "1.1.1"
+source = "git+git://benbridle.com/vagabond?tag=v1.1.1#b190582517e6008ad1deff1859f15988e4efaa26"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/Cargo.toml b/Cargo.toml
index 9673558..a278ddc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "bedrock-asm"
-version = "0.1.0"
+version = "1.0.0"
authors = ["Ben Bridle"]
edition = "2024"
description = "Assembler for the Bedrock assembly language"
diff --git a/src/bin/br-asm.rs b/src/bin/br-asm.rs
index ced4245..e7a9230 100644
--- a/src/bin/br-asm.rs
+++ b/src/bin/br-asm.rs
@@ -3,25 +3,6 @@ use switchboard::*;
fn main() {
- let mut args = Switchboard::from_env();
- args.named("version");
- args.named("verbose").short('v');
-
- if args.get("version").as_bool() {
- print_version();
- }
- if args.get("verbose").as_bool() {
- log::set_log_level(log::LogLevel::Info);
- }
-
+ let args = Switchboard::from_env();
assemble(args, "br-asm");
}
-
-
-fn print_version() -> ! {
- let name = env!("CARGO_PKG_NAME");
- let version = env!("CARGO_PKG_VERSION");
- eprintln!("{name} v{version}");
- eprintln!("Written by Ben Bridle.");
- std::process::exit(0);
-}
diff --git a/src/lib.rs b/src/lib.rs
index d45d449..3f7bf59 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,7 +20,26 @@ pub const WIDE_MODE: u8 = 0x40;
pub const IMMEDIATE_MODE: u8 = 0x20;
-pub fn assemble(mut args: Switchboard, invocation: &str) {
+pub fn assemble(mut args: Switchboard, invocation: &str) -> ! {
+ args.named("help").short('h');
+ args.named("version");
+ args.named("verbose").short('v');
+
+ if args.get("help").as_bool() {
+ print_help(invocation);
+ std::process::exit(0);
+ }
+ if args.get("version").as_bool() {
+ let name = env!("CARGO_PKG_NAME");
+ let version = env!("CARGO_PKG_VERSION");
+ eprintln!("{name} v{version}");
+ eprintln!("Written by Ben Bridle.");
+ std::process::exit(0);
+ }
+ if args.get("verbose").as_bool() {
+ log::set_log_level(log::LogLevel::Info);
+ }
+
args.positional("source");
args.positional("destination");
args.named("extension").default("brc");
@@ -34,14 +53,8 @@ pub fn assemble(mut args: Switchboard, invocation: &str) {
args.named("dry-run").short('n');
args.named("tree");
args.named("with-symbols");
- args.named("help").short('h');
args.raise_errors();
- if args.get("help").as_bool() {
- print_help(invocation);
- std::process::exit(0);
- }
-
let source_path = args.get("source").as_path_opt().map(
|p| p.canonicalize().unwrap_or_else(|e| fatal!("{p:?}: {e:?}")));
let destination_path = args.get("destination").as_path_opt();
@@ -169,6 +182,7 @@ pub fn assemble(mut args: Switchboard, invocation: &str) {
};
write_bytes_and_exit(&bytes, destination_path.as_ref());
}
+ std::process::exit(0);
}
@@ -191,7 +205,7 @@ fn print_help(invocation: &str) {
eprintln!("\
Usage: {invocation} [source] [destination]
-Convert Bedrock source code into an assembled Bedrock program.
+Assembler for the Bedrock computer system.
Usage:
To assemble a Bedrock program from a source file and write to an output
@@ -204,7 +218,7 @@ Usage:
Environment variables:
BEDROCK_LIBS
- A list of colon-separated paths which will be searched to find Bedrock
+ A list of colon-separated paths that will be searched to find Bedrock
source code files to use as libraries when assembling a Bedrock program.
If a library file resolves an unresolved symbol in the program being
assembled, the library file will be merged into the program.
diff --git a/src/stages/bytecode.rs b/src/stages/bytecode.rs
index 6878c42..f0b99df 100644
--- a/src/stages/bytecode.rs
+++ b/src/stages/bytecode.rs
@@ -14,14 +14,8 @@ pub fn generate_bytecode(semantic: &Program) -> Result<AssembledProgram, Vec<Tra
let address = information.address;
symbols.push(AssembledSymbol { name, address, source });
}
-
match generator.errors.is_empty() {
- true => Ok(
- AssembledProgram {
- bytecode: generator.bytecode,
- symbols,
- }
- ),
+ true => Ok(AssembledProgram { bytecode: generator.bytecode, symbols }),
false => Err(generator.errors),
}
}
@@ -61,9 +55,7 @@ impl<'a> BytecodeGenerator<'a> {
pub fn parse(&mut self, tokens: &[Tracked<SemanticToken>], in_macro: bool) {
macro_rules! byte {
- ($byte:expr) => {
- self.bytecode.push($byte)
- };
+ ($byte:expr) => { self.bytecode.push($byte) };
}
macro_rules! double {
($double:expr) => {{
@@ -140,7 +132,7 @@ impl<'a> BytecodeGenerator<'a> {
}
}
- if !self.stack.is_empty() {
+ if !in_macro && !self.stack.is_empty() {
unreachable!("Uncaught unterminated block");
}
}
diff --git a/src/stages/syntactic.rs b/src/stages/syntactic.rs
index 6453ae0..59b8b95 100644
--- a/src/stages/syntactic.rs
+++ b/src/stages/syntactic.rs
@@ -37,7 +37,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
// Eat characters until the end character is found.
- macro_rules! is_any_end {
+ macro_rules! is_end {
($end:expr) => {
|t: &mut Tokeniser| {
t.eat_char() == Some($end)
@@ -45,15 +45,6 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
};
}
- // Eat characters until the end character is found without a preceding back-slash.
- macro_rules! is_plain_end {
- ($end:expr) => {
- |t: &mut Tokeniser| {
- t.eat_if(concat!('\\', $end)).is_some() || t.eat_char() == Some($end)
- }
- };
- }
-
loop {
// Eat leading whitespace.
while let Some(c) = t.peek_char() {
@@ -67,7 +58,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
let token = match c {
'"' => {
let source = t.get_source();
- match t.track_until(is_plain_end!('"')) {
+ match t.track_until(is_end!('"')) {
Some(string) => {
let mut bytes = string.into_bytes();
bytes.push(0x00);
@@ -78,14 +69,14 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
'\'' => {
let source = t.get_source();
- match t.track_until(is_plain_end!('\'')) {
+ match t.track_until(is_end!('\'')) {
Some(string) => SyntacticToken::String(string.into_bytes()),
None => err!(SyntacticError::UnterminatedRawString, source),
}
}
'(' => {
let source = t.get_source();
- if let Some(string) = t.track_until(is_any_end!(')')) {
+ if let Some(string) = t.track_until(is_end!(')')) {
// Check if the comment fills the entire line.
if t.start.position.column == 0 && t.end_of_line() {
if let Some(path) = string.strip_prefix(": ") {
@@ -105,7 +96,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
let source = t.get_source();
check_name!(name, source);
t.mark_child();
- if let Some(_) = t.track_until(is_any_end!(';')) {
+ if let Some(_) = t.track_until(is_end!(';')) {
let child = t.tokenise_child_span();
match parse_body_from_tokeniser(child, &label_name) {
Ok(body) => {
@@ -149,7 +140,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
},
':' => {
- SyntacticToken::Symbol(String::from(':'))
+ SyntacticToken::Instruction(Instruction { value: 0x21 })
}
c => {
let token = format!("{c}{}", t.eat_token());
diff --git a/src/stages/syntactic_tokens.rs b/src/stages/syntactic_tokens.rs
index 2a95967..35afa80 100644
--- a/src/stages/syntactic_tokens.rs
+++ b/src/stages/syntactic_tokens.rs
@@ -80,7 +80,7 @@ pub fn print_syntactic_token(i: usize, token: &SyntacticToken) {
SyntacticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)),
SyntacticToken::Comment(_) => indent!(i, "Comment"),
SyntacticToken::BlockOpen => indent!(i, "BlockOpen"),
- SyntacticToken::BlockClose => indent!(i, "BlockOpen"),
+ SyntacticToken::BlockClose => indent!(i, "BlockClose"),
SyntacticToken::Symbol(name) => indent!(i, "Symbol({name})"),
SyntacticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"),
SyntacticToken::LabelDefinition(name) => indent!(i, "LabelDefinition({name})"),