From 36dc5d5ed41466e44781c583b788a75c7ad4b35d Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Wed, 16 Mar 2022 23:47:20 -0500 Subject: [PATCH] Some refactoring --- vasm/src/ast.rs | 119 ---------------------------------------- vasm/src/vasm.pest | 2 +- vasm/src/vasm_parser.rs | 111 ++++++++++++++++++++++++++++++++++--- 3 files changed, 104 insertions(+), 128 deletions(-) diff --git a/vasm/src/ast.rs b/vasm/src/ast.rs index a1d6eaf..cac6b73 100644 --- a/vasm/src/ast.rs +++ b/vasm/src/ast.rs @@ -1,32 +1,7 @@ -use std::str::FromStr; - -use pest::iterators::Pair; - use vcore::opcodes::Opcode; -use crate::vasm_parser::Rule; use std::fmt::{Display, Formatter}; -/// A non-opcode directive to the assembler -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum Directive { - Db, - Equ, - Org, -} - -impl From> for Directive { - fn from(value: Pair) -> Self { - use Directive::*; - match value.as_str() { - ".db" => Db, - ".equ" => Equ, - ".org" => Org, - _ => unreachable!(), - } - } -} - /// One of the five arithmetical operators #[derive(Debug, PartialEq, Copy, Clone)] pub enum Operator { @@ -37,20 +12,6 @@ pub enum Operator { Mod, } -impl From> for Operator { - fn from(s: Pair) -> Self { - use Operator::*; - match s.as_str() { - "+" => Add, - "-" => Sub, - "*" => Mul, - "/" => Div, - "%" => Mod, - _ => unreachable!(), - } - } -} - /// An AST node for an instruction argument. This can be a string, number, label reference, /// line offset, or an expr containing a sequence of other Nodes joined by same-precedence /// `Operator`s. @@ -65,86 +26,6 @@ pub enum Node<'a> { Expr(Box>, Vec<(Operator, Node<'a>)>), } -impl<'a> Node<'a> { - /// Create a `Node` containing the string represented by a given pair. Since the pair will - /// reference bytes containing escape sequences, this isn't the same as an &str to the - /// original code; this is a new string translating those escape sequences to their actual - /// bytes. - fn string(pair: Pair<'a, Rule>) -> Node<'a> { - let mut string = String::with_capacity(pair.as_str().len()); - for inner in pair.into_inner() { - let string_inner = inner.as_str(); - match string_inner { - "\\t" => string.push('\t'), - "\\r" => string.push('\r'), - "\\n" => string.push('\n'), - "\\0" => string.push('\0'), - "\\\\" => string.push('\\'), - "\\\"" => string.push('\"'), - _ => string.push_str(string_inner), - } - } - Node::String(string) - } - - /// Create a `Node` containing the line offset represented by a pair. - fn line_offset(pair: Pair<'a, Rule>) -> Node<'a> { - let outer = pair.as_rule(); - let mut inner = pair.into_inner(); - let sign = inner.next().unwrap().as_str(); - let mut num = i32::from_str(inner.next().unwrap().as_str()).unwrap(); - if sign == "-" { - num *= -1 - } - match outer { - Rule::relative_line_offset => Node::RelativeOffset(num), - Rule::absolute_line_offset => Node::AbsoluteOffset(num), - _ => unreachable!(), - } - } -} - -impl<'a> From> for Node<'a> { - /// Parse a given pair into the `Node` it represents. The result of this is a - /// `Node` that might contain a borrow of part of the original code, but which in no way - /// depends on the original pair's object model. - fn from(pair: Pair<'a, Rule>) -> Self { - match pair.as_rule() { - Rule::expr | Rule::term => { - let mut iter = pair.into_inner(); - let first = Node::from(iter.next().unwrap()); - let mut rest = Vec::<(Operator, Node)>::new(); - - while let Some(operator) = iter.next() { - let rhs = iter.next().unwrap(); - let op = Operator::from(operator); - let node = Node::from(rhs); - rest.push((op, node)); - } - Node::Expr(Box::from(first), rest) - } - Rule::fact | Rule::number => Node::from(pair.into_inner().next().unwrap()), - Rule::dec_number | Rule::dec_zero | Rule::neg_number => { - Node::Number(i32::from_str(pair.as_str()).unwrap()) - } - Rule::hex_number => { - Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 16).unwrap()) - } - Rule::bin_number => { - Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 2).unwrap()) - } - Rule::oct_number => { - Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 8).unwrap()) - } - Rule::string => Node::string(pair), - Rule::label => Node::Label(pair.as_str()), - Rule::relative_label => Node::RelativeLabel(pair.as_str().get(1..).unwrap()), - Rule::absolute_line_offset | Rule::relative_line_offset => Node::line_offset(pair), - _ => unreachable!(), - } - } -} - #[derive(Debug, PartialEq, Clone)] pub struct Label<'a>(pub &'a str); diff --git a/vasm/src/vasm.pest b/vasm/src/vasm.pest index c779eae..469bd8b 100644 --- a/vasm/src/vasm.pest +++ b/vasm/src/vasm.pest @@ -44,7 +44,7 @@ sign = { "+" | "-" } term_op = { "/" | "*" | "%" } expr = { term ~ (sign ~ term)* } term = { fact ~ (term_op ~ fact)* } -fact = { ("(" ~ expr ~ ")") | (number | relative_line_offset | relative_label | absolute_line_offset | label) } +fact = { ("(" ~ expr ~ ")") | number | relative_line_offset | relative_label | absolute_line_offset | label } // Likewise, .db would get tedious quick without a string syntax, so, let's define one of those. An escape // sequence is a backslash followed by certain other characters: diff --git a/vasm/src/vasm_parser.rs b/vasm/src/vasm_parser.rs index dcff99f..f564617 100644 --- a/vasm/src/vasm_parser.rs +++ b/vasm/src/vasm_parser.rs @@ -4,12 +4,17 @@ use pest::Parser; use vcore::opcodes::Opcode; -use crate::ast::{Label, Node, VASMLine}; +use crate::ast::{Label, Node, Operator, VASMLine}; use crate::parse_error::ParseError; +use std::str::FromStr; -#[derive(Parser)] -#[grammar = "vasm.pest"] -pub struct VASMParser; +mod inner { + #[derive(Parser)] + #[grammar = "vasm.pest"] + pub struct VASMParser; +} + +use inner::*; type Pair<'a> = pest::iterators::Pair<'a, Rule>; @@ -47,6 +52,96 @@ fn shake(node: Node) -> Node { } } +impl From> for Operator { + fn from(s: Pair) -> Self { + use Operator::*; + match s.as_str() { + "+" => Add, + "-" => Sub, + "*" => Mul, + "/" => Div, + "%" => Mod, + _ => unreachable!(), + } + } +} + +/// Create a `Node` containing the string represented by a given pair. Since the pair will +/// reference bytes containing escape sequences, this isn't the same as an &str to the +/// original code; this is a new string translating those escape sequences to their actual +/// bytes. +fn create_string_node(pair: Pair) -> Node { + let mut string = String::with_capacity(pair.as_str().len()); + for inner in pair.into_inner() { + let string_inner = inner.as_str(); + match string_inner { + "\\t" => string.push('\t'), + "\\r" => string.push('\r'), + "\\n" => string.push('\n'), + "\\0" => string.push('\0'), + "\\\\" => string.push('\\'), + "\\\"" => string.push('\"'), + _ => string.push_str(string_inner), + } + } + Node::String(string) +} + +/// Create a `Node` containing the line offset represented by a pair. +fn create_line_offset_node(pair: Pair) -> Node { + let outer = pair.as_rule(); + let mut inner = pair.into_inner(); + let sign = inner.next().unwrap().as_str(); + let mut num = i32::from_str(inner.next().unwrap().as_str()).unwrap(); + if sign == "-" { + num *= -1 + } + match outer { + Rule::relative_line_offset => Node::RelativeOffset(num), + Rule::absolute_line_offset => Node::AbsoluteOffset(num), + _ => unreachable!(), + } +} + +/// Parse a given pair into the `Node` it represents. The result of this is a +/// `Node` that might contain a borrow of part of the original code, but which in no way +/// depends on the original pair's object model. +fn parse(pair: Pair) -> Node { + match pair.as_rule() { + Rule::expr | Rule::term => { + let mut iter = pair.into_inner(); + let first = parse(iter.next().unwrap()); + let mut rest = Vec::<(Operator, Node)>::new(); + + while let Some(operator) = iter.next() { + let rhs = iter.next().unwrap(); + let op = Operator::from(operator); + let node = parse(rhs); + rest.push((op, node)); + } + Node::Expr(Box::from(first), rest) + } + Rule::fact | Rule::number => parse(pair.only()), + Rule::dec_number | Rule::dec_zero | Rule::neg_number => { + Node::Number(i32::from_str(pair.as_str()).unwrap()) + } + Rule::hex_number => { + Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 16).unwrap()) + } + Rule::bin_number => { + Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 2).unwrap()) + } + Rule::oct_number => { + Node::Number(i32::from_str_radix(pair.as_str().get(2..).unwrap(), 8).unwrap()) + } + Rule::string => create_string_node(pair), + Rule::label => Node::Label(pair.as_str()), + Rule::relative_label => Node::RelativeLabel(pair.as_str().get(1..).unwrap()), + Rule::absolute_line_offset | Rule::relative_line_offset => create_line_offset_node(pair), + _ => unreachable!(), + } +} + fn optional_label(pair: Option) -> Option