diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 236d91837..cb627ed97 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -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) } diff --git a/compiler/test/ast/TestVariousCompilerAst.kt b/compiler/test/ast/TestVariousCompilerAst.kt index 7c430584c..aa5371601 100644 --- a/compiler/test/ast/TestVariousCompilerAst.kt +++ b/compiler/test/ast/TestVariousCompilerAst.kt @@ -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" + } }) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 7e4726bd9..b8c38f208 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -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 diff --git a/docs/source/structpointers.rst b/docs/source/structpointers.rst index d634d709e..6137af127 100644 --- a/docs/source/structpointers.rst +++ b/docs/source/structpointers.rst @@ -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 diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8ef919119..51c1d91c5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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" ? diff --git a/examples/test.p8 b/examples/test.p8 index b8716347f..b210356eb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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! } } diff --git a/parser/src/main/antlr/Prog8ANTLR.g4 b/parser/src/main/antlr/Prog8ANTLR.g4 index 03285cbea..71a406cf6 100644 --- a/parser/src/main/antlr/Prog8ANTLR.g4 +++ b/parser/src/main/antlr/Prog8ANTLR.g4 @@ -151,7 +151,7 @@ labeldef : identifier ':' ; unconditionaljump : GOTO expression ; -directive : directivename (directivenamelist | (directivearg? | directivearg (',' directivearg)*)) ; +directive : directivename '!'? (directivenamelist | (directivearg? | directivearg (',' directivearg)*)) ; directivename: '%' UNICODEDNAME;