style: improve code formatting and consistency in typeChecker and assemblyIR
This commit is contained in:
parent
1488281223
commit
f30cf42c4b
@ -19,7 +19,7 @@ object asmGenerator {
|
|||||||
val RBP = Register(RegSize.R64, RegName.BP)
|
val RBP = Register(RegSize.R64, RegName.BP)
|
||||||
val RSI = Register(RegSize.R64, RegName.SI)
|
val RSI = Register(RegSize.R64, RegName.SI)
|
||||||
|
|
||||||
val _8_BIT_MASK = 0xFF
|
val _8_BIT_MASK = 0xff
|
||||||
|
|
||||||
object labelGenerator {
|
object labelGenerator {
|
||||||
var labelVal = -1
|
var labelVal = -1
|
||||||
@ -27,8 +27,8 @@ object asmGenerator {
|
|||||||
labelVal += 1
|
labelVal += 1
|
||||||
s".L$labelVal"
|
s".L$labelVal"
|
||||||
}
|
}
|
||||||
def getLabel(target: CallTarget): String = target match{
|
def getLabel(target: CallTarget): String = target match {
|
||||||
case Ident(v,_) => s"wacc_$v"
|
case Ident(v, _) => s"wacc_$v"
|
||||||
case Builtin(name) => s"_$name"
|
case Builtin(name) => s"_$name"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,33 +61,31 @@ object asmGenerator {
|
|||||||
strings: ListBuffer[String]
|
strings: ListBuffer[String]
|
||||||
): List[AsmLine] = {
|
): List[AsmLine] = {
|
||||||
LabelDef(labelName) ::
|
LabelDef(labelName) ::
|
||||||
funcPrologue() ++
|
funcPrologue() ++
|
||||||
funcBody ++
|
funcBody ++
|
||||||
funcEpilogue()
|
funcEpilogue()
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateBuiltInFuncs()(using
|
def generateBuiltInFuncs()(using
|
||||||
stack: LinkedHashMap[Ident, Int],
|
stack: LinkedHashMap[Ident, Int],
|
||||||
strings: ListBuffer[String]
|
strings: ListBuffer[String]
|
||||||
): List[AsmLine] = {
|
): List[AsmLine] = {
|
||||||
wrapFunc(labelGenerator.getLabel(Builtin.Exit),
|
wrapFunc(
|
||||||
|
labelGenerator.getLabel(Builtin.Exit),
|
||||||
alignStack() ++
|
alignStack() ++
|
||||||
List(Pop(RDI),
|
List(Pop(RDI), assemblyIR.Call(CLibFunc.Exit))
|
||||||
assemblyIR.Call(CLibFunc.Exit))
|
|
||||||
) ++
|
) ++
|
||||||
wrapFunc(labelGenerator.getLabel(Builtin.Printf),
|
wrapFunc(
|
||||||
alignStack() ++
|
labelGenerator.getLabel(Builtin.Printf),
|
||||||
List(assemblyIR.Call(CLibFunc.PrintF),
|
alignStack() ++
|
||||||
Move(RDI, ImmediateVal(0)),
|
List(
|
||||||
assemblyIR.Call(CLibFunc.Fflush)
|
assemblyIR.Call(CLibFunc.PrintF),
|
||||||
)
|
Move(RDI, ImmediateVal(0)),
|
||||||
)++
|
assemblyIR.Call(CLibFunc.Fflush)
|
||||||
wrapFunc(labelGenerator.getLabel(Builtin.Malloc),
|
)
|
||||||
List()
|
) ++
|
||||||
)++
|
wrapFunc(labelGenerator.getLabel(Builtin.Malloc), List()) ++
|
||||||
wrapFunc(labelGenerator.getLabel(Builtin.Free),
|
wrapFunc(labelGenerator.getLabel(Builtin.Free), List())
|
||||||
List()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateStmt(
|
def generateStmt(
|
||||||
@ -95,7 +93,7 @@ object asmGenerator {
|
|||||||
)(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] =
|
)(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] =
|
||||||
stmt match {
|
stmt match {
|
||||||
case microWacc.Call(Builtin.Exit, code :: _) =>
|
case microWacc.Call(Builtin.Exit, code :: _) =>
|
||||||
List()
|
List()
|
||||||
case Assign(lhs, rhs) =>
|
case Assign(lhs, rhs) =>
|
||||||
var dest: IndexAddress =
|
var dest: IndexAddress =
|
||||||
IndexAddress(RSP, 0) // gets overrwitten
|
IndexAddress(RSP, 0) // gets overrwitten
|
||||||
@ -188,97 +186,100 @@ object asmGenerator {
|
|||||||
// TODO other array types
|
// TODO other array types
|
||||||
case _ => List()
|
case _ => List()
|
||||||
}
|
}
|
||||||
case BoolLiter(v) => List(Push(ImmediateVal(if (v) 1 else 0)))
|
case BoolLiter(v) => List(Push(ImmediateVal(if (v) 1 else 0)))
|
||||||
case NullLiter() => List(Push(ImmediateVal(0)))
|
case NullLiter() => List(Push(ImmediateVal(0)))
|
||||||
case ArrayElem(value, indices) => List()
|
case ArrayElem(value, indices) => List()
|
||||||
case UnaryOp(x, op) => op match {
|
case UnaryOp(x, op) =>
|
||||||
// TODO: chr and ord are TYPE CASTS. They do not change the internal value,
|
op match {
|
||||||
// but will need bound checking e.t.c.
|
// TODO: chr and ord are TYPE CASTS. They do not change the internal value,
|
||||||
case UnaryOperator.Chr => List()
|
// but will need bound checking e.t.c.
|
||||||
case UnaryOperator.Ord => List()
|
case UnaryOperator.Chr => List()
|
||||||
case UnaryOperator.Len => List()
|
case UnaryOperator.Ord => List()
|
||||||
case UnaryOperator.Negate => List(
|
case UnaryOperator.Len => List()
|
||||||
Negate(MemLocation(RSP,SizeDir.Word))
|
case UnaryOperator.Negate =>
|
||||||
)
|
List(
|
||||||
case UnaryOperator.Not =>
|
Negate(MemLocation(RSP, SizeDir.Word))
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
List(
|
|
||||||
Xor(MemLocation(RSP, SizeDir.Word), ImmediateVal(1))
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
case BinaryOp(x, y, op) => op match {
|
|
||||||
case BinaryOperator.Add =>
|
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
evalExprOntoStack(y) ++
|
|
||||||
List(
|
|
||||||
Pop(EAX),
|
|
||||||
Add(MemLocation(RSP, SizeDir.Word), EAX)
|
|
||||||
// TODO OVERFLOWING
|
|
||||||
)
|
|
||||||
case BinaryOperator.Sub =>
|
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
evalExprOntoStack(y) ++
|
|
||||||
List(
|
|
||||||
Pop(EAX),
|
|
||||||
Subtract(MemLocation(RSP, SizeDir.Word), EAX)
|
|
||||||
// TODO OVERFLOWING
|
|
||||||
)
|
|
||||||
case BinaryOperator.Mul =>
|
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
evalExprOntoStack(y) ++
|
|
||||||
List(
|
|
||||||
Pop(EAX),
|
|
||||||
Multiply(MemLocation(RSP, SizeDir.Word), EAX)
|
|
||||||
// TODO OVERFLOWING
|
|
||||||
)
|
|
||||||
case BinaryOperator.Div =>
|
|
||||||
evalExprOntoStack(y) ++
|
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
List(
|
|
||||||
Pop(EAX),
|
|
||||||
Divide(MemLocation(RSP, SizeDir.Word)),
|
|
||||||
Add(RSP, ImmediateVal(8)),
|
|
||||||
Push(EAX)
|
|
||||||
// TODO CHECK DIVISOR IS NOT 0
|
|
||||||
)
|
|
||||||
case BinaryOperator.Mod =>
|
|
||||||
evalExprOntoStack(y) ++
|
|
||||||
evalExprOntoStack(x) ++
|
|
||||||
List(
|
|
||||||
Pop(EAX),
|
|
||||||
Divide(MemLocation(RSP, SizeDir.Word)),
|
|
||||||
Add(RSP, ImmediateVal(8)),
|
|
||||||
Push(EDX)
|
|
||||||
// TODO CHECK DIVISOR IS NOT 0
|
|
||||||
)
|
)
|
||||||
case BinaryOperator.Eq =>
|
case UnaryOperator.Not =>
|
||||||
generateComparison(x, y, Cond.Equal)
|
evalExprOntoStack(x) ++
|
||||||
case BinaryOperator.Neq =>
|
List(
|
||||||
generateComparison(x, y, Cond.NotEqual)
|
Xor(MemLocation(RSP, SizeDir.Word), ImmediateVal(1))
|
||||||
case BinaryOperator.Greater =>
|
)
|
||||||
generateComparison(x, y, Cond.Greater)
|
|
||||||
case BinaryOperator.GreaterEq =>
|
}
|
||||||
generateComparison(x, y, Cond.GreaterEqual)
|
case BinaryOp(x, y, op) =>
|
||||||
case BinaryOperator.Less =>
|
op match {
|
||||||
generateComparison(x, y, Cond.Less)
|
case BinaryOperator.Add =>
|
||||||
case BinaryOperator.LessEq =>
|
evalExprOntoStack(x) ++
|
||||||
generateComparison(x, y, Cond.LessEqual)
|
evalExprOntoStack(y) ++
|
||||||
case BinaryOperator.And =>
|
List(
|
||||||
evalExprOntoStack(x) ++
|
Pop(EAX),
|
||||||
evalExprOntoStack(y) ++
|
Add(MemLocation(RSP, SizeDir.Word), EAX)
|
||||||
List(
|
// TODO OVERFLOWING
|
||||||
Pop(EAX),
|
)
|
||||||
And(MemLocation(RSP, SizeDir.Word), EAX),
|
case BinaryOperator.Sub =>
|
||||||
)
|
evalExprOntoStack(x) ++
|
||||||
case BinaryOperator.Or =>
|
evalExprOntoStack(y) ++
|
||||||
evalExprOntoStack(x) ++
|
List(
|
||||||
evalExprOntoStack(y) ++
|
Pop(EAX),
|
||||||
List(
|
Subtract(MemLocation(RSP, SizeDir.Word), EAX)
|
||||||
Pop(EAX),
|
// TODO OVERFLOWING
|
||||||
Or(MemLocation(RSP, SizeDir.Word), EAX),
|
)
|
||||||
)
|
case BinaryOperator.Mul =>
|
||||||
}
|
evalExprOntoStack(x) ++
|
||||||
|
evalExprOntoStack(y) ++
|
||||||
|
List(
|
||||||
|
Pop(EAX),
|
||||||
|
Multiply(MemLocation(RSP, SizeDir.Word), EAX)
|
||||||
|
// TODO OVERFLOWING
|
||||||
|
)
|
||||||
|
case BinaryOperator.Div =>
|
||||||
|
evalExprOntoStack(y) ++
|
||||||
|
evalExprOntoStack(x) ++
|
||||||
|
List(
|
||||||
|
Pop(EAX),
|
||||||
|
Divide(MemLocation(RSP, SizeDir.Word)),
|
||||||
|
Add(RSP, ImmediateVal(8)),
|
||||||
|
Push(EAX)
|
||||||
|
// TODO CHECK DIVISOR IS NOT 0
|
||||||
|
)
|
||||||
|
case BinaryOperator.Mod =>
|
||||||
|
evalExprOntoStack(y) ++
|
||||||
|
evalExprOntoStack(x) ++
|
||||||
|
List(
|
||||||
|
Pop(EAX),
|
||||||
|
Divide(MemLocation(RSP, SizeDir.Word)),
|
||||||
|
Add(RSP, ImmediateVal(8)),
|
||||||
|
Push(EDX)
|
||||||
|
// TODO CHECK DIVISOR IS NOT 0
|
||||||
|
)
|
||||||
|
case BinaryOperator.Eq =>
|
||||||
|
generateComparison(x, y, Cond.Equal)
|
||||||
|
case BinaryOperator.Neq =>
|
||||||
|
generateComparison(x, y, Cond.NotEqual)
|
||||||
|
case BinaryOperator.Greater =>
|
||||||
|
generateComparison(x, y, Cond.Greater)
|
||||||
|
case BinaryOperator.GreaterEq =>
|
||||||
|
generateComparison(x, y, Cond.GreaterEqual)
|
||||||
|
case BinaryOperator.Less =>
|
||||||
|
generateComparison(x, y, Cond.Less)
|
||||||
|
case BinaryOperator.LessEq =>
|
||||||
|
generateComparison(x, y, Cond.LessEqual)
|
||||||
|
case BinaryOperator.And =>
|
||||||
|
evalExprOntoStack(x) ++
|
||||||
|
evalExprOntoStack(y) ++
|
||||||
|
List(
|
||||||
|
Pop(EAX),
|
||||||
|
And(MemLocation(RSP, SizeDir.Word), EAX)
|
||||||
|
)
|
||||||
|
case BinaryOperator.Or =>
|
||||||
|
evalExprOntoStack(x) ++
|
||||||
|
evalExprOntoStack(y) ++
|
||||||
|
List(
|
||||||
|
Pop(EAX),
|
||||||
|
Or(MemLocation(RSP, SizeDir.Word), EAX)
|
||||||
|
)
|
||||||
|
}
|
||||||
case microWacc.Call(target, args) => List()
|
case microWacc.Call(target, args) => List()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,19 +309,19 @@ object asmGenerator {
|
|||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
def generateComparison(x : Expr, y: Expr, cond: Cond)(using
|
def generateComparison(x: Expr, y: Expr, cond: Cond)(using
|
||||||
stack: LinkedHashMap[Ident, Int],
|
stack: LinkedHashMap[Ident, Int],
|
||||||
strings: ListBuffer[String]
|
strings: ListBuffer[String]
|
||||||
): List[AsmLine] = {
|
): List[AsmLine] = {
|
||||||
evalExprOntoStack(x) ++
|
evalExprOntoStack(x) ++
|
||||||
evalExprOntoStack(y) ++
|
evalExprOntoStack(y) ++
|
||||||
List(
|
List(
|
||||||
Pop(EAX),
|
Pop(EAX),
|
||||||
Compare(MemLocation(RSP, SizeDir.Word), EAX),
|
Compare(MemLocation(RSP, SizeDir.Word), EAX),
|
||||||
Set(Register(RegSize.Byte, RegName.AL), cond),
|
Set(Register(RegSize.Byte, RegName.AL), cond),
|
||||||
And(EAX, ImmediateVal(_8_BIT_MASK)),
|
And(EAX, ImmediateVal(_8_BIT_MASK)),
|
||||||
Push(EAX)
|
Push(EAX)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
def accessVar(ident: Ident)(using stack: LinkedHashMap[Ident, Int]): IndexAddress =
|
def accessVar(ident: Ident)(using stack: LinkedHashMap[Ident, Int]): IndexAddress =
|
||||||
IndexAddress(RSP, (stack.size - stack(ident)) * 8)
|
IndexAddress(RSP, (stack.size - stack(ident)) * 8)
|
||||||
@ -397,8 +398,8 @@ object asmGenerator {
|
|||||||
)
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
evalExprOntoStack(expr) ++
|
evalExprOntoStack(expr) ++
|
||||||
List(Pop(RSI))
|
List(Pop(RSI))
|
||||||
})
|
})
|
||||||
// print the value
|
// print the value
|
||||||
++
|
++
|
||||||
|
@ -12,14 +12,15 @@ object assemblyIR {
|
|||||||
case Byte
|
case Byte
|
||||||
|
|
||||||
override def toString = this match {
|
override def toString = this match {
|
||||||
case R64 => "r"
|
case R64 => "r"
|
||||||
case E32 => "e"
|
case E32 => "e"
|
||||||
case Byte => ""
|
case Byte => ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RegName {
|
enum RegName {
|
||||||
case AX, AL, BX, CX, DX, SI, DI, SP, BP, IP, Reg8, Reg9, Reg10, Reg11, Reg12, Reg13, Reg14, Reg15
|
case AX, AL, BX, CX, DX, SI, DI, SP, BP, IP, Reg8, Reg9, Reg10, Reg11, Reg12, Reg13, Reg14,
|
||||||
|
Reg15
|
||||||
override def toString = this match {
|
override def toString = this match {
|
||||||
case AX => "ax"
|
case AX => "ax"
|
||||||
case AL => "al"
|
case AL => "al"
|
||||||
@ -59,17 +60,24 @@ object assemblyIR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO register naming conventions are wrong
|
// TODO register naming conventions are wrong
|
||||||
case class Register(size: RegSize, name: RegName) extends Dest with Src {
|
case class Register(size: RegSize, name: RegName) extends Dest with Src {
|
||||||
override def toString = s"${size}${name}"
|
override def toString = s"${size}${name}"
|
||||||
}
|
}
|
||||||
case class MemLocation(pointer: Long | Register, opSize: SizeDir = SizeDir.Unspecified) extends Dest with Src {
|
case class MemLocation(pointer: Long | Register, opSize: SizeDir = SizeDir.Unspecified)
|
||||||
|
extends Dest
|
||||||
|
with Src {
|
||||||
override def toString = pointer match {
|
override def toString = pointer match {
|
||||||
case hex: Long => opSize.toString + f"[0x$hex%X]"
|
case hex: Long => opSize.toString + f"[0x$hex%X]"
|
||||||
case reg: Register => opSize.toString + s"[$reg]"
|
case reg: Register => opSize.toString + s"[$reg]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case class IndexAddress(base: Register, offset: Int | LabelArg, opSize: SizeDir = SizeDir.Unspecified) extends Dest with Src {
|
case class IndexAddress(
|
||||||
|
base: Register,
|
||||||
|
offset: Int | LabelArg,
|
||||||
|
opSize: SizeDir = SizeDir.Unspecified
|
||||||
|
) extends Dest
|
||||||
|
with Src {
|
||||||
override def toString = s"$opSize[$base + $offset]"
|
override def toString = s"$opSize[$base + $offset]"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +119,7 @@ object assemblyIR {
|
|||||||
extends Operation(s"j${condition.toString}", op1)
|
extends Operation(s"j${condition.toString}", op1)
|
||||||
|
|
||||||
case class Set(op1: Dest, condition: Cond = Cond.Always)
|
case class Set(op1: Dest, condition: Cond = Cond.Always)
|
||||||
extends Operation(s"set${condition.toString}", op1)
|
extends Operation(s"set${condition.toString}", op1)
|
||||||
|
|
||||||
case class LabelDef(name: String) extends AsmLine {
|
case class LabelDef(name: String) extends AsmLine {
|
||||||
override def toString = s"$name:"
|
override def toString = s"$name:"
|
||||||
@ -165,14 +173,14 @@ object assemblyIR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum SizeDir {
|
enum SizeDir {
|
||||||
case Byte, Word, Unspecified
|
case Byte, Word, Unspecified
|
||||||
|
|
||||||
private val ptr = "ptr "
|
private val ptr = "ptr "
|
||||||
|
|
||||||
override def toString(): String = this match {
|
override def toString(): String = this match {
|
||||||
case Byte => "byte " + ptr
|
case Byte => "byte " + ptr
|
||||||
case Word => "word " + ptr
|
case Word => "word " + ptr
|
||||||
case Unspecified => ""
|
case Unspecified => ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ object typeChecker {
|
|||||||
microWacc.Builtin.Read,
|
microWacc.Builtin.Read,
|
||||||
List(
|
List(
|
||||||
destTy match {
|
destTy match {
|
||||||
case KnownType.Int => "%d".toMicroWaccCharArray
|
case KnownType.Int => "%d".toMicroWaccCharArray
|
||||||
case KnownType.Char | _ => "%c".toMicroWaccCharArray
|
case KnownType.Char | _ => "%c".toMicroWaccCharArray
|
||||||
},
|
},
|
||||||
destTyped
|
destTyped
|
||||||
@ -218,9 +218,9 @@ object typeChecker {
|
|||||||
val exprTyped = checkValue(expr, Constraint.Unconstrained)
|
val exprTyped = checkValue(expr, Constraint.Unconstrained)
|
||||||
val format = exprTyped.ty match {
|
val format = exprTyped.ty match {
|
||||||
case KnownType.Bool | KnownType.String => "%s"
|
case KnownType.Bool | KnownType.String => "%s"
|
||||||
case KnownType.Char => "%c"
|
case KnownType.Char => "%c"
|
||||||
case KnownType.Int => "%d"
|
case KnownType.Int => "%d"
|
||||||
case _ => "%p"
|
case _ => "%p"
|
||||||
}
|
}
|
||||||
List(
|
List(
|
||||||
microWacc.Call(
|
microWacc.Call(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user