diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 74d06db42..be8ccf248 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -1054,16 +1054,18 @@ internal class AstChecker(private val program: Program, private fun visitStatements(statements: List) { for((index, stmt) in statements.withIndex()) { - if(stmt is FunctionCallStatement - && stmt.target.nameInSource.last()=="exit" - && index < statements.lastIndex) { - println("STMT AFTER EXIT ${statements[index+1]}") // TODO fix message if next stmt is not a regular stmt - errors.warn("unreachable code, preceding exit call will never return", statements[index + 1].position) - } - - if(stmt is Return && index < statements.lastIndex) { - println("STMT AFTER RETURN ${statements[index+1]}") // TODO fix message if next stmt is not a regular stmt - errors.warn("unreachable code, preceding return statement", statements[index + 1].position) + if(index < statements.lastIndex && statements[index+1] !is Subroutine) { + when { + stmt is FunctionCallStatement && stmt.target.nameInSource.last() == "exit" -> { + errors.warn("unreachable code, preceding exit call will never return", statements[index + 1].position) + } + stmt is Return && statements[index + 1] !is Subroutine -> { + errors.warn("unreachable code, preceding return statement", statements[index + 1].position) + } + stmt is Jump && statements[index + 1] !is Subroutine -> { + errors.warn("unreachable code, preceding jump statement", statements[index + 1].position) + } + } } stmt.accept(this) diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 424ad15ff..164904429 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -40,7 +40,6 @@ fun compileProgram(filepath: Path, if (optimize) optimizeAst(programAst, errors) postprocessAst(programAst, errors, compilationOptions) - printAst(programAst) // TODO if(writeAssembly) programName = writeAssembly(programAst, errors, outputDir, optimize, compilationOptions) } diff --git a/docs/source/index.rst b/docs/source/index.rst index 63097375b..c9fbbb730 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -135,31 +135,29 @@ Design principles and features - It is a cross-compiler running on modern machines (Linux, MacOS, Windows, ...) The generated output is a machine code program runnable on actual 8-bit 6502 hardware. -- Usable on most operating systems. -- Based on simple and familiar imperative structured programming paradigm. -- 'One statement per line' code style, resulting in clear readable programs. +- Based on simple and familiar imperative structured programming (it looks like a mix of C and Python) +- 'One statement per line' code, resulting in clear readable programs. - Modular programming and scoping via modules, code blocks, and subroutines. -- Provide high level programming constructs but stay close to the metal; +- Provide high level programming constructs but at the same time stay close to the metal; still able to directly use memory addresses, CPU registers and ROM subroutines, and inline assembly to have full control when every cycle or byte matters -- Arbitrary number of subroutine parameters (constrained only by available memory) -- Nested subroutines can access variables from outer scopes, this avoids the need and overhead to pass everything via parameters +- Arbitrary number of subroutine parameters - Complex nested expressions are possible -- Values are typed. Types supported include signed and unsigned bytes and words, arrays, strings and floats. +- Nested subroutines can access variables from outer scopes to avoids the overhead to pass everything via parameters +- Values are typed. Available data types include signed and unsigned bytes and words, arrays, strings and floats. - No dynamic memory allocation or sizing! All variables stay fixed size as determined at compile time. - Provide various quality of life language features and library subroutines specifically for the target platform. - Provide a very convenient edit/compile/run cycle by being able to directly launch - the compiled program in an emulator and provide debugging information to the emulator. -- The compiler outputs a regular 6502 assembly source code file, but doesn't assemble this itself. - The (separate) '64tass' cross-assembler tool is used for that. + the compiled program in an emulator and provide debugging information to this emulator. - Arbitrary control flow jumps and branches are possible, and will usually translate directly into the appropriate single 6502 jump/branch instruction. - There are no complicated built-in error handling or overflow checks, you'll have to take care of this yourself if required. This keeps the language and code simple and efficient. -- The compiler tries to optimize the program and generated code, but hand-tuning of the +- The compiler tries to optimize the program and generated code a bit, but hand-tuning of the performance or space-critical parts will likely still be required. This is supported by the ability to easily write embedded assembly code directly in the program source code. - There are many built-in functions, such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``, ``sort`` and ``reverse`` +- Assembling the generated code into a program wil be done by an external cross-assembler tool. .. _requirements: diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4ce07a91c..63958eef0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,19 +3,14 @@ TODO ==== - implement the asm for bitshift on arrays (last missing assembly code generation) -- remove statements after an exit() or return -- fix warnings about that unreachable code? -- add a compiler option to not include variable initialization code (useful if the program is expected to run only once, such as a game) - the program will then rely solely on the values as they are in memory at the time of program startup. - -- create real assembly routines for the bresenham line and circle code -- also add assembly routines in c64scr for drawing rectangles (filled/open) -- add these routines for bitmap screen modes as well -- add a turtle example once we have highres drawing routines +- add a routine to plot a single bitmap pixel +- create real assembly routines for the bresenham line and circle and disc code in bitmap gfx +- also add assembly routines for drawing rectangles (filled/open) in bitmap gfx +- add a turtle example once we have such highres drawing routines - aliases for imported symbols for example perhaps '%alias print = c64scr.print' -- option to load library files from a directory instead of the embedded ones +- option to load library files from a directory instead of the embedded ones (easier library development/debugging) @@ -42,12 +37,14 @@ More optimizations Add more compiler optimizations to the existing ones. -- on the language AST level -- on the final assembly source level +- remove unreachable code after an exit(), return or goto +- working subroutine inlining (start with trivial routines, grow to taking care of vars and identifier refs to them) +- add a compiler option to not include variable initialization code (useful if the program is expected to run only once, such as a game) + the program will then rely solely on the values as they are in memory at the time of program startup. +- Also some library routines and code patterns could perhaps be optimized further - can the parameter passing to subroutines be optimized to avoid copying? -- working subroutine inlining (taking care of vars and identifier refs to them) - -Also some library routines and code patterns could perhaps be optimized further +- more optimizations on the language AST level +- more optimizations on the final assembly source level Eval stack redesign? (lot of work) @@ -59,13 +56,14 @@ It could then even be moved into the zeropage to greatly reduce code size and sl Or just move the LSB portion into a slab of the zeropage. -Allocate a fixed word in ZP that is the TOS so we can always operate on TOS directly -without having to to index into the stack? +Allocate a fixed word in ZP that is the Top Of Stack value so we can always operate on TOS directly +without having to index with X into the eval stack all the time? +This could GREATLY improvde code size and speed for operatios that work on just a single value. -Bugs -^^^^ -Ofcourse there are still bugs to fix ;) +Bug Fixing +^^^^^^^^^^ +Ofcourse there are always bugs to fix ;) Misc diff --git a/examples/test.p8 b/examples/test.p8 index 5d39fe345..6ed1c2deb 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -12,16 +12,19 @@ main { bla() exit(4) v1 = 100 + goto start ; TODO unreachable code warning v2 = 127 A=5 + return sub bla () { A=99 bla2() - + exit(99) sub bla2 () { A=100 + return foo.ding() foo.ding2() }