mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-15 23:18:48 +00:00
Update IR
This commit is contained in:
@@ -217,7 +217,7 @@ impl AssertSupported for Declarator {
|
||||
fn assert_supported(&self) {
|
||||
self.kind.assert_supported();
|
||||
self.derived.assert_supported();
|
||||
self.extensions.is_empty();
|
||||
assert!(self.extensions.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ impl AssertSupported for ParameterDeclaration {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarator.assert_supported();
|
||||
self.extensions.is_empty();
|
||||
assert!(self.extensions.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ pub trait HasDtype {
|
||||
#[derive(Default)]
|
||||
struct BaseDtype {
|
||||
scalar: Option<ast::TypeSpecifier>,
|
||||
size_modifiers: Option<ast::TypeSpecifier>,
|
||||
size_modifier: Option<ast::TypeSpecifier>,
|
||||
signed_option: Option<ast::TypeSpecifier>,
|
||||
typedef_name: Option<String>,
|
||||
is_const: bool,
|
||||
@@ -129,12 +129,12 @@ impl BaseDtype {
|
||||
self.scalar = Some(type_specifier.clone());
|
||||
}
|
||||
ast::TypeSpecifier::Short | ast::TypeSpecifier::Long => {
|
||||
if self.size_modifiers.is_some() {
|
||||
if self.size_modifier.is_some() {
|
||||
return Err(DtypeError::Misc {
|
||||
message: "two or more size modifiers in declaration specifiers".to_string(),
|
||||
});
|
||||
}
|
||||
self.size_modifiers = Some(type_specifier.clone());
|
||||
self.size_modifier = Some(type_specifier.clone());
|
||||
}
|
||||
ast::TypeSpecifier::TypedefName(identifier) => {
|
||||
if self.typedef_name.is_some() {
|
||||
@@ -277,7 +277,7 @@ impl TryFrom<BaseDtype> for Dtype {
|
||||
fn try_from(spec: BaseDtype) -> Result<Self, DtypeError> {
|
||||
assert!(
|
||||
!(spec.scalar.is_none()
|
||||
&& spec.size_modifiers.is_none()
|
||||
&& spec.size_modifier.is_none()
|
||||
&& spec.signed_option.is_none()
|
||||
&& spec.typedef_name.is_none()
|
||||
&& !spec.is_const),
|
||||
@@ -313,19 +313,19 @@ impl TryFrom<BaseDtype> for Dtype {
|
||||
};
|
||||
|
||||
// Applies size modifier
|
||||
if let Some(size_modifiers) = spec.size_modifiers {
|
||||
if let Some(size_modifier) = spec.size_modifier {
|
||||
if dtype != Self::INT {
|
||||
return Err(DtypeError::Misc {
|
||||
message: "size modifier can only be used with `int`".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
dtype = match size_modifiers {
|
||||
dtype = match size_modifier {
|
||||
ast::TypeSpecifier::Short => Self::SHORT,
|
||||
ast::TypeSpecifier::Long => Self::LONG,
|
||||
_ => panic!(
|
||||
"Dtype::try_from::<BaseDtype>: {:?} is not a size modifier",
|
||||
size_modifiers
|
||||
size_modifier
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -341,6 +341,13 @@ impl TryFrom<BaseDtype> for Dtype {
|
||||
),
|
||||
};
|
||||
|
||||
if dtype.get_int_width().is_none() {
|
||||
return Err(DtypeError::Misc {
|
||||
message: "`signed` and `unsigned` only be applied to `Dtype::Int`"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
dtype = dtype.set_signed(is_signed);
|
||||
}
|
||||
|
||||
@@ -662,12 +669,18 @@ impl Dtype {
|
||||
self.with_ast_array_size(&array_decl.node.size)?
|
||||
}
|
||||
ast::DerivedDeclarator::Function(func_decl) => {
|
||||
let params = func_decl
|
||||
let mut params = func_decl
|
||||
.node
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|p| Self::try_from(&p.node))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// If function parameter is (void), remove it
|
||||
if params.len() == 1 && params[0] == Dtype::unit() {
|
||||
let _ = params.pop();
|
||||
}
|
||||
|
||||
Self::function(self, params)
|
||||
}
|
||||
ast::DerivedDeclarator::KRFunction(kr_func_decl) => {
|
||||
@@ -758,16 +771,6 @@ impl Dtype {
|
||||
|
||||
Ok(dtype)
|
||||
}
|
||||
|
||||
pub fn merge(self, other: Self) -> Result<Self, DtypeError> {
|
||||
if self == other {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(DtypeError::Misc {
|
||||
message: format!("Dtype::merge({:?}, {:?}) failed", self, other),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Dtype {
|
||||
|
||||
@@ -286,27 +286,31 @@ mod calculator {
|
||||
ast::BinaryOperator::Modulo => Ok(Value::int(lhs % rhs, lhs_w, lhs_s)),
|
||||
ast::BinaryOperator::Equals => {
|
||||
let result = if lhs == rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::NotEquals => {
|
||||
let result = if lhs != rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::Less => {
|
||||
// TODO: consider signed option
|
||||
let result = if lhs < rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::Greater => {
|
||||
// TODO: consider signed option
|
||||
let result = if lhs > rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::LessOrEqual => {
|
||||
// TODO: consider signed option
|
||||
let result = if lhs <= rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::GreaterOrEqual => {
|
||||
// TODO: consider signed option
|
||||
let result = if lhs >= rhs { 1 } else { 0 };
|
||||
Ok(Value::int(result, 1, lhs_s))
|
||||
Ok(Value::int(result, 1, false))
|
||||
}
|
||||
ast::BinaryOperator::LogicalAnd => {
|
||||
assert!(lhs < 2);
|
||||
|
||||
@@ -5,6 +5,7 @@ mod write_ir;
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use hexf::{parse_hexf32, parse_hexf64};
|
||||
use lang_c::ast;
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::collections::HashMap;
|
||||
@@ -504,23 +505,44 @@ impl TryFrom<&ast::Constant> for Constant {
|
||||
}
|
||||
.set_signed(is_signed);
|
||||
|
||||
let pat = match integer.base {
|
||||
ast::IntegerBase::Decimal => Self::DECIMAL,
|
||||
ast::IntegerBase::Octal => Self::OCTAL,
|
||||
ast::IntegerBase::Hexadecimal => Self::HEXADECIMAL,
|
||||
};
|
||||
|
||||
let value = if is_signed {
|
||||
integer.number.parse::<i128>().unwrap() as u128
|
||||
i128::from_str_radix(integer.number.deref(), pat).unwrap() as u128
|
||||
} else {
|
||||
integer.number.parse::<u128>().unwrap()
|
||||
u128::from_str_radix(integer.number.deref(), pat).unwrap()
|
||||
};
|
||||
|
||||
Ok(Self::int(value, dtype))
|
||||
}
|
||||
ast::Constant::Float(float) => {
|
||||
let pat = match float.base {
|
||||
ast::FloatBase::Decimal => Self::DECIMAL,
|
||||
ast::FloatBase::Hexadecimal => Self::HEXADECIMAL,
|
||||
};
|
||||
|
||||
let (dtype, value) = match float.suffix.format {
|
||||
ast::FloatFormat::Float => {
|
||||
// Casting from an f32 to an f64 is perfect and lossless (f32 -> f64)
|
||||
// https://doc.rust-lang.org/stable/reference/expressions/operator-expr.html#type-cast-expressions
|
||||
(Dtype::FLOAT, float.number.parse::<f32>().unwrap() as f64)
|
||||
let value = if pat == Self::DECIMAL {
|
||||
float.number.parse::<f32>().unwrap() as f64
|
||||
} else {
|
||||
parse_hexf32(float.number.deref(), false).unwrap() as f64
|
||||
};
|
||||
(Dtype::FLOAT, value)
|
||||
}
|
||||
ast::FloatFormat::Double => {
|
||||
(Dtype::DOUBLE, float.number.parse::<f64>().unwrap())
|
||||
let value = if pat == Self::DECIMAL {
|
||||
float.number.parse::<f64>().unwrap()
|
||||
} else {
|
||||
parse_hexf64(float.number.deref(), false).unwrap()
|
||||
};
|
||||
(Dtype::DOUBLE, value)
|
||||
}
|
||||
ast::FloatFormat::LongDouble => {
|
||||
panic!("`FloatFormat::LongDouble` is_unsupported")
|
||||
@@ -567,6 +589,10 @@ impl TryFrom<&ast::Initializer> for Constant {
|
||||
}
|
||||
|
||||
impl Constant {
|
||||
const DECIMAL: u32 = 10;
|
||||
const OCTAL: u32 = 8;
|
||||
const HEXADECIMAL: u32 = 16;
|
||||
|
||||
#[inline]
|
||||
pub fn is_integer_constant(&self) -> bool {
|
||||
if let Self::Int { .. } = self {
|
||||
|
||||
22
src/tests.rs
22
src/tests.rs
@@ -57,13 +57,21 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) {
|
||||
.status()
|
||||
.expect("failed to remove compiled executable");
|
||||
|
||||
let ir = Irgen::default()
|
||||
.translate(unit)
|
||||
.expect("failed to generate ir");
|
||||
let ir = match Irgen::default().translate(unit) {
|
||||
Ok(ir) => ir,
|
||||
Err(irgen_error) => panic!("{}", irgen_error),
|
||||
};
|
||||
|
||||
let args = Vec::new();
|
||||
assert_eq!(
|
||||
ir::interp(&ir, args),
|
||||
Ok(ir::Value::int(status as u128, 32, true))
|
||||
);
|
||||
let result = match ir::interp(&ir, args) {
|
||||
Ok(result) => result,
|
||||
Err(interp_error) => panic!("{}", interp_error),
|
||||
};
|
||||
let result = if let ir::Value::Int { .. } = &result {
|
||||
result
|
||||
} else {
|
||||
panic!("non-integer value occurs")
|
||||
};
|
||||
|
||||
assert_eq!(result, ir::Value::int(status as u128, 32, true));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user