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:
2020-02-09 13:04:56 -05:00
parent 329e61e087
commit e198da5825
19 changed files with 739 additions and 311 deletions

114
src/vm/obj/syn/ast.rs Normal file
View 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())
}
}

View File

@@ -0,0 +1,2 @@
struct GetLayout {
}

47
src/vm/obj/syn/error.rs Normal file
View 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
View 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;

View 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*> => <>,
}