parsing seems to be working fine
This commit is contained in:
30
src/asm.pest
Normal file
30
src/asm.pest
Normal file
@@ -0,0 +1,30 @@
|
||||
program = _{ SOI ~ "\n"* ~ (stmt ~ "\n"+) * ~ stmt? ~ EOI }
|
||||
|
||||
|
||||
stmt = { ((label ~ ":")? ~ instruction)}
|
||||
|
||||
|
||||
instruction = {
|
||||
no_arg_instruction |
|
||||
arg_instruction ~ argument |
|
||||
jump_instruction ~ jump_argument |
|
||||
memory_location_instruction ~ memory_location |
|
||||
constant_arg_instruction ~ digit_literal
|
||||
}
|
||||
|
||||
memory_location_instruction = {"STA"}
|
||||
constant_arg_instruction = {"BRZ" | "BRC" | "BRN"}
|
||||
jump_instruction = {"JMP"}
|
||||
arg_instruction = {"LDA" | "ADD" | "SUB"}
|
||||
no_arg_instruction = { "NOP" }
|
||||
|
||||
jump_argument = { jump_location | label}
|
||||
argument = { memory_location | digit_literal }
|
||||
memory_location = { "(" ~ ASCII_HEX_DIGIT ~")" }
|
||||
digit_literal = {"#" ~ ASCII_HEX_DIGIT}
|
||||
jump_location = { ASCII_HEX_DIGIT }
|
||||
|
||||
label = { ASCII_ALPHA_UPPER+ }
|
||||
|
||||
WHITESPACE = _{ " " | "\t" }
|
||||
COMMENT = _{"//" ~ (!"\n" ~ ANY)* }
|
||||
51
src/asm.rs
Normal file
51
src/asm.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Argument {
|
||||
MemoryLocation(u8),
|
||||
Constant(u8)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Label<'a>{
|
||||
pub name: &'a str,
|
||||
pub location: u8
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum JumpArgument<'a> {
|
||||
Location(u8),
|
||||
Label(&'a str)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Instruction<'a> {
|
||||
NoArgumentInstruction(NoArgumentInstruction, Option<Label<'a>>),
|
||||
MemoryLocationInstruction(MemoryLocationInstruction, Option<Label<'a>>),
|
||||
ConstantArgumentInstruction(ConstantArgumentInstruction, Option<Label<'a>>),
|
||||
ArgumentInstruction(ArgumentInstruction, Option<Label<'a>>),
|
||||
Jump(JumpArgument<'a>, Option<Label<'a>>)
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NoArgumentInstruction {
|
||||
NOP
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MemoryLocationInstruction {
|
||||
STA(u8)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ConstantArgumentInstruction {
|
||||
BRZ(u8),
|
||||
BRC(u8),
|
||||
BRN(u8)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ArgumentInstruction {
|
||||
LDA(Argument),
|
||||
ADD(Argument),
|
||||
SUB(Argument),
|
||||
}
|
||||
0
src/generate.rs
Normal file
0
src/generate.rs
Normal file
32
src/main.rs
Normal file
32
src/main.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use std::fs;
|
||||
use std::env;
|
||||
|
||||
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
use pest::Parser;
|
||||
|
||||
|
||||
mod asm;
|
||||
mod parse;
|
||||
mod generate;
|
||||
|
||||
use parse::{parse_asm, AsmParser};
|
||||
|
||||
fn main() {
|
||||
let file_name = env::args().nth(1);
|
||||
|
||||
let file_content = match file_name {
|
||||
Some(file_name) => {
|
||||
fs::read_to_string(file_name).expect("Could not read the provided asm file")
|
||||
}
|
||||
None => {
|
||||
println!("No input file was provided");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let instructions = parse_asm(AsmParser::parse(parse::Rule::program, &file_content).unwrap_or_else(|e| panic!("{}", e)));
|
||||
println!("{:#?}", instructions);
|
||||
}
|
||||
137
src/parse.rs
Normal file
137
src/parse.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
use crate::asm::*;
|
||||
use pest::iterators::{Pair, Pairs};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "asm.pest"]
|
||||
pub struct AsmParser;
|
||||
|
||||
pub fn parse_asm<'a>(pairs: Pairs<'a, Rule>) -> Vec<Instruction<'a>> {
|
||||
let mut instruction = Vec::new();
|
||||
let mut instruction_counter = 0;
|
||||
for stmnt in pairs {
|
||||
if let Rule::stmt = stmnt.as_rule() {
|
||||
let mut stmnt = stmnt.into_inner();
|
||||
let first = stmnt.next();
|
||||
let second = stmnt.next();
|
||||
|
||||
// Second can only be Some if we have a label, thus second must be the
|
||||
// instruction if that is the case.
|
||||
if second.is_some() {
|
||||
instruction.push(parse_instruction(second.unwrap(), first, instruction_counter));
|
||||
} else {
|
||||
instruction.push(parse_instruction(first.unwrap(), None, instruction_counter));
|
||||
}
|
||||
|
||||
instruction_counter += 1;
|
||||
}
|
||||
|
||||
if instruction_counter > 15 {
|
||||
panic!("This program contains more than 16 instructions, that is impossible on this processor");
|
||||
}
|
||||
}
|
||||
instruction
|
||||
}
|
||||
|
||||
fn parse_instruction<'a>(instruction: Pair<'a, Rule>, label: Option<Pair<'a, Rule>>, instruction_counter: u8) -> Instruction<'a>{
|
||||
let label = label.map(|l| parse_label(l, instruction_counter));
|
||||
let mut instruction = instruction.into_inner();
|
||||
let mnemonic = instruction.next().unwrap();
|
||||
|
||||
match mnemonic.as_rule() {
|
||||
Rule::no_arg_instruction => parse_no_arg_instruction(mnemonic, label),
|
||||
Rule::arg_instruction => {
|
||||
parse_arg_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
},
|
||||
Rule::jump_instruction => {
|
||||
parse_jump_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
},
|
||||
Rule::memory_location_instruction => {
|
||||
parse_memory_location_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
},
|
||||
Rule::constant_arg_instruction => {
|
||||
parse_constant_arg_instruction(mnemonic, instruction.next().unwrap(), label)
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_no_arg_instruction<'a>(instruction: Pair<'a, Rule>, label: Option<Label<'a>>) -> Instruction<'a> {
|
||||
match instruction.as_str() {
|
||||
"NOP" => Instruction::NoArgumentInstruction(NoArgumentInstruction::NOP, label),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arg_instruction<'a>(instruction: Pair<'a, Rule>, arg: Pair<'a, Rule>, label: Option<Label<'a>>) -> Instruction<'a> {
|
||||
let arg = parse_argument(arg);
|
||||
match instruction.as_str() {
|
||||
"LDA" => Instruction::ArgumentInstruction(ArgumentInstruction::LDA(arg), label),
|
||||
"ADD" => Instruction::ArgumentInstruction(ArgumentInstruction::ADD(arg), label),
|
||||
"SUB" => Instruction::ArgumentInstruction(ArgumentInstruction::SUB(arg), label),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_jump_instruction<'a>(instruction: Pair<'a, Rule>, arg: Pair<'a, Rule>, label: Option<Label<'a>>) -> Instruction<'a> {
|
||||
let arg = parse_jump_argument(arg);
|
||||
match instruction.as_str() {
|
||||
"JMP" => Instruction::Jump(arg, label),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_memory_location_instruction<'a>(instruction: Pair<'a, Rule>, arg: Pair<'a, Rule>,label: Option<Label<'a>>) -> Instruction<'a> {
|
||||
let arg_string = arg.as_str();
|
||||
let arg_value = u8::from_str_radix(&arg_string[1..arg_string.len()-1], 16).unwrap();
|
||||
match instruction.as_str() {
|
||||
"STA" => Instruction::MemoryLocationInstruction(MemoryLocationInstruction::STA(arg_value), label),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_constant_arg_instruction<'a>(instruction: Pair<'a, Rule>, arg: Pair<'a, Rule>, label: Option<Label<'a>>) -> Instruction<'a> {
|
||||
let arg_value = u8::from_str_radix(&arg.as_str()[1..], 16).unwrap();
|
||||
match instruction.as_str() {
|
||||
"BRZ" => Instruction::ConstantArgumentInstruction(ConstantArgumentInstruction::BRZ(arg_value), label),
|
||||
"BRC" => Instruction::ConstantArgumentInstruction(ConstantArgumentInstruction::BRC(arg_value), label),
|
||||
"BRN" => Instruction::ConstantArgumentInstruction(ConstantArgumentInstruction::BRN(arg_value), label),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_argument<'a>(argument: Pair<'a, Rule>) -> Argument {
|
||||
let argument = argument.into_inner().next().unwrap();
|
||||
match argument.as_rule() {
|
||||
Rule::memory_location => {
|
||||
let arg_string = argument.as_str();
|
||||
let arg_value = u8::from_str_radix(&arg_string[1..arg_string.len()-1], 16).unwrap();
|
||||
Argument::MemoryLocation(arg_value)
|
||||
},
|
||||
Rule::digit_literal => {
|
||||
let arg_value = u8::from_str_radix(&argument.as_str()[1..], 16).unwrap();
|
||||
Argument::Constant(arg_value)
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_label<'a>(label: Pair<'a, Rule>, instruction_counter: u8) -> Label<'a> {
|
||||
match label.as_rule() {
|
||||
Rule::label => {
|
||||
Label {
|
||||
name: label.as_str(),
|
||||
location: instruction_counter
|
||||
}
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_jump_argument<'a>(arg: Pair<'a, Rule>) -> JumpArgument<'a> {
|
||||
let arg = arg.into_inner().next().unwrap();
|
||||
match arg.as_rule() {
|
||||
Rule::label => JumpArgument::Label(arg.as_str()),
|
||||
Rule::jump_location => JumpArgument::Location(u8::from_str_radix(arg.as_str(), 16).unwrap()),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user