Commit 9aca9c57 authored by Fletcher Haynes's avatar Fletcher Haynes
Browse files

Merge branch 'part-16' into 'master'

Part 16 of Tutorial

See merge request !1
parents 00688107 26ef6227
Pipeline #29158069 passed with stage
in 2 minutes and 56 seconds
[[package]]
name = "aho-corasick"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
......@@ -21,6 +29,16 @@ name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.32.0"
......@@ -36,22 +54,61 @@ dependencies = [
"yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "humantime"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iridium"
version = "0.0.1"
dependencies = [
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.0.1"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -62,9 +119,14 @@ name = "nom"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_syscall"
version = "0.1.40"
......@@ -78,11 +140,39 @@ dependencies = [
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "termcolor"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
......@@ -101,16 +191,39 @@ dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.5"
......@@ -125,32 +238,66 @@ name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wincolor"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "yaml-rust"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2"
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
"checksum nom 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "898696750eb5c3ce5eb5afbfbe46e7f7c4e1936e19d3e97be4b7937da7b6d114"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "67d0301b0c6804eca7e3c275119d0b01ff3b7ab9258a65709e608a66312a1025"
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3390f44f1f706d8870297b6a2c4f92d9ab65a37c265fbbc6ac4ee72bcc2f3698"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
......@@ -10,6 +10,9 @@ repository = "https://gitlab.com/subnetzero/iridium"
[dependencies]
nom = "^4.0"
clap = { version = "2.32", features = ["yaml"] }
log = "0.4"
env_logger = "0.5.13"
byteorder = "1"
[profile.dev]
opt-level = 0
......
use std::fmt;
use std::error::Error;
#[derive(Debug, Clone)]
pub enum AssemblerError {
NoSegmentDeclarationFound{ instruction: u32 },
StringConstantDeclaredWithoutLabel{ instruction: u32 },
SymbolAlreadyDeclared,
UnknownDirectiveFound{ directive: String },
NonOpcodeInOpcodeField,
InsufficientSections,
ParseError{ error: String }
}
impl fmt::Display for AssemblerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AssemblerError::NoSegmentDeclarationFound{ instruction } => {
f.write_str(&format!("No segment declaration (e.g., .code, .data) prior to finding an opcode or other directive. Instruction # was {}:", instruction))
}
AssemblerError::StringConstantDeclaredWithoutLabel{ instruction } => {
f.write_str(&format!("Found a string constant without a corresponding label. Instruction # was {}: ", instruction))
}
AssemblerError::SymbolAlreadyDeclared => {
f.write_str("This symbol was previously declared.")
}
AssemblerError::UnknownDirectiveFound { ref directive } => {
f.write_str(&format!("Invalid or unknown directive found. Directive name was: {}", directive))
}
AssemblerError::NonOpcodeInOpcodeField => {
f.write_str("An non-opcode was found in an opcode field")
}
AssemblerError::InsufficientSections => {
f.write_str("Less than two sections/segments were found in the code")
}
AssemblerError::ParseError{ ref error } => {
f.write_str(&format!("There was an error parsing the code: {}", error))
}
}
}
}
impl Error for AssemblerError {
fn description(&self) -> &str {
match self {
AssemblerError::NoSegmentDeclarationFound{ .. } => {
"No segment declaration (e.g., .code, .data) prior to finding an opcode or other directive."
}
AssemblerError::StringConstantDeclaredWithoutLabel{ .. } => {
"Found a string constant without a corresponding label."
}
AssemblerError::SymbolAlreadyDeclared => {
"This symbol was previously declared."
}
AssemblerError::UnknownDirectiveFound{ .. } => {
"Invalid or unknown directive found."
}
AssemblerError::NonOpcodeInOpcodeField => {
"A non-opcode was found in an opcode field"
}
AssemblerError::InsufficientSections => {
"Less than two sections/segments were found in the code"
}
AssemblerError::ParseError{ .. } => {
"There was an error parsing the code"
}
}
}
}
......@@ -3,6 +3,7 @@ use nom::types::CompleteStr;
use assembler::instruction_parsers::AssemblerInstruction;
use assembler::Token;
use assembler::label_parsers::label_declaration;
use assembler::operand_parsers::operand;
named!(directive_declaration<CompleteStr, Token>,
......@@ -18,7 +19,7 @@ named!(directive_declaration<CompleteStr, Token>,
named!(directive_combined<CompleteStr, AssemblerInstruction>,
ws!(
do_parse!(
tag!(".") >>
l: opt!(label_declaration) >>
name: directive_declaration >>
o1: opt!(operand) >>
o2: opt!(operand) >>
......@@ -27,7 +28,7 @@ named!(directive_combined<CompleteStr, AssemblerInstruction>,
AssemblerInstruction{
opcode: None,
directive: Some(name),
label: None,
label: l,
operand1: o1,
operand2: o2,
operand3: o3,
......@@ -52,8 +53,9 @@ named!(pub directive<CompleteStr, AssemblerInstruction>,
mod tests {
#![allow(unused_imports)]
use nom::types::CompleteStr;
use super::directive_declaration;
use assembler::Token;
use super::{directive_declaration, directive_combined};
use assembler::{Token};
use assembler::instruction_parsers::AssemblerInstruction;
#[test]
fn test_parser_directive() {
......@@ -62,4 +64,29 @@ mod tests {
let (_, directive) = result.unwrap();
assert_eq!(directive, Token::Directive{name: "data".to_string() })
}
#[test]
fn test_string_directive() {
let result = directive_combined(CompleteStr("test: .asciiz 'Hello'"));
assert_eq!(result.is_ok(), true);
let (_, directive) = result.unwrap();
// Yes, this is the what the result should be
let correct_instruction =
AssemblerInstruction {
opcode: None,
label: Some(
Token::LabelDeclaration {
name: "test".to_string()
}),
directive: Some(
Token::Directive {
name: "asciiz".to_string()
}),
operand1: Some(Token::IrString { name: "Hello".to_string() }),
operand2: None,
operand3: None };
assert_eq!(directive, correct_instruction);
}
}
use std;
use nom::types::CompleteStr;
use assembler::opcode_parsers::*;
......@@ -19,28 +17,25 @@ pub struct AssemblerInstruction {
impl AssemblerInstruction {
pub fn to_bytes(&self, symbols: &SymbolTable) -> Vec<u8> {
let mut results = vec![];
match self.opcode {
Some(ref token) => {
match token {
Token::Op { code } => match code {
_ => {
results.push(*code as u8);
}
},
if let Some(ref token) = self.opcode {
match token {
Token::Op { code } => match code {
_ => {
println!("Non-opcode found in opcode field");
std::process::exit(1);
results.push(*code as u8);
}
},
_ => {
println!("Non-opcode found in opcode field");
}
}
None => {},
};
}
for operand in &[&self.operand1, &self.operand2, &self.operand3] {
if let Some(token) = operand {
AssemblerInstruction::extract_operand(token, &mut results, symbols)
}
}
while results.len() < 4 {
results.push(0);
}
......@@ -60,7 +55,42 @@ impl AssemblerInstruction {
self.directive.is_some()
}
pub fn label_name(&self) -> Option<String> {
/// Checks if the AssemblyInstruction has any operands at all
pub fn has_operands(&self) -> bool {
self.operand1.is_some() ||
self.operand2.is_some() ||
self.operand3.is_some()
}
pub fn get_directive_name(&self) -> Option<String> {
match &self.directive {
Some(d) => {
match d {
Token::Directive { name } => {
Some(name.to_string())
}
_ => { None }
}
}
None => { None }
}
}
pub fn get_string_constant(&self) -> Option<String> {
match &self.operand1 {
Some(d) => {
match d {
Token::IrString { name } => {
Some(name.to_string())
}
_ => None
}
}
None => { None }
}
}
pub fn get_label_name(&self) -> Option<String> {
match &self.label {
Some(l) => {
match l {
......@@ -89,19 +119,15 @@ impl AssemblerInstruction {
results.push(byte1 as u8);
}
Token::LabelUsage { name } => {
match symbols.symbol_value(name) {
Some(value) => {
let byte1 = value;
let byte2 = value >> 8;
results.push(byte2 as u8);
results.push(byte1 as u8);
},
None => {}
if let Some(value) = symbols.symbol_value(name) {
let byte1 = value;
let byte2 = value >> 8;
results.push(byte2 as u8);
results.push(byte1 as u8);
}
}
_ => {
println!("Opcode found in operand field");
std::process::exit(1);
println!("Opcode found in operand field: {:#?}", t);
}
};
}
......
......@@ -5,13 +5,22 @@ pub mod program_parsers;
pub mod register_parsers;
pub mod label_parsers;
pub mod directive_parsers;
pub mod assembler_errors;
pub mod symbols;
use nom::types::CompleteStr;
use instruction::Opcode;
use assembler::program_parsers::{program, Program};
use assembler::instruction_parsers::{AssemblerInstruction};
use assembler::assembler_errors::AssemblerError;
use assembler::symbols::{Symbol, SymbolTable, SymbolType};
/// Magic number that begins every bytecode file prefix. These spell out EPIE in ASCII, if you were wondering.
pub const PIE_HEADER_PREFIX: [u8; 4] = [45, 50, 49, 45];
/// Constant that determines how long the header is. There are 60 zeros left after the prefix, for later
/// usage if needed.
pub const PIE_HEADER_LENGTH: usize = 64;
#[derive(Debug, PartialEq)]
......@@ -21,76 +30,233 @@ pub enum Token {
IntegerOperand { value: i32 },
LabelDeclaration { name: String },
LabelUsage { name: String },
Directive { name: String }
Directive { name: String },
IrString { name: String }
}
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct Assembler {
/// Tracks which phase the assember is in
phase: AssemblerPhase,
pub symbols: SymbolTable
/// Symbol table for constants and variables
pub symbols: SymbolTable,
/// The read-only data section constants are put in
pub ro: Vec<u8>,
/// The compiled bytecode generated from the assembly instructions
pub bytecode: Vec<u8>,
/// Tracks the current offset of the read-only section
ro_offset: u32,
/// A list of all the sections we've seen in the code
sections: Vec<AssemblerSection>,
/// The current section the assembler is in
current_section: Option<AssemblerSection>,
/// The current instruction the assembler is converting to bytecode
current_instruction: u32,
/// Any errors we find along the way. At the end, we'll present them to the user.
errors: Vec<AssemblerError>
}
impl Assembler {
pub fn new() -> Assembler {
Assembler {
current_instruction: 0,
ro_offset: 0,
ro: vec![],
bytecode: vec![],
sections: vec![],
errors: vec![],
phase: AssemblerPhase::First,
symbols: SymbolTable::new(),
current_section: None
}
}
pub fn assemble(&mut self, raw: &str) -> Option<Vec<u8>> {
pub fn assemble(&mut self, raw: &str) -> Result<Vec<u8>, Vec<AssemblerError>> {
match program(CompleteStr(raw)) {
Ok((_remainder, program)) => {
// First get the header so we can smush it into the bytecode letter
let mut assembled_program = self.write_pie_header();
// Start processing the AssembledInstructions
self.process_first_phase(&program);
if !self.errors.is_empty() {
// TODO: Can we avoid a clone here?
return Err(self.errors.clone());
};
// Make sure that we have at least one data section and one code section
if self.sections.len() != 2 {
// TODO: Detail out which one(s) are missing
println!("Did not find at least two sections.");
self.errors.push(AssemblerError::InsufficientSections);
// TODO: Can we avoid a clone here?
return Err(self.errors.clone());
}
// Run the second pass, which translates opcodes and associated operands into the bytecode
let mut body = self.process_second_phase(&program);
// Merge the header with the populated body vector
assembled_program.append(&mut body);
Some(assembled_program)
Ok(assembled_program)
},
// If there were parsing errors, bad syntax, etc, this arm is run
Err(e) => {
println!("There was an error assembling the code: {:?}", e);
None
println!("There was an error parsing the code: {:?}", e);
Err(vec![AssemblerError::ParseError{ error: e.to_string() }])
}
}
}
/// Runs the first pass of the two-pass assembling process. It looks for labels and puts them in the symbol table
fn process_first_phase(&mut self, p: &Program) {