Finish up parser and assembler with more-or-less complete syntax
Major changes inlude: * Bit the bullet and now instructions have their length hard-coded * Move from_utf8 object parsing to be done by their objects (instead of a Parser god object) * A list of AST sections are assembled into an Object using the new vm::obj::assemble module. * Changed the object layout some in the spec, and adjusted code to match this. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
114
src/vm/obj/syn/ast.rs
Normal file
114
src/vm/obj/syn/ast.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use crate::vm::{reg::Reg, inst::*};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SectionBlock {
|
||||
Data {
|
||||
org: Option<SectionOrg>,
|
||||
body: Vec<Line>,
|
||||
},
|
||||
Code {
|
||||
org: Option<SectionOrg>,
|
||||
body: Vec<Line>,
|
||||
},
|
||||
Meta {
|
||||
entries: Vec<(String, ImmValue)>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SectionOrg {
|
||||
Start(u64),
|
||||
Range(u64, u64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Line {
|
||||
Inst(Inst),
|
||||
LabelDef(String),
|
||||
ImmValue(ImmValue),
|
||||
Export(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ImmValue {
|
||||
Number(u64),
|
||||
Label(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Inst {
|
||||
Add(Reg, Reg),
|
||||
Mul(Reg, Reg),
|
||||
Div(Reg, Reg),
|
||||
Mod(Reg, Reg),
|
||||
INeg(Reg),
|
||||
And(Reg, Reg),
|
||||
Or(Reg, Reg),
|
||||
Inv(Reg),
|
||||
Not(Reg),
|
||||
Xor(Reg, Reg),
|
||||
Shl(Reg, Reg),
|
||||
Shr(Reg, Reg),
|
||||
|
||||
CmpEq(Reg, Reg),
|
||||
CmpLt(Reg, Reg),
|
||||
Jmp(Reg),
|
||||
Jz(Reg),
|
||||
Jnz(Reg),
|
||||
|
||||
Load(Reg, Reg),
|
||||
Store(Reg, Reg),
|
||||
StoreImm(Reg, ImmValue),
|
||||
MemCopy(Reg, Reg),
|
||||
RegCopy(Reg, Reg),
|
||||
|
||||
Nop,
|
||||
Halt,
|
||||
}
|
||||
|
||||
impl Inst {
|
||||
pub fn op(&self) -> InstOp {
|
||||
match self {
|
||||
Inst::Add(_, _) => { ADD }
|
||||
Inst::Mul(_, _) => { MUL }
|
||||
Inst::Div(_, _) => { DIV }
|
||||
Inst::Mod(_, _) => { MOD }
|
||||
Inst::INeg(_) => { INEG }
|
||||
Inst::And(_, _) => { AND }
|
||||
Inst::Or(_, _) => { OR }
|
||||
Inst::Inv(_) => { INV }
|
||||
Inst::Not(_) => { NOT }
|
||||
Inst::Xor(_, _) => { XOR }
|
||||
Inst::Shl(_, _) => { SHL }
|
||||
Inst::Shr(_, _) => { SHR }
|
||||
|
||||
Inst::CmpEq(_, _) => { CMPEQ }
|
||||
Inst::CmpLt(_, _) => { CMPLT }
|
||||
Inst::Jmp(_) => { JMP }
|
||||
Inst::Jz(_) => { JZ }
|
||||
Inst::Jnz(_) => { JNZ }
|
||||
|
||||
Inst::Load(_, _) => { LOAD }
|
||||
Inst::Store(_, _) => { STORE }
|
||||
Inst::StoreImm(_, imm) => {
|
||||
if let ImmValue::Number(imm) = imm {
|
||||
if *imm > (u32::max_value() as u64) {
|
||||
STOREIMM64
|
||||
} else {
|
||||
STOREIMM32
|
||||
}
|
||||
} else {
|
||||
STOREIMM64
|
||||
}
|
||||
}
|
||||
Inst::MemCopy(_, _) => { MEMCOPY }
|
||||
Inst::RegCopy(_, _) => { REGCOPY }
|
||||
|
||||
Inst::Nop => { NOP }
|
||||
Inst::Halt => { HALT }
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
inst_len(self.op())
|
||||
}
|
||||
}
|
||||
2
src/vm/obj/syn/convert.rs
Normal file
2
src/vm/obj/syn/convert.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
struct GetLayout {
|
||||
}
|
||||
47
src/vm/obj/syn/error.rs
Normal file
47
src/vm/obj/syn/error.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use snafu::Snafu;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
io,
|
||||
};
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum ParseError {
|
||||
#[snafu(display("IO error: {}", source))]
|
||||
Io { source: io::Error },
|
||||
|
||||
#[snafu(display("wrong magic number"))]
|
||||
WrongMagic,
|
||||
|
||||
#[snafu(display("unknown section kind: 0x{:02x}", kind))]
|
||||
UnknownSectionKind { kind: u8 },
|
||||
|
||||
#[snafu(display("invalid UTF-8 string: {}", source))]
|
||||
InvalidUtf8String { source: std::string::FromUtf8Error },
|
||||
|
||||
#[snafu(display("duplicate symbol name: {}", name))]
|
||||
DuplicateName { name: String },
|
||||
|
||||
#[snafu(display("duplicate exported symbol name: {}", name))]
|
||||
DuplicateExportName { name: String },
|
||||
}
|
||||
|
||||
macro_rules! into_parse_error {
|
||||
(
|
||||
$($type:ty : $variant:ident),* $(,)?
|
||||
) => {
|
||||
$(
|
||||
impl From<$type> for ParseError {
|
||||
fn from(other: $type) -> Self {
|
||||
ParseError::$variant { source: other }
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
into_parse_error! {
|
||||
io::Error: Io,
|
||||
std::string::FromUtf8Error: InvalidUtf8String,
|
||||
}
|
||||
|
||||
pub type Result<T, E = ParseError> = std::result::Result<T, E>;
|
||||
5
src/vm/obj/syn/mod.rs
Normal file
5
src/vm/obj/syn/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use lalrpop_util::lalrpop_mod;
|
||||
|
||||
lalrpop_mod!(pub parser, "/vm/obj/syn/parser.rs");
|
||||
pub mod ast;
|
||||
pub mod error;
|
||||
100
src/vm/obj/syn/parser.lalrpop
Normal file
100
src/vm/obj/syn/parser.lalrpop
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::str::FromStr;
|
||||
use crate::vm::{
|
||||
obj::syn::ast::*,
|
||||
reg::*,
|
||||
};
|
||||
|
||||
grammar;
|
||||
|
||||
LabelDef: String = {
|
||||
<Label> ":" => <>
|
||||
}
|
||||
|
||||
// TODO : Value (ImmValue, String)
|
||||
|
||||
ImmValue: ImmValue = {
|
||||
<Label> => ImmValue::Label(<>),
|
||||
<Number> => ImmValue::Number(<>),
|
||||
}
|
||||
|
||||
Label: String = {
|
||||
r"[a-zA-Z]+" => String::from(<>),
|
||||
}
|
||||
|
||||
Number: u64 = {
|
||||
<s:r"\$[0-9]+"> => u64::from_str(&s[1..]).unwrap(),
|
||||
<s:r"\$0x[0-9a-fA-F]+"> => u64::from_str_radix(&s[3..], 16).unwrap()
|
||||
}
|
||||
|
||||
Reg: Reg = {
|
||||
r"%ip" => IP,
|
||||
r"%sp" => SP,
|
||||
r"%fp" => FP,
|
||||
r"%flags" => FLAGS,
|
||||
r"%status" => STATUS,
|
||||
r"%r[0-9]{2}" => {
|
||||
let offset = (&<>[2..]).parse::<u8>().unwrap();
|
||||
let reg = R00 + offset;
|
||||
assert!(reg < LAST_REG, "invalid register");
|
||||
reg
|
||||
}
|
||||
}
|
||||
|
||||
Inst: Inst = {
|
||||
"add" <d:Reg> "," <s:Reg> => Inst::Add(d, s),
|
||||
"mul" <d:Reg> "," <s:Reg> => Inst::Mul(d, s),
|
||||
"div" <d:Reg> "," <s:Reg> =>Inst::Div(d, s),
|
||||
"mod" <d:Reg> "," <s:Reg> => Inst::Mod(d, s),
|
||||
"ineg" <d:Reg> => Inst::INeg(d),
|
||||
"and" <d:Reg> "," <s:Reg> => Inst::And(d, s),
|
||||
"or" <d:Reg> "," <s:Reg> => Inst::Or(d, s),
|
||||
"xor" <d:Reg> "," <s:Reg> => Inst::Xor(d, s),
|
||||
"shl" <d:Reg> "," <s:Reg> => Inst::Shl(d, s),
|
||||
"shr" <d:Reg> "," <s:Reg> => Inst::Shr(d, s),
|
||||
"cmpeq" <d:Reg> "," <s:Reg> => Inst::CmpEq(d, s),
|
||||
"cmplt" <d:Reg> "," <s:Reg> => Inst::CmpLt(d, s),
|
||||
"jmp" <d:Reg> => Inst::Jmp(d),
|
||||
"jz" <d:Reg> => Inst::Jz(d),
|
||||
"jnz" <d:Reg> => Inst::Jnz(d),
|
||||
"load" <d:Reg> "," <s:Reg> => Inst::Load(d, s),
|
||||
"store" <d:Reg> "," <s:Reg> => Inst::Store(d, s),
|
||||
"storeimm" <d:Reg> "," <s:ImmValue> => Inst::StoreImm(d, s),
|
||||
"memcopy" <d:Reg> "," <s:Reg> => Inst::MemCopy(d, s),
|
||||
"regcopy" <d:Reg> "," <s:Reg> => Inst::RegCopy(d, s),
|
||||
"nop" => Inst::Nop,
|
||||
"halt" => Inst::Halt,
|
||||
}
|
||||
|
||||
Line: Line = {
|
||||
<Inst> => Line::Inst(<>),
|
||||
<LabelDef> => Line::LabelDef(<>),
|
||||
<ImmValue> => Line::ImmValue(<>),
|
||||
r"\.export" <Label> => Line::Export(<>),
|
||||
}
|
||||
|
||||
MetaLine: (String, ImmValue) = {
|
||||
<name:Label> ":" <value:ImmValue> => (name, value),
|
||||
}
|
||||
|
||||
SectionOrg: SectionOrg = {
|
||||
<start:Number> => SectionOrg::Start(start),
|
||||
<start:Number> r"\.\." <end:Number> => SectionOrg::Range(start, end),
|
||||
}
|
||||
|
||||
Section: SectionBlock = {
|
||||
"data" <org:SectionOrg?> "{" <body:Line*> "}" => {
|
||||
SectionBlock::Data { org, body }
|
||||
},
|
||||
|
||||
"code" <org:SectionOrg?> "{" <body:Line*> "}" => {
|
||||
SectionBlock::Code { org, body }
|
||||
},
|
||||
|
||||
"meta" "{" <entries:MetaLine*> "}" => {
|
||||
SectionBlock::Meta { entries, }
|
||||
}
|
||||
}
|
||||
|
||||
pub Sections: Vec<SectionBlock> = {
|
||||
<Section*> => <>,
|
||||
}
|
||||
Reference in New Issue
Block a user