fixed function calls, added some string-to-number conversion functions

This commit is contained in:
Irmen de Jong 2018-09-30 22:43:34 +02:00
parent 734948c813
commit 3278d4c945
8 changed files with 112 additions and 99 deletions

View File

@ -1,81 +1,46 @@
%output prg
~ main {
sub start() -> () {
sub start() {
str name = " "
str guess = "0000000000"
byte secretnumber = 0
byte attempts_left = 10
str guess = "000000"
byte guessednumber
byte secretnumber
byte attempts_left
; greeting
_vm_write_str("Let's play a number guessing game!\n")
_vm_write_str("Enter your name: ")
_vm_input_str(name)
_vm_write_char($8d)
_vm_write_char($8d)
_vm_write_str("Hello, ")
_vm_write_str("\nHello, ")
_vm_write_str(name)
_vm_write_char($2e)
_vm_write_char($8d)
_vm_write_str(".\nI am thinking of a number from 1 to 100! You'll have to guess it!\n")
secretnumber = make_number()
secretnumber = rnd() % 100
for attempts_left in 10 to 1 step -1 {
_vm_write_str("\nYou have ")
_vm_write_num(attempts_left)
_vm_write_str(" guess")
if attempts_left>1 _vm_write_str("es")
_vm_write_str(" left. What is your next guess? ")
_vm_input_str(guess)
guessednumber = str2byte(guess)
if guessednumber==secretnumber {
_vm_write_str("\nYou guessed it, impressive!\n")
_vm_write_str("Thanks for playing.\n")
return
} else {
_vm_write_str("That is too ")
if guessednumber<secretnumber
_vm_write_str("low!\n")
else
_vm_write_str("high!\n")
}
}
_vm_write_str("\nToo bad! My number was: ")
_vm_write_num(secretnumber)
_vm_write_str(".\n")
return
sub make_number() -> (X) {
byte number
number = rnd()
return rnd()
return number
}
; ; create a secret random number from 1-100
; c64.RNDA(0) ; fac = rnd(0)
; c64.MUL10() ; fac *= 10
; c64.MUL10() ; .. and now *100
; c64.FADDH() ; add 0.5..
; c64.FADDH() ; and again, so +1 total
; AY = c64flt.GETADRAY()
; secretnumber = A
; ;A=math.randbyte()
; ;A+=c64.RASTER
; ;A-=c64.TIME_LO
; ;X,secretnumber=math.divmod_bytes(A, 99)
;
; c64scr.print_string("I am thinking of a number from 1 to 100!You'll have to guess it!\n")
;
;ask_guess:
; c64scr.print_string("\nYou have ")
; c64scr.print_byte_decimal(attempts_left)
; c64scr.print_string(" guess")
; if(attempts_left>0) c64scr.print_string("es")
;
; c64scr.print_string(" left.\nWhat is your next guess? ")
; Y = c64scr.input_chars(guess)
; c64.CHROUT("\n")
; freadstr_arg = guess
; c64.FREADSTR(A)
; AY = c64flt.GETADRAY()
; if(A==secretnumber) {
; c64scr.print_string("\nThat's my number, impressive!\n")
; goto goodbye
; }
; c64scr.print_string("That is too ")
; if(A > secretnumber)
; c64scr.print_string("low!\n")
; else
; c64scr.print_string("high!\n")
;
; attempts_left--
; if(attempts_left>0) goto ask_guess
; ; more efficient: if_nz goto ask_guess
;
; ; game over.
; c64scr.print_string("\nToo bad! It was: ")
; c64scr.print_byte_decimal(secretnumber)
; c64.CHROUT("\n")
;
;goodbye:
; c64scr.print_string("\nThanks for playing. Bye!\n")
; return
}
}

View File

@ -12,13 +12,19 @@ sub start() {
byte[2,3] matrixvar
byte[5] barrayvar
word[5] warrayvar
; byte eol = "\n" ;; todo: convert string of len 1 to byte
fvar=test(34455)
fvar=test(15, 222.22)
_vm_write_num(fvar)
_vm_write_char($8d)
fvar=test(17, 333.33)
_vm_write_num(fvar)
_vm_write_char($8d)
return
sub test(arg: byte) -> float {
return 44.54
sub test(arg: byte, f: float) -> float {
return f/arg
}
}

View File

@ -37,13 +37,6 @@ enum class Register {
XY
}
enum class Statusflag {
Pc,
Pz,
Pv,
Pn
}
enum class BranchCondition {
CS,
CC,

View File

@ -513,6 +513,8 @@ class AstChecker(private val namespace: INameScope,
val targetStatement = checkFunctionOrLabelExists(functionCall.target, functionCall)
if(targetStatement!=null)
checkFunctionCall(targetStatement, functionCall.arglist, functionCall.position)
if(targetStatement is Subroutine && targetStatement.returnvalues.isNotEmpty())
printWarning("result value of subroutine call is discarded", functionCall.position)
return super.process(functionCall)
}
@ -524,7 +526,7 @@ class AstChecker(private val namespace: INameScope,
// it's a call to a builtin function.
val func = BuiltinFunctions[target.name]!!
if(args.size!=func.parameters.size)
checkResult.add(SyntaxError("invalid number of parameters", position))
checkResult.add(SyntaxError("invalid number of arguments", position))
else {
for (arg in args.withIndex().zip(func.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) !in arg.second.possibleDatatypes)
@ -533,7 +535,7 @@ class AstChecker(private val namespace: INameScope,
}
} else if(target is Subroutine) {
if(args.size!=target.parameters.size)
checkResult.add(SyntaxError("invalid number of parameters", position))
checkResult.add(SyntaxError("invalid number of arguments", position))
else {
for (arg in args.withIndex().zip(target.parameters)) {
if(arg.first.value.resultingDatatype(namespace, heap) != arg.second.type)

View File

@ -220,6 +220,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
override fun process(subroutine: Subroutine): IStatement {
stackvmProg.label(subroutine.scopedname)
// note: the caller has already written the arguments into the subroutine's parameter variables.
translate(subroutine.statements)
return super.process(subroutine)
}
@ -403,7 +404,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
translateFunctionCall(funcname, expr.arglist)
} else {
when(target) {
is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.parent)
is Subroutine -> translateSubroutineCall(target, expr.arglist)
else -> TODO("non-builtin-function call to $target")
}
}
@ -468,8 +469,12 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
when(targetStmt) {
is Label ->
stackvmProg.instr(Opcode.CALL, callLabel = targetStmt.scopedname)
is Subroutine ->
translateSubroutineCall(targetStmt, stmt.arglist, stmt)
is Subroutine -> {
translateSubroutineCall(targetStmt, stmt.arglist)
// make sure we clean up the unused result values from the stack.
for(rv in targetStmt.returnvalues)
stackvmProg.instr(Opcode.DISCARD)
}
else ->
throw AstException("invalid call target node type: ${targetStmt::class}")
}
@ -504,9 +509,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
}
}
fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, parent: Node) {
for(param in arguments.zip(subroutine.parameters)) {
// @todo push params onto stack in correct order
private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>) {
// evaluate the arguments and assign them into the subroutine's argument variables.
for(arg in arguments.zip(subroutine.parameters)) {
translate(arg.first)
stackvmProg.instr(Opcode.POP_VAR, callLabel = subroutine.scopedname+"."+arg.second.name)
}
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
}
@ -666,9 +673,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
}
private fun translate(stmt: Return) {
val returnvalues = (stmt.definingScope() as? Subroutine)?.returnvalues ?: emptyList()
for(value in stmt.values.zip(returnvalues)) {
// @todo assign the return values to the proper return variables
// put the return values on the stack, in reversed order. The caller will process them.
for(value in stmt.values.reversed()) {
translate(value)
}
stackvmProg.line(stmt.position)
stackvmProg.instr(Opcode.RETURN)

View File

@ -54,15 +54,26 @@ val BuiltinFunctions = mapOf(
"clear_carry" to FunctionSignature(false, emptyList(), null),
"set_irqd" to FunctionSignature(false, emptyList(), null),
"clear_irqd" to FunctionSignature(false, emptyList(), null),
"_vm_write_memchr" to FunctionSignature(false, emptyList(), null),
"_vm_write_memstr" to FunctionSignature(false, emptyList(), null),
"_vm_write_num" to FunctionSignature(false, emptyList(), null),
"_vm_write_char" to FunctionSignature(false, emptyList(), null),
"_vm_write_str" to FunctionSignature(false, emptyList(), null),
"_vm_input_str" to FunctionSignature(false, emptyList(), null),
"_vm_gfx_clearscr" to FunctionSignature(false, emptyList(), null),
"_vm_gfx_pixel" to FunctionSignature(false, emptyList(), null),
"_vm_gfx_text" to FunctionSignature(false, emptyList(), null)
"str2byte" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))), DataType.BYTE),
"str2word" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))), DataType.WORD),
"str2float" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))), DataType.FLOAT),
"_vm_write_memchr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", listOf(DataType.WORD))), null),
"_vm_write_memstr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", listOf(DataType.WORD))), null),
"_vm_write_num" to FunctionSignature(false, listOf(BuiltinFunctionParam("number", listOf(DataType.BYTE, DataType.WORD, DataType.FLOAT))), null),
"_vm_write_char" to FunctionSignature(false, listOf(BuiltinFunctionParam("char", listOf(DataType.BYTE))), null),
"_vm_write_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("string", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))), null),
"_vm_input_str" to FunctionSignature(false, listOf(BuiltinFunctionParam("intovar", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))), null),
"_vm_gfx_clearscr" to FunctionSignature(false, listOf(BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
"_vm_gfx_pixel" to FunctionSignature(false, listOf(
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("color", listOf(DataType.BYTE))), null),
"_vm_gfx_text" to FunctionSignature(false, listOf(
BuiltinFunctionParam("x", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("y", listOf(DataType.BYTE, DataType.WORD)),
BuiltinFunctionParam("color", listOf(DataType.BYTE)),
BuiltinFunctionParam("text", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS))),
null)
)

View File

@ -158,6 +158,9 @@ enum class Syscall(val callNr: Short) {
FUNC_RND(89), // push a random byte on the stack
FUNC_RNDW(90), // push a random word on the stack
FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0)
FUNC_STR2BYTE(92),
FUNC_STR2WORD(93),
FUNC_STR2FLOAT(94)
// note: not all builtin functions of the Prog8 language are present as functions:
// some of them are straight opcodes (such as MSB, LSB, LSL, LSR, ROL, ROR, ROL2, ROR2, and FLT)!
@ -618,7 +621,24 @@ class StackVm(private var traceOutputFile: String?) {
else
evalstack.push(Value(DataType.BYTE, if (value.array!!.all{v->v!=0}) 1 else 0))
}
else -> throw VmExecutionException("unimplemented syscall $syscall")
Syscall.FUNC_STR2BYTE -> {
val strvar = evalstack.pop()
val str = heap.get(strvar.heapId)
val y = str.str!!.trim().trimEnd('\u0000')
evalstack.push(Value(DataType.BYTE, y.toShort()))
}
Syscall.FUNC_STR2WORD -> {
val strvar = evalstack.pop()
val str = heap.get(strvar.heapId)
val y = str.str!!.trim().trimEnd('\u0000')
evalstack.push(Value(DataType.BYTE, y.toInt()))
}
Syscall.FUNC_STR2FLOAT -> {
val strvar = evalstack.pop()
val str = heap.get(strvar.heapId)
val y = str.str!!.trim().trimEnd('\u0000')
evalstack.push(Value(DataType.BYTE, y.toDouble()))
}
}
}

View File

@ -561,6 +561,15 @@ rndw()
rndf()
returns a pseudo-random float between 0.0 and 1.0
str2byte(s)
converts string s into the numeric value that s represents (byte).
str2word(s)
converts string s into the numeric value that s represents (word).
str2float(s)
converts string s into the numeric value that s represents (float).
lsl(x)
Shift the bits in x (byte or word) one position to the left.
Bit 0 is set to 0 (and the highest bit is shifted into the status register's Carry flag)