Giter Club home page Giter Club logo

irmen / prog8 Goto Github PK

View Code? Open in Web Editor NEW
135.0 12.0 15.0 28.29 MB

high level programming language and compiler targeting 6502 machines such as the C-64 and CommanderX16

Home Page: https://prog8.readthedocs.io/

License: Other

Shell 0.01% Makefile 0.03% ANTLR 0.23% Lua 19.95% Kotlin 75.84% Assembly 1.50% Python 1.31% Vim Script 1.12%
6502 retro retrocomputing commodore-64 compiler programming-language c64 kotlin language commander-x16

prog8's People

Contributors

adiee5 avatar akumanatt avatar elektron72 avatar fboldog avatar freddyoffenga avatar frosty-j avatar irmen avatar markjreed avatar meisl avatar mike-mcgann avatar oodler577 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prog8's Issues

Docs reference X16 v39 roms, but not available?

The docs for prog8 state that the system targets V39 of the Commander X16 ROMS.
However the latest version available on the Commander X16 github is V38 (as of 11.06.2021)
So far what I have compiled has worked on V38.
The prog8 documentation as it stands seems a little confusing.

irq handler should use its own eval-stack

right now the irq-handler will use the same eval stack as the regular code.
This will cause issues when the irq is triggered while stack manipulations occur in regular code.

Irq handler should get its own eval stack.

.... is it acceptable to take the lower say 100 bytes of the normal stack (the size of which will be reduced to 156 bytes then instead of 256). Saves one whole memory page...

ALSO: the interrupt handler should backup the contents of the handful of zeropage scratch addresses and restore them on exit (SCRATCH_ZP_REG etc etc)

sometimes absolute file path is printed in error messages, sometimes not

For instance when compiling cx16assem:

Processing for target cx16...
src/assembler.p8:426:31: WARNING this asmsub also has one or more return 'values' in one of the status flags
src/assembler.p8:458:33: WARNING this asmsub also has one or more return 'values' in one of the status flags
/home/irmen/Projects/cx16assem/src/asmsymbols.p8:86:21: WARNING this asmsub also has one or more return 'values' in one of the status flags
/home/irmen/Projects/cx16assem/src/asmsymbols.p8:118:21: WARNING this asmsub also has one or more return 'values' in one of the status flags
/home/irmen/Projects/cx16assem/src/asmsymbols.p8:162:21: WARNING this asmsub also has one or more return 'values' in one of the status flags

Seems like the position object now sometimes contains full absolute paths
that's not bad in itself but

  • sometimes it still contains relative paths or so it seems from the first 2 warnings printed above
  • I'd like to see this unified
  • in error messages for the user, we should normalize the path relative to the current working directory.

NullPointerException when assigning string literal to byte array

  • Prog8 version: 6.4
  • Command: java -jar prog8compiler-6.4-all.jar prog8-issue34.p8
  • Source code:
%import textio
%zeropage basicsafe
%option no_sysinit

main {
	byte[] xs = "foo" ; <<<<<<<<<<<<
	sub start() {
		txt.print(xs)
	}
}
  • Expected: type error being reported
  • Actual:
* internal error *
Exception in thread "main" java.lang.NullPointerException
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:631)
        at prog8.ast.statements.VarDecl.accept(AstStatements.kt:242)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:30)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:182)
        at prog8.ast.statements.Block.accept(AstStatements.kt:66)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:14)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:48)
        at prog8.ast.Module.accept(AstToplevel.kt:365)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:10)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:44)
        at prog8.compiler.astprocessing.AstExtensionsKt.checkValid(AstExtensions.kt:14)
        at prog8.compiler.CompilerKt.processAst(Compiler.kt:257)
        at prog8.compiler.CompilerKt.compileProgram(Compiler.kt:97)
        at prog8.CompilerMainKt.compileMain(CompilerMain.kt:106)
        at prog8.CompilerMainKt.main(CompilerMain.kt:23)
  • Remarks:
    • I've never worked with Kotlin, so please bear with me :)
    • In AstChecker.kt, there's the private fun checkValueTypeAndRangeString(...) : Boolean called from inside visit(...). It seems the return value is not used.
    • The above link points to the v6.4 source file, ie. line numbers from the trace refer to this rev.

Questions re parameters of ctor Module (AST node)

[
Sorry for pressing on you, @irmen. But I only got the weekend and I need to at least write it down now.
And again: PLEASE don't be put off by the style of writing. I'm just trying to be concise. No offense of any sort intended; on the contrary!
What I'm laying out looks like a total mess (= what's in my head) - which does not at all mean that there isn't a simple solution.
Likewise: it's totally possible that I'm just dumb and not seeing things.
]


These questions came up to me when implementing the plan laid out in #50. They are, however, in fact independent of that.

Looking at the constructor of AST node Module,

    class Module(override val name: String,
             override var statements: MutableList<Statement>,
             override val position: Position,
             val isLibraryModule: Boolean,
             val source: Path): Node, INameScope

together with that of Position,

    data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int)

we can see that name, position (via Position's file) and source - plus, maybe?, isLibraryModule - are somewhat interdependent/redundant, and not entirely clear wrt. their exact meaning.

  • source: Path
    • what if the module comes from resources (the .jar of a release)?
    • what if the user has a folder prog8lib/ in their file system, and stated it via CLI option -libdirs as a location to search in?
    • what if the Module instance does not come from any source code file at all? Think of "prog8_interned_strings", or just plain Strings as in testing. Maybe also, eventually, precompiled libraries.
  • position: Position
    • its file: same as above, only that it's a String instead of a Path
    • its line, startCol, endCol:
      • either they follow the (assumed) convention of a Node's position and mark the chunk of text from which that Module was parsed. But then that would technically be from 1st character up to last character of that text, which isn't even expressible with just line, startCol and endCol.
      • or they relate to an %import directive elsewhere. But then it's impossible to properly define them:
        • either a) there is no %import for the Module at all ("prog8_interned_strings", and also the "root" module, the user "program")
        • or b) there's more than one %import for it, which is the general case because a module can be %imported from more than one other module, hence not uniquely definable.
  • name: String
    • this is pretty much just the sources / position's file name without .p8 extension, thus same problems as these
    • it is currently used to detect if a Module was already %imported by some other module. Since it's only the file name, this means that you can't have different modules of the same name from different locations (and of course no user module in a file that happens to be named "prog8_interned_strings.p8")
  • Finally isLibrary: Boolean
    • obviously used by the optimizer for dead code removal (in particular: NOT removing anything if isLibrary == true)
    • maybe also used for something else?
    • how would the exact meaning of this be defined?
      • could it be implemented as intended simply by source.toString().contains("prog8lib")? But then again what about a folder of that name in -libdirs?
      • or iff it came from resources? But then what about tests (where we don't have resources or a jar)?

Faulty codegen for memory access through non-zeropage ptr var

  • Prog8 version: 6.4
  • Command line: java -jar prog8compiler-6.4-all.jar test.p8 or with -noopt
  • Source code:
    Not so easily reproduced (see below), but here's the (a) problematic line:
      pokew(non_zp_ptr_var + CONST_OFFSET, some_value)
    
  • Expected:
    Assembly code to be generated that
    • either first calculates non_zp_ptr_var + CONST_OFFSET, stores the sum somewhere in zeropage, eg P8ZP_SCRATCH_W1 and then
          lda some_value
          ldy #0
          sta (P8ZP_SCRATCH_W1),y
          lda some_value+1
          iny
          sta (P8ZP_SCRATCH_W1),y
      
    • or - if CONST_OFFSET is small enough (ie. a byte) - stores just non_zp_ptr_var in zeropage (say, P8ZP_SCRATCH_W1), loads the CONST_OFFSET into Y and then
          lda some_value
          ldy #CONST_OFFSET
          sta (P8ZP_SCRATCH_W1),y
          lda some_value+1
          iny
          sta (P8ZP_SCRATCH_W1),y
      
  • Actual:
    ATTENTION: not always, only under certain conditions - see below
    non_zp_ptr_var is used directly:
          lda some_value
          ldy  #CONST_OFFSET
          sta  (non_zp_ptr_var),y ; <<<<<<<<<
          lda some_value+1
          iny
          sta  (non_zp_ptr_var),y ; <<<<<<<<<
    
    Since this addressing mode, indirect zeropage indexed, can only be used with zeropage addresses, tass64 then complains:
    .\test.asm:4807:8: error: not a direct page address address '($1439),y'
          sta  (non_zp_ptr_var),y
                ^
    
  • Remarks:
    • The actual source with which I encountered the problem consists of several p8 modules and is rather large, which seems to be part of the problem. I can't post it here in entirety.
    • I was able to hunt down the codegen for pokew, but that may well be just one instance.
    • Obviously, if non_zp_ptr_var actually were a zeropage var, then the actually generated code would be fine. So: one necessary condition is that the compiler runs out of zeropage locations to put local variables.
    • This allocation strategy is a thing of itself that could be improved. But first the compiler must be made to emit valid assembly even in this case.
    • A second condition seems to be that for some reason the compiler did not resort to first copying to P8ZP_SCRATCH_W1 (or P8ZP_SCRATCH_W2 which exists as well)
    • I have found that right before the problematic line there is another, similar one, which got translated correctly using P8ZP_SCRATCH_W2, as shown in "Expected". So my guess is that the compiler "thought" it ran out of scratches, so to speak.
    • There is a workaround for pokew - maybe not the only instance, as said - in Prog8, no asm:
          @(non_zp_ptr_var + CONST_OFFSET) = lsb(some_value)
          @(non_zp_ptr_var + CONST_OFFSET + 1) = msb(some_value)
      

problem with labels in asm code

Referencing labels is problematic because of the preceding underscore in the generated code. Should we just remove that prefix?

This fails to assemble, because 64tass can't find the symbol.

%import textio

main {
    str myBar = "main.bar"

foo_bar:
    %asminclude "compiler/test/fixtures/foo_bar.asm"   ; FIXME: should be accessible from inside start() but give assembler error

	sub start() {
	    txt.print(myBar)
	    txt.print(&foo_bar)
	    return
	}
}

See test fixture file asmIncludeFromSameFolder.p8

Prog8 sensitive to ending on newline

This is just a small annoyance and possibly just cause by my choice of editor (Emacs). The editor does not automatically add a newline at the last line when editing normally.

test.p8:9:1: missing EOL at ''

Attaching a minimal file that reproduce the error.

test.zip

implement mccarthy evaluation?

or and and currently don't short-circuit.

maybe we should make them short-circuit?
how can this be done in the expression code generation? It needs to be aware of the preceding logical operator's result and branch to the end if it detects short circuit possibility? Is this even worth the hassel. sounds like it will make compount logical expressions very slow on 6502 (unless ofcourse the operands are hard to calculate and a short circuit avoids a whole calculation...)

Using constants in assembler?

Hello :)

I got a short question today: can I use my own constants in an assembler code? I can see you use it in your libraries, for example in syslib.p8:

asmsub init_system()  {
    %asm {{
        lda  #$80
        sta  VERA_CTRL

However, when I try to use my constant, i.e:

    const ubyte SCREEN_BACKGROUND_COLOR = 1
    asmsub set_pallete_color(ubyte color @ A) {
        %asm {{
            lda #SCREEN_BACKGROUND_COLOR

it fails on assembling phase since the constant's name isn't replaced by value nor there is SCREEN_BACKGROUND_COLOR defined in *.asm file.

Bug: float[] initializer with range and no array size given

  • Prog8 version: 7.0
  • Command line: java -jar prog8compiler-7.0-all.jar floatArrayInitializerWithRange.p8
  • Source code:
    floatArrayInitializerWithRange.p8
    %option enable_floats
    main {
        sub start() {
            float[] cs = 1 to 42 ; values are computed at compile time
            cs[0] = 23 ; keep optimizer from removing it
        }
    } 
    
  • Expected:
    array size of 42 deduced from the given range and the ubytes from it converted to floats, i.e. turned into an explicit array initializer with 42 float constants
  • Actual:
Prog8 compiler v7.0 by Irmen de Jong ([email protected])
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html

Compiler target: c64. Parsing...
importing 'floatArrayInitializerWithRange'
importing 'syslib' (library)
importing 'math' (library)
importing 'prog8_lib' (library)
Processing for target c64...

* internal error *
Exception in thread "main" prog8.ast.base.FatalAstException: range expressions in vardecls should have been converted into array values during constFolding  VarDecl(name=cs, vartype=VAR, datatype=ARRAY_F, value=RangeExpr(from NumericLiteral(UBYTE:1), to NumericLiteral(UBYTE:42), step NumericLiteral(UBYTE:1), pos=[floatArrayInitializerWithRange.p8: line 4 col 22-29]), pos=[floatArrayInitializerWithRange.p8: line 4 col 9-29])
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:537)
        at prog8.ast.statements.VarDecl.accept(AstStatements.kt:228)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:39)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:253)
        at prog8.ast.statements.Subroutine.accept(AstStatements.kt:643)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:30)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:207)
        at prog8.ast.statements.Block.accept(AstStatements.kt:69)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:14)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:56)
        at prog8.ast.Module.accept(AstToplevel.kt:369)
        at prog8.ast.walk.IAstVisitor$DefaultImpls.visit(IAstVisitor.kt:10)
        at prog8.compiler.astprocessing.AstChecker.visit(AstChecker.kt:52)
        at prog8.compiler.astprocessing.AstExtensionsKt.checkValid(AstExtensions.kt:14)
        at prog8.compiler.CompilerKt.processAst(Compiler.kt:264)
        at prog8.compiler.CompilerKt.compileProgram(Compiler.kt:98)
        at prog8.CompilerMainKt.compileMain(CompilerMain.kt:115)
        at prog8.CompilerMainKt.main(CompilerMain.kt:21)
  • Discussion:

    • does NOT happen if array size is given explicitly
    • does NOT happen for other array types
    • the constFolding mentioned in the stack trace happens (or should happen?) in ConstantIdentifierReplacer.before(VarDecl, Node) if decl.dataType == DataType.FLOAT, around line 117 of compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt
    • in this branch of the where range initializers are not covered, whereas they are for the other array types. However: why is it then not also showing if array size is given explicitly?
  • Remarks:

    • again, found this while working on #53
    • there I have added tests for this bug
    • I have to change the relevant AST Node, RangeExpr now, but not in order to solve this bug (I don't know how) but rather because it depends on IStringEncoding, in particular its methods .toConstantIntegerRange and .size
    • I will do so in the most defensive way possible, but conflicts are guaranteed if this is worked on in parallel on another branch
    • apart from that the PR also contains considerable test infrastructure which should actually be used
    • so, if anyone feels inclined to work on this, then it would be best to do so based on what's in the PR, ie. on https://github.com/meisl/prog8/tree/testability_steps_1_2_3_again

continuous mode

add a 'continuous mode' where it watches the files it used to compile the program for changes, and automatically recompiles.
To avoid having to warm up the jvm/jit everytime

optimizer bug: inserts constant instead of variable

Hi,

there seems to be a bug in the optimizer when it comes to constant folding/propagation (wrt. strings/characters in this case).

  • prog8 version: 6.4
  • command: java -jar ../prog8compiler-6.4-all.jar -target cx16 p8-bug_str-opt.p8
  • source code:
%target cx16
%import textio
%zeropage basicsafe
%option no_sysinit

main {
	str   input = "1234"
	ubyte index = 0
	str   temp  = "?"

	sub start() {
		ubyte @zp ch
		
		repeat {
			ch = input[index]
			when ch {
				0 -> {
					break
				}
				else -> {
                                        temp[0] = ch ; <<<<<<<<<<<<<
					txt.print(temp) ; wrongly optimized to
					;      lda #$3f
					;      jsr txt.chrout

					; with -noopt it's correctly turned into
					;      ldy  #>temp
					;      ldy  #<temp
					;      jsr  txt.print
				}
			}
			index++
		}
		return
	}
}
  • expected assembly (properly optimized away the access to temp, see remarks below):
    	;	src line: p8-bug_str-opt.p8:21
	lda  ch
	sta  temp+0
	;	src line: p8-bug_str-opt.p8:22
	jsr  txt.chrout
  • actual assembly:
	;	src line: p8-bug_str-opt.p8:21
	lda  ch
	sta  temp+0
	;	src line: p8-bug_str-opt.p8:22
	lda  #$3f
	jsr  txt.chrout
  • Remarks:
    • With -noopt of course correct code is generated
    • What I'd "expected" as an optimization - if at all - is the elimination of the access to temp; constant folding/propagation however is not applicable here. But note: this depends on the string temp to be only one character long (so we could use txt.chrout rather than txt.print. This is by no means a simple "peephole" optimization, so better not try such "stunts" at all - at least at this stage.
    • I could provide the two .asm files for convenience if desired, but rather not here in the OP, as they are of course rather long.

get rid of pascal strings

the pascal-string type (with the length prefix byte) should be removed, so that the string type (where string ends with a 0-byte) remains.

This reduces the number of string types from 4 to 2, and avoids having to code two types of loops every time when we want to deal with a string.
While pascal strings could be faster or more flexible, the c-string type is actually used by several kernel routines in the C64 and having just a pascal string type will make them unusable

Extract data from variables

In Millfork you can extract the data from variables like this:

**code_start
word mydata = 258 ; that would be $0102 in hex.
byte look_lo = mydata.b0
byte look_hi = mydata.b1
**code_end

look_lo whould have the value 2
look_hi whould have 1

Is there a way to do that in Prog8?

asmbinary import issue in windows?

I did write about my problems with %asmbinary in the X16 forum, but I actually did find a workaround for that part after thinking about the problem a bit more.

I added an small array in from of the import and can use that to figure out the start address of the actual data. Very hacky though.

However, the actual import by 64tass fails.

%asmbinary "data.bin"

then fails with

.\screen_test.asm:40:10: warning: the file's real name is not './data.bin' [-Wportable]
.binary "./data.bin"
^

Seem like 64tass doesn't like the ./ prefix for path. I can assemble this fine if I just remove this and run 64tass myself.

Exception/Error thrown on various escape sequences in str literals, depending on encoding

  • Prog8 version: 6.4
  • Command line: java -jar prog8compiler-6.4-all.jar prog8_issue37.p8
  • Source code:
     	%import textio ; txt.*
     	main {
     		sub start() {
     			; ATTENTION: uncomment only one problematic line at a time!
     		
     			; Normal string literals, i.e. PETSCII encoding
     			; ---------------------------------------------
     			txt.print("\"")	; fine
     			txt.print("\n")	; fine
     			txt.print("\r")	; fine
     			; txt.print("\\")	; yields CharConversionException
     			; txt.print("xyz\\")	; yields prog8.compiler.AssemblyError
     		
     			; @-strings, i.e. translated into 
     			; the alternate character encoding (Screencodes/pokes)
     			; ----------------------------------------------------
     			txt.print(@"\"")	; fine
     			txt.print(@"\n")	; yields CharConversionException
     			; txt.print(@"xyz\n")	; yields prog8.compiler.AssemblyError
     			; txt.print(@"\r")	; yields CharConversionException
     			; txt.print(@"xyz\r")	; yields prog8.compiler.AssemblyError
     			; txt.print(@"\\")	; yields CharConversionException
     			; txt.print(@"\\")	; yields prog8.compiler.AssemblyError
     			
     			; there may be more...
     		}
     	}
    
  • Expected:
    • regular error message, including src location in user program
    • also: the problematic character should be shown in escaped form, eg: "\n" rather than an actual new line in the output
  • Actual: exception thrown
    • either CharConversionException in the case of one-letter only strings (eg @"\\", "\\")
    • or prog8.compiler.AssemblyError in the case of longer strings (eg @"xyz\\", "xyz\\")
    • ATTENTION: uncomment only one problematic line at a time!
      You will otherwise get very quickly confused which error is caused by which line (reason: happen in completely different phases).
    • shown below are the faults for the @"\n" and @"xyz\n" cases; the others are similar
      	* internal error *
      	Exception in thread "main" java.io.CharConversionException: no lowerScreencode character for '
      	' (10)
      			at prog8.compiler.target.c64.Petscii.encodeScreencode(Petscii.kt:1088)
      			at prog8.compiler.target.Cx16Target.encodeString(ICompilationTarget.kt:92)
      			at prog8.optimizer.StatementOptimizer.after(StatementOptimizer.kt:103)
      			at prog8.ast.walk.AstWalker.visit(AstWalker.kt:247)
      			at prog8.ast.statements.FunctionCallStatement.accept(AstStatements.kt:547)
      			at prog8.ast.walk.AstWalker.visit(AstWalker.kt:232)
      			at prog8.ast.statements.Subroutine.accept(AstStatements.kt:670)
      			at prog8.ast.walk.AstWalker.visit(AstWalker.kt:218)
      			at prog8.ast.statements.Block.accept(AstStatements.kt:67)
      			at prog8.ast.walk.AstWalker.visit(AstWalker.kt:194)
      			at prog8.ast.Module.accept(AstToplevel.kt:366)
      			at prog8.ast.walk.AstWalker.visit(AstWalker.kt:188)
      			at prog8.optimizer.ExtensionsKt.optimizeStatements(Extensions.kt:49)
      			at prog8.compiler.CompilerKt.optimizeAst(Compiler.kt:270)
      			at prog8.compiler.CompilerKt.compileProgram(Compiler.kt:99)
      			at prog8.CompilerMainKt.compileMain(CompilerMain.kt:106)
      			at prog8.CompilerMainKt.main(CompilerMain.kt:23)
      
      	* internal error *
      	Exception in thread "main" prog8.compiler.AssemblyError: There was a problem converting a string to the target machine's char encoding: no lowerScreencode character for '
      	' (10)
      			at prog8.compiler.target.cpu6502.codegen.AsmGen.encode(AsmGen.kt:254)
      			at prog8.compiler.target.cpu6502.codegen.AsmGen.vardecls2asm(AsmGen.kt:393)
      			at prog8.compiler.target.cpu6502.codegen.AsmGen.block2asm(AsmGen.kt:198)
      			at prog8.compiler.target.cpu6502.codegen.AsmGen.compileToAssembly(AsmGen.kt:62)
      			at prog8.compiler.CompilerKt.writeAssembly(Compiler.kt:312)
      			at prog8.compiler.CompilerKt.compileProgram(Compiler.kt:105)
      			at prog8.CompilerMainKt.compileMain(CompilerMain.kt:106)
      			at prog8.CompilerMainKt.main(CompilerMain.kt:23)
      
  • Remarks:
    • -noopt irrelevant for the prog8.compiler.AssemblyError
    • Using single quotes (character literals) - txt.print(@'\n'), txt.print(@'\r'), txt.print(@'\\') - does yield a proper syntax error, even though characters aren't properly escaped there either
    • I haven't tried everything, so there might be more problematic characters

allow str in subroutine signature

Currently you can use str only in asmsub signature, for regular subroutines the compiler gives an error about that reference types should be an uword.

examples/test.p8:10:0: ERROR Pass-by-reference types (str, array) cannot occur as a parameter type directly. Instead, use an uword to receive their address, or access the variable from the outer scope directly.

This should be fixed so that str can be used in signature .
(The issue is related to the way subroutine params are treated as local variables.)

Ideally we do the same for array types but that's a different issue, one that is difficult to solve because the compiler now treats array vars as a direct (name) reference to the array in memory. Passing different arrays in the place of an array var can't be done right now.

bug: crash in codegen for uword/ubyte function call argument type mismatch

the following code crashes the compiler:

        ubyte[] ubs = [1]
        txt.print_uw(ubs[0])

expected result: compiles fine, prints 1 (it should successfully typecast the argument from ubyte to uword)

observed result:
compiler crashes with require() not met (the requirement is that it expects a byte/ubyte datatype):

* internal error *
Exception in thread "main" java.lang.IllegalArgumentException: Failed requirement.
	at prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen.assignRegisterByte$compiler(AssignmentAsmGen.kt:1369)
	at prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen.translateNormalAssignment(AssignmentAsmGen.kt:75)
	at prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen.assignExpressionToRegister$compiler(AssignmentAsmGen.kt:2162)
	at prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen.assignTypeCastedValue(AssignmentAsmGen.kt:409)
	at prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen.translateNormalAssignment(AssignmentAsmGen.kt:155)
	at prog8.compiler.target.cpu6502.codegen.AsmGen.translateNormalAssignment$compiler(AsmGen.kt:850)
	at prog8.compiler.target.cpu6502.codegen.FunctionCallAsmGen.argumentViaRegister(FunctionCallAsmGen.kt:341)
	at prog8.compiler.target.cpu6502.codegen.FunctionCallAsmGen.translateFunctionCall$compiler(FunctionCallAsmGen.kt:70)
....

The AST passed to the codegenerator is fine btw, it contains the cast:
txt.print_uw((ubs[0] as uword) )

arrays could be parallel in memory to be able to use 256 entries for words/floats as well

Just as the evaluation stack, store the bytes in 'separate' arrays in memory.

This will break the few places where we now depend on word arrays to be sequential in memory so that needs to go (most notably the SPXYW array for the sprite x/y coordinate pairs) or we need to support both array layout types.

Changing this also requires rewriting all the code that now deals with arrays and assumes the values are sequential in memory....

is -target on the command-line mandatory?

Should this fail if you do NOT use -target cx16 ?

PS D:\CommanderX16\Prog8> & 'C:\Program Files\AdoptOpenJDK\jre-11.0.11.9-hotspot\bin\java.exe' -jar D:\CommanderX16\Prog8\prog8compiler-7.0-all.jar .\cx16\amiga.p8

Prog8 compiler v7.0 by Irmen de Jong ([email protected])
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html

Compiler target: c64. Parsing...
importing 'amiga' (from 'cx16\amiga.p8')
importing 'textio' (library)
importing 'syslib' (library)
importing 'conv' (library)
โ†[91m[cx16\amiga.p8: line 3 col 1-16] Import: no module source file 'palette.p8' found (I've looked in: embedded libs and [cx16, D:\CommanderX16\Prog8\prog8lib])

Works fine if I add -target cx16 to the command-line, but the source-code already have %target cx16 ?

PS it does this on the examples files for x16

On making an AST

[
Here's a little write-up of how I currently understand things to work in compilerAst, parts of which may be of use for a future guide on how to get going/engaged with development of the compiler.
In addition I'm trying to evaluate the pros and cons of the current approach and offer some ideas re possible other approaches.

@irmen: this is NOT URGENT AT ALL, rather a recap for myself and some outlook. Up (maybe) only after "the plan" (CompilerDevelopment.md).
]


General organization (prep/basic, skip if you're already in the know)

  • The Prog8 compiler is written in Kotlin. It uses ANTLR4 as its parser generator.
  • The next best thing to Kotlin that ANTLR can generate is Java. All of that is under parser/.
  • We don't want to write any Java ourselves, much less tests in Java.
  • Hence there's compilerAst/, which is to provide an interface to this generated thing - purely in Kotlin. Here's also where we put tests of the grammar (via the Kotlin parser), and of the AST nodes.
  • The parser in Java generated by ANTLR produces a parse tree, very closely reflecting the grammar.
  • The other purpose of compilerAst is to turn this parse tree into an AST (Abstract Syntax Tree), which
    • consists only of (Kotlin) prog8.parser.ast.Nodes, no more (Java) prog8.parser.Prog8ANTLRParser.ParserRuleContexts.
    • is somewhat more abstract, meaning: leaving out / summarizing unnecessary detail about the actual parse [TODO: example].
  • The unit of work, as seen by the parser itself, is a Prog8 module: a piece of Prog8 source text which on the top level has directives and blocks, the latter of which then contain variable declarations, subroutines, ...
  • The parser itself does NOT do %import resolution, it simply puts such directives (similar: %asminclude, %asmbinary) in the AST as is.

Current approach

Aside from error handling and possibly recovery, and looking only at the parse tree -> AST conversion:

  • Happens in Antlr2Kotlin.kt, via extension methods .toAst(...) on ParserRuleContext subclasses.
  • Involved as well: ext. method .toPosition() (also in Antlr2Kotlin.kt).
  • This works recursively, started by calling ModuleContext.toPosition(..), which is the only such ext. method visible from the outside.
  • Due to the (current) nature of almost all AST Node constructors, child nodes have to be instantiated before the parent node can be.

Pros

  • no subclassing of Java classes needed
  • implicit this in ext. methods (here: the ParserRuleContext instance), hence no need to write it (or "it"...)
  • (maybe) feels "natural", particularly the explicit recursion

Cons

  • Because of ext. methods, any global state about the current conversion can be shared only via parameter passing
  • There is some such global state necessary:
    • IStringEncoding (atm, but hopefully soon to go, see #50)
    • the current Prog8 module, aka unit of work. Of that at least the origin (file system, embedded library/resources, plain String) is needed, particularly for equipping every Node with a proper Position (-> ext. method .toPosition())
  • Therefore: if we want to change what's shared global state, then that means going over each and every ext. method's declaration as well as invocation, without much help from the IDE.
  • Unfortunately, due to the recursive, bottom-up nature, the actual Module instance is built at the very last. Likewise for any other non-leaf Node...
  • Similarly, every Nodes .parent has to be lateinit; and there's Node.linkParents(...) (although this linking might be possible without it, even with the current approach)
  • On the other hand, a Nodes .position is (atm) NOT lateinit, leading to a variety of weird and intricate problems (the Positions .file being the cause).

Alternative approaches

First, let's get some "givens" out of the way:

  • I am assuming that we'll keep the general approach of not using the Java ParserRuleContext instances from the ANTLR-generated parser for anything other than just turning them into our own Kotlin objects.
    Even though this means a good deal of simple copying-over, I, personally, am fine with that. Be it only for the unbearably ugly names: XyzContext..!
  • By default, the generated parser collects all children (parse-tree!) nodes - ie. including EOL tokens, commas, etc. - in a children list on each ParserRuleContext, but that can be switched off. Atm, it is switched on, but we don't use any of that (I think). It's probably not so big an impact, but still work to do for the garbage collector.
  • ANTLR optionally does provide a) a listener interface (= enterXyzContext/exitXyzContext "events") and/or b) a visitor interface (= visitXyzContext(...) callbacks). However, as alluded to in parentheses, neither of them uses double-dispatch, meaning you're stuck with those all-to-chatty names. Currently, we don't use them, and neither of these options are enabled.
  • The generated parser can be made to do a lot more, only by editing the grammar. That goes from collecting results from subrules into lists (trivial code, way simpler than Java or Kotlin) up to semantic predicates and pre/post code blocks in the target language (= Java). The latter is definitely too much, but we could profit from the former. Currently, we're using practically zero.

Finally, actual ideas:


[
Remark: from here on it's pretty much "TODO"/rough sketch. Sorry for that, but it's late and a lot already. I'll edit and amend this OP later, possibly incorporating comments, if any.
]


During conversion, it would be nice to have the sharing of state...

  • ...not through parameters
  • ...but rather simpler, as common closed-over scope (usually an "object" in OO, but also in the traditional sense)
  • Again: this should make a lot - if not all - of those "when-to-initialize-what-but-dont-have-it-yet" problems go away (TODO: proof...)
  • Both, the Listener and Visitor pattern provide for that. Of course in addition to - just like ext. methods - the ability to "attach on after the fact".
  • Unfortunately neither of them are provided by ANTLR in an acceptable form, so we have to make them ourselves.
  • Well, why not? Has been done before for Kotlin AST nodes: IAstVisitor, AstWalker (even though somewhat "unusual").
  • Have actually tried out both of the below with Prog8Parser, so not purely theoretical.

Alternative 1: (self-made) parse tree visitor (client driven, "pull-model")

  • too much boiler-plate as it stands (even though once written, much less so for clients)
  • benefit over listener would be that the client can actively steer the traversal
  • but: that's actually not needed here (in entirety)
  • and: additional burden on client code: must call super.visit(..)
  • since the normal case is to visit the children, that means more client boiler-plate in the normal case

TODO: example client code

Alternative 2: (self-made) parse listener (event-driven, "push-model")

  • still a lot repetitive code to be written, but about half compared to visitor (for the client: even less)
  • plus: can use Kotlin's type system to help us when introducing or removing AST Node subtypes
  • still possible to e.g. request to "skip children" from client
  • simpler client interface: you don't do anything in the normal case (see above), but only when you do skip children
  • easier to comprehend for readers new to the code base (if done right)

TODO: example client code

add pointer-dereference logic @( pointer )

we have & to make a pointer to a value,
we need @ (pointer) to be able to dereference it again to get the actual value once more.

Problem: we don't have a true pointer type so we can't dereference pointers (UWORDS) without explicitly telling the compiler what type it is we expect.... something like:

@ (pointer) as str
@ (pointer) as ubyte[3]

should probably be used (where pointer is a UWORD)

note: @ ( &variable ) is ok already because it is reduced in the AST to only the variable

Confusing error when assigning illegal value in array

Using somthing like this
ubyte[] ar = [-2]
gives
error.p8:9:18: ERROR cannot type cast to string or array type
which is a bit confusing since I assume it's assigning a byte to a ubyte arrray that fails.

Note that I did have this somewhere like
ubyte[] ar = [ ..., CONST-2, ... ]
which made a bit hard to figure out what was wrong.

-watch option does not work on MacOS

Hi Irmen!

When trying to use the option -watch on MacOS (Big Sur v 11.0.1), i.e:

java -jar prog8compiler-5.0-all.jar -target cx16 -watch test.p8

it gives me a result:

Imported files (now watching:)
  test.p8
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.nio.file.Path.register(java.nio.file.WatchService, java.nio.file.WatchEvent$Kind[])" because the return value of "java.nio.file.Path.getParent()" is null
	at prog8.CompilerMainKt.compileMain(CompilerMain.kt:71)
	at prog8.CompilerMainKt.main(CompilerMain.kt:21)

Java version:

java 15 2020-09-15
Java(TM) SE Runtime Environment (build 15+36-1562)
Java HotSpot(TM) 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)

Ref indexing not allowed as initializer value

This may be fixed in the latest source but I thought I should report this just in case. The following doesn't work

main {
  ubyte[] bytearr = [0,1,2,3,4]
  
  sub start() {
    uword ref = &bytearr
    ubyte get = ref[0]
  }
}

I get

* internal error *
Exception in thread "main" java.lang.IllegalArgumentException: Failed requirement.
        at prog8.ast.statements.VarDecl.replaceChildNode(AstStatements.kt:235)
        at prog8.ast.walk.IAstModification$ReplaceNode.perform(AstWalker.kt:62)
        at prog8.ast.walk.AstWalker.applyModifications(AstWalker.kt:178)
        at prog8.compiler.astprocessing.AstExtensionsKt.reorderStatements(AstExtensions.kt:26)
        at prog8.compiler.CompilerKt.processAst(Compiler.kt:252)
        at prog8.compiler.CompilerKt.compileProgram(Compiler.kt:97)
        at prog8.CompilerMainKt.compileMain(CompilerMain.kt:106)
        at prog8.CompilerMainKt.main(CompilerMain.kt:23)

I've attached a small test program for testing

test.zip

Variables on stack limit?

Hello again :)

Is there any limit of variables I can declare?

Look at this code snippet:

-target cx16

        ubyte i
        for i in 0 to BOARD_FIELDS - 1 {

            if (board_fields[i-5] == 4) {
                txt.plot(30, 12)
            }   

It compiles to:

 ;if (board_fields[i-5] == 4) starts here:
        lda  i
	sta  prog8_autovar_index_1835841364
	sec
	sbc  #5
	sta  prog8_autovar_index_1835841364
	ldy  prog8_autovar_index_1835841364
	lda  board_fields,y

;this is important:
	sta  P8ESTACK_LO,x
	dex
	lda  #4
	sta  P8ESTACK_LO,x
	dex
	jsr  prog8_lib.equal_b ;this comparison sometimes fails
	inx
	lda  P8ESTACK_LO,x
	beq  _prog8_label_51_if_end 
	ldy  #$1e
	lda  #12
	jsr  txt.plot

It works for a while until it stops working :) The problem is with prog8_lib.equal_b procedure and X-register. I have debugged code and found that X-register is equal to $00 what causes problem:

;X = $00
;this is important:
    sta $0400,x 
    dex ;X = $ff
    lda #04
    sta $0400,x
    dex ;X = $fe
    jsr prog8_lib.equal_b
    inx
    lda $0400,x
    beq _prog8_label_51_if_end


prog8_lib.equal_b:
    lda $0402,x ;X = $fe, $402+$FE=$500 WRONG!
    cmp $0401,x 

So it should compare $0400 to $04ff - instead it compares $0500 ($402+$FE) to $04ff ($401+$fe).

I found a solution, I can change:

if (board_fields[i-5] == 4) {

into:

ubyte val = board_fields[i-5]
if (val == 4) {

And it's even faster because it doesn't use prog8_lib.equal_b anymore but I would like to know why the problem exists in my original case.

inline sub that returns a value not handled correctly

for instance

inline sub color_word(ubyte ix) -> uword {
    uword color = mkword(reds[ix], (greens[ix] << 4) | blues[ix] )
    return color
}

this behaves wrong. When it is not inlined it's ok

Also when you omit the return, no error or warning is issued

Add ASCII encoding for cx16's "ISO mode"?

Rationale

Prog8 currently (v6.4) supports two character encodings: PETSCII (eg "foo") and screencodes/pokes (eg @"foo").
Now there's also Commander X16's "ISO mode".
However, there's no easy way in Prog8 to use strings or characters (literals) in this encoding.

Proposal

Add some kind of support for switching to/from this and other encodings to the language.
The exact syntax, semantics and mechanism remain to be discussed.

Workarounds

  1. Use \xHH escapes inside strings, these are copied verbatim without translation.
    • Not really a lot of fun...
  2. Let 64tass, Prog8's assembler, do the work:
    • It has the directives .enc, .cdef and .edef which let you define a custom encoding
    • See example below for how to use them
  3. Maybe others I don't know of.

Discussion

  • The technique outlined above and demonstrated below could also be employed by Prog8, even right now for the existing encodings, leading to code reduction
  • Instead of emitting a bunch of hex literals to the .asm file - as is done atm - the literals from the p8 source could be pasted in there pretty much as-is
  • "Pretty much" meaning: apart from the escape \" which would have to be replaced by eg \{qq} (see demo code)
  • As for which language constructs to provide:
    • There's already the @"string" notation for screencodes/pokes - which is a bit unfortunate, as "@" probably rather hints to ASCII...
    • The "ISO mode" is only available on the X16, not the C64. So the compiler would allow the ISO/ASCII encoding only with %target cx16. Or maybe better not as restrictive, and just warn about it.
    • The @ is also used for indicating where parameters go in asmsubs - something completely different.
    • A better (and more regular) way might be via
      • an %option encoding_xyz, setting the default for the whole src file (of course not imported ones)
      • and/or some modifier or built-in function to set the encoding for individual string literals (questionable)
      • in any case: the (syntactical) mechanism should be a) rather explicit (ie stating the actual name of the encoding), b) regular and c) extensible
      • none of the above three are met by the current @ syntax, IMHO

Of course these are just a few thoughts of mine on the subject - looking forward to anybody else's :)

Illustration

I've written a little demo, with explanations in comments. But first, here's how it looks like:
prog8_issue38

Code

; x16emu -prg prog8_issue38.prg -run -gif prog8_issue38.gif,wait

%target cx16
%import textio ; txt.*
%import syslib ; cx16.*, sys.*
%zeropage basicsafe
%option no_sysinit

main {
	; Define the encoding at top of block
	; NOT inside a sub!
	%asm {{
			.enc	"ascii"		; define an encoding named ascii
			.cdef	" ~", 32	; identity for printable characters (from " " to "~")
			.edef	"\r", 13  	; define escape sequence for CR carriage return
			.edef	"\n", 13  	; define escape sequence for LF line feed, map it to CR (original: $0a)
			.edef   "\\", $5c	; define escape sequence for backslash (cannot be used in P8's PETSCII enc)
			.edef	"\t", [32, 32, 32, 32]	; TAB (original $09) -> four spaces
			.edef	"\{clr}", 147	; we can even define nice custom control sequences
			.edef	"\{qq}", $22	; or this: double quote (cannot define \")
	}}
	
	; String literals must also be defined via %asm; also in block
	%asm {{
		ascii_strings	.proc ; create a 64tass scope s.t. we can give them the same names as in p8
			.enc "ascii" ; not actually necessary since directly following the definition
		mytext
			.text "This is ASCII: lower & UPPER\nsecond\tline\twith\ttabs\r"
			.text "backslash in double quotes: \{qq}\\\{qq}"
			.byte 0 ; null-terminated for txt.print
			.pend
	}}
	
	; We can still use normal PETSCII by switching back via .enc "none":
	%asm {{
		petscii_strings	.proc
			.enc "none"
		myothertext
			.text "we are petscii (all upper case)"
			.byte 0 ; null-terminated for txt.print
			.pend
	}}
	
	
	; inline subs for convenient switching between modes
	inline sub iso_on() {
		txt.chrout($0f)
	}
	inline sub iso_off() {
		txt.chrout($8f)
	}
	
	sub start() {
		void cx16.screen_set_mode(0) ; switch to 40x30 text mode
		iso_on(); switch to ISO-8859-15 encoding ("ISO mode")
		
		; We cannot (yet?) use iso-/ascii-encoded literals in Prog8
		; because they're always a) translated and b) put "some place we don't know" (see issue #31)
		str garbled = "this is garbled: lower & UPPER\nsecond line\rdouble quote: \""
		txt.print(garbled)
		txt.nl()
		txt.nl()
		txt.nl()
		
		; Neither can we use escapes \\ (because there is no petscii equiv) nor \t (missing?)
		; ...not to speak of our custom ones like \{clr} (of course).
		; So each of the following would yield Prog8 syntax errors:
		;str backslash = "\\"
		;str tab = "\t"
		;str clr =  "\{clr}"

		; Workaround:
		;   1. put actual ASCII-encoded text in block (above) via %asm
		;   2. declare Prog8 uword to point to actual text
		;   3. with %asm: initialize the pointer accordingly
		; That's basically what the compiler would do as well.
		uword mytext
		%asm {{
			lda #<ascii_strings.mytext
			sta mytext
			lda #>ascii_strings.mytext
			sta mytext+1
		}}
		txt.print(mytext)
		txt.nl()
		txt.nl()
		txt.nl()
		
		uword myothertext
		%asm {{
			lda #<petscii_strings.myothertext
			sta myothertext
			lda #>petscii_strings.myothertext
			sta myothertext+1
		}}
		txt.print(myothertext)
		txt.nl()
		txt.nl()
		txt.nl()
		
		sys.wait(60) ; wait a second
		; make single screenshot
		%asm {{
			lda #1
			sta $9FB5
		}}
	}
}

Would it be possible to add some way to add platform compile clause (like preprocessor directives)

I.e I'm working on some code that is almost platform independent (so far). I just have 1 line of CX16 specific code I need to remove to get my code to compile on both platforms. Basically I'm asking for something like this

#ifdef TARGET_C64
  void cx16.screen_set_mode(0)
#endif

If I ever consider adding sound this might possible be done with a similar solution just around the %import

#ifdef TARGET_C64
  %import c64_sound
#endif
#ifdef TARGET_CX16
  %import cx16_sound
#endif

or perhaps some target specific flag like this

%import %target%_sound

might be possible instead

Bug: file name missing in err msgs for imported files

  • Prog8 version: 7.0 beta2, NOT 6.4, goes away with PR #45 (but not properly fixed there; see discussion below)
  • Command line: java -jar prog8compiler-7.0-BETA2-all.jar issue46_main.p8
  • Source code:
    1. issue46_main.p8:
        %import issue46_imported
        main {
            sub start() {
            }
        }
      
      
    2. issue46_imported.p8:
        foo {
            str str ; parse error (non-lexical) -> BUG
            str bar = "missing closing quotes (lexical error) -> NO bug
        } ; incidentally, the previous lexical error yields another non-lexical one -> BUG
      
      
  • Expected:
    All error messages should state the proper file name, as in v6.4:
Prog8 compiler v6.4 by Irmen de Jong ([email protected])
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html

Compiler target: c64. Parsing...
importing 'issue46_main'
importing 'issue46_imported' (from '.\issue46_imported.p8')
.\issue46_imported.p8:3:11: token recognition error at: '"missing closing quotes (lexical error) -> no bug\r'
.\issue46_imported.p8:2:5: no viable alternative at input 'strstr'
.\issue46_imported.p8:3:61: mismatched input '\n' expecting {'[', '+', '-', '~', 'not', '(', 'true', 'false', NAME, DEC_INTEGER, HEX_INTEGER, BIN_INTEGER, '&', '@', FLOAT_NUMBER, STRING, SINGLECHAR}
There are 3 errors in 'issue46_imported'.
  • Actual:
    Two of the three error messages state "<unknown>" instead of the file name:
Prog8 compiler v7.0-BETA2 by Irmen de Jong ([email protected])
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html

Compiler target: c64. Parsing...
importing 'issue46_main'
importing 'issue46_imported' (from '.\issue46_imported.p8')
.\issue46_imported.p8:3:11: token recognition error at: '"missing closing quotes (lexical error) -> no bug\n'
<unknown>:2:5: no viable alternative at input 'strstr'
<unknown>:4:0: mismatched input '}' expecting {'[', '+', '-', '~', 'not', '(', 'true', 'false', NAME, DEC_INTEGER, HEX_INTEGER, BIN_INTEGER, '&', '@', FLOAT_NUMBER, STRING, SINGLECHAR}
There are 3 errors in 'issue46_imported'.
  • Discussion
    • While working on #45 I was able to determine the exact reason for this, and incidentally this PR makes it go away.
    • However, a proper fix requires more changes, and - more importantly - tests. I'd volunteer for that, but would need your help, @irmen.
    • So, what's going on?
      • First, let's note that one of the error messages still contains the proper file name. The difference is this: lexical error (coming from the lexer -> no bug) versus non-lexical (coming from the parser -> bug).
      • The bug was introduced in b4700af, not exactly for but related to #40
      • The crucial change there (in compilerAst/src/prog8/parser/Moduleparsing.kt) wrt to the bug is the first argument to importModule; before: CharStreams.fromPath(filePath) (effectively) and after: CharStreams.fromString(content). content is read from filePath and modified. The problem is that CharStreams (from antlr) remembers the file name info when called with .fromPath, but cannot do so when called with .fromString.
      • Even though the filePath info was still passed to importModule as additional argument, this then goes on and registers a custom ErrorListener, which in turn relies on recognizer.inputStream.sourceName for reporting errors - but only so for non-lexical errors. For lexical errors it uses recognizer.modulePath, which continued to work.
      • #45 again uses CharStreams.fromPath(filePath), but obviously that's only removing the symptom, not the real cause.
    • IMHO, this is an urgent call for tests now, not least in order to prevent a regression.
    • I tried, but unfortunately I was unable to create some. Reasons: a) test fixtures (files) are needed (new thing in this project), plus b) getting the code under test to execute - and at best only that - isn't possible due to visibility issues and rather long dependency chains. I'm not brave enough for the necessary refactorings, and there are no other tests to guard me.
    • But: I would really like to work on fixing this (incl. writing tests). I'd just need help/advice.
  • Further notes
    • Interesting: the errors are not reported in order, 3:11 comes before 2:5...
    • Note the 2nd msg, @ 2:5 (first in source): "...at input 'strstr'" - white space in src citation is missing
    • The main file, issue46_main.p8 is reported as being "imported" - minor but awkward

Allocating memory block

Hi Irmen,

Is it possible to allocate a memory block bigger than 256 bytes?

Sure, I can always make a bunch of arrays:

ubyte[256] memory_block0
ubyte[256] memory_block1
ubyte[256] memory_block2
ubyte[256] memory_block3

However, it's not an elegant solution and I'm not sure if the compiler puts them one after another in memory. Does it?

fix loop label generation

see examples/looplabelproblem.p8

due to lack of proper label generation / label naming standardization, the above code generates invalid assembly due to invalid label naming.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.