1
0
mirror of https://github.com/irmen/prog8.git synced 2025-04-14 02:37:09 +00:00

memory() name argument should be string literal, nice error message

This commit is contained in:
Irmen de Jong 2025-03-01 12:38:42 +01:00
parent 6ff75bef29
commit 41e963b04b
5 changed files with 35 additions and 12 deletions
README.md
compiler/src/prog8/compiler/astprocessing
docs/source
examples

@ -63,10 +63,11 @@ What does Prog8 provide?
- various data types other than just bytes (16-bit words, floats, strings)
- floating point math is supported on certain targets
- access to most Kernal ROM routines as external subroutine definitions you can call normally
- tight control over Zeropage usage
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
- automatic static variable allocations, automatic string and array variables and string sharing
- high-level program optimizations
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
- conditional branches that map 1:1 to cpu status flags
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``in`` expression for concise and efficient multi-value/containment check

@ -1375,8 +1375,10 @@ internal class AstChecker(private val program: Program,
if(targetStatement!=null)
checkFunctionCall(targetStatement, functionCallExpr.args, functionCallExpr.position)
val builtinFunctionName = functionCallExpr.target.nameInSource.singleOrNull()
// warn about sgn(unsigned) this is likely a mistake
if(functionCallExpr.target.nameInSource.last()=="sgn") {
if(builtinFunctionName=="sgn") {
val sgnArgType = functionCallExpr.args.first().inferType(program)
if(sgnArgType issimpletype BaseDataType.UBYTE || sgnArgType issimpletype BaseDataType.UWORD)
errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCallExpr.args.first().position)
@ -1400,7 +1402,7 @@ internal class AstChecker(private val program: Program,
}
}
if(functionCallExpr.target.nameInSource.singleOrNull() in listOf("peek", "peekw")) {
if(builtinFunctionName in listOf("peek", "peekw")) {
val pointervar = functionCallExpr.args[0] as? IdentifierReference
if(pointervar!=null)
checkPointer(pointervar)
@ -1409,6 +1411,14 @@ internal class AstChecker(private val program: Program,
checkPointer(binexpr.left as IdentifierReference)
}
if(builtinFunctionName=="memory") {
val str = functionCallExpr.args[0] as? StringLiteral
if(str==null)
errors.err("memory name argument must be a string literal", functionCallExpr.args[0].position)
else if(str.value.isEmpty())
errors.err("memory name argument cannot be empty string", functionCallExpr.args[0].position)
}
super.visit(functionCallExpr)
}

@ -96,6 +96,8 @@ Features
and inline assembly to have full control when every register, cycle or byte matters
- Variables are all allocated statically, no memory allocation overhead
- Variable data types include signed and unsigned bytes and words, arrays, strings.
- Tight control over Zeropage usage
- Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations.
- Conditional branches for status flags that map 1:1 to processor branch instructions for optimal efficiency
- ``when`` statement to avoid if-else chains
- ``in`` expression for concise and efficient multi-value/containment test
@ -110,7 +112,6 @@ Features
- Identifiers can contain Unicode Letters, so ``knäckebröd``, ``приблизительно``, ``見せしめ`` and ``π`` are all valid identifiers.
- Subroutines can return more than one result value
- Advanced code optimizations to make the resulting program smaller and faster
- Programs can be restarted after exiting (i.e. run them multiple times without having to reload everything), due to automatic variable (re)initializations.
- Supports the sixteen 'virtual' 16-bit registers R0 to R15 as defined on the Commander X16. You can look at them as general purpose global variables. These are also available on the other compilation targets!
- On the Commander X16: Support for low level system features such as Vera Fx, which includes 16x16 bits multiplication in hardware and fast memory copy and fill.
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether

@ -187,7 +187,8 @@ sizeof (name) ; sizeof (number)
memory (name, size, alignment)
Returns the address of the first location of a statically "reserved" block of memory of the given size in bytes,
with the given name. The block is *uninitialized memory*; unlike other variables in Prog8 it is *not* set to zero at the start of the program!
with the given name. The name must be a string literal, it cannot be empty or be a variable.
The block is *uninitialized memory*; unlike other variables in Prog8 it is *not* set to zero at the start of the program!
(if that is required, you can do so yourself using ``memset``).
If you specify an alignment value >1, it means the block of memory will
be aligned to such a dividable address in memory, for instance an alignment of $100 means the

@ -1,14 +1,24 @@
%import textio
%zeropage basicsafe
%option no_sysinit, romable
%option no_sysinit
main {
sub start() {
repeat {
if cbm.GETIN2()==27
cx16.poweroff_system()
if cbm.GETIN2()==27
cx16.reset_system()
}
str name1 = "n1"
str name2 = ""
uword buf1 = memory("a", 2000, 0)
uword buf2 = memory("", 2000, 0)
uword buf3 = memory(name1, 2000, 0)
uword buf4 = memory(name2, 2000, 0)
txt.print_uwhex(buf1, true)
txt.spc()
txt.print_uwhex(buf2, true)
txt.spc()
txt.print_uwhex(buf3, true)
txt.spc()
txt.print_uwhex(buf4, true)
txt.spc()
}
}