Add "sym" and "def" instructions, add argument naming
This commit is contained in:
Generated
+1
@@ -176,6 +176,7 @@ dependencies = [
|
||||
"dyn-clonable",
|
||||
"log",
|
||||
"num-traits",
|
||||
"parking_lot",
|
||||
"sexp",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -12,3 +12,4 @@ anyhow = "1.0.32"
|
||||
dyn-clonable = "0.9.0"
|
||||
log = "0.4.11"
|
||||
num-traits = "0.2.12"
|
||||
parking_lot = "0.11.0"
|
||||
|
||||
@@ -124,3 +124,6 @@ impl From<String> for RoutineName {
|
||||
Self(n)
|
||||
}
|
||||
}
|
||||
|
||||
pub type RegisterAlias = String;
|
||||
pub type ConstantName = String;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
use crate::asm::error::CrsnError;
|
||||
|
||||
/// Register name
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum Register {
|
||||
/// Argument register, read-only
|
||||
Arg(u8),
|
||||
@@ -24,13 +24,23 @@ impl Display for Register {
|
||||
}
|
||||
|
||||
pub fn parse_reg(name: &str) -> anyhow::Result<Register> {
|
||||
// TODO deduplicate code
|
||||
if let Some(rn) = name.strip_prefix("arg") {
|
||||
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
|
||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
||||
}
|
||||
let val: u8 = rn.parse()?;
|
||||
Ok(Register::Arg(val))
|
||||
} else if let Some(rn) = name.strip_prefix("res") {
|
||||
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
|
||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
||||
}
|
||||
let val: u8 = rn.parse()?;
|
||||
Ok(Register::Res(val))
|
||||
} else if let Some(rn) = name.strip_prefix("r") {
|
||||
if rn.chars().find(|c : &char| !c.is_ascii_digit()).is_some() {
|
||||
Err(CrsnError::Parse(format!("Bad register: {}", name).into()))?;
|
||||
}
|
||||
let val: u8 = rn.parse()?;
|
||||
Ok(Register::Gen(val))
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,12 @@ pub trait Flatten {
|
||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError>;
|
||||
}
|
||||
|
||||
impl Flatten for () {
|
||||
fn flatten(self: Box<Self>, _label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl Flatten for Instr {
|
||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||
let mut ops = vec![self.op];
|
||||
@@ -58,12 +64,13 @@ impl Flatten for Vec<Box<dyn Flatten>> {
|
||||
impl Flatten for Routine {
|
||||
fn flatten(self: Box<Self>, label_num: &AtomicU32) -> Result<Vec<Op>, CrsnError> {
|
||||
let mut ops = vec![
|
||||
BuiltinOp::Barrier(Some(format!("Routine \"{}\" start", self.name).into())).into(),
|
||||
BuiltinOp::Routine(self.name.clone()).into(),
|
||||
];
|
||||
|
||||
ops.extend(self.body.flatten(label_num)?);
|
||||
|
||||
ops.push(BuiltinOp::Barrier(Some(format!("Routine \"{}\" overrun", self.name).into())).into());
|
||||
ops.push(BuiltinOp::Barrier(Some(format!("Routine \"{}\" end", self.name).into())).into());
|
||||
|
||||
numbered_labels_to_skips(ops)
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,5 +1,7 @@
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::asm::parse::{ParserContext, ParserState};
|
||||
use crate::module::CrsnExtension;
|
||||
use crate::runtime::program::Program;
|
||||
|
||||
@@ -11,7 +13,16 @@ pub mod patches;
|
||||
|
||||
/// Parse a program from string and assemble a low level instruction sequence from it.
|
||||
pub fn assemble(source: &str, parsers: Arc<Vec<Box<dyn CrsnExtension>>>) -> Result<Arc<Program>, error::CrsnError> {
|
||||
let ops = parse::parse(source, &parsers)?;
|
||||
let pcx = ParserContext {
|
||||
parsers: &parsers,
|
||||
state: RefCell::new(ParserState {
|
||||
reg_aliases: Default::default(),
|
||||
reg_alias_stack: vec![],
|
||||
constants: Default::default(),
|
||||
}),
|
||||
};
|
||||
|
||||
let ops = parse::parse(source, &pcx)?;
|
||||
|
||||
trace!("--- Compiled program ---");
|
||||
for (n, op) in ops.iter().enumerate() {
|
||||
|
||||
@@ -2,31 +2,36 @@ use sexp::Sexp;
|
||||
|
||||
use crate::asm::data::{Mask, Rd, RdData, RdObj, Wr};
|
||||
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
|
||||
use crate::asm::parse::ParserContext;
|
||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||
|
||||
/// Utility for argument parsing
|
||||
pub struct TokenParser {
|
||||
pub struct TokenParser<'a> {
|
||||
orig_len: usize,
|
||||
args: Vec<Sexp>,
|
||||
pub pcx: &'a ParserContext<'a>,
|
||||
}
|
||||
|
||||
impl IntoIterator for TokenParser {
|
||||
impl<'a> IntoIterator for TokenParser<'a> {
|
||||
type Item = Sexp;
|
||||
type IntoIter = std::vec::IntoIter<Sexp>;
|
||||
|
||||
fn into_iter(mut self) -> Self::IntoIter {
|
||||
// The vec is reversed so we can call "pop", but here we will iterate it as slice so it
|
||||
// must be reversed to its original direction.
|
||||
self.args.reverse();
|
||||
self.args.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenParser {
|
||||
impl<'a> TokenParser<'a> {
|
||||
/// Create a new argument parser
|
||||
pub fn new(mut args: Vec<Sexp>) -> Self {
|
||||
pub fn new(mut args: Vec<Sexp>, pcx: &'a ParserContext) -> Self {
|
||||
args.reverse();
|
||||
Self {
|
||||
orig_len: args.len(),
|
||||
args,
|
||||
pcx,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,17 +66,19 @@ impl TokenParser {
|
||||
|
||||
/// Get the next string entry
|
||||
pub fn next_string(&mut self) -> anyhow::Result<String> {
|
||||
Ok(expect_string_atom(self.next())?)
|
||||
let next = self.next();
|
||||
let esa = expect_string_atom(next)?;
|
||||
Ok(esa)
|
||||
}
|
||||
|
||||
/// Get the next entry as read location
|
||||
pub fn next_rd(&mut self) -> anyhow::Result<Rd> {
|
||||
parse_rd(self.next())
|
||||
parse_rd(self.next(), self.pcx)
|
||||
}
|
||||
|
||||
/// Get the next entry as read location
|
||||
pub fn next_rdobj(&mut self) -> anyhow::Result<RdObj> {
|
||||
match parse_rd(self.next())? {
|
||||
match parse_rd(self.next(), self.pcx)? {
|
||||
Rd(RdData::ObjectPtr(reg), Mask::FULL) => {
|
||||
return Ok(RdObj::new(reg));
|
||||
}
|
||||
@@ -83,6 +90,6 @@ impl TokenParser {
|
||||
|
||||
/// Get the next entry as write location
|
||||
pub fn next_wr(&mut self) -> anyhow::Result<Wr> {
|
||||
parse_wr(self.next())
|
||||
parse_wr(self.next(), self.pcx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
pub use parse_instr::parse_instructions;
|
||||
|
||||
use crate::asm::data::literal::{ConstantName, RegisterAlias, Value};
|
||||
use crate::asm::data::Register;
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::Op;
|
||||
use crate::asm::parse::sexp_expect::expect_list;
|
||||
@@ -13,8 +17,27 @@ pub mod parse_data;
|
||||
pub mod sexp_expect;
|
||||
pub mod parse_op;
|
||||
pub mod arg_parser;
|
||||
pub mod parse_routine;
|
||||
|
||||
pub fn parse(source: &str, parsers: &[Box<dyn CrsnExtension>]) -> Result<Vec<Op>, CrsnError> {
|
||||
pub struct ParserContext<'a> {
|
||||
/// Extension modules
|
||||
pub parsers: &'a [Box<dyn CrsnExtension>],
|
||||
/// Mutable state
|
||||
pub state: RefCell<ParserState>,
|
||||
}
|
||||
|
||||
pub struct ParserState {
|
||||
/// Register aliases within the routine
|
||||
pub reg_aliases: HashMap<RegisterAlias, Register>,
|
||||
|
||||
/// The old reg aliases map is pushed here when entering a routine definition
|
||||
pub reg_alias_stack: Vec<HashMap<RegisterAlias, Register>>,
|
||||
|
||||
/// Global constants
|
||||
pub constants: HashMap<ConstantName, Value>,
|
||||
}
|
||||
|
||||
pub fn parse(source: &str, parsers: &ParserContext) -> Result<Vec<Op>, CrsnError> {
|
||||
let items = expect_list(Some(sexp::parse(source)?), true)?;
|
||||
|
||||
let label_num = AtomicU32::new(0);
|
||||
|
||||
@@ -3,11 +3,11 @@ use sexp::Sexp;
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::{Cond, cond, Flatten};
|
||||
use crate::asm::parse::parse_instr::parse_instructions;
|
||||
use crate::asm::parse::ParserContext;
|
||||
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||
use crate::asm::patches::TryRemove;
|
||||
use crate::module::CrsnExtension;
|
||||
|
||||
pub fn parse_cond_branch(tok: Sexp, parsers: &[Box<dyn CrsnExtension>]) -> Result<(Cond, Box<dyn Flatten>), CrsnError> {
|
||||
pub fn parse_cond_branch(tok: Sexp, parsers: &ParserContext) -> Result<(Cond, Box<dyn Flatten>), CrsnError> {
|
||||
let mut list = expect_list(Some(tok), false)?;
|
||||
let kw = expect_string_atom(list.try_remove(0))?;
|
||||
|
||||
|
||||
@@ -4,18 +4,54 @@ use std::convert::TryFrom;
|
||||
use sexp::{Atom, Sexp};
|
||||
|
||||
use crate::asm::data::{DataDisp, Rd, RdData, reg, Wr, WrData};
|
||||
use crate::asm::data::literal::Label;
|
||||
use crate::asm::data::literal::{ConstantName, Label, RegisterAlias, Value};
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::parse::ParserContext;
|
||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||
|
||||
fn is_valid_identifier(name: &str) -> bool {
|
||||
name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_')
|
||||
&& name.chars().find(|c| !c.is_ascii_alphanumeric() && *c != '_').is_none()
|
||||
}
|
||||
|
||||
/// Parse register alias
|
||||
pub fn parse_reg_alias(name: Option<Sexp>) -> Result<RegisterAlias, CrsnError> {
|
||||
trace!("parse reg alias: {:?}", name);
|
||||
|
||||
let name = expect_string_atom(name)?;
|
||||
|
||||
if !is_valid_identifier(&name) {
|
||||
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed register alias.", name).into()));
|
||||
}
|
||||
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Parse constant name
|
||||
pub fn parse_constant_name(name: Option<Sexp>) -> Result<ConstantName, CrsnError> {
|
||||
trace!("parse const name: {:?}", name);
|
||||
|
||||
let name = expect_string_atom(name)?;
|
||||
|
||||
if !is_valid_identifier(&name) {
|
||||
return Err(CrsnError::Parse(format!("\"{}\" is not an allowed constant name.", name).into()));
|
||||
}
|
||||
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Parse a label
|
||||
pub fn parse_label(name: Option<Sexp>) -> Result<Label, CrsnError> {
|
||||
trace!("parse label: {:?}", name);
|
||||
|
||||
let name = expect_string_atom(name)?;
|
||||
Ok(Label::Named(name.trim_start_matches(':').into()))
|
||||
}
|
||||
|
||||
/// Parse data disposition (address/value, without the read/write restriction)
|
||||
pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, CrsnError> {
|
||||
pub fn parse_data_disp(tok: Option<Sexp>, pcx: &ParserContext) -> Result<DataDisp, CrsnError> {
|
||||
trace!("parse data: {:?}", tok);
|
||||
|
||||
let tok = if let Some(tok) = tok {
|
||||
tok
|
||||
} else {
|
||||
@@ -33,6 +69,18 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, CrsnError> {
|
||||
return Ok(DataDisp::Discard);
|
||||
}
|
||||
|
||||
// check if we have an alias defined
|
||||
{
|
||||
let pstate = pcx.state.borrow();
|
||||
if let Some(val) = pstate.constants.get(s) {
|
||||
return Ok(DataDisp::Immediate(*val));
|
||||
}
|
||||
|
||||
if let Some(val) = pstate.reg_aliases.get(s) {
|
||||
return Ok(DataDisp::Register(*val));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(reference) = s.strip_prefix('@') {
|
||||
Ok(DataDisp::ObjectPtr(reg::parse_reg(reference)?))
|
||||
} else if s.starts_with(|c: char| c.is_ascii_digit()) {
|
||||
@@ -47,7 +95,32 @@ pub fn parse_data_disp(tok: Option<Sexp>) -> Result<DataDisp, CrsnError> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse immediate value
|
||||
pub fn parse_value(tok: Option<Sexp>) -> Result<Value, CrsnError> {
|
||||
let tok = if let Some(tok) = tok {
|
||||
tok
|
||||
} else {
|
||||
return Err(CrsnError::Parse("Expected value token".into()));
|
||||
};
|
||||
|
||||
trace!("parse value: {:?}", tok);
|
||||
|
||||
match &tok {
|
||||
Sexp::Atom(Atom::I(val)) => {
|
||||
Ok(unsafe { std::mem::transmute(*val) })
|
||||
}
|
||||
Sexp::Atom(Atom::S(s)) => {
|
||||
Ok(unsafe { std::mem::transmute(parse_i64(s)?) })
|
||||
}
|
||||
_ => {
|
||||
Err(CrsnError::Parse(format!("bad value format: {:?}", tok).into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
|
||||
trace!("parse u64 from {}", literal);
|
||||
let mut without_underscores = Cow::Borrowed(literal);
|
||||
if without_underscores.contains('_') {
|
||||
without_underscores = without_underscores.replace('_', "").into();
|
||||
@@ -63,6 +136,7 @@ pub fn parse_u64(literal: &str) -> anyhow::Result<u64> {
|
||||
}
|
||||
|
||||
pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
|
||||
trace!("parse i64 from {}", literal);
|
||||
if let Some(_value) = literal.strip_prefix("-") {
|
||||
Ok(-1 * i64::try_from(parse_u64(literal)?)?)
|
||||
} else {
|
||||
@@ -70,10 +144,10 @@ pub fn parse_i64(literal: &str) -> anyhow::Result<i64> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_rd(tok: Option<Sexp>) -> anyhow::Result<Rd> {
|
||||
Ok(Rd::new(RdData::try_from(parse_data_disp(tok)?)?))
|
||||
pub fn parse_rd(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Rd> {
|
||||
Ok(Rd::new(RdData::try_from(parse_data_disp(tok, pcx)?)?))
|
||||
}
|
||||
|
||||
pub fn parse_wr(tok: Option<Sexp>) -> anyhow::Result<Wr> {
|
||||
Ok(Wr::new(WrData::try_from(parse_data_disp(tok)?)?))
|
||||
pub fn parse_wr(tok: Option<Sexp>, pcx: &ParserContext) -> anyhow::Result<Wr> {
|
||||
Ok(Wr::new(WrData::try_from(parse_data_disp(tok, pcx)?)?))
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
use sexp::Sexp;
|
||||
|
||||
use crate::asm::data::literal::RoutineName;
|
||||
use crate::asm::data::Register;
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::{Flatten, Instr, Routine};
|
||||
use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::asm::parse::parse_cond::parse_cond_branch;
|
||||
use crate::asm::parse::parse_data::parse_reg_alias;
|
||||
use crate::asm::parse::ParserContext;
|
||||
use crate::asm::parse::sexp_expect::{expect_list, expect_string_atom};
|
||||
use crate::asm::patches::SexpIsA;
|
||||
use crate::module::{CrsnExtension, ParseRes};
|
||||
use crate::module::ParseRes;
|
||||
|
||||
use super::parse_op::parse_op;
|
||||
use crate::asm::parse::parse_routine::parse_routine;
|
||||
|
||||
pub fn parse_instructions(items: impl Iterator<Item=Sexp>, parsers: &[Box<dyn CrsnExtension>]) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||
pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||
let mut parsed = vec![];
|
||||
for expr in items {
|
||||
let tokens = expect_list(Some(expr), false)?;
|
||||
@@ -20,14 +24,15 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, parsers: &[Box<dyn Cr
|
||||
let name = expect_string_atom(toki.next())?;
|
||||
|
||||
if name == "proc" {
|
||||
parsed.push(parse_routine(toki, parsers)?);
|
||||
parsed.push(parse_routine(toki, pcx)?);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut token_parser = TokenParser::new(toki.collect());
|
||||
for p in parsers {
|
||||
token_parser = match p.parse_syntax(&name, token_parser, parsers) {
|
||||
let mut token_parser = TokenParser::new(toki.collect(), pcx);
|
||||
for p in pcx.parsers {
|
||||
token_parser = match p.parse_syntax(&name, token_parser) {
|
||||
Ok(ParseRes::Parsed(op)) => return Ok(op),
|
||||
Ok(ParseRes::ParsedNone) => return Ok(Box::new(())),
|
||||
Ok(ParseRes::Unknown(to_reuse)) => {
|
||||
if to_reuse.parsing_started() {
|
||||
panic!("Module \"{}\" started parsing syntax, but returned Unknown!", p.name());
|
||||
@@ -43,7 +48,7 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, parsers: &[Box<dyn Cr
|
||||
// Get back the original iterator
|
||||
let toki = token_parser.into_iter();
|
||||
|
||||
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect());
|
||||
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx);
|
||||
let branch_tokens = toki
|
||||
.skip_while(|e| e.is_atom())
|
||||
.take_while(|e| e.is_list());
|
||||
@@ -51,7 +56,7 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, parsers: &[Box<dyn Cr
|
||||
let branches = {
|
||||
let mut branches = vec![];
|
||||
for t in branch_tokens {
|
||||
branches.push(parse_cond_branch(t, parsers)?);
|
||||
branches.push(parse_cond_branch(t, pcx)?);
|
||||
}
|
||||
if branches.is_empty() {
|
||||
None
|
||||
@@ -60,25 +65,12 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, parsers: &[Box<dyn Cr
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(op) = parse_op(name.as_str(), arg_tokens)? {
|
||||
parsed.push(Box::new(Instr {
|
||||
op: parse_op(name.as_str(), arg_tokens, parsers)?,
|
||||
op,
|
||||
branches,
|
||||
}));
|
||||
}
|
||||
}
|
||||
Ok(Box::new(parsed))
|
||||
}
|
||||
|
||||
fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, parsers: &[Box<dyn CrsnExtension>]) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||
let name = expect_string_atom(toki.next())?;
|
||||
|
||||
let _arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect());
|
||||
|
||||
// TODO parse arg tokens
|
||||
|
||||
let body = parse_instructions(toki, parsers)?;
|
||||
|
||||
return Ok(Box::new(Routine {
|
||||
name: RoutineName(name),
|
||||
body,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -2,15 +2,16 @@ use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::Op;
|
||||
use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::builtin::parse::BuiltinOps;
|
||||
use crate::module::{CrsnExtension, ParseRes};
|
||||
use crate::module::ParseRes;
|
||||
|
||||
pub fn parse_op(keyword: &str, mut arg_tokens: TokenParser, parsers: &[Box<dyn CrsnExtension>]) -> Result<Op, CrsnError> {
|
||||
pub fn parse_op<'a>(keyword: &str, mut arg_tokens: TokenParser<'a>) -> Result<Option<Op>, CrsnError> {
|
||||
// Include built-in instructions
|
||||
let builtins = [BuiltinOps::new()];
|
||||
|
||||
for p in builtins.iter().chain(parsers) {
|
||||
for p in builtins.iter().chain(arg_tokens.pcx.parsers) {
|
||||
arg_tokens = match p.parse_op(keyword, arg_tokens) {
|
||||
Ok(ParseRes::Parsed(op)) => return Ok(op),
|
||||
Ok(ParseRes::Parsed(op)) => return Ok(Some(op)),
|
||||
Ok(ParseRes::ParsedNone) => return Ok(None),
|
||||
Ok(ParseRes::Unknown(to_reuse)) => {
|
||||
if to_reuse.parsing_started() {
|
||||
panic!("Module \"{}\" started parsing {}, but returned Unknown!", p.name(), keyword);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use sexp::Sexp;
|
||||
use crate::asm::parse::{ParserContext, parse_instructions};
|
||||
use crate::asm::instr::{Flatten, Routine};
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||
use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::asm::patches::SexpIsA;
|
||||
use crate::asm::parse::parse_data::parse_reg_alias;
|
||||
use crate::asm::data::Register;
|
||||
use crate::asm::data::literal::RoutineName;
|
||||
|
||||
pub fn parse_routine(mut toki: impl Iterator<Item=Sexp> + Clone, pcx: &ParserContext) -> Result<Box<dyn Flatten>, CrsnError> {
|
||||
let name = expect_string_atom(toki.next())?;
|
||||
|
||||
let arg_tokens = TokenParser::new(toki.clone().take_while(|e| e.is_atom()).collect(), pcx);
|
||||
let toki = toki.skip_while(|e| e.is_atom());
|
||||
|
||||
{
|
||||
let mut pstate = pcx.state.borrow_mut();
|
||||
|
||||
let old = std::mem::replace(&mut pstate.reg_aliases, Default::default());
|
||||
pstate.reg_alias_stack.push(old);
|
||||
|
||||
for (n, tok) in arg_tokens.into_iter().enumerate() {
|
||||
let alias = parse_reg_alias(Some(tok))?;
|
||||
|
||||
if pstate.constants.contains_key(&alias) {
|
||||
return Err(CrsnError::Parse(format!("Symbol \"{}\" already used for a constant.", alias).into()));
|
||||
}
|
||||
|
||||
pstate.reg_aliases.insert(alias, Register::Arg(n as u8));
|
||||
}
|
||||
}
|
||||
|
||||
let body = parse_instructions(toki, pcx)?;
|
||||
|
||||
{
|
||||
let mut pstate = pcx.state.borrow_mut();
|
||||
let old = pstate.reg_alias_stack.pop().unwrap();
|
||||
pstate.reg_aliases = old;
|
||||
}
|
||||
|
||||
return Ok(Box::new(Routine {
|
||||
name: RoutineName(name),
|
||||
body,
|
||||
}));
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
use sexp::{Atom, Sexp};
|
||||
|
||||
use crate::asm::data::literal::{Label, RoutineName};
|
||||
use crate::asm::data::reg::parse_reg;
|
||||
use crate::asm::error::CrsnError;
|
||||
use crate::asm::instr::cond::parse_cond;
|
||||
use crate::asm::instr::Op;
|
||||
use crate::asm::parse::arg_parser::TokenParser;
|
||||
use crate::asm::parse::parse_data::{parse_label, parse_rd};
|
||||
use crate::asm::parse::parse_data::{parse_constant_name, parse_label, parse_rd, parse_reg_alias, parse_value};
|
||||
use crate::asm::parse::sexp_expect::expect_string_atom;
|
||||
use crate::builtin::defs::BuiltinOp;
|
||||
use crate::module::{CrsnExtension, ParseRes};
|
||||
@@ -28,7 +29,9 @@ impl CrsnExtension for BuiltinOps {
|
||||
"builtin"
|
||||
}
|
||||
|
||||
fn parse_op(&self, keyword: &str, mut args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
fn parse_op<'a>(&self, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
let pcx = args.pcx;
|
||||
|
||||
Ok(ParseRes::Parsed(Op::BuiltIn(match keyword {
|
||||
"nop" => {
|
||||
BuiltinOp::Nop
|
||||
@@ -44,6 +47,48 @@ impl CrsnExtension for BuiltinOps {
|
||||
}
|
||||
}
|
||||
|
||||
"sym" => {
|
||||
let alias = parse_reg_alias(args.next())?;
|
||||
trace!("alias={:?}", alias);
|
||||
let register = parse_reg(&args.next_string()?)?;
|
||||
trace!("register={:?}", alias);
|
||||
|
||||
let mut pstate = pcx.state.borrow_mut();
|
||||
if pstate.reg_aliases.contains_key(&alias) {
|
||||
return Err(CrsnError::Parse(format!("Register alias \"{}\" already defined!", alias).into()));
|
||||
}
|
||||
|
||||
if pstate.constants.contains_key(&alias) {
|
||||
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a constant!", alias).into()));
|
||||
}
|
||||
|
||||
if pstate.reg_aliases.iter().find(|x| x.1 == ®ister).is_some() {
|
||||
return Err(CrsnError::Parse(format!("Register \"{}\" already aliased!", register).into()));
|
||||
}
|
||||
|
||||
pstate.reg_aliases.insert(alias, register);
|
||||
|
||||
return Ok(ParseRes::ParsedNone);
|
||||
}
|
||||
|
||||
"def" => {
|
||||
let name = parse_constant_name(args.next())?;
|
||||
let value = parse_value(args.next())?;
|
||||
|
||||
let mut pstate = pcx.state.borrow_mut();
|
||||
if pstate.constants.contains_key(&name) {
|
||||
return Err(CrsnError::Parse(format!("Constant \"{}\" already defined!", name).into()));
|
||||
}
|
||||
|
||||
if pstate.reg_aliases.contains_key(&name) {
|
||||
return Err(CrsnError::Parse(format!("Name \"{}\" already used for a register alias!", name).into()));
|
||||
}
|
||||
|
||||
pstate.constants.insert(name, value);
|
||||
|
||||
return Ok(ParseRes::ParsedNone);
|
||||
}
|
||||
|
||||
"j" => {
|
||||
let dest = parse_label(args.next())?;
|
||||
BuiltinOp::Jump(dest)
|
||||
@@ -59,7 +104,7 @@ impl CrsnExtension for BuiltinOps {
|
||||
|
||||
let mut call_args = vec![];
|
||||
for t in args {
|
||||
call_args.push(parse_rd(Some(t))?);
|
||||
call_args.push(parse_rd(Some(t), pcx)?);
|
||||
}
|
||||
BuiltinOp::Call(dest, call_args)
|
||||
}
|
||||
@@ -67,7 +112,7 @@ impl CrsnExtension for BuiltinOps {
|
||||
"ret" => {
|
||||
let mut ret_vals = vec![];
|
||||
for t in args {
|
||||
ret_vals.push(parse_rd(Some(t))?);
|
||||
ret_vals.push(parse_rd(Some(t), pcx)?);
|
||||
}
|
||||
BuiltinOp::Ret(ret_vals)
|
||||
}
|
||||
@@ -77,11 +122,13 @@ impl CrsnExtension for BuiltinOps {
|
||||
BuiltinOp::Routine(dest)
|
||||
}
|
||||
|
||||
"s" => {
|
||||
"sk" => {
|
||||
BuiltinOp::Skip(args.next_rd()?)
|
||||
}
|
||||
|
||||
"sif" => {
|
||||
// TODO add jne-style names for jif ne ...
|
||||
|
||||
"skif" => {
|
||||
let cond = parse_cond(&args.next_string()?)?;
|
||||
let offs = args.next_rd()?;
|
||||
BuiltinOp::SkipIf(cond, offs)
|
||||
|
||||
+12
-6
@@ -16,14 +16,16 @@ use crate::runtime::run_thread::ThreadInfo;
|
||||
mod eval_res;
|
||||
|
||||
/// Result type returned from the op parser. This is the Ok variant of a Result.
|
||||
pub enum ParseRes<T> {
|
||||
pub enum ParseRes<'a, T> {
|
||||
/// Parsing successful.
|
||||
Parsed(T),
|
||||
/// Parsing successful, but did not yield any result
|
||||
ParsedNone,
|
||||
/// Instruction not recognized, but there was no error.
|
||||
Unknown(TokenParser),
|
||||
Unknown(TokenParser<'a>),
|
||||
}
|
||||
|
||||
impl ParseRes<Op> {
|
||||
impl<'a> ParseRes<'a, Op> {
|
||||
/// Helper to construct an extension op
|
||||
pub fn ext(op: impl OpTrait) -> Self {
|
||||
Self::Parsed(Op::Ext(Box::new(op)))
|
||||
@@ -43,11 +45,15 @@ pub trait CrsnExtension: Debug + Send + Sync + 'static {
|
||||
/// the argument list and either return Ok or Err.
|
||||
///
|
||||
/// If the instruction keyword is not recognized, return Unknown with the unchanged argument list.
|
||||
fn parse_op(&self, keyword: &str, arg_tokens: TokenParser) -> Result<ParseRes<Op>, CrsnError>;
|
||||
///
|
||||
/// pcx is available on the arg_tokens parser
|
||||
fn parse_op<'a>(&self, keyword: &str, arg_tokens: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError>;
|
||||
|
||||
/// Parse a generic S-expression (non-op)
|
||||
fn parse_syntax(&self, keyword: &str, tokens: TokenParser, parsers: &[Box<dyn CrsnExtension>])
|
||||
-> Result<ParseRes<Box<dyn Flatten>>, CrsnError>
|
||||
///
|
||||
/// pcx is available on the arg_tokens parser
|
||||
fn parse_syntax<'a>(&self, keyword: &str, tokens: TokenParser<'a>)
|
||||
-> Result<ParseRes<'a, Box<dyn Flatten>>, CrsnError>
|
||||
{
|
||||
Ok(ParseRes::Unknown(tokens))
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ impl CrsnExtension for ArithOps {
|
||||
"arith"
|
||||
}
|
||||
|
||||
fn parse_op(&self, keyword: &str, args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
parse::parse(keyword, args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crsn::module::ParseRes;
|
||||
|
||||
use crate::defs::ArithOp;
|
||||
|
||||
pub(crate) fn parse(keyword: &str, mut args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
Ok(ParseRes::ext(match keyword {
|
||||
"cmp" => {
|
||||
ArithOp::Compare {
|
||||
|
||||
@@ -24,7 +24,7 @@ impl CrsnExtension for ScreenOps {
|
||||
"screen"
|
||||
}
|
||||
|
||||
fn parse_op(&self, keyword: &str, args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
parse::parse(keyword, args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crsn::module::ParseRes;
|
||||
|
||||
use crate::defs::ScreenOp;
|
||||
|
||||
pub(crate) fn parse(keyword: &str, mut args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
Ok(ParseRes::ext(match keyword {
|
||||
"sc-init" => {
|
||||
ScreenOp::ScreenInit {
|
||||
|
||||
@@ -24,7 +24,7 @@ impl CrsnExtension for StackOps {
|
||||
"stacks"
|
||||
}
|
||||
|
||||
fn parse_op(&self, keyword: &str, args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
fn parse_op<'a>(&self, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
parse::parse(keyword, args)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crsn::module::ParseRes;
|
||||
|
||||
use crate::defs::StackOp;
|
||||
|
||||
pub(crate) fn parse(keyword: &str, mut args: TokenParser) -> Result<ParseRes<Op>, CrsnError> {
|
||||
pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, Op>, CrsnError> {
|
||||
Ok(ParseRes::ext(match keyword {
|
||||
"stack" => {
|
||||
StackOp::NewStack {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
(
|
||||
(def FOO 123) ; define a constant
|
||||
(call my-add 7 8)
|
||||
(cmp res0 138 (ne? (fault "assert failed")))
|
||||
(halt)
|
||||
|
||||
(proc my-add a b ; give arguments names
|
||||
(sym q r0) ; give register a temporary alias
|
||||
(add q a b)
|
||||
(add q FOO)
|
||||
(ret q)
|
||||
)
|
||||
)
|
||||
@@ -1,9 +1,8 @@
|
||||
(
|
||||
(proc main
|
||||
(call fac 5)
|
||||
(ld r0 res0)
|
||||
(halt)
|
||||
)
|
||||
|
||||
(proc fac
|
||||
(cmp arg0 2
|
||||
(eq? (ret 2)))
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
; Set log level to "info" or above for the best results!
|
||||
|
||||
(
|
||||
(proc main
|
||||
(sc-init 800 600)
|
||||
(sc-opt 1 1) ; auto blit
|
||||
(sc-opt 2 25) ; frame rate
|
||||
@@ -22,5 +20,5 @@
|
||||
(cmp r0 799 (eq? (ld r2 -1)) (ne? (cmp r0 0 (eq? (ld r2 1)))))
|
||||
(cmp r1 599 (eq? (ld r3 -1)) (ne? (cmp r1 0 (eq? (ld r3 1)))))
|
||||
(j :loop)
|
||||
)
|
||||
(fault "unreachable")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user