mirror of https://github.com/KarolS/millfork.git
224 lines
6.6 KiB
Scala
224 lines
6.6 KiB
Scala
package millfork.env
|
|
|
|
import millfork.error.ErrorReporting
|
|
import millfork.node.Position
|
|
|
|
object Constant {
|
|
val Zero: Constant = NumericConstant(0, 1)
|
|
val One: Constant = NumericConstant(1, 1)
|
|
|
|
def error(msg: String, position: Option[Position] = None): Constant = {
|
|
ErrorReporting.error(msg, position)
|
|
Zero
|
|
}
|
|
|
|
def minimumSize(value: Long): Int = if (value < -128 || value > 255) 2 else 1 // TODO !!!
|
|
}
|
|
|
|
import millfork.env.Constant.minimumSize
|
|
import millfork.error.ErrorReporting
|
|
import millfork.node.Position
|
|
|
|
sealed trait Constant {
|
|
|
|
def asl(i: Constant): Constant = i match {
|
|
case NumericConstant(sa, _) => asl(sa.toInt)
|
|
case _ => CompoundConstant(MathOperator.Shl, this, i)
|
|
}
|
|
|
|
def asl(i: Int): Constant = CompoundConstant(MathOperator.Shl, this, NumericConstant(i, 1))
|
|
|
|
def requiredSize: Int
|
|
|
|
def +(that: Constant): Constant = CompoundConstant(MathOperator.Plus, this, that)
|
|
|
|
def -(that: Constant): Constant = CompoundConstant(MathOperator.Minus, this, that)
|
|
|
|
def +(that: Long): Constant = if (that == 0) this else this + NumericConstant(that, minimumSize(that))
|
|
|
|
def -(that: Long): Constant = this + (-that)
|
|
|
|
def loByte: Constant = {
|
|
if (requiredSize == 1) return this
|
|
HalfWordConstant(this, hi = false)
|
|
}
|
|
|
|
def hiByte: Constant = {
|
|
if (requiredSize == 1) Constant.Zero
|
|
else HalfWordConstant(this, hi = true)
|
|
}
|
|
|
|
def subbyte(index: Int): Constant = {
|
|
if (requiredSize <= index) Constant.Zero
|
|
else index match {
|
|
case 0 => loByte
|
|
case 1 => hiByte
|
|
case _ => SubbyteConstant(this, index)
|
|
}
|
|
}
|
|
|
|
def isLowestByteAlwaysEqual(i: Int) : Boolean = false
|
|
|
|
def quickSimplify: Constant = this
|
|
}
|
|
|
|
case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant
|
|
|
|
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
|
|
if (requiredSize == 1) {
|
|
if (value < -128 || value > 255) {
|
|
throw new IllegalArgumentException("The constant is too big")
|
|
}
|
|
}
|
|
|
|
override def isLowestByteAlwaysEqual(i: Int) : Boolean = (value & 0xff) == (i&0xff)
|
|
|
|
override def asl(i: Int) = NumericConstant(value << i, requiredSize + i / 8)
|
|
|
|
override def +(that: Constant): Constant = that + value
|
|
|
|
override def +(that: Long) = NumericConstant(value + that, minimumSize(value + that))
|
|
|
|
override def toString: String = if (value > 9) value.formatted("$%X") else value.toString
|
|
}
|
|
|
|
case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant {
|
|
override def requiredSize = 2
|
|
|
|
override def toString: String = thing.name
|
|
}
|
|
|
|
case class HalfWordConstant(base: Constant, hi: Boolean) extends Constant {
|
|
override def quickSimplify: Constant = {
|
|
val simplified = base.quickSimplify
|
|
simplified match {
|
|
case NumericConstant(x, size) => if (hi) {
|
|
if (size == 1) Constant.Zero else NumericConstant((x >> 8) & 0xff, 1)
|
|
} else {
|
|
NumericConstant(x & 0xff, 1)
|
|
}
|
|
case _ => HalfWordConstant(simplified, hi)
|
|
}
|
|
}
|
|
|
|
override def requiredSize = 1
|
|
|
|
override def toString: String = base + (if (hi) ".hi" else ".lo")
|
|
}
|
|
|
|
case class SubbyteConstant(base: Constant, index: Int) extends Constant {
|
|
override def quickSimplify: Constant = {
|
|
val simplified = base.quickSimplify
|
|
simplified match {
|
|
case NumericConstant(x, size) => if (index >= size) {
|
|
Constant.Zero
|
|
} else {
|
|
NumericConstant((x >> (index * 8)) & 0xff, 1)
|
|
}
|
|
case _ => SubbyteConstant(simplified, index)
|
|
}
|
|
}
|
|
|
|
override def requiredSize = 1
|
|
|
|
override def toString: String = base + (index match {
|
|
case 0 => ".lo"
|
|
case 1 => ".hi"
|
|
case 2 => ".b2"
|
|
case 3 => ".b3"
|
|
})
|
|
}
|
|
|
|
object MathOperator extends Enumeration {
|
|
val Plus, Minus, Times, Shl, Shr,
|
|
DecimalPlus, DecimalMinus, DecimalTimes, DecimalShl, DecimalShr,
|
|
And, Or, Exor = Value
|
|
}
|
|
|
|
case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Constant) extends Constant {
|
|
override def quickSimplify: Constant = {
|
|
val l = lhs.quickSimplify
|
|
val r = rhs.quickSimplify
|
|
(l, r) match {
|
|
case (NumericConstant(lv, ls), NumericConstant(rv, rs)) =>
|
|
var size = ls max rs
|
|
val value = operator match {
|
|
case MathOperator.Plus => lv + rv
|
|
case MathOperator.Minus => lv - rv
|
|
case MathOperator.Times => lv * rv
|
|
case MathOperator.Shl => lv << rv
|
|
case MathOperator.Shr => lv >> rv
|
|
case MathOperator.Exor => lv ^ rv
|
|
case MathOperator.Or => lv | rv
|
|
case MathOperator.And => lv & rv
|
|
case _ => return this
|
|
}
|
|
operator match {
|
|
case MathOperator.Times | MathOperator.Shl =>
|
|
val mask = (1 << (size * 8)) - 1
|
|
if (value != (value & mask)){
|
|
size = ls + rs
|
|
}
|
|
case _ =>
|
|
}
|
|
NumericConstant(value, size)
|
|
case _ => CompoundConstant(operator, l, r)
|
|
}
|
|
}
|
|
|
|
|
|
import MathOperator._
|
|
|
|
override def +(that: Constant): Constant = {
|
|
that match {
|
|
case NumericConstant(n, _) => this + n
|
|
case _ => super.+(that)
|
|
}
|
|
}
|
|
|
|
override def +(that: Long): Constant = {
|
|
if (that == 0) {
|
|
return this
|
|
}
|
|
val That = that
|
|
val MinusThat = -that
|
|
this match {
|
|
case CompoundConstant(Plus, NumericConstant(MinusThat, _), r) => r
|
|
case CompoundConstant(Plus, l, NumericConstant(MinusThat, _)) => l
|
|
case CompoundConstant(Plus, NumericConstant(x, _), r) => CompoundConstant(Plus, r, NumericConstant(x + that, minimumSize(x + that)))
|
|
case CompoundConstant(Plus, l, NumericConstant(x, _)) => CompoundConstant(Plus, l, NumericConstant(x + that, minimumSize(x + that)))
|
|
case CompoundConstant(Minus, l, NumericConstant(That, _)) => l
|
|
case _ => CompoundConstant(Plus, this, NumericConstant(that, minimumSize(that)))
|
|
}
|
|
}
|
|
|
|
private def plhs = lhs match {
|
|
case _: NumericConstant | _: MemoryAddressConstant => lhs
|
|
case _ => "(" + lhs + ')'
|
|
}
|
|
|
|
private def prhs = lhs match {
|
|
case _: NumericConstant | _: MemoryAddressConstant => rhs
|
|
case _ => "(" + rhs + ')'
|
|
}
|
|
|
|
override def toString: String = {
|
|
operator match {
|
|
case Plus => f"$plhs + $prhs"
|
|
case Minus => f"$plhs - $prhs"
|
|
case Times => f"$plhs * $prhs"
|
|
case Shl => f"$plhs << $prhs"
|
|
case Shr => f"$plhs >> $prhs"
|
|
case DecimalPlus => f"$plhs +' $prhs"
|
|
case DecimalMinus => f"$plhs -' $prhs"
|
|
case DecimalTimes => f"$plhs *' $prhs"
|
|
case DecimalShl => f"$plhs <<' $prhs"
|
|
case DecimalShr => f"$plhs >>' $prhs"
|
|
case And => f"$plhs & $prhs"
|
|
case Or => f"$plhs | $prhs"
|
|
case Exor => f"$plhs ^ $prhs"
|
|
}
|
|
}
|
|
|
|
override def requiredSize: Int = lhs.requiredSize max rhs.requiredSize
|
|
} |