functions

This commit is contained in:
Irmen de Jong 2018-08-14 01:15:11 +02:00
parent 74fd5d29b8
commit 666b9b2263
5 changed files with 111 additions and 10 deletions

View File

@ -360,3 +360,54 @@ by nothing, which is the same as AXY) to tell the compiler you want to preserve
value of the given registers after the subroutine call. Otherwise, the subroutine may just value of the given registers after the subroutine call. Otherwise, the subroutine may just
as well clobber all three registers. Preserving the original values does result in some as well clobber all three registers. Preserving the original values does result in some
stack manipulation code to be inserted for every call like this, which can be quite slow. stack manipulation code to be inserted for every call like this, which can be quite slow.
Built-in Functions
------------------
The compiler has the following built-in functions that you can use in expressions:
sin(value)
Sine.
cos(value)
Cosine.
abs(value)
Absolute value.
acos(value)
Arccosine.
asin(value)
Arcsine.
tan(value)
Tangent.
atan(value)
Arctangent.
log(value)
Natural logarithm.
log10(value)
Base-10 logarithm.
sqrt(value)
Square root.
max(value [, value, ...])
Maximum of the values.
min(value [, value, ...])
Minumum of the values.
round(value)
Rounds the floating point to an integer.
rad(value)
Degrees to radians.
deg(value)
Radians to degrees.

View File

@ -1,7 +1,12 @@
~ main $c003 { ~ main $c003 {
;memory byte derp = $ffdd memory byte derp = max($ffdd)
;memory byte derp2 = 2+$ffdd+sin(3) memory byte derpA = abs(-2.5-0.5)
memory byte derp3 = round(sin(3)) memory byte derpB = max(1, 2.2, 4.4, 100)
memory byte cderp = min($ffdd)
memory byte cderpA = min($ffdd, 10, 20, 30)
memory byte cderpB = min(1, 2.2, 4.4, 100)
memory byte derp2 = 2+$ffdd+round(10*sin(3))
memory byte derp3 = round(100*sin(3))
const byte hopla=55-33 const byte hopla=55-33
const byte hopla2=100+(-main.hopla) const byte hopla2=100+(-main.hopla)
const byte hopla3=100+(-hopla) const byte hopla3=100+(-hopla)

View File

@ -525,7 +525,6 @@ data class FunctionCall(var location: Identifier, var arglist: List<IExpression>
override fun constValue(namespace: INameScope): LiteralValue? { override fun constValue(namespace: INameScope): LiteralValue? {
// if the function is a built-in function and the args are consts, should evaluate! // if the function is a built-in function and the args are consts, should evaluate!
println("CONSTVALUE of Function call $location") // todo
if(location.scopedName.size>1) return null if(location.scopedName.size>1) return null
return when(location.scopedName[0]){ return when(location.scopedName[0]){
"sin" -> builtin_sin(arglist, namespace) "sin" -> builtin_sin(arglist, namespace)
@ -541,6 +540,8 @@ data class FunctionCall(var location: Identifier, var arglist: List<IExpression>
"max" -> builtin_max(arglist, namespace) "max" -> builtin_max(arglist, namespace)
"min" -> builtin_min(arglist, namespace) "min" -> builtin_min(arglist, namespace)
"round" -> builtin_round(arglist, namespace) "round" -> builtin_round(arglist, namespace)
"rad" -> builtin_rad(arglist, namespace)
"deg" -> builtin_deg(arglist, namespace)
else -> null else -> null
} }
} }

View File

@ -30,9 +30,12 @@ class AstOptimizer(private val globalNamespace: INameScope) : IAstProcessor {
* some identifiers can be replaced with the constant value they refer to * some identifiers can be replaced with the constant value they refer to
*/ */
override fun process(identifier: Identifier): IExpression { override fun process(identifier: Identifier): IExpression {
println("PROCESS ID $identifier") // todo return identifier.constValue(globalNamespace) ?: identifier
val const = identifier.constValue(globalNamespace) }
return const ?: identifier
override fun process(functionCall: FunctionCall): IExpression {
super.process(functionCall)
return functionCall.constValue(globalNamespace) ?: functionCall
} }
/** /**

View File

@ -3,6 +3,7 @@ package il65.functions
import il65.ast.IExpression import il65.ast.IExpression
import il65.ast.INameScope import il65.ast.INameScope
import il65.ast.LiteralValue import il65.ast.LiteralValue
import il65.ast.Position
private fun oneDoubleArg(args: List<IExpression>, namespace: INameScope, function: (arg: Double)->Double): LiteralValue { private fun oneDoubleArg(args: List<IExpression>, namespace: INameScope, function: (arg: Double)->Double): LiteralValue {
if(args.size!=1) if(args.size!=1)
@ -50,7 +51,6 @@ private fun twoDoubleArg(args: List<IExpression>, namespace: INameScope, functio
fun builtin_round(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArgOutputInt(args, namespace) { it -> Math.round(it).toInt() } fun builtin_round(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArgOutputInt(args, namespace) { it -> Math.round(it).toInt() }
fun builtin_sin(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::sin) fun builtin_sin(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::sin)
fun builtin_cos(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::cos) fun builtin_cos(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::cos)
fun builtin_abs(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::abs)
fun builtin_acos(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::acos) fun builtin_acos(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::acos)
fun builtin_asin(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::asin) fun builtin_asin(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::asin)
fun builtin_tan(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::tan) fun builtin_tan(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::tan)
@ -58,5 +58,46 @@ fun builtin_atan(args: List<IExpression>, namespace: INameScope): LiteralValue =
fun builtin_log(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::log) fun builtin_log(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::log)
fun builtin_log10(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::log10) fun builtin_log10(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::log10)
fun builtin_sqrt(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::sqrt) fun builtin_sqrt(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::sqrt)
fun builtin_max(args: List<IExpression>, namespace: INameScope): LiteralValue = twoDoubleArg(args, namespace, Math::max) fun builtin_rad(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::toRadians)
fun builtin_min(args: List<IExpression>, namespace: INameScope): LiteralValue = twoDoubleArg(args, namespace, Math::min) fun builtin_deg(args: List<IExpression>, namespace: INameScope): LiteralValue = oneDoubleArg(args, namespace, Math::toDegrees)
fun builtin_abs(args: List<IExpression>, namespace: INameScope): LiteralValue {
if(args.size!=1)
throw UnsupportedOperationException("built-in function abs requires one numeric argument")
val float = args[0].constValue(namespace)?.asFloat()
if(float!=null)
return IntOrFloatLiteral(Math.abs(float), args[0].position)
else
throw UnsupportedOperationException("built-in function abs requires floating point value as argument")
}
fun builtin_max(args: List<IExpression>, namespace: INameScope): LiteralValue {
if(args.isEmpty())
throw UnsupportedOperationException("max requires at least one argument")
val constants = args.map { it.constValue(namespace) }
if(constants.contains(null))
throw UnsupportedOperationException("not all arguments to max are a constant value")
val result = constants.map { it?.asFloat()!! }.max()
return IntOrFloatLiteral(result!!, args[0].position)
}
fun builtin_min(args: List<IExpression>, namespace: INameScope): LiteralValue {
if(args.isEmpty())
throw UnsupportedOperationException("min requires at least one argument")
val constants = args.map { it.constValue(namespace) }
if(constants.contains(null))
throw UnsupportedOperationException("not all arguments to min are a constant value")
val result = constants.map { it?.asFloat()!! }.min()
return IntOrFloatLiteral(result!!, args[0].position)
}
private fun IntOrFloatLiteral(value: Double, position: Position?): LiteralValue {
val intresult = value.toInt()
val result = if(value-intresult==0.0)
LiteralValue(intvalue = intresult)
else
LiteralValue(floatvalue = value)
result.position = position
return result
}