Added prefix dereference

This commit is contained in:
2023-08-13 18:58:47 -05:00
parent e3b20aae41
commit 190ceb5f13
4 changed files with 37 additions and 19 deletions
+1
View File
@@ -171,6 +171,7 @@ pub enum Expr {
Name(String),
Not(BoxExpr),
Neg(BoxExpr),
Deref(BoxExpr),
Address(Lvalue),
Call(BoxExpr, Vec<Rvalue>),
Subscript(BoxExpr, BoxExpr),
+22 -17
View File
@@ -66,14 +66,14 @@ pub enum Variable {
/// and replace it with the design from last year with the mode argument... but as a DMA "device"
/// with an interface in the zero page.
#[derive(Clone, PartialEq, Debug, Default)]
pub struct Signature {
pub struct CompiledFn {
pub label: Label,
pub frame_size: usize,
pub local_scope: Scope,
pub body: Vec<String>,
}
impl Signature {
impl CompiledFn {
/// Add a name to the local scope, which:
/// - Increases the size of the stack frame by that much
/// - Records the offset into the local stack frame where that variable is stored
@@ -115,7 +115,7 @@ struct State {
/// The globally-defined names
pub global_scope: Scope,
/// The functions
pub functions: BTreeMap<String, Signature>,
pub functions: BTreeMap<String, CompiledFn>,
/// The string table
pub strings: Vec<(Label, String)>,
}
@@ -161,14 +161,14 @@ trait Compilable {
fn process(
self,
state: &mut State,
function: Option<&mut Signature>,
function: Option<&mut CompiledFn>,
) -> Result<(), CompileError>;
}
///////////////////////////////////////////////////////////
impl Compilable for Program {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, _: Option<&mut CompiledFn>) -> Result<(), CompileError> {
for decl in self.0 {
decl.process(state, None)?
}
@@ -179,7 +179,7 @@ impl Compilable for Program {
///////////////////////////////////////////////////////////
impl Compilable for Declaration {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, _: Option<&mut CompiledFn>) -> Result<(), CompileError> {
match self {
Declaration::Function(f) => f.process(state, None),
Declaration::Global(g) => g.process(state, None),
@@ -192,9 +192,9 @@ impl Compilable for Declaration {
///////////////////////////////////////////////////////////
impl Compilable for Function {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, _: Option<&mut CompiledFn>) -> Result<(), CompileError> {
// The signature for this function, which will eventually get added to the state
let mut sig = Signature {
let mut sig = CompiledFn {
label: state.gensym(),
..Default::default()
};
@@ -255,7 +255,7 @@ fn lookup<'a>(name: &str, global_scope: &'a Scope, local_scope: &'a Scope) -> Op
///////////////////////////////////////////////////////////
impl Compilable for Assignment {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let Assignment { lvalue, rvalue } = self;
let sig = sig.expect("Assignment outside function");
// First the value, then the address we'll storew it to
@@ -269,7 +269,7 @@ impl Compilable for Assignment {
///////////////////////////////////////////////////////////
impl Compilable for VarDecl {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let mut sig = sig.expect("Var declaration outside function");
if self.typename.is_some() || self.size.is_some() {
todo!("Structs and arrays are not yet supported")
@@ -294,7 +294,7 @@ impl Compilable for VarDecl {
///////////////////////////////////////////////////////////
impl Compilable for Rvalue {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let sig = sig.expect("Assignment outside function");
// For a normal expr, eval and leave on the stack; for a string literal, add it to
// the str table and push the label's address
@@ -313,7 +313,7 @@ impl Compilable for Rvalue {
/// Evaluate an lvalue and leave its address on the stack (ready to be consumed by storew)
impl Compilable for Lvalue {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let global_scope = &state.global_scope;
let mut sig = sig.expect("lvalue outside a function");
@@ -355,7 +355,7 @@ impl Compilable for Lvalue {
/// Evaluate an expression in the context of a local scope. The runtime brother to eval_const.
/// This recursively evaluates a Node and leaves its value on the stack.
impl Compilable for Expr {
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let mut sig = sig.expect("Non-const expression outside a function");
let global_scope = &state.global_scope;
@@ -420,6 +420,11 @@ impl Compilable for Expr {
}
// Handling addresses is very easy because processing an lvalue leaves the address on the stack
Expr::Address(lvalue) => lvalue.process(state, Some(sig)),
Expr::Deref(BoxExpr(e)) => {
(*e).process(state, Some(sig))?;
sig.emit("loadw");
Ok(())
}
Expr::Call(_, _) => todo!(),
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
Expr::Member(_, _) => todo!("Structs and arrays are not yen supported"),
@@ -479,7 +484,7 @@ impl Compilable for Expr {
///////////////////////////////////////////////////////////
impl Compilable for Global {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, _: Option<&mut CompiledFn>) -> Result<(), CompileError> {
if self.typename.is_some() || self.size.is_some() {
todo!("Structs and arrays are not yet supported")
}
@@ -490,7 +495,7 @@ impl Compilable for Global {
///////////////////////////////////////////////////////////
impl Compilable for Const {
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
fn process(self, state: &mut State, _: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let var = if self.string.is_some() {
// If it's a string, add it to the string table
Variable::DirectLabel(state.add_string(&self.string.unwrap()))
@@ -534,7 +539,7 @@ pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
let val = eval_const(*e.0, scope)?;
Ok(if val != 0 { 0 } else { 1 })
}
Expr::Address(_) => Err(CompileError(
Expr::Address(_) | Expr::Deref(_) => Err(CompileError(
0,
0,
String::from("Addresses are not known at compile time"),
@@ -637,7 +642,7 @@ mod test {
.is_err());
}
fn body_as_string(sig: &Signature) -> String {
fn body_as_string(sig: &CompiledFn) -> String {
sig.body.join("\n")
}
+13 -1
View File
@@ -462,6 +462,7 @@ impl AstNode for Expr {
.map_prefix(|prefix, expr| match prefix.as_str() {
"-" => Expr::Neg(expr.into()),
"!" => Expr::Not(expr.into()),
"*" => Expr::Deref(expr.into()),
_ => unreachable!(),
})
.map_postfix(|expr, suffix| match suffix.as_rule() {
@@ -866,7 +867,18 @@ mod test {
assert_eq!(
Expr::from_str("&foo()"),
Ok(Expr::Call(Expr::Address("foo".into()).into(), vec![]))
)
);
// Dereferencing
assert_eq!(
Expr::from_str("*foo"),
Ok(Expr::Deref("foo".into()))
);
assert_eq!(
Expr::from_str("*foo[3]"), // The subscript happens before the dereference
Ok(Expr::Deref(Expr::Subscript("foo".into(), 3.into()).into()))
);
}
#[test]
+1 -1
View File
@@ -41,7 +41,7 @@ eq = { "==" }
ne = { "!=" }
lshift = { "<<" }
rshift = { ">>" }
prefix = { "-" | "!" }
prefix = { "*" | "-" | "!" }
operator = _{
add