mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fixed function calls, added some string-to-number conversion functions
This commit is contained in:
parent
734948c813
commit
3278d4c945
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,13 +37,6 @@ enum class Register {
|
||||
XY
|
||||
}
|
||||
|
||||
enum class Statusflag {
|
||||
Pc,
|
||||
Pz,
|
||||
Pv,
|
||||
Pn
|
||||
}
|
||||
|
||||
enum class BranchCondition {
|
||||
CS,
|
||||
CC,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user