From 5482ac0302720a0649f27fc4a5f528a7af5532e0 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 21 Dec 2024 01:05:08 +0100 Subject: [PATCH] simplify grammar of @tags, also improving their error message --- compiler/src/prog8/compiler/Compiler.kt | 2 +- .../compiler/astprocessing/AstPreprocessor.kt | 6 ++ compiler/test/ast/TestVariousCompilerAst.kt | 6 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 56 +++++++++---------- docs/source/todo.rst | 1 - examples/test.p8 | 5 -- parser/src/main/antlr/Prog8ANTLR.g4 | 26 +-------- 7 files changed, 41 insertions(+), 61 deletions(-) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 69eab8cd7..4f75753bf 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -414,7 +414,7 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat private fun processAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { program.preprocessAst(errors, compilerOptions) - if(compilerOptions.dumpSymbols) { + if(errors.noErrors() && compilerOptions.dumpSymbols) { printSymbols(program) exitProcess(0) } diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index e7942fd1e..7dc6c5628 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -56,6 +56,12 @@ class AstPreprocessor(val program: Program, vardecl.value = NumericLiteral(oldAddr.type, address.toDouble(), oldAddr.position) } + override fun before(directive: Directive, parent: Node): Iterable { + if(directive.parent is Expression) + errors.err("${directive.directive} is ambiguous here as an operand for the % operator and a directive. Add spaces around the operator % to distinguish it.", directive.position) + return noModifications + } + override fun before(char: CharLiteral, parent: Node): Iterable { if(char.encoding== Encoding.DEFAULT) char.encoding = char.definingModule.textEncoding diff --git a/compiler/test/ast/TestVariousCompilerAst.kt b/compiler/test/ast/TestVariousCompilerAst.kt index b4dab744f..70d44db21 100644 --- a/compiler/test/ast/TestVariousCompilerAst.kt +++ b/compiler/test/ast/TestVariousCompilerAst.kt @@ -756,9 +756,9 @@ main { val src=""" main { sub start() { - ubyte bb1 = 199 - ubyte bb2 = 12 - ubyte @shared bb3 = bb1%bb2 + ubyte @shared bb = 199 + ubyte @shared cc = 12 + ubyte @shared bb2 = bb%cc } }""" diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 7c1e69535..4a510e815 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -332,12 +332,13 @@ private fun SubroutineContext.toAst() : Subroutine { private fun Sub_paramsContext.toAst(): List = sub_param().map { val decl = it.vardecl() - val options = decl.decloptions() - if(options.ALIGNPAGE().isNotEmpty() || options.ALIGNWORD().isNotEmpty()) - throw SyntaxError("cannot use alignments on parameters", it.toPosition()) - if(options.DIRTY().isNotEmpty()) - throw SyntaxError("cannot use @dirty on parameters", it.toPosition()) - val zp = getZpOption(options) + val tags = decl.TAG().map { it.text } + val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared") + for(tag in tags) { + if(tag !in validTags) + throw SyntaxError("invalid parameter tag '$tag'", toPosition()) + } + val zp = getZpOption(tags) var baseDt = decl.datatype()?.toAst() ?: BaseDataType.UNDEFINED var datatype = DataType.forDt(baseDt) if(decl.ARRAYSIG()!=null || decl.arrayindex()!=null) @@ -355,23 +356,17 @@ private fun Sub_paramsContext.toAst(): List = SubroutineParameter(identifiername.text, datatype, zp, registerorpair, it.toPosition()) } -private fun getZpOption(options: DecloptionsContext?): ZeropageWish { - if(options==null) - return ZeropageWish.DONTCARE - return when { - options.ZEROPAGEREQUIRE().isNotEmpty() -> ZeropageWish.REQUIRE_ZEROPAGE - options.ZEROPAGE().isNotEmpty() -> ZeropageWish.PREFER_ZEROPAGE - options.ZEROPAGENOT().isNotEmpty() -> ZeropageWish.NOT_IN_ZEROPAGE - else -> ZeropageWish.DONTCARE - } +private fun getZpOption(tags: List): ZeropageWish = when { + "@requirezp" in tags -> ZeropageWish.REQUIRE_ZEROPAGE + "@zp" in tags -> ZeropageWish.PREFER_ZEROPAGE + "@nozp" in tags -> ZeropageWish.NOT_IN_ZEROPAGE + else -> ZeropageWish.DONTCARE } -private fun getSplitOption(options: DecloptionsContext?): SplitWish { - if(options==null) - return SplitWish.DONTCARE +private fun getSplitOption(tags: List): SplitWish { return when { - options.NOSPLIT().isNotEmpty() -> SplitWish.NOSPLIT - options.SPLIT().isNotEmpty() -> SplitWish.SPLIT + "@nosplit" in tags -> SplitWish.NOSPLIT + "@split" in tags -> SplitWish.SPLIT else -> SplitWish.DONTCARE } } @@ -773,16 +768,21 @@ private fun When_choiceContext.toAst(): WhenChoice { } private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl { - val options = decloptions() - val zp = getZpOption(options) - val split = getSplitOption(options) + val tags = TAG().map { it.text } + val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared", "@alignword", "@alignpage", "@align64", "@dirty") + for(tag in tags) { + if(tag !in validTags) + throw SyntaxError("invalid variable tag '$tag'", toPosition()) + } + val zp = getZpOption(tags) + val split = getSplitOption(tags) val identifiers = identifier() val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() val name = if(identifiers.size==1) identifiername.text else "" val isArray = ARRAYSIG() != null || arrayindex() != null - val alignword = options.ALIGNWORD().isNotEmpty() - val align64 = options.ALIGN64().isNotEmpty() - val alignpage = options.ALIGNPAGE().isNotEmpty() + val alignword = "@alignword" in tags + val align64 = "@align64" in tags + val alignpage = "@alignpage" in tags if(alignpage && alignword) throw SyntaxError("choose a single alignment option", toPosition()) val baseDt = datatype()?.toAst() ?: BaseDataType.UNDEFINED @@ -800,9 +800,9 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl idname.text }, value, - options.SHARED().isNotEmpty(), + "@shared" in tags, if(alignword) 2u else if(align64) 64u else if(alignpage) 256u else 0u, - options.DIRTY().isNotEmpty(), + "@dirty" in tags, toPosition() ) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 09c76b4d1..efc357a1f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -20,7 +20,6 @@ TODO Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ -- SourceLineCache should be removed as a separate thing, it reloads all source files again and splits them by line. It should re-use the already loaded Sources. Wrap it all in a ImporterFileSystem? - Compiling Libraries: improve ability to create library files in prog8; for instance there's still stuff injected into the start of the start() routine AND there is separate setup logic going on before calling it. Make up our mind! Maybe all setup does need to be put into start() ? because the program cannot function correctly when the variables aren't initialized properly bss is not cleared etc. etc. Add a -library $xxxx command line option (and/or some directive) to preselect every setting that is required to make a library at $xxxx rather than a normal loadable and runnable program? diff --git a/examples/test.p8 b/examples/test.p8 index e8c414a6e..fb81add50 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,9 +1,4 @@ -%import compression - main { sub start() { - ; compression.decode_rle(0,0,0) - ; compression.decode_zx0(0,0) - compression.decode_tscrunch(0,0) } } diff --git a/parser/src/main/antlr/Prog8ANTLR.g4 b/parser/src/main/antlr/Prog8ANTLR.g4 index ad022dbc6..3d7442fc7 100644 --- a/parser/src/main/antlr/Prog8ANTLR.g4 +++ b/parser/src/main/antlr/Prog8ANTLR.g4 @@ -55,25 +55,7 @@ SINGLECHAR : '\'' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f'] ) '\'' ; -ZEROPAGE : '@zp' ; - -ZEROPAGEREQUIRE : '@requirezp' ; - -ZEROPAGENOT: '@nozp' ; - -SHARED : '@shared' ; - -SPLIT: '@split' ; - -NOSPLIT: '@nosplit' ; - -ALIGNWORD: '@alignword' ; - -ALIGN64: '@align64' ; - -ALIGNPAGE: '@alignpage' ; - -DIRTY: '@dirty' ; +TAG: '@' ('a'..'z' | '0'..'9')+ ; ARRAYSIG : '[' [ \t]* ']' ; @@ -161,9 +143,7 @@ directive : directivearg : stringliteral | identifier | integerliteral ; -vardecl: datatype (arrayindex | ARRAYSIG)? decloptions identifier (',' identifier)* ; - -decloptions: (SHARED | ZEROPAGE | ZEROPAGEREQUIRE | ZEROPAGENOT | NOSPLIT | SPLIT | ALIGNWORD | ALIGN64 | ALIGNPAGE | DIRTY)* ; +vardecl: datatype (arrayindex | ARRAYSIG)? TAG* identifier (',' identifier)* ; varinitializer : vardecl '=' expression ; @@ -302,7 +282,7 @@ asmsubroutine : ; extsubroutine : - 'extsub' ('@bank' (constbank=integerliteral | varbank=scoped_identifier))? address=expression '=' asmsub_decl + 'extsub' (TAG (constbank=integerliteral | varbank=scoped_identifier))? address=expression '=' asmsub_decl ; asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns? ;