forked from MightyPork/crsn
Merge branch 'nat-master' into master
This commit is contained in:
@@ -98,6 +98,7 @@ These keywords (among others) are used in conditional branches to specify flag t
|
|||||||
- `nem`, `nempty` … Not empty
|
- `nem`, `nempty` … Not empty
|
||||||
- `eof` … EOF
|
- `eof` … EOF
|
||||||
- `neof` … Not EOF
|
- `neof` … Not EOF
|
||||||
|
- `else` … Always true, may be used in the last branch
|
||||||
|
|
||||||
# Syntax
|
# Syntax
|
||||||
|
|
||||||
@@ -207,6 +208,7 @@ Conditonal branches are written like this:
|
|||||||
then only one branch is taken - there is no fall-through.
|
then only one branch is taken - there is no fall-through.
|
||||||
- The definition order is preserved, i.e. if the `inval` flag is to be checked, it should be done
|
- The definition order is preserved, i.e. if the `inval` flag is to be checked, it should be done
|
||||||
before checking e.g. `nz`, which is, incidentally, true by default, because most flags are cleared by instructions that affects flags.
|
before checking e.g. `nz`, which is, incidentally, true by default, because most flags are cleared by instructions that affects flags.
|
||||||
|
- `else` can be used as a final choice of branch that will always be taken.
|
||||||
|
|
||||||
## Routines
|
## Routines
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ pub struct SourcePosition {
|
|||||||
pub index: u32,
|
pub index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SourcePosition {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "{}:{}", self.line, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Since errors are the uncommon case, they're boxed. This keeps the size of
|
/// Since errors are the uncommon case, they're boxed. This keeps the size of
|
||||||
/// structs down, which helps performance in the common case.
|
/// structs down, which helps performance in the common case.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -331,10 +331,11 @@ fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
|
|||||||
//trace!("parse_sexp {}", pos);
|
//trace!("parse_sexp {}", pos);
|
||||||
zspace(s, pos)?;
|
zspace(s, pos)?;
|
||||||
let (c, _) = peek(s, *pos)?;
|
let (c, _) = peek(s, *pos)?;
|
||||||
|
let pos0 = *pos;
|
||||||
let r = if c == '(' {
|
let r = if c == '(' {
|
||||||
Ok(Sexp::List(parse_list(s, pos)?, spos(s, *pos)))
|
Ok(Sexp::List(parse_list(s, pos)?, spos(s, pos0)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Sexp::Atom(parse_atom(s, pos)?, spos(s, *pos)))
|
Ok(Sexp::Atom(parse_atom(s, pos)?, spos(s, pos0)))
|
||||||
};
|
};
|
||||||
zspace(s, pos)?;
|
zspace(s, pos)?;
|
||||||
r
|
r
|
||||||
|
|||||||
@@ -106,6 +106,10 @@ pub enum Cond {
|
|||||||
Eof,
|
Eof,
|
||||||
/// Not empty
|
/// Not empty
|
||||||
NotEof,
|
NotEof,
|
||||||
|
// Always true, for eg. (else? ...)
|
||||||
|
True,
|
||||||
|
/// Always false
|
||||||
|
False,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
||||||
@@ -134,6 +138,7 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
|
|||||||
"neof" => Cond::NotEof,
|
"neof" => Cond::NotEof,
|
||||||
"ov" => Cond::Overflow,
|
"ov" => Cond::Overflow,
|
||||||
"nov" => Cond::NotOverflow,
|
"nov" => Cond::NotOverflow,
|
||||||
|
"else" => Cond::True,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone()));
|
return Err(CrsnError::Parse(format!("Unknown cond: {}", text).into(), pos.clone()));
|
||||||
}
|
}
|
||||||
@@ -174,6 +179,8 @@ impl Display for Cond {
|
|||||||
Cond::Valid => "valid",
|
Cond::Valid => "valid",
|
||||||
Cond::Eof => "eof",
|
Cond::Eof => "eof",
|
||||||
Cond::NotEof => "neof",
|
Cond::NotEof => "neof",
|
||||||
|
Cond::True => "else",
|
||||||
|
Cond::False => "never",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,6 +221,9 @@ impl Not for Cond {
|
|||||||
|
|
||||||
Cond::NotEof => Cond::Eof,
|
Cond::NotEof => Cond::Eof,
|
||||||
Cond::Eof => Cond::NotEof,
|
Cond::Eof => Cond::NotEof,
|
||||||
|
|
||||||
|
Cond::True => Cond::False,
|
||||||
|
Cond::False => Cond::True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ impl Flatten for InstrWithBranches {
|
|||||||
return Err(CrsnError::Asm(AsmError::ConditionalAlreadyUsed(cond), branch.pos()));
|
return Err(CrsnError::Asm(AsmError::ConditionalAlreadyUsed(cond), branch.pos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cnt != branch_count - 1 && cond == Cond::True {
|
||||||
|
warn!("\"Else\" conditional used in non-final branch at {}", branch.pos());
|
||||||
|
}
|
||||||
|
|
||||||
let next_lbl = if cnt == branch_count - 1 {
|
let next_lbl = if cnt == branch_count - 1 {
|
||||||
end_lbl.clone()
|
end_lbl.clone()
|
||||||
} else {
|
} else {
|
||||||
@@ -64,11 +68,13 @@ impl Flatten for InstrWithBranches {
|
|||||||
// optimization for single-branch conditionals with a single instruction
|
// optimization for single-branch conditionals with a single instruction
|
||||||
ops.push(Op { cond: Some(cond), pos: pos.clone(), kind: flattened.remove(0).kind });
|
ops.push(Op { cond: Some(cond), pos: pos.clone(), kind: flattened.remove(0).kind });
|
||||||
} else {
|
} else {
|
||||||
|
if cond != Cond::True { // evoid emiting `op.never`
|
||||||
ops.push(Op {
|
ops.push(Op {
|
||||||
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
|
kind: OpKind::BuiltIn(BuiltinOp::Jump(next_lbl.clone())),
|
||||||
pos: pos.clone(),
|
pos: pos.clone(),
|
||||||
cond: Some(!cond),
|
cond: Some(!cond),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
ops.extend(flattened);
|
ops.extend(flattened);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ impl OpTrait for Op {
|
|||||||
OpKind::Ext(op) => op.to_sexp()
|
OpKind::Ext(op) => op.to_sexp()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO rewrite to be more readable?
|
||||||
if let Some(cond) = self.cond {
|
if let Some(cond) = self.cond {
|
||||||
|
// "true" is used for "else" branches, it has no effect - just omit it
|
||||||
|
if cond != Cond::True {
|
||||||
if let Sexp::List(items, _) = &mut se {
|
if let Sexp::List(items, _) = &mut se {
|
||||||
if let Some(Sexp::Atom(Atom::S(s), _)) = &mut items.get_mut(0) {
|
if let Some(Sexp::Atom(Atom::S(s), _)) = &mut items.get_mut(0) {
|
||||||
s.push('.');
|
s.push('.');
|
||||||
@@ -58,6 +61,7 @@ impl OpTrait for Op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
se
|
se
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ impl StatusFlags {
|
|||||||
Cond::NotEmpty => !self.empty,
|
Cond::NotEmpty => !self.empty,
|
||||||
Cond::Eof => self.eof,
|
Cond::Eof => self.eof,
|
||||||
Cond::NotEof => !self.eof,
|
Cond::NotEof => !self.eof,
|
||||||
|
Cond::True => true,
|
||||||
|
Cond::False => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
(
|
||||||
|
; test else
|
||||||
|
|
||||||
|
(cmp 0 5
|
||||||
|
(eq? (fault))
|
||||||
|
(else? (ld r0 15))
|
||||||
|
(lt? (fault)) ; This should produce a warning
|
||||||
|
)
|
||||||
|
(cmp 15 r0
|
||||||
|
(ne? (fault "else did not run")))
|
||||||
|
|
||||||
|
(ld r0 0)
|
||||||
|
|
||||||
|
(cmp 0 5
|
||||||
|
(lt? (nop))
|
||||||
|
(else? (fault "fallthrough to else"))
|
||||||
|
)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
(ld r8 0)
|
||||||
|
|
||||||
|
(ld r0 1
|
||||||
|
(else? (add r8 1))
|
||||||
|
)
|
||||||
|
|
||||||
|
(sub r0 1
|
||||||
|
(pos? (fault))
|
||||||
|
(else? (add r8 1))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(cmp r8 2
|
||||||
|
(ne? (fault))
|
||||||
|
)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user