Compare commits

...

37 Commits

Author SHA1 Message Date
Irmen de Jong
747ee32e81 updated tehtriz screenshot 2019-03-10 20:22:33 +01:00
Irmen de Jong
75fadaa24f added holding area 2019-03-10 20:17:58 +01:00
Irmen de Jong
e4ea1f1014 tweaked controls, score, sounds 2019-03-10 19:24:11 +01:00
Irmen de Jong
cd2c4e13da cleanups 2019-03-10 18:30:01 +01:00
Irmen de Jong
f5ba072294 removed str_p and str_ps pascal string types, fixes #10 2019-03-10 18:11:26 +01:00
Irmen de Jong
87d6312a37 tetriz screen 2019-03-10 05:38:14 +01:00
Irmen de Jong
3af7d4c930 tweaked tetriz speedup 2019-03-10 05:24:07 +01:00
Irmen de Jong
0fc3071a21 updated examples 2019-03-10 04:36:48 +01:00
Irmen de Jong
7f36d08acc simple sound effects 2019-03-10 04:22:02 +01:00
Irmen de Jong
b040e5ddad speedup at every 10 lines 2019-03-10 03:59:58 +01:00
Irmen de Jong
f36ce5e0ee line clearing 2019-03-10 03:21:14 +01:00
Irmen de Jong
ffbdac7e9a don't draw 8 pieces instead of 7. Implemented simple wall kick when rotating. 2019-03-09 00:42:56 +01:00
Irmen de Jong
f2b03342ac tehtriz joystick input 2019-03-07 23:29:23 +01:00
Irmen de Jong
52ff61470b fixed rotation of I piece to conform to current tetris guidelines 2019-03-07 22:41:59 +01:00
Irmen de Jong
28277469b6 fixed a compiler crash because with noopt, strings weren't put on the heap 2019-03-07 22:04:00 +01:00
Irmen de Jong
aa98104d54 doc 2019-03-07 02:46:24 +01:00
Irmen de Jong
9be70bcbe7 tetris stuff 2019-03-07 02:28:01 +01:00
Irmen de Jong
3a6fae4447 simplified tehtris collision check a bit 2019-03-07 01:46:38 +01:00
Irmen de Jong
06f0984fa1 docs about irq handlers 2019-03-07 01:02:11 +01:00
Irmen de Jong
77dc35dc6a added read_flags() function, uword2bcd routine no longer enables irq again if it wasn't enabled before calling it. 2019-03-05 23:10:00 +01:00
Irmen de Jong
ed43f7cd9b grade: also include parser in fatJar to make it complete, and exclude the huge ic4j library that isn't used 2019-03-02 22:41:21 +01:00
Irmen de Jong
32405a1637 Merge pull request #7 from fboldog/add-antlr4-runtime
possible solution for antlr4-runtime in the fatjar
2019-03-02 22:39:08 +01:00
Ferenc Boldog
43cab3f247 possible solution for antlr4-runtime in the fatjar 2019-02-28 15:02:10 +01:00
Irmen de Jong
5ea2f2d4db docs about @zp tag 2019-02-28 00:13:59 +01:00
Irmen de Jong
b8ae808b65 compiler was confused about resulting expression type 2019-02-27 23:58:08 +01:00
Irmen de Jong
96ecbc9fe4 fixed too eager expression operand type adjustment 2019-02-27 23:07:12 +01:00
Irmen de Jong
588133d418 fixed primes.p8 2019-02-25 01:37:05 +01:00
Irmen de Jong
2f1249489b datatype cleanups 2019-02-25 01:22:56 +01:00
Irmen de Jong
95f7c9bad0 asmsubroutines now also return their value on the evalstack (this fixes their use in expressions) 2019-02-24 18:54:25 +01:00
Irmen de Jong
8811d2f7c5 fixed a compiler ast crash and added -noopt command line flag 2019-02-24 16:56:38 +01:00
Irmen de Jong
d6ca1e6a12 fixed len() returntype 2019-02-24 15:25:46 +01:00
Irmen de Jong
b0ad66bd04 added missing bitwise and/or/xor asm code 2019-02-23 23:06:46 +01:00
Irmen de Jong
c1d2b4601b fixed/added logical and/or/xor 2019-02-23 22:13:42 +01:00
Irmen de Jong
c265625ed1 gradle 2019-02-23 13:17:42 +01:00
Irmen de Jong
52352d9d04 added c64scr.getchr/getclr 2019-02-21 01:31:33 +01:00
Irmen de Jong
cc5898d010 more tetriz work 2019-02-15 01:53:20 +01:00
Irmen de Jong
8684f0c8f5 clean exit mandelbrot 2019-02-12 23:24:47 +01:00
54 changed files with 2053 additions and 1289 deletions

View File

@@ -109,3 +109,6 @@ Another example (cube3d-sprites.p8) draws the vertices of a rotating 3d cube:
![cube3d screen](docs/source/_static/cube3d.png) ![cube3d screen](docs/source/_static/cube3d.png)
If you want to play a video game, a fully working Tetris clone is included in the examples:
![tehtriz_screen](docs/source/_static/tehtriz.png)

View File

@@ -1,5 +1,5 @@
plugins { plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.20" id "org.jetbrains.kotlin.jvm" version "1.3.21"
id 'application' id 'application'
} }
@@ -8,12 +8,15 @@ repositories {
jcenter() jcenter()
} }
def kotlinVersion = '1.3.20' def kotlinVersion = '1.3.21'
dependencies { dependencies {
implementation project(':parser') implementation project(':parser')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
runtime "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" runtime "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
runtime 'org.antlr:antlr4-runtime:4.7.2'
runtime project(':parser')
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit5:$kotlinVersion"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2'
@@ -61,8 +64,10 @@ task fatJar(type: Jar) {
attributes 'Main-Class': 'prog8.CompilerMainKt' attributes 'Main-Class': 'prog8.CompilerMainKt'
} }
archiveBaseName = 'prog8compiler' archiveBaseName = 'prog8compiler'
destinationDir = rootProject.projectDir destinationDirectory = rootProject.projectDir
from { project.configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } } from {
project.configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar with jar
} }
// build.finalizedBy(fatJar) // build.finalizedBy(fatJar)

View File

@@ -105,8 +105,8 @@
; ---- CIA 6526 1 & 2 registers ---- ; ---- CIA 6526 1 & 2 registers ----
memory ubyte CIA1PRA = $DC00 ; CIA 1 DRA, keyboard column drive memory ubyte CIA1PRA = $DC00 ; CIA 1 DRA, keyboard column drive (and joystick control port #2)
memory ubyte CIA1PRB = $DC01 ; CIA 1 DRB, keyboard row port memory ubyte CIA1PRB = $DC01 ; CIA 1 DRB, keyboard row port (and joystick control port #1)
memory ubyte CIA1DDRA = $DC02 ; CIA 1 DDRA, keyboard column memory ubyte CIA1DDRA = $DC02 ; CIA 1 DDRA, keyboard column
memory ubyte CIA1DDRB = $DC03 ; CIA 1 DDRB, keyboard row memory ubyte CIA1DDRB = $DC03 ; CIA 1 DDRB, keyboard row
memory ubyte CIA1TAL = $DC04 ; CIA 1 timer A low byte memory ubyte CIA1TAL = $DC04 ; CIA 1 timer A low byte

View File

@@ -99,6 +99,10 @@ asmsub uword2bcd (uword value @ AY) -> clobbers(A,Y) -> () {
%asm {{ %asm {{
sta c64.SCRATCH_ZPB1 sta c64.SCRATCH_ZPB1
sty c64.SCRATCH_ZPREG sty c64.SCRATCH_ZPREG
php
pla ; read status register
and #%00000100
sta _had_irqd
sei ; disable interrupts because of bcd math sei ; disable interrupts because of bcd math
sed ; switch to decimal mode sed ; switch to decimal mode
lda #0 ; ensure the result is clear lda #0 ; ensure the result is clear
@@ -121,8 +125,11 @@ asmsub uword2bcd (uword value @ AY) -> clobbers(A,Y) -> () {
dey ; and repeat for next bit dey ; and repeat for next bit
bne - bne -
cld ; back to binary cld ; back to binary
cli ; enable interrupts again @todo don't re-enable if it wasn't enabled before lda _had_irqd
rts bne +
cli ; enable interrupts again (only if they were enabled before)
+ rts
_had_irqd .byte 0
}} }}
} }
@@ -713,27 +720,6 @@ asmsub print (str text @ AY) -> clobbers(A,Y) -> () {
} }
asmsub print_p (str_p text @ AY) -> clobbers(A) -> (ubyte @ Y) {
; ---- print pstring (length as first byte) from A/Y, returns str len in Y
%asm {{
sta c64.SCRATCH_ZPB1
sty c64.SCRATCH_ZPREG
stx c64.SCRATCH_ZPREGX
ldy #0
lda (c64.SCRATCH_ZPB1),y
beq +
tax
- iny
lda (c64.SCRATCH_ZPB1),y
jsr c64.CHROUT
dex
bne -
+ ldx c64.SCRATCH_ZPREGX
rts ; output string length is in Y
}}
}
asmsub print_ub0 (ubyte value @ A) -> clobbers(A,Y) -> () { asmsub print_ub0 (ubyte value @ A) -> clobbers(A,Y) -> () {
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
%asm {{ %asm {{
@@ -972,6 +958,25 @@ _screenrows .word $0400 + range(0, 1000, 40)
}} }}
} }
asmsub getchr (ubyte col @Y, ubyte row @A) -> clobbers(Y) -> (ubyte @ A) {
; ---- get the character in the screen matrix at the given location
%asm {{
sty c64.SCRATCH_ZPB1
asl a
tay
lda setchr._screenrows+1,y
sta _mod+2
lda setchr._screenrows,y
clc
adc c64.SCRATCH_ZPB1
sta _mod+1
bcc _mod
inc _mod+2
_mod lda $ffff ; modified
rts
}}
}
asmsub setclr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () { asmsub setclr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () {
; ---- set the color in SCRATCH_ZPB1 on the screen matrix at the given position ; ---- set the color in SCRATCH_ZPB1 on the screen matrix at the given position
%asm {{ %asm {{
@@ -994,6 +999,24 @@ _colorrows .word $d800 + range(0, 1000, 40)
}} }}
} }
asmsub getclr (ubyte col @Y, ubyte row @A) -> clobbers(Y) -> (ubyte @ A) {
; ---- get the color in the screen color matrix at the given location
%asm {{
sty c64.SCRATCH_ZPB1
asl a
tay
lda setclr._colorrows+1,y
sta _mod+2
lda setclr._colorrows,y
clc
adc c64.SCRATCH_ZPB1
sta _mod+1
bcc _mod
inc _mod+2
_mod lda $ffff ; modified
rts
}}
}
sub setcc (ubyte column, ubyte row, ubyte char, ubyte color) { sub setcc (ubyte column, ubyte row, ubyte char, ubyte color) {
; ---- set char+color at the given position on the screen ; ---- set char+color at the given position on the screen

View File

@@ -106,6 +106,161 @@ not_word .proc
rts rts
.pend .pend
bitand_b .proc
; -- bitwise and (of 2 bytes)
lda c64.ESTACK_LO+2,x
and c64.ESTACK_LO+1,x
inx
sta c64.ESTACK_LO+1,x
rts
.pend
bitor_b .proc
; -- bitwise or (of 2 bytes)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_LO+1,x
inx
sta c64.ESTACK_LO+1,x
rts
.pend
bitxor_b .proc
; -- bitwise xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
eor c64.ESTACK_LO+1,x
inx
sta c64.ESTACK_LO+1,x
rts
.pend
bitand_w .proc
; -- bitwise and (of 2 words)
lda c64.ESTACK_LO+2,x
and c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+2,x
lda c64.ESTACK_HI+2,x
and c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+2,x
inx
rts
.pend
bitor_w .proc
; -- bitwise or (of 2 words)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+2,x
lda c64.ESTACK_HI+2,x
ora c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+2,x
inx
rts
.pend
bitxor_w .proc
; -- bitwise xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
eor c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+2,x
lda c64.ESTACK_HI+2,x
eor c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+2,x
inx
rts
.pend
and_b .proc
; -- logical and (of 2 bytes)
lda c64.ESTACK_LO+2,x
beq +
lda #1
+ sta c64.SCRATCH_ZPB1
lda c64.ESTACK_LO+1,x
beq +
lda #1
+ and c64.SCRATCH_ZPB1
inx
sta c64.ESTACK_LO+1,x
rts
.pend
or_b .proc
; -- logical or (of 2 bytes)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_LO+1,x
beq +
lda #1
+ inx
sta c64.ESTACK_LO+1,x
rts
.pend
xor_b .proc
; -- logical xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
beq +
lda #1
+ sta c64.SCRATCH_ZPB1
lda c64.ESTACK_LO+1,x
beq +
lda #1
+ eor c64.SCRATCH_ZPB1
inx
sta c64.ESTACK_LO+1,x
rts
.pend
and_w .proc
; -- logical and (word and word -> byte)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_HI+2,x
beq +
lda #1
+ sta c64.SCRATCH_ZPB1
lda c64.ESTACK_LO+1,x
ora c64.ESTACK_HI+1,x
beq +
lda #1
+ and c64.SCRATCH_ZPB1
inx
sta c64.ESTACK_LO+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
or_w .proc
; -- logical or (word or word -> byte)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_LO+1,x
ora c64.ESTACK_HI+2,x
ora c64.ESTACK_HI+1,x
beq +
lda #1
+ inx
sta c64.ESTACK_LO+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
xor_w .proc
; -- logical xor (word xor word -> byte)
lda c64.ESTACK_LO+2,x
ora c64.ESTACK_HI+2,x
beq +
lda #1
+ sta c64.SCRATCH_ZPB1
lda c64.ESTACK_LO+1,x
ora c64.ESTACK_HI+1,x
beq +
lda #1
+ eor c64.SCRATCH_ZPB1
inx
sta c64.ESTACK_LO+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
abs_b .proc abs_b .proc
; -- push abs(byte) on stack (as byte) ; -- push abs(byte) on stack (as byte)
lda c64.ESTACK_LO+1,x lda c64.ESTACK_LO+1,x
@@ -485,6 +640,15 @@ greatereq_w .proc
bmi equal_b._equal_b_false bmi equal_b._equal_b_false
.pend .pend
func_read_flags .proc
; -- put the processor status register on the stack
php
pla
sta c64.ESTACK_LO,x
dex
rts
.pend
func_sin8 .proc func_sin8 .proc
ldy c64.ESTACK_LO+1,x ldy c64.ESTACK_LO+1,x

View File

@@ -1 +1 @@
1.2 (beta) 1.4 (beta)

View File

@@ -46,6 +46,7 @@ private fun compileMain(args: Array<String>) {
var moduleFile = "" var moduleFile = ""
var writeVmCode = false var writeVmCode = false
var writeAssembly = true var writeAssembly = true
var optimize = true
for (arg in args) { for (arg in args) {
if(arg=="-emu") if(arg=="-emu")
emulatorToStart = "x64" emulatorToStart = "x64"
@@ -55,6 +56,8 @@ private fun compileMain(args: Array<String>) {
writeVmCode = true writeVmCode = true
else if(arg=="-noasm") else if(arg=="-noasm")
writeAssembly = false writeAssembly = false
else if(arg=="-noopt")
optimize = false
else if(!arg.startsWith("-")) else if(!arg.startsWith("-"))
moduleFile = arg moduleFile = arg
else else
@@ -101,9 +104,12 @@ private fun compileMain(args: Array<String>) {
} }
//println(" time4: $time4") //println(" time4: $time4")
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(heap) // useful for checking symbol usage later?
// moduleAst.simplifyExpressions(namespace, heap)
// moduleAst.optimizeStatements(namespace, heap)
if(optimize) {
// optimize the parse tree // optimize the parse tree
println("Optimizing...") println("Optimizing...")
val allScopedSymbolDefinitions = moduleAst.checkIdentifiers(heap) // useful for checking symbol usage later?
while (true) { while (true) {
// keep optimizing expressions and statements until no more steps remain // keep optimizing expressions and statements until no more steps remain
val optsDone1 = moduleAst.simplifyExpressions(namespace, heap) val optsDone1 = moduleAst.simplifyExpressions(namespace, heap)
@@ -111,6 +117,7 @@ private fun compileMain(args: Array<String>) {
if (optsDone1 + optsDone2 == 0) if (optsDone1 + optsDone2 == 0)
break break
} }
}
namespace = moduleAst.definingScope() // create it again, it could have changed in the meantime namespace = moduleAst.definingScope() // create it again, it could have changed in the meantime
moduleAst.checkValid(namespace, compilerOptions, heap) // check if final tree is valid moduleAst.checkValid(namespace, compilerOptions, heap) // check if final tree is valid
@@ -121,6 +128,7 @@ private fun compileMain(args: Array<String>) {
// compile the syntax tree into stackvmProg form, and optimize that // compile the syntax tree into stackvmProg form, and optimize that
val compiler = Compiler(moduleAst, namespace, heap) val compiler = Compiler(moduleAst, namespace, heap)
val intermediate = compiler.compile(compilerOptions) val intermediate = compiler.compile(compilerOptions)
if(optimize)
intermediate.optimize() intermediate.optimize()
if(writeVmCode) { if(writeVmCode) {
@@ -134,7 +142,7 @@ private fun compileMain(args: Array<String>) {
if(writeAssembly) { if(writeAssembly) {
val zeropage = C64Zeropage(compilerOptions) val zeropage = C64Zeropage(compilerOptions)
intermediate.allocateZeropage(zeropage) intermediate.allocateZeropage(zeropage)
val assembly = AsmGen(compilerOptions, intermediate, heap, zeropage).compileToAssembly() val assembly = AsmGen(compilerOptions, intermediate, heap, zeropage).compileToAssembly(optimize)
assembly.assemble(compilerOptions) assembly.assemble(compilerOptions)
programname = assembly.name programname = assembly.name
} }
@@ -211,6 +219,7 @@ private fun usage() {
System.err.println(" [-writevm] write intermediate vm code to a file as well") System.err.println(" [-writevm] write intermediate vm code to a file as well")
System.err.println(" [-noasm] don't create assembly code") System.err.println(" [-noasm] don't create assembly code")
System.err.println(" [-vm] launch the prog8 virtual machine instead of the compiler") System.err.println(" [-vm] launch the prog8 virtual machine instead of the compiler")
System.err.println(" [-noopt] don't perform optimizations")
System.err.println(" modulefile main module file to compile") System.err.println(" modulefile main module file to compile")
exitProcess(1) exitProcess(1)
} }

View File

@@ -26,9 +26,7 @@ enum class DataType {
WORD, WORD,
FLOAT, FLOAT,
STR, STR,
STR_P,
STR_S, STR_S,
STR_PS,
ARRAY_UB, ARRAY_UB,
ARRAY_B, ARRAY_B,
ARRAY_UW, ARRAY_UW,
@@ -44,9 +42,7 @@ enum class DataType {
WORD -> targetType == WORD || targetType==UWORD || targetType == FLOAT WORD -> targetType == WORD || targetType==UWORD || targetType == FLOAT
FLOAT -> targetType == FLOAT FLOAT -> targetType == FLOAT
STR -> targetType == STR || targetType==STR_S || targetType == UWORD STR -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_P -> targetType == STR_P || targetType==STR_PS || targetType == UWORD
STR_S -> targetType == STR || targetType==STR_S || targetType == UWORD STR_S -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_PS -> targetType == STR_P || targetType==STR_PS || targetType == UWORD
ARRAY_UB -> targetType == UWORD || targetType==ARRAY_UB ARRAY_UB -> targetType == UWORD || targetType==ARRAY_UB
ARRAY_B -> targetType == UWORD || targetType==ARRAY_B ARRAY_B -> targetType == UWORD || targetType==ARRAY_B
ARRAY_UW -> targetType == UWORD || targetType==ARRAY_UW ARRAY_UW -> targetType == UWORD || targetType==ARRAY_UW
@@ -98,14 +94,15 @@ enum class BranchCondition {
val IterableDatatypes = setOf( val IterableDatatypes = setOf(
DataType.STR, DataType.STR_S, DataType.STR, DataType.STR_S,
DataType.STR_P, DataType.STR_PS, // note: these are a bit weird they store their length as the first byte
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_B,
DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_W,
DataType.ARRAY_F) DataType.ARRAY_F)
val StringDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) val ByteDatatypes = setOf(DataType.UBYTE, DataType.BYTE)
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT) val WordDatatypes = setOf(DataType.UWORD, DataType.WORD)
val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD) val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
val StringDatatypes = setOf(DataType.STR, DataType.STR_S)
val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F) val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
@@ -790,7 +787,7 @@ data class AssignTarget(val register: Register?,
fun shortString(withTypePrefix: Boolean=false): String { fun shortString(withTypePrefix: Boolean=false): String {
if(register!=null) if(register!=null)
return (if(withTypePrefix) "0register::" else "") + register.toString() return (if(withTypePrefix) "0register::" else "") + register.name
if(identifier!=null) if(identifier!=null)
return (if(withTypePrefix) "3identifier::" else "") + identifier.nameInSource.last() return (if(withTypePrefix) "3identifier::" else "") + identifier.nameInSource.last()
if(arrayindexed!=null) if(arrayindexed!=null)
@@ -918,8 +915,8 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
DataType.BYTE -> when(rightDt) { DataType.BYTE -> when(rightDt) {
DataType.BYTE, DataType.UBYTE -> DataType.BYTE in ByteDatatypes -> DataType.BYTE
DataType.WORD, DataType.UWORD -> DataType.WORD in WordDatatypes -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
@@ -930,7 +927,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
DataType.WORD -> when(rightDt) { DataType.WORD -> when(rightDt) {
DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD -> DataType.WORD in IntegerDatatypes -> DataType.WORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt") else -> throw FatalAstException("arithmetic operation on incompatible datatypes: $leftDt and $rightDt")
} }
@@ -1073,8 +1070,8 @@ class LiteralValue(val type: DataType,
fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue { fun fromNumber(value: Number, type: DataType, position: Position) : LiteralValue {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> LiteralValue(type, bytevalue = value.toShort(), position = position) in ByteDatatypes -> LiteralValue(type, bytevalue = value.toShort(), position = position)
DataType.UWORD, DataType.WORD -> LiteralValue(type, wordvalue = value.toInt(), position = position) in WordDatatypes -> LiteralValue(type, wordvalue = value.toInt(), position = position)
DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position) DataType.FLOAT -> LiteralValue(type, floatvalue = value.toDouble(), position = position)
else -> throw FatalAstException("non numeric datatype") else -> throw FatalAstException("non numeric datatype")
} }
@@ -1110,8 +1107,8 @@ class LiteralValue(val type: DataType,
init { init {
when(type){ when(type){
DataType.UBYTE, DataType.BYTE -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue") in ByteDatatypes -> if(bytevalue==null) throw FatalAstException("literal value missing bytevalue")
DataType.UWORD, DataType.WORD -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue") in WordDatatypes -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue") DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
in StringDatatypes -> in StringDatatypes ->
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId") if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
@@ -1159,14 +1156,15 @@ class LiteralValue(val type: DataType,
DataType.UWORD -> "uword:$wordvalue" DataType.UWORD -> "uword:$wordvalue"
DataType.WORD -> "word:$wordvalue" DataType.WORD -> "word:$wordvalue"
DataType.FLOAT -> "float:$floatvalue" DataType.FLOAT -> "float:$floatvalue"
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS-> { in StringDatatypes -> {
if(heapId!=null) "str:#$heapId" if(heapId!=null) "str:#$heapId"
else "str:$initialstrvalue" else "str:$initialstrvalue"
} }
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> { in ArrayDatatypes -> {
if(heapId!=null) "arrayspec:#$heapId" if(heapId!=null) "arrayspec:#$heapId"
else "arrayspec:$arrayvalue" else "arrayspec:$arrayvalue"
} }
else -> throw FatalAstException("weird datatype")
} }
return "LiteralValue($vstr)" return "LiteralValue($vstr)"
} }
@@ -1272,7 +1270,7 @@ class LiteralValue(val type: DataType,
return LiteralValue(targettype, wordvalue = value, position = position) return LiteralValue(targettype, wordvalue = value, position = position)
} }
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
if(targettype in StringDatatypes) if(targettype in StringDatatypes)
return this return this
} }
@@ -1314,9 +1312,7 @@ class RangeExpr(var from: IExpression,
fromDt==DataType.UBYTE && toDt==DataType.UBYTE -> DataType.UBYTE fromDt==DataType.UBYTE && toDt==DataType.UBYTE -> DataType.UBYTE
fromDt==DataType.UWORD && toDt==DataType.UWORD -> DataType.UWORD fromDt==DataType.UWORD && toDt==DataType.UWORD -> DataType.UWORD
fromDt==DataType.STR && toDt==DataType.STR -> DataType.STR fromDt==DataType.STR && toDt==DataType.STR -> DataType.STR
fromDt==DataType.STR_P && toDt==DataType.STR_P -> DataType.STR_P
fromDt==DataType.STR_S && toDt==DataType.STR_S -> DataType.STR_S fromDt==DataType.STR_S && toDt==DataType.STR_S -> DataType.STR_S
fromDt==DataType.STR_PS && toDt==DataType.STR_PS -> DataType.STR_PS
fromDt==DataType.WORD || toDt==DataType.WORD -> DataType.WORD fromDt==DataType.WORD || toDt==DataType.WORD -> DataType.WORD
fromDt==DataType.BYTE || toDt==DataType.BYTE -> DataType.BYTE fromDt==DataType.BYTE || toDt==DataType.BYTE -> DataType.BYTE
else -> DataType.UBYTE else -> DataType.UBYTE
@@ -1649,7 +1645,7 @@ class Subroutine(override val name: String,
.map { (it as InlineAssembly).assembly } .map { (it as InlineAssembly).assembly }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it } .count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it }
val canBeAsmSubroutine =false // TODO see below val canBeAsmSubroutine =false // TODO disabled for now, see below about problem with converting to asm subroutine
// !isAsmSubroutine // !isAsmSubroutine
// && ((parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD)) // && ((parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD))
// || (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE })) // || (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE }))
@@ -2078,7 +2074,11 @@ private fun prog8Parser.IntegerliteralContext.toAst(): NumericLiteral {
var datatype = DataType.UBYTE var datatype = DataType.UBYTE
when (radix) { when (radix) {
10 -> { 10 -> {
integer = text.toInt() integer = try {
text.toInt()
} catch(x: NumberFormatException) {
throw AstException("${toPosition()} invalid decimal literal ${x.message}")
}
datatype = when(integer) { datatype = when(integer) {
in 0..255 -> DataType.UBYTE in 0..255 -> DataType.UBYTE
in -128..127 -> DataType.BYTE in -128..127 -> DataType.BYTE
@@ -2090,12 +2090,20 @@ private fun prog8Parser.IntegerliteralContext.toAst(): NumericLiteral {
2 -> { 2 -> {
if(text.length>8) if(text.length>8)
datatype = DataType.UWORD datatype = DataType.UWORD
try {
integer = text.toInt(2) integer = text.toInt(2)
} catch(x: NumberFormatException) {
throw AstException("${toPosition()} invalid binary literal ${x.message}")
}
} }
16 -> { 16 -> {
if(text.length>2) if(text.length>2)
datatype = DataType.UWORD datatype = DataType.UWORD
try {
integer = text.toInt(16) integer = text.toInt(16)
} catch(x: NumberFormatException) {
throw AstException("${toPosition()} invalid hexadecimal literal ${x.message}")
}
} }
else -> throw FatalAstException("invalid radix") else -> throw FatalAstException("invalid radix")
} }

View File

@@ -704,8 +704,8 @@ private class AstChecker(private val namespace: INameScope,
} }
} }
val leftDt = expr.left.resultingDatatype(namespace, heap)!! val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap)!! val rightDt = expr.right.resultingDatatype(namespace, heap)
if(leftDt !in NumericDatatypes) if(leftDt !in NumericDatatypes)
checkResult.add(ExpressionError("left operand is not numeric", expr.left.position)) checkResult.add(ExpressionError("left operand is not numeric", expr.left.position))
if(rightDt!in NumericDatatypes) if(rightDt!in NumericDatatypes)
@@ -830,6 +830,19 @@ private class AstChecker(private val namespace: INameScope,
if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference) if (arg.first.value !is LiteralValue && arg.first.value !is IdentifierReference)
printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position) printWarning("calling a subroutine that expects X as a parameter is problematic, more so when providing complex arguments. If you see a compiler error/crash about this later, try to simplify this call", position)
} }
// check if the argument types match the register(pairs)
val asmParamReg = target.asmParameterRegisters[arg.first.index]
if(asmParamReg.statusflag!=null) {
if(argDt !in ByteDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for statusflag", position))
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
if(argDt !in ByteDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be byte type for single register", position))
} else if(asmParamReg.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
if(argDt !in WordDatatypes+ IterableDatatypes)
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} must be word type for register pair", position))
}
} }
} }
} }
@@ -877,9 +890,6 @@ private class AstChecker(private val namespace: INameScope,
if(index!=null && (index<0 || index>=arraysize)) if(index!=null && (index<0 || index>=arraysize))
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position)) checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position))
} else if(target.datatype in StringDatatypes) { } else if(target.datatype in StringDatatypes) {
// check supported string tyep
if(target.datatype == DataType.STR_P || target.datatype==DataType.STR_PS)
checkResult.add(ExpressionError("indexing pascal-strings is not supported, use regular str type instead", arrayIndexedExpression.arrayspec.position))
// check string lengths // check string lengths
val heapId = (target.value as LiteralValue).heapId!! val heapId = (target.value as LiteralValue).heapId!!
val stringLen = heap.get(heapId).str!!.length val stringLen = heap.get(heapId).str!!.length
@@ -902,7 +912,7 @@ private class AstChecker(private val namespace: INameScope,
val targetStatement = target.targetStatement(namespace) val targetStatement = target.targetStatement(namespace)
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder) if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
return targetStatement return targetStatement
checkResult.add(SyntaxError("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", statement.position)) checkResult.add(NameError("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", statement.position))
return null return null
} }
@@ -954,8 +964,8 @@ private class AstChecker(private val namespace: INameScope,
when (targetDt) { when (targetDt) {
DataType.FLOAT -> { DataType.FLOAT -> {
val number = when(value.type) { val number = when(value.type) {
DataType.UBYTE, DataType.BYTE -> value.bytevalue!!.toDouble() in ByteDatatypes -> value.bytevalue!!.toDouble()
DataType.UWORD, DataType.WORD -> value.wordvalue!!.toDouble() in WordDatatypes -> value.wordvalue!!.toDouble()
DataType.FLOAT -> value.floatvalue!! DataType.FLOAT -> value.floatvalue!!
else -> return err("numeric value expected") else -> return err("numeric value expected")
} }
@@ -996,7 +1006,7 @@ private class AstChecker(private val namespace: INameScope,
if (number < -32768 || number > 32767) if (number < -32768 || number > 32767)
return err("value '$number' out of range for word") return err("value '$number' out of range for word")
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { DataType.STR, DataType.STR_S -> {
if(!value.isString) if(!value.isString)
return err("string value expected") return err("string value expected")
val str = value.strvalue(heap) val str = value.strvalue(heap)
@@ -1122,8 +1132,6 @@ private class AstChecker(private val namespace: INameScope,
DataType.FLOAT -> sourceDatatype in NumericDatatypes DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype==DataType.STR DataType.STR -> sourceDatatype==DataType.STR
DataType.STR_S -> sourceDatatype==DataType.STR_S DataType.STR_S -> sourceDatatype==DataType.STR_S
DataType.STR_P -> sourceDatatype==DataType.STR_P
DataType.STR_PS -> sourceDatatype==DataType.STR_PS
else -> checkResult.add(SyntaxError("cannot assign new value to variable of type $targetDatatype", position)) else -> checkResult.add(SyntaxError("cannot assign new value to variable of type $targetDatatype", position))
} }
@@ -1137,9 +1145,9 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position)) checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
} }
else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes) else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes)
checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)) checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.name.toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position))
else else
checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position)) checkResult.add(ExpressionError("cannot assign ${sourceDatatype.name.toLowerCase()} to ${targetDatatype.name.toLowerCase()}", position))
return false return false
} }

View File

@@ -33,6 +33,7 @@ fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
} }
else -> TODO("replace literalvalue by identifierref: $variable (in $parent)") else -> TODO("replace literalvalue by identifierref: $variable (in $parent)")
} }
variable.second.linkParents(scope as Node)
} }
printErrors(checker.result(), name) printErrors(checker.result(), name)

View File

@@ -92,17 +92,12 @@ class HeapValues {
fun update(heapId: Int, str: String) { fun update(heapId: Int, str: String) {
val oldVal = heap[heapId] ?: throw IllegalArgumentException("heapId not found in heap") val oldVal = heap[heapId] ?: throw IllegalArgumentException("heapId not found in heap")
when(oldVal.type){ if(oldVal.type in StringDatatypes) {
DataType.STR,
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> {
if (oldVal.str!!.length != str.length) if (oldVal.str!!.length != str.length)
throw IllegalArgumentException("heap string length mismatch") throw IllegalArgumentException("heap string length mismatch")
heap[heapId] = oldVal.copy(str = str) heap[heapId] = oldVal.copy(str = str)
} }
else-> throw IllegalArgumentException("heap data type mismatch") else throw IllegalArgumentException("heap data type mismatch")
}
} }
fun update(heapId: Int, heapval: HeapValue) { fun update(heapId: Int, heapval: HeapValue) {
@@ -237,12 +232,11 @@ internal class Compiler(private val rootModule: Module,
private fun opcodePush(dt: DataType): Opcode { private fun opcodePush(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE in ByteDatatypes -> Opcode.PUSH_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD in WordDatatypes -> Opcode.PUSH_WORD
in IterableDatatypes -> Opcode.PUSH_WORD
DataType.FLOAT -> Opcode.PUSH_FLOAT DataType.FLOAT -> Opcode.PUSH_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
} }
} }
@@ -280,12 +274,11 @@ internal class Compiler(private val rootModule: Module,
private fun opcodePushvar(dt: DataType): Opcode { private fun opcodePushvar(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_VAR_BYTE in ByteDatatypes -> Opcode.PUSH_VAR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_VAR_WORD in WordDatatypes -> Opcode.PUSH_VAR_WORD
in IterableDatatypes -> Opcode.PUSH_ADDR_HEAPVAR
DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT DataType.FLOAT -> Opcode.PUSH_VAR_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_ADDR_HEAPVAR
} }
} }
@@ -295,7 +288,6 @@ internal class Compiler(private val rootModule: Module,
DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_WORD DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_WORD
DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_FLOAT DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_FLOAT
DataType.STR, DataType.STR_S -> Opcode.READ_INDEXED_VAR_BYTE DataType.STR, DataType.STR_S -> Opcode.READ_INDEXED_VAR_BYTE
DataType.STR_P, DataType.STR_PS -> throw CompilerException("cannot index on type $dt - use regular 0-terminated str type")
else -> throw CompilerException("invalid dt for indexed access $dt") else -> throw CompilerException("invalid dt for indexed access $dt")
} }
} }
@@ -306,41 +298,37 @@ internal class Compiler(private val rootModule: Module,
DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_WORD DataType.ARRAY_UW, DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_WORD
DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_FLOAT DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_FLOAT
DataType.STR, DataType.STR_S -> Opcode.WRITE_INDEXED_VAR_BYTE DataType.STR, DataType.STR_S -> Opcode.WRITE_INDEXED_VAR_BYTE
DataType.STR_P, DataType.STR_PS -> TODO("cannot index on type $dt - use regular str type")
else -> throw CompilerException("invalid dt for indexed access $dt") else -> throw CompilerException("invalid dt for indexed access $dt")
} }
} }
private fun opcodeDiscard(dt: DataType): Opcode { private fun opcodeDiscard(dt: DataType): Opcode {
return when(dt) { return when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.DISCARD_BYTE in ByteDatatypes -> Opcode.DISCARD_BYTE
DataType.UWORD, DataType.WORD -> Opcode.DISCARD_WORD in WordDatatypes -> Opcode.DISCARD_WORD
in IterableDatatypes -> Opcode.DISCARD_WORD
DataType.FLOAT -> Opcode.DISCARD_FLOAT DataType.FLOAT -> Opcode.DISCARD_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.DISCARD_WORD
} }
} }
private fun opcodePopvar(dt: DataType): Opcode { private fun opcodePopvar(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.POP_VAR_BYTE in ByteDatatypes -> Opcode.POP_VAR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.POP_VAR_WORD in WordDatatypes -> Opcode.POP_VAR_WORD
in IterableDatatypes -> Opcode.POP_VAR_WORD
DataType.FLOAT -> Opcode.POP_VAR_FLOAT DataType.FLOAT -> Opcode.POP_VAR_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_VAR_WORD
} }
} }
private fun opcodePopmem(dt: DataType): Opcode { private fun opcodePopmem(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.POP_MEM_BYTE in ByteDatatypes -> Opcode.POP_MEM_BYTE
DataType.UWORD, DataType.WORD -> Opcode.POP_MEM_WORD in WordDatatypes -> Opcode.POP_MEM_WORD
in IterableDatatypes -> Opcode.POP_MEM_WORD
DataType.FLOAT -> Opcode.POP_MEM_FLOAT DataType.FLOAT -> Opcode.POP_MEM_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw CompilerException("invalid dt $dt")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.POP_MEM_WORD
} }
} }
@@ -517,8 +505,8 @@ internal class Compiler(private val rootModule: Module,
if(trueGoto!=null) { if(trueGoto!=null) {
// optimization for if (condition) goto .... // optimization for if (condition) goto ....
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
translate(trueGoto, conditionJumpOpcode) translate(trueGoto, conditionJumpOpcode)
@@ -527,8 +515,8 @@ internal class Compiler(private val rootModule: Module,
} }
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JZ in ByteDatatypes -> Opcode.JZ
DataType.UWORD, DataType.WORD -> Opcode.JZW in WordDatatypes -> Opcode.JZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
val labelEnd = makeLabel("end") val labelEnd = makeLabel("end")
@@ -573,8 +561,8 @@ internal class Compiler(private val rootModule: Module,
} }
DataType.BYTE -> { DataType.BYTE -> {
when(rightDt) { when(rightDt) {
DataType.UBYTE, DataType.BYTE -> DataType.BYTE in ByteDatatypes -> DataType.BYTE
DataType.UWORD, DataType.WORD -> DataType.WORD in WordDatatypes -> DataType.WORD
DataType.FLOAT -> { DataType.FLOAT -> {
printWarning(floatWarning, leftpos) printWarning(floatWarning, leftpos)
DataType.FLOAT DataType.FLOAT
@@ -615,7 +603,7 @@ internal class Compiler(private val rootModule: Module,
private fun translate(expr: IExpression) { private fun translate(expr: IExpression) {
when(expr) { when(expr) {
is RegisterExpr -> { is RegisterExpr -> {
prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = expr.register.toString()) prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = expr.register.name)
} }
is PrefixExpression -> { is PrefixExpression -> {
translate(expr.expression) translate(expr.expression)
@@ -645,7 +633,7 @@ internal class Compiler(private val rootModule: Module,
if(target is BuiltinFunctionStatementPlaceholder) { if(target is BuiltinFunctionStatementPlaceholder) {
// call to a builtin function (some will just be an opcode!) // call to a builtin function (some will just be an opcode!)
val funcname = expr.target.nameInSource[0] val funcname = expr.target.nameInSource[0]
translateFunctionCall(funcname, expr.arglist) translateBuiltinFunctionCall(funcname, expr.arglist)
} else { } else {
when(target) { when(target) {
is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.position) is Subroutine -> translateSubroutineCall(target, expr.arglist, expr.position)
@@ -662,20 +650,20 @@ internal class Compiler(private val rootModule: Module,
else -> { else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr") val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) { when(lv.type) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!)) in ByteDatatypes -> prog.instr(Opcode.PUSH_BYTE, Value(lv.type, lv.bytevalue!!))
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!)) in WordDatatypes -> prog.instr(Opcode.PUSH_WORD, Value(lv.type, lv.wordvalue!!))
DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!)) DataType.FLOAT -> prog.instr(Opcode.PUSH_FLOAT, Value(lv.type, lv.floatvalue!!))
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("string should have been moved into heap ${lv.position}") throw CompilerException("string should have been moved into heap ${lv.position}")
TODO("push address of string with PUSH_ADDR_HEAPVAR") TODO("push address of string with PUSH_ADDR_HEAPVAR")
} }
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F, in ArrayDatatypes -> {
DataType.ARRAY_B, DataType.ARRAY_W -> {
if(lv.heapId==null) if(lv.heapId==null)
throw CompilerException("array should have been moved into heap ${lv.position}") throw CompilerException("array should have been moved into heap ${lv.position}")
TODO("push address of array with PUSH_WORD") TODO("push address of array with PUSH_WORD")
} }
else -> throw CompilerException("weird datatype")
} }
} }
} }
@@ -714,12 +702,12 @@ internal class Compiler(private val rootModule: Module,
else -> {} else -> {}
} }
DataType.UWORD -> when(targetDt) { DataType.UWORD -> when(targetDt) {
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type") in ByteDatatypes -> throw CompilerException("narrowing type")
DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F) DataType.FLOAT -> prog.instr(Opcode.CAST_UW_TO_F)
else -> {} else -> {}
} }
DataType.WORD -> when(targetDt) { DataType.WORD -> when(targetDt) {
DataType.UBYTE, DataType.BYTE -> throw CompilerException("narrowing type") in ByteDatatypes -> throw CompilerException("narrowing type")
DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F) DataType.FLOAT -> prog.instr(Opcode.CAST_W_TO_F)
else -> {} else -> {}
} }
@@ -761,7 +749,7 @@ internal class Compiler(private val rootModule: Module,
val targetStmt = stmt.target.targetStatement(namespace)!! val targetStmt = stmt.target.targetStatement(namespace)!!
if(targetStmt is BuiltinFunctionStatementPlaceholder) { if(targetStmt is BuiltinFunctionStatementPlaceholder) {
val funcname = stmt.target.nameInSource[0] val funcname = stmt.target.nameInSource[0]
translateFunctionCall(funcname, stmt.arglist) translateBuiltinFunctionCall(funcname, stmt.arglist)
return return
} }
@@ -771,8 +759,6 @@ internal class Compiler(private val rootModule: Module,
is Subroutine -> { is Subroutine -> {
translateSubroutineCall(targetStmt, stmt.arglist, stmt.position) translateSubroutineCall(targetStmt, stmt.arglist, stmt.position)
// make sure we clean up the unused result values from the stack // make sure we clean up the unused result values from the stack
// only if they're non-register return values!
if(targetStmt.asmReturnvaluesRegisters.isEmpty())
for(rv in targetStmt.returntypes) { for(rv in targetStmt.returntypes) {
val opcode=opcodeDiscard(rv) val opcode=opcodeDiscard(rv)
prog.instr(opcode) prog.instr(opcode)
@@ -783,8 +769,8 @@ internal class Compiler(private val rootModule: Module,
} }
} }
private fun translateFunctionCall(funcname: String, args: List<IExpression>) { private fun translateBuiltinFunctionCall(funcname: String, args: List<IExpression>) {
// some functions are implemented as vm opcodes // some builtin functions are implemented directly as vm opcodes
if(funcname == "swap") { if(funcname == "swap") {
translateSwap(args) translateSwap(args)
@@ -812,10 +798,7 @@ internal class Compiler(private val rootModule: Module,
// 1 argument, type determines the exact syscall to use // 1 argument, type determines the exact syscall to use
val arg=args.single() val arg=args.single()
when (arg.resultingDatatype(namespace, heap)) { when (arg.resultingDatatype(namespace, heap)) {
DataType.STR -> createSyscall("${funcname}_str") DataType.STR, DataType.STR_S -> createSyscall("${funcname}_str")
DataType.STR_P -> createSyscall("${funcname}_strp")
DataType.STR_S -> createSyscall("${funcname}_str")
DataType.STR_PS -> createSyscall("${funcname}_strp")
else -> throw CompilerException("wrong datatype for len()") else -> throw CompilerException("wrong datatype for len()")
} }
} }
@@ -895,12 +878,12 @@ internal class Compiler(private val rootModule: Module,
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHL_BYTE) in ByteDatatypes -> prog.instr(Opcode.SHL_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHL_WORD) in WordDatatypes -> prog.instr(Opcode.SHL_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"lsr" -> { "lsr" -> {
val arg = args.single() val arg = args.single()
@@ -930,34 +913,34 @@ internal class Compiler(private val rootModule: Module,
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROR_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR_WORD) in WordDatatypes -> prog.instr(Opcode.ROR_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"rol2" -> { "rol2" -> {
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROL2_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROL2_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROL2_WORD) in WordDatatypes -> prog.instr(Opcode.ROL2_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"ror2" -> { "ror2" -> {
val arg = args.single() val arg = args.single()
val dt = arg.resultingDatatype(namespace, heap) val dt = arg.resultingDatatype(namespace, heap)
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.ROR2_BYTE) in ByteDatatypes -> prog.instr(Opcode.ROR2_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.ROR2_WORD) in WordDatatypes -> prog.instr(Opcode.ROR2_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again // this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
popValueIntoTarget(AssignTarget.fromExpr(arg), dt) popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
} }
"set_carry" -> prog.instr(Opcode.SEC) "set_carry" -> prog.instr(Opcode.SEC)
"clear_carry" -> prog.instr(Opcode.CLC) "clear_carry" -> prog.instr(Opcode.CLC)
@@ -1000,8 +983,41 @@ internal class Compiler(private val rootModule: Module,
// We don't bother about saving A and Y. They're considered expendable. // We don't bother about saving A and Y. They're considered expendable.
if(subroutine.isAsmSubroutine) { if(subroutine.isAsmSubroutine) {
restoreX = translateAsmSubCallArguments(subroutine, arguments, callPosition, restoreX)
} else {
// only regular (non-register) arguments
// "assign" the arguments to the locally scoped parameter variables for this subroutine
// (subroutine arguments are not passed via the stack!)
for (arg in arguments.zip(subroutine.parameters)) {
translate(arg.first)
convertType(arg.first.resultingDatatype(namespace, heap)!!, arg.second.type) // convert types of arguments to required parameter type
val opcode = opcodePopvar(arg.second.type)
prog.instr(opcode, callLabel = subroutine.scopedname + "." + arg.second.name)
}
}
prog.instr(Opcode.CALL, callLabel = subroutine.scopedname)
if(restoreX)
prog.instr(Opcode.RRESTOREX)
if(subroutine.isAsmSubroutine && subroutine.asmReturnvaluesRegisters.isNotEmpty()) {
// the result values of the asm-subroutine that are returned in registers, have to be pushed on the stack
// (in reversed order) otherwise the asm-subroutine can't be used in expressions.
for(rv in subroutine.asmReturnvaluesRegisters.reversed()) {
if(rv.statusflag!=null)
TODO("not yet supported: return values in cpu status flag $rv $subroutine")
when(rv.registerOrPair) {
A,X,Y -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = rv.registerOrPair.name)
AX, AY, XY -> prog.instr(Opcode.PUSH_VAR_WORD, callLabel = rv.registerOrPair.name)
null -> {}
}
}
}
}
private fun translateAsmSubCallArguments(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position, restoreXinitial: Boolean): Boolean {
var restoreX = restoreXinitial
if (subroutine.parameters.size != subroutine.asmParameterRegisters.size) if (subroutine.parameters.size != subroutine.asmParameterRegisters.size)
throw CompilerException("no support for mix of register and non-register subroutine arguments") TODO("no support yet for mix of register and non-register subroutine arguments")
// only register arguments (or status-flag bits) // only register arguments (or status-flag bits)
var carryParam: Boolean? = null var carryParam: Boolean? = null
@@ -1085,7 +1101,7 @@ internal class Compiler(private val rootModule: Module,
translate(assignA) translate(assignA)
translate(assignY) translate(assignY)
} }
DataType.UWORD, DataType.WORD -> { in WordDatatypes -> {
translate(arg.first) translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD) prog.instr(Opcode.POP_REGAY_WORD)
} }
@@ -1151,20 +1167,7 @@ internal class Compiler(private val rootModule: Module,
true -> prog.instr(Opcode.SEC) true -> prog.instr(Opcode.SEC)
false -> prog.instr(Opcode.CLC) false -> prog.instr(Opcode.CLC)
} }
} else { return restoreX
// only regular (non-register) arguments
// "assign" the arguments to the locally scoped parameter variables for this subroutine
// (subroutine arguments are not passed via the stack!)
for (arg in arguments.zip(subroutine.parameters)) {
translate(arg.first)
convertType(arg.first.resultingDatatype(namespace, heap)!!, arg.second.type) // convert types of arguments to required parameter type
val opcode = opcodePopvar(arg.second.type)
prog.instr(opcode, callLabel = subroutine.scopedname + "." + arg.second.name)
}
}
prog.instr(Opcode.CALL, callLabel = subroutine.scopedname)
if(restoreX)
prog.instr(Opcode.RRESTOREX)
} }
private fun translateBinaryOperator(operator: String, dt: DataType) { private fun translateBinaryOperator(operator: String, dt: DataType) {
@@ -1231,43 +1234,43 @@ internal class Compiler(private val rootModule: Module,
} }
"&" -> { "&" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITAND_BYTE in ByteDatatypes -> Opcode.BITAND_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITAND_WORD in WordDatatypes -> Opcode.BITAND_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"|" -> { "|" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITOR_BYTE in ByteDatatypes -> Opcode.BITOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITOR_WORD in WordDatatypes -> Opcode.BITOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"^" -> { "^" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.BITXOR_BYTE in ByteDatatypes -> Opcode.BITXOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.BITXOR_WORD in WordDatatypes -> Opcode.BITXOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"and" -> { "and" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.AND_BYTE in ByteDatatypes -> Opcode.AND_BYTE
DataType.UWORD, DataType.WORD -> Opcode.AND_WORD in WordDatatypes -> Opcode.AND_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"or" -> { "or" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.OR_BYTE in ByteDatatypes -> Opcode.OR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.OR_WORD in WordDatatypes -> Opcode.OR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"xor" -> { "xor" -> {
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.XOR_BYTE in ByteDatatypes -> Opcode.XOR_BYTE
DataType.UWORD, DataType.WORD -> Opcode.XOR_WORD in WordDatatypes -> Opcode.XOR_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
@@ -1313,16 +1316,16 @@ internal class Compiler(private val rootModule: Module,
} }
"==" -> { "==" -> {
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.EQUAL_BYTE in ByteDatatypes -> Opcode.EQUAL_BYTE
DataType.UWORD, DataType.WORD -> Opcode.EQUAL_WORD in WordDatatypes -> Opcode.EQUAL_WORD
DataType.FLOAT -> Opcode.EQUAL_F DataType.FLOAT -> Opcode.EQUAL_F
else -> throw CompilerException("only byte/word/lfoat possible") else -> throw CompilerException("only byte/word/lfoat possible")
} }
} }
"!=" -> { "!=" -> {
when (dt) { when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.NOTEQUAL_BYTE in ByteDatatypes -> Opcode.NOTEQUAL_BYTE
DataType.UWORD, DataType.WORD -> Opcode.NOTEQUAL_WORD in WordDatatypes -> Opcode.NOTEQUAL_WORD
DataType.FLOAT -> Opcode.NOTEQUAL_F DataType.FLOAT -> Opcode.NOTEQUAL_F
else -> throw CompilerException("only byte/word/lfoat possible") else -> throw CompilerException("only byte/word/lfoat possible")
} }
@@ -1353,8 +1356,8 @@ internal class Compiler(private val rootModule: Module,
} }
} else if(operator=="<<") { } else if(operator=="<<") {
when (leftDt) { when (leftDt) {
DataType.UBYTE, DataType.BYTE -> prog.instr(Opcode.SHIFTEDL_BYTE) in ByteDatatypes -> prog.instr(Opcode.SHIFTEDL_BYTE)
DataType.UWORD, DataType.WORD -> prog.instr(Opcode.SHIFTEDL_WORD) in WordDatatypes -> prog.instr(Opcode.SHIFTEDL_WORD)
else -> throw CompilerException("wrong datatype") else -> throw CompilerException("wrong datatype")
} }
} }
@@ -1377,15 +1380,15 @@ internal class Compiler(private val rootModule: Module,
} }
"~" -> { "~" -> {
when(operandDt) { when(operandDt) {
DataType.UBYTE, DataType.BYTE -> Opcode.INV_BYTE in ByteDatatypes -> Opcode.INV_BYTE
DataType.UWORD, DataType.WORD -> Opcode.INV_WORD in WordDatatypes -> Opcode.INV_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
"not" -> { "not" -> {
when(operandDt) { when(operandDt) {
DataType.UBYTE, DataType.BYTE -> Opcode.NOT_BYTE in ByteDatatypes -> Opcode.NOT_BYTE
DataType.UWORD, DataType.WORD -> Opcode.NOT_WORD in WordDatatypes -> Opcode.NOT_WORD
else -> throw CompilerException("only byte/word possible") else -> throw CompilerException("only byte/word possible")
} }
} }
@@ -1442,8 +1445,8 @@ internal class Compiler(private val rootModule: Module,
prog.line(stmt.position) prog.line(stmt.position)
when { when {
stmt.target.register != null -> when(stmt.operator) { stmt.target.register != null -> when(stmt.operator) {
"++" -> prog.instr(Opcode.INC_VAR_UB, callLabel = stmt.target.register.toString()) "++" -> prog.instr(Opcode.INC_VAR_UB, callLabel = stmt.target.register!!.name)
"--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register.toString()) "--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register!!.name)
} }
stmt.target.identifier != null -> { stmt.target.identifier != null -> {
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
@@ -1496,7 +1499,7 @@ internal class Compiler(private val rootModule: Module,
// convert value to target datatype if possible // convert value to target datatype if possible
// @todo use convertType()???? // @todo use convertType()????
when(targetDt) { when(targetDt) {
DataType.UBYTE, DataType.BYTE -> in ByteDatatypes ->
if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE) if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE)
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.WORD -> { DataType.WORD -> {
@@ -1532,24 +1535,15 @@ internal class Compiler(private val rootModule: Module,
else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") else -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
} }
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
null -> throw CompilerException("could not determine targetdt") else -> throw CompilerException("weird/unknonwn targetdt")
} }
} }
if(stmt.aug_op!=null) if(stmt.aug_op!=null)
throw CompilerException("augmented assignment should have been converted to regular assignment already") throw CompilerException("augmented assignment should have been converted to regular assignment already")
if(stmt.value is FunctionCall) {
val sub = (stmt.value as FunctionCall).target.targetStatement(namespace)
if(sub is Subroutine && sub.asmReturnvaluesRegisters.isNotEmpty()) {
// the subroutine call returns its values in registers
storeRegisterIntoTarget(sub.asmReturnvaluesRegisters.single(), assignTarget, stmt)
return
}
}
// pop the result value back into the assignment target // pop the result value back into the assignment target
val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!! val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!!
popValueIntoTarget(assignTarget, datatype) popValueIntoTarget(assignTarget, datatype)
@@ -1581,6 +1575,7 @@ internal class Compiler(private val rootModule: Module,
private fun translateMultiReturnAssignment(stmt: Assignment) { private fun translateMultiReturnAssignment(stmt: Assignment) {
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace) val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace)
if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) { if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) {
// TODO check correctness of multi-return values (they should be on the stack rather than directly assigned!)
// we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values // we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values
// for now, we only support multiple return values as long as they're returned in registers as well. // for now, we only support multiple return values as long as they're returned in registers as well.
if(targetStmt.asmReturnvaluesRegisters.isEmpty()) if(targetStmt.asmReturnvaluesRegisters.isEmpty())
@@ -1667,7 +1662,7 @@ internal class Compiler(private val rootModule: Module,
} }
} else throw CompilerException("invalid assignment target type ${target::class}") } else throw CompilerException("invalid assignment target type ${target::class}")
} }
assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.toString()) assignTarget.register != null -> prog.instr(Opcode.POP_VAR_BYTE, callLabel = assignTarget.register.name)
assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it assignTarget.arrayindexed != null -> translate(assignTarget.arrayindexed, true) // write value to it
assignTarget.memoryAddress != null -> { assignTarget.memoryAddress != null -> {
val address = assignTarget.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue val address = assignTarget.memoryAddress?.addressExpression?.constValue(namespace, heap)?.asIntegerValue
@@ -1703,7 +1698,7 @@ internal class Compiler(private val rootModule: Module,
if(loop.loopRegister!=null) { if(loop.loopRegister!=null) {
val reg = loop.loopRegister val reg = loop.loopRegister
loopVarName = reg.toString() loopVarName = reg.name
loopVarDt = DataType.UBYTE loopVarDt = DataType.UBYTE
} else { } else {
val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl) val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl)
@@ -1768,7 +1763,7 @@ internal class Compiler(private val rootModule: Module,
} }
private fun translateForOverIterableVar(loop: ForLoop, loopvarDt: DataType, iterableValue: LiteralValue) { private fun translateForOverIterableVar(loop: ForLoop, loopvarDt: DataType, iterableValue: LiteralValue) {
if(loopvarDt==DataType.UBYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY_UB)) if(loopvarDt==DataType.UBYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_S, DataType.ARRAY_UB))
throw CompilerException("loop variable type doesn't match iterableValue type") throw CompilerException("loop variable type doesn't match iterableValue type")
else if(loopvarDt==DataType.UWORD && iterableValue.type != DataType.ARRAY_UW) else if(loopvarDt==DataType.UWORD && iterableValue.type != DataType.ARRAY_UW)
throw CompilerException("loop variable type doesn't match iterableValue type") throw CompilerException("loop variable type doesn't match iterableValue type")
@@ -1777,10 +1772,7 @@ internal class Compiler(private val rootModule: Module,
val numElements: Int val numElements: Int
when(iterableValue.type) { when(iterableValue.type) {
DataType.UBYTE, DataType.BYTE, !in IterableDatatypes -> throw CompilerException("non-iterableValue type")
DataType.UWORD, DataType.WORD,
DataType.FLOAT -> throw CompilerException("non-iterableValue type")
DataType.STR_P, DataType.STR_PS -> throw CompilerException("can't iterate string type ${iterableValue.type}")
DataType.STR, DataType.STR_S -> { DataType.STR, DataType.STR_S -> {
numElements = iterableValue.strvalue(heap).length numElements = iterableValue.strvalue(heap).length
if(numElements>255) throw CompilerException("string length > 255") if(numElements>255) throw CompilerException("string length > 255")
@@ -1794,6 +1786,7 @@ internal class Compiler(private val rootModule: Module,
numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize
if(numElements>255) throw CompilerException("string length > 255") if(numElements>255) throw CompilerException("string length > 255")
} }
else -> throw CompilerException("weird datatype")
} }
if(loop.loopRegister!=null && loop.loopRegister==Register.X) if(loop.loopRegister!=null && loop.loopRegister==Register.X)
@@ -2036,15 +2029,15 @@ internal class Compiler(private val rootModule: Module,
postIncr.linkParents(body) postIncr.linkParents(body)
translate(postIncr) translate(postIncr)
if(lvTarget.register!=null) if(lvTarget.register!=null)
prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString()) prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.name)
else { else {
val opcode = opcodePushvar(targetStatement!!.datatype) val opcode = opcodePushvar(targetStatement!!.datatype)
prog.instr(opcode, callLabel = targetStatement.scopedname) prog.instr(opcode, callLabel = targetStatement.scopedname)
} }
// TODO: optimize this to use a compare + branch opcode somehow? // TODO: optimize this to use a compare + branch opcode somehow?
val conditionJumpOpcode = when(targetStatement!!.datatype) { val conditionJumpOpcode = when(targetStatement!!.datatype) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget") else -> throw CompilerException("invalid loopvar datatype (expected byte or word) $lvTarget")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)
@@ -2095,8 +2088,8 @@ internal class Compiler(private val rootModule: Module,
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.condition) translate(stmt.condition)
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ in ByteDatatypes -> Opcode.JNZ
DataType.UWORD, DataType.WORD -> Opcode.JNZW in WordDatatypes -> Opcode.JNZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)
@@ -2132,8 +2125,8 @@ internal class Compiler(private val rootModule: Module,
prog.label(continueLabel) prog.label(continueLabel)
translate(stmt.untilCondition) translate(stmt.untilCondition)
val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) { val conditionJumpOpcode = when(stmt.untilCondition.resultingDatatype(namespace, heap)) {
DataType.UBYTE, DataType.BYTE -> Opcode.JZ in ByteDatatypes -> Opcode.JZ
DataType.UWORD, DataType.WORD -> Opcode.JZW in WordDatatypes -> Opcode.JZW
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt") else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
} }
prog.instr(conditionJumpOpcode, callLabel = loopLabel) prog.instr(conditionJumpOpcode, callLabel = loopLabel)

View File

@@ -20,8 +20,8 @@ abstract class Zeropage(protected val options: CompilationOptions) {
val size = val size =
when (datatype) { when (datatype) {
DataType.UBYTE, DataType.BYTE -> 1 in ByteDatatypes -> 1
DataType.UWORD, DataType.WORD -> 2 in WordDatatypes -> 2
DataType.FLOAT -> { DataType.FLOAT -> {
if (options.floats) { if (options.floats) {
if(position!=null) if(position!=null)

View File

@@ -23,10 +23,10 @@ open class Instruction(val opcode: Opcode,
} }
opcode in opcodesWithVarArgument -> { opcode in opcodesWithVarArgument -> {
// opcodes that manipulate a variable // opcodes that manipulate a variable
"${opcode.toString().toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd() "${opcode.name.toLowerCase()} ${callLabel?:""} ${callLabel2?:""}".trimEnd()
} }
callLabel==null -> "${opcode.toString().toLowerCase()} $argStr" callLabel==null -> "${opcode.name.toLowerCase()} $argStr"
else -> "${opcode.toString().toLowerCase()} $callLabel $argStr" else -> "${opcode.name.toLowerCase()} $callLabel $argStr"
} }
.trimEnd() .trimEnd()

View File

@@ -389,20 +389,20 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
when(decl.type) { when(decl.type) {
VarDeclType.VAR -> { VarDeclType.VAR -> {
val value = when(decl.datatype) { val value = when(decl.datatype) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!) in NumericDatatypes -> Value(decl.datatype, (decl.value as LiteralValue).asNumericValue!!)
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
val litval = (decl.value as LiteralValue) val litval = (decl.value as LiteralValue)
if(litval.heapId==null) if(litval.heapId==null)
throw CompilerException("string should already be in the heap") throw CompilerException("string should already be in the heap")
Value(decl.datatype, litval.heapId) Value(decl.datatype, litval.heapId)
} }
DataType.ARRAY_B, DataType.ARRAY_W, in ArrayDatatypes -> {
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F -> {
val litval = (decl.value as LiteralValue) val litval = (decl.value as LiteralValue)
if(litval.heapId==null) if(litval.heapId==null)
throw CompilerException("array should already be in the heap") throw CompilerException("array should already be in the heap")
Value(decl.datatype, litval.heapId) Value(decl.datatype, litval.heapId)
} }
else -> throw CompilerException("weird datatype")
} }
currentBlock.variables[scopedname] = value currentBlock.variables[scopedname] = value
if(decl.zeropage) if(decl.zeropage)
@@ -462,11 +462,11 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
heap.allEntries().forEach { heap.allEntries().forEach {
when { when {
it.value.str!=null -> it.value.str!=null ->
out.println("${it.key} ${it.value.type.toString().toLowerCase()} \"${escape(it.value.str!!)}\"") out.println("${it.key} ${it.value.type.name.toLowerCase()} \"${escape(it.value.str!!)}\"")
it.value.array!=null -> it.value.array!=null ->
out.println("${it.key} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}") out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.array!!.toList()}")
it.value.doubleArray!=null -> it.value.doubleArray!=null ->
out.println("${it.key} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}") out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.doubleArray!!.toList()}")
else -> throw CompilerException("invalid heap entry $it") else -> throw CompilerException("invalid heap entry $it")
} }
} }
@@ -477,12 +477,12 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
out.println("%variables") out.println("%variables")
for(variable in blk.variables) { for(variable in blk.variables) {
val valuestr = variable.value.toString() val valuestr = variable.value.toString()
out.println("${variable.key} ${variable.value.type.toString().toLowerCase()} $valuestr") out.println("${variable.key} ${variable.value.type.name.toLowerCase()} $valuestr")
} }
out.println("%end_variables") out.println("%end_variables")
out.println("%memorypointers") out.println("%memorypointers")
for(iconst in blk.memoryPointers) { for(iconst in blk.memoryPointers) {
out.println("${iconst.key} ${iconst.value.second.toString().toLowerCase()} uw:${iconst.value.first.toString(16)}") out.println("${iconst.key} ${iconst.value.second.name.toLowerCase()} uw:${iconst.value.first.toString(16)}")
} }
out.println("%end_memorypointers") out.println("%end_memorypointers")
out.println("%instructions") out.println("%instructions")

View File

@@ -79,8 +79,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun numericValue(): Number { fun numericValue(): Number {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> byteval!! in ByteDatatypes -> byteval!!
DataType.UWORD, DataType.WORD -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> floatval!! DataType.FLOAT -> floatval!!
else -> throw ValueException("invalid datatype for numeric value: $type") else -> throw ValueException("invalid datatype for numeric value: $type")
} }
@@ -88,8 +88,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun integerValue(): Int { fun integerValue(): Int {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> byteval!!.toInt() in ByteDatatypes -> byteval!!.toInt()
DataType.UWORD, DataType.WORD -> wordval!! in WordDatatypes -> wordval!!
DataType.FLOAT -> throw ValueException("float to integer loss of precision") DataType.FLOAT -> throw ValueException("float to integer loss of precision")
else -> throw ValueException("invalid datatype for integer value: $type") else -> throw ValueException("invalid datatype for integer value: $type")
} }
@@ -393,8 +393,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
fun msb(): Value { fun msb(): Value {
return when(type) { return when(type) {
DataType.UBYTE, DataType.BYTE -> Value(DataType.UBYTE, 0) in ByteDatatypes -> Value(DataType.UBYTE, 0)
DataType.UWORD, DataType.WORD -> Value(DataType.UBYTE, wordval!! ushr 8 and 255) in WordDatatypes -> Value(DataType.UBYTE, wordval!! ushr 8 and 255)
else -> throw ValueException("msb can only work on (u)byte/(u)word") else -> throw ValueException("msb can only work on (u)byte/(u)word")
} }
} }
@@ -428,7 +428,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
} }
DataType.UWORD -> { DataType.UWORD -> {
when (targetType) { when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255) in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> this DataType.UWORD -> this
DataType.WORD -> { DataType.WORD -> {
if(integerValue()<=32767) if(integerValue()<=32767)
@@ -442,7 +442,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
} }
DataType.WORD -> { DataType.WORD -> {
when (targetType) { when (targetType) {
DataType.BYTE, DataType.UBYTE -> Value(DataType.UBYTE, integerValue() and 255) in ByteDatatypes -> Value(DataType.UBYTE, integerValue() and 255)
DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535) DataType.UWORD -> Value(DataType.UWORD, integerValue() and 65535)
DataType.WORD -> this DataType.WORD -> this
DataType.FLOAT -> Value(DataType.FLOAT, numericValue()) DataType.FLOAT -> Value(DataType.FLOAT, numericValue())

View File

@@ -16,9 +16,6 @@ import kotlin.math.abs
class AssemblyError(msg: String) : RuntimeException(msg) class AssemblyError(msg: String) : RuntimeException(msg)
// TODO: code generation for POW instruction
class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues, val zeropage: Zeropage) { class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues, val zeropage: Zeropage) {
private val globalFloatConsts = mutableMapOf<Double, String>() private val globalFloatConsts = mutableMapOf<Double, String>()
private val assemblyLines = mutableListOf<String>() private val assemblyLines = mutableListOf<String>()
@@ -76,7 +73,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
} }
fun compileToAssembly(): AssemblyProgram { fun compileToAssembly(optimize: Boolean): AssemblyProgram {
println("Generating assembly code from intermediate code... ") println("Generating assembly code from intermediate code... ")
assemblyLines.clear() assemblyLines.clear()
@@ -84,10 +81,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
for(b in program.blocks) for(b in program.blocks)
block2asm(b) block2asm(b)
if(optimize) {
var optimizationsDone = 1 var optimizationsDone = 1
while (optimizationsDone > 0) { while (optimizationsDone > 0) {
optimizationsDone = optimizeAssembly(assemblyLines) optimizationsDone = optimizeAssembly(assemblyLines)
} }
}
File("${program.name}.asm").printWriter().use { File("${program.name}.asm").printWriter().use {
for (line in assemblyLines) { it.println(line) } for (line in assemblyLines) { it.println(line) }
@@ -294,10 +293,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
DataType.UWORD -> out("${v.first}\t.word 0") DataType.UWORD -> out("${v.first}\t.word 0")
DataType.WORD -> out("${v.first}\t.sint 0") DataType.WORD -> out("${v.first}\t.sint 0")
DataType.FLOAT -> out("${v.first}\t.byte 0,0,0,0,0 ; float") DataType.FLOAT -> out("${v.first}\t.byte 0,0,0,0,0 ; float")
DataType.STR, DataType.STR, DataType.STR_S -> {
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> {
val rawStr = heap.get(v.second.heapId).str!! val rawStr = heap.get(v.second.heapId).str!!
val bytes = encodeStr(rawStr, v.second.type).map { "$" + it.toString(16).padStart(2, '0') } val bytes = encodeStr(rawStr, v.second.type).map { "$" + it.toString(16).padStart(2, '0') }
out("${v.first}\t; ${v.second.type} \"${escape(rawStr)}\"") out("${v.first}\t; ${v.second.type} \"${escape(rawStr)}\"")
@@ -361,24 +357,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
} }
private fun encodeStr(str: String, dt: DataType): List<Short> { private fun encodeStr(str: String, dt: DataType): List<Short> {
when(dt) { return when(dt) {
DataType.STR -> { DataType.STR -> {
val bytes = Petscii.encodePetscii(str, true) val bytes = Petscii.encodePetscii(str, true)
return bytes.plus(0) bytes.plus(0)
}
DataType.STR_P -> {
val result = listOf(str.length.toShort())
val bytes = Petscii.encodePetscii(str, true)
return result.plus(bytes)
} }
DataType.STR_S -> { DataType.STR_S -> {
val bytes = Petscii.encodeScreencode(str, true) val bytes = Petscii.encodeScreencode(str, true)
return bytes.plus(0) bytes.plus(0)
}
DataType.STR_PS -> {
val result = listOf(str.length.toShort())
val bytes = Petscii.encodeScreencode(str, true)
return result.plus(bytes)
} }
else -> throw AssemblyError("invalid str type") else -> throw AssemblyError("invalid str type")
} }
@@ -515,8 +501,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Syscall.FUNC_MAX_F, Syscall.FUNC_MAX_F,
Syscall.FUNC_MIN_F, Syscall.FUNC_MIN_F,
Syscall.FUNC_AVG_F, Syscall.FUNC_AVG_F,
Syscall.FUNC_SUM_F -> " jsr c64flt.${call.toString().toLowerCase()}" Syscall.FUNC_SUM_F -> " jsr c64flt.${call.name.toLowerCase()}"
else -> " jsr prog8_lib.${call.toString().toLowerCase()}" null -> ""
else -> " jsr prog8_lib.${call.name.toLowerCase()}"
} }
} }
Opcode.BREAKPOINT -> { Opcode.BREAKPOINT -> {
@@ -887,30 +874,20 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.IDIV_W -> " jsr prog8_lib.idiv_w" Opcode.IDIV_W -> " jsr prog8_lib.idiv_w"
Opcode.IDIV_UW -> " jsr prog8_lib.idiv_uw" Opcode.IDIV_UW -> " jsr prog8_lib.idiv_uw"
Opcode.AND_BYTE -> { Opcode.AND_BYTE -> " jsr prog8_lib.and_b"
""" Opcode.OR_BYTE -> " jsr prog8_lib.or_b"
lda ${(ESTACK_LO + 2).toHex()},x Opcode.XOR_BYTE -> " jsr prog8_lib.xor_b"
and ${(ESTACK_LO + 1).toHex()},x Opcode.AND_WORD -> " jsr prog8_lib.and_w"
inx Opcode.OR_WORD -> " jsr prog8_lib.or_w"
sta ${(ESTACK_LO + 1).toHex()},x Opcode.XOR_WORD -> " jsr prog8_lib.xor_w"
"""
} Opcode.BITAND_BYTE -> " jsr prog8_lib.bitand_b"
Opcode.OR_BYTE -> { Opcode.BITOR_BYTE -> " jsr prog8_lib.bitor_b"
""" Opcode.BITXOR_BYTE -> " jsr prog8_lib.bitxor_b"
lda ${(ESTACK_LO + 2).toHex()},x Opcode.BITAND_WORD -> " jsr prog8_lib.bitand_w"
ora ${(ESTACK_LO + 1).toHex()},x Opcode.BITOR_WORD -> " jsr prog8_lib.bitor_w"
inx Opcode.BITXOR_WORD -> " jsr prog8_lib.bitxor_w"
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.XOR_BYTE -> {
"""
lda ${(ESTACK_LO + 2).toHex()},x
eor ${(ESTACK_LO + 1).toHex()},x
inx
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.REMAINDER_UB -> " jsr prog8_lib.remainder_ub" Opcode.REMAINDER_UB -> " jsr prog8_lib.remainder_ub"
Opcode.REMAINDER_UW -> " jsr prog8_lib.remainder_uw" Opcode.REMAINDER_UW -> " jsr prog8_lib.remainder_uw"
@@ -3327,44 +3304,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
null null
}, },
// 16 bit addition avoiding excessive stack usage // @todo optimize 8 and 16 bit adds and subs (avoid stack use altogether on most common operations)
// @todo optimize 8 and 16 bit adds and subs even more with longer asmpatterns (avoid stack use altogether on most common operations)
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.ADD_UW),
listOf(Opcode.PUSH_VAR_WORD, Opcode.ADD_W)) { segment ->
"""
clc
lda ${segment[0].callLabel}
adc ${(ESTACK_LO+1).toHex()},x
sta ${(ESTACK_LO+1).toHex()},x
lda ${segment[0].callLabel}+1
adc ${(ESTACK_HI+1).toHex()},x
sta ${(ESTACK_HI+1).toHex()},x
"""
},
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.ADD_UW),
listOf(Opcode.PUSH_MEM_W, Opcode.ADD_W)) { segment ->
"""
clc
lda ${hexVal(segment[0])}
adc ${(ESTACK_LO + 1).toHex()},x
sta ${(ESTACK_LO + 1).toHex()},x
lda ${hexValPlusOne(segment[0])}
adc ${(ESTACK_HI + 1).toHex()},x
sta ${(ESTACK_HI + 1).toHex()},x
"""
},
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.ADD_UW),
listOf(Opcode.PUSH_WORD, Opcode.ADD_W)) { segment ->
"""
clc
lda #<${hexVal(segment[0])}
adc ${(ESTACK_LO+1).toHex()},x
sta ${(ESTACK_LO+1).toHex()},x
lda #>${hexVal(segment[0])}
adc ${(ESTACK_HI+1).toHex()},x
sta ${(ESTACK_HI+1).toHex()},x
"""
},
AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.CMP_B), listOf(Opcode.PUSH_VAR_BYTE, Opcode.CMP_UB)) { segment -> AsmPattern(listOf(Opcode.PUSH_VAR_BYTE, Opcode.CMP_B), listOf(Opcode.PUSH_VAR_BYTE, Opcode.CMP_UB)) { segment ->
// this pattern is encountered as part of the loop bound condition in for loops (var + cmp + jz/jnz) // this pattern is encountered as part of the loop bound condition in for loops (var + cmp + jz/jnz)

View File

@@ -30,6 +30,7 @@ val BuiltinFunctions = mapOf(
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args "sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
"abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument "abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
// normal functions follow: // normal functions follow:
"sin" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sin) }, "sin" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sin) },
"sin8" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ), "sin8" to FunctionSignature(true, listOf(BuiltinFunctionParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ),
@@ -53,7 +54,6 @@ val BuiltinFunctions = mapOf(
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::round) }, "round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::round) },
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::floor) }, "floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::floor) },
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::ceil) }, "ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArgOutputWord(a, p, n, h, Math::ceil) },
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", IterableDatatypes)), DataType.UWORD, ::builtinLen),
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }}, "any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }}, "all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
"lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }}, "lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }},
@@ -70,15 +70,16 @@ val BuiltinFunctions = mapOf(
"clear_carry" to FunctionSignature(false, emptyList(), null), "clear_carry" to FunctionSignature(false, emptyList(), null),
"set_irqd" to FunctionSignature(false, emptyList(), null), "set_irqd" to FunctionSignature(false, emptyList(), null),
"clear_irqd" to FunctionSignature(false, emptyList(), null), "clear_irqd" to FunctionSignature(false, emptyList(), null),
"read_flags" to FunctionSignature(false, emptyList(), DataType.UBYTE),
"swap" to FunctionSignature(false, listOf(BuiltinFunctionParam("first", NumericDatatypes), BuiltinFunctionParam("second", NumericDatatypes)), null), "swap" to FunctionSignature(false, listOf(BuiltinFunctionParam("first", NumericDatatypes), BuiltinFunctionParam("second", NumericDatatypes)), null),
"memcopy" to FunctionSignature(false, listOf( "memcopy" to FunctionSignature(false, listOf(
BuiltinFunctionParam("from", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("from", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("to", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("to", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("numbytes", IntegerDatatypes)), null), BuiltinFunctionParam("numbytes", setOf(DataType.UBYTE))), null),
"memset" to FunctionSignature(false, listOf( "memset" to FunctionSignature(false, listOf(
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)), BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)),
BuiltinFunctionParam("bytevalue", setOf(DataType.UBYTE, DataType.BYTE))), null), BuiltinFunctionParam("bytevalue", ByteDatatypes)), null),
"memsetw" to FunctionSignature(false, listOf( "memsetw" to FunctionSignature(false, listOf(
BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)),
BuiltinFunctionParam("numwords", setOf(DataType.UWORD)), BuiltinFunctionParam("numwords", setOf(DataType.UWORD)),
@@ -126,14 +127,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
if(arglist is IdentifierReference) { if(arglist is IdentifierReference) {
val dt = arglist.resultingDatatype(namespace, heap) val dt = arglist.resultingDatatype(namespace, heap)
return when(dt) { return when(dt) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT, in NumericDatatypes -> dt!!
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt in StringDatatypes -> dt!!
DataType.ARRAY_UB -> DataType.UBYTE DataType.ARRAY_UB -> DataType.UBYTE
DataType.ARRAY_B -> DataType.BYTE DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
null -> throw FatalAstException("function '$function' requires one argument which is an iterable") else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
} }
} }
throw FatalAstException("function '$function' requires one argument which is an iterable") throw FatalAstException("function '$function' requires one argument which is an iterable")
@@ -148,8 +149,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
"abs" -> { "abs" -> {
val dt = args.single().resultingDatatype(namespace, heap) val dt = args.single().resultingDatatype(namespace, heap)
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE in ByteDatatypes -> DataType.UBYTE
DataType.UWORD, DataType.WORD -> DataType.UWORD in WordDatatypes -> DataType.UWORD
DataType.FLOAT -> DataType.FLOAT DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("weird datatype passed to abs $dt") else -> throw FatalAstException("weird datatype passed to abs $dt")
} }
@@ -157,13 +158,14 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
"max", "min" -> { "max", "min" -> {
val dt = datatypeFromIterableArg(args.single()) val dt = datatypeFromIterableArg(args.single())
when(dt) { when(dt) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> dt in NumericDatatypes -> dt
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UBYTE in StringDatatypes -> DataType.UBYTE
DataType.ARRAY_UB -> DataType.UBYTE DataType.ARRAY_UB -> DataType.UBYTE
DataType.ARRAY_B -> DataType.BYTE DataType.ARRAY_B -> DataType.BYTE
DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
else -> null
} }
} }
"sum" -> { "sum" -> {
@@ -175,9 +177,15 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD DataType.ARRAY_UB, DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD DataType.ARRAY_B, DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT DataType.ARRAY_F -> DataType.FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UWORD in StringDatatypes -> DataType.UWORD
else -> null
} }
} }
"len" -> {
// a length can be >255 so in that case, the result is an UWORD instead of an UBYTE
// but to avoid a lot of code duplication we simply assume UWORD in all cases for now
return DataType.UWORD
}
else -> return null else -> return null
} }
} }
@@ -295,7 +303,7 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
} }
private fun builtinLen(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { private fun builtinLen(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
// note: in some cases the length is > 255 and so we have to return a UWORD type instead of a byte. // note: in some cases the length is > 255 and then we have to return a UWORD type instead of a UBYTE.
if(args.size!=1) if(args.size!=1)
throw SyntaxError("len requires one argument", position) throw SyntaxError("len requires one argument", position)
var argument = args[0].constValue(namespace, heap) var argument = args[0].constValue(namespace, heap)
@@ -312,23 +320,22 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).arraysize val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).arraysize
if(arraySize>256) if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${argument.position}") throw CompilerException("array length exceeds byte limit ${argument.position}")
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position) LiteralValue.optimalInteger(arraySize, args[0].position)
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).arraysize val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).arraysize
if(arraySize>256) if(arraySize>256)
throw CompilerException("array length exceeds byte limit ${argument.position}") throw CompilerException("array length exceeds byte limit ${argument.position}")
LiteralValue(DataType.UWORD, wordvalue=arraySize, position=args[0].position) LiteralValue.optimalInteger(arraySize, args[0].position)
} }
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
val str = argument.strvalue(heap) val str = argument.strvalue(heap)
if(str.length>255) if(str.length>255)
throw CompilerException("string length exceeds byte limit ${argument.position}") throw CompilerException("string length exceeds byte limit ${argument.position}")
LiteralValue(DataType.UWORD, wordvalue=str.length, position=args[0].position) LiteralValue.optimalInteger(str.length, args[0].position)
} }
DataType.UBYTE, DataType.BYTE, in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
DataType.UWORD, DataType.WORD, else -> throw CompilerException("weird datatype")
DataType.FLOAT -> throw SyntaxError("len of weird argument ${args[0]}", position)
} }
} }

View File

@@ -534,7 +534,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
if(literalValue.strvalue(heap).length !in 1..255) if(literalValue.strvalue(heap).length !in 1..255)
addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position)) addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position))
else { else {
val heapId = heap.add(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_P etc... val heapId = heap.add(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_S etc...
val newValue = LiteralValue(literalValue.type, heapId = heapId, position = literalValue.position) val newValue = LiteralValue(literalValue.type, heapId = heapId, position = literalValue.position)
return super.process(newValue) return super.process(newValue)
} }

View File

@@ -75,7 +75,7 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
val leftDt = expr.left.resultingDatatype(namespace, heap) val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap) val rightDt = expr.right.resultingDatatype(namespace, heap)
if (leftDt != null && rightDt != null && leftDt != rightDt) { if (leftDt != null && rightDt != null && leftDt != rightDt) {
// try to convert a datatype into the other // try to convert a datatype into the other (where ddd
if (adjustDatatypes(expr, leftVal, leftDt, rightVal, rightDt)) { if (adjustDatatypes(expr, leftVal, leftDt, rightVal, rightDt)) {
optimizationsDone++ optimizationsDone++
return expr return expr
@@ -347,26 +347,37 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
} }
if(leftConstVal==null && rightConstVal!=null) { if(leftConstVal==null && rightConstVal!=null) {
if(isBiggerType(leftDt, rightDt)) {
val (adjusted, newValue) = adjust(rightConstVal, leftDt) val (adjusted, newValue) = adjust(rightConstVal, leftDt)
if (adjusted) { if (adjusted) {
expr.right = newValue expr.right = newValue
optimizationsDone++ optimizationsDone++
return true return true
} }
}
return false return false
} else if(leftConstVal!=null && rightConstVal==null) { } else if(leftConstVal!=null && rightConstVal==null) {
if(isBiggerType(rightDt, leftDt)) {
val (adjusted, newValue) = adjust(leftConstVal, rightDt) val (adjusted, newValue) = adjust(leftConstVal, rightDt)
if (adjusted) { if (adjusted) {
expr.left = newValue expr.left = newValue
optimizationsDone++ optimizationsDone++
return true return true
} }
}
return false return false
} else { } else {
return false return false // two const values, don't adjust (should have been const-folded away)
} }
} }
private fun isBiggerType(type: DataType, other: DataType) =
when(type) {
in ByteDatatypes -> false
in WordDatatypes -> other in ByteDatatypes
else -> true
}
private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?) private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?)

View File

@@ -5,7 +5,6 @@ import prog8.ast.*
import prog8.compiler.LauncherType import prog8.compiler.LauncherType
import prog8.compiler.OutputType import prog8.compiler.OutputType
import prog8.determineCompilationOptions import prog8.determineCompilationOptions
import java.io.File
import java.io.InputStream import java.io.InputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path

View File

@@ -1,8 +1,6 @@
package prog8.stackvm package prog8.stackvm
import prog8.ast.DataType import prog8.ast.*
import prog8.ast.Position
import prog8.ast.unescape
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.compiler.intermediate.* import prog8.compiler.intermediate.*
import java.io.File import java.io.File
@@ -88,10 +86,7 @@ class Program (val name: String,
} }
heapvalues.sortedBy { it.first }.forEach { heapvalues.sortedBy { it.first }.forEach {
when(it.second) { when(it.second) {
DataType.STR, DataType.STR, DataType.STR_S -> heap.add(it.second, unescape(it.third.substring(1, it.third.length-1), Position("<stackvmsource>", 0, 0, 0)))
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> heap.add(it.second, unescape(it.third.substring(1, it.third.length-1), Position("<stackvmsource>", 0, 0, 0)))
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_B,
DataType.ARRAY_UW, DataType.ARRAY_W -> { DataType.ARRAY_UW, DataType.ARRAY_W -> {
val numbers = it.third.substring(1, it.third.length-1).split(',') val numbers = it.third.substring(1, it.third.length-1).split(',')
@@ -103,7 +98,8 @@ class Program (val name: String,
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray() val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
heap.add(it.second, doublearray) heap.add(it.second, doublearray)
} }
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("invalid heap value type ${it.second}") in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}")
else -> throw VmExecutionException("weird datatype")
} }
} }
} }
@@ -200,7 +196,7 @@ class Program (val name: String,
DataType.UWORD -> Value(DataType.UWORD, valueStr.substring(3).toInt(16)) DataType.UWORD -> Value(DataType.UWORD, valueStr.substring(3).toInt(16))
DataType.WORD -> Value(DataType.WORD, valueStr.substring(2).toInt(16)) DataType.WORD -> Value(DataType.WORD, valueStr.substring(2).toInt(16))
DataType.FLOAT -> Value(DataType.FLOAT, valueStr.substring(2).toDouble()) DataType.FLOAT -> Value(DataType.FLOAT, valueStr.substring(2).toDouble())
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { in StringDatatypes -> {
if(valueStr.startsWith('"') && valueStr.endsWith('"')) if(valueStr.startsWith('"') && valueStr.endsWith('"'))
throw VmExecutionException("encountered a var with a string value, but all string values should already have been moved into the heap") throw VmExecutionException("encountered a var with a string value, but all string values should already have been moved into the heap")
else if(!valueStr.startsWith("heap:")) else if(!valueStr.startsWith("heap:"))
@@ -210,11 +206,7 @@ class Program (val name: String,
Value(type, heapId) Value(type, heapId)
} }
} }
DataType.ARRAY_UB, in ArrayDatatypes -> {
DataType.ARRAY_B,
DataType.ARRAY_UW,
DataType.ARRAY_W,
DataType.ARRAY_F -> {
if(!valueStr.startsWith("heap:")) if(!valueStr.startsWith("heap:"))
throw VmExecutionException("invalid array value, should be a heap reference") throw VmExecutionException("invalid array value, should be a heap reference")
else { else {
@@ -222,6 +214,7 @@ class Program (val name: String,
Value(type, heapId) Value(type, heapId)
} }
} }
else -> throw VmExecutionException("weird datatype")
} }
vars[name] = value vars[name] = value
} }

View File

@@ -49,9 +49,7 @@ enum class Syscall(val callNr: Short) {
FUNC_RNDW(90), // push a random word on the stack FUNC_RNDW(90), // push a random word on the stack
FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0) FUNC_RNDF(91), // push a random float on the stack (between 0.0 and 1.0)
FUNC_LEN_STR(105), FUNC_LEN_STR(105),
FUNC_LEN_STRP(106), FUNC_LEN_STRS(106),
FUNC_LEN_STRS(107),
FUNC_LEN_STRPS(108),
FUNC_ANY_B(109), FUNC_ANY_B(109),
FUNC_ANY_W(110), FUNC_ANY_W(110),
FUNC_ANY_F(111), FUNC_ANY_F(111),
@@ -80,7 +78,8 @@ enum class Syscall(val callNr: Short) {
FUNC_SUM_F(134), FUNC_SUM_F(134),
FUNC_MEMCOPY(138), FUNC_MEMCOPY(138),
FUNC_MEMSET(139), FUNC_MEMSET(139),
FUNC_MEMSETW(140) FUNC_MEMSETW(140),
FUNC_READ_FLAGS(141)
// note: not all builtin functions of the Prog8 language are present as functions: // note: not all builtin functions of the Prog8 language are present as functions:
// some of them are straight opcodes (such as MSB, LSB, LSL, LSR, ROL_BYTE, ROR, ROL2, ROR2, and FLT)! // some of them are straight opcodes (such as MSB, LSB, LSL, LSR, ROL_BYTE, ROR, ROL2, ROR2, and FLT)!
@@ -922,9 +921,9 @@ class StackVm(private var traceOutputFile: String?) {
} }
Opcode.POP_VAR_WORD -> { Opcode.POP_VAR_WORD -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) checkDt(value, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_S)
val variable = getVar(ins.callLabel!!) val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS) checkDt(variable, DataType.UWORD, DataType.WORD, DataType.STR, DataType.STR_S)
if(value.type!=variable.type) if(value.type!=variable.type)
throw VmExecutionException("datatype mismatch") throw VmExecutionException("datatype mismatch")
variables[ins.callLabel] = value variables[ins.callLabel] = value
@@ -1322,7 +1321,7 @@ class StackVm(private var traceOutputFile: String?) {
when (array.type) { when (array.type) {
DataType.ARRAY_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index])) DataType.ARRAY_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index]))
DataType.ARRAY_B -> evalstack.push(Value(DataType.BYTE, array.array!![index])) DataType.ARRAY_B -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0])) DataType.STR, DataType.STR_S -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
else -> throw VmExecutionException("not a proper array/string variable with byte elements") else -> throw VmExecutionException("not a proper array/string variable with byte elements")
} }
} }
@@ -1413,10 +1412,7 @@ class StackVm(private var traceOutputFile: String?) {
when (array.type) { when (array.type) {
DataType.ARRAY_UB -> array.array!![index] = value.integerValue() DataType.ARRAY_UB -> array.array!![index] = value.integerValue()
DataType.ARRAY_B -> array.array!![index] = value.integerValue() DataType.ARRAY_B -> array.array!![index] = value.integerValue()
DataType.STR, DataType.STR, DataType.STR_S -> {
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> {
val chars = array.str!!.toCharArray() val chars = array.str!!.toCharArray()
chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0] chars[index] = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
heap.update(variable.heapId, chars.joinToString("")) heap.update(variable.heapId, chars.joinToString(""))
@@ -1608,11 +1604,19 @@ class StackVm(private var traceOutputFile: String?) {
Syscall.FUNC_RND -> evalstack.push(Value(DataType.UBYTE, rnd.nextInt() and 255)) Syscall.FUNC_RND -> evalstack.push(Value(DataType.UBYTE, rnd.nextInt() and 255))
Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.UWORD, rnd.nextInt() and 65535)) Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.UWORD, rnd.nextInt() and 65535))
Syscall.FUNC_RNDF -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble())) Syscall.FUNC_RNDF -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble()))
Syscall.FUNC_LEN_STR, Syscall.FUNC_LEN_STRS, Syscall.FUNC_LEN_STRP, Syscall.FUNC_LEN_STRPS -> { Syscall.FUNC_LEN_STR, Syscall.FUNC_LEN_STRS -> {
val strPtr = evalstack.pop().integerValue() val strPtr = evalstack.pop().integerValue()
val text = heap.get(strPtr).str!! val text = heap.get(strPtr).str!!
evalstack.push(Value(DataType.UBYTE, text.length)) evalstack.push(Value(DataType.UBYTE, text.length))
} }
Syscall.FUNC_READ_FLAGS -> {
val carry = if(P_carry) 1 else 0
val zero = if(P_zero) 2 else 0
val irqd = if(P_irqd) 4 else 0
val negative = if(P_negative) 128 else 0
val flags = carry or zero or irqd or negative
evalstack.push(Value(DataType.UBYTE, flags))
}
Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_SIN8 -> { Syscall.FUNC_SIN8 -> {

View File

@@ -4,7 +4,10 @@ import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.empty import org.hamcrest.Matchers.empty
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import prog8.ast.ByteDatatypes
import prog8.ast.DataType import prog8.ast.DataType
import prog8.ast.IterableDatatypes
import prog8.ast.WordDatatypes
import prog8.compiler.HeapValues import prog8.compiler.HeapValues
import prog8.compiler.intermediate.Instruction import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Opcode
@@ -1234,12 +1237,11 @@ class TestStackVmOpcodes {
private fun pushOpcode(dt: DataType): Opcode { private fun pushOpcode(dt: DataType): Opcode {
return when (dt) { return when (dt) {
DataType.UBYTE, DataType.BYTE -> Opcode.PUSH_BYTE in ByteDatatypes -> Opcode.PUSH_BYTE
DataType.UWORD, DataType.WORD -> Opcode.PUSH_WORD in WordDatatypes -> Opcode.PUSH_WORD
in IterableDatatypes -> Opcode.PUSH_WORD
DataType.FLOAT -> Opcode.PUSH_FLOAT DataType.FLOAT -> Opcode.PUSH_FLOAT
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, else -> throw IllegalArgumentException("invalid datatype")
DataType.ARRAY_UB, DataType.ARRAY_UW, DataType.ARRAY_F,
DataType.ARRAY_B, DataType.ARRAY_W -> Opcode.PUSH_WORD
} }
} }

View File

@@ -82,7 +82,6 @@ class TestStackVmValue {
fun testEqualsAndNotEqualsHeapTypes() fun testEqualsAndNotEqualsHeapTypes()
{ {
assertTrue(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 999))) assertTrue(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 999)))
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR_P, 999)))
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 222))) assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 222)))
assertTrue(sameValueAndType(Value(DataType.ARRAY_UB, 99), Value(DataType.ARRAY_UB, 99))) assertTrue(sameValueAndType(Value(DataType.ARRAY_UB, 99), Value(DataType.ARRAY_UB, 99)))

View File

@@ -5,7 +5,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/build" /> <excludeFolder url="file://$MODULE_DIR$/build" />
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.7 (py3)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -187,9 +187,13 @@ Values will usually be part of an expression or assignment statement::
byte counter = 42 ; variable of size 8 bits, with initial value 42 byte counter = 42 ; variable of size 8 bits, with initial value 42
.. todo:: *zeropage tag:*
There must be a way to tell the compiler which variables you require to be in Zeropage: If you add the ``@zp`` tag to the variable declaration, the compiler will prioritize this variable
``zeropage`` modifier keyword on vardecl perhaps? when selecting variables to put into zero page. If there are enough free locations in the zeropage,
it will then try to fill it with as much other variables as possible (before they will be put in regular memory pages).
Example::
byte @zp zeropageCounter = 42
Variables that represent CPU hardware registers Variables that represent CPU hardware registers
@@ -321,6 +325,11 @@ be set to zero only for the first run of the program. A second run will utilize
where it left off (but your code will be a bit smaller because no initialization instructions where it left off (but your code will be a bit smaller because no initialization instructions
are generated) are generated)
.. caution::
variables that get allocated in zero-page will *not* have a zero starting value when you omit
the variable's initialization. They'll be whatever the last value in that zero page
location was. So it's best to don't depend on the uninitialized starting value!
.. warning:: .. warning::
this behavior may change in a future version so that subsequent runs always this behavior may change in a future version so that subsequent runs always
use the same initial values use the same initial values
@@ -462,11 +471,7 @@ There are various built-in functions such as sin(), cos(), min(), max() that can
You can also reference idendifiers defined elsewhere in your code. You can also reference idendifiers defined elsewhere in your code.
.. attention:: .. attention::
**Data type conversion (during calculations) and floating point handling:** **Floating points used in expressions:**
BYTE values used in arithmetic expressions (calculations) will be automatically converted into WORD values
if the calculation needs that to store the resulting value. Once a WORD value is used, all other results will be WORDs as well
(there's no automatic conversion of WORD into BYTE).
When a floating point value is used in a calculation, the result will be a floating point, and byte or word values When a floating point value is used in a calculation, the result will be a floating point, and byte or word values
will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating will be automatically converted into floats in this case. The compiler will issue a warning though when this happens, because floating
@@ -494,6 +499,28 @@ Usually the normal precedence rules apply (``*`` goes before ``+`` etc.) but sub
within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20, within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20,
and ``(true or false) and false`` is false instead of true. and ``(true or false) and false`` is false instead of true.
.. attention::
**calculations keep their datatype:**
When you do calculations on a BYTE type, the result will remain a BYTE.
When you do calculations on a WORD type, the result will remain a WORD.
For instance::
byte b = 44
word w = b*55 ; the result will be 116! (even though the target variable is a word)
w *= 999 ; the result will be -15188 (the multiplication stays within a word)
The compiler will NOT give a warning about this! It's doing this for
performance reasons - so you won't get sudden 16 bit (or even float)
calculations where you needed only simple fast byte arithmetic.
If you do need the extended resulting value, cast at least one of the
operands of an operator to the larger datatype. For example::
byte b = 44
word w = b*55.w ; the result will be 2420
w = (b as word)*55 ; same result
Subroutines Subroutines
----------- -----------
@@ -517,7 +544,9 @@ will issue a warning then telling you the result values of a subroutine call are
subroutines are *non-reentrant*. This means you cannot create recursive calls. subroutines are *non-reentrant*. This means you cannot create recursive calls.
If you do need a recursive algorithm, you'll have to hand code it in embedded assembly for now, If you do need a recursive algorithm, you'll have to hand code it in embedded assembly for now,
or rewrite it into an iterative algorithm. or rewrite it into an iterative algorithm.
Also, subroutines used in the main program should not be used from an IRQ handler. Also, subroutines used in the main program should not be used from an IRQ handler. This is because
the subroutine may be interrupted, and will then call itself from the IRQ handler. Results are
then undefined because the variables will get overwritten.
.. _builtinfunctions: .. _builtinfunctions:
@@ -708,3 +737,19 @@ rsave()
rrestore() rrestore()
Restores the CPU registers and the status flags from previously saved values. Restores the CPU registers and the status flags from previously saved values.
read_flags()
Returns the current value of the CPU status register.
Library routines
----------------
There are many routines available in the compiler libraries.
Some are used internally by the compiler as well.
There's too many to list here, just have a look through the source code
of the library modules to see what's there.
(They can be found in the compiler/res directory)
The example programs also use a small set of the library routines, you can study
their source code to see how they might be used.

View File

@@ -213,9 +213,11 @@ Variable declarations
Variables should be declared with their exact type and size so the compiler can allocate storage Variables should be declared with their exact type and size so the compiler can allocate storage
for them. You must give them an initial value as well. That value can be a simple literal value, for them. You must give them an initial value as well. That value can be a simple literal value,
or an expression. The syntax is:: or an expression. You can add a ``@zp`` zeropage-tag, to tell the compiler to prioritize it
when selecting variables to be put into zeropage.
The syntax is::
<datatype> <variable name> [ = <initial value> ] <datatype> [ @zp ] <variable name> [ = <initial value> ]
Various examples:: Various examples::
@@ -228,6 +230,8 @@ Various examples::
byte[5] values = [11, 22, 33, 44, 55] byte[5] values = [11, 22, 33, 44, 55]
byte[5] values = 255 ; initialize with five 255 bytes byte[5] values = 255 ; initialize with five 255 bytes
word @zp zpword = 9999 ; prioritize this when selecting vars for zeropage storage
Data types Data types
@@ -254,12 +258,8 @@ type identifier type storage size example var declara
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]`` ``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
``str`` string (petscii) varies ``str myvar = "hello."`` ``str`` string (petscii) varies ``str myvar = "hello."``
implicitly terminated by a 0-byte implicitly terminated by a 0-byte
``str_p`` pascal-string (petscii) varies ``str_p myvar = "hello."``
implicit first byte = length, no 0-byte
``str_s`` string (screencodes) varies ``str_s myvar = "hello."`` ``str_s`` string (screencodes) varies ``str_s myvar = "hello."``
implicitly terminated by a 0-byte implicitly terminated by a 0-byte
``str_ps`` pascal-string varies ``str_ps myvar = "hello."``
(screencodes) implicit first byte = length, no 0-byte
=============== ======================= ================= ========================================= =============== ======================= ================= =========================================
**arrays:** you can split an array initializer list over several lines if you want. **arrays:** you can split an array initializer list over several lines if you want.
@@ -361,8 +361,13 @@ Operators
--------- ---------
.. todo:: .. todo::
address-of: ``#`` address-of: ``#`` or ``&`` (to stay close to C)
Takes the address of the symbol following it: ``word address = #somevar`` Takes the address of the symbol following it: ``word address = &somevar``
Perhaps requires an explicit pointer type as well instead of just word?
This can replace the ``memory`` var decl prefix as well, instead of
``memory uword var = $c000`` we could write ``&uword var = $c000``
arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%`` arithmetic: ``+`` ``-`` ``*`` ``/`` ``**`` ``%``
@@ -510,6 +515,13 @@ And this is a loop over the values of the array ``fibonacci_numbers`` where the
} }
You can inline the loop variable declaration in the for statement, including optional zp-tag::
for ubyte @zp fastindex in 10 to 20 {
; do something
}
while loop while loop
^^^^^^^^^^ ^^^^^^^^^^

View File

@@ -117,7 +117,8 @@ The following 6502 CPU hardware registers are directly usable in program code (a
- ``A``, ``X``, ``Y`` the three main cpu registers (8 bits) - ``A``, ``X``, ``Y`` the three main cpu registers (8 bits)
- the status register (P) carry flag and interrupt disable flag can be written via a couple of special - the status register (P) carry flag and interrupt disable flag can be written via a couple of special
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``) builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``),
and read via the ``read_flags()`` function.
However, you must assume that the 3 hardware registers ``A``, ``X`` and ``Y`` However, you must assume that the 3 hardware registers ``A``, ``X`` and ``Y``
are volatile. Their values cannot be depended upon, the compiler will use them as required. are volatile. Their values cannot be depended upon, the compiler will use them as required.
@@ -144,3 +145,35 @@ Arguments and result values are passed via global variables stored in memory
*These are not allocated on a stack* so it is not possible to create recursive calls! *These are not allocated on a stack* so it is not possible to create recursive calls!
The result value(s) of a subroutine are returned on the evaluation stack, The result value(s) of a subroutine are returned on the evaluation stack,
to make it possible to use subroutines in expressions. to make it possible to use subroutines in expressions.
IRQ Handling
============
Normally, the system's default IRQ handling is not interfered with.
You can however install your own IRQ handler.
This is possible ofcourse by doing it all using customized inline assembly,
but there are a few library routines available to make setting up C-64 IRQs and raster IRQs a lot easier (no assembly code required).
These routines are::
c64utils.set_irqvec()
c64utils.set_irqvec_excl()
c64utils.set_rasterirq( <raster line> )
c64utils.set_rasterirq_excl( <raster line> )
c64utils.restore_irqvec() ; set it back to the systems default irq handler
If you activate an IRQ handler with one of these, it expects the handler to be defined
as a subroutine ``irq`` in the module ``irq`` so like this::
~ irq {
sub irq() {
; ... irq handling here ...
}
}
.. todo::
@todo the irq handler should use its own eval-stack to avoid stack interference issues

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,18 @@
~ main {
sub start() {
if A>10 {
A=44
while true {
;derp
}
} else {
gameover:
goto gameover
}
}
}

View File

@@ -1,6 +1,8 @@
%import c64lib %import c64lib
%import c64utils %import c64utils
%import c64flt %import c64flt
%zeropage basicsafe
~ main { ~ main {
const uword width = 30 const uword width = 30

View File

@@ -4,25 +4,31 @@
~ main { ~ main {
ubyte[256] sieve ubyte[256] sieve
ubyte candidate_prime = 2 ubyte candidate_prime = 2 ; is increased in the loop
sub start() { sub start() {
memset(sieve, 256, false) ; clear the sieve memset(sieve, 256, false) ; clear the sieve, to reset starting situation on subsequent runs
; calculate primes ; calculate primes
c64scr.print("prime numbers up to 255:\n\n") c64scr.print("prime numbers up to 255:\n\n")
ubyte amount=0
while true { while true {
ubyte prime = find_next_prime() ubyte prime = find_next_prime()
if prime==0 if prime==0
break break
c64scr.print_ub(prime) c64scr.print_ub(prime)
c64scr.print(", ") c64scr.print(", ")
amount++
} }
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print("number of primes (expected 54): ")
c64scr.print_ub(amount)
c64.CHROUT('\n')
} }
sub find_next_prime() -> ubyte { sub find_next_prime() -> ubyte {
while sieve[candidate_prime] { while sieve[candidate_prime] {
candidate_prime++ candidate_prime++
if candidate_prime==0 if candidate_prime==0
@@ -31,7 +37,7 @@
; found next one, mark the multiples and return it. ; found next one, mark the multiples and return it.
sieve[candidate_prime] = true sieve[candidate_prime] = true
uword multiple = candidate_prime**2 uword multiple = candidate_prime
while multiple < len(sieve) { while multiple < len(sieve) {
sieve[lsb(multiple)] = true sieve[lsb(multiple)] = true
multiple += candidate_prime multiple += candidate_prime

View File

@@ -1,100 +1,636 @@
; TehTriz - a Tetris clone.
;
; features:
; holding area
; wall kick rotations
; shows next piece
; staged speed increase
; some simple sound effects
;
; @todo show ghost?
~ main { ~ main {
const ubyte boardOffsetX = 14 const ubyte boardOffsetX = 14
const ubyte boardOffsetY = 3 const ubyte boardOffsetY = 3
const ubyte boardWidth = 10 const ubyte boardWidth = 10
const ubyte boardHeight = 20 const ubyte boardHeight = 20
const ubyte startXpos = boardOffsetX + 3
const ubyte startYpos = boardOffsetY - 2
uword lines
uword score
ubyte xpos
ubyte ypos
ubyte nextBlock
ubyte speedlevel
ubyte holding
ubyte holdingAllowed
; 3x3, rotating around their center square:
ubyte[4] blockJ = [0, 4, 5, 6]
ubyte[4] blockL = [2, 4, 5, 6]
ubyte[4] blockS = [1, 2, 4, 5]
ubyte[4] blockT = [1, 4, 5, 6]
ubyte[4] blockZ = [0, 1, 5, 6]
;4x4, rotating around center:
ubyte[4] blockI = [4, 5, 6, 7]
ubyte[4] blockO = [1, 2, 5, 6]
; block colors I, J, L, O, S, T, Z: cyan, blue, orange, yellow, green, purple, red
ubyte[7] blockColors = [3, 6, 8, 7, 5, 4, 2]
ubyte[7] blockSizes = [4, 3, 3, 4, 3, 3, 3] ; needed for proper rotation? (or just use block num?)
ubyte[16] currentBlock
ubyte currentBlockSize ; 3 or 4
ubyte currentBlockNum
sub start() { sub start() {
@(650) = 128 ; set all keys to repeat
sound.init()
newGame()
drawBoard() drawBoard()
gameOver()
for ubyte b in 7 to 0 step -1 { newgame:
newCurrentBlock(b) newGame()
drawBlock(3, 2+b*3, 102) ; 102 = stipple drawBoard()
drawBlock(boardOffsetX+3, 1+b*3, 160) ; 160 = block, 32 = erase (space) spawnNextBlock()
waitkey:
if c64.TIME_LO>=(60-4*speedlevel) {
c64.TIME_LO = 0
drawBlock(xpos, ypos, 32) ; hide block
if blocklogic.noCollision(xpos, ypos+1) {
; slowly move the block down
ypos++
drawBlock(xpos, ypos, 160) ; show block on new position
} else {
; block can't move further down!
; check if the game area is full, if not, spawn the next block at the top.
if blocklogic.isGameOver(xpos, ypos) {
gameOver()
goto newgame
} else {
sound.blockrotate()
checkForLines()
spawnNextBlock()
score++
}
} }
while(true) { drawScore()
; loop
} }
ubyte key=c64.GETIN()
if key==0 goto waitkey
keypress(key)
goto waitkey
}
sub keypress(ubyte key) {
if key==157 or key==',' {
; move left
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos-1, ypos) {
xpos--
}
drawBlock(xpos, ypos, 160)
}
else if key==29 or key=='/' {
; move right
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos+1, ypos) {
xpos++
}
drawBlock(xpos, ypos, 160)
}
else if key==17 or key=='.' {
; move down faster
drawBlock(xpos, ypos, 32)
if blocklogic.noCollision(xpos, ypos+1) {
ypos++
}
drawBlock(xpos, ypos, 160)
}
else if key==145 or key==' ' {
; drop down immediately
drawBlock(xpos, ypos, 32)
ubyte dropypos
for dropypos in ypos+1 to boardOffsetY+boardHeight-1 {
if not blocklogic.noCollision(xpos, dropypos) {
dropypos-- ; the furthest down that still fits
break
}
}
if dropypos>ypos {
ypos = dropypos
sound.blockdrop()
drawBlock(xpos, ypos, 160)
checkForLines()
spawnNextBlock()
score++
drawScore()
}
}
else if key=='z' { ; no joystick equivalent (there is only 1 fire button)
; rotate counter clockwise
drawBlock(xpos, ypos, 32)
if blocklogic.canRotateCCW(xpos, ypos) {
blocklogic.rotateCCW()
sound.blockrotate()
}
else if blocklogic.canRotateCCW(xpos-1, ypos) {
xpos--
blocklogic.rotateCCW()
sound.blockrotate()
}
else if blocklogic.canRotateCCW(xpos+1, ypos) {
xpos++
blocklogic.rotateCCW()
sound.blockrotate()
}
drawBlock(xpos, ypos, 160)
}
else if key=='x' {
; rotate clockwise
drawBlock(xpos, ypos, 32)
if blocklogic.canRotateCW(xpos, ypos) {
blocklogic.rotateCW()
sound.blockrotate()
}
else if blocklogic.canRotateCW(xpos-1, ypos) {
xpos--
blocklogic.rotateCW()
sound.blockrotate()
}
else if blocklogic.canRotateCW(xpos+1, ypos) {
xpos++
blocklogic.rotateCW()
sound.blockrotate()
}
drawBlock(xpos, ypos, 160)
}
else if key=='c' {
; hold
if holdingAllowed {
sound.swapping()
if holding<7 {
drawBlock(xpos, ypos, 32)
ubyte newholding = blocklogic.currentBlockNum
swapBlock(holding)
holding = newholding
holdingAllowed = false
} else {
holding = blocklogic.currentBlockNum
drawBlock(xpos, ypos, 32)
spawnNextBlock()
}
drawHoldBlock()
}
}
}
sub checkForLines() {
; check if line(s) are full -> flash/clear line(s) + add score + move rest down
ubyte[boardHeight] complete_lines
ubyte num_lines=0
memset(complete_lines, len(complete_lines), 0)
for ubyte linepos in boardOffsetY to boardOffsetY+boardHeight-1 {
if blocklogic.isLineFull(linepos) {
complete_lines[num_lines]=linepos
num_lines++
for ubyte x in boardOffsetX to boardOffsetX+boardWidth-1
c64scr.setcc(x, linepos, 160, 1)
}
}
if num_lines {
if num_lines>3
sound.lineclear_big()
else
sound.lineclear()
c64.TIME_LO=0
while c64.TIME_LO<20 {
; slight delay to flash the line
}
c64.TIME_LO=0
for ubyte linepos in complete_lines
if linepos and blocklogic.isLineFull(linepos)
blocklogic.collapse(linepos)
lines += num_lines
uword[4] scores = [10, 25, 50, 100] ; can never clear more than 4 lines
score += scores[num_lines-1]
speedlevel = 1+lsb(lines/10)
drawScore()
}
}
sub gameOver() {
sound.gameover()
c64scr.PLOT(7, 7)
c64.CHROUT('U')
c64scr.print("────────────────────────")
c64.CHROUT('I')
c64scr.PLOT(7, 8)
c64scr.print("│*** g a m e o v e r ***│")
c64scr.PLOT(7, 9)
c64.CHROUT('J')
c64scr.print("────────────────────────")
c64.CHROUT('K')
c64scr.PLOT(7, 18)
c64.CHROUT('U')
c64scr.print("────────────────────────")
c64.CHROUT('I')
c64scr.PLOT(7, 19)
c64scr.print("│ f1 for new game │")
c64scr.PLOT(7, 20)
c64.CHROUT('J')
c64scr.print("────────────────────────")
c64.CHROUT('K')
while(c64.GETIN()!=133) {
; endless loop until user presses F1 to restart the game
}
}
sub newGame() {
lines = 0
score = 0
xpos = startXpos
ypos = startYpos
speedlevel = 1
nextBlock = rnd() % 7
holding = 255
holdingAllowed = true
}
sub swapBlock(ubyte newblock) {
c64.TIME_LO = 0
blocklogic.newCurrentBlock(newblock)
xpos = startXpos
ypos = startYpos
drawBlock(xpos, ypos, 160)
}
sub spawnNextBlock() {
swapBlock(nextBlock)
nextBlock = (rnd() + c64.RASTER) % 7
drawNextBlock()
holdingAllowed = true
} }
sub drawBoard() { sub drawBoard() {
c64.CLEARSCR()
c64.COLOR = 7
c64scr.PLOT(1,1) c64scr.PLOT(1,1)
c64scr.print("irmen's")
c64scr.PLOT(2,2)
c64scr.print("teh▁triz") c64scr.print("teh▁triz")
c64.COLOR = 5
c64scr.PLOT(6,4)
c64scr.print("hold:")
c64scr.PLOT(2,22)
c64scr.print("speed: ")
c64scr.PLOT(28,3)
c64scr.print("next:")
c64scr.PLOT(28,10)
c64scr.print("lines:")
c64scr.PLOT(28,14)
c64scr.print("score:")
c64.COLOR = 12
c64scr.PLOT(27,18)
c64scr.print("controls:")
c64.COLOR = 11
c64scr.PLOT(28,19)
c64scr.print(",/ move")
c64scr.PLOT(28,20)
c64scr.print("zx rotate")
c64scr.PLOT(29,21)
c64scr.print(". descend")
c64scr.PLOT(27,22)
c64scr.print("spc drop")
c64scr.PLOT(29,23)
c64scr.print("c hold")
c64scr.setcc(boardOffsetX-1, boardOffsetY-2, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX-1, boardOffsetY-3, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-2, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-3, 255, 0) ; invisible barrier
c64scr.setcc(boardOffsetX-1, boardOffsetY-1, 108, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-1, 123, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY-1, 123, 12)
c64scr.setcc(boardOffsetX-1, boardOffsetY+boardHeight, 124, 12) c64scr.setcc(boardOffsetX-1, boardOffsetY+boardHeight, 124, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY+boardHeight, 126, 12) c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY+boardHeight, 126, 12)
ubyte i ubyte i
for i in boardOffsetX+boardWidth-1 to boardOffsetX step -1 for i in boardOffsetX+boardWidth-1 to boardOffsetX step -1 {
c64scr.setcc(i, boardOffsetY-3, 255, 0) ; invisible barrier
c64scr.setcc(i, boardOffsetY+boardHeight, 69, 11) c64scr.setcc(i, boardOffsetY+boardHeight, 69, 11)
}
for i in boardOffsetY+boardHeight-1 to boardOffsetY step -1 { for i in boardOffsetY+boardHeight-1 to boardOffsetY step -1 {
c64scr.setcc(boardOffsetX-1, i, 89, 11) c64scr.setcc(boardOffsetX-1, i, 89, 11)
c64scr.setcc(boardOffsetX+boardWidth, i, 84, 11) c64scr.setcc(boardOffsetX+boardWidth, i, 84, 11)
} }
ubyte[5] colors = [6,8,7,5,4]
for i in len(colors)-1 to 0 step -1 {
for ubyte x in 5 to 0 step -1 {
c64scr.setcc(6+x-i, 11+2*i, 102, colors[i])
}
}
drawScore()
} }
sub drawScore() {
c64.COLOR=1
c64scr.PLOT(30,11)
c64scr.print_uw(lines)
c64scr.PLOT(30,15)
c64scr.print_uw(score)
c64scr.PLOT(9,22)
c64scr.print_ub(speedlevel)
}
sub newCurrentBlock(ubyte block) { sub drawNextBlock() {
memset(currentBlock, len(currentBlock), 0) const ubyte nextBlockXpos = 29
currentBlockNum = block const ubyte nextBlockYpos = 5
currentBlockSize = blockSizes[block] for ubyte x in nextBlockXpos+3 to nextBlockXpos step -1 {
c64scr.setcc(x, nextBlockYpos, ' ', 0)
c64scr.setcc(x, nextBlockYpos+1, ' ', 0)
}
; @todo would be nice to have an explicit pointer type to reference the array, and code the loop only once... ; reuse the normal block draw routine (because we can't manipulate array pointers yet)
ubyte blockCol = blockColors[block] ubyte prev = blocklogic.currentBlockNum
ubyte i blocklogic.newCurrentBlock(nextBlock)
if block==0 { ; I drawBlock(nextBlockXpos, nextBlockYpos, 160)
for i in blockI blocklogic.newCurrentBlock(prev)
currentBlock[i] = blockCol
} }
else if block==1 { ; J
for i in blockJ sub drawHoldBlock() {
currentBlock[i] = blockCol const ubyte holdBlockXpos = 7
const ubyte holdBlockYpos = 6
for ubyte x in holdBlockXpos+3 to holdBlockXpos step -1 {
c64scr.setcc(x, holdBlockYpos, '@', 0)
c64scr.setcc(x, holdBlockYpos+1, '@', 0)
} }
else if block==2 { ; L if holding < 7 {
for i in blockL ; reuse the normal block draw routine (because we can't manipulate array pointers yet)
currentBlock[i] = blockCol ubyte prev = blocklogic.currentBlockNum
} blocklogic.newCurrentBlock(holding)
else if block==3 { ; O drawBlock(holdBlockXpos, holdBlockYpos, 160)
for i in blockO blocklogic.newCurrentBlock(prev)
currentBlock[i] = blockCol
}
else if block==4 { ; S
for i in blockS
currentBlock[i] = blockCol
}
else if block==5 { ; T
for i in blockT
currentBlock[i] = blockCol
}
else if block==6 { ; Z
for i in blockZ
currentBlock[i] = blockCol
} }
} }
sub drawBlock(ubyte x, ubyte y, ubyte character) { sub drawBlock(ubyte x, ubyte y, ubyte character) {
for ubyte i in 15 to 0 step -1 { for ubyte i in 15 to 0 step -1 {
ubyte c=currentBlock[i] ubyte c=blocklogic.currentBlock[i]
if c if c
c64scr.setcc((i&3)+x, (i/4)+y, character, c) c64scr.setcc((i&3)+x, (i/4)+y, character, c)
} }
} }
} }
~ blocklogic {
ubyte currentBlockNum
ubyte[16] currentBlock
ubyte[16] rotated
; the 7 tetrominos
ubyte[16] blockI = [0,0,0,0, ; cyan ; note: special rotation (around matrix center)
3,3,3,3,
0,0,0,0,
0,0,0,0]
ubyte[16] blockJ = [6,0,0,0, ; blue
6,6,6,0,
0,0,0,0,
0,0,0,0]
ubyte[16] blockL = [0,0,8,0, ; orange
8,8,8,0,
0,0,0,0,
0,0,0,0]
ubyte[16] blockO = [0,7,7,0, ; yellow ; note: no rotation (square)
0,7,7,0,
0,0,0,0,
0,0,0,0]
ubyte[16] blockS = [0,5,5,0, ; green
5,5,0,0,
0,0,0,0,
0,0,0,0]
ubyte[16] blockT = [0,4,0,0, ; purple
4,4,4,0,
0,0,0,0,
0,0,0,0]
ubyte[16] blockZ = [2,2,0,0, ; red
0,2,2,0,
0,0,0,0,
0,0,0,0]
; @todo would be nice to have a pointer type, like so:
; uword[7] blocks = [&blockI, &blockJ, &blockL, &blockO, &blockS, &blockT, &blockZ]
sub newCurrentBlock(ubyte block) {
currentBlockNum = block
if block==0
memcopy(blockI, currentBlock, len(currentBlock))
else if block==1
memcopy(blockJ, currentBlock, len(currentBlock))
else if block==2
memcopy(blockL, currentBlock, len(currentBlock))
else if block==3
memcopy(blockO, currentBlock, len(currentBlock))
else if block==4
memcopy(blockS, currentBlock, len(currentBlock))
else if block==5
memcopy(blockT, currentBlock, len(currentBlock))
else if block==6
memcopy(blockZ, currentBlock, len(currentBlock))
}
sub rotateCW() {
; rotates the current block clockwise.
if currentBlockNum==0 {
; the 'I' block rotates a 4x4 matrix around the center
rotated[0] = currentBlock[12]
rotated[1] = currentBlock[8]
rotated[2] = currentBlock[4]
rotated[3] = currentBlock[0]
rotated[4] = currentBlock[13]
rotated[5] = currentBlock[9]
rotated[6] = currentBlock[5]
rotated[7] = currentBlock[1]
rotated[8] = currentBlock[14]
rotated[9] = currentBlock[10]
rotated[10] = currentBlock[6]
rotated[11] = currentBlock[2]
rotated[12] = currentBlock[15]
rotated[13] = currentBlock[11]
rotated[14] = currentBlock[7]
rotated[15] = currentBlock[3]
memcopy(rotated, currentBlock, len(currentBlock))
}
else if currentBlockNum!=3 {
; rotate all blocks (except 3, the square) around their center square in a 3x3 matrix
memset(rotated, len(rotated), 0)
rotated[0] = currentBlock[8]
rotated[1] = currentBlock[4]
rotated[2] = currentBlock[0]
rotated[4] = currentBlock[9]
rotated[5] = currentBlock[5]
rotated[6] = currentBlock[1]
rotated[8] = currentBlock[10]
rotated[9] = currentBlock[6]
rotated[10] = currentBlock[2]
memcopy(rotated, currentBlock, len(currentBlock))
}
}
sub rotateCCW() {
; rotates the current block counterclockwise.
if currentBlockNum==0 {
; the 'I' block rotates a 4x4 matrix around the center
rotated[0] = currentBlock[3]
rotated[1] = currentBlock[7]
rotated[2] = currentBlock[11]
rotated[3] = currentBlock[15]
rotated[4] = currentBlock[2]
rotated[5] = currentBlock[6]
rotated[6] = currentBlock[10]
rotated[7] = currentBlock[14]
rotated[8] = currentBlock[1]
rotated[9] = currentBlock[5]
rotated[10] = currentBlock[9]
rotated[11] = currentBlock[13]
rotated[12] = currentBlock[0]
rotated[13] = currentBlock[4]
rotated[14] = currentBlock[8]
rotated[15] = currentBlock[12]
memcopy(rotated, currentBlock, len(currentBlock))
}
else if currentBlockNum!=3 {
; rotate all blocks (except 3, the square) around their center square in a 3x3 matrix
memset(rotated, len(rotated), 0)
rotated[0] = currentBlock[2]
rotated[1] = currentBlock[6]
rotated[2] = currentBlock[10]
rotated[4] = currentBlock[1]
rotated[5] = currentBlock[5]
rotated[6] = currentBlock[9]
rotated[8] = currentBlock[0]
rotated[9] = currentBlock[4]
rotated[10] = currentBlock[8]
memcopy(rotated, currentBlock, len(currentBlock))
}
}
; For movement checking it is not needed to clamp the x/y coordinates,
; because we have to check for brick collisions anyway.
; The full play area is bordered by (in)visible characters that will collide.
; Collision is determined by reading the screen data directly.
sub canRotateCW(ubyte xpos, ubyte ypos) -> ubyte {
rotateCW()
ubyte nocollision = noCollision(xpos, ypos)
rotateCCW()
return nocollision
}
sub canRotateCCW(ubyte xpos, ubyte ypos) -> ubyte {
rotateCCW()
ubyte nocollision = noCollision(xpos, ypos)
rotateCW()
return nocollision
}
sub noCollision(ubyte xpos, ubyte ypos) -> ubyte {
for ubyte i in 15 to 0 step -1 {
if currentBlock[i] and c64scr.getchr(xpos + (i&3), ypos+i/4)!=32
return false
}
return true
}
sub isGameOver(ubyte xpos, ubyte ypos) -> ubyte {
main.drawBlock(xpos, ypos, 32)
ubyte result = ypos==main.startYpos and not noCollision(xpos, ypos+1)
main.drawBlock(xpos, ypos, 160)
return result
}
sub isLineFull(ubyte ypos) -> ubyte {
for ubyte x in main.boardOffsetX to main.boardOffsetX+main.boardWidth-1 {
if c64scr.getchr(x, ypos)==32
return false
}
return true
}
sub collapse(ubyte ypos) {
while(ypos>main.startYpos+1) {
for ubyte x in main.boardOffsetX+main.boardWidth-1 to main.boardOffsetX step -1 {
ubyte char = c64scr.getchr(x, ypos-1)
ubyte color = c64scr.getclr(x, ypos-1)
c64scr.setcc(x, ypos, char, color)
}
ypos--
}
}
}
~ sound {
sub init() {
c64.MVOL = 15
}
sub blockrotate() {
; soft click
c64.MVOL = 5
c64.AD1 = %00100010
c64.SR1 = %00000000
c64.FREQ1 = 15600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
sub blockdrop() {
; swish
c64.MVOL = 5
c64.AD1 = %01010111
c64.SR1 = %00000000
c64.FREQ1 = 4600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
sub swapping() {
; beep
c64.MVOL = 8
c64.AD1 = %01010111
c64.SR1 = %00000000
c64.FREQ1 = 5500
c64.CR1 = %00010000
c64.CR1 = %00010001
}
sub lineclear() {
; explosion
c64.MVOL = 15
c64.AD1 = %01100110
c64.SR1 = %00000000
c64.FREQ1 = 1600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
sub lineclear_big() {
; big explosion
c64.MVOL = 15
c64.AD1 = %01101010
c64.SR1 = %00000000
c64.FREQ1 = 2600
c64.CR1 = %10000000
c64.CR1 = %10000001
}
sub gameover() {
; buzz
c64.MVOL = 15
c64.FREQ2 = 600
c64.AD2 = %00111010
c64.SR2 = %00000000
c64.CR2 = %00110000
c64.CR2 = %00110001
}
}

View File

@@ -3,40 +3,10 @@
~ main { ~ main {
; mul_word_3 ; @todo see problem in looplabelproblem.p8
; @todo compiler error for using literal values other than 0 or 1 with boolean expressions
sub start() { sub start() {
byte b1
byte b2 = -3
ubyte ub1
ubyte ub2 = 4
word w1
word w2 = -499
uword uw1
uword uw2 = 1199
b1 = b2*40
ub1 = ub2*40
w1 = w2*40
uw1 = uw2*40
c64scr.print_b(b1)
c64.CHROUT('\n')
c64scr.print_ub(ub1)
c64.CHROUT('\n')
c64scr.print_w(w1)
c64.CHROUT('\n')
c64scr.print_uw(uw1)
c64.CHROUT('\n')
c64.CHROUT('\n')
c64scr.print_ub(X)
c64.CHROUT('\n')
} }
} }

View File

@@ -111,7 +111,7 @@ constdecl: 'const' varinitializer ;
memoryvardecl: 'memory' varinitializer; memoryvardecl: 'memory' varinitializer;
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_p' | 'str_s' | 'str_ps' ; datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_s' ;
arrayspec: '[' expression ']' ; arrayspec: '[' expression ']' ;

View File

@@ -8,7 +8,9 @@ repositories {
} }
dependencies { dependencies {
antlr 'org.antlr:antlr4:4.7.2' antlr('org.antlr:antlr4:4.7.2') {
exclude group: 'com.ibm.icu', module: 'icu4j'
}
} }
compileJava { compileJava {

View File

@@ -1,4 +1,4 @@
// Generated from prog8.g4 by ANTLR 4.7.2 // Generated from ./parser/antlr/prog8.g4 by ANTLR 4.7.2
package prog8.parser; package prog8.parser;
@@ -34,10 +34,9 @@ public class prog8Lexer extends Lexer {
T__87=88, T__88=89, T__89=90, T__90=91, T__91=92, T__92=93, T__93=94, T__87=88, T__88=89, T__89=90, T__90=91, T__91=92, T__92=93, T__93=94,
T__94=95, T__95=96, T__96=97, T__97=98, T__98=99, T__99=100, T__100=101, T__94=95, T__95=96, T__96=97, T__97=98, T__98=99, T__99=100, T__100=101,
T__101=102, T__102=103, T__103=104, T__104=105, T__105=106, T__106=107, T__101=102, T__102=103, T__103=104, T__104=105, T__105=106, T__106=107,
T__107=108, T__108=109, T__109=110, T__110=111, T__111=112, LINECOMMENT=113, T__107=108, T__108=109, T__109=110, LINECOMMENT=111, COMMENT=112, WS=113,
COMMENT=114, WS=115, EOL=116, NAME=117, DEC_INTEGER=118, HEX_INTEGER=119, EOL=114, NAME=115, DEC_INTEGER=116, HEX_INTEGER=117, BIN_INTEGER=118,
BIN_INTEGER=120, FLOAT_NUMBER=121, STRING=122, INLINEASMBLOCK=123, SINGLECHAR=124, FLOAT_NUMBER=119, STRING=120, INLINEASMBLOCK=121, SINGLECHAR=122, ZEROPAGE=123;
ZEROPAGE=125;
public static String[] channelNames = { public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN" "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
}; };
@@ -61,10 +60,10 @@ public class prog8Lexer extends Lexer {
"T__81", "T__82", "T__83", "T__84", "T__85", "T__86", "T__87", "T__88", "T__81", "T__82", "T__83", "T__84", "T__85", "T__86", "T__87", "T__88",
"T__89", "T__90", "T__91", "T__92", "T__93", "T__94", "T__95", "T__96", "T__89", "T__90", "T__91", "T__92", "T__93", "T__94", "T__95", "T__96",
"T__97", "T__98", "T__99", "T__100", "T__101", "T__102", "T__103", "T__104", "T__97", "T__98", "T__99", "T__100", "T__101", "T__102", "T__103", "T__104",
"T__105", "T__106", "T__107", "T__108", "T__109", "T__110", "T__111", "T__105", "T__106", "T__107", "T__108", "T__109", "LINECOMMENT", "COMMENT",
"LINECOMMENT", "COMMENT", "WS", "EOL", "NAME", "DEC_INTEGER", "HEX_INTEGER", "WS", "EOL", "NAME", "DEC_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER",
"BIN_INTEGER", "FLOAT_NUMBER", "FNUMBER", "STRING_ESCAPE_SEQ", "STRING", "FNUMBER", "STRING_ESCAPE_SEQ", "STRING", "INLINEASMBLOCK", "SINGLECHAR",
"INLINEASMBLOCK", "SINGLECHAR", "ZEROPAGE" "ZEROPAGE"
}; };
} }
public static final String[] ruleNames = makeRuleNames(); public static final String[] ruleNames = makeRuleNames();
@@ -74,19 +73,19 @@ public class prog8Lexer extends Lexer {
null, "'~'", "':'", "'goto'", "'%output'", "'%launcher'", "'%zeropage'", null, "'~'", "':'", "'goto'", "'%output'", "'%launcher'", "'%zeropage'",
"'%zpreserved'", "'%address'", "'%import'", "'%breakpoint'", "'%asminclude'", "'%zpreserved'", "'%address'", "'%import'", "'%breakpoint'", "'%asminclude'",
"'%asmbinary'", "'%option'", "','", "'='", "'const'", "'memory'", "'ubyte'", "'%asmbinary'", "'%option'", "','", "'='", "'const'", "'memory'", "'ubyte'",
"'byte'", "'uword'", "'word'", "'float'", "'str'", "'str_p'", "'str_s'", "'byte'", "'uword'", "'word'", "'float'", "'str'", "'str_s'", "'['",
"'str_ps'", "'['", "']'", "'+='", "'-='", "'/='", "'*='", "'**='", "'&='", "']'", "'+='", "'-='", "'/='", "'*='", "'**='", "'&='", "'|='", "'^='",
"'|='", "'^='", "'%='", "'<<='", "'>>='", "'++'", "'--'", "'+'", "'-'", "'%='", "'<<='", "'>>='", "'++'", "'--'", "'+'", "'-'", "'**'", "'*'",
"'**'", "'*'", "'/'", "'%'", "'<<'", "'>>'", "'<'", "'>'", "'<='", "'>='", "'/'", "'%'", "'<<'", "'>>'", "'<'", "'>'", "'<='", "'>='", "'=='", "'!='",
"'=='", "'!='", "'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'", "'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'", "'xor'", "'not'",
"'xor'", "'not'", "'('", "')'", "'as'", "'@'", "'return'", "'break'", "'('", "')'", "'as'", "'@'", "'return'", "'break'", "'continue'", "'.'",
"'continue'", "'.'", "'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'",
"'Pz'", "'Pn'", "'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'->'", "'{'",
"'->'", "'{'", "'}'", "'asmsub'", "'clobbers'", "'stack'", "'if'", "'else'", "'}'", "'asmsub'", "'clobbers'", "'stack'", "'if'", "'else'", "'if_cs'",
"'if_cs'", "'if_cc'", "'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_cc'", "'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_pos'",
"'if_pos'", "'if_mi'", "'if_neg'", "'if_vs'", "'if_vc'", "'for'", "'in'", "'if_mi'", "'if_neg'", "'if_vs'", "'if_vc'", "'for'", "'in'", "'while'",
"'while'", "'repeat'", "'until'", null, null, null, null, null, null, "'repeat'", "'until'", null, null, null, null, null, null, null, null,
null, null, null, null, null, null, "'@zp'" null, null, null, null, "'@zp'"
}; };
} }
private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static final String[] _LITERAL_NAMES = makeLiteralNames();
@@ -101,9 +100,9 @@ public class prog8Lexer extends Lexer {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, "LINECOMMENT", "COMMENT", "WS", "EOL", null, null, null, "LINECOMMENT", "COMMENT", "WS", "EOL", "NAME", "DEC_INTEGER",
"NAME", "DEC_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "STRING", "INLINEASMBLOCK",
"STRING", "INLINEASMBLOCK", "SINGLECHAR", "ZEROPAGE" "SINGLECHAR", "ZEROPAGE"
}; };
} }
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
@@ -167,13 +166,13 @@ public class prog8Lexer extends Lexer {
@Override @Override
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) { public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
switch (ruleIndex) { switch (ruleIndex) {
case 123: case 121:
STRING_action((RuleContext)_localctx, actionIndex); STRING_action((RuleContext)_localctx, actionIndex);
break; break;
case 124: case 122:
INLINEASMBLOCK_action((RuleContext)_localctx, actionIndex); INLINEASMBLOCK_action((RuleContext)_localctx, actionIndex);
break; break;
case 125: case 123:
SINGLECHAR_action((RuleContext)_localctx, actionIndex); SINGLECHAR_action((RuleContext)_localctx, actionIndex);
break; break;
} }
@@ -213,299 +212,292 @@ public class prog8Lexer extends Lexer {
} }
public static final String _serializedATN = public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\177\u0373\b\1\4\2"+ "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2}\u0362\b\1\4\2\t"+
"\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+ "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
"\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t"+ "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!"+
" \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t"+ "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+
"+\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64"+ ",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64\t"+
"\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t"+ "\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t="+
"=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4"+ "\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I"+
"I\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\t"+ "\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+
"T\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_"+ "\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+
"\4`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k"+ "`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k\t"+
"\tk\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\4q\tq\4r\tr\4s\ts\4t\tt\4u\tu\4v\tv"+ "k\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\4q\tq\4r\tr\4s\ts\4t\tt\4u\tu\4v\tv\4"+
"\4w\tw\4x\tx\4y\ty\4z\tz\4{\t{\4|\t|\4}\t}\4~\t~\4\177\t\177\4\u0080\t"+ "w\tw\4x\tx\4y\ty\4z\tz\4{\t{\4|\t|\4}\t}\4~\t~\3\2\3\2\3\3\3\3\3\4\3\4"+
"\u0080\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5"+ "\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3"+
"\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3"+ "\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b"+
"\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t"+ "\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3"+
"\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13"+ "\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13"+
"\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f"+ "\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3"+
"\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3"+ "\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16\3"+
"\r\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3"+ "\16\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3"+
"\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3"+ "\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3"+
"\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3"+ "\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3"+
"\25\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3"+ "\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\31\3\31\3\31\3\31\3"+
"\30\3\30\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3"+ "\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\34\3\35\3\35\3\35\3\36\3\36\3"+
"\33\3\33\3\33\3\33\3\33\3\33\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\36\3"+ "\36\3\37\3\37\3\37\3 \3 \3 \3 \3!\3!\3!\3\"\3\"\3\"\3#\3#\3#\3$\3$\3$"+
"\37\3\37\3\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3\"\3\"\3#\3#\3#\3$\3$\3$\3%\3"+ "\3%\3%\3%\3%\3&\3&\3&\3&\3\'\3\'\3\'\3(\3(\3(\3)\3)\3*\3*\3+\3+\3+\3,"+
"%\3%\3&\3&\3&\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3)\3)\3)\3*\3*\3*\3+\3+\3,\3"+ "\3,\3-\3-\3.\3.\3/\3/\3/\3\60\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63"+
",\3-\3-\3-\3.\3.\3/\3/\3\60\3\60\3\61\3\61\3\61\3\62\3\62\3\62\3\63\3"+ "\3\63\3\64\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\38\38\39"+
"\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3\67\38\38\38\3"+ "\39\3:\3:\3:\3;\3;\3;\3;\3;\3<\3<\3<\3<\3=\3=\3=\3>\3>\3>\3>\3?\3?\3?"+
"9\39\3:\3:\3;\3;\3<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3>\3>\3?\3?\3?\3@\3@\3"+ "\3?\3@\3@\3A\3A\3B\3B\3B\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E\3E\3E\3E\3E\3E"+
"@\3@\3A\3A\3A\3A\3B\3B\3C\3C\3D\3D\3D\3E\3E\3F\3F\3F\3F\3F\3F\3F\3G\3"+ "\3F\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K\3K\3K\3L\3L\3L"+
"G\3G\3G\3G\3G\3H\3H\3H\3H\3H\3H\3H\3H\3H\3I\3I\3J\3J\3K\3K\3L\3L\3M\3"+ "\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R\3S\3S\3S\3S\3S"+
"M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R\3S\3S\3S\3T\3T\3T\3"+ "\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3W\3W\3W\3X\3X\3Y\3Y\3Z"+
"U\3U\3U\3U\3U\3V\3V\3V\3V\3V\3V\3W\3W\3W\3W\3W\3X\3X\3X\3X\3Y\3Y\3Y\3"+ "\3Z\3Z\3Z\3Z\3Z\3Z\3[\3[\3[\3[\3[\3[\3[\3[\3[\3\\\3\\\3\\\3\\\3\\\3\\"+
"Z\3Z\3[\3[\3\\\3\\\3\\\3\\\3\\\3\\\3\\\3]\3]\3]\3]\3]\3]\3]\3]\3]\3^\3"+ "\3]\3]\3]\3^\3^\3^\3^\3^\3_\3_\3_\3_\3_\3_\3`\3`\3`\3`\3`\3`\3a\3a\3a"+
"^\3^\3^\3^\3^\3_\3_\3_\3`\3`\3`\3`\3`\3a\3a\3a\3a\3a\3a\3b\3b\3b\3b\3"+ "\3a\3a\3a\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3d\3e\3e\3e"+
"b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3e\3e\3e\3e\3e\3e\3f\3f\3f\3f\3"+ "\3e\3e\3e\3f\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3h\3h\3h\3h\3h\3h\3h"+
"f\3f\3g\3g\3g\3g\3g\3g\3h\3h\3h\3h\3h\3h\3h\3i\3i\3i\3i\3i\3i\3j\3j\3"+ "\3i\3i\3i\3i\3i\3i\3j\3j\3j\3j\3j\3j\3k\3k\3k\3k\3l\3l\3l\3m\3m\3m\3m"+
"j\3j\3j\3j\3j\3k\3k\3k\3k\3k\3k\3l\3l\3l\3l\3l\3l\3m\3m\3m\3m\3n\3n\3"+ "\3m\3m\3n\3n\3n\3n\3n\3n\3n\3o\3o\3o\3o\3o\3o\3p\3p\7p\u02ed\np\fp\16"+
"n\3o\3o\3o\3o\3o\3o\3p\3p\3p\3p\3p\3p\3p\3q\3q\3q\3q\3q\3q\3r\3r\7r\u02fe"+ "p\u02f0\13p\3p\3p\3p\3p\3q\3q\7q\u02f8\nq\fq\16q\u02fb\13q\3q\3q\3r\3"+
"\nr\fr\16r\u0301\13r\3r\3r\3r\3r\3s\3s\7s\u0309\ns\fs\16s\u030c\13s\3"+ "r\3r\3r\3s\6s\u0304\ns\rs\16s\u0305\3t\3t\7t\u030a\nt\ft\16t\u030d\13"+
"s\3s\3t\3t\3t\3t\3u\6u\u0315\nu\ru\16u\u0316\3v\3v\7v\u031b\nv\fv\16v"+ "t\3u\3u\3u\6u\u0312\nu\ru\16u\u0313\5u\u0316\nu\3v\3v\6v\u031a\nv\rv\16"+
"\u031e\13v\3w\3w\3w\6w\u0323\nw\rw\16w\u0324\5w\u0327\nw\3x\3x\6x\u032b"+ "v\u031b\3w\3w\6w\u0320\nw\rw\16w\u0321\3x\3x\3x\5x\u0327\nx\3x\5x\u032a"+
"\nx\rx\16x\u032c\3y\3y\6y\u0331\ny\ry\16y\u0332\3z\3z\3z\5z\u0338\nz\3"+ "\nx\3y\6y\u032d\ny\ry\16y\u032e\3y\3y\6y\u0333\ny\ry\16y\u0334\5y\u0337"+
"z\5z\u033b\nz\3{\6{\u033e\n{\r{\16{\u033f\3{\3{\6{\u0344\n{\r{\16{\u0345"+ "\ny\3z\3z\3z\3z\5z\u033d\nz\3{\3{\3{\7{\u0342\n{\f{\16{\u0345\13{\3{\3"+
"\5{\u0348\n{\3|\3|\3|\3|\5|\u034e\n|\3}\3}\3}\7}\u0353\n}\f}\16}\u0356"+ "{\3{\3|\3|\3|\3|\6|\u034e\n|\r|\16|\u034f\3|\3|\3|\3|\3|\3}\3}\3}\5}\u035a"+
"\13}\3}\3}\3}\3~\3~\3~\3~\6~\u035f\n~\r~\16~\u0360\3~\3~\3~\3~\3~\3\177"+ "\n}\3}\3}\3}\3~\3~\3~\3~\3\u034f\2\177\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21"+
"\3\177\3\177\5\177\u036b\n\177\3\177\3\177\3\177\3\u0080\3\u0080\3\u0080"+ "\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30"+
"\3\u0080\3\u0360\2\u0081\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f"+ "/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.["+
"\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63"+ "/]\60_\61a\62c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083"+
"\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62"+ "C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097"+
"c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087"+ "M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00ab"+
"E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009b"+ "W\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bf"+
"O\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00af"+ "a\u00c1b\u00c3c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3"+
"Y\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3"+ "k\u00d5l\u00d7m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1r\u00e3s\u00e5t\u00e7"+
"c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3k\u00d5l\u00d7"+ "u\u00e9v\u00ebw\u00edx\u00efy\u00f1\2\u00f3\2\u00f5z\u00f7{\u00f9|\u00fb"+
"m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1r\u00e3s\u00e5t\u00e7u\u00e9v\u00eb"+ "}\3\2\n\4\2\f\f\17\17\4\2\13\13\"\"\5\2C\\aac|\6\2\62;C\\aac|\5\2\62;"+
"w\u00edx\u00efy\u00f1z\u00f3{\u00f5\2\u00f7\2\u00f9|\u00fb}\u00fd~\u00ff"+ "CHch\4\2GGgg\4\2--//\6\2\f\f\16\17$$^^\2\u0371\2\3\3\2\2\2\2\5\3\2\2\2"+
"\177\3\2\n\4\2\f\f\17\17\4\2\13\13\"\"\5\2C\\aac|\6\2\62;C\\aac|\5\2\62"+ "\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3"+
";CHch\4\2GGgg\4\2--//\6\2\f\f\16\17$$^^\2\u0382\2\3\3\2\2\2\2\5\3\2\2"+ "\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2"+
"\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21"+ "\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2"+
"\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2"+ "\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2"+
"\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3"+ "\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2"+
"\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3"+ "\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2"+
"\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3"+ "\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y"+
"\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2"+ "\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2"+
"\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2"+ "\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2"+
"Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3"+ "\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177"+
"\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2"+ "\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2"+
"\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2"+ "\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2\2\u0091"+
"\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3"+ "\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099\3\2\2"+
"\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2"+ "\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1\3\2\2\2\2\u00a3"+
"\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099"+ "\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2\2\2\u00ab\3\2\2"+
"\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1\3\2\2"+ "\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3\3\2\2\2\2\u00b5"+
"\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2\2\2\u00ab"+ "\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb\3\2\2\2\2\u00bd\3\2\2"+
"\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3\3\2\2"+ "\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5\3\2\2\2\2\u00c7"+
"\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb\3\2\2\2\2\u00bd"+ "\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd\3\2\2\2\2\u00cf\3\2\2"+
"\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5\3\2\2"+ "\2\2\u00d1\3\2\2\2\2\u00d3\3\2\2\2\2\u00d5\3\2\2\2\2\u00d7\3\2\2\2\2\u00d9"+
"\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd\3\2\2\2\2\u00cf"+ "\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\2\u00df\3\2\2\2\2\u00e1\3\2\2"+
"\3\2\2\2\2\u00d1\3\2\2\2\2\u00d3\3\2\2\2\2\u00d5\3\2\2\2\2\u00d7\3\2\2"+ "\2\2\u00e3\3\2\2\2\2\u00e5\3\2\2\2\2\u00e7\3\2\2\2\2\u00e9\3\2\2\2\2\u00eb"+
"\2\2\u00d9\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\2\u00df\3\2\2\2\2\u00e1"+ "\3\2\2\2\2\u00ed\3\2\2\2\2\u00ef\3\2\2\2\2\u00f5\3\2\2\2\2\u00f7\3\2\2"+
"\3\2\2\2\2\u00e3\3\2\2\2\2\u00e5\3\2\2\2\2\u00e7\3\2\2\2\2\u00e9\3\2\2"+ "\2\2\u00f9\3\2\2\2\2\u00fb\3\2\2\2\3\u00fd\3\2\2\2\5\u00ff\3\2\2\2\7\u0101"+
"\2\2\u00eb\3\2\2\2\2\u00ed\3\2\2\2\2\u00ef\3\2\2\2\2\u00f1\3\2\2\2\2\u00f3"+ "\3\2\2\2\t\u0106\3\2\2\2\13\u010e\3\2\2\2\r\u0118\3\2\2\2\17\u0122\3\2"+
"\3\2\2\2\2\u00f9\3\2\2\2\2\u00fb\3\2\2\2\2\u00fd\3\2\2\2\2\u00ff\3\2\2"+ "\2\2\21\u012e\3\2\2\2\23\u0137\3\2\2\2\25\u013f\3\2\2\2\27\u014b\3\2\2"+
"\2\3\u0101\3\2\2\2\5\u0103\3\2\2\2\7\u0105\3\2\2\2\t\u010a\3\2\2\2\13"+ "\2\31\u0157\3\2\2\2\33\u0162\3\2\2\2\35\u016a\3\2\2\2\37\u016c\3\2\2\2"+
"\u0112\3\2\2\2\r\u011c\3\2\2\2\17\u0126\3\2\2\2\21\u0132\3\2\2\2\23\u013b"+ "!\u016e\3\2\2\2#\u0174\3\2\2\2%\u017b\3\2\2\2\'\u0181\3\2\2\2)\u0186\3"+
"\3\2\2\2\25\u0143\3\2\2\2\27\u014f\3\2\2\2\31\u015b\3\2\2\2\33\u0166\3"+ "\2\2\2+\u018c\3\2\2\2-\u0191\3\2\2\2/\u0197\3\2\2\2\61\u019b\3\2\2\2\63"+
"\2\2\2\35\u016e\3\2\2\2\37\u0170\3\2\2\2!\u0172\3\2\2\2#\u0178\3\2\2\2"+ "\u01a1\3\2\2\2\65\u01a3\3\2\2\2\67\u01a5\3\2\2\29\u01a8\3\2\2\2;\u01ab"+
"%\u017f\3\2\2\2\'\u0185\3\2\2\2)\u018a\3\2\2\2+\u0190\3\2\2\2-\u0195\3"+ "\3\2\2\2=\u01ae\3\2\2\2?\u01b1\3\2\2\2A\u01b5\3\2\2\2C\u01b8\3\2\2\2E"+
"\2\2\2/\u019b\3\2\2\2\61\u019f\3\2\2\2\63\u01a5\3\2\2\2\65\u01ab\3\2\2"+ "\u01bb\3\2\2\2G\u01be\3\2\2\2I\u01c1\3\2\2\2K\u01c5\3\2\2\2M\u01c9\3\2"+
"\2\67\u01b2\3\2\2\29\u01b4\3\2\2\2;\u01b6\3\2\2\2=\u01b9\3\2\2\2?\u01bc"+ "\2\2O\u01cc\3\2\2\2Q\u01cf\3\2\2\2S\u01d1\3\2\2\2U\u01d3\3\2\2\2W\u01d6"+
"\3\2\2\2A\u01bf\3\2\2\2C\u01c2\3\2\2\2E\u01c6\3\2\2\2G\u01c9\3\2\2\2I"+ "\3\2\2\2Y\u01d8\3\2\2\2[\u01da\3\2\2\2]\u01dc\3\2\2\2_\u01df\3\2\2\2a"+
"\u01cc\3\2\2\2K\u01cf\3\2\2\2M\u01d2\3\2\2\2O\u01d6\3\2\2\2Q\u01da\3\2"+ "\u01e2\3\2\2\2c\u01e4\3\2\2\2e\u01e6\3\2\2\2g\u01e9\3\2\2\2i\u01ec\3\2"+
"\2\2S\u01dd\3\2\2\2U\u01e0\3\2\2\2W\u01e2\3\2\2\2Y\u01e4\3\2\2\2[\u01e7"+ "\2\2k\u01ef\3\2\2\2m\u01f2\3\2\2\2o\u01f4\3\2\2\2q\u01f6\3\2\2\2s\u01f8"+
"\3\2\2\2]\u01e9\3\2\2\2_\u01eb\3\2\2\2a\u01ed\3\2\2\2c\u01f0\3\2\2\2e"+ "\3\2\2\2u\u01fb\3\2\2\2w\u0200\3\2\2\2y\u0204\3\2\2\2{\u0207\3\2\2\2}"+
"\u01f3\3\2\2\2g\u01f5\3\2\2\2i\u01f7\3\2\2\2k\u01fa\3\2\2\2m\u01fd\3\2"+ "\u020b\3\2\2\2\177\u020f\3\2\2\2\u0081\u0211\3\2\2\2\u0083\u0213\3\2\2"+
"\2\2o\u0200\3\2\2\2q\u0203\3\2\2\2s\u0205\3\2\2\2u\u0207\3\2\2\2w\u0209"+ "\2\u0085\u0216\3\2\2\2\u0087\u0218\3\2\2\2\u0089\u021f\3\2\2\2\u008b\u0225"+
"\3\2\2\2y\u020c\3\2\2\2{\u0211\3\2\2\2}\u0215\3\2\2\2\177\u0218\3\2\2"+ "\3\2\2\2\u008d\u022e\3\2\2\2\u008f\u0230\3\2\2\2\u0091\u0232\3\2\2\2\u0093"+
"\2\u0081\u021c\3\2\2\2\u0083\u0220\3\2\2\2\u0085\u0222\3\2\2\2\u0087\u0224"+ "\u0234\3\2\2\2\u0095\u0236\3\2\2\2\u0097\u0239\3\2\2\2\u0099\u023c\3\2"+
"\3\2\2\2\u0089\u0227\3\2\2\2\u008b\u0229\3\2\2\2\u008d\u0230\3\2\2\2\u008f"+ "\2\2\u009b\u023f\3\2\2\2\u009d\u0242\3\2\2\2\u009f\u0245\3\2\2\2\u00a1"+
"\u0236\3\2\2\2\u0091\u023f\3\2\2\2\u0093\u0241\3\2\2\2\u0095\u0243\3\2"+ "\u0248\3\2\2\2\u00a3\u024b\3\2\2\2\u00a5\u024e\3\2\2\2\u00a7\u0253\3\2"+
"\2\2\u0097\u0245\3\2\2\2\u0099\u0247\3\2\2\2\u009b\u024a\3\2\2\2\u009d"+ "\2\2\u00a9\u0259\3\2\2\2\u00ab\u025e\3\2\2\2\u00ad\u0262\3\2\2\2\u00af"+
"\u024d\3\2\2\2\u009f\u0250\3\2\2\2\u00a1\u0253\3\2\2\2\u00a3\u0256\3\2"+ "\u0265\3\2\2\2\u00b1\u0267\3\2\2\2\u00b3\u0269\3\2\2\2\u00b5\u0270\3\2"+
"\2\2\u00a5\u0259\3\2\2\2\u00a7\u025c\3\2\2\2\u00a9\u025f\3\2\2\2\u00ab"+ "\2\2\u00b7\u0279\3\2\2\2\u00b9\u027f\3\2\2\2\u00bb\u0282\3\2\2\2\u00bd"+
"\u0264\3\2\2\2\u00ad\u026a\3\2\2\2\u00af\u026f\3\2\2\2\u00b1\u0273\3\2"+ "\u0287\3\2\2\2\u00bf\u028d\3\2\2\2\u00c1\u0293\3\2\2\2\u00c3\u0299\3\2"+
"\2\2\u00b3\u0276\3\2\2\2\u00b5\u0278\3\2\2\2\u00b7\u027a\3\2\2\2\u00b9"+ "\2\2\u00c5\u029e\3\2\2\2\u00c7\u02a4\3\2\2\2\u00c9\u02aa\3\2\2\2\u00cb"+
"\u0281\3\2\2\2\u00bb\u028a\3\2\2\2\u00bd\u0290\3\2\2\2\u00bf\u0293\3\2"+ "\u02b0\3\2\2\2\u00cd\u02b7\3\2\2\2\u00cf\u02bd\3\2\2\2\u00d1\u02c4\3\2"+
"\2\2\u00c1\u0298\3\2\2\2\u00c3\u029e\3\2\2\2\u00c5\u02a4\3\2\2\2\u00c7"+ "\2\2\u00d3\u02ca\3\2\2\2\u00d5\u02d0\3\2\2\2\u00d7\u02d4\3\2\2\2\u00d9"+
"\u02aa\3\2\2\2\u00c9\u02af\3\2\2\2\u00cb\u02b5\3\2\2\2\u00cd\u02bb\3\2"+ "\u02d7\3\2\2\2\u00db\u02dd\3\2\2\2\u00dd\u02e4\3\2\2\2\u00df\u02ea\3\2"+
"\2\2\u00cf\u02c1\3\2\2\2\u00d1\u02c8\3\2\2\2\u00d3\u02ce\3\2\2\2\u00d5"+ "\2\2\u00e1\u02f5\3\2\2\2\u00e3\u02fe\3\2\2\2\u00e5\u0303\3\2\2\2\u00e7"+
"\u02d5\3\2\2\2\u00d7\u02db\3\2\2\2\u00d9\u02e1\3\2\2\2\u00db\u02e5\3\2"+ "\u0307\3\2\2\2\u00e9\u0315\3\2\2\2\u00eb\u0317\3\2\2\2\u00ed\u031d\3\2"+
"\2\2\u00dd\u02e8\3\2\2\2\u00df\u02ee\3\2\2\2\u00e1\u02f5\3\2\2\2\u00e3"+ "\2\2\u00ef\u0323\3\2\2\2\u00f1\u032c\3\2\2\2\u00f3\u033c\3\2\2\2\u00f5"+
"\u02fb\3\2\2\2\u00e5\u0306\3\2\2\2\u00e7\u030f\3\2\2\2\u00e9\u0314\3\2"+ "\u033e\3\2\2\2\u00f7\u0349\3\2\2\2\u00f9\u0356\3\2\2\2\u00fb\u035e\3\2"+
"\2\2\u00eb\u0318\3\2\2\2\u00ed\u0326\3\2\2\2\u00ef\u0328\3\2\2\2\u00f1"+ "\2\2\u00fd\u00fe\7\u0080\2\2\u00fe\4\3\2\2\2\u00ff\u0100\7<\2\2\u0100"+
"\u032e\3\2\2\2\u00f3\u0334\3\2\2\2\u00f5\u033d\3\2\2\2\u00f7\u034d\3\2"+ "\6\3\2\2\2\u0101\u0102\7i\2\2\u0102\u0103\7q\2\2\u0103\u0104\7v\2\2\u0104"+
"\2\2\u00f9\u034f\3\2\2\2\u00fb\u035a\3\2\2\2\u00fd\u0367\3\2\2\2\u00ff"+ "\u0105\7q\2\2\u0105\b\3\2\2\2\u0106\u0107\7\'\2\2\u0107\u0108\7q\2\2\u0108"+
"\u036f\3\2\2\2\u0101\u0102\7\u0080\2\2\u0102\4\3\2\2\2\u0103\u0104\7<"+ "\u0109\7w\2\2\u0109\u010a\7v\2\2\u010a\u010b\7r\2\2\u010b\u010c\7w\2\2"+
"\2\2\u0104\6\3\2\2\2\u0105\u0106\7i\2\2\u0106\u0107\7q\2\2\u0107\u0108"+ "\u010c\u010d\7v\2\2\u010d\n\3\2\2\2\u010e\u010f\7\'\2\2\u010f\u0110\7"+
"\7v\2\2\u0108\u0109\7q\2\2\u0109\b\3\2\2\2\u010a\u010b\7\'\2\2\u010b\u010c"+ "n\2\2\u0110\u0111\7c\2\2\u0111\u0112\7w\2\2\u0112\u0113\7p\2\2\u0113\u0114"+
"\7q\2\2\u010c\u010d\7w\2\2\u010d\u010e\7v\2\2\u010e\u010f\7r\2\2\u010f"+ "\7e\2\2\u0114\u0115\7j\2\2\u0115\u0116\7g\2\2\u0116\u0117\7t\2\2\u0117"+
"\u0110\7w\2\2\u0110\u0111\7v\2\2\u0111\n\3\2\2\2\u0112\u0113\7\'\2\2\u0113"+ "\f\3\2\2\2\u0118\u0119\7\'\2\2\u0119\u011a\7|\2\2\u011a\u011b\7g\2\2\u011b"+
"\u0114\7n\2\2\u0114\u0115\7c\2\2\u0115\u0116\7w\2\2\u0116\u0117\7p\2\2"+ "\u011c\7t\2\2\u011c\u011d\7q\2\2\u011d\u011e\7r\2\2\u011e\u011f\7c\2\2"+
"\u0117\u0118\7e\2\2\u0118\u0119\7j\2\2\u0119\u011a\7g\2\2\u011a\u011b"+ "\u011f\u0120\7i\2\2\u0120\u0121\7g\2\2\u0121\16\3\2\2\2\u0122\u0123\7"+
"\7t\2\2\u011b\f\3\2\2\2\u011c\u011d\7\'\2\2\u011d\u011e\7|\2\2\u011e\u011f"+ "\'\2\2\u0123\u0124\7|\2\2\u0124\u0125\7r\2\2\u0125\u0126\7t\2\2\u0126"+
"\7g\2\2\u011f\u0120\7t\2\2\u0120\u0121\7q\2\2\u0121\u0122\7r\2\2\u0122"+ "\u0127\7g\2\2\u0127\u0128\7u\2\2\u0128\u0129\7g\2\2\u0129\u012a\7t\2\2"+
"\u0123\7c\2\2\u0123\u0124\7i\2\2\u0124\u0125\7g\2\2\u0125\16\3\2\2\2\u0126"+ "\u012a\u012b\7x\2\2\u012b\u012c\7g\2\2\u012c\u012d\7f\2\2\u012d\20\3\2"+
"\u0127\7\'\2\2\u0127\u0128\7|\2\2\u0128\u0129\7r\2\2\u0129\u012a\7t\2"+ "\2\2\u012e\u012f\7\'\2\2\u012f\u0130\7c\2\2\u0130\u0131\7f\2\2\u0131\u0132"+
"\2\u012a\u012b\7g\2\2\u012b\u012c\7u\2\2\u012c\u012d\7g\2\2\u012d\u012e"+ "\7f\2\2\u0132\u0133\7t\2\2\u0133\u0134\7g\2\2\u0134\u0135\7u\2\2\u0135"+
"\7t\2\2\u012e\u012f\7x\2\2\u012f\u0130\7g\2\2\u0130\u0131\7f\2\2\u0131"+ "\u0136\7u\2\2\u0136\22\3\2\2\2\u0137\u0138\7\'\2\2\u0138\u0139\7k\2\2"+
"\20\3\2\2\2\u0132\u0133\7\'\2\2\u0133\u0134\7c\2\2\u0134\u0135\7f\2\2"+ "\u0139\u013a\7o\2\2\u013a\u013b\7r\2\2\u013b\u013c\7q\2\2\u013c\u013d"+
"\u0135\u0136\7f\2\2\u0136\u0137\7t\2\2\u0137\u0138\7g\2\2\u0138\u0139"+ "\7t\2\2\u013d\u013e\7v\2\2\u013e\24\3\2\2\2\u013f\u0140\7\'\2\2\u0140"+
"\7u\2\2\u0139\u013a\7u\2\2\u013a\22\3\2\2\2\u013b\u013c\7\'\2\2\u013c"+ "\u0141\7d\2\2\u0141\u0142\7t\2\2\u0142\u0143\7g\2\2\u0143\u0144\7c\2\2"+
"\u013d\7k\2\2\u013d\u013e\7o\2\2\u013e\u013f\7r\2\2\u013f\u0140\7q\2\2"+ "\u0144\u0145\7m\2\2\u0145\u0146\7r\2\2\u0146\u0147\7q\2\2\u0147\u0148"+
"\u0140\u0141\7t\2\2\u0141\u0142\7v\2\2\u0142\24\3\2\2\2\u0143\u0144\7"+ "\7k\2\2\u0148\u0149\7p\2\2\u0149\u014a\7v\2\2\u014a\26\3\2\2\2\u014b\u014c"+
"\'\2\2\u0144\u0145\7d\2\2\u0145\u0146\7t\2\2\u0146\u0147\7g\2\2\u0147"+ "\7\'\2\2\u014c\u014d\7c\2\2\u014d\u014e\7u\2\2\u014e\u014f\7o\2\2\u014f"+
"\u0148\7c\2\2\u0148\u0149\7m\2\2\u0149\u014a\7r\2\2\u014a\u014b\7q\2\2"+ "\u0150\7k\2\2\u0150\u0151\7p\2\2\u0151\u0152\7e\2\2\u0152\u0153\7n\2\2"+
"\u014b\u014c\7k\2\2\u014c\u014d\7p\2\2\u014d\u014e\7v\2\2\u014e\26\3\2"+ "\u0153\u0154\7w\2\2\u0154\u0155\7f\2\2\u0155\u0156\7g\2\2\u0156\30\3\2"+
"\2\2\u014f\u0150\7\'\2\2\u0150\u0151\7c\2\2\u0151\u0152\7u\2\2\u0152\u0153"+ "\2\2\u0157\u0158\7\'\2\2\u0158\u0159\7c\2\2\u0159\u015a\7u\2\2\u015a\u015b"+
"\7o\2\2\u0153\u0154\7k\2\2\u0154\u0155\7p\2\2\u0155\u0156\7e\2\2\u0156"+ "\7o\2\2\u015b\u015c\7d\2\2\u015c\u015d\7k\2\2\u015d\u015e\7p\2\2\u015e"+
"\u0157\7n\2\2\u0157\u0158\7w\2\2\u0158\u0159\7f\2\2\u0159\u015a\7g\2\2"+ "\u015f\7c\2\2\u015f\u0160\7t\2\2\u0160\u0161\7{\2\2\u0161\32\3\2\2\2\u0162"+
"\u015a\30\3\2\2\2\u015b\u015c\7\'\2\2\u015c\u015d\7c\2\2\u015d\u015e\7"+ "\u0163\7\'\2\2\u0163\u0164\7q\2\2\u0164\u0165\7r\2\2\u0165\u0166\7v\2"+
"u\2\2\u015e\u015f\7o\2\2\u015f\u0160\7d\2\2\u0160\u0161\7k\2\2\u0161\u0162"+ "\2\u0166\u0167\7k\2\2\u0167\u0168\7q\2\2\u0168\u0169\7p\2\2\u0169\34\3"+
"\7p\2\2\u0162\u0163\7c\2\2\u0163\u0164\7t\2\2\u0164\u0165\7{\2\2\u0165"+ "\2\2\2\u016a\u016b\7.\2\2\u016b\36\3\2\2\2\u016c\u016d\7?\2\2\u016d \3"+
"\32\3\2\2\2\u0166\u0167\7\'\2\2\u0167\u0168\7q\2\2\u0168\u0169\7r\2\2"+ "\2\2\2\u016e\u016f\7e\2\2\u016f\u0170\7q\2\2\u0170\u0171\7p\2\2\u0171"+
"\u0169\u016a\7v\2\2\u016a\u016b\7k\2\2\u016b\u016c\7q\2\2\u016c\u016d"+ "\u0172\7u\2\2\u0172\u0173\7v\2\2\u0173\"\3\2\2\2\u0174\u0175\7o\2\2\u0175"+
"\7p\2\2\u016d\34\3\2\2\2\u016e\u016f\7.\2\2\u016f\36\3\2\2\2\u0170\u0171"+ "\u0176\7g\2\2\u0176\u0177\7o\2\2\u0177\u0178\7q\2\2\u0178\u0179\7t\2\2"+
"\7?\2\2\u0171 \3\2\2\2\u0172\u0173\7e\2\2\u0173\u0174\7q\2\2\u0174\u0175"+ "\u0179\u017a\7{\2\2\u017a$\3\2\2\2\u017b\u017c\7w\2\2\u017c\u017d\7d\2"+
"\7p\2\2\u0175\u0176\7u\2\2\u0176\u0177\7v\2\2\u0177\"\3\2\2\2\u0178\u0179"+ "\2\u017d\u017e\7{\2\2\u017e\u017f\7v\2\2\u017f\u0180\7g\2\2\u0180&\3\2"+
"\7o\2\2\u0179\u017a\7g\2\2\u017a\u017b\7o\2\2\u017b\u017c\7q\2\2\u017c"+ "\2\2\u0181\u0182\7d\2\2\u0182\u0183\7{\2\2\u0183\u0184\7v\2\2\u0184\u0185"+
"\u017d\7t\2\2\u017d\u017e\7{\2\2\u017e$\3\2\2\2\u017f\u0180\7w\2\2\u0180"+ "\7g\2\2\u0185(\3\2\2\2\u0186\u0187\7w\2\2\u0187\u0188\7y\2\2\u0188\u0189"+
"\u0181\7d\2\2\u0181\u0182\7{\2\2\u0182\u0183\7v\2\2\u0183\u0184\7g\2\2"+ "\7q\2\2\u0189\u018a\7t\2\2\u018a\u018b\7f\2\2\u018b*\3\2\2\2\u018c\u018d"+
"\u0184&\3\2\2\2\u0185\u0186\7d\2\2\u0186\u0187\7{\2\2\u0187\u0188\7v\2"+ "\7y\2\2\u018d\u018e\7q\2\2\u018e\u018f\7t\2\2\u018f\u0190\7f\2\2\u0190"+
"\2\u0188\u0189\7g\2\2\u0189(\3\2\2\2\u018a\u018b\7w\2\2\u018b\u018c\7"+ ",\3\2\2\2\u0191\u0192\7h\2\2\u0192\u0193\7n\2\2\u0193\u0194\7q\2\2\u0194"+
"y\2\2\u018c\u018d\7q\2\2\u018d\u018e\7t\2\2\u018e\u018f\7f\2\2\u018f*"+ "\u0195\7c\2\2\u0195\u0196\7v\2\2\u0196.\3\2\2\2\u0197\u0198\7u\2\2\u0198"+
"\3\2\2\2\u0190\u0191\7y\2\2\u0191\u0192\7q\2\2\u0192\u0193\7t\2\2\u0193"+ "\u0199\7v\2\2\u0199\u019a\7t\2\2\u019a\60\3\2\2\2\u019b\u019c\7u\2\2\u019c"+
"\u0194\7f\2\2\u0194,\3\2\2\2\u0195\u0196\7h\2\2\u0196\u0197\7n\2\2\u0197"+ "\u019d\7v\2\2\u019d\u019e\7t\2\2\u019e\u019f\7a\2\2\u019f\u01a0\7u\2\2"+
"\u0198\7q\2\2\u0198\u0199\7c\2\2\u0199\u019a\7v\2\2\u019a.\3\2\2\2\u019b"+ "\u01a0\62\3\2\2\2\u01a1\u01a2\7]\2\2\u01a2\64\3\2\2\2\u01a3\u01a4\7_\2"+
"\u019c\7u\2\2\u019c\u019d\7v\2\2\u019d\u019e\7t\2\2\u019e\60\3\2\2\2\u019f"+ "\2\u01a4\66\3\2\2\2\u01a5\u01a6\7-\2\2\u01a6\u01a7\7?\2\2\u01a78\3\2\2"+
"\u01a0\7u\2\2\u01a0\u01a1\7v\2\2\u01a1\u01a2\7t\2\2\u01a2\u01a3\7a\2\2"+ "\2\u01a8\u01a9\7/\2\2\u01a9\u01aa\7?\2\2\u01aa:\3\2\2\2\u01ab\u01ac\7"+
"\u01a3\u01a4\7r\2\2\u01a4\62\3\2\2\2\u01a5\u01a6\7u\2\2\u01a6\u01a7\7"+ "\61\2\2\u01ac\u01ad\7?\2\2\u01ad<\3\2\2\2\u01ae\u01af\7,\2\2\u01af\u01b0"+
"v\2\2\u01a7\u01a8\7t\2\2\u01a8\u01a9\7a\2\2\u01a9\u01aa\7u\2\2\u01aa\64"+ "\7?\2\2\u01b0>\3\2\2\2\u01b1\u01b2\7,\2\2\u01b2\u01b3\7,\2\2\u01b3\u01b4"+
"\3\2\2\2\u01ab\u01ac\7u\2\2\u01ac\u01ad\7v\2\2\u01ad\u01ae\7t\2\2\u01ae"+ "\7?\2\2\u01b4@\3\2\2\2\u01b5\u01b6\7(\2\2\u01b6\u01b7\7?\2\2\u01b7B\3"+
"\u01af\7a\2\2\u01af\u01b0\7r\2\2\u01b0\u01b1\7u\2\2\u01b1\66\3\2\2\2\u01b2"+ "\2\2\2\u01b8\u01b9\7~\2\2\u01b9\u01ba\7?\2\2\u01baD\3\2\2\2\u01bb\u01bc"+
"\u01b3\7]\2\2\u01b38\3\2\2\2\u01b4\u01b5\7_\2\2\u01b5:\3\2\2\2\u01b6\u01b7"+ "\7`\2\2\u01bc\u01bd\7?\2\2\u01bdF\3\2\2\2\u01be\u01bf\7\'\2\2\u01bf\u01c0"+
"\7-\2\2\u01b7\u01b8\7?\2\2\u01b8<\3\2\2\2\u01b9\u01ba\7/\2\2\u01ba\u01bb"+ "\7?\2\2\u01c0H\3\2\2\2\u01c1\u01c2\7>\2\2\u01c2\u01c3\7>\2\2\u01c3\u01c4"+
"\7?\2\2\u01bb>\3\2\2\2\u01bc\u01bd\7\61\2\2\u01bd\u01be\7?\2\2\u01be@"+ "\7?\2\2\u01c4J\3\2\2\2\u01c5\u01c6\7@\2\2\u01c6\u01c7\7@\2\2\u01c7\u01c8"+
"\3\2\2\2\u01bf\u01c0\7,\2\2\u01c0\u01c1\7?\2\2\u01c1B\3\2\2\2\u01c2\u01c3"+ "\7?\2\2\u01c8L\3\2\2\2\u01c9\u01ca\7-\2\2\u01ca\u01cb\7-\2\2\u01cbN\3"+
"\7,\2\2\u01c3\u01c4\7,\2\2\u01c4\u01c5\7?\2\2\u01c5D\3\2\2\2\u01c6\u01c7"+ "\2\2\2\u01cc\u01cd\7/\2\2\u01cd\u01ce\7/\2\2\u01ceP\3\2\2\2\u01cf\u01d0"+
"\7(\2\2\u01c7\u01c8\7?\2\2\u01c8F\3\2\2\2\u01c9\u01ca\7~\2\2\u01ca\u01cb"+ "\7-\2\2\u01d0R\3\2\2\2\u01d1\u01d2\7/\2\2\u01d2T\3\2\2\2\u01d3\u01d4\7"+
"\7?\2\2\u01cbH\3\2\2\2\u01cc\u01cd\7`\2\2\u01cd\u01ce\7?\2\2\u01ceJ\3"+ ",\2\2\u01d4\u01d5\7,\2\2\u01d5V\3\2\2\2\u01d6\u01d7\7,\2\2\u01d7X\3\2"+
"\2\2\2\u01cf\u01d0\7\'\2\2\u01d0\u01d1\7?\2\2\u01d1L\3\2\2\2\u01d2\u01d3"+ "\2\2\u01d8\u01d9\7\61\2\2\u01d9Z\3\2\2\2\u01da\u01db\7\'\2\2\u01db\\\3"+
"\7>\2\2\u01d3\u01d4\7>\2\2\u01d4\u01d5\7?\2\2\u01d5N\3\2\2\2\u01d6\u01d7"+ "\2\2\2\u01dc\u01dd\7>\2\2\u01dd\u01de\7>\2\2\u01de^\3\2\2\2\u01df\u01e0"+
"\7@\2\2\u01d7\u01d8\7@\2\2\u01d8\u01d9\7?\2\2\u01d9P\3\2\2\2\u01da\u01db"+ "\7@\2\2\u01e0\u01e1\7@\2\2\u01e1`\3\2\2\2\u01e2\u01e3\7>\2\2\u01e3b\3"+
"\7-\2\2\u01db\u01dc\7-\2\2\u01dcR\3\2\2\2\u01dd\u01de\7/\2\2\u01de\u01df"+ "\2\2\2\u01e4\u01e5\7@\2\2\u01e5d\3\2\2\2\u01e6\u01e7\7>\2\2\u01e7\u01e8"+
"\7/\2\2\u01dfT\3\2\2\2\u01e0\u01e1\7-\2\2\u01e1V\3\2\2\2\u01e2\u01e3\7"+ "\7?\2\2\u01e8f\3\2\2\2\u01e9\u01ea\7@\2\2\u01ea\u01eb\7?\2\2\u01ebh\3"+
"/\2\2\u01e3X\3\2\2\2\u01e4\u01e5\7,\2\2\u01e5\u01e6\7,\2\2\u01e6Z\3\2"+ "\2\2\2\u01ec\u01ed\7?\2\2\u01ed\u01ee\7?\2\2\u01eej\3\2\2\2\u01ef\u01f0"+
"\2\2\u01e7\u01e8\7,\2\2\u01e8\\\3\2\2\2\u01e9\u01ea\7\61\2\2\u01ea^\3"+ "\7#\2\2\u01f0\u01f1\7?\2\2\u01f1l\3\2\2\2\u01f2\u01f3\7(\2\2\u01f3n\3"+
"\2\2\2\u01eb\u01ec\7\'\2\2\u01ec`\3\2\2\2\u01ed\u01ee\7>\2\2\u01ee\u01ef"+ "\2\2\2\u01f4\u01f5\7`\2\2\u01f5p\3\2\2\2\u01f6\u01f7\7~\2\2\u01f7r\3\2"+
"\7>\2\2\u01efb\3\2\2\2\u01f0\u01f1\7@\2\2\u01f1\u01f2\7@\2\2\u01f2d\3"+ "\2\2\u01f8\u01f9\7v\2\2\u01f9\u01fa\7q\2\2\u01fat\3\2\2\2\u01fb\u01fc"+
"\2\2\2\u01f3\u01f4\7>\2\2\u01f4f\3\2\2\2\u01f5\u01f6\7@\2\2\u01f6h\3\2"+ "\7u\2\2\u01fc\u01fd\7v\2\2\u01fd\u01fe\7g\2\2\u01fe\u01ff\7r\2\2\u01ff"+
"\2\2\u01f7\u01f8\7>\2\2\u01f8\u01f9\7?\2\2\u01f9j\3\2\2\2\u01fa\u01fb"+ "v\3\2\2\2\u0200\u0201\7c\2\2\u0201\u0202\7p\2\2\u0202\u0203\7f\2\2\u0203"+
"\7@\2\2\u01fb\u01fc\7?\2\2\u01fcl\3\2\2\2\u01fd\u01fe\7?\2\2\u01fe\u01ff"+ "x\3\2\2\2\u0204\u0205\7q\2\2\u0205\u0206\7t\2\2\u0206z\3\2\2\2\u0207\u0208"+
"\7?\2\2\u01ffn\3\2\2\2\u0200\u0201\7#\2\2\u0201\u0202\7?\2\2\u0202p\3"+ "\7z\2\2\u0208\u0209\7q\2\2\u0209\u020a\7t\2\2\u020a|\3\2\2\2\u020b\u020c"+
"\2\2\2\u0203\u0204\7(\2\2\u0204r\3\2\2\2\u0205\u0206\7`\2\2\u0206t\3\2"+ "\7p\2\2\u020c\u020d\7q\2\2\u020d\u020e\7v\2\2\u020e~\3\2\2\2\u020f\u0210"+
"\2\2\u0207\u0208\7~\2\2\u0208v\3\2\2\2\u0209\u020a\7v\2\2\u020a\u020b"+ "\7*\2\2\u0210\u0080\3\2\2\2\u0211\u0212\7+\2\2\u0212\u0082\3\2\2\2\u0213"+
"\7q\2\2\u020bx\3\2\2\2\u020c\u020d\7u\2\2\u020d\u020e\7v\2\2\u020e\u020f"+ "\u0214\7c\2\2\u0214\u0215\7u\2\2\u0215\u0084\3\2\2\2\u0216\u0217\7B\2"+
"\7g\2\2\u020f\u0210\7r\2\2\u0210z\3\2\2\2\u0211\u0212\7c\2\2\u0212\u0213"+ "\2\u0217\u0086\3\2\2\2\u0218\u0219\7t\2\2\u0219\u021a\7g\2\2\u021a\u021b"+
"\7p\2\2\u0213\u0214\7f\2\2\u0214|\3\2\2\2\u0215\u0216\7q\2\2\u0216\u0217"+ "\7v\2\2\u021b\u021c\7w\2\2\u021c\u021d\7t\2\2\u021d\u021e\7p\2\2\u021e"+
"\7t\2\2\u0217~\3\2\2\2\u0218\u0219\7z\2\2\u0219\u021a\7q\2\2\u021a\u021b"+ "\u0088\3\2\2\2\u021f\u0220\7d\2\2\u0220\u0221\7t\2\2\u0221\u0222\7g\2"+
"\7t\2\2\u021b\u0080\3\2\2\2\u021c\u021d\7p\2\2\u021d\u021e\7q\2\2\u021e"+ "\2\u0222\u0223\7c\2\2\u0223\u0224\7m\2\2\u0224\u008a\3\2\2\2\u0225\u0226"+
"\u021f\7v\2\2\u021f\u0082\3\2\2\2\u0220\u0221\7*\2\2\u0221\u0084\3\2\2"+ "\7e\2\2\u0226\u0227\7q\2\2\u0227\u0228\7p\2\2\u0228\u0229\7v\2\2\u0229"+
"\2\u0222\u0223\7+\2\2\u0223\u0086\3\2\2\2\u0224\u0225\7c\2\2\u0225\u0226"+ "\u022a\7k\2\2\u022a\u022b\7p\2\2\u022b\u022c\7w\2\2\u022c\u022d\7g\2\2"+
"\7u\2\2\u0226\u0088\3\2\2\2\u0227\u0228\7B\2\2\u0228\u008a\3\2\2\2\u0229"+ "\u022d\u008c\3\2\2\2\u022e\u022f\7\60\2\2\u022f\u008e\3\2\2\2\u0230\u0231"+
"\u022a\7t\2\2\u022a\u022b\7g\2\2\u022b\u022c\7v\2\2\u022c\u022d\7w\2\2"+ "\7C\2\2\u0231\u0090\3\2\2\2\u0232\u0233\7Z\2\2\u0233\u0092\3\2\2\2\u0234"+
"\u022d\u022e\7t\2\2\u022e\u022f\7p\2\2\u022f\u008c\3\2\2\2\u0230\u0231"+ "\u0235\7[\2\2\u0235\u0094\3\2\2\2\u0236\u0237\7C\2\2\u0237\u0238\7Z\2"+
"\7d\2\2\u0231\u0232\7t\2\2\u0232\u0233\7g\2\2\u0233\u0234\7c\2\2\u0234"+ "\2\u0238\u0096\3\2\2\2\u0239\u023a\7C\2\2\u023a\u023b\7[\2\2\u023b\u0098"+
"\u0235\7m\2\2\u0235\u008e\3\2\2\2\u0236\u0237\7e\2\2\u0237\u0238\7q\2"+ "\3\2\2\2\u023c\u023d\7Z\2\2\u023d\u023e\7[\2\2\u023e\u009a\3\2\2\2\u023f"+
"\2\u0238\u0239\7p\2\2\u0239\u023a\7v\2\2\u023a\u023b\7k\2\2\u023b\u023c"+ "\u0240\7R\2\2\u0240\u0241\7e\2\2\u0241\u009c\3\2\2\2\u0242\u0243\7R\2"+
"\7p\2\2\u023c\u023d\7w\2\2\u023d\u023e\7g\2\2\u023e\u0090\3\2\2\2\u023f"+ "\2\u0243\u0244\7|\2\2\u0244\u009e\3\2\2\2\u0245\u0246\7R\2\2\u0246\u0247"+
"\u0240\7\60\2\2\u0240\u0092\3\2\2\2\u0241\u0242\7C\2\2\u0242\u0094\3\2"+ "\7p\2\2\u0247\u00a0\3\2\2\2\u0248\u0249\7R\2\2\u0249\u024a\7x\2\2\u024a"+
"\2\2\u0243\u0244\7Z\2\2\u0244\u0096\3\2\2\2\u0245\u0246\7[\2\2\u0246\u0098"+ "\u00a2\3\2\2\2\u024b\u024c\7\60\2\2\u024c\u024d\7y\2\2\u024d\u00a4\3\2"+
"\3\2\2\2\u0247\u0248\7C\2\2\u0248\u0249\7Z\2\2\u0249\u009a\3\2\2\2\u024a"+ "\2\2\u024e\u024f\7v\2\2\u024f\u0250\7t\2\2\u0250\u0251\7w\2\2\u0251\u0252"+
"\u024b\7C\2\2\u024b\u024c\7[\2\2\u024c\u009c\3\2\2\2\u024d\u024e\7Z\2"+ "\7g\2\2\u0252\u00a6\3\2\2\2\u0253\u0254\7h\2\2\u0254\u0255\7c\2\2\u0255"+
"\2\u024e\u024f\7[\2\2\u024f\u009e\3\2\2\2\u0250\u0251\7R\2\2\u0251\u0252"+ "\u0256\7n\2\2\u0256\u0257\7u\2\2\u0257\u0258\7g\2\2\u0258\u00a8\3\2\2"+
"\7e\2\2\u0252\u00a0\3\2\2\2\u0253\u0254\7R\2\2\u0254\u0255\7|\2\2\u0255"+ "\2\u0259\u025a\7\'\2\2\u025a\u025b\7c\2\2\u025b\u025c\7u\2\2\u025c\u025d"+
"\u00a2\3\2\2\2\u0256\u0257\7R\2\2\u0257\u0258\7p\2\2\u0258\u00a4\3\2\2"+ "\7o\2\2\u025d\u00aa\3\2\2\2\u025e\u025f\7u\2\2\u025f\u0260\7w\2\2\u0260"+
"\2\u0259\u025a\7R\2\2\u025a\u025b\7x\2\2\u025b\u00a6\3\2\2\2\u025c\u025d"+ "\u0261\7d\2\2\u0261\u00ac\3\2\2\2\u0262\u0263\7/\2\2\u0263\u0264\7@\2"+
"\7\60\2\2\u025d\u025e\7y\2\2\u025e\u00a8\3\2\2\2\u025f\u0260\7v\2\2\u0260"+ "\2\u0264\u00ae\3\2\2\2\u0265\u0266\7}\2\2\u0266\u00b0\3\2\2\2\u0267\u0268"+
"\u0261\7t\2\2\u0261\u0262\7w\2\2\u0262\u0263\7g\2\2\u0263\u00aa\3\2\2"+ "\7\177\2\2\u0268\u00b2\3\2\2\2\u0269\u026a\7c\2\2\u026a\u026b\7u\2\2\u026b"+
"\2\u0264\u0265\7h\2\2\u0265\u0266\7c\2\2\u0266\u0267\7n\2\2\u0267\u0268"+ "\u026c\7o\2\2\u026c\u026d\7u\2\2\u026d\u026e\7w\2\2\u026e\u026f\7d\2\2"+
"\7u\2\2\u0268\u0269\7g\2\2\u0269\u00ac\3\2\2\2\u026a\u026b\7\'\2\2\u026b"+ "\u026f\u00b4\3\2\2\2\u0270\u0271\7e\2\2\u0271\u0272\7n\2\2\u0272\u0273"+
"\u026c\7c\2\2\u026c\u026d\7u\2\2\u026d\u026e\7o\2\2\u026e\u00ae\3\2\2"+ "\7q\2\2\u0273\u0274\7d\2\2\u0274\u0275\7d\2\2\u0275\u0276\7g\2\2\u0276"+
"\2\u026f\u0270\7u\2\2\u0270\u0271\7w\2\2\u0271\u0272\7d\2\2\u0272\u00b0"+ "\u0277\7t\2\2\u0277\u0278\7u\2\2\u0278\u00b6\3\2\2\2\u0279\u027a\7u\2"+
"\3\2\2\2\u0273\u0274\7/\2\2\u0274\u0275\7@\2\2\u0275\u00b2\3\2\2\2\u0276"+ "\2\u027a\u027b\7v\2\2\u027b\u027c\7c\2\2\u027c\u027d\7e\2\2\u027d\u027e"+
"\u0277\7}\2\2\u0277\u00b4\3\2\2\2\u0278\u0279\7\177\2\2\u0279\u00b6\3"+ "\7m\2\2\u027e\u00b8\3\2\2\2\u027f\u0280\7k\2\2\u0280\u0281\7h\2\2\u0281"+
"\2\2\2\u027a\u027b\7c\2\2\u027b\u027c\7u\2\2\u027c\u027d\7o\2\2\u027d"+ "\u00ba\3\2\2\2\u0282\u0283\7g\2\2\u0283\u0284\7n\2\2\u0284\u0285\7u\2"+
"\u027e\7u\2\2\u027e\u027f\7w\2\2\u027f\u0280\7d\2\2\u0280\u00b8\3\2\2"+ "\2\u0285\u0286\7g\2\2\u0286\u00bc\3\2\2\2\u0287\u0288\7k\2\2\u0288\u0289"+
"\2\u0281\u0282\7e\2\2\u0282\u0283\7n\2\2\u0283\u0284\7q\2\2\u0284\u0285"+ "\7h\2\2\u0289\u028a\7a\2\2\u028a\u028b\7e\2\2\u028b\u028c\7u\2\2\u028c"+
"\7d\2\2\u0285\u0286\7d\2\2\u0286\u0287\7g\2\2\u0287\u0288\7t\2\2\u0288"+ "\u00be\3\2\2\2\u028d\u028e\7k\2\2\u028e\u028f\7h\2\2\u028f\u0290\7a\2"+
"\u0289\7u\2\2\u0289\u00ba\3\2\2\2\u028a\u028b\7u\2\2\u028b\u028c\7v\2"+ "\2\u0290\u0291\7e\2\2\u0291\u0292\7e\2\2\u0292\u00c0\3\2\2\2\u0293\u0294"+
"\2\u028c\u028d\7c\2\2\u028d\u028e\7e\2\2\u028e\u028f\7m\2\2\u028f\u00bc"+ "\7k\2\2\u0294\u0295\7h\2\2\u0295\u0296\7a\2\2\u0296\u0297\7g\2\2\u0297"+
"\3\2\2\2\u0290\u0291\7k\2\2\u0291\u0292\7h\2\2\u0292\u00be\3\2\2\2\u0293"+ "\u0298\7s\2\2\u0298\u00c2\3\2\2\2\u0299\u029a\7k\2\2\u029a\u029b\7h\2"+
"\u0294\7g\2\2\u0294\u0295\7n\2\2\u0295\u0296\7u\2\2\u0296\u0297\7g\2\2"+ "\2\u029b\u029c\7a\2\2\u029c\u029d\7|\2\2\u029d\u00c4\3\2\2\2\u029e\u029f"+
"\u0297\u00c0\3\2\2\2\u0298\u0299\7k\2\2\u0299\u029a\7h\2\2\u029a\u029b"+ "\7k\2\2\u029f\u02a0\7h\2\2\u02a0\u02a1\7a\2\2\u02a1\u02a2\7p\2\2\u02a2"+
"\7a\2\2\u029b\u029c\7e\2\2\u029c\u029d\7u\2\2\u029d\u00c2\3\2\2\2\u029e"+ "\u02a3\7g\2\2\u02a3\u00c6\3\2\2\2\u02a4\u02a5\7k\2\2\u02a5\u02a6\7h\2"+
"\u029f\7k\2\2\u029f\u02a0\7h\2\2\u02a0\u02a1\7a\2\2\u02a1\u02a2\7e\2\2"+ "\2\u02a6\u02a7\7a\2\2\u02a7\u02a8\7p\2\2\u02a8\u02a9\7|\2\2\u02a9\u00c8"+
"\u02a2\u02a3\7e\2\2\u02a3\u00c4\3\2\2\2\u02a4\u02a5\7k\2\2\u02a5\u02a6"+ "\3\2\2\2\u02aa\u02ab\7k\2\2\u02ab\u02ac\7h\2\2\u02ac\u02ad\7a\2\2\u02ad"+
"\7h\2\2\u02a6\u02a7\7a\2\2\u02a7\u02a8\7g\2\2\u02a8\u02a9\7s\2\2\u02a9"+ "\u02ae\7r\2\2\u02ae\u02af\7n\2\2\u02af\u00ca\3\2\2\2\u02b0\u02b1\7k\2"+
"\u00c6\3\2\2\2\u02aa\u02ab\7k\2\2\u02ab\u02ac\7h\2\2\u02ac\u02ad\7a\2"+ "\2\u02b1\u02b2\7h\2\2\u02b2\u02b3\7a\2\2\u02b3\u02b4\7r\2\2\u02b4\u02b5"+
"\2\u02ad\u02ae\7|\2\2\u02ae\u00c8\3\2\2\2\u02af\u02b0\7k\2\2\u02b0\u02b1"+ "\7q\2\2\u02b5\u02b6\7u\2\2\u02b6\u00cc\3\2\2\2\u02b7\u02b8\7k\2\2\u02b8"+
"\7h\2\2\u02b1\u02b2\7a\2\2\u02b2\u02b3\7p\2\2\u02b3\u02b4\7g\2\2\u02b4"+ "\u02b9\7h\2\2\u02b9\u02ba\7a\2\2\u02ba\u02bb\7o\2\2\u02bb\u02bc\7k\2\2"+
"\u00ca\3\2\2\2\u02b5\u02b6\7k\2\2\u02b6\u02b7\7h\2\2\u02b7\u02b8\7a\2"+ "\u02bc\u00ce\3\2\2\2\u02bd\u02be\7k\2\2\u02be\u02bf\7h\2\2\u02bf\u02c0"+
"\2\u02b8\u02b9\7p\2\2\u02b9\u02ba\7|\2\2\u02ba\u00cc\3\2\2\2\u02bb\u02bc"+ "\7a\2\2\u02c0\u02c1\7p\2\2\u02c1\u02c2\7g\2\2\u02c2\u02c3\7i\2\2\u02c3"+
"\7k\2\2\u02bc\u02bd\7h\2\2\u02bd\u02be\7a\2\2\u02be\u02bf\7r\2\2\u02bf"+ "\u00d0\3\2\2\2\u02c4\u02c5\7k\2\2\u02c5\u02c6\7h\2\2\u02c6\u02c7\7a\2"+
"\u02c0\7n\2\2\u02c0\u00ce\3\2\2\2\u02c1\u02c2\7k\2\2\u02c2\u02c3\7h\2"+ "\2\u02c7\u02c8\7x\2\2\u02c8\u02c9\7u\2\2\u02c9\u00d2\3\2\2\2\u02ca\u02cb"+
"\2\u02c3\u02c4\7a\2\2\u02c4\u02c5\7r\2\2\u02c5\u02c6\7q\2\2\u02c6\u02c7"+ "\7k\2\2\u02cb\u02cc\7h\2\2\u02cc\u02cd\7a\2\2\u02cd\u02ce\7x\2\2\u02ce"+
"\7u\2\2\u02c7\u00d0\3\2\2\2\u02c8\u02c9\7k\2\2\u02c9\u02ca\7h\2\2\u02ca"+ "\u02cf\7e\2\2\u02cf\u00d4\3\2\2\2\u02d0\u02d1\7h\2\2\u02d1\u02d2\7q\2"+
"\u02cb\7a\2\2\u02cb\u02cc\7o\2\2\u02cc\u02cd\7k\2\2\u02cd\u00d2\3\2\2"+ "\2\u02d2\u02d3\7t\2\2\u02d3\u00d6\3\2\2\2\u02d4\u02d5\7k\2\2\u02d5\u02d6"+
"\2\u02ce\u02cf\7k\2\2\u02cf\u02d0\7h\2\2\u02d0\u02d1\7a\2\2\u02d1\u02d2"+ "\7p\2\2\u02d6\u00d8\3\2\2\2\u02d7\u02d8\7y\2\2\u02d8\u02d9\7j\2\2\u02d9"+
"\7p\2\2\u02d2\u02d3\7g\2\2\u02d3\u02d4\7i\2\2\u02d4\u00d4\3\2\2\2\u02d5"+ "\u02da\7k\2\2\u02da\u02db\7n\2\2\u02db\u02dc\7g\2\2\u02dc\u00da\3\2\2"+
"\u02d6\7k\2\2\u02d6\u02d7\7h\2\2\u02d7\u02d8\7a\2\2\u02d8\u02d9\7x\2\2"+ "\2\u02dd\u02de\7t\2\2\u02de\u02df\7g\2\2\u02df\u02e0\7r\2\2\u02e0\u02e1"+
"\u02d9\u02da\7u\2\2\u02da\u00d6\3\2\2\2\u02db\u02dc\7k\2\2\u02dc\u02dd"+ "\7g\2\2\u02e1\u02e2\7c\2\2\u02e2\u02e3\7v\2\2\u02e3\u00dc\3\2\2\2\u02e4"+
"\7h\2\2\u02dd\u02de\7a\2\2\u02de\u02df\7x\2\2\u02df\u02e0\7e\2\2\u02e0"+ "\u02e5\7w\2\2\u02e5\u02e6\7p\2\2\u02e6\u02e7\7v\2\2\u02e7\u02e8\7k\2\2"+
"\u00d8\3\2\2\2\u02e1\u02e2\7h\2\2\u02e2\u02e3\7q\2\2\u02e3\u02e4\7t\2"+ "\u02e8\u02e9\7n\2\2\u02e9\u00de\3\2\2\2\u02ea\u02ee\t\2\2\2\u02eb\u02ed"+
"\2\u02e4\u00da\3\2\2\2\u02e5\u02e6\7k\2\2\u02e6\u02e7\7p\2\2\u02e7\u00dc"+ "\t\3\2\2\u02ec\u02eb\3\2\2\2\u02ed\u02f0\3\2\2\2\u02ee\u02ec\3\2\2\2\u02ee"+
"\3\2\2\2\u02e8\u02e9\7y\2\2\u02e9\u02ea\7j\2\2\u02ea\u02eb\7k\2\2\u02eb"+ "\u02ef\3\2\2\2\u02ef\u02f1\3\2\2\2\u02f0\u02ee\3\2\2\2\u02f1\u02f2\5\u00e1"+
"\u02ec\7n\2\2\u02ec\u02ed\7g\2\2\u02ed\u00de\3\2\2\2\u02ee\u02ef\7t\2"+ "q\2\u02f2\u02f3\3\2\2\2\u02f3\u02f4\bp\2\2\u02f4\u00e0\3\2\2\2\u02f5\u02f9"+
"\2\u02ef\u02f0\7g\2\2\u02f0\u02f1\7r\2\2\u02f1\u02f2\7g\2\2\u02f2\u02f3"+ "\7=\2\2\u02f6\u02f8\n\2\2\2\u02f7\u02f6\3\2\2\2\u02f8\u02fb\3\2\2\2\u02f9"+
"\7c\2\2\u02f3\u02f4\7v\2\2\u02f4\u00e0\3\2\2\2\u02f5\u02f6\7w\2\2\u02f6"+ "\u02f7\3\2\2\2\u02f9\u02fa\3\2\2\2\u02fa\u02fc\3\2\2\2\u02fb\u02f9\3\2"+
"\u02f7\7p\2\2\u02f7\u02f8\7v\2\2\u02f8\u02f9\7k\2\2\u02f9\u02fa\7n\2\2"+ "\2\2\u02fc\u02fd\bq\2\2\u02fd\u00e2\3\2\2\2\u02fe\u02ff\t\3\2\2\u02ff"+
"\u02fa\u00e2\3\2\2\2\u02fb\u02ff\t\2\2\2\u02fc\u02fe\t\3\2\2\u02fd\u02fc"+ "\u0300\3\2\2\2\u0300\u0301\br\3\2\u0301\u00e4\3\2\2\2\u0302\u0304\t\2"+
"\3\2\2\2\u02fe\u0301\3\2\2\2\u02ff\u02fd\3\2\2\2\u02ff\u0300\3\2\2\2\u0300"+ "\2\2\u0303\u0302\3\2\2\2\u0304\u0305\3\2\2\2\u0305\u0303\3\2\2\2\u0305"+
"\u0302\3\2\2\2\u0301\u02ff\3\2\2\2\u0302\u0303\5\u00e5s\2\u0303\u0304"+ "\u0306\3\2\2\2\u0306\u00e6\3\2\2\2\u0307\u030b\t\4\2\2\u0308\u030a\t\5"+
"\3\2\2\2\u0304\u0305\br\2\2\u0305\u00e4\3\2\2\2\u0306\u030a\7=\2\2\u0307"+ "\2\2\u0309\u0308\3\2\2\2\u030a\u030d\3\2\2\2\u030b\u0309\3\2\2\2\u030b"+
"\u0309\n\2\2\2\u0308\u0307\3\2\2\2\u0309\u030c\3\2\2\2\u030a\u0308\3\2"+ "\u030c\3\2\2\2\u030c\u00e8\3\2\2\2\u030d\u030b\3\2\2\2\u030e\u0316\4\62"+
"\2\2\u030a\u030b\3\2\2\2\u030b\u030d\3\2\2\2\u030c\u030a\3\2\2\2\u030d"+ ";\2\u030f\u0311\4\63;\2\u0310\u0312\4\62;\2\u0311\u0310\3\2\2\2\u0312"+
"\u030e\bs\2\2\u030e\u00e6\3\2\2\2\u030f\u0310\t\3\2\2\u0310\u0311\3\2"+ "\u0313\3\2\2\2\u0313\u0311\3\2\2\2\u0313\u0314\3\2\2\2\u0314\u0316\3\2"+
"\2\2\u0311\u0312\bt\3\2\u0312\u00e8\3\2\2\2\u0313\u0315\t\2\2\2\u0314"+ "\2\2\u0315\u030e\3\2\2\2\u0315\u030f\3\2\2\2\u0316\u00ea\3\2\2\2\u0317"+
"\u0313\3\2\2\2\u0315\u0316\3\2\2\2\u0316\u0314\3\2\2\2\u0316\u0317\3\2"+ "\u0319\7&\2\2\u0318\u031a\t\6\2\2\u0319\u0318\3\2\2\2\u031a\u031b\3\2"+
"\2\2\u0317\u00ea\3\2\2\2\u0318\u031c\t\4\2\2\u0319\u031b\t\5\2\2\u031a"+ "\2\2\u031b\u0319\3\2\2\2\u031b\u031c\3\2\2\2\u031c\u00ec\3\2\2\2\u031d"+
"\u0319\3\2\2\2\u031b\u031e\3\2\2\2\u031c\u031a\3\2\2\2\u031c\u031d\3\2"+ "\u031f\7\'\2\2\u031e\u0320\4\62\63\2\u031f\u031e\3\2\2\2\u0320\u0321\3"+
"\2\2\u031d\u00ec\3\2\2\2\u031e\u031c\3\2\2\2\u031f\u0327\4\62;\2\u0320"+ "\2\2\2\u0321\u031f\3\2\2\2\u0321\u0322\3\2\2\2\u0322\u00ee\3\2\2\2\u0323"+
"\u0322\4\63;\2\u0321\u0323\4\62;\2\u0322\u0321\3\2\2\2\u0323\u0324\3\2"+ "\u0329\5\u00f1y\2\u0324\u0326\t\7\2\2\u0325\u0327\t\b\2\2\u0326\u0325"+
"\2\2\u0324\u0322\3\2\2\2\u0324\u0325\3\2\2\2\u0325\u0327\3\2\2\2\u0326"+ "\3\2\2\2\u0326\u0327\3\2\2\2\u0327\u0328\3\2\2\2\u0328\u032a\5\u00f1y"+
"\u031f\3\2\2\2\u0326\u0320\3\2\2\2\u0327\u00ee\3\2\2\2\u0328\u032a\7&"+ "\2\u0329\u0324\3\2\2\2\u0329\u032a\3\2\2\2\u032a\u00f0\3\2\2\2\u032b\u032d"+
"\2\2\u0329\u032b\t\6\2\2\u032a\u0329\3\2\2\2\u032b\u032c\3\2\2\2\u032c"+ "\4\62;\2\u032c\u032b\3\2\2\2\u032d\u032e\3\2\2\2\u032e\u032c\3\2\2\2\u032e"+
"\u032a\3\2\2\2\u032c\u032d\3\2\2\2\u032d\u00f0\3\2\2\2\u032e\u0330\7\'"+ "\u032f\3\2\2\2\u032f\u0336\3\2\2\2\u0330\u0332\7\60\2\2\u0331\u0333\4"+
"\2\2\u032f\u0331\4\62\63\2\u0330\u032f\3\2\2\2\u0331\u0332\3\2\2\2\u0332"+ "\62;\2\u0332\u0331\3\2\2\2\u0333\u0334\3\2\2\2\u0334\u0332\3\2\2\2\u0334"+
"\u0330\3\2\2\2\u0332\u0333\3\2\2\2\u0333\u00f2\3\2\2\2\u0334\u033a\5\u00f5"+ "\u0335\3\2\2\2\u0335\u0337\3\2\2\2\u0336\u0330\3\2\2\2\u0336\u0337\3\2"+
"{\2\u0335\u0337\t\7\2\2\u0336\u0338\t\b\2\2\u0337\u0336\3\2\2\2\u0337"+ "\2\2\u0337\u00f2\3\2\2\2\u0338\u0339\7^\2\2\u0339\u033d\13\2\2\2\u033a"+
"\u0338\3\2\2\2\u0338\u0339\3\2\2\2\u0339\u033b\5\u00f5{\2\u033a\u0335"+ "\u033b\7^\2\2\u033b\u033d\5\u00e5s\2\u033c\u0338\3\2\2\2\u033c\u033a\3"+
"\3\2\2\2\u033a\u033b\3\2\2\2\u033b\u00f4\3\2\2\2\u033c\u033e\4\62;\2\u033d"+ "\2\2\2\u033d\u00f4\3\2\2\2\u033e\u0343\7$\2\2\u033f\u0342\5\u00f3z\2\u0340"+
"\u033c\3\2\2\2\u033e\u033f\3\2\2\2\u033f\u033d\3\2\2\2\u033f\u0340\3\2"+ "\u0342\n\t\2\2\u0341\u033f\3\2\2\2\u0341\u0340\3\2\2\2\u0342\u0345\3\2"+
"\2\2\u0340\u0347\3\2\2\2\u0341\u0343\7\60\2\2\u0342\u0344\4\62;\2\u0343"+ "\2\2\u0343\u0341\3\2\2\2\u0343\u0344\3\2\2\2\u0344\u0346\3\2\2\2\u0345"+
"\u0342\3\2\2\2\u0344\u0345\3\2\2\2\u0345\u0343\3\2\2\2\u0345\u0346\3\2"+ "\u0343\3\2\2\2\u0346\u0347\7$\2\2\u0347\u0348\b{\4\2\u0348\u00f6\3\2\2"+
"\2\2\u0346\u0348\3\2\2\2\u0347\u0341\3\2\2\2\u0347\u0348\3\2\2\2\u0348"+ "\2\u0349\u034a\7}\2\2\u034a\u034b\7}\2\2\u034b\u034d\3\2\2\2\u034c\u034e"+
"\u00f6\3\2\2\2\u0349\u034a\7^\2\2\u034a\u034e\13\2\2\2\u034b\u034c\7^"+ "\13\2\2\2\u034d\u034c\3\2\2\2\u034e\u034f\3\2\2\2\u034f\u0350\3\2\2\2"+
"\2\2\u034c\u034e\5\u00e9u\2\u034d\u0349\3\2\2\2\u034d\u034b\3\2\2\2\u034e"+ "\u034f\u034d\3\2\2\2\u0350\u0351\3\2\2\2\u0351\u0352\7\177\2\2\u0352\u0353"+
"\u00f8\3\2\2\2\u034f\u0354\7$\2\2\u0350\u0353\5\u00f7|\2\u0351\u0353\n"+ "\7\177\2\2\u0353\u0354\3\2\2\2\u0354\u0355\b|\5\2\u0355\u00f8\3\2\2\2"+
"\t\2\2\u0352\u0350\3\2\2\2\u0352\u0351\3\2\2\2\u0353\u0356\3\2\2\2\u0354"+ "\u0356\u0359\7)\2\2\u0357\u035a\5\u00f3z\2\u0358\u035a\n\t\2\2\u0359\u0357"+
"\u0352\3\2\2\2\u0354\u0355\3\2\2\2\u0355\u0357\3\2\2\2\u0356\u0354\3\2"+ "\3\2\2\2\u0359\u0358\3\2\2\2\u035a\u035b\3\2\2\2\u035b\u035c\7)\2\2\u035c"+
"\2\2\u0357\u0358\7$\2\2\u0358\u0359\b}\4\2\u0359\u00fa\3\2\2\2\u035a\u035b"+ "\u035d\b}\6\2\u035d\u00fa\3\2\2\2\u035e\u035f\7B\2\2\u035f\u0360\7|\2"+
"\7}\2\2\u035b\u035c\7}\2\2\u035c\u035e\3\2\2\2\u035d\u035f\13\2\2\2\u035e"+ "\2\u0360\u0361\7r\2\2\u0361\u00fc\3\2\2\2\26\2\u02ee\u02f9\u0305\u030b"+
"\u035d\3\2\2\2\u035f\u0360\3\2\2\2\u0360\u0361\3\2\2\2\u0360\u035e\3\2"+ "\u0313\u0315\u0319\u031b\u0321\u0326\u0329\u032e\u0334\u0336\u033c\u0341"+
"\2\2\u0361\u0362\3\2\2\2\u0362\u0363\7\177\2\2\u0363\u0364\7\177\2\2\u0364"+ "\u0343\u034f\u0359\7\2\3\2\b\2\2\3{\2\3|\3\3}\4";
"\u0365\3\2\2\2\u0365\u0366\b~\5\2\u0366\u00fc\3\2\2\2\u0367\u036a\7)\2"+
"\2\u0368\u036b\5\u00f7|\2\u0369\u036b\n\t\2\2\u036a\u0368\3\2\2\2\u036a"+
"\u0369\3\2\2\2\u036b\u036c\3\2\2\2\u036c\u036d\7)\2\2\u036d\u036e\b\177"+
"\6\2\u036e\u00fe\3\2\2\2\u036f\u0370\7B\2\2\u0370\u0371\7|\2\2\u0371\u0372"+
"\7r\2\2\u0372\u0100\3\2\2\2\26\2\u02ff\u030a\u0316\u031c\u0324\u0326\u032a"+
"\u032c\u0332\u0337\u033a\u033f\u0345\u0347\u034d\u0352\u0354\u0360\u036a"+
"\7\2\3\2\b\2\2\3}\2\3~\3\3\177\4";
public static final ATN _ATN = public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray()); new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static { static {

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="prog8" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id="prog8" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python">
<configuration sdkName="Python 3.7" />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
@@ -17,6 +12,5 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Python 3.7 interpreter library" level="application" />
</component> </component>
</module> </module>