Commit 40113dc8 authored by Kai Rese's avatar Kai Rese
Browse files

format and lint

parent bcfc3fcb
/*!
# Arschitek_zero_assembler
This is an assembler for the arschitek_zero instruction set architecture.
*/
mod assembler;
use assembler::scanner;
use assembler::parser;
use assembler::assembler::assemble;
pub fn run(filename: &str) -> Result<(), Box<dyn std::error::Error>> {
let raw = std::fs::read_to_string(filename)?;
let tokens = scanner::scan(&raw);
let statements = parser::parse(&tokens)?;
let code = assemble(&statements)?;
let output_filename = String::from(filename) + ".out";
std::fs::write(output_filename, code)?;
Ok(())
}
\ No newline at end of file
/*!
# Arschitek_zero_assembler
This is an assembler for the arschitek_zero instruction set architecture.
*/
mod program;
use program::assembler::assemble;
use program::parser;
use program::scanner;
pub fn run(filename: &str) -> Result<(), Box<dyn std::error::Error>> {
let raw = std::fs::read_to_string(filename)?;
let tokens = scanner::scan(&raw);
let statements = parser::parse(&tokens)?;
let code = assemble(&statements)?;
let output_filename = String::from(filename) + ".out";
std::fs::write(output_filename, code)?;
Ok(())
}
extern crate arschitek_zero_assembler;
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() == 2 {
if let Err(e) = arschitek_zero_assembler::run(args[1].as_str()) {
println!("{}", e);
}
} else {
println!("Usage: {} <filename>", args[0]);
}
}
\ No newline at end of file
extern crate arschitek_zero_assembler;
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() == 2 {
if let Err(e) = arschitek_zero_assembler::run(args[1].as_str()) {
println!("{}", e);
}
} else {
println!("Usage: {} <filename>", args[0]);
}
}
pub mod error;
pub mod instruction;
pub mod token;
pub mod statement;
pub mod scanner;
pub mod parser;
pub mod assembler;
pub mod error;
pub mod instruction;
pub mod statement;
pub mod token;
pub mod assembler;
pub mod parser;
pub mod scanner;
use std::fmt::Display;
#[derive(Debug)]
pub struct Error {
pub kind: ErrorKind,
pub line_number: usize,
}
#[derive(Debug)]
pub struct ErrorVec {
errors: Vec<Error>
}
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
InvalidStatement(&'static str),
OperandType{
position: usize,
expected: &'static str,
other_expected: Option<&'static str>,
actual: &'static str
},
OperandCount{
expected: usize,
other_expected: Option<usize>,
actual: usize
},
ValueOutOfRange{ bits: u8, signed: bool, value: isize},
RedefinedLabel(String),
UndefinedIdentifier(String),
UndefinedLabel(String)
}
impl std::error::Error for Error {
fn source(&self) -> Option<&'static std::error::Error> { None }
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self.kind {
ErrorKind::InvalidStatement(token) => write!(
f, "Line {}: Expected operation or label, found {}", self.line_number, token),
ErrorKind::OperandType {
position, expected, other_expected, actual
} => {
let position_strings = ["first", "second", "third"];
if let Some(other_expected) = other_expected {
write!(f, "Line {}: Expected {} or {} as {} operand, found {}",
self.line_number, expected, other_expected, position_strings[*position],
actual)
} else {
write!(f, "Line {}: Expected {} as {} operand, found {}",
self.line_number, expected, position_strings[*position], actual)
}
},
ErrorKind::OperandCount {
expected, other_expected, actual
} => {
if let Some(other_expected) = other_expected {
write!(f, "Line {}: Expected {} or {} operands, found {}", self.line_number,
expected, other_expected, actual)
} else {
write!(f, "Line {}: Expected {} operands, found {}", self.line_number,
expected, actual)
}
},
ErrorKind::ValueOutOfRange {bits, signed, value} => {
if *signed {
write!(f, "Line {}: The immediate value is out of range, range is from \
{} to {}", self.line_number, -1 << (*bits - 1), (1 << (*bits - 1)) - 1)
} else {
if *value >= 0 {
write!(f, "Line {}: The unsigned immediate value is too big, maximum value \
is {}", self.line_number, (1 << *bits) - 1)
} else {
write!(f, "Line {}: The immediate value is unsigned and therefore must be \
positive", self.line_number)
}
}
},
ErrorKind::RedefinedLabel(name) => {
write!(f, "Line {}: The label \"{}\" has already been defined",
self.line_number, name)
},
ErrorKind::UndefinedLabel(name) => {
write!(f, "Line {}: Can't find the label \"{}\"", self.line_number, name)
},
ErrorKind::UndefinedIdentifier(name) => {
write!(f, "Line {}: Can't find the definition for \"{}\"", self.line_number, name)
}
}
}
}
impl PartialEq for Error {
fn eq(&self, other: &Error) -> bool {
(self.line_number == other.line_number) && (self.kind == other.kind)
}
}
impl ErrorVec {
pub fn new() -> ErrorVec {
ErrorVec{ errors: Vec::<Error>::new() }
}
pub fn len(&self) -> usize { self.errors.len() }
pub fn push(&mut self, error: Error) {
self.errors.push(error)
}
}
impl std::error::Error for ErrorVec {
fn source(&self) -> Option<&'static std::error::Error> { None }
}
impl std::fmt::Display for ErrorVec {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for error in &self.errors {
writeln!(f, "{}", error)?;
}
Ok(())
}
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", match self {
ErrorKind::InvalidStatement(..) => "Invalid statement",
ErrorKind::OperandType{..} => "Operand type",
ErrorKind::OperandCount{..} => "Operand count",
ErrorKind::ValueOutOfRange{..} => "Value out of range",
ErrorKind::UndefinedIdentifier(_) => "Undefined identifier",
ErrorKind::UndefinedLabel(_) => "Undefined label",
ErrorKind::RedefinedLabel(_) => "Redefined label"
})
}
}
\ No newline at end of file
use std::fmt::Display;
#[derive(Debug)]
pub struct Error {
pub kind: ErrorKind,
pub line_number: usize,
}
#[derive(Debug)]
pub struct ErrorVec {
errors: Vec<Error>,
}
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
InvalidStatement(&'static str),
OperandType {
position: usize,
expected: &'static str,
other_expected: Option<&'static str>,
actual: &'static str,
},
OperandCount {
expected: usize,
other_expected: Option<usize>,
actual: usize,
},
ValueOutOfRange {
bits: u8,
signed: bool,
value: isize,
},
RedefinedLabel(String),
UndefinedIdentifier(String),
UndefinedLabel(String),
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self.kind {
ErrorKind::InvalidStatement(token) => write!(
f,
"Line {}: Expected operation or label, found {}",
self.line_number, token
),
ErrorKind::OperandType {
position,
expected,
other_expected,
actual,
} => {
let position_strings = ["first", "second", "third"];
if let Some(other_expected) = other_expected {
write!(
f,
"Line {}: Expected {} or {} as {} operand, found {}",
self.line_number,
expected,
other_expected,
position_strings[*position],
actual
)
} else {
write!(
f,
"Line {}: Expected {} as {} operand, found {}",
self.line_number, expected, position_strings[*position], actual
)
}
}
ErrorKind::OperandCount {
expected,
other_expected,
actual,
} => {
if let Some(other_expected) = other_expected {
write!(
f,
"Line {}: Expected {} or {} operands, found {}",
self.line_number, expected, other_expected, actual
)
} else {
write!(
f,
"Line {}: Expected {} operands, found {}",
self.line_number, expected, actual
)
}
}
ErrorKind::ValueOutOfRange {
bits,
signed,
value,
} => {
if *signed {
write!(
f,
"Line {}: The immediate value is out of range, range is from \
{} to {}",
self.line_number,
-1 << (*bits - 1),
(1 << (*bits - 1)) - 1
)
} else if *value >= 0 {
write!(
f,
"Line {}: The unsigned immediate value is too big, maximum value \
is {}",
self.line_number,
(1 << *bits) - 1
)
} else {
write!(
f,
"Line {}: The immediate value is unsigned and therefore must be \
positive",
self.line_number
)
}
}
ErrorKind::RedefinedLabel(name) => {
write!(
f,
"Line {}: The label \"{}\" has already been defined",
self.line_number, name
)
}
ErrorKind::UndefinedLabel(name) => {
write!(
f,
"Line {}: Can't find the label \"{}\"",
self.line_number, name
)
}
ErrorKind::UndefinedIdentifier(name) => {
write!(
f,
"Line {}: Can't find the definition for \"{}\"",
self.line_number, name
)
}
}
}
}
impl PartialEq for Error {
fn eq(&self, other: &Error) -> bool {
(self.line_number == other.line_number) && (self.kind == other.kind)
}
}
impl ErrorVec {
pub fn new() -> ErrorVec {
ErrorVec {
errors: Vec::<Error>::new(),
}
}
pub fn len(&self) -> usize {
self.errors.len()
}
pub fn push(&mut self, error: Error) {
self.errors.push(error)
}
}
impl std::error::Error for ErrorVec {}
impl std::fmt::Display for ErrorVec {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for error in &self.errors {
writeln!(f, "{}", error)?;
}
Ok(())
}
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match self {
ErrorKind::InvalidStatement(..) => "Invalid statement",
ErrorKind::OperandType { .. } => "Operand type",
ErrorKind::OperandCount { .. } => "Operand count",
ErrorKind::ValueOutOfRange { .. } => "Value out of range",
ErrorKind::UndefinedIdentifier(_) => "Undefined identifier",
ErrorKind::UndefinedLabel(_) => "Undefined label",
ErrorKind::RedefinedLabel(_) => "Redefined label",
}
)
}
}
use std::fmt::Display;
pub fn get_instruction_type(name: &str) -> Option<InstructionToken> {
if let Ok(index) = INSTRUCTION_CODE_TABLE.binary_search_by(
|entry| {entry.0.cmp(name.to_ascii_lowercase().as_str())}) {
Some(INSTRUCTION_CODE_TABLE[index].1)
} else {
None
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum InstructionToken {
Add,
Sub,
SetTarget,
Load,
Store,
Jump,
BranchEqual,
BranchGreater,
ShiftLeft,
ShiftRight,
BoolTable,
Stop,
Data
}
#[derive(Debug, PartialEq)]
pub enum InstructionStatement<'a> {
AddReg(&'a str, &'a str, &'a str),
AddImm(&'a str, isize),
Sub(&'a str, &'a str, &'a str),
SetTarget(&'a str, Option<&'a str>, isize),
LoadReg(&'a str, &'a str, &'a str),
LoadImm(&'a str, Option<&'a str>, isize),
StoreReg(&'a str, &'a str, &'a str),
StoreImm(&'a str, Option<&'a str>, isize),
JumpImm(Option<&'a str>, isize),
JumpReg(&'a str, isize),
BranchEqualZero(&'a str, Option<&'a str>, isize),
BranchGreaterZero(&'a str, Option<&'a str>, isize),
ShiftLeft(&'a str, &'a str, isize),
ShiftRight(&'a str, &'a str, isize),
BoolTable(&'a str, &'a str, isize),
Stop,
Data(isize, Option<&'a str>)
}
impl Display for InstructionToken {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", match self {
InstructionToken::Add => "Add",
InstructionToken::Sub => "Sub",
InstructionToken::SetTarget => "Set Target",
InstructionToken::Load => "Load",
InstructionToken::Store => "Store",
InstructionToken::Jump => "Jump",
InstructionToken::BranchEqual => "Branch when equal to zero",
InstructionToken::BranchGreater => "Branch when greater than zero",
InstructionToken::ShiftLeft => "Shift left",
InstructionToken::ShiftRight => "Shift right",
InstructionToken::BoolTable => "Bool table",
InstructionToken::Stop => "Stop",
InstructionToken::Data => "Data"
})
}
}
const INSTRUCTION_CODE_TABLE: [(&str, InstructionToken); 13] = [
("add", InstructionToken::Add),
("bez", InstructionToken::BranchEqual),
("bgz", InstructionToken::BranchGreater),
("botab", InstructionToken::BoolTable),
("data", InstructionToken::Data),
("jmp", InstructionToken::Jump),
("load", InstructionToken::Load),
("shftl", InstructionToken::ShiftLeft),
("shftr", InstructionToken::ShiftRight),
("stg", InstructionToken::SetTarget),
("stop", InstructionToken::Stop),
("store", InstructionToken::Store),
("sub", InstructionToken::Sub),
];
\ No newline at end of file
use std::fmt::Display;
pub fn get_instruction_type(name: &str) -> Option<InstructionToken> {
if let Ok(index) = INSTRUCTION_CODE_TABLE
.binary_search_by(|entry| entry.0.cmp(name.to_ascii_lowercase().as_str()))
{
Some(INSTRUCTION_CODE_TABLE[index].1)
} else {
None
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum InstructionToken {
Add,
Sub,
SetTarget,
Load,
Store,
Jump,
BranchEqual,
BranchGreater,
ShiftLeft,
ShiftRight,
BoolTable,
Stop,
Data,
}
#[derive(Debug, PartialEq)]
pub enum InstructionStatement<'a> {
AddReg(&'a str, &'a str, &'a str),
AddImm(&'a str, isize),
Sub(&'a str, &'a str, &'a str),
SetTarget(&'a str, Option<&'a str>, isize),
LoadReg(&'a str, &'a str, &'a str),
LoadImm(&'a str, Option<&'a str>, isize),
StoreReg(&'a str, &'a str, &'a str),
StoreImm(&'a str, Option<&'a str>, isize),
JumpImm(Option<&'a str>, isize),
JumpReg(&'a str, isize),
BranchEqualZero(&'a str, Option<&'a str>, isize),
BranchGreaterZero(&'a str, Option<&'a str>, isize),
ShiftLeft(&'a str, &'a str, isize),
ShiftRight(&'a str, &'a str, isize),
BoolTable(&'a str, &'a str, isize),
Stop,
Data(isize, Option<&'a str>),
}
impl Display for InstructionToken {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match self {
InstructionToken::Add => "Add",
InstructionToken::Sub => "Sub",
InstructionToken::SetTarget => "Set Target",
InstructionToken::Load => "Load",
InstructionToken::Store => "Store",
InstructionToken::Jump => "Jump",
InstructionToken::BranchEqual => "Branch when equal to zero",
InstructionToken::BranchGreater => "Branch when greater than zero",
InstructionToken::ShiftLeft => "Shift left",
InstructionToken::ShiftRight => "Shift right",
InstructionToken::BoolTable => "Bool table",
InstructionToken::Stop => "Stop",
InstructionToken::Data => "Data",
}
)
}
}
const INSTRUCTION_CODE_TABLE: [(&str, InstructionToken); 13] = [
("add", InstructionToken::Add),
("bez", InstructionToken::BranchEqual),
("bgz", InstructionToken::BranchGreater),
("botab", InstructionToken::BoolTable),
("data", InstructionToken::Data),
("jmp", InstructionToken::Jump),
("load", InstructionToken::Load),
("shftl", InstructionToken::ShiftLeft),
("shftr", InstructionToken::ShiftRight),
("stg", InstructionToken::SetTarget),
("stop", InstructionToken::Stop),
("store", InstructionToken::Store),
("sub", InstructionToken::Sub),
];