mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-15 23:18:48 +00:00
Initial commit
This commit is contained in:
2
src/asm.rs
Normal file
2
src/asm.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
/// TODO
|
||||
pub struct Asm {}
|
||||
543
src/assert_ast_equiv.rs
Normal file
543
src/assert_ast_equiv.rs
Normal file
@@ -0,0 +1,543 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use lang_c::ast::*;
|
||||
use lang_c::span::Node;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
trait IsEquiv {
|
||||
fn is_equiv(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
impl<T: IsEquiv> IsEquiv for Node<T> {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.node.is_equiv(&other.node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IsEquiv> IsEquiv for Box<T> {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.deref().is_equiv(other.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IsEquiv> IsEquiv for &T {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
(*self).is_equiv(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IsEquiv> IsEquiv for Option<T> {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Some(lhs), Some(rhs)) => lhs.is_equiv(rhs),
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IsEquiv> IsEquiv for Vec<T> {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && izip!(self, other).all(|(lhs, rhs)| lhs.is_equiv(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for TranslationUnit {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.0.is_equiv(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for ExternalDeclaration {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Declaration(decl), Self::Declaration(other_decl)) => decl.is_equiv(other_decl),
|
||||
(Self::FunctionDefinition(fdef), Self::FunctionDefinition(other_fdef)) => {
|
||||
fdef.is_equiv(other_fdef)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Declaration {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.specifiers.is_equiv(&other.specifiers) && self.declarators.is_equiv(&other.declarators)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for FunctionDefinition {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.specifiers.is_equiv(&other.specifiers)
|
||||
&& self.declarator.is_equiv(&other.declarator)
|
||||
&& self.declarations.is_equiv(&other.declarations)
|
||||
&& self.statement.is_equiv(&other.statement)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for InitDeclarator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.declarator.is_equiv(&other.declarator) && self.initializer.is_equiv(&other.initializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Initializer {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Expression(expr), Self::Expression(other_expr)) => expr.is_equiv(other_expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Declarator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.kind.is_equiv(&other.kind) && self.derived.is_equiv(&other.derived)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for DeclaratorKind {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Identifier(identifier), Self::Identifier(other_identifier)) => {
|
||||
identifier.node.name == other_identifier.node.name
|
||||
}
|
||||
(Self::Declarator(decl), Self::Declarator(other_decl)) => decl.is_equiv(&other_decl),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for DerivedDeclarator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Pointer(pointer_qualifiers), Self::Pointer(other_pointer_qualifiers)) => {
|
||||
pointer_qualifiers.is_equiv(other_pointer_qualifiers)
|
||||
}
|
||||
(Self::Array(array_decl), Self::Array(other_array_decl)) => {
|
||||
let array_decl = &array_decl.node;
|
||||
let other_array_decl = &other_array_decl.node;
|
||||
|
||||
array_decl.qualifiers.is_equiv(&other_array_decl.qualifiers)
|
||||
&& array_decl.size.is_equiv(&other_array_decl.size)
|
||||
}
|
||||
(Self::Function(func_decl), Self::Function(other_func_decl)) => {
|
||||
let params = &func_decl.node.parameters;
|
||||
let other_params = &other_func_decl.node.parameters;
|
||||
params.is_equiv(other_params)
|
||||
}
|
||||
(Self::KRFunction(kr_func_decl), Self::KRFunction(other_kr_func_decl)) => {
|
||||
kr_func_decl.is_equiv(&other_kr_func_decl)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for PointerQualifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::TypeQualifier(type_qualifier), Self::TypeQualifier(other_type_qualifier)) => {
|
||||
type_qualifier.is_equiv(other_type_qualifier)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for ArraySize {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Unknown, Self::Unknown) => true,
|
||||
(Self::VariableUnknown, Self::VariableUnknown) => true,
|
||||
(Self::VariableExpression(expr), Self::VariableExpression(other_expr)) => {
|
||||
expr.is_equiv(&other_expr)
|
||||
}
|
||||
(Self::StaticExpression(expr), Self::StaticExpression(other_expr)) => {
|
||||
expr.is_equiv(&other_expr)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for ParameterDeclaration {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.specifiers.is_equiv(&other.specifiers)
|
||||
&& self
|
||||
.declarator
|
||||
.as_ref()
|
||||
.map(|d| &d.node)
|
||||
.is_equiv(&other.declarator.as_ref().map(|d| &d.node))
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Statement {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Labeled(stmt), Self::Labeled(other_stmt)) => {
|
||||
stmt.node.label.is_equiv(&other_stmt.node.label)
|
||||
&& stmt.node.statement.is_equiv(&other_stmt.node.statement)
|
||||
}
|
||||
(Self::Compound(items), Self::Compound(other_items)) => items.is_equiv(other_items),
|
||||
(Self::Expression(expr), Self::Expression(other_expr)) => {
|
||||
expr.as_ref().is_equiv(&other_expr.as_ref())
|
||||
}
|
||||
(Self::If(stmt), Self::If(other_stmt)) => {
|
||||
let else_stmt = stmt.node.else_statement.as_ref();
|
||||
let other_else_stmt = other_stmt.node.else_statement.as_ref();
|
||||
stmt.node.condition.is_equiv(&other_stmt.node.condition)
|
||||
&& stmt
|
||||
.node
|
||||
.then_statement
|
||||
.is_equiv(&other_stmt.node.then_statement)
|
||||
&& else_stmt.is_equiv(&other_else_stmt)
|
||||
}
|
||||
(Self::Switch(stmt), Self::Switch(other_stmt)) => {
|
||||
stmt.node.expression.is_equiv(&other_stmt.node.expression)
|
||||
&& stmt.node.statement.is_equiv(&other_stmt.node.statement)
|
||||
}
|
||||
(Self::While(stmt), Self::While(other_stmt)) => {
|
||||
stmt.node.expression.is_equiv(&other_stmt.node.expression)
|
||||
&& stmt.node.statement.is_equiv(&other_stmt.node.statement)
|
||||
}
|
||||
(Self::DoWhile(stmt), Self::DoWhile(other_stmt)) => {
|
||||
stmt.node.statement.is_equiv(&other_stmt.node.statement)
|
||||
&& stmt.node.expression.is_equiv(&other_stmt.node.expression)
|
||||
}
|
||||
(Self::For(stmt), Self::For(other_stmt)) => {
|
||||
stmt.node.initializer.is_equiv(&other_stmt.node.initializer)
|
||||
&& stmt
|
||||
.node
|
||||
.condition
|
||||
.as_ref()
|
||||
.is_equiv(&other_stmt.node.condition.as_ref())
|
||||
&& stmt
|
||||
.node
|
||||
.step
|
||||
.as_ref()
|
||||
.is_equiv(&other_stmt.node.step.as_ref())
|
||||
&& stmt.node.statement.is_equiv(&other_stmt.node.statement)
|
||||
}
|
||||
(Self::Goto(label), Self::Goto(other_label)) => label.is_equiv(other_label),
|
||||
(Self::Continue, Self::Continue) => true,
|
||||
(Self::Break, Self::Break) => true,
|
||||
(Self::Return(expr), Self::Return(other_expr)) => expr.is_equiv(other_expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Label {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Identifier(ident), Self::Identifier(other_ident)) => ident.is_equiv(other_ident),
|
||||
(Self::Case(expr), Self::Case(other_expr)) => expr.is_equiv(other_expr),
|
||||
(Self::Default, Self::Default) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Identifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.name == other.name
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for ForInitializer {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Empty, Self::Empty) => true,
|
||||
(Self::Expression(expr), Self::Expression(other_expr)) => expr.is_equiv(other_expr),
|
||||
(Self::Declaration(decl), Self::Declaration(other_decl)) => decl.is_equiv(other_decl),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Expression {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Identifier(identifier), Self::Identifier(other_identifier)) => {
|
||||
identifier.is_equiv(other_identifier)
|
||||
}
|
||||
(Self::Constant(constant), Self::Constant(other_constant)) => {
|
||||
constant.is_equiv(other_constant)
|
||||
}
|
||||
(Self::StringLiteral(other_string_lit), Self::StringLiteral(string_lit)) => {
|
||||
string_lit.is_equiv(other_string_lit)
|
||||
}
|
||||
(Self::Member(member), Self::Member(other_member)) => member.is_equiv(other_member),
|
||||
(Self::Call(call), Self::Call(other_call)) => call.is_equiv(other_call),
|
||||
(Self::SizeOf(typename), Self::SizeOf(other_typename)) => {
|
||||
typename.is_equiv(other_typename)
|
||||
}
|
||||
(Self::AlignOf(typename), Self::AlignOf(other_typename)) => {
|
||||
typename.is_equiv(other_typename)
|
||||
}
|
||||
(Self::UnaryOperator(unary), Self::UnaryOperator(other_unary)) => {
|
||||
unary.node.operator.is_equiv(&other_unary.node.operator)
|
||||
&& unary.node.operand.is_equiv(&other_unary.node.operand)
|
||||
}
|
||||
(Self::Cast(cast), Self::Cast(other_cast)) => {
|
||||
cast.node.type_name.is_equiv(&other_cast.node.type_name)
|
||||
&& cast.node.expression.is_equiv(&other_cast.node.expression)
|
||||
}
|
||||
(Self::BinaryOperator(binary), Self::BinaryOperator(other_binary)) => {
|
||||
binary.node.lhs.is_equiv(&other_binary.node.lhs)
|
||||
&& binary.node.operator.is_equiv(&other_binary.node.operator)
|
||||
&& binary.node.rhs.is_equiv(&other_binary.node.rhs)
|
||||
}
|
||||
(Self::Conditional(conditional), Self::Conditional(other_conditional)) => {
|
||||
conditional
|
||||
.node
|
||||
.condition
|
||||
.is_equiv(&other_conditional.node.condition)
|
||||
&& conditional
|
||||
.node
|
||||
.then_expression
|
||||
.is_equiv(&other_conditional.node.then_expression)
|
||||
&& conditional
|
||||
.node
|
||||
.else_expression
|
||||
.is_equiv(&other_conditional.node.else_expression)
|
||||
}
|
||||
(Self::Comma(exprs), Self::Comma(other_exprs)) => {
|
||||
exprs.as_ref().is_equiv(other_exprs.as_ref())
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for TypeName {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.specifiers.is_equiv(&other.specifiers) && self.declarator.is_equiv(&other.declarator)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for SpecifierQualifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::TypeSpecifier(type_specifier), Self::TypeSpecifier(other_type_specifier)) => {
|
||||
type_specifier.is_equiv(other_type_specifier)
|
||||
}
|
||||
|
||||
(Self::TypeQualifier(type_qualifier), Self::TypeQualifier(other_type_qualifier)) => {
|
||||
type_qualifier.is_equiv(other_type_qualifier)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for MemberExpression {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.expression.is_equiv(&other.expression)
|
||||
&& self.operator.is_equiv(&other.operator)
|
||||
&& self.identifier.is_equiv(&other.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for MemberOperator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for UnaryOperator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for BinaryOperator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Constant {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Integer(integer), Self::Integer(other_integer)) => {
|
||||
integer.base.is_equiv(&other_integer.base)
|
||||
&& integer.number == other_integer.number
|
||||
&& integer.suffix.is_equiv(&other_integer.suffix)
|
||||
}
|
||||
(Self::Float(float), Self::Float(other_float)) => {
|
||||
float.base == other_float.base
|
||||
&& float.number == other_float.number
|
||||
&& float.suffix.is_equiv(&other_float.suffix)
|
||||
}
|
||||
(Self::Character(literal), Self::Character(other_literal)) => literal == other_literal,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for IntegerBase {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for IntegerSuffix {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.unsigned == other.unsigned && self.size == other.size
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for FloatSuffix {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.imaginary == other.imaginary && self.format == other.format
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StringLiteral {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for BlockItem {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Declaration(decl), Self::Declaration(other_decl)) => decl.is_equiv(other_decl),
|
||||
(Self::Statement(statement), Self::Statement(other_statement)) => {
|
||||
statement.is_equiv(other_statement)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for DeclarationSpecifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(
|
||||
Self::StorageClass(storage_class_spec),
|
||||
Self::StorageClass(other_storage_class_spec),
|
||||
) => storage_class_spec.is_equiv(other_storage_class_spec),
|
||||
(Self::TypeSpecifier(type_specifier), Self::TypeSpecifier(other_type_specifier)) => {
|
||||
type_specifier.is_equiv(other_type_specifier)
|
||||
}
|
||||
(Self::TypeQualifier(type_qualifier), Self::TypeQualifier(other_type_qualifier)) => {
|
||||
type_qualifier.is_equiv(other_type_qualifier)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StorageClassSpecifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for TypeSpecifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Void, Self::Void) => true,
|
||||
(Self::Char, Self::Char) => true,
|
||||
(Self::Short, Self::Short) => true,
|
||||
(Self::Int, Self::Int) => true,
|
||||
(Self::Long, Self::Long) => true,
|
||||
(Self::Float, Self::Float) => true,
|
||||
(Self::Double, Self::Double) => true,
|
||||
(Self::Signed, Self::Signed) => true,
|
||||
(Self::Unsigned, Self::Unsigned) => true,
|
||||
(Self::Bool, Self::Bool) => true,
|
||||
(Self::Struct(struct_type), Self::Struct(other_struct_type)) => {
|
||||
struct_type.is_equiv(other_struct_type)
|
||||
}
|
||||
(Self::Enum(enum_type), Self::Enum(other_enum_type)) => {
|
||||
enum_type.is_equiv(other_enum_type)
|
||||
}
|
||||
(Self::TypedefName(identifier), Self::TypedefName(other_identifier)) => {
|
||||
identifier.is_equiv(other_identifier)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StructType {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.declarations.is_equiv(&other.declarations)
|
||||
&& self.kind.is_equiv(&other.kind)
|
||||
&& self.identifier.is_equiv(&other.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StructKind {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StructDeclaration {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Field(struct_field), Self::Field(other_struct_field)) => {
|
||||
struct_field.is_equiv(other_struct_field)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StructField {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.specifiers.is_equiv(&other.specifiers) && self.declarators.is_equiv(&other.declarators)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for StructDeclarator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.declarator.is_equiv(&other.declarator) && self.bit_width.is_equiv(&other.bit_width)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for EnumType {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.identifier.is_equiv(&other.identifier) && self.enumerators.is_equiv(&other.enumerators)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for Enumerator {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.identifier.is_equiv(&other.identifier) && self.expression.is_equiv(&other.expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for TypeQualifier {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Const, Self::Const) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsEquiv for CallExpression {
|
||||
fn is_equiv(&self, other: &Self) -> bool {
|
||||
self.callee.is_equiv(&other.callee) && self.arguments.is_equiv(&other.arguments)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_ast_equiv(lhs: &TranslationUnit, rhs: &TranslationUnit) {
|
||||
if !lhs.is_equiv(rhs) {
|
||||
panic!(
|
||||
r#"assertion failed: `(left.is_equiv(right))`
|
||||
left: `{:?}`,
|
||||
right: `{:?}`"#,
|
||||
lhs, rhs
|
||||
)
|
||||
}
|
||||
}
|
||||
15
src/codegen.rs
Normal file
15
src/codegen.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use crate::asm::Asm;
|
||||
use crate::ir;
|
||||
use crate::Translate;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Codegen {}
|
||||
|
||||
impl Translate<ir::TranslationUnit> for Codegen {
|
||||
type Target = Asm;
|
||||
type Error = ();
|
||||
|
||||
fn translate(&mut self, _source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
26
src/irgen.rs
Normal file
26
src/irgen.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use std::fmt;
|
||||
|
||||
use lang_c::ast::*;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Irgen {}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct IrgenError {}
|
||||
|
||||
impl fmt::Display for IrgenError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "IrgenError")
|
||||
}
|
||||
}
|
||||
|
||||
impl Translate<TranslationUnit> for Irgen {
|
||||
type Target = ir::TranslationUnit;
|
||||
type Error = IrgenError;
|
||||
|
||||
fn translate(&mut self, _unit: &TranslationUnit) -> Result<Self::Target, Self::Error> {
|
||||
todo!("homework 2")
|
||||
}
|
||||
}
|
||||
37
src/lib.rs
Normal file
37
src/lib.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
mod utils;
|
||||
|
||||
pub mod asm;
|
||||
pub mod ir;
|
||||
|
||||
mod codegen;
|
||||
mod irgen;
|
||||
mod optimize;
|
||||
mod parse;
|
||||
|
||||
pub mod run_ir;
|
||||
mod write_asm;
|
||||
mod write_base;
|
||||
mod write_c;
|
||||
mod write_ir;
|
||||
|
||||
pub mod assert_ast_equiv;
|
||||
pub mod write_c_test;
|
||||
|
||||
pub use utils::*;
|
||||
|
||||
pub use asm::Asm;
|
||||
|
||||
pub use codegen::Codegen;
|
||||
pub use irgen::Irgen;
|
||||
pub use optimize::{O0, O1};
|
||||
pub use parse::Parse;
|
||||
pub use utils::{Optimize, Repeat, Translate};
|
||||
|
||||
pub use write_asm::write_asm;
|
||||
pub use write_c::write_c;
|
||||
pub use write_ir::write_ir;
|
||||
|
||||
pub use assert_ast_equiv::assert_ast_equiv;
|
||||
pub use write_c_test::write_c_test;
|
||||
31
src/optimize.rs
Normal file
31
src/optimize.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::ir;
|
||||
use crate::{Optimize, Repeat};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct O0 {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Mem2reg {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Gvn {}
|
||||
|
||||
pub type O1 = Repeat<(Mem2reg, Gvn)>;
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for O0 {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for Mem2reg {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for Gvn {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
551
src/parse.rs
Normal file
551
src/parse.rs
Normal file
@@ -0,0 +1,551 @@
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
|
||||
use lang_c::ast::*;
|
||||
use lang_c::driver::{parse, Config, Error as ParseError};
|
||||
use lang_c::span::Node;
|
||||
|
||||
use crate::Translate;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ParseError(ParseError),
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Parse {}
|
||||
|
||||
impl<P: AsRef<Path>> Translate<P> for Parse {
|
||||
type Target = TranslationUnit;
|
||||
type Error = Error;
|
||||
|
||||
fn translate(&mut self, source: &P) -> Result<Self::Target, Self::Error> {
|
||||
let config = Config::default();
|
||||
let ast = parse(&config, source).map_err(Error::ParseError)?;
|
||||
let unit = ast.unit;
|
||||
|
||||
unit.assert_supported();
|
||||
Ok(unit)
|
||||
}
|
||||
}
|
||||
|
||||
trait AssertSupported {
|
||||
fn assert_supported(&self);
|
||||
}
|
||||
|
||||
impl<T: AssertSupported> AssertSupported for Node<T> {
|
||||
fn assert_supported(&self) {
|
||||
self.node.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AssertSupported> AssertSupported for Option<T> {
|
||||
fn assert_supported(&self) {
|
||||
if let Some(this) = self {
|
||||
this.assert_supported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AssertSupported> AssertSupported for Box<T> {
|
||||
fn assert_supported(&self) {
|
||||
self.deref().assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AssertSupported> AssertSupported for Vec<T> {
|
||||
fn assert_supported(&self) {
|
||||
self.iter().for_each(AssertSupported::assert_supported);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AssertSupported> AssertSupported for [T] {
|
||||
fn assert_supported(&self) {
|
||||
self.iter().for_each(AssertSupported::assert_supported);
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for TranslationUnit {
|
||||
fn assert_supported(&self) {
|
||||
self.0.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for ExternalDeclaration {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Declaration(decl) => decl.assert_supported(),
|
||||
Self::StaticAssert(_) => panic!("ExternalDeclaration::StaticAssert"),
|
||||
Self::FunctionDefinition(fdef) => fdef.assert_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Declaration {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarators.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for FunctionDefinition {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarator.assert_supported();
|
||||
self.declarations.is_empty();
|
||||
self.statement.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for DeclarationSpecifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::StorageClass(_) => panic!("DeclarationSpecifier::StorageClass"),
|
||||
Self::TypeSpecifier(type_specifier) => type_specifier.assert_supported(),
|
||||
Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(),
|
||||
Self::Function(_) => panic!("DeclarationSpecifier::Function"),
|
||||
Self::Alignment(_) => panic!("DeclarationSpecifier::Alignment"),
|
||||
Self::Extension(_) => panic!("DeclarationSpecifier::Extension"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for TypeSpecifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Void => (),
|
||||
Self::Char => (),
|
||||
Self::Short => (),
|
||||
Self::Int => (),
|
||||
Self::Long => (),
|
||||
Self::Float => (),
|
||||
Self::Double => (),
|
||||
Self::Signed => (),
|
||||
Self::Unsigned => (),
|
||||
Self::Bool => (),
|
||||
Self::Complex => panic!("TypeSpecifier::Complex"),
|
||||
Self::Atomic(_) => panic!("TypeSpecifier::Atomic"),
|
||||
Self::Struct(struct_type) => struct_type.assert_supported(),
|
||||
Self::Enum(_) => panic!("TypeSpecifier::Enum"),
|
||||
Self::TypedefName(_) => panic!("TypeSpecifier::TypedefName"),
|
||||
Self::TypeOf(_) => panic!("TypeSpecifier::TypeOf"),
|
||||
Self::TS18661Float(_) => panic!("TypeSpecifier::TS18661Float"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for StructType {
|
||||
fn assert_supported(&self) {
|
||||
self.kind.assert_supported();
|
||||
self.declarations.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for StructDeclaration {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Field(field) => field.assert_supported(),
|
||||
Self::StaticAssert(_) => panic!("StructDeclaration::StaticAssert"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for StructField {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarators.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for StructDeclarator {
|
||||
fn assert_supported(&self) {
|
||||
self.declarator.assert_supported();
|
||||
assert_eq!(true, self.bit_width.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for StructKind {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Struct => (),
|
||||
Self::Union => panic!("StructKind::Union"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for AlignmentSpecifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Type(typename) => typename.assert_supported(),
|
||||
Self::Constant(_) => panic!(AlignmentSpecifier::Constant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for InitDeclarator {
|
||||
fn assert_supported(&self) {
|
||||
self.declarator.assert_supported();
|
||||
self.initializer.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Initializer {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Expression(expr) => expr.assert_supported(),
|
||||
Self::List(_) => panic!("Initializer::List"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Declarator {
|
||||
fn assert_supported(&self) {
|
||||
self.kind.assert_supported();
|
||||
self.derived.assert_supported();
|
||||
self.extensions.is_empty();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for DerivedDeclarator {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Pointer(pointer_qualifiers) => pointer_qualifiers.assert_supported(),
|
||||
Self::Array(array_decl) => array_decl.assert_supported(),
|
||||
Self::Function(func_decl) => func_decl.assert_supported(),
|
||||
// Support when K&R function has no parameter
|
||||
Self::KRFunction(kr_func_decl) => assert_eq!(true, kr_func_decl.is_empty()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for PointerQualifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(),
|
||||
Self::Extension(_) => panic!("PointerQualifier::Extension"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for ArrayDeclarator {
|
||||
fn assert_supported(&self) {
|
||||
self.qualifiers.assert_supported();
|
||||
self.size.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for TypeQualifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Const => (),
|
||||
_ => panic!("TypeQualifier::_"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for ArraySize {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::VariableExpression(expr) => expr.assert_supported(),
|
||||
_ => panic!("ArraySize::_"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for FunctionDeclarator {
|
||||
fn assert_supported(&self) {
|
||||
self.parameters.assert_supported();
|
||||
assert_eq!(self.ellipsis, Ellipsis::None);
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for ParameterDeclaration {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarator.assert_supported();
|
||||
self.extensions.is_empty();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for DeclaratorKind {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Abstract => panic!("DeclaratorKind::Abstract"),
|
||||
Self::Identifier(_) => (),
|
||||
Self::Declarator(decl) => decl.assert_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for BlockItem {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Declaration(decl) => decl.assert_supported(),
|
||||
Self::StaticAssert(_) => panic!("BlockItem::StaticAssert"),
|
||||
Self::Statement(stmt) => stmt.assert_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for ForInitializer {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Empty => (),
|
||||
Self::Expression(expr) => expr.assert_supported(),
|
||||
Self::Declaration(decl) => decl.assert_supported(),
|
||||
Self::StaticAssert(_) => panic!("ForInitializer::StaticAssert"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Statement {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Labeled(_) => panic!("Statement::Labeled"),
|
||||
Self::Compound(items) => items.assert_supported(),
|
||||
Self::Expression(expr) => expr.assert_supported(),
|
||||
Self::If(stmt) => {
|
||||
stmt.node.condition.assert_supported();
|
||||
stmt.node.then_statement.assert_supported();
|
||||
stmt.node.else_statement.assert_supported();
|
||||
}
|
||||
Self::Switch(stmt) => stmt.assert_supported(),
|
||||
Self::While(stmt) => {
|
||||
stmt.node.expression.assert_supported();
|
||||
stmt.node.statement.assert_supported();
|
||||
}
|
||||
Self::DoWhile(stmt) => {
|
||||
stmt.node.statement.assert_supported();
|
||||
stmt.node.expression.assert_supported();
|
||||
}
|
||||
Self::For(stmt) => {
|
||||
stmt.node.initializer.assert_supported();
|
||||
stmt.node.condition.assert_supported();
|
||||
stmt.node.step.assert_supported();
|
||||
stmt.node.statement.assert_supported();
|
||||
}
|
||||
Self::Goto(_) => panic!("Statement::Goto"),
|
||||
Self::Continue | Self::Break => (),
|
||||
Self::Return(expr) => expr.assert_supported(),
|
||||
Self::Asm(_) => panic!("Statement::Asm"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for SwitchStatement {
|
||||
fn assert_supported(&self) {
|
||||
self.expression.assert_supported();
|
||||
|
||||
let items = if let Statement::Compound(items) = &self.statement.node {
|
||||
items
|
||||
} else {
|
||||
panic!("`Statement` in the `switch` is unsupported except `Statement::Compound`")
|
||||
};
|
||||
|
||||
for item in items {
|
||||
let stmt = if let BlockItem::Statement(stmt) = &item.node {
|
||||
&stmt.node
|
||||
} else {
|
||||
panic!(
|
||||
"`BlockItem` in the `Statement::Compound` of the `switch` \
|
||||
is unsupported except `BlockItem::Statement`"
|
||||
)
|
||||
};
|
||||
|
||||
let stmt_in_label = if let Statement::Labeled(label_stmt) = stmt {
|
||||
label_stmt.node.label.assert_supported();
|
||||
&label_stmt.node.statement.node
|
||||
} else {
|
||||
panic!(
|
||||
"`BlockItem::Statement` in the `Statement::Compound` of the `switch` \
|
||||
is unsupported except `Statement::Labeled`"
|
||||
)
|
||||
};
|
||||
|
||||
let items = if let Statement::Compound(items) = stmt_in_label {
|
||||
items
|
||||
} else {
|
||||
panic!("`Statement` in the `label` is unsupported except `Statement::Compound`")
|
||||
};
|
||||
|
||||
// Split last and all the rest of the elements of the `Compound` items
|
||||
let (last, items) = items
|
||||
.split_last()
|
||||
.unwrap_or_else(|| panic!("`Statement::Compound` has no item"));
|
||||
|
||||
for item in items {
|
||||
match &item.node {
|
||||
BlockItem::Declaration(decl) => decl.assert_supported(),
|
||||
BlockItem::StaticAssert(_) => panic!("BlockItem::StaticAssert"),
|
||||
BlockItem::Statement(stmt) => {
|
||||
assert_ne!(
|
||||
&stmt.node,
|
||||
&Statement::Break,
|
||||
"`BlockItem::Statement` in the `Statement::Compound` of the \
|
||||
`label` should not be `Statement::Break` except the last one"
|
||||
);
|
||||
stmt.assert_supported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The last element of the `items` must be `Statement::Break`
|
||||
let stmt = if let BlockItem::Statement(stmt) = &last.node {
|
||||
&stmt.node
|
||||
} else {
|
||||
panic!(
|
||||
"`BlockItem` in the `Statement::Compound` of the `label` \
|
||||
is unsupported except `BlockItem::Statement`"
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
stmt,
|
||||
&Statement::Break,
|
||||
"the last `BlockItem` in the `Statement::Compound` \
|
||||
of the `label` must be `Statement::Break`"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Expression {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Identifier(_) => (),
|
||||
Self::Constant(constant) => constant.assert_supported(),
|
||||
Self::StringLiteral(_) => panic!("Expression:StringLiteral"),
|
||||
Self::GenericSelection(_) => panic!("Expression:GenericSelection"),
|
||||
Self::Member(member) => member.assert_supported(),
|
||||
Self::Call(call) => call.assert_supported(),
|
||||
Self::CompoundLiteral(_) => panic!("Expression::CompoundLiteral"),
|
||||
Self::SizeOf(typename) => typename.assert_supported(),
|
||||
Self::AlignOf(typename) => typename.assert_supported(),
|
||||
Self::UnaryOperator(unary) => unary.assert_supported(),
|
||||
Self::Cast(cast) => cast.assert_supported(),
|
||||
Self::BinaryOperator(binary) => binary.assert_supported(),
|
||||
Self::Conditional(conditional) => conditional.assert_supported(),
|
||||
Self::Comma(exprs) => exprs.assert_supported(),
|
||||
Self::OffsetOf(_) => panic!("Expression::OffsetOf"),
|
||||
Self::VaArg(_) => panic!("Expression::VaArg"),
|
||||
Self::Statement(_) => panic!("Expression::Statement"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Label {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Identifier(_) => panic!("Label::Identifier"),
|
||||
Self::Case(_) => (),
|
||||
Self::Default => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for MemberExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.expression.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for CallExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.callee.assert_supported();
|
||||
self.arguments.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for TypeName {
|
||||
fn assert_supported(&self) {
|
||||
self.specifiers.assert_supported();
|
||||
self.declarator.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for SpecifierQualifier {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::TypeSpecifier(type_specifier) => type_specifier.assert_supported(),
|
||||
Self::TypeQualifier(type_qualifier) => type_qualifier.assert_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for UnaryOperatorExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.operator.assert_supported();
|
||||
self.operand.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for CastExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.type_name.assert_supported();
|
||||
self.expression.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for BinaryOperatorExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.operator.assert_supported();
|
||||
self.lhs.assert_supported();
|
||||
self.rhs.assert_supported();
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Constant {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Integer(integer) => integer.assert_supported(),
|
||||
Self::Float(float) => float.assert_supported(),
|
||||
Self::Character(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Integer {
|
||||
fn assert_supported(&self) {
|
||||
assert_eq!(false, self.suffix.imaginary);
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for Float {
|
||||
fn assert_supported(&self) {
|
||||
assert_eq!(self.base, FloatBase::Decimal);
|
||||
self.suffix.format.assert_supported();
|
||||
assert_eq!(false, self.suffix.imaginary);
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for FloatFormat {
|
||||
fn assert_supported(&self) {
|
||||
match self {
|
||||
Self::Float => (),
|
||||
Self::Double => (),
|
||||
Self::LongDouble => (),
|
||||
Self::TS18661Format(_) => panic!("TS18861"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for UnaryOperator {
|
||||
fn assert_supported(&self) {
|
||||
if let Self::SizeOf = self {
|
||||
panic!("UnaryOperaotr::SizeOf")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AssertSupported for BinaryOperator {
|
||||
fn assert_supported(&self) {}
|
||||
}
|
||||
|
||||
impl AssertSupported for ConditionalExpression {
|
||||
fn assert_supported(&self) {
|
||||
self.condition.assert_supported();
|
||||
self.then_expression.assert_supported();
|
||||
self.else_expression.assert_supported();
|
||||
}
|
||||
}
|
||||
592
src/run_ir.rs
Normal file
592
src/run_ir.rs
Normal file
@@ -0,0 +1,592 @@
|
||||
use crate::ir::*;
|
||||
use crate::*;
|
||||
|
||||
use failure::Fail;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
// TODO: the variants of Value will be added in the future
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Value {
|
||||
Undef,
|
||||
Unit,
|
||||
Int(i32),
|
||||
Float(f32),
|
||||
Bool(bool),
|
||||
Pointer { bid: Option<usize>, offset: usize },
|
||||
}
|
||||
|
||||
impl Value {
|
||||
#[inline]
|
||||
fn pointer(bid: Option<usize>, offset: usize) -> Self {
|
||||
Self::Pointer { bid, offset }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_bool(self) -> Option<bool> {
|
||||
if let Value::Bool(value) = self {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_pointer(self) -> Option<(Option<usize>, usize)> {
|
||||
if let Value::Pointer { bid, offset } = self {
|
||||
Some((bid, offset))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nullptr() -> Self {
|
||||
Self::Pointer {
|
||||
bid: None,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn default_from_dtype(dtype: &Dtype) -> Self {
|
||||
match dtype {
|
||||
// TODO: consider `Unit` value in the future
|
||||
ir::Dtype::Unit { .. } => todo!(),
|
||||
ir::Dtype::Int { width, .. } => match width {
|
||||
32 => Self::Int(i32::default()),
|
||||
_ => todo!("other cases will be covered"),
|
||||
},
|
||||
ir::Dtype::Float { .. } => Self::Float(f32::default()),
|
||||
ir::Dtype::Pointer { .. } => Self::nullptr(),
|
||||
ir::Dtype::Function { .. } => panic!("function types do not have a default value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Fail)]
|
||||
pub enum InterpreterError {
|
||||
#[fail(display = "current block is unreachable")]
|
||||
Unreachable,
|
||||
#[fail(display = "ir has no main function")]
|
||||
NoMainFunction,
|
||||
#[fail(display = "ir has no function definition of {} function", func_name)]
|
||||
NoFunctionDefinition { func_name: String },
|
||||
#[fail(
|
||||
display = "{}:{}:{} / Undef value cannot be used as an operand",
|
||||
func_name, bid, iid
|
||||
)]
|
||||
Undef {
|
||||
func_name: String,
|
||||
bid: BlockId,
|
||||
iid: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct Pc {
|
||||
pub bid: BlockId,
|
||||
pub iid: usize,
|
||||
}
|
||||
|
||||
impl Pc {
|
||||
fn new(bid: BlockId) -> Pc {
|
||||
Pc { bid, iid: 0 }
|
||||
}
|
||||
|
||||
fn increment(&mut self) {
|
||||
self.iid += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct RegisterMap {
|
||||
inner: HashMap<RegisterId, Value>,
|
||||
}
|
||||
|
||||
impl RegisterMap {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Clone)]
|
||||
/// Bidirectional map between the name of a global variable and memory box id
|
||||
struct GlobalMap {
|
||||
/// Map name of a global variable to memory box id
|
||||
///
|
||||
/// Since IR treats global variable as `Constant::GlobalVariable`,
|
||||
/// the interpreter should be able to generate pointer values by infer 'bid'
|
||||
/// from the 'name' of the global variable.
|
||||
var_to_bid: HashMap<String, usize>,
|
||||
/// Map memory box id to the name of a global variable
|
||||
///
|
||||
/// When a function call occurs, the interpreter should be able to find `name` of the function
|
||||
/// from `bid` of the `callee` which is a function pointer.
|
||||
bid_to_var: HashMap<usize, String>,
|
||||
}
|
||||
|
||||
impl GlobalMap {
|
||||
/// Create a bi-directional mapping between `var` and `bid`.
|
||||
fn insert(&mut self, var: String, bid: usize) -> Result<(), InterpreterError> {
|
||||
if self.var_to_bid.insert(var.clone(), bid).is_some() {
|
||||
panic!("variable name should be unique in IR")
|
||||
}
|
||||
if self.bid_to_var.insert(bid, var).is_some() {
|
||||
panic!("`bid` is connected to only one `var`")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_bid(&self, var: &str) -> Option<usize> {
|
||||
self.var_to_bid.get(var).cloned()
|
||||
}
|
||||
|
||||
fn get_var(&self, bid: usize) -> Option<String> {
|
||||
self.bid_to_var.get(&bid).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct StackFrame<'i> {
|
||||
pub pc: Pc,
|
||||
pub registers: RegisterMap,
|
||||
pub func_name: String,
|
||||
pub func_def: &'i FunctionDefinition,
|
||||
}
|
||||
|
||||
impl<'i> StackFrame<'i> {
|
||||
fn new(bid: BlockId, func_name: String, func_def: &'i FunctionDefinition) -> Self {
|
||||
StackFrame {
|
||||
pc: Pc::new(bid),
|
||||
registers: RegisterMap::new(),
|
||||
func_name,
|
||||
func_def,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod calculator {
|
||||
use super::Value;
|
||||
use lang_c::ast;
|
||||
|
||||
pub fn calculate_binary_operator_expression(
|
||||
op: &ast::BinaryOperator,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
) -> Result<Value, ()> {
|
||||
match (op, lhs, rhs) {
|
||||
(_, Value::Undef, _) => Err(()),
|
||||
(_, _, Value::Undef) => Err(()),
|
||||
(ast::BinaryOperator::Plus, Value::Int(lhs), Value::Int(rhs)) => {
|
||||
Ok(Value::Int(lhs + rhs))
|
||||
}
|
||||
(ast::BinaryOperator::Minus, Value::Int(lhs), Value::Int(rhs)) => {
|
||||
Ok(Value::Int(lhs - rhs))
|
||||
}
|
||||
(ast::BinaryOperator::Equals, Value::Int(lhs), Value::Int(rhs)) => {
|
||||
Ok(Value::Bool(lhs == rhs))
|
||||
}
|
||||
(ast::BinaryOperator::NotEquals, Value::Int(lhs), Value::Int(rhs)) => {
|
||||
Ok(Value::Bool(lhs != rhs))
|
||||
}
|
||||
(ast::BinaryOperator::Less, Value::Int(lhs), Value::Int(rhs)) => {
|
||||
Ok(Value::Bool(lhs < rhs))
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_unary_operator_expression(
|
||||
op: &ast::UnaryOperator,
|
||||
operand: Value,
|
||||
) -> Result<Value, ()> {
|
||||
match (op, operand) {
|
||||
(_, Value::Undef) => Err(()),
|
||||
(ast::UnaryOperator::Plus, Value::Int(value)) => Ok(Value::Int(value)),
|
||||
(ast::UnaryOperator::Minus, Value::Int(value)) => Ok(Value::Int(-value)),
|
||||
(ast::UnaryOperator::Negate, Value::Bool(value)) => Ok(Value::Bool(!value)),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: allocation fields will be added in the future
|
||||
// TODO: program fields will be added in the future
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct State<'i> {
|
||||
/// A data structure that maps each global variable to a pointer value
|
||||
/// When function call occurs, `registers` can be initialized by `global_registers`
|
||||
pub global_map: GlobalMap,
|
||||
pub stack_frame: StackFrame<'i>,
|
||||
pub stack: Vec<StackFrame<'i>>,
|
||||
// TODO: memory type should change to Vec<Vec<Byte>>
|
||||
pub memory: Vec<Vec<Value>>,
|
||||
pub ir: &'i TranslationUnit,
|
||||
}
|
||||
|
||||
impl<'i> State<'i> {
|
||||
fn new(ir: &'i TranslationUnit, args: Vec<Value>) -> Result<State, InterpreterError> {
|
||||
// Interpreter starts with the main function
|
||||
let func_name = String::from("main");
|
||||
let func = ir
|
||||
.decls
|
||||
.get(&func_name)
|
||||
.ok_or_else(|| InterpreterError::NoMainFunction)?;
|
||||
let (_, func_def) = func
|
||||
.get_function()
|
||||
.ok_or_else(|| InterpreterError::NoMainFunction)?;
|
||||
let func_def = func_def
|
||||
.as_ref()
|
||||
.ok_or_else(|| InterpreterError::NoFunctionDefinition {
|
||||
func_name: func_name.clone(),
|
||||
})?;
|
||||
|
||||
// Create State
|
||||
let mut state = State {
|
||||
global_map: GlobalMap::default(),
|
||||
stack_frame: StackFrame::new(func_def.bid_init.clone(), func_name, func_def),
|
||||
stack: Vec::new(),
|
||||
memory: Vec::new(),
|
||||
ir,
|
||||
};
|
||||
|
||||
state.alloc_global_variable()?;
|
||||
|
||||
// Initialize state with main function and args
|
||||
state.pass_arguments(args)?;
|
||||
state.alloc_local_variable()?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn alloc_global_variable(&mut self) -> Result<(), InterpreterError> {
|
||||
for (name, decl) in &self.ir.decls {
|
||||
// Memory allocation
|
||||
let bid = self.alloc_memory(&decl.dtype())?;
|
||||
self.global_map.insert(name.clone(), bid)?;
|
||||
|
||||
// Initialize allocated memory space
|
||||
match decl {
|
||||
Declaration::Variable { dtype, initializer } => {
|
||||
let value = if let Some(constant) = initializer {
|
||||
self.constant_to_value(constant.clone())
|
||||
} else {
|
||||
Value::default_from_dtype(dtype)
|
||||
};
|
||||
|
||||
self.memory[bid][0] = value;
|
||||
}
|
||||
// If functin declaration, skip initialization
|
||||
Declaration::Function { .. } => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pass_arguments(&mut self, args: Vec<Value>) -> Result<(), InterpreterError> {
|
||||
for (i, value) in args.iter().enumerate() {
|
||||
self.register_write(RegisterId::arg(i), value.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn alloc_local_variable(&mut self) -> Result<(), InterpreterError> {
|
||||
// add alloc register
|
||||
for (id, allocation) in self.stack_frame.func_def.allocations.iter().enumerate() {
|
||||
let bid = self.alloc_memory(&allocation)?;
|
||||
let ptr = Value::pointer(Some(bid), 0);
|
||||
let rid = RegisterId::local("".to_string(), id);
|
||||
|
||||
self.register_write(rid, ptr)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn alloc_memory(&mut self, dtype: &Dtype) -> Result<usize, InterpreterError> {
|
||||
// TODO: memory block will be handled as Vec<Byte>
|
||||
let memory_block = match dtype {
|
||||
Dtype::Unit { .. } => vec![],
|
||||
Dtype::Int { width, .. } => match width {
|
||||
32 => vec![Value::Undef],
|
||||
_ => todo!(),
|
||||
},
|
||||
Dtype::Float { .. } => todo!(),
|
||||
Dtype::Pointer { .. } => vec![Value::Undef],
|
||||
Dtype::Function { .. } => vec![],
|
||||
};
|
||||
|
||||
self.memory.push(memory_block);
|
||||
|
||||
Ok(self.memory.len() - 1)
|
||||
}
|
||||
|
||||
fn preprocess_args(
|
||||
&self,
|
||||
signature: &FunctionSignature,
|
||||
args: &[Operand],
|
||||
) -> Result<Vec<Value>, InterpreterError> {
|
||||
// Check that the dtype of each args matches the expected
|
||||
if !(args.len() == signature.params.len()
|
||||
&& izip!(args, &signature.params).all(|(a, d)| a.dtype().is_compatible(d)))
|
||||
{
|
||||
panic!("dtype of args and params must be compatible")
|
||||
}
|
||||
|
||||
args.iter()
|
||||
.map(|a| self.get_value(a.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
fn step(&mut self) -> Result<Option<Value>, InterpreterError> {
|
||||
let block = self
|
||||
.stack_frame
|
||||
.func_def
|
||||
.blocks
|
||||
.get(&self.stack_frame.pc.bid.clone())
|
||||
.expect("block matched with `bid` must be exist");
|
||||
|
||||
if block.instructions.len() == self.stack_frame.pc.iid {
|
||||
self.interpret_block_exit(&block.exit)
|
||||
} else {
|
||||
let instr = block
|
||||
.instructions
|
||||
.get(self.stack_frame.pc.iid)
|
||||
.expect("instruction matched with `iid` must be exist");
|
||||
|
||||
self.interpret_instruction(instr)
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&mut self) -> Result<Value, InterpreterError> {
|
||||
loop {
|
||||
if let Some(value) = self.step()? {
|
||||
// TODO: Before return, free memory allocated in a function
|
||||
|
||||
// restore previous state
|
||||
let prev_stack_frame = some_or!(self.stack.pop(), {
|
||||
return Ok(value);
|
||||
});
|
||||
self.stack_frame = prev_stack_frame;
|
||||
|
||||
// create temporary register to write return value
|
||||
let register =
|
||||
RegisterId::temp(self.stack_frame.pc.bid.clone(), self.stack_frame.pc.iid);
|
||||
self.register_write(register, value);
|
||||
self.stack_frame.pc.increment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn interpret_block_exit(
|
||||
&mut self,
|
||||
block_exit: &BlockExit,
|
||||
) -> Result<Option<Value>, InterpreterError> {
|
||||
match block_exit {
|
||||
BlockExit::Jump { bid } => {
|
||||
self.stack_frame.pc = Pc::new(bid.clone());
|
||||
Ok(None)
|
||||
}
|
||||
BlockExit::ConditionalJump {
|
||||
condition,
|
||||
bid_then,
|
||||
bid_else,
|
||||
} => {
|
||||
let value = self.get_value(condition.clone())?;
|
||||
let value = value.get_bool().expect("`condition` must be `Value::Bool`");
|
||||
|
||||
self.stack_frame.pc = Pc::new(if value {
|
||||
bid_then.clone()
|
||||
} else {
|
||||
bid_else.clone()
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
BlockExit::Switch {
|
||||
value,
|
||||
default,
|
||||
cases,
|
||||
} => {
|
||||
let value = self.get_value(value.clone())?;
|
||||
|
||||
// TODO: consider different integer `width` in the future
|
||||
let bid_next = cases
|
||||
.iter()
|
||||
.find(|(c, _)| value == self.constant_to_value(c.clone()))
|
||||
.map(|(_, bid)| bid.clone())
|
||||
.unwrap_or_else(|| default.clone());
|
||||
|
||||
self.stack_frame.pc = Pc::new(bid_next);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
BlockExit::Return { value } => Ok(Some(self.get_value(value.clone())?)),
|
||||
BlockExit::Unreachable => Err(InterpreterError::Unreachable),
|
||||
}
|
||||
}
|
||||
|
||||
fn interpret_instruction(
|
||||
&mut self,
|
||||
instruction: &Instruction,
|
||||
) -> Result<Option<Value>, InterpreterError> {
|
||||
let result = match instruction {
|
||||
Instruction::BinOp { op, lhs, rhs, .. } => {
|
||||
let lhs = self.get_value(lhs.clone())?;
|
||||
let rhs = self.get_value(rhs.clone())?;
|
||||
|
||||
calculator::calculate_binary_operator_expression(&op, lhs, rhs).map_err(|_| {
|
||||
InterpreterError::Undef {
|
||||
func_name: self.stack_frame.func_name.clone(),
|
||||
bid: self.stack_frame.pc.bid.clone(),
|
||||
iid: self.stack_frame.pc.iid,
|
||||
}
|
||||
})?
|
||||
}
|
||||
Instruction::UnaryOp { op, operand, .. } => {
|
||||
let operand = self.get_value(operand.clone())?;
|
||||
|
||||
calculator::calculate_unary_operator_expression(&op, operand).map_err(|_| {
|
||||
InterpreterError::Undef {
|
||||
func_name: self.stack_frame.func_name.clone(),
|
||||
bid: self.stack_frame.pc.bid.clone(),
|
||||
iid: self.stack_frame.pc.iid,
|
||||
}
|
||||
})?
|
||||
}
|
||||
Instruction::Store { ptr, value, .. } => {
|
||||
let ptr = self.get_value(ptr.clone())?;
|
||||
let value = self.get_value(value.clone())?;
|
||||
|
||||
self.memory_store(ptr, value)?;
|
||||
|
||||
Value::Unit
|
||||
}
|
||||
Instruction::Load { ptr, .. } => {
|
||||
let ptr = self.get_value(ptr.clone())?;
|
||||
|
||||
self.memory_load(ptr)?
|
||||
}
|
||||
Instruction::Call { callee, args, .. } => {
|
||||
let ptr = self.get_value(callee.clone())?;
|
||||
|
||||
// Get function name from pointer
|
||||
let (bid, _) = ptr.get_pointer().expect("`ptr` must be `Value::Pointer`");
|
||||
let bid = bid.expect("pointer for global variable must have bid value");
|
||||
let callee_name = self
|
||||
.global_map
|
||||
.get_var(bid)
|
||||
.expect("bid must have relation with global variable");
|
||||
|
||||
let func = self
|
||||
.ir
|
||||
.decls
|
||||
.get(&callee_name)
|
||||
.expect("function must be declared before being called");
|
||||
let (func_signature, func_def) = func
|
||||
.get_function()
|
||||
.expect("`func` must be function declaration");
|
||||
let func_def =
|
||||
func_def
|
||||
.as_ref()
|
||||
.ok_or_else(|| InterpreterError::NoFunctionDefinition {
|
||||
func_name: callee_name.clone(),
|
||||
})?;
|
||||
|
||||
let args = self.preprocess_args(func_signature, args)?;
|
||||
|
||||
let stack_frame = StackFrame::new(func_def.bid_init.clone(), callee_name, func_def);
|
||||
let prev_stack_frame = mem::replace(&mut self.stack_frame, stack_frame);
|
||||
self.stack.push(prev_stack_frame);
|
||||
|
||||
// Initialize state with function obtained by callee and args
|
||||
self.pass_arguments(args)?;
|
||||
self.alloc_local_variable()?;
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
_ => todo!("{:?} will be supported in the future", instruction),
|
||||
};
|
||||
|
||||
let register = RegisterId::temp(self.stack_frame.pc.bid.clone(), self.stack_frame.pc.iid);
|
||||
self.register_write(register, result);
|
||||
self.stack_frame.pc.increment();
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_value(&self, operand: Operand) -> Result<Value, InterpreterError> {
|
||||
match &operand {
|
||||
Operand::Constant(value) => Ok(self.constant_to_value(value.clone())),
|
||||
Operand::Register { rid, .. } => Ok(self.register_read(rid.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_to_value(&self, value: Constant) -> Value {
|
||||
match value {
|
||||
Constant::Unit => Value::Unit,
|
||||
// TODO: consider `width` and `is_signed` in the future
|
||||
Constant::Int { value, .. } => Value::Int(value as i32),
|
||||
Constant::Float { value, .. } => Value::Float(value as f32),
|
||||
Constant::GlobalVariable { name, .. } => {
|
||||
let bid = self
|
||||
.global_map
|
||||
.get_bid(&name)
|
||||
.expect("The name matching `bid` must exist.");
|
||||
|
||||
// Generate appropriate pointer from `bid`
|
||||
Value::Pointer {
|
||||
bid: Some(bid),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn register_write(&mut self, rid: RegisterId, value: Value) {
|
||||
let _ = self.stack_frame.registers.inner.insert(rid, value);
|
||||
}
|
||||
|
||||
fn register_read(&self, rid: RegisterId) -> Value {
|
||||
self.stack_frame
|
||||
.registers
|
||||
.inner
|
||||
.get(&rid)
|
||||
.cloned()
|
||||
.expect("`rid` must be assigned before it can be used")
|
||||
}
|
||||
|
||||
fn memory_store(&mut self, pointer: Value, value: Value) -> Result<(), InterpreterError> {
|
||||
let (bid, offset) = pointer
|
||||
.get_pointer()
|
||||
.expect("`pointer` must be `Value::Pointer` to access memory");
|
||||
|
||||
let bid = bid.expect("write to memory using constant value address is not allowed");
|
||||
self.memory[bid][offset] = value;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn memory_load(&self, pointer: Value) -> Result<Value, InterpreterError> {
|
||||
let (bid, offset) = pointer
|
||||
.get_pointer()
|
||||
.expect("`pointer` must be `Value::Pointer` to access memory");
|
||||
|
||||
let bid = bid.expect("read from memory using constant value address is not allowed");
|
||||
|
||||
Ok(self.memory[bid][offset].clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn run_ir(ir: &TranslationUnit, args: Vec<Value>) -> Result<Value, InterpreterError> {
|
||||
let mut init_state = State::new(ir, args)?;
|
||||
init_state.run()
|
||||
}
|
||||
81
src/utils.rs
Normal file
81
src/utils.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
#[macro_export]
|
||||
/// Ok or executing the given expression.
|
||||
macro_rules! ok_or {
|
||||
($e:expr, $err:expr) => {{
|
||||
match $e {
|
||||
Ok(r) => r,
|
||||
Err(_) => $err,
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Some or executing the given expression.
|
||||
macro_rules! some_or {
|
||||
($e:expr, $err:expr) => {{
|
||||
match $e {
|
||||
Some(r) => r,
|
||||
None => $err,
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Ok or exiting the process.
|
||||
macro_rules! ok_or_exit {
|
||||
($e:expr, $code:expr) => {{
|
||||
match $e {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
eprintln!("{:?}", e);
|
||||
::std::process::exit($code);
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Ok or exiting the process.
|
||||
macro_rules! some_or_exit {
|
||||
($e:expr, $code:expr) => {{
|
||||
match $e {
|
||||
Some(r) => r,
|
||||
None => ::std::process::exit($code),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
pub trait Translate<S> {
|
||||
type Target;
|
||||
type Error;
|
||||
|
||||
fn translate(&mut self, source: &S) -> Result<Self::Target, Self::Error>;
|
||||
}
|
||||
|
||||
pub trait Optimize<T> {
|
||||
fn optimize(&mut self, code: &mut T) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Repeat<O> {
|
||||
inner: O,
|
||||
}
|
||||
|
||||
impl<T, O1: Optimize<T>, O2: Optimize<T>> Optimize<T> for (O1, O2) {
|
||||
fn optimize(&mut self, code: &mut T) -> bool {
|
||||
let changed1 = self.0.optimize(code);
|
||||
let changed2 = self.1.optimize(code);
|
||||
changed1 || changed2
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, O: Optimize<T>> Optimize<T> for Repeat<O> {
|
||||
fn optimize(&mut self, code: &mut T) -> bool {
|
||||
if !self.inner.optimize(code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while self.inner.optimize(code) {}
|
||||
true
|
||||
}
|
||||
}
|
||||
5
src/write_asm.rs
Normal file
5
src/write_asm.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use crate::asm::Asm;
|
||||
|
||||
pub fn write_asm(_asm: &Asm, _write: &mut dyn ::std::io::Write) {
|
||||
unimplemented!();
|
||||
}
|
||||
18
src/write_base.rs
Normal file
18
src/write_base.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use std::io::{Result, Write};
|
||||
|
||||
#[inline]
|
||||
pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||
write!(write, "{}", " ".repeat(indent))
|
||||
}
|
||||
|
||||
pub trait WriteLine {
|
||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()>;
|
||||
}
|
||||
|
||||
pub trait WriteString {
|
||||
fn write_string(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait WriteOp {
|
||||
fn write_operation(&self) -> String;
|
||||
}
|
||||
51
src/write_c.rs
Normal file
51
src/write_c.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use lang_c::ast::*;
|
||||
use lang_c::span::Node;
|
||||
|
||||
use std::io::{Result, Write};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::write_base::*;
|
||||
|
||||
impl<T: WriteLine> WriteLine for Node<T> {
|
||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||
self.node.write_line(indent, write)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WriteString> WriteString for Node<T> {
|
||||
fn write_string(&self) -> String {
|
||||
self.node.write_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WriteString> WriteString for Box<T> {
|
||||
fn write_string(&self) -> String {
|
||||
self.deref().write_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WriteString> WriteString for &T {
|
||||
fn write_string(&self) -> String {
|
||||
(*self).write_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WriteString> WriteString for Option<T> {
|
||||
fn write_string(&self) -> String {
|
||||
if let Some(this) = self {
|
||||
this.write_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteLine for TranslationUnit {
|
||||
fn write_line(&self, _indent: usize, _write: &mut dyn Write) -> Result<()> {
|
||||
todo!("homework 1")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_c(unit: &TranslationUnit, write: &mut dyn Write) -> Result<()> {
|
||||
unit.write_line(0, write)
|
||||
}
|
||||
20
src/write_c_test.rs
Normal file
20
src/write_c_test.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use lang_c::ast::*;
|
||||
use std::fs::File;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub fn write_c_test(unit: &TranslationUnit) {
|
||||
let temp_dir = tempdir().expect("temp dir creation failed");
|
||||
let temp_file_path = temp_dir.path().join("temp.c");
|
||||
let mut temp_file = File::create(&temp_file_path).unwrap();
|
||||
|
||||
write_c(&unit, &mut temp_file).unwrap();
|
||||
|
||||
let new_unit = Parse::default()
|
||||
.translate(&temp_file_path.as_path())
|
||||
.expect("parse failed while parsing file from implemented printer");
|
||||
drop(temp_file);
|
||||
assert_ast_equiv(&unit, &new_unit);
|
||||
temp_dir.close().expect("temp dir deletion failed");
|
||||
}
|
||||
224
src/write_ir.rs
Normal file
224
src/write_ir.rs
Normal file
@@ -0,0 +1,224 @@
|
||||
use crate::ir::*;
|
||||
|
||||
use std::io::{Result, Write};
|
||||
|
||||
use crate::write_base::*;
|
||||
use crate::*;
|
||||
|
||||
use lang_c::ast;
|
||||
|
||||
impl WriteLine for TranslationUnit {
|
||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||
write_indent(indent, write)?;
|
||||
writeln!(write, "<variable list>")?;
|
||||
writeln!(write)?;
|
||||
for (name, decl) in &self.decls {
|
||||
let _ = some_or!(decl.get_variable(), continue);
|
||||
(name, decl).write_line(indent, write)?;
|
||||
}
|
||||
|
||||
writeln!(write)?;
|
||||
writeln!(write)?;
|
||||
write_indent(indent, write)?;
|
||||
writeln!(write, "<function list>")?;
|
||||
writeln!(write)?;
|
||||
for (name, decl) in &self.decls {
|
||||
let _ = some_or!(decl.get_function(), continue);
|
||||
(name, decl).write_line(indent, write)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteLine for (&String, &Declaration) {
|
||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||
let name = self.0;
|
||||
let decl = self.1;
|
||||
|
||||
match decl {
|
||||
Declaration::Variable { dtype, .. } => {
|
||||
writeln!(write, "{} = {}", name, dtype)?;
|
||||
}
|
||||
Declaration::Function {
|
||||
signature,
|
||||
definition,
|
||||
} => {
|
||||
let declaration = format!(
|
||||
"{} @{}({})",
|
||||
signature.ret,
|
||||
name,
|
||||
signature
|
||||
.params
|
||||
.iter()
|
||||
.map(|d| d.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
|
||||
match definition.as_ref() {
|
||||
Some(defintion) => {
|
||||
// print meta data for function
|
||||
writeln!(
|
||||
write,
|
||||
"; function meta data:\n; bid_init: {}\n; allocations: {}",
|
||||
defintion.bid_init,
|
||||
defintion
|
||||
.allocations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| format!("{}:{}", i, a))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)?;
|
||||
|
||||
// print function definition
|
||||
writeln!(write, "define {} {{", declaration)?;
|
||||
|
||||
for (id, block) in &defintion.blocks {
|
||||
writeln!(write, "; <BoxId> {}", id)?;
|
||||
(id, block).write_line(indent + 1, write)?;
|
||||
writeln!(write)?;
|
||||
}
|
||||
|
||||
writeln!(write, "}}")?;
|
||||
writeln!(write)?;
|
||||
}
|
||||
None => {
|
||||
// print declaration line only
|
||||
writeln!(write, "declare {}", declaration)?;
|
||||
writeln!(write)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteLine for (&BlockId, &Block) {
|
||||
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
|
||||
for (i, instr) in self.1.instructions.iter().enumerate() {
|
||||
write_indent(indent, write)?;
|
||||
writeln!(
|
||||
write,
|
||||
"{}:{} = {}",
|
||||
RegisterId::temp(self.0.clone(), i),
|
||||
instr.dtype(),
|
||||
instr.write_string()
|
||||
)?;
|
||||
}
|
||||
|
||||
write_indent(indent, write)?;
|
||||
writeln!(write, "{}", self.1.exit.write_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteString for Instruction {
|
||||
fn write_string(&self) -> String {
|
||||
match self {
|
||||
Instruction::BinOp { op, lhs, rhs, .. } => format!(
|
||||
"{} {} {}",
|
||||
op.write_operation(),
|
||||
lhs.write_string(),
|
||||
rhs.write_string()
|
||||
),
|
||||
Instruction::UnaryOp { op, operand, .. } => {
|
||||
format!("{} {}", op.write_operation(), operand.write_string(),)
|
||||
}
|
||||
Instruction::Store { ptr, value } => {
|
||||
format!("store {} {}", value.write_string(), ptr.write_string())
|
||||
}
|
||||
Instruction::Load { ptr } => format!("load {}", ptr.write_string()),
|
||||
Instruction::Call { callee, args, .. } => format!(
|
||||
"call {}({})",
|
||||
callee,
|
||||
args.iter()
|
||||
.map(WriteString::write_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
Instruction::TypeCast {
|
||||
value,
|
||||
target_dtype,
|
||||
} => format!("typecast {} to {}", value.write_string(), target_dtype),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteString for Operand {
|
||||
fn write_string(&self) -> String {
|
||||
format!("{}:{}", self, self.dtype())
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteOp for ast::BinaryOperator {
|
||||
fn write_operation(&self) -> String {
|
||||
match self {
|
||||
Self::Multiply => "mul",
|
||||
Self::Divide => "div",
|
||||
Self::Modulo => "mod",
|
||||
Self::Plus => "add",
|
||||
Self::Minus => "sub",
|
||||
Self::Equals => "cmp eq",
|
||||
Self::NotEquals => "cmp ne",
|
||||
Self::Less => "cmp lt",
|
||||
Self::LessOrEqual => "cmp le",
|
||||
Self::Greater => "cmp gt",
|
||||
Self::GreaterOrEqual => "cmp ge",
|
||||
_ => todo!(),
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteOp for ast::UnaryOperator {
|
||||
fn write_operation(&self) -> String {
|
||||
match self {
|
||||
Self::Minus => "minus",
|
||||
_ => todo!(),
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteString for BlockExit {
|
||||
fn write_string(&self) -> String {
|
||||
match self {
|
||||
BlockExit::Jump { bid } => format!("j {}", bid),
|
||||
BlockExit::ConditionalJump {
|
||||
condition,
|
||||
bid_then,
|
||||
bid_else,
|
||||
} => format!(
|
||||
"br {}, {}, {}",
|
||||
condition.write_string(),
|
||||
bid_then,
|
||||
bid_else
|
||||
),
|
||||
BlockExit::Switch {
|
||||
value,
|
||||
default,
|
||||
cases,
|
||||
} => format!(
|
||||
"switch {}, default: {} [\n{}\n ]",
|
||||
value.write_string(),
|
||||
default,
|
||||
cases
|
||||
.iter()
|
||||
.map(|(v, b)| format!(" {}:{}, {}", v, v.dtype(), b))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
),
|
||||
BlockExit::Return { value } => format!("ret {}", value.write_string()),
|
||||
BlockExit::Unreachable => "<unreachable>\t\t\t\t; error state".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_ir(ir: &TranslationUnit, write: &mut dyn Write) -> Result<()> {
|
||||
ir.write_line(0, write)
|
||||
}
|
||||
Reference in New Issue
Block a user