%breakpoint! introduced to place after an assignment to make it parse correctly

This commit is contained in:
Irmen de Jong
2025-09-19 23:46:04 +02:00
parent ed5f4d5855
commit ad0c767ea8
7 changed files with 57 additions and 37 deletions
@@ -1092,7 +1092,7 @@ internal class AstChecker(private val program: Program,
if(decl.datatype.isStructInstance && decl.origin!=VarDeclOrigin.SUBROUTINEPARAM) {
if(decl.type==VarDeclType.MEMORY)
errors.err("cannot declare memory mapped struct instances, use a pointer and memory allocation call or direct address assignment instead", decl.position)
errors.err("struct instances cannot be declared as memory-mapped currently, use a pointer and memory allocation call or direct address assignment instead", decl.position)
else
errors.err("struct instances cannot be declared directly, use a pointer and memory allocation call or direct address assignment instead", decl.position)
}
@@ -1173,5 +1173,30 @@ main {
compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false) shouldNotBe null
}
test("breakpoint after expression") {
val src="""
main {
ubyte a,b
sub start() {
func1()
func2()
}
sub func1() {
a = b
%breakpoint ; parse error
}
sub func2() {
a = b
%breakpoint! ; parse ok
}
}"""
val errors = ErrorReporterForTests()
compileText(VMTarget(), optimize=false, src, outputDir, errors=errors) shouldBe null
errors.errors.size shouldBe 3
errors.errors[1] shouldContain "12:10: undefined symbol: breakpoint"
}
})
+11 -1
View File
@@ -340,10 +340,20 @@ Directives
}
.. data:: %breakpoint
.. data:: %breakpoint! or %breakpoint
Level: not at module scope.
Defines a debugging breakpoint at this location. See :ref:`debugging`
The version with the explamation point '!' at the end can be used even
if the breakpoint follows an expression. If you don't use the '!' version in this case
the compiler may think it is just a term in the expression (modulo operator and breakpoint operand value),
instead of a breakpoint directive::
a = b
%breakpoint ; parse error because it thinks it is part of the previous line
a = b
%breakpoint! ; parsed correctly as directive
.. data:: %encoding <encodingname>
+7 -5
View File
@@ -154,9 +154,11 @@ Because it implies pointer dereferencing you can usually omit the explicit `^^`,
.. note::
Structs are only supported as a *reference type* (via a pointer). It is currently not possible to use them as a value type.
Structs are currently only supported as a *reference type* (they always have to be accessed through a pointer).
It is not yet possible to use them as a value type, or as memory-mapped types.
This means you cannot create an array of structs either - only arrays of pointers to structs.
There are a couple of simple case where the compiler allows assignment of struct instances. You are allowed to write::
There are a couple of simple case where the compiler does allow assignment of struct instances though, and it will
automatically copy all the fields for you. You are allowed to write::
ptr2^^ = ptr1^^
ptr2^^ = ptr1[2]
@@ -166,14 +168,14 @@ Because it implies pointer dereferencing you can usually omit the explicit `^^`,
In the future more cases may be supported.
.. note::
Using structs instead of plain arrays may result in less efficent code being generated.
Using structs instead of plain arrays usually results in more and less efficent code being generated.
This is because the 6502 CPU is not particularly well equipped to dealing with pointers and accessing struct fields via offsets,
as compared to direct variable access or array indexing. The prog8 program code may be easier to work with though!
.. note::
Accessing the first field in a struct is more efficient than subsequent fields, because it
is at offset 0 so no additional addition has to be done on a pointer to reach the first field.
Try to put the most often accessed field as the first field to gain a rather substantial code size and efficiency boost.
is at offset 0 so no additional addition has to be computed on a pointer to reach the first field.
Try to put the most often accessed field as the first field to potentially gain a rather substantial boost in code efficiency.
Static initialization of structs
-1
View File
@@ -85,7 +85,6 @@ Future Things and Ideas
9 }
- improve ANTLR grammar with better error handling (according to Qwen AI)
- allow memory() to occur in array initializer
- %breakpoint after an assignment is parsed as part of the expression (x % breakpoint), that should not happen
- when a complete block is removed because unused, suppress all info messages about everything in the block being removed
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1
- is "checkAssignmentCompatible" redundant (gets called just 1 time!) when we also have "checkValueTypeAndRange" ?
+12 -28
View File
@@ -1,34 +1,18 @@
main {
ubyte a,b
sub start() {
^^uword @shared ptr
func1()
func2()
}
add1()
add2()
sub1()
sub2()
sub func1() {
a = b
%breakpoint
}
sub add1() {
ptr += 5
cx16.r0 = ptr + 5
cx16.r0 = peekw(ptr + 5)
}
sub add2() {
ptr += cx16.r0L
cx16.r0 = ptr + cx16.r0L
cx16.r0 = peekw(ptr + cx16.r0L)
}
sub sub1() {
ptr -= 5
cx16.r0 = ptr - 5
cx16.r0 = peekw(ptr - 5)
}
sub sub2() {
ptr -= cx16.r0L
cx16.r0 = ptr - cx16.r0L
cx16.r0 = peekw(ptr - cx16.r0L)
}
sub func2() {
a = b
%breakpoint!
}
}
+1 -1
View File
@@ -151,7 +151,7 @@ labeldef : identifier ':' ;
unconditionaljump : GOTO expression ;
directive : directivename (directivenamelist | (directivearg? | directivearg (',' directivearg)*)) ;
directive : directivename '!'? (directivenamelist | (directivearg? | directivearg (',' directivearg)*)) ;
directivename: '%' UNICODEDNAME;