Compare commits

...
49 Commits
Author SHA1 Message Date
Irmen de Jong 262e0bd6b9 fix avg() on float arrays 2019-04-21 03:04:36 +02:00
Irmen de Jong 755af6010e fix some more issues with array vardecls without array size specifier 2019-04-21 03:04:13 +02:00
Irmen de Jong 0298cf8b90 scripts use gradle build dirs 2019-04-20 13:26:04 +02:00
Irmen de Jong a6d0aecd66 fix invalid assignment reordering 2019-04-20 13:24:42 +02:00
Irmen de Jong ef6e364339 intellij idea config 2019-04-20 01:18:47 +02:00
Irmen de Jong 3b37e0f99d new build scripts 2019-04-20 00:50:15 +02:00
Irmen de Jong 78fbbf7119 %asmbinary implemented 2019-04-17 01:33:07 +02:00
Irmen de Jong 0ee43294c4 check for file with %asmbinary, %asminclude 2019-04-17 00:55:42 +02:00
Irmen de Jong a81b82495c fix wrong values generated from range expression in array vardecl 2019-04-17 00:27:27 +02:00
Irmen de Jong 390043e9e8 some fixes in syntaxchecking array initializer values 2019-04-16 01:50:12 +02:00
Irmen de Jong e384822b2c array size in vardecl is optional when initializer array value is given 2019-04-16 01:19:51 +02:00
Irmen de Jong 730e08698d comment 2019-04-13 00:58:39 +02:00
Irmen de Jong 5497de4234 optimize @( &thing )) in ast into just thing 2019-04-12 23:59:26 +02:00
Irmen de Jong c71b78dee6 use array of pointers to blocks instead of a large if statement 2019-04-12 23:35:27 +02:00
Irmen de Jong dfcb57a0b0 couple of small shortcuts on identifier ast to lookup what it is pointing to 2019-04-12 23:04:19 +02:00
Irmen de Jong f219ae43f7 more inspiring code example 2019-04-12 22:34:43 +02:00
Irmen de Jong a9bbe0bc40 removed the memory keyword instead use & now (reuse the address-of operator to reduce the number of different concepts in the grammar) 2019-04-12 22:00:32 +02:00
Irmen de Jong 35aa954be8 doc 2019-04-12 01:06:46 +02:00
Irmen de Jong 78ddcf9db7 address-of works the test program 2019-04-12 00:58:40 +02:00
Irmen de Jong cd0fa9405a comments 2019-04-12 00:54:04 +02:00
Irmen de Jong 4462def8ea fix array processing and ASM code gen of arrays with addressOf in them 2019-04-12 00:37:33 +02:00
Irmen de Jong 3f93b87745 fix array processing and ASM code gen of arrays with addressOf in them 2019-04-12 00:04:15 +02:00
Irmen de Jong 9f302cc640 docs about '&' operator 2019-04-11 21:41:46 +02:00
Irmen de Jong 0a73125606 fix auto-insertion of AddressOf expression in function call arguments 2019-04-11 21:32:23 +02:00
Irmen de Jong 7780441524 fix build scripts to point to new IntelliJ version 2019-04-11 21:26:46 +02:00
Irmen de Jong 8bec4eaa87 rename PointerOf to AddressOf 2019-04-11 21:01:02 +02:00
Irmen de Jong 4434d31a3b upgrade to Kotlin 1.3.30 and increase memory settings for command line build script 2019-04-11 19:58:28 +02:00
Irmen de Jong 51454c71c7 Merge branch 'master' into pointerto
# Conflicts:
#	compiler/res/prog8lib/c64flt.p8
2019-04-10 23:16:08 +02:00
Irmen de Jong fb2796ac06 truly fix min(f)/max(f) also fix ceil(f) 2019-04-10 23:14:28 +02:00
Irmen de Jong 742b15357b fix all(f) 2019-04-10 22:42:48 +02:00
Irmen de Jong ac6ed27052 restore tweaks in c64flt.p8 2019-04-10 22:18:45 +02:00
Irmen de Jong f3c1783bf2 correct intermediate code output of pointers in arrayvalues 2019-04-10 22:08:21 +02:00
Irmen de Jong ce8853ab50 restore tweaks in c64flt.p8 2019-04-08 00:36:19 +02:00
Irmen de Jong 5e3e00fbad fix stackvm 2019-04-08 00:29:10 +02:00
Irmen de Jong 1dde49d644 Merge branch 'master' into pointerto
# Conflicts:
#	compiler/res/prog8lib/c64flt.p8
#	compiler/src/prog8/stackvm/StackVm.kt
2019-04-08 00:19:18 +02:00
Irmen de Jong fd19298a05 fixed stackvm pop signed byte into register 2019-04-08 00:08:23 +02:00
Irmen de Jong ede2b83ce4 got rid of unused avg syscalls and fixed stackvm iterable functions (min, max, avg, sum, any, all) 2019-04-08 00:00:43 +02:00
Irmen de Jong fc47d3feb8 repaired min(f) max(f) fixes #13 2019-04-07 23:19:31 +02:00
Irmen de Jong 87446028e0 no more duplicate auto heap vars, attempt at automatic insertion of & expression for subroutine params 2019-04-05 13:14:19 +02:00
Irmen de Jong b200f9945f asmgen array with pointer values (w.i.p) 2019-04-04 23:51:22 +02:00
Irmen de Jong eebd4e5f18 fix float constants prefix mistakes, removed broken max_f/min_f (fix pending), tweaked sum_f 2019-04-04 23:39:28 +02:00
Irmen de Jong 1069b5f5d5 w.i.p pointer-to 2019-04-04 21:45:30 +02:00
Irmen de Jong 3e7e44acfe no hard crash anymore for invalid string escape sequences or unknown petscii characters 2019-04-03 22:25:26 +02:00
Irmen de Jong 518c3bfd76 actually, get rid of integer pow() because a naive multiplication loop approach is way too slow 2019-03-31 18:05:41 +02:00
Irmen de Jong 905d8a0c06 actually, get rid of integer pow() because a naive multiplication loop approach is way too slow 2019-03-31 18:04:19 +02:00
Irmen de Jong b57c02b0ba don't remove 'duplicate' assignments that aren't removable (i.e. not literalvalues) 2019-03-31 16:10:02 +02:00
Irmen de Jong 03d0411679 pow_f implemented 2019-03-31 14:28:38 +02:00
Irmen de Jong 83ace753b2 got rid of problematic signed POW operator, added compiler checks for this 2019-03-31 13:56:03 +02:00
Irmen de Jong ec2e7db23e doc fix 2019-03-30 00:40:09 +01:00
58 changed files with 2886 additions and 2415 deletions

No files matched your search

+1 -2
View File
@@ -1,11 +1,10 @@
**/.idea/
.idea/workspace.xml
/build/
/dist/
/output/
.*cache/
*.directory
*.prg
*.asm
*.bin
*.labels.txt
*.vm.txt
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="/usr/share/java/gradle" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/compiler" />
<option value="$PROJECT_DIR$/parser" />
</set>
</option>
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+40 -37
View File
@@ -50,55 +50,58 @@ of the [Vice emulator](http://vice-emu.sourceforge.net/)
Example code
------------
When this code is compiled::
This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
%import c64lib
%import c64utils
%import c64flt
%zeropage basicsafe
~ main {
ubyte[256] sieve
ubyte candidate_prime = 2
sub start() {
; set text color and activate lowercase charset
c64.COLOR = 13
c64.VMCSB |= 2
memset(sieve, 256, false)
; use optimized routine to write text
c64scr.print("Hello!\n")
; use iteration to write text
str question = "How are you?\n"
for ubyte char in question
c64.CHROUT(char)
; use indexed loop to write characters
str bye = "Goodbye!\n"
for ubyte c in 0 to len(bye)
c64.CHROUT(bye[c])
float clock_seconds = ((mkword(c64.TIME_LO, c64.TIME_MID) as float)
+ (c64.TIME_HI as float)*65536.0)
/ 60
float hours = floor(clock_seconds / 3600)
clock_seconds -= hours*3600
float minutes = floor(clock_seconds / 60)
clock_seconds = floor(clock_seconds - minutes * 60.0)
c64scr.print("system time in ti$ is ")
c64flt.print_f(hours)
c64.CHROUT(':')
c64flt.print_f(minutes)
c64.CHROUT(':')
c64flt.print_f(clock_seconds)
c64scr.print("prime numbers up to 255:\n\n")
ubyte amount=0
while true {
ubyte prime = find_next_prime()
if prime==0
break
c64scr.print_ub(prime)
c64scr.print(", ")
amount++
}
c64.CHROUT('\n')
c64scr.print("number of primes (expected 54): ")
c64scr.print_ub(amount)
c64.CHROUT('\n')
}
sub find_next_prime() -> ubyte {
while sieve[candidate_prime] {
candidate_prime++
if candidate_prime==0
return 0
}
sieve[candidate_prime] = true
uword multiple = candidate_prime
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
}
return candidate_prime
}
}
when compiled an ran on a C-64 you'll get:
you get a program that outputs this when loaded on a C-64:
![c64 screen](docs/source/_static/hello_screen.png)
![c64 screen](docs/source/_static/primes_example.png)
One of the included examples (wizzine.p8) animates a bunch of sprite balloons and looks like this:
+29 -5
View File
@@ -1,5 +1,5 @@
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.21"
id "org.jetbrains.kotlin.jvm" version "1.3.30"
id 'application'
}
@@ -8,7 +8,7 @@ repositories {
jcenter()
}
def kotlinVersion = '1.3.21'
def kotlinVersion = '1.3.30'
dependencies {
implementation project(':parser')
@@ -18,11 +18,18 @@ dependencies {
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.hamcrest:hamcrest-junit:2.0.0.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.2'
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
sourceSets {
main {
@@ -55,8 +62,8 @@ task p8vmScript(type: CreateStartScripts) {
}
applicationDistribution.into("bin") {
from(p8vmScript)
fileMode = 0755
from(p8vmScript)
fileMode = 0755
}
task fatJar(type: Jar) {
@@ -71,3 +78,20 @@ task fatJar(type: Jar) {
with jar
}
// build.finalizedBy(fatJar)
// Java target version
sourceCompatibility = 1.8
test {
// Enable JUnit 5 (Gradle 4.6+).
useJUnitPlatform()
// Always run tests, even when nothing changed.
dependsOn 'cleanTest'
// Show test results.
testLogging {
events "passed", "skipped", "failed"
}
}
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="antlr-runtime-4.7.2" level="project" />
<orderEntry type="library" name="testlibs" level="project" />
<orderEntry type="module" module-name="parser" />
</component>
</module>
+174 -160
View File
@@ -9,31 +9,32 @@
~ c64flt {
; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
; ---- C64 basic and kernal ROM float constants and functions ----
; note: the fac1 and fac2 are working registers and take 6 bytes each,
; floats in memory (and rom) are stored in 5-byte MFLPT packed format.
; constants in five-byte "mflpt" format in the BASIC ROM
memory float FL_PIVAL = $aea8 ; 3.1415926...
memory float FL_N32768 = $b1a5 ; -32768
memory float FL_FONE = $b9bc ; 1
memory float FL_SQRHLF = $b9d6 ; SQR(2) / 2
memory float FL_SQRTWO = $b9db ; SQR(2)
memory float FL_NEGHLF = $b9e0 ; -.5
memory float FL_LOG2 = $b9e5 ; LOG(2)
memory float FL_TENC = $baf9 ; 10
memory float FL_NZMIL = $bdbd ; 1e9 (1 billion)
memory float FL_FHALF = $bf11 ; .5
memory float FL_LOGEB2 = $bfbf ; 1 / LOG(2)
memory float FL_PIHALF = $e2e0 ; PI / 2
memory float FL_TWOPI = $e2e5 ; 2 * PI
memory float FL_FR4 = $e2ea ; .25
&float FL_PIVAL = $aea8 ; 3.1415926...
&float FL_N32768 = $b1a5 ; -32768
&float FL_FONE = $b9bc ; 1
&float FL_SQRHLF = $b9d6 ; SQR(2) / 2
&float FL_SQRTWO = $b9db ; SQR(2)
&float FL_NEGHLF = $b9e0 ; -.5
&float FL_LOG2 = $b9e5 ; LOG(2)
&float FL_TENC = $baf9 ; 10
&float FL_NZMIL = $bdbd ; 1e9 (1 billion)
&float FL_FHALF = $bf11 ; .5
&float FL_LOGEB2 = $bfbf ; 1 / LOG(2)
&float FL_PIHALF = $e2e0 ; PI / 2
&float FL_TWOPI = $e2e5 ; 2 * PI
&float FL_FR4 = $e2ea ; .25
float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel
; note: fac1/2 might get clobbered even if not mentioned in the function's name.
@@ -165,14 +166,14 @@ asmsub GIVAYFAY (uword value @ AY) -> clobbers(A,X,Y) -> () {
sta c64.SCRATCH_ZPREG
tya
ldy c64.SCRATCH_ZPREG
jmp c64flt.GIVAYF ; this uses the inverse order, Y/A
jmp GIVAYF ; this uses the inverse order, Y/A
}}
}
asmsub FTOSWRDAY () -> clobbers(X) -> (uword @ AY) {
; ---- fac1 to signed word in A/Y
%asm {{
jsr c64flt.FTOSWORDYA ; note the inverse Y/A order
jsr FTOSWORDYA ; note the inverse Y/A order
sta c64.SCRATCH_ZPREG
tya
ldy c64.SCRATCH_ZPREG
@@ -183,7 +184,7 @@ asmsub FTOSWRDAY () -> clobbers(X) -> (uword @ AY) {
asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) {
; ---- fac1 to unsigned word in A/Y
%asm {{
jsr c64flt.GETADR ; this uses the inverse order, Y/A
jsr GETADR ; this uses the inverse order, Y/A
sta c64.SCRATCH_ZPB1
tya
ldy c64.SCRATCH_ZPB1
@@ -192,13 +193,13 @@ asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) {
}
sub print_f (float value) {
; ---- prints the floating point value (without a newline) using basic rom routines.
; ---- prints the floating point value (without a newline) using basic rom routines.
%asm {{
stx c64.SCRATCH_ZPREGX
lda #<print_f_value
ldy #>print_f_value
jsr c64flt.MOVFM ; load float into fac1
jsr c64flt.FOUT ; fac1 to string in A/Y
jsr MOVFM ; load float into fac1
jsr FOUT ; fac1 to string in A/Y
jsr c64.STROUT ; print string in A/Y
ldx c64.SCRATCH_ZPREGX
rts
@@ -211,12 +212,12 @@ sub print_fln (float value) {
stx c64.SCRATCH_ZPREGX
lda #<print_fln_value
ldy #>print_fln_value
jsr c64flt.MOVFM ; load float into fac1
jsr c64flt.FPRINTLN ; print fac1 with newline
jsr MOVFM ; load float into fac1
jsr FPRINTLN ; print fac1 with newline
ldx c64.SCRATCH_ZPREGX
rts
}}
}
@@ -229,10 +230,10 @@ ub2float .proc
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
ldy c64.SCRATCH_ZPB1
jsr c64flt.FREADUY
jsr FREADUY
_fac_to_mem ldx c64.SCRATCH_ZPWORD2
ldy c64.SCRATCH_ZPWORD2+1
jsr c64flt.MOVMF
jsr MOVMF
ldx c64.SCRATCH_ZPREGX
rts
.pend
@@ -244,7 +245,7 @@ b2float .proc
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPB1
jsr c64flt.FREADSA
jsr FREADSA
jmp ub2float._fac_to_mem
.pend
@@ -255,7 +256,7 @@ uw2float .proc
sty c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.GIVUAYFAY
jsr GIVUAYFAY
jmp ub2float._fac_to_mem
.pend
@@ -266,26 +267,26 @@ w2float .proc
sty c64.SCRATCH_ZPWORD2+1
ldy c64.SCRATCH_ZPWORD1
lda c64.SCRATCH_ZPWORD1+1
jsr c64flt.GIVAYF
jsr GIVAYF
jmp ub2float._fac_to_mem
.pend
stack_b2float .proc
; -- b2float operating on the stack
inx
lda c64.ESTACK_LO,x
stx c64.SCRATCH_ZPREGX
jsr c64flt.FREADSA
jsr FREADSA
jmp push_fac1_as_result
.pend
stack_w2float .proc
; -- w2float operating on the stack
inx
ldy c64.ESTACK_LO,x
lda c64.ESTACK_HI,x
stx c64.SCRATCH_ZPREGX
jsr c64flt.GIVAYF
jsr GIVAYF
jmp push_fac1_as_result
.pend
@@ -295,7 +296,7 @@ stack_ub2float .proc
lda c64.ESTACK_LO,x
stx c64.SCRATCH_ZPREGX
tay
jsr c64flt.FREADUY
jsr FREADUY
jmp push_fac1_as_result
.pend
@@ -305,14 +306,14 @@ stack_uw2float .proc
lda c64.ESTACK_LO,x
ldy c64.ESTACK_HI,x
stx c64.SCRATCH_ZPREGX
jsr c64flt.GIVUAYFAY
jsr GIVUAYFAY
jmp push_fac1_as_result
.pend
stack_float2w .proc
stack_float2w .proc
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.AYINT
jsr AYINT
ldx c64.SCRATCH_ZPREGX
lda $64
sta c64.ESTACK_HI,x
@@ -321,11 +322,11 @@ stack_float2w .proc
dex
rts
.pend
stack_float2uw .proc
stack_float2uw .proc
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.GETADR
jsr GETADR
ldx c64.SCRATCH_ZPREGX
sta c64.ESTACK_HI,x
tya
@@ -335,7 +336,7 @@ stack_float2uw .proc
.pend
push_float .proc
; ---- push mflpt5 in A/Y onto stack
; ---- push mflpt5 in A/Y onto stack
; (taking 3 stack positions = 6 bytes of which 1 is padding)
sta c64.SCRATCH_ZPWORD1
sty c64.SCRATCH_ZPWORD1+1
@@ -359,23 +360,23 @@ push_float .proc
dex
rts
.pend
func_rndf .proc
; -- put a random floating point value on the stack
stx c64.SCRATCH_ZPREG
lda #1
jsr c64flt.FREADSA
jsr c64flt.RND ; rng into fac1
jsr FREADSA
jsr RND ; rng into fac1
ldx #<_rndf_rnum5
ldy #>_rndf_rnum5
jsr c64flt.MOVMF ; fac1 to mem X/Y
jsr MOVMF ; fac1 to mem X/Y
ldx c64.SCRATCH_ZPREG
lda #<_rndf_rnum5
ldy #>_rndf_rnum5
jmp push_float
_rndf_rnum5 .byte 0,0,0,0,0
.pend
push_float_from_indexed_var .proc
; -- push the float from the array at A/Y with index on stack, onto the stack.
sta c64.SCRATCH_ZPWORD1
@@ -412,7 +413,7 @@ pop_float .proc
sta (c64.SCRATCH_ZPWORD1),y
rts
.pend
pop_float_fac1 .proc
; -- pops float from stack into FAC1
lda #<fmath_float1
@@ -420,9 +421,9 @@ pop_float_fac1 .proc
jsr pop_float
lda #<fmath_float1
ldy #>fmath_float1
jmp c64flt.MOVFM
jmp MOVFM
.pend
pop_float_to_indexed_var .proc
; -- pop the float on the stack, to the memory in the array at A/Y indexed by the byte on stack
sta c64.SCRATCH_ZPWORD1
@@ -435,7 +436,7 @@ pop_float_to_indexed_var .proc
.pend
copy_float .proc
; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1,
; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1,
; into the 5 bytes pointed to by A/Y. Clobbers A,Y.
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
@@ -462,17 +463,17 @@ inc_var_f .proc
sta c64.SCRATCH_ZPWORD1
sty c64.SCRATCH_ZPWORD1+1
stx c64.SCRATCH_ZPREGX
jsr c64flt.MOVFM
jsr MOVFM
lda #<FL_FONE
ldy #>FL_FONE
jsr c64flt.FADD
jsr FADD
ldx c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.MOVMF
jsr MOVMF
ldx c64.SCRATCH_ZPREGX
rts
.pend
dec_var_f .proc
; -- subtract 1 from float pointed to by A/Y
sta c64.SCRATCH_ZPWORD1
@@ -480,17 +481,17 @@ dec_var_f .proc
stx c64.SCRATCH_ZPREGX
lda #<FL_FONE
ldy #>FL_FONE
jsr c64flt.MOVFM
jsr MOVFM
lda c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.FSUB
jsr FSUB
ldx c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.MOVMF
jsr MOVMF
ldx c64.SCRATCH_ZPREGX
rts
.pend
inc_indexed_var_f .proc
; -- add 1 to float in array pointed to by A/Y, at index X
pha
@@ -508,7 +509,7 @@ inc_indexed_var_f .proc
iny
+ jmp inc_var_f
.pend
dec_indexed_var_f .proc
; -- subtract 1 to float in array pointed to by A/Y, at index X
pha
@@ -526,7 +527,7 @@ dec_indexed_var_f .proc
iny
+ jmp dec_var_f
.pend
pop_2_floats_f2_in_fac1 .proc
; -- pop 2 floats from stack, load the second one in FAC1 as well
@@ -538,9 +539,10 @@ pop_2_floats_f2_in_fac1 .proc
jsr pop_float
lda #<fmath_float2
ldy #>fmath_float2
jmp c64flt.MOVFM
jmp MOVFM
.pend
fmath_float1 .byte 0,0,0,0,0 ; storage for a mflpt5 value
fmath_float2 .byte 0,0,0,0,0 ; storage for a mflpt5 value
@@ -548,13 +550,31 @@ push_fac1_as_result .proc
; -- push the float in FAC1 onto the stack, and return from calculation
ldx #<fmath_float1
ldy #>fmath_float1
jsr c64flt.MOVMF
jsr MOVMF
lda #<fmath_float1
ldy #>fmath_float1
ldx c64.SCRATCH_ZPREGX
jmp push_float
.pend
pow_f .proc
; -- push f1 ** f2 on stack
lda #<fmath_float2
ldy #>fmath_float2
jsr pop_float
lda #<fmath_float1
ldy #>fmath_float1
jsr pop_float
stx c64.SCRATCH_ZPREGX
lda #<fmath_float1
ldy #>fmath_float1
jsr CONUPK ; fac2 = float1
lda #<fmath_float2
ldy #>fmath_float2
jsr FPWR
ldx c64.SCRATCH_ZPREGX
jmp push_fac1_as_result
.pend
div_f .proc
; -- push f1/f2 on stack
@@ -562,7 +582,7 @@ div_f .proc
stx c64.SCRATCH_ZPREGX
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.FDIV
jsr FDIV
jmp push_fac1_as_result
.pend
@@ -572,7 +592,7 @@ add_f .proc
stx c64.SCRATCH_ZPREGX
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.FADD
jsr FADD
jmp push_fac1_as_result
.pend
@@ -582,7 +602,7 @@ sub_f .proc
stx c64.SCRATCH_ZPREGX
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.FSUB
jsr FSUB
jmp push_fac1_as_result
.pend
@@ -592,15 +612,15 @@ mul_f .proc
stx c64.SCRATCH_ZPREGX
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.FMULT
jsr FMULT
jmp push_fac1_as_result
.pend
neg_f .proc
; -- push -flt back on stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.NEGOP
jsr NEGOP
jmp push_fac1_as_result
.pend
@@ -608,7 +628,7 @@ abs_f .proc
; -- push abs(float) on stack (as float)
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.ABS
jsr ABS
jmp push_fac1_as_result
.pend
@@ -638,7 +658,7 @@ _equals_store inx
sta c64.ESTACK_LO+1,x
rts
_equals_false lda #0
beq _equals_store
beq _equals_store
.pend
notequal_f .proc
@@ -656,7 +676,7 @@ less_f .proc
beq compare_floats._return_true
bne compare_floats._return_false
.pend
lesseq_f .proc
; -- is f1 <= f2?
@@ -695,11 +715,11 @@ compare_floats .proc
jsr pop_float
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.MOVFM ; fac1 = flt1
jsr MOVFM ; fac1 = flt1
lda #<fmath_float2
ldy #>fmath_float2
stx c64.SCRATCH_ZPREG
jsr c64flt.FCOMP ; A = flt1 compared with flt2 (0=equal, 1=flt1>flt2, 255=flt1<flt2)
jsr FCOMP ; A = flt1 compared with flt2 (0=equal, 1=flt1>flt2, 255=flt1<flt2)
ldx c64.SCRATCH_ZPREG
rts
_return_false lda #0
@@ -708,13 +728,13 @@ _return_result sta c64.ESTACK_LO,x
rts
_return_true lda #1
bne _return_result
.pend
.pend
func_sin .proc
; -- push sin(f) back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.SIN
jsr SIN
jmp push_fac1_as_result
.pend
@@ -722,7 +742,7 @@ func_cos .proc
; -- push cos(f) back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.COS
jsr COS
jmp push_fac1_as_result
.pend
@@ -730,99 +750,99 @@ func_tan .proc
; -- push tan(f) back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.TAN
jsr TAN
jmp push_fac1_as_result
.pend
func_atan .proc
; -- push atan(f) back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.ATN
jsr ATN
jmp push_fac1_as_result
.pend
func_ln .proc
; -- push ln(f) back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.LOG
jsr LOG
jmp push_fac1_as_result
.pend
func_log2 .proc
; -- push log base 2, ln(f)/ln(2), back onto stack
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.LOG
jsr c64flt.MOVEF
jsr LOG
jsr MOVEF
lda #<c64.FL_LOG2
ldy #>c64.FL_LOG2
jsr c64flt.MOVFM
jsr c64flt.FDIVT
jsr MOVFM
jsr FDIVT
jmp push_fac1_as_result
.pend
func_sqrt .proc
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.SQR
jsr SQR
jmp push_fac1_as_result
.pend
func_rad .proc
; -- convert degrees to radians (d * pi / 180)
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
lda #<_pi_div_180
ldy #>_pi_div_180
jsr c64flt.FMULT
jsr FMULT
jmp push_fac1_as_result
_pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
.pend
func_deg .proc
; -- convert radians to degrees (d * (1/ pi * 180))
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
lda #<_one_over_pi_div_180
ldy #>_one_over_pi_div_180
jsr c64flt.FMULT
jsr FMULT
jmp push_fac1_as_result
_one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
.pend
func_round .proc
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.FADDH
jsr c64flt.INT
jsr FADDH
jsr INT
jmp push_fac1_as_result
.pend
func_floor .proc
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
jsr c64flt.INT
jsr INT
jmp push_fac1_as_result
.pend
func_ceil .proc
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
jsr pop_float_fac1
stx c64.SCRATCH_ZPREGX
ldx #<fmath_float1
ldy #>fmath_float1
jsr MOVMF
jsr INT
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.MOVMF
jsr c64flt.INT
lda #<fmath_float1
ldy #>fmath_float1
jsr c64flt.FCOMP
jsr FCOMP
cmp #0
beq +
lda #<FL_FONE
ldy #>FL_FONE
jsr c64flt.FADD
jsr FADD
+ jmp push_fac1_as_result
.pend
@@ -834,98 +854,93 @@ func_any_f .proc
asl a
clc
adc c64.SCRATCH_ZPB1 ; times 5 because of float
jmp func_any_b._entry
jmp prog8_lib.func_any_b._entry
.pend
func_all_f .proc
inx
jsr prog8_lib.peek_address
lda c64.ESTACK_LO,x ; array size
sta c64.SCRATCH_ZPB1
asl a
asl a
clc
adc c64.SCRATCH_ZPB1 ; times 5 because of float
sta _cmp_mod+1 ; self-modifying code
jsr peek_address
ldy #0
tay
dey
- lda (c64.SCRATCH_ZPWORD1),y
bne +
iny
lda (c64.SCRATCH_ZPWORD1),y
bne +
iny
lda (c64.SCRATCH_ZPWORD1),y
bne +
iny
lda (c64.SCRATCH_ZPWORD1),y
bne +
iny
lda (c64.SCRATCH_ZPWORD1),y
bne +
lda #0
sta c64.ESTACK_LO+1,x
rts
+ iny
_cmp_mod cpy #255 ; modified
bne -
clc
dey
adc (c64.SCRATCH_ZPWORD1),y
dey
adc (c64.SCRATCH_ZPWORD1),y
dey
adc (c64.SCRATCH_ZPWORD1),y
dey
adc (c64.SCRATCH_ZPWORD1),y
dey
cmp #0
beq +
cpy #255
bne -
lda #1
sta c64.ESTACK_LO+1,x
rts
+ sta c64.ESTACK_LO+1,x
rts
.pend
func_max_f .proc
lda #<_min_float
ldy #>_min_float
jsr c64flt.MOVFM ; fac1=min(float)
lda #255
sta _cmp_mod+1 ; compare using 255 so we keep larger values
_minmax_entry jsr pop_array_and_lengthmin1Y
sta _minmax_cmp+1
lda #<_largest_neg_float
ldy #>_largest_neg_float
_minmax_entry jsr MOVFM
jsr prog8_lib.pop_array_and_lengthmin1Y
stx c64.SCRATCH_ZPREGX
- sty c64.SCRATCH_ZPREG
lda c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.FCOMP
_cmp_mod cmp #255 ; will be modified
jsr FCOMP
_minmax_cmp cmp #255 ; modified
bne +
; fac1 is smaller/larger, so store the new value instead
lda c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.MOVFM
ldy c64.SCRATCH_ZPREG
dey
cmp #255
beq +
lda c64.SCRATCH_ZPWORD1
jsr MOVFM
+ lda c64.SCRATCH_ZPWORD1
clc
adc #5
sta c64.SCRATCH_ZPWORD1
bcc -
bcc +
inc c64.SCRATCH_ZPWORD1+1
+ ldy c64.SCRATCH_ZPREG
dey
cpy #255
bne -
+ jmp push_fac1_as_result
_min_float .byte 255,255,255,255,255 ; -1.7014118345e+38
jmp push_fac1_as_result
_largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38
.pend
func_min_f .proc
lda #<_max_float
ldy #>_max_float
jsr c64flt.MOVFM ; fac1=max(float)
lda #1
sta func_max_f._cmp_mod+1 ; compare using 1 so we keep smaller values
sta func_max_f._minmax_cmp+1
lda #<_largest_pos_float
ldy #>_largest_pos_float
jmp func_max_f._minmax_entry
_max_float .byte 255,127,255,255,255 ; 1.7014118345e+38
_largest_pos_float .byte 255,127,255,255,255 ; largest positive float
rts
.pend
func_sum_f .proc
lda #<c64.FL_NEGHLF
ldy #>c64.FL_NEGHLF
jsr c64flt.MOVFM
jsr pop_array_and_lengthmin1Y
lda #<FL_ZERO
ldy #>FL_ZERO
jsr MOVFM
jsr prog8_lib.pop_array_and_lengthmin1Y
stx c64.SCRATCH_ZPREGX
- sty c64.SCRATCH_ZPREG
lda c64.SCRATCH_ZPWORD1
ldy c64.SCRATCH_ZPWORD1+1
jsr c64flt.FADD
jsr FADD
ldy c64.SCRATCH_ZPREG
dey
cpy #255
@@ -937,8 +952,7 @@ func_sum_f .proc
bcc -
inc c64.SCRATCH_ZPWORD1+1
bne -
+ jsr c64flt.FADDH
jmp push_fac1_as_result
+ jmp push_fac1_as_result
.pend
}}
+144 -144
View File
@@ -7,178 +7,178 @@
~ c64 {
memory ubyte SCRATCH_ZPB1 = $02 ; scratch byte 1 in ZP
memory ubyte SCRATCH_ZPREG = $03 ; scratch register in ZP
memory ubyte SCRATCH_ZPREGX = $fa ; temp storage for X register (stack pointer)
memory uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
memory uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
const uword ESTACK_LO = $ce00 ; evaluation stack (lsb)
const uword ESTACK_HI = $cf00 ; evaluation stack (msb)
&ubyte SCRATCH_ZPB1 = $02 ; scratch byte 1 in ZP
&ubyte SCRATCH_ZPREG = $03 ; scratch register in ZP
&ubyte SCRATCH_ZPREGX = $fa ; temp storage for X register (stack pointer)
&uword SCRATCH_ZPWORD1 = $fb ; scratch word in ZP ($fb/$fc)
&uword SCRATCH_ZPWORD2 = $fd ; scratch word in ZP ($fd/$fe)
memory ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
memory ubyte TIME_MID = $a1 ; .. mid byte
memory ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
memory ubyte STKEY = $91 ; various keyboard statuses (updated by IRQ)
memory ubyte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
memory ubyte COLOR = $0286 ; cursor color
memory ubyte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
memory uword CINV = $0314 ; IRQ vector
memory uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
memory uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
memory uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
&ubyte TIME_MID = $a1 ; .. mid byte
&ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
&ubyte STKEY = $91 ; various keyboard statuses (updated by IRQ)
&ubyte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
&ubyte COLOR = $0286 ; cursor color
&ubyte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
&uword CINV = $0314 ; IRQ vector
&uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
&uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
&uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
; the default addresses for the character screen chars and colors
const uword Screen = $0400 ; to have this as an array[40*25] the compiler would have to support array size > 255
const uword Colors = $d800 ; to have this as an array[40*25] the compiler would have to support array size > 255
; the default locations of the 8 sprite pointers (store address of sprite / 64)
memory ubyte SPRPTR0 = 2040
memory ubyte SPRPTR1 = 2041
memory ubyte SPRPTR2 = 2042
memory ubyte SPRPTR3 = 2043
memory ubyte SPRPTR4 = 2044
memory ubyte SPRPTR5 = 2045
memory ubyte SPRPTR6 = 2046
memory ubyte SPRPTR7 = 2047
memory ubyte[8] SPRPTR = 2040 ; the 8 sprite pointers as an array.
&ubyte SPRPTR0 = 2040
&ubyte SPRPTR1 = 2041
&ubyte SPRPTR2 = 2042
&ubyte SPRPTR3 = 2043
&ubyte SPRPTR4 = 2044
&ubyte SPRPTR5 = 2045
&ubyte SPRPTR6 = 2046
&ubyte SPRPTR7 = 2047
&ubyte[8] SPRPTR = 2040 ; the 8 sprite pointers as an array.
; ---- VIC-II 6567/6569/856x registers ----
memory ubyte SP0X = $d000
memory ubyte SP0Y = $d001
memory ubyte SP1X = $d002
memory ubyte SP1Y = $d003
memory ubyte SP2X = $d004
memory ubyte SP2Y = $d005
memory ubyte SP3X = $d006
memory ubyte SP3Y = $d007
memory ubyte SP4X = $d008
memory ubyte SP4Y = $d009
memory ubyte SP5X = $d00a
memory ubyte SP5Y = $d00b
memory ubyte SP6X = $d00c
memory ubyte SP6Y = $d00d
memory ubyte SP7X = $d00e
memory ubyte SP7Y = $d00f
memory ubyte[16] SPXY = $d000 ; the 8 sprite X and Y registers as an array.
memory uword[8] SPXYW = $d000 ; the 8 sprite X and Y registers as a combined xy word array.
&ubyte SP0X = $d000
&ubyte SP0Y = $d001
&ubyte SP1X = $d002
&ubyte SP1Y = $d003
&ubyte SP2X = $d004
&ubyte SP2Y = $d005
&ubyte SP3X = $d006
&ubyte SP3Y = $d007
&ubyte SP4X = $d008
&ubyte SP4Y = $d009
&ubyte SP5X = $d00a
&ubyte SP5Y = $d00b
&ubyte SP6X = $d00c
&ubyte SP6Y = $d00d
&ubyte SP7X = $d00e
&ubyte SP7Y = $d00f
&ubyte[16] SPXY = $d000 ; the 8 sprite X and Y registers as an array.
&uword[8] SPXYW = $d000 ; the 8 sprite X and Y registers as a combined xy word array.
memory ubyte MSIGX = $d010
memory ubyte SCROLY = $d011
memory ubyte RASTER = $d012
memory ubyte LPENX = $d013
memory ubyte LPENY = $d014
memory ubyte SPENA = $d015
memory ubyte SCROLX = $d016
memory ubyte YXPAND = $d017
memory ubyte VMCSB = $d018
memory ubyte VICIRQ = $d019
memory ubyte IREQMASK = $d01a
memory ubyte SPBGPR = $d01b
memory ubyte SPMC = $d01c
memory ubyte XXPAND = $d01d
memory ubyte SPSPCL = $d01e
memory ubyte SPBGCL = $d01f
&ubyte MSIGX = $d010
&ubyte SCROLY = $d011
&ubyte RASTER = $d012
&ubyte LPENX = $d013
&ubyte LPENY = $d014
&ubyte SPENA = $d015
&ubyte SCROLX = $d016
&ubyte YXPAND = $d017
&ubyte VMCSB = $d018
&ubyte VICIRQ = $d019
&ubyte IREQMASK = $d01a
&ubyte SPBGPR = $d01b
&ubyte SPMC = $d01c
&ubyte XXPAND = $d01d
&ubyte SPSPCL = $d01e
&ubyte SPBGCL = $d01f
memory ubyte EXTCOL = $d020 ; border color
memory ubyte BGCOL0 = $d021 ; screen color
memory ubyte BGCOL1 = $d022
memory ubyte BGCOL2 = $d023
memory ubyte BGCOL4 = $d024
memory ubyte SPMC0 = $d025
memory ubyte SPMC1 = $d026
memory ubyte SP0COL = $d027
memory ubyte SP1COL = $d028
memory ubyte SP2COL = $d029
memory ubyte SP3COL = $d02a
memory ubyte SP4COL = $d02b
memory ubyte SP5COL = $d02c
memory ubyte SP6COL = $d02d
memory ubyte SP7COL = $d02e
memory ubyte[8] SPCOL = $d027
&ubyte EXTCOL = $d020 ; border color
&ubyte BGCOL0 = $d021 ; screen color
&ubyte BGCOL1 = $d022
&ubyte BGCOL2 = $d023
&ubyte BGCOL4 = $d024
&ubyte SPMC0 = $d025
&ubyte SPMC1 = $d026
&ubyte SP0COL = $d027
&ubyte SP1COL = $d028
&ubyte SP2COL = $d029
&ubyte SP3COL = $d02a
&ubyte SP4COL = $d02b
&ubyte SP5COL = $d02c
&ubyte SP6COL = $d02d
&ubyte SP7COL = $d02e
&ubyte[8] SPCOL = $d027
; ---- end of VIC-II registers ----
; ---- CIA 6526 1 & 2 registers ----
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 (and joystick control port #1)
memory ubyte CIA1DDRA = $DC02 ; CIA 1 DDRA, keyboard column
memory ubyte CIA1DDRB = $DC03 ; CIA 1 DDRB, keyboard row
memory ubyte CIA1TAL = $DC04 ; CIA 1 timer A low byte
memory ubyte CIA1TAH = $DC05 ; CIA 1 timer A high byte
memory ubyte CIA1TBL = $DC06 ; CIA 1 timer B low byte
memory ubyte CIA1TBH = $DC07 ; CIA 1 timer B high byte
memory ubyte CIA1TOD10 = $DC08 ; time of day, 1/10 sec.
memory ubyte CIA1TODSEC = $DC09 ; time of day, seconds
memory ubyte CIA1TODMMIN = $DC0A ; time of day, minutes
memory ubyte CIA1TODHR = $DC0B ; time of day, hours
memory ubyte CIA1SDR = $DC0C ; Serial Data Register
memory ubyte CIA1ICR = $DC0D
memory ubyte CIA1CRA = $DC0E
memory ubyte CIA1CRB = $DC0F
&ubyte CIA1PRA = $DC00 ; CIA 1 DRA, keyboard column drive (and joystick control port #2)
&ubyte CIA1PRB = $DC01 ; CIA 1 DRB, keyboard row port (and joystick control port #1)
&ubyte CIA1DDRA = $DC02 ; CIA 1 DDRA, keyboard column
&ubyte CIA1DDRB = $DC03 ; CIA 1 DDRB, keyboard row
&ubyte CIA1TAL = $DC04 ; CIA 1 timer A low byte
&ubyte CIA1TAH = $DC05 ; CIA 1 timer A high byte
&ubyte CIA1TBL = $DC06 ; CIA 1 timer B low byte
&ubyte CIA1TBH = $DC07 ; CIA 1 timer B high byte
&ubyte CIA1TOD10 = $DC08 ; time of day, 1/10 sec.
&ubyte CIA1TODSEC = $DC09 ; time of day, seconds
&ubyte CIA1TODMMIN = $DC0A ; time of day, minutes
&ubyte CIA1TODHR = $DC0B ; time of day, hours
&ubyte CIA1SDR = $DC0C ; Serial Data Register
&ubyte CIA1ICR = $DC0D
&ubyte CIA1CRA = $DC0E
&ubyte CIA1CRB = $DC0F
memory ubyte CIA2PRA = $DD00 ; CIA 2 DRA, serial port and video address
memory ubyte CIA2PRB = $DD01 ; CIA 2 DRB, RS232 port / USERPORT
memory ubyte CIA2DDRA = $DD02 ; CIA 2 DDRA, serial port and video address
memory ubyte CIA2DDRB = $DD03 ; CIA 2 DDRB, RS232 port / USERPORT
memory ubyte CIA2TAL = $DD04 ; CIA 2 timer A low byte
memory ubyte CIA2TAH = $DD05 ; CIA 2 timer A high byte
memory ubyte CIA2TBL = $DD06 ; CIA 2 timer B low byte
memory ubyte CIA2TBH = $DD07 ; CIA 2 timer B high byte
memory ubyte CIA2TOD10 = $DD08 ; time of day, 1/10 sec.
memory ubyte CIA2TODSEC = $DD09 ; time of day, seconds
memory ubyte CIA2TODMIN = $DD0A ; time of day, minutes
memory ubyte CIA2TODHR = $DD0B ; time of day, hours
memory ubyte CIA2SDR = $DD0C ; Serial Data Register
memory ubyte CIA2ICR = $DD0D
memory ubyte CIA2CRA = $DD0E
memory ubyte CIA2CRB = $DD0F
&ubyte CIA2PRA = $DD00 ; CIA 2 DRA, serial port and video address
&ubyte CIA2PRB = $DD01 ; CIA 2 DRB, RS232 port / USERPORT
&ubyte CIA2DDRA = $DD02 ; CIA 2 DDRA, serial port and video address
&ubyte CIA2DDRB = $DD03 ; CIA 2 DDRB, RS232 port / USERPORT
&ubyte CIA2TAL = $DD04 ; CIA 2 timer A low byte
&ubyte CIA2TAH = $DD05 ; CIA 2 timer A high byte
&ubyte CIA2TBL = $DD06 ; CIA 2 timer B low byte
&ubyte CIA2TBH = $DD07 ; CIA 2 timer B high byte
&ubyte CIA2TOD10 = $DD08 ; time of day, 1/10 sec.
&ubyte CIA2TODSEC = $DD09 ; time of day, seconds
&ubyte CIA2TODMIN = $DD0A ; time of day, minutes
&ubyte CIA2TODHR = $DD0B ; time of day, hours
&ubyte CIA2SDR = $DD0C ; Serial Data Register
&ubyte CIA2ICR = $DD0D
&ubyte CIA2CRA = $DD0E
&ubyte CIA2CRB = $DD0F
; ---- end of CIA registers ----
; ---- SID 6581/8580 registers ----
memory ubyte FREQLO1 = $D400 ; channel 1 freq lo
memory ubyte FREQHI1 = $D401 ; channel 1 freq hi
memory uword FREQ1 = $D400 ; channel 1 freq (word)
memory ubyte PWLO1 = $D402 ; channel 1 pulse width lo (7-0)
memory ubyte PWHI1 = $D403 ; channel 1 pulse width hi (11-8)
memory uword PW1 = $D402 ; channel 1 pulse width (word)
memory ubyte CR1 = $D404 ; channel 1 voice control register
memory ubyte AD1 = $D405 ; channel 1 attack & decay
memory ubyte SR1 = $D406 ; channel 1 sustain & release
memory ubyte FREQLO2 = $D407 ; channel 2 freq lo
memory ubyte FREQHI2 = $D408 ; channel 2 freq hi
memory uword FREQ2 = $D407 ; channel 2 freq (word)
memory ubyte PWLO2 = $D409 ; channel 2 pulse width lo (7-0)
memory ubyte PWHI2 = $D40A ; channel 2 pulse width hi (11-8)
memory uword PW2 = $D409 ; channel 2 pulse width (word)
memory ubyte CR2 = $D40B ; channel 2 voice control register
memory ubyte AD2 = $D40C ; channel 2 attack & decay
memory ubyte SR2 = $D40D ; channel 2 sustain & release
memory ubyte FREQLO3 = $D40E ; channel 3 freq lo
memory ubyte FREQHI3 = $D40F ; channel 3 freq hi
memory uword FREQ3 = $D40E ; channel 3 freq (word)
memory ubyte PWLO3 = $D410 ; channel 3 pulse width lo (7-0)
memory ubyte PWHI3 = $D411 ; channel 3 pulse width hi (11-8)
memory uword PW3 = $D410 ; channel 3 pulse width (word)
memory ubyte CR3 = $D412 ; channel 3 voice control register
memory ubyte AD3 = $D413 ; channel 3 attack & decay
memory ubyte SR3 = $D414 ; channel 3 sustain & release
memory ubyte FCLO = $D415 ; filter cutoff lo (2-0)
memory ubyte FCHI = $D416 ; filter cutoff hi (10-3)
memory uword FC = $D415 ; filter cutoff (word)
memory ubyte RESFILT = $D417 ; filter resonance and routing
memory ubyte MVOL = $D418 ; filter mode and main volume control
memory ubyte POTX = $D419 ; potentiometer X
memory ubyte POTY = $D41A ; potentiometer Y
memory ubyte OSC3 = $D41B ; channel 3 oscillator value read
memory ubyte ENV3 = $D41C ; channel 3 envelope value read
&ubyte FREQLO1 = $D400 ; channel 1 freq lo
&ubyte FREQHI1 = $D401 ; channel 1 freq hi
&uword FREQ1 = $D400 ; channel 1 freq (word)
&ubyte PWLO1 = $D402 ; channel 1 pulse width lo (7-0)
&ubyte PWHI1 = $D403 ; channel 1 pulse width hi (11-8)
&uword PW1 = $D402 ; channel 1 pulse width (word)
&ubyte CR1 = $D404 ; channel 1 voice control register
&ubyte AD1 = $D405 ; channel 1 attack & decay
&ubyte SR1 = $D406 ; channel 1 sustain & release
&ubyte FREQLO2 = $D407 ; channel 2 freq lo
&ubyte FREQHI2 = $D408 ; channel 2 freq hi
&uword FREQ2 = $D407 ; channel 2 freq (word)
&ubyte PWLO2 = $D409 ; channel 2 pulse width lo (7-0)
&ubyte PWHI2 = $D40A ; channel 2 pulse width hi (11-8)
&uword PW2 = $D409 ; channel 2 pulse width (word)
&ubyte CR2 = $D40B ; channel 2 voice control register
&ubyte AD2 = $D40C ; channel 2 attack & decay
&ubyte SR2 = $D40D ; channel 2 sustain & release
&ubyte FREQLO3 = $D40E ; channel 3 freq lo
&ubyte FREQHI3 = $D40F ; channel 3 freq hi
&uword FREQ3 = $D40E ; channel 3 freq (word)
&ubyte PWLO3 = $D410 ; channel 3 pulse width lo (7-0)
&ubyte PWHI3 = $D411 ; channel 3 pulse width hi (11-8)
&uword PW3 = $D410 ; channel 3 pulse width (word)
&ubyte CR3 = $D412 ; channel 3 voice control register
&ubyte AD3 = $D413 ; channel 3 attack & decay
&ubyte SR3 = $D414 ; channel 3 sustain & release
&ubyte FCLO = $D415 ; filter cutoff lo (2-0)
&ubyte FCHI = $D416 ; filter cutoff hi (10-3)
&uword FC = $D415 ; filter cutoff (word)
&ubyte RESFILT = $D417 ; filter resonance and routing
&ubyte MVOL = $D418 ; filter mode and main volume control
&ubyte POTX = $D419 ; potentiometer X
&ubyte POTY = $D41A ; potentiometer Y
&ubyte OSC3 = $D41B ; channel 3 oscillator value read
&ubyte ENV3 = $D41C ; channel 3 envelope value read
; ---- end of SID registers ----
+10 -10
View File
@@ -58,29 +58,29 @@ multiply_words .proc
stx c64.SCRATCH_ZPREGX
mult16 lda #$00
sta multiply_words_result+2 ; clear upper bits of product
sta multiply_words_result+3
sta result+2 ; clear upper bits of product
sta result+3
ldx #16 ; for all 16 bits...
- lsr c64.SCRATCH_ZPWORD1+1 ; divide multiplier by 2
ror c64.SCRATCH_ZPWORD1
bcc +
lda multiply_words_result+2 ; get upper half of product and add multiplicand
lda result+2 ; get upper half of product and add multiplicand
clc
adc c64.SCRATCH_ZPWORD2
sta multiply_words_result+2
lda multiply_words_result+3
sta result+2
lda result+3
adc c64.SCRATCH_ZPWORD2+1
+ ror a ; rotate partial product
sta multiply_words_result+3
ror multiply_words_result+2
ror multiply_words_result+1
ror multiply_words_result
sta result+3
ror result+2
ror result+1
ror result
dex
bne -
ldx c64.SCRATCH_ZPREGX
rts
multiply_words_result .byte 0,0,0,0
result .byte 0,0,0,0
.pend
+19 -19
View File
@@ -105,7 +105,7 @@ not_word .proc
sta c64.ESTACK_HI + 1,x
rts
.pend
bitand_b .proc
; -- bitwise and (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -114,7 +114,7 @@ bitand_b .proc
sta c64.ESTACK_LO+1,x
rts
.pend
bitor_b .proc
; -- bitwise or (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -123,7 +123,7 @@ bitor_b .proc
sta c64.ESTACK_LO+1,x
rts
.pend
bitxor_b .proc
; -- bitwise xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -144,7 +144,7 @@ bitand_w .proc
inx
rts
.pend
bitor_w .proc
; -- bitwise or (of 2 words)
lda c64.ESTACK_LO+2,x
@@ -156,7 +156,7 @@ bitor_w .proc
inx
rts
.pend
bitxor_w .proc
; -- bitwise xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -168,7 +168,7 @@ bitxor_w .proc
inx
rts
.pend
and_b .proc
; -- logical and (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -183,7 +183,7 @@ and_b .proc
sta c64.ESTACK_LO+1,x
rts
.pend
or_b .proc
; -- logical or (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -194,7 +194,7 @@ or_b .proc
sta c64.ESTACK_LO+1,x
rts
.pend
xor_b .proc
; -- logical xor (of 2 bytes)
lda c64.ESTACK_LO+2,x
@@ -227,7 +227,7 @@ and_w .proc
sta c64.ESTACK_HI+1,x
rts
.pend
or_w .proc
; -- logical or (word or word -> byte)
lda c64.ESTACK_LO+2,x
@@ -241,7 +241,7 @@ or_w .proc
sta c64.ESTACK_HI+1,x
rts
.pend
xor_w .proc
; -- logical xor (word xor word -> byte)
lda c64.ESTACK_LO+2,x
@@ -322,9 +322,9 @@ mul_word .proc
stx c64.SCRATCH_ZPREGX
jsr math.multiply_words
ldx c64.SCRATCH_ZPREGX
lda math.multiply_words.multiply_words_result
lda math.multiply_words.result
sta c64.ESTACK_LO+1,x
lda math.multiply_words.multiply_words_result+1
lda math.multiply_words.result+1
sta c64.ESTACK_HI+1,x
rts
.pend
@@ -648,8 +648,8 @@ func_read_flags .proc
dex
rts
.pend
func_sqrt16 .proc
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD2
@@ -698,8 +698,8 @@ _skip3
rts
_stab .byte $01,$02,$04,$08,$10,$20,$40,$80
.pend
func_sin8 .proc
ldy c64.ESTACK_LO+1,x
lda _sinecos8,y
@@ -1194,7 +1194,7 @@ func_rndw .proc
.pend
func_memcopy .proc
func_memcopy .proc
; note: clobbers A,Y
inx
stx c64.SCRATCH_ZPREGX
@@ -1220,7 +1220,7 @@ func_memcopy .proc
rts
.pend
func_memset .proc
func_memset .proc
; note: clobbers A,Y
inx
stx c64.SCRATCH_ZPREGX
@@ -1240,7 +1240,7 @@ func_memset .proc
rts
.pend
func_memsetw .proc
func_memsetw .proc
; note: clobbers A,Y
; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
+1 -1
View File
@@ -1 +1 @@
1.5 (beta)
1.7
+5
View File
@@ -152,6 +152,11 @@ private fun compileMain(args: Array<String>) {
System.err.println(px.message)
System.err.print("\u001b[0m") // reset
exitProcess(1)
} catch (ax: AstException) {
System.err.print("\u001b[91m") // bright red
System.err.println(ax.toString())
System.err.print("\u001b[0m") // reset
exitProcess(1)
} catch (x: Exception) {
print("\u001b[91m") // bright red
println("\n* internal error *")
+86 -42
View File
@@ -11,6 +11,7 @@ import prog8.functions.NotConstArgumentException
import prog8.functions.builtinFunctionReturnType
import prog8.parser.CustomLexer
import prog8.parser.prog8Parser
import java.io.CharConversionException
import java.io.File
import java.nio.file.Path
import kotlin.math.abs
@@ -41,13 +42,10 @@ enum class DataType {
UWORD -> targetType == UWORD || targetType == FLOAT
WORD -> targetType == WORD || targetType==UWORD || targetType == FLOAT
FLOAT -> targetType == FLOAT
STR -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_S -> targetType == STR || targetType==STR_S || targetType == UWORD
ARRAY_UB -> targetType == UWORD || targetType==ARRAY_UB
ARRAY_B -> targetType == UWORD || targetType==ARRAY_B
ARRAY_UW -> targetType == UWORD || targetType==ARRAY_UW
ARRAY_W -> targetType == UWORD || targetType==ARRAY_W
ARRAY_F -> targetType == UWORD || targetType==ARRAY_F
STR -> targetType == STR || targetType==STR_S
STR_S -> targetType == STR || targetType==STR_S
in ArrayDatatypes -> targetType === this
else -> false
}
@@ -158,7 +156,7 @@ interface IAstProcessor {
fun process(decl: VarDecl): IStatement {
decl.value = decl.value?.process(this)
decl.arrayspec?.process(this)
decl.arraysize?.process(this)
return decl
}
@@ -212,6 +210,7 @@ interface IAstProcessor {
}
fun process(literalValue: LiteralValue): LiteralValue {
literalValue.arrayvalue?.forEach { it.process(this) }
return literalValue
}
@@ -290,6 +289,11 @@ interface IAstProcessor {
memwrite.addressExpression = memwrite.addressExpression.process(this)
return memwrite
}
fun process(addressOf: AddressOf): IExpression {
process(addressOf.identifier)
return addressOf
}
}
@@ -624,30 +628,30 @@ class Break(override val position: Position) : IStatement {
}
class ArraySpec(var x: IExpression, override val position: Position) : Node {
class ArrayIndex(var index: IExpression, override val position: Position) : Node {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
x.linkParents(this)
index.linkParents(this)
}
companion object {
fun forArray(v: LiteralValue, heap: HeapValues): ArraySpec {
fun forArray(v: LiteralValue, heap: HeapValues): ArrayIndex {
val arraySize = v.arrayvalue?.size ?: heap.get(v.heapId!!).arraysize
return ArraySpec(LiteralValue.optimalNumeric(arraySize, v.position), v.position)
return ArrayIndex(LiteralValue.optimalNumeric(arraySize, v.position), v.position)
}
}
fun process(processor: IAstProcessor) {
x = x.process(processor)
index = index.process(processor)
}
override fun toString(): String {
return("ArraySpec($x, pos=$position)")
return("ArrayIndex($index, pos=$position)")
}
fun size() = (x as? LiteralValue)?.asIntegerValue
fun size() = (index as? LiteralValue)?.asIntegerValue
}
@@ -660,7 +664,8 @@ enum class VarDeclType {
class VarDecl(val type: VarDeclType,
private val declaredDatatype: DataType,
val zeropage: Boolean,
val arrayspec: ArraySpec?,
var arraysize: ArrayIndex?,
val isUnsizedArray: Boolean,
val name: String,
var value: IExpression?,
override val position: Position) : IStatement {
@@ -668,7 +673,7 @@ class VarDecl(val type: VarDeclType,
val datatypeErrors = mutableListOf<SyntaxError>() // don't crash at init time, report them in the AstChecker
val datatype =
if (arrayspec == null) declaredDatatype
if (arraysize == null && !isUnsizedArray) declaredDatatype
else when (declaredDatatype) {
DataType.UBYTE -> DataType.ARRAY_UB
DataType.BYTE -> DataType.ARRAY_B
@@ -683,7 +688,7 @@ class VarDecl(val type: VarDeclType,
override fun linkParents(parent: Node) {
this.parent = parent
arrayspec?.linkParents(this)
arraysize?.linkParents(this)
value?.linkParents(this)
}
@@ -704,7 +709,7 @@ class VarDecl(val type: VarDeclType,
DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue=0.0, position=position)
else -> throw FatalAstException("can only set a default value for a numeric type")
}
val decl = VarDecl(type, declaredDatatype, zeropage, arrayspec, name, constValue, position)
val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, isUnsizedArray, name, constValue, position)
if(parent!=null)
decl.linkParents(parent)
return decl
@@ -801,6 +806,9 @@ data class AssignTarget(val register: Register?,
return (if(withTypePrefix) "1address::" else "") +address.asIntegerValue.toString()
return if(withTypePrefix) "???::???" else "???"
}
fun isMemoryMapped(namespace: INameScope): Boolean =
memoryAddress!=null || (identifier?.targetVarDecl(namespace)?.type==VarDeclType.MEMORY)
}
@@ -947,7 +955,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
}
class ArrayIndexedExpression(val identifier: IdentifierReference,
var arrayspec: ArraySpec,
var arrayspec: ArrayIndex,
override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
@@ -979,7 +987,7 @@ class ArrayIndexedExpression(val identifier: IdentifierReference,
}
override fun toString(): String {
return "ArrayIndexed(ident=$identifier, arrayspec=$arrayspec; pos=$position)"
return "ArrayIndexed(ident=$identifier, arraysize=$arrayspec; pos=$position)"
}
}
@@ -1008,6 +1016,23 @@ class TypecastExpression(var expression: IExpression, var type: DataType, overri
}
data class AddressOf(val identifier: IdentifierReference, override val position: Position) : IExpression {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
identifier.parent=this
}
var scopedname: String? = null // will be set in a later state by the compiler
override fun isIterable(namespace: INameScope, heap: HeapValues) = false
override fun constValue(namespace: INameScope, heap: HeapValues): LiteralValue? = null
override fun referencesIdentifier(name: String) = false
override fun resultingDatatype(namespace: INameScope, heap: HeapValues) = DataType.UWORD
override fun process(processor: IAstProcessor) = processor.process(this)
}
class DirectMemoryRead(var addressExpression: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node
@@ -1165,8 +1190,8 @@ class LiteralValue(val type: DataType,
else "str:$initialstrvalue"
}
in ArrayDatatypes -> {
if(heapId!=null) "arrayspec:#$heapId"
else "arrayspec:$arrayvalue"
if(heapId!=null) "array:#$heapId"
else "array:$arrayvalue"
}
else -> throw FatalAstException("weird datatype")
}
@@ -1395,6 +1420,9 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
else
namespace.lookup(nameInSource, this)
fun targetVarDecl(namespace: INameScope): VarDecl? = targetStatement(namespace) as? VarDecl
fun targetSubroutine(namespace: INameScope): Subroutine? = targetStatement(namespace) as? Subroutine
override fun linkParents(parent: Node) {
this.parent = parent
}
@@ -1831,40 +1859,47 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
return VarDecl(VarDeclType.VAR,
it.datatype().toAst(),
it.ZEROPAGE()!=null,
it.arrayspec()?.toAst(),
it.arrayindex()?.toAst(),
it.ARRAYSIG()!=null,
it.identifier().text,
null,
it.toPosition())
}
varinitializer()?.let {
val vd = it.vardecl()
return VarDecl(VarDeclType.VAR,
it.vardecl().datatype().toAst(),
it.vardecl().ZEROPAGE()!=null,
it.vardecl().arrayspec()?.toAst(),
it.vardecl().identifier().text,
vd.datatype().toAst(),
vd.ZEROPAGE()!=null,
vd.arrayindex()?.toAst(),
vd.ARRAYSIG()!=null,
vd.identifier().text,
it.expression().toAst(),
it.toPosition())
}
constdecl()?.let {
val cvarinit = it.varinitializer()
val vd = cvarinit.vardecl()
return VarDecl(VarDeclType.CONST,
cvarinit.vardecl().datatype().toAst(),
cvarinit.vardecl().ZEROPAGE()!=null,
cvarinit.vardecl().arrayspec()?.toAst(),
cvarinit.vardecl().identifier().text,
vd.datatype().toAst(),
vd.ZEROPAGE()!=null,
vd.arrayindex()?.toAst(),
vd.ARRAYSIG()!=null,
vd.identifier().text,
cvarinit.expression().toAst(),
cvarinit.toPosition())
}
memoryvardecl()?.let {
val mvarinit = it.varinitializer()
val vd = mvarinit.vardecl()
return VarDecl(VarDeclType.MEMORY,
mvarinit.vardecl().datatype().toAst(),
mvarinit.vardecl().ZEROPAGE()!=null,
mvarinit.vardecl().arrayspec()?.toAst(),
mvarinit.vardecl().identifier().text,
vd.datatype().toAst(),
vd.ZEROPAGE()!=null,
vd.arrayindex()?.toAst(),
vd.ARRAYSIG()!=null,
vd.identifier().text,
mvarinit.expression().toAst(),
mvarinit.toPosition())
}
@@ -2060,8 +2095,8 @@ private fun prog8Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperC
private fun prog8Parser.RegisterorpairContext.toAst() = RegisterOrPair.valueOf(text.toUpperCase())
private fun prog8Parser.ArrayspecContext.toAst() : ArraySpec =
ArraySpec(expression().toAst(), toPosition())
private fun prog8Parser.ArrayindexContext.toAst() : ArrayIndex =
ArrayIndex(expression().toAst(), toPosition())
private fun prog8Parser.DirectiveContext.toAst() : Directive =
@@ -2145,10 +2180,16 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
}
litval.floatliteral()!=null -> LiteralValue(DataType.FLOAT, floatvalue = litval.floatliteral().toAst(), position = litval.toPosition())
litval.stringliteral()!=null -> LiteralValue(DataType.STR, strvalue = unescape(litval.stringliteral().text, litval.toPosition()), position = litval.toPosition())
litval.charliteral()!=null -> LiteralValue(DataType.UBYTE, bytevalue = Petscii.encodePetscii(unescape(litval.charliteral().text, litval.toPosition()), true)[0], position = litval.toPosition())
litval.charliteral()!=null -> {
try {
LiteralValue(DataType.UBYTE, bytevalue = Petscii.encodePetscii(unescape(litval.charliteral().text, litval.toPosition()), true)[0], position = litval.toPosition())
} catch (ce: CharConversionException) {
throw SyntaxError(ce.message ?: ce.toString(), litval.toPosition())
}
}
litval.arrayliteral()!=null -> {
val array = litval.arrayliteral()?.toAst()
// the actual type of the arrayspec can not yet be determined here (missing namespace & heap)
// the actual type of the arraysize can not yet be determined here (missing namespace & heap)
// the ConstantFolder takes care of that and converts the type if needed.
LiteralValue(DataType.ARRAY_UB, arrayvalue = array, position = litval.toPosition())
}
@@ -2189,13 +2230,16 @@ private fun prog8Parser.ExpressionContext.toAst() : IExpression {
if(directmemory()!=null)
return DirectMemoryRead(directmemory().expression().toAst(), toPosition())
if(addressof()!=null)
return AddressOf(addressof().scoped_identifier().toAst(), toPosition())
throw FatalAstException(text)
}
private fun prog8Parser.ArrayindexedContext.toAst(): ArrayIndexedExpression {
return ArrayIndexedExpression(scoped_identifier().toAst(),
arrayspec().toAst(),
arrayindex().toAst(),
toPosition())
}
@@ -2304,7 +2348,7 @@ internal fun unescape(str: String, position: Position): String {
'u' -> {
"${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}".toInt(16).toChar()
}
else -> throw AstException("$position invalid escape char in string: \\$ec")
else -> throw SyntaxError("invalid escape char in string: \\$ec", position)
})
} else {
result.add(c)
+86 -57
View File
@@ -7,6 +7,7 @@ import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
import prog8.functions.BuiltinFunctions
import prog8.optimizing.same
import prog8.parser.ParsingFailedError
import java.io.File
/**
* General checks on the Ast
@@ -58,7 +59,7 @@ private class AstChecker(private val namespace: INameScope,
private val heapStringSentinel: Int
init {
val stringSentinel = heap.allEntries().firstOrNull {it.value.str==""}
heapStringSentinel = stringSentinel?.key ?: heap.add(DataType.STR, "")
heapStringSentinel = stringSentinel?.key ?: heap.addString(DataType.STR, "")
}
fun result(): List<AstException> {
@@ -150,7 +151,7 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position))
} else {
// loop variable
val loopvar = forLoop.loopVar!!.targetStatement(namespace) as? VarDecl
val loopvar = forLoop.loopVar!!.targetVarDecl(namespace)
if(loopvar==null || loopvar.type==VarDeclType.CONST) {
checkResult.add(SyntaxError("for loop requires a variable to loop with", forLoop.position))
@@ -333,7 +334,7 @@ private class AstChecker(private val namespace: INameScope,
if(subroutine.asmClobbers.intersect(regCounts.keys).isNotEmpty())
err("a return register is also in the clobber list")
} else {
// TODO: non-asm subroutines can only take numeric arguments for now. (not strings and arrays)
// TODO: non-asm subroutines can only take numeric arguments for now. (not strings and arrays) Maybe this can be improved now that we have '&' ?
// the way string params are treated is almost okay (their address is passed) but the receiving subroutine treats it as an integer rather than referring back to the original string.
// the way array params are treated is buggy; it thinks the subroutine needs a byte parameter in place of a byte[] ...
// This is not easy to fix because strings and arrays are treated a bit simplistic (a "virtual" pointer to the value on the heap)
@@ -401,23 +402,10 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return assignment
}
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
if(targetSymbol.datatype==DataType.UWORD)
return assignment // array can be assigned to UWORD (it's address should be taken as the value then)
}
}
}
}
// it is only possible to assign an array to something that is an UWORD or UWORD array (in which case the address of the array value is used as the value)
if(assignment.value.resultingDatatype(namespace, heap) in ArrayDatatypes) {
// the UWORD case has been handled above already, check for UWORD array
val arrayVar = target.arrayindexed?.identifier?.targetStatement(namespace)
if(arrayVar is VarDecl && arrayVar.datatype==DataType.ARRAY_UW)
return assignment
checkResult.add(SyntaxError("it's not possible to assign an array to something other than an UWORD, use it as a variable decl initializer instead", assignment.position))
}
if(assignment.aug_op!=null) {
// check augmented assignment (and convert it into a normal assignment!)
// A /= 3 -> check as if it was A = A / 3
@@ -443,10 +431,10 @@ private class AstChecker(private val namespace: INameScope,
if(constVal!=null) {
val arrayspec = if(target.identifier!=null) {
val targetVar = namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
targetVar?.arrayspec
targetVar?.arraysize
} else null
checkValueTypeAndRange(targetDatatype,
arrayspec ?: ArraySpec(LiteralValue.optimalInteger(-1, assignment.position), assignment.position),
arrayspec ?: ArrayIndex(LiteralValue.optimalInteger(-1, assignment.position), assignment.position),
constVal, heap)
} else {
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap)
@@ -468,6 +456,18 @@ private class AstChecker(private val namespace: INameScope,
return assignment
}
override fun process(addressOf: AddressOf): IExpression {
val variable=addressOf.identifier.targetVarDecl(namespace)
if(variable==null)
checkResult.add(ExpressionError("pointer-of operand must be the name of a heap variable", addressOf.position))
else {
if(variable.datatype !in ArrayDatatypes && variable.datatype !in StringDatatypes)
checkResult.add(ExpressionError("pointer-of operand must be the name of a string or array heap variable", addressOf.position))
}
if(addressOf.scopedname==null)
throw FatalAstException("the scopedname of AddressOf should have been set by now $addressOf")
return super.process(addressOf)
}
/**
* Check the variable declarations (values within range etc)
@@ -478,7 +478,7 @@ private class AstChecker(private val namespace: INameScope,
}
// the initializer value can't refer to the variable itself (recursive definition)
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arrayspec?.x?.referencesIdentifier(decl.name) == true) {
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.index?.referencesIdentifier(decl.name) == true) {
err("recursive var declaration")
}
@@ -493,6 +493,22 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", decl.position))
}
// ARRAY without size specifier MUST have an iterable initializer value
if(decl.isUnsizedArray) {
if(decl.type==VarDeclType.MEMORY)
checkResult.add(SyntaxError("memory mapped array must have a size specification", decl.position))
if(decl.value==null) {
checkResult.add(SyntaxError("array variable is missing a size specification or an initialization value", decl.position))
return decl
}
if(decl.value is LiteralValue && !(decl.value as LiteralValue).isArray) {
checkResult.add(SyntaxError("unsized array declaration cannot use a single literal initialization value", decl.position))
return decl
}
if(decl.value is RangeExpr)
throw FatalAstException("range expressions in vardecls should have been converted into array values during constFolding $decl")
}
when(decl.type) {
VarDeclType.VAR, VarDeclType.CONST -> {
if (decl.value == null) {
@@ -514,13 +530,16 @@ private class AstChecker(private val namespace: INameScope,
return super.process(decl)
}
when {
decl.value is RangeExpr -> checkValueTypeAndRange(decl.datatype, decl.arrayspec, decl.value as RangeExpr)
decl.value is RangeExpr -> {
if(!decl.isUnsizedArray)
checkValueTypeAndRange(decl.datatype, decl.arraysize!!, decl.value as RangeExpr)
}
decl.value is LiteralValue -> {
val arraySpec = decl.arrayspec ?: (
val arraySpec = decl.arraysize ?: (
if((decl.value as LiteralValue).isArray)
ArraySpec.forArray(decl.value as LiteralValue, heap)
ArrayIndex.forArray(decl.value as LiteralValue, heap)
else
ArraySpec(LiteralValue.optimalInteger(-2, decl.position), decl.position)
ArrayIndex(LiteralValue.optimalInteger(-2, decl.position), decl.position)
)
checkValueTypeAndRange(decl.datatype, arraySpec, decl.value as LiteralValue, heap)
}
@@ -531,8 +550,8 @@ private class AstChecker(private val namespace: INameScope,
}
}
VarDeclType.MEMORY -> {
if(decl.arrayspec!=null) {
val arraySize = decl.arrayspec.size() ?: 1
if(decl.arraysize!=null) {
val arraySize = decl.arraysize!!.size() ?: 1
when(decl.datatype) {
DataType.ARRAY_B, DataType.ARRAY_UB ->
if(arraySize > 256)
@@ -614,6 +633,7 @@ private class AstChecker(private val namespace: INameScope,
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].str==null)
err("invalid asminclude directive, expected arguments: \"filename\", \"scopelabel\"")
checkFileExists(directive, directive.args[0].str!!)
}
"%asmbinary" -> {
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
@@ -623,6 +643,7 @@ private class AstChecker(private val namespace: INameScope,
if(directive.args.size>=2 && directive.args[1].int==null) err(errormsg)
if(directive.args.size==3 && directive.args[2].int==null) err(errormsg)
if(directive.args.size>3) err(errormsg)
checkFileExists(directive, directive.args[0].str!!)
}
"%option" -> {
if(directive.parent !is Block && directive.parent !is Module) err("this directive may only occur in a block or at module level")
@@ -636,15 +657,23 @@ private class AstChecker(private val namespace: INameScope,
return super.process(directive)
}
private fun checkFileExists(directive: Directive, filename: String) {
var definingModule = directive.parent
while (definingModule !is Module)
definingModule = definingModule.parent
if (!(filename.startsWith("library:") || definingModule.importedFrom.resolveSibling(filename).toFile().isFile || File(filename).isFile))
checkResult.add(NameError("included file not found: $filename", directive.position))
}
override fun process(literalValue: LiteralValue): LiteralValue {
if(!compilerOptions.floats && literalValue.type==DataType.FLOAT) {
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", literalValue.position))
}
val arrayspec =
if(literalValue.isArray)
ArraySpec.forArray(literalValue, heap)
ArrayIndex.forArray(literalValue, heap)
else
ArraySpec(LiteralValue.optimalInteger(-3, literalValue.position), literalValue.position)
ArrayIndex(LiteralValue.optimalInteger(-3, literalValue.position), literalValue.position)
checkValueTypeAndRange(literalValue.type, arrayspec, literalValue, heap)
val lv = super.process(literalValue)
@@ -673,6 +702,9 @@ private class AstChecker(private val namespace: INameScope,
}
override fun process(expr: BinaryExpression): IExpression {
val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap)
when(expr.operator){
"/", "%" -> {
val constvalRight = expr.right.constValue(namespace, heap)
@@ -680,16 +712,16 @@ private class AstChecker(private val namespace: INameScope,
if(divisor==0.0)
checkResult.add(ExpressionError("division by zero", expr.right.position))
if(expr.operator=="%") {
val rightDt = constvalRight?.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if ((rightDt != DataType.UBYTE && rightDt != DataType.UWORD) || (leftDt!=DataType.UBYTE && leftDt!=DataType.UWORD))
checkResult.add(ExpressionError("remainder can only be used on unsigned integer operands", expr.right.position))
}
}
"**" -> {
if(leftDt in IntegerDatatypes)
checkResult.add(ExpressionError("power operator requires floating point", expr.position))
}
"and", "or", "xor" -> {
// only integer numeric operands accepted, and if literal constants, only boolean values accepted (0 or 1)
val rightDt = expr.right.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
checkResult.add(ExpressionError("logical operator can only be used on boolean operands", expr.right.position))
val constLeft = expr.left.constValue(namespace, heap)
@@ -699,15 +731,11 @@ private class AstChecker(private val namespace: INameScope,
}
"&", "|", "^" -> {
// only integer numeric operands accepted
val rightDt = expr.right.resultingDatatype(namespace, heap)
val leftDt = expr.left.resultingDatatype(namespace, heap)
if(leftDt !in IntegerDatatypes || rightDt !in IntegerDatatypes)
checkResult.add(ExpressionError("bitwise operator can only be used on integer operands", expr.right.position))
}
}
val leftDt = expr.left.resultingDatatype(namespace, heap)
val rightDt = expr.right.resultingDatatype(namespace, heap)
if(leftDt !in NumericDatatypes)
checkResult.add(ExpressionError("left operand is not numeric", expr.left.position))
if(rightDt!in NumericDatatypes)
@@ -818,8 +846,11 @@ private class AstChecker(private val namespace: INameScope,
else {
for (arg in args.withIndex().zip(target.parameters)) {
val argDt = arg.first.value.resultingDatatype(namespace, heap)
if(argDt!=null && !argDt.assignableTo(arg.second.type))
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} has invalid type $argDt, expected ${arg.second.type}", position))
if(argDt!=null && !argDt.assignableTo(arg.second.type)) {
// for asm subroutines having STR param it's okay to provide a UWORD too (pointer value)
if(!(target.isAsmSubroutine && arg.second.type in StringDatatypes && argDt==DataType.UWORD))
checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.type}", position))
}
if(target.isAsmSubroutine) {
if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) {
@@ -879,17 +910,17 @@ private class AstChecker(private val namespace: INameScope,
if(target is VarDecl) {
if(target.datatype !in IterableDatatypes)
checkResult.add(SyntaxError("indexing requires an iterable variable", arrayIndexedExpression.position))
val arraysize = target.arrayspec?.size()
val arraysize = target.arraysize?.size()
if(arraysize!=null) {
// check out of bounds
val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue
val index = (arrayIndexedExpression.arrayspec.index as? LiteralValue)?.asIntegerValue
if(index!=null && (index<0 || index>=arraysize))
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position))
} else if(target.datatype in StringDatatypes) {
// check string lengths
val heapId = (target.value as LiteralValue).heapId!!
val stringLen = heap.get(heapId).str!!.length
val index = (arrayIndexedExpression.arrayspec.x as? LiteralValue)?.asIntegerValue
val index = (arrayIndexedExpression.arrayspec.index as? LiteralValue)?.asIntegerValue
if(index!=null && (index<0 || index>=stringLen))
checkResult.add(ExpressionError("index out of bounds", arrayIndexedExpression.arrayspec.position))
}
@@ -897,7 +928,7 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(SyntaxError("indexing requires a variable to act upon", arrayIndexedExpression.position))
// check index value 0..255
val dtx = arrayIndexedExpression.arrayspec.x.resultingDatatype(namespace, heap)
val dtx = arrayIndexedExpression.arrayspec.index.resultingDatatype(namespace, heap)
if(dtx!=DataType.UBYTE && dtx!=DataType.BYTE)
checkResult.add(SyntaxError("array indexing is limited to byte size 0..255", arrayIndexedExpression.position))
@@ -912,7 +943,7 @@ private class AstChecker(private val namespace: INameScope,
return null
}
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArraySpec?, range: RangeExpr) : Boolean {
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArrayIndex, range: RangeExpr) : Boolean {
val from = range.from.constValue(namespace, heap)
val to = range.to.constValue(namespace, heap)
if(from==null || to==null) {
@@ -940,7 +971,7 @@ private class AstChecker(private val namespace: INameScope,
}
in ArrayDatatypes -> {
// range and length check bytes
val expectedSize = arrayspec!!.size()
val expectedSize = arrayspec.size()
val rangeSize=range.size(heap)
if(rangeSize!=null && rangeSize != expectedSize) {
checkResult.add(ExpressionError("range size doesn't match array size, expected $expectedSize found $rangeSize", range.position))
@@ -952,7 +983,7 @@ private class AstChecker(private val namespace: INameScope,
}
}
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArraySpec, value: LiteralValue, heap: HeapValues) : Boolean {
private fun checkValueTypeAndRange(targetDt: DataType, arrayspec: ArrayIndex, value: LiteralValue, heap: HeapValues) : Boolean {
fun err(msg: String) : Boolean {
checkResult.add(ExpressionError(msg, value.position))
return false
@@ -985,8 +1016,6 @@ private class AstChecker(private val namespace: INameScope,
return err("value '$number' out of range for byte")
}
DataType.UWORD -> {
if(value.isString || value.isArray) // string or array are assignable to uword; their memory address is used.
return true
val number = value.asIntegerValue ?: return if (value.floatvalue!=null)
err("unsigned word value expected instead of float; possible loss of precision")
else
@@ -1010,7 +1039,7 @@ private class AstChecker(private val namespace: INameScope,
return err("string length must be 0-255")
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
// value may be either a single byte, or a byte arrayspec (of all constant values)
// value may be either a single byte, or a byte arraysize (of all constant values), or a range
if(value.type==targetDt) {
if(!checkArrayValues(value, targetDt))
return false
@@ -1019,7 +1048,7 @@ private class AstChecker(private val namespace: INameScope,
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize<1 || arraySpecSize>256)
return err("byte array length must be 1-256")
val constX = arrayspec.x.constValue(namespace, heap)
val constX = arrayspec.index.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
@@ -1032,7 +1061,7 @@ private class AstChecker(private val namespace: INameScope,
return err("invalid byte array initialization value ${value.type}, expected $targetDt")
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
// value may be either a single word, or a word arrayspec
// value may be either a single word, or a word arraysize, or a range
if(value.type==targetDt) {
if(!checkArrayValues(value, targetDt))
return false
@@ -1041,7 +1070,7 @@ private class AstChecker(private val namespace: INameScope,
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize<1 || arraySpecSize>128)
return err("word array length must be 1-128")
val constX = arrayspec.x.constValue(namespace, heap)
val constX = arrayspec.index.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
@@ -1054,7 +1083,7 @@ private class AstChecker(private val namespace: INameScope,
return err("invalid word array initialization value ${value.type}, expected $targetDt")
}
DataType.ARRAY_F -> {
// value may be either a single float, or a float arrayspec
// value may be either a single float, or a float arraysize
if(value.type==targetDt) {
if(!checkArrayValues(value, targetDt))
return false
@@ -1063,7 +1092,7 @@ private class AstChecker(private val namespace: INameScope,
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize < 1 || arraySpecSize>51)
return err("float array length must be 1-51")
val constX = arrayspec.x.constValue(namespace, heap)
val constX = arrayspec.index.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
@@ -1092,16 +1121,16 @@ private class AstChecker(private val namespace: INameScope,
val correct: Boolean
when(type) {
DataType.ARRAY_UB -> {
correct=array.array!=null && array.array.all { it in 0..255 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in 0..255 }
}
DataType.ARRAY_B -> {
correct=array.array!=null && array.array.all { it in -128..127 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in -128..127 }
}
DataType.ARRAY_UW -> {
correct=array.array!=null && array.array.all { it in 0..65535 }
correct=array.array!=null && array.array.all { (it.integer!=null && it.integer in 0..65535) || it.addressOf!=null}
}
DataType.ARRAY_W -> {
correct=array.array!=null && array.array.all { it in -32768..32767 }
correct=array.array!=null && array.array.all { it.integer!=null && it.integer in -32768..32767 }
}
DataType.ARRAY_F -> correct = array.doubleArray!=null
else -> throw AstException("invalid array type $type")
@@ -1124,7 +1153,7 @@ private class AstChecker(private val namespace: INameScope,
DataType.BYTE -> sourceDatatype==DataType.BYTE
DataType.UBYTE -> sourceDatatype==DataType.UBYTE
DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.WORD
DataType.UWORD -> sourceDatatype in setOf(DataType.UBYTE, DataType.UWORD, DataType.STR, DataType.STR_S) || sourceDatatype in ArrayDatatypes
DataType.UWORD -> sourceDatatype==DataType.UBYTE || sourceDatatype==DataType.UWORD
DataType.FLOAT -> sourceDatatype in NumericDatatypes
DataType.STR -> sourceDatatype==DataType.STR
DataType.STR_S -> sourceDatatype==DataType.STR_S
@@ -14,7 +14,7 @@ fun Module.checkIdentifiers(namespace: INameScope) {
// add any anonymous variables for heap values that are used,
// and replace an iterable literalvalue by identifierref to new local variable
for (variable in checker.anonymousVariablesFromHeap) {
for (variable in checker.anonymousVariablesFromHeap.values) {
val scope = variable.first.definingScope()
scope.statements.add(variable.second)
val parent = variable.first.parent
@@ -126,7 +126,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
subroutine.parameters
.filter { it.name !in allDefinedNames }
.forEach {
val vardecl = VarDecl(VarDeclType.VAR, it.type, false, null, it.name, null, subroutine.position)
val vardecl = VarDecl(VarDeclType.VAR, it.type, false, null, false, it.name, null, subroutine.position)
vardecl.linkParents(subroutine)
subroutine.statements.add(0, vardecl)
}
@@ -164,7 +164,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
if(existing==null) {
// create the local scoped for loop variable itself
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, true, null, varName, null, forLoop.loopVar.position)
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, true, null, false, varName, null, forLoop.loopVar.position)
vardecl.linkParents(forLoop.body)
forLoop.body.statements.add(0, vardecl)
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
@@ -176,7 +176,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first())
if(existing==null) {
// create loop iteration counter variable (without value, to avoid an assignment)
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, true, null, ForLoop.iteratorLoopcounterVarname, null, forLoop.loopVar.position)
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, true, null, false, ForLoop.iteratorLoopcounterVarname, null, forLoop.loopVar.position)
vardecl.linkParents(forLoop.body)
forLoop.body.statements.add(0, vardecl)
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
@@ -217,18 +217,26 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro
}
internal val anonymousVariablesFromHeap = mutableSetOf<Pair<LiteralValue, VarDecl>>()
internal val anonymousVariablesFromHeap = mutableMapOf<String, Pair<LiteralValue, VarDecl>>()
override fun process(literalValue: LiteralValue): LiteralValue {
if(literalValue.heapId!=null && literalValue.parent !is VarDecl) {
// a literal value that's not declared as a variable, which refers to something on the heap.
// we need to introduce an auto-generated variable for this to be able to refer to the value!
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, literalValue.position)
anonymousVariablesFromHeap.add(Pair(literalValue, variable))
val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, false, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, literalValue.position)
anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable)
}
return super.process(literalValue)
}
override fun process(addressOf: AddressOf): IExpression {
// register the scoped name of the referenced identifier
val variable= addressOf.identifier.targetVarDecl(namespace) ?: return addressOf
addressOf.scopedname = variable.scopedname
return super.process(addressOf)
}
}
private const val autoHeapValuePrefix = "auto_heap_value_"
internal const val autoHeapValuePrefix = "auto_heap_value_"
+80 -9
View File
@@ -3,7 +3,7 @@ package prog8.ast
import prog8.compiler.HeapValues
fun Module.reorderStatements(namespace: INameScope, heap: HeapValues) {
val initvalueCreator = VarInitValueCreator()
val initvalueCreator = VarInitValueAndAddressOfCreator(namespace)
this.process(initvalueCreator)
val checker = StatementReorderer(namespace, heap)
@@ -155,12 +155,23 @@ private class StatementReorderer(private val namespace: INameScope, private val
return scope
}
override fun process(decl: VarDecl): IStatement {
if(decl.arraysize==null) {
val array = decl.value as? LiteralValue
if(array!=null && array.isArray) {
val size = heap.get(array.heapId!!).arraysize
decl.arraysize = ArrayIndex(LiteralValue.optimalInteger(size, decl.position), decl.position)
}
}
return super.process(decl)
}
private fun sortConstantAssignments(statements: MutableList<IStatement>) {
// sort assignments by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once)
val result = mutableListOf<IStatement>()
val stmtIter = statements.iterator()
for(stmt in stmtIter) {
if(stmt is Assignment) {
if(stmt is Assignment && !stmt.targets.any { it.isMemoryMapped(namespace) }) {
val constval = stmt.value.constValue(namespace, heap)
if(constval!=null) {
val (sorted, trailing) = sortConstantAssignmentSequence(stmt, stmtIter)
@@ -203,7 +214,7 @@ private class StatementReorderer(private val namespace: INameScope, private val
}
private class VarInitValueCreator: IAstProcessor {
private class VarInitValueAndAddressOfCreator(private val namespace: INameScope): IAstProcessor {
// Replace the var decl with an assignment and add a new vardecl with the default constant value.
// This makes sure the variables get reset to the intended value on a next run of the program.
// Variable decls without a value don't get this treatment, which means they retain the last
@@ -211,7 +222,10 @@ private class VarInitValueCreator: IAstProcessor {
// This is done in a separate step because it interferes with the namespace lookup of symbols
// in other ast processors.
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
// Also takes care to insert AddressOf (&) expression where required (string params to a UWORD function param etc).
private val vardeclsToAdd = mutableMapOf<INameScope, MutableMap<String, VarDecl>>()
override fun process(module: Module) {
super.process(module)
@@ -219,8 +233,8 @@ private class VarInitValueCreator: IAstProcessor {
// add any new vardecls to the various scopes
for(decl in vardeclsToAdd)
for(d in decl.value) {
d.linkParents(decl.key as Node)
decl.key.statements.add(0, d)
d.value.linkParents(decl.key as Node)
decl.key.statements.add(0, d.value)
}
}
@@ -231,9 +245,7 @@ private class VarInitValueCreator: IAstProcessor {
if(decl.datatype in NumericDatatypes) {
val scope = decl.definingScope()
if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableListOf()
vardeclsToAdd.getValue(scope).add(decl.asDefaultValueDecl(null))
addVarDecl(scope, decl.asDefaultValueDecl(null))
val declvalue = decl.value!!
val value =
if(declvalue is LiteralValue) {
@@ -252,4 +264,63 @@ private class VarInitValueCreator: IAstProcessor {
return decl
}
override fun process(functionCall: FunctionCall): IExpression {
val targetStatement = functionCall.target.targetSubroutine(namespace)
if(targetStatement!=null) {
var node: Node = functionCall
while(node !is IStatement)
node=node.parent
addAddressOfExprIfNeeded(targetStatement, functionCall.arglist, node)
}
return functionCall
}
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
val targetStatement = functionCallStatement.target.targetSubroutine(namespace)
if(targetStatement!=null)
addAddressOfExprIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement)
return functionCallStatement
}
private fun addAddressOfExprIfNeeded(subroutine: Subroutine, arglist: MutableList<IExpression>, parent: IStatement) {
// functions that accept UWORD and are given an array type, or string, will receive the AddressOf (memory location) of that value instead.
for(argparam in subroutine.parameters.withIndex().zip(arglist)) {
if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type in StringDatatypes) {
if(argparam.second is AddressOf)
continue
val idref = argparam.second as? IdentifierReference
val strvalue = argparam.second as? LiteralValue
if(idref!=null) {
val variable = idref.targetVarDecl(namespace)
if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) {
val pointerExpr = AddressOf(idref, idref.position)
pointerExpr.scopedname = parent.makeScopedName(idref.nameInSource.single())
pointerExpr.linkParents(arglist[argparam.first.index].parent)
arglist[argparam.first.index] = pointerExpr
}
}
else if(strvalue!=null) {
if(strvalue.isString) {
// replace the argument with &autovar
val autoVarName = "$autoHeapValuePrefix${strvalue.heapId}"
val autoHeapvarRef = IdentifierReference(listOf(autoVarName), strvalue.position)
val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position)
pointerExpr.scopedname = parent.makeScopedName(autoVarName)
pointerExpr.linkParents(arglist[argparam.first.index].parent)
arglist[argparam.first.index] = pointerExpr
// add a vardecl so that the autovar can be resolved in later lookups
val variable = VarDecl(VarDeclType.VAR, strvalue.type, false, null, false, autoVarName, strvalue, strvalue.position)
addVarDecl(strvalue.definingScope(), variable)
}
}
}
}
}
private fun addVarDecl(scope: INameScope, variable: VarDecl) {
if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableMapOf()
vardeclsToAdd.getValue(scope)[variable.name]=variable
}
}
+57 -71
View File
@@ -36,8 +36,11 @@ fun Number.toHex(): String {
}
data class IntegerOrAddressOf(val integer: Int?, val addressOf: AddressOf?)
class HeapValues {
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?, val doubleArray: DoubleArray?) {
data class HeapValue(val type: DataType, val str: String?, val array: Array<IntegerOrAddressOf>?, val doubleArray: DoubleArray?) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@@ -61,7 +64,7 @@ class HeapValues {
fun size(): Int = heap.size
fun add(type: DataType, str: String): Int {
fun addString(type: DataType, str: String): Int {
if (str.length > 255)
throw IllegalArgumentException("string length must be 0-255")
@@ -76,17 +79,19 @@ class HeapValues {
return newId
}
fun add(type: DataType, array: IntArray): Int {
fun addIntegerArray(type: DataType, array: Array<IntegerOrAddressOf>): Int {
// arrays are never shared, don't check for existing
if(type !in ArrayDatatypes)
throw CompilerException("wrong array type")
val newId = heapId++
heap[newId] = HeapValue(type, null, array, null)
return newId
}
fun add(type: DataType, darray: DoubleArray): Int {
fun addDoublesArray(darray: DoubleArray): Int {
// arrays are never shared, don't check for existing
val newId = heapId++
heap[newId] = HeapValue(type, null, null, darray)
heap[newId] = HeapValue(DataType.ARRAY_F, null, null, darray)
return newId
}
@@ -653,6 +658,7 @@ internal class Compiler(private val rootModule: Module,
is TypecastExpression -> translate(expr)
is DirectMemoryRead -> translate(expr)
is DirectMemoryWrite -> translate(expr)
is AddressOf -> translate(expr)
else -> {
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
when(lv.type) {
@@ -811,8 +817,8 @@ internal class Compiler(private val rootModule: Module,
"any", "all" -> {
// 1 array argument, type determines the exact syscall to use
val arg=args.single() as IdentifierReference
val target=arg.targetStatement(namespace) as VarDecl
val length=Value(DataType.UBYTE, target.arrayspec!!.size()!!)
val target=arg.targetVarDecl(namespace)!!
val length=Value(DataType.UBYTE, target.arraysize!!.size()!!)
prog.instr(Opcode.PUSH_BYTE, length)
when (arg.resultingDatatype(namespace, heap)) {
DataType.ARRAY_B, DataType.ARRAY_UB -> createSyscall("${funcname}_b")
@@ -824,8 +830,8 @@ internal class Compiler(private val rootModule: Module,
"avg" -> {
// 1 array argument, type determines the exact syscall to use
val arg=args.single() as IdentifierReference
val target=arg.targetStatement(namespace) as VarDecl
val length=Value(DataType.UBYTE, target.arrayspec!!.size()!!)
val target=arg.targetVarDecl(namespace)!!
val length=Value(DataType.UBYTE, target.arraysize!!.size()!!)
val arrayDt=arg.resultingDatatype(namespace, heap)
prog.instr(Opcode.PUSH_BYTE, length)
when (arrayDt) {
@@ -855,8 +861,8 @@ internal class Compiler(private val rootModule: Module,
"min", "max", "sum" -> {
// 1 array argument, type determines the exact syscall to use
val arg=args.single() as IdentifierReference
val target=arg.targetStatement(namespace) as VarDecl
val length=Value(DataType.UBYTE, target.arrayspec!!.size()!!)
val target=arg.targetVarDecl(namespace)!!
val length=Value(DataType.UBYTE, target.arraysize!!.size()!!)
prog.instr(Opcode.PUSH_BYTE, length)
when (arg.resultingDatatype(namespace, heap)) {
DataType.ARRAY_UB -> createSyscall("${funcname}_ub")
@@ -1081,22 +1087,11 @@ internal class Compiler(private val rootModule: Module,
translate(assignA)
translate(assignX)
}
DataType.UWORD -> {
in WordDatatypes -> {
translate(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAX_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGAX_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition")
}
}
@@ -1119,18 +1114,7 @@ internal class Compiler(private val rootModule: Module,
translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGAY_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGAY_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition")
}
}
@@ -1153,22 +1137,11 @@ internal class Compiler(private val rootModule: Module,
translate(assignX)
translate(assignY)
}
DataType.UWORD -> {
in WordDatatypes -> {
translate(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
DataType.STR, DataType.STR_S -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
DataType.FLOAT -> {
pushFloatAddress(arg.first)
prog.instr(Opcode.POP_REGXY_WORD)
}
in ArrayDatatypes -> {
pushStringAddress(arg.first, false)
prog.instr(Opcode.POP_REGXY_WORD)
}
in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition")
else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition")
}
}
@@ -1238,12 +1211,9 @@ internal class Compiler(private val rootModule: Module,
}
"**" -> {
when(dt) {
DataType.UBYTE -> Opcode.POW_UB
DataType.BYTE -> Opcode.POW_B
DataType.UWORD -> Opcode.POW_UW
DataType.WORD -> Opcode.POW_W
in IntegerDatatypes -> throw CompilerException("power operator requires floating points")
DataType.FLOAT -> Opcode.POW_F
else -> throw CompilerException("only byte/word/float possible")
else -> throw CompilerException("only numeric datatype possible")
}
}
"&" -> {
@@ -1412,8 +1382,8 @@ internal class Compiler(private val rootModule: Module,
}
private fun translate(arrayindexed: ArrayIndexedExpression, write: Boolean) {
val variable = arrayindexed.identifier.targetStatement(namespace) as VarDecl
translate(arrayindexed.arrayspec.x)
val variable = arrayindexed.identifier.targetVarDecl(namespace)!!
translate(arrayindexed.arrayspec.index)
if (write)
prog.instr(opcodeWriteindexedvar(variable.datatype), callLabel = variable.scopedname)
else
@@ -1463,15 +1433,15 @@ internal class Compiler(private val rootModule: Module,
"--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register!!.name)
}
stmt.target.identifier != null -> {
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
val targetStatement = stmt.target.identifier!!.targetVarDecl(namespace)!!
when(stmt.operator) {
"++" -> prog.instr(opcodeIncvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
"--" -> prog.instr(opcodeDecvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
}
}
stmt.target.arrayindexed != null -> {
val variable = stmt.target.arrayindexed!!.identifier.targetStatement(namespace) as VarDecl
translate(stmt.target.arrayindexed!!.arrayspec.x)
val variable = stmt.target.arrayindexed!!.identifier.targetVarDecl(namespace)!!
translate(stmt.target.arrayindexed!!.arrayspec.index)
when(stmt.operator) {
"++" -> prog.instr(opcodeIncArrayindexedVar(variable.datatype), callLabel = variable.scopedname)
"--" -> prog.instr(opcodeDecArrayindexedVar(variable.datatype), callLabel = variable.scopedname)
@@ -1527,10 +1497,10 @@ internal class Compiler(private val rootModule: Module,
when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.CAST_UB_TO_UW)
DataType.BYTE -> prog.instr(Opcode.CAST_B_TO_UW)
DataType.STR, DataType.STR_S -> pushStringAddress(stmt.value, true)
DataType.STR, DataType.STR_S -> pushHeapVarAddress(stmt.value, true)
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_F -> {
if (stmt.value is IdentifierReference) {
val vardecl = (stmt.value as IdentifierReference).targetStatement(namespace) as VarDecl
val vardecl = (stmt.value as IdentifierReference).targetVarDecl(namespace)!!
prog.removeLastInstruction()
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
@@ -1551,7 +1521,7 @@ internal class Compiler(private val rootModule: Module,
}
in StringDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
in ArrayDatatypes -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
else -> throw CompilerException("weird/unknonwn targetdt")
else -> throw CompilerException("weird/unknown targetdt")
}
}
@@ -1563,11 +1533,11 @@ internal class Compiler(private val rootModule: Module,
popValueIntoTarget(assignTarget, datatype)
}
private fun pushStringAddress(value: IExpression, removeLastOpcode: Boolean) {
private fun pushHeapVarAddress(value: IExpression, removeLastOpcode: Boolean) {
when (value) {
is LiteralValue -> throw CompilerException("can only push address of string that is a variable on the heap")
is LiteralValue -> throw CompilerException("can only push address of string or array (value on the heap)")
is IdentifierReference -> {
val vardecl = value.targetStatement(namespace) as VarDecl
val vardecl = value.targetVarDecl(namespace)!!
if(removeLastOpcode) prog.removeLastInstruction()
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
@@ -1579,7 +1549,7 @@ internal class Compiler(private val rootModule: Module,
when (value) {
is LiteralValue -> throw CompilerException("can only push address of float that is a variable on the heap")
is IdentifierReference -> {
val vardecl = value.targetStatement(namespace) as VarDecl
val vardecl = value.targetVarDecl(namespace)!!
prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname)
}
else -> throw CompilerException("can only take address of a the float as constant literal or variable")
@@ -1658,7 +1628,7 @@ internal class Compiler(private val rootModule: Module,
loopVarName = reg.name
loopVarDt = DataType.UBYTE
} else {
val loopvar = (loop.loopVar!!.targetStatement(namespace) as VarDecl)
val loopvar = loop.loopVar!!.targetVarDecl(namespace)!!
loopVarName = loopvar.scopedname
loopVarDt = loopvar.datatype
}
@@ -1707,7 +1677,7 @@ internal class Compiler(private val rootModule: Module,
when {
loop.iterable is IdentifierReference -> {
val idRef = loop.iterable as IdentifierReference
val vardecl = (idRef.targetStatement(namespace) as VarDecl)
val vardecl = idRef.targetVarDecl(namespace)!!
val iterableValue = vardecl.value as LiteralValue
if(!iterableValue.isIterable(namespace, heap))
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
@@ -1782,7 +1752,7 @@ internal class Compiler(private val rootModule: Module,
AssignTarget(loop.loopRegister, null, null, null, loop.position)
else
AssignTarget(null, loop.loopVar!!.copy(), null, null, loop.position)
val arrayspec = ArraySpec(IdentifierReference(listOf(ForLoop.iteratorLoopcounterVarname), loop.position), loop.position)
val arrayspec = ArrayIndex(IdentifierReference(listOf(ForLoop.iteratorLoopcounterVarname), loop.position), loop.position)
val assignLv = Assignment(
listOf(assignTarget), null,
ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), arrayspec, loop.position),
@@ -1971,7 +1941,7 @@ internal class Compiler(private val rootModule: Module,
lvTarget.linkParents(body)
val targetStatement: VarDecl? =
if(lvTarget.identifier!=null) {
lvTarget.identifier.targetStatement(namespace) as VarDecl
lvTarget.identifier.targetVarDecl(namespace)
} else {
null
}
@@ -2166,6 +2136,18 @@ internal class Compiler(private val rootModule: Module,
}
}
private fun translate(addrof: AddressOf) {
val target = addrof.identifier.targetVarDecl(namespace)!!
if(target.datatype in ArrayDatatypes || target.datatype in StringDatatypes|| target.datatype==DataType.FLOAT) {
pushHeapVarAddress(addrof.identifier, false)
}
else if(target.datatype==DataType.FLOAT) {
pushFloatAddress(addrof.identifier)
}
else
throw CompilerException("cannot take memory pointer $addrof")
}
private fun translateAsmInclude(args: List<DirectiveArg>, importedFrom: Path) {
val scopeprefix = if(args[1].str!!.isNotBlank()) "${args[1].str}\t.proc\n" else ""
val scopeprefixEnd = if(args[1].str!!.isNotBlank()) "\t.pend\n" else ""
@@ -2187,7 +2169,11 @@ internal class Compiler(private val rootModule: Module,
}
private fun translateAsmBinary(args: List<DirectiveArg>) {
TODO("asmbinary not implemented yet $args")
val offset = if(args.size>=2) Value(DataType.UWORD, args[1].int!!) else null
val length = if(args.size==3) Value(DataType.UWORD, args[2].int!!) else null
val filename = args[0].str!!
// reading the actual data is not performed by the compiler but is delegated to the assembler
prog.instr(Opcode.INCLUDE_FILE, offset, length, filename)
}
}
@@ -23,6 +23,9 @@ open class Instruction(val opcode: Opcode,
else
"inline_assembly"
}
opcode==Opcode.INCLUDE_FILE -> {
"include_file \"$callLabel\" $arg $arg2"
}
opcode==Opcode.SYSCALL -> {
val syscall = Syscall.values().find { it.callNr==arg!!.numericValue() }
"syscall $syscall"
@@ -14,9 +14,9 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
class ProgramBlock(val name: String,
var address: Int?,
val instructions: MutableList<Instruction> = mutableListOf(),
val variables: MutableMap<String, Value> = mutableMapOf(),
val variables: MutableMap<String, Value> = mutableMapOf(), // names are fully scoped
val memoryPointers: MutableMap<String, Pair<Int, DataType>> = mutableMapOf(),
val labels: MutableMap<String, Instruction> = mutableMapOf(),
val labels: MutableMap<String, Instruction> = mutableMapOf(), // names are fully scoped
val force_output: Boolean)
{
val numVariables: Int
@@ -69,7 +69,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
optimizeMultipleSequentialLineInstrs()
optimizeCallReturnIntoJump()
optimizeConditionalBranches()
// todo: add more optimizations to stackvm code
// todo: add more optimizations to intermediate code!
optimizeRemoveNops() // must be done as the last step
optimizeMultipleSequentialLineInstrs() // once more
@@ -459,13 +459,28 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
out.println("%end_memory")
out.println("%heap")
heap.allEntries().forEach {
out.print("${it.key} ${it.value.type.name.toLowerCase()} ")
when {
it.value.str!=null ->
out.println("${it.key} ${it.value.type.name.toLowerCase()} \"${escape(it.value.str!!)}\"")
it.value.array!=null ->
out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.array!!.toList()}")
out.println("\"${escape(it.value.str!!)}\"")
it.value.array!=null -> {
// this array can contain both normal integers, and pointer values
val arrayvalues = it.value.array!!.map { av ->
when {
av.integer!=null -> av.integer.toString()
av.addressOf!=null -> {
if(av.addressOf.scopedname==null)
throw CompilerException("AddressOf scopedname should have been set")
else
"&${av.addressOf.scopedname}"
}
else -> throw CompilerException("weird array value")
}
}
out.println(arrayvalues)
}
it.value.doubleArray!=null ->
out.println("${it.key} ${it.value.type.name.toLowerCase()} ${it.value.doubleArray!!.toList()}")
out.println(it.value.doubleArray!!.toList())
else -> throw CompilerException("invalid heap entry $it")
}
}
@@ -58,10 +58,6 @@ enum class Opcode {
DIV_F,
REMAINDER_UB, // signed remainder is undefined/unimplemented
REMAINDER_UW, // signed remainder is undefined/unimplemented
POW_UB,
POW_B,
POW_UW,
POW_W,
POW_F,
NEG_B,
NEG_W,
@@ -266,7 +262,8 @@ enum class Opcode {
BREAKPOINT, // breakpoint
TERMINATE, // end the program
LINE, // track source file line number
INLINE_ASSEMBLY // container to hold inline raw assembly code
INLINE_ASSEMBLY, // container to hold inline raw assembly code
INCLUDE_FILE // directive to include a file at this position in the memory of the program
}
val opcodesWithVarArgument = setOf(
@@ -288,7 +288,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
out(" .byte " + chunk.joinToString())
}
DataType.ARRAY_UB -> {
// unsigned integer byte arrayspec
// unsigned integer byte arraysize
val data = makeArrayFillDataUnsigned(v.second)
if (data.size <= 16)
out("${v.first}\t.byte ${data.joinToString()}")
@@ -299,7 +299,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
DataType.ARRAY_B -> {
// signed integer byte arrayspec
// signed integer byte arraysize
val data = makeArrayFillDataSigned(v.second)
if (data.size <= 16)
out("${v.first}\t.char ${data.joinToString()}")
@@ -310,7 +310,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
DataType.ARRAY_UW -> {
// unsigned word arrayspec
// unsigned word arraysize
val data = makeArrayFillDataUnsigned(v.second)
if (data.size <= 16)
out("${v.first}\t.word ${data.joinToString()}")
@@ -321,7 +321,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
DataType.ARRAY_W -> {
// signed word arrayspec
// signed word arraysize
val data = makeArrayFillDataSigned(v.second)
if (data.size <= 16)
out("${v.first}\t.sint ${data.joinToString()}")
@@ -332,7 +332,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
DataType.ARRAY_F -> {
// float arrayspec
// float arraysize
val array = heap.get(v.second.heapId).doubleArray!!
val floatFills = array.map { makeFloatFill(Mflpt5.fromNumber(it)) }
out(v.first)
@@ -359,23 +359,33 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
private fun makeArrayFillDataUnsigned(value: Value): List<String> {
val array = heap.get(value.heapId).array!!
return if (value.type == DataType.ARRAY_UB || value.type == DataType.ARRAY_UW)
array.map { "$"+it.toString(16).padStart(2, '0') }
else
throw AssemblyError("invalid arrayspec type")
return when {
value.type==DataType.ARRAY_UB ->
// byte array can never contain pointer-to types, so treat values as all integers
array.map { "$"+it.integer!!.toString(16).padStart(2, '0') }
value.type==DataType.ARRAY_UW -> array.map {
when {
it.integer!=null -> "$"+it.integer.toString(16).padStart(2, '0')
it.addressOf!=null -> symname(it.addressOf.scopedname!!, block)
else -> throw AssemblyError("weird type in array")
}
}
else -> throw AssemblyError("invalid arraysize type")
}
}
private fun makeArrayFillDataSigned(value: Value): List<String> {
val array = heap.get(value.heapId).array!!
// note: array of signed value can never contain pointer-to type, so simply process values as being all integers
return if (value.type == DataType.ARRAY_B || value.type == DataType.ARRAY_W) {
array.map {
if(it>=0)
"$"+it.toString(16).padStart(2, '0')
if(it.integer!!>=0)
"$"+it.integer.toString(16).padStart(2, '0')
else
"-$"+abs(it).toString(16).padStart(2, '0')
"-$"+abs(it.integer).toString(16).padStart(2, '0')
}
}
else throw AssemblyError("invalid arrayspec type")
else throw AssemblyError("invalid arraysize type")
}
private fun instr2asm(ins: List<Instruction>): Int {
@@ -462,6 +472,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.DISCARD_WORD -> " inx"
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel2 ?: "") // All of the inline assembly is stored in the calllabel2 property. the '@inline@' is a special marker to process it.
Opcode.INCLUDE_FILE -> {
val offset = if(ins.arg==null) "" else ", ${ins.arg.integerValue()}"
val length = if(ins.arg2==null) "" else ", ${ins.arg2.integerValue()}"
" .binary \"${ins.callLabel}\" $offset $length"
}
Opcode.SYSCALL -> {
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
@@ -485,7 +500,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Syscall.FUNC_ALL_F,
Syscall.FUNC_MAX_F,
Syscall.FUNC_MIN_F,
Syscall.FUNC_AVG_F,
Syscall.FUNC_SUM_F -> " jsr c64flt.${call.name.toLowerCase()}"
null -> ""
else -> " jsr prog8_lib.${call.name.toLowerCase()}"
@@ -729,6 +743,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.ABS_B -> " jsr prog8_lib.abs_b"
Opcode.ABS_W -> " jsr prog8_lib.abs_w"
Opcode.ABS_F -> " jsr c64flt.abs_f"
Opcode.POW_F -> " jsr c64flt.pow_f"
Opcode.INV_BYTE -> {
"""
lda ${(ESTACK_LO + 1).toHex()},x
@@ -922,23 +937,21 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
if(mulIns.opcode == Opcode.MUL_B || mulIns.opcode==Opcode.MUL_UB) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40))
return " jsr math.mul_byte_$amount"
if(mulIns.opcode == Opcode.MUL_B && amount in setOf(-3,-5,-6,-7,-9,-10,-11,-12,-13,-14,-15,-20,-25,-40))
return " jsr prog8_lib.neg_b | jsr math.mul_byte_${-amount}"
}
else if(mulIns.opcode == Opcode.MUL_UW) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,12,15,20,25,40))
return " jsr math.mul_word_$amount"
}
else if(mulIns.opcode == Opcode.MUL_W) {
if(amount in setOf(0,1,2,4,8,16,32,64,128,256))
throw AssemblyError("multiplication by power of 2 should have been converted into a left shift instruction already")
printWarning("multiplication by power of 2 should have been optimized into a left shift instruction: $mulIns $amount")
if(amount in setOf(3,5,6,7,9,10,12,15,20,25,40))
return " jsr math.mul_word_$amount"
if(amount in setOf(-3,-5,-6,-7,-9,-10,-12,-15,-20,-25,-40))
@@ -118,7 +118,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
if(arglist.type==DataType.ARRAY_UB || arglist.type==DataType.ARRAY_UW || arglist.type==DataType.ARRAY_F) {
val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)}
if(dt.any { it!=DataType.UBYTE && it!=DataType.UWORD && it!=DataType.FLOAT}) {
throw FatalAstException("fuction $function only accepts arrayspec of numeric values")
throw FatalAstException("fuction $function only accepts arraysize of numeric values")
}
if(dt.any { it==DataType.FLOAT }) return DataType.FLOAT
if(dt.any { it==DataType.UWORD }) return DataType.UWORD
@@ -245,7 +245,12 @@ private fun collectionArgOutputNumber(args: List<IExpression>, position: Positio
if(iterable.heapId==null)
throw FatalAstException("iterable value should be on the heap")
val array = heap.get(iterable.heapId).array ?: throw SyntaxError("function expects an iterable type", position)
function(array.map { it.toDouble() })
function(array.map {
if(it.integer!=null)
it.integer.toDouble()
else
throw FatalAstException("cannot perform function over array that contains other values besides constant integers")
})
}
}
}
@@ -266,7 +271,12 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
function(constants.map { it!!.toDouble() })
} else {
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("function requires array argument", position)
function(array.map { it.toDouble() })
function(array.map {
if(it.integer!=null)
it.integer.toDouble()
else
throw FatalAstException("cannot perform function over array that contains other values besides constant integers")
})
}
return LiteralValue.fromBoolean(result, position)
}
@@ -289,7 +299,6 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
if(args.size!=1)
throw SyntaxError("avg requires array argument", position)
val iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
val result = if(iterable.arrayvalue!=null) {
val constants = iterable.arrayvalue.map { it.constValue(namespace, heap)?.asNumericValue }
if (null in constants)
@@ -297,8 +306,17 @@ private fun builtinAvg(args: List<IExpression>, position: Position, namespace:IN
(constants.map { it!!.toDouble() }).average()
}
else {
val array = heap.get(iterable.heapId!!).array ?: throw SyntaxError("avg requires array argument", position)
array.average()
val integerarray = heap.get(iterable.heapId!!).array
if(integerarray!=null) {
if (integerarray.all { it.integer != null }) {
integerarray.map { it.integer!! }.average()
} else {
throw ExpressionError("cannot avg() over array that does not only contain constant numerical values", position)
}
} else {
val doublearray = heap.get(iterable.heapId).doubleArray
doublearray?.average() ?: throw SyntaxError("avg requires array argument", position)
}
}
return numericLiteral(result, args[0].position)
}
@@ -323,8 +341,12 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
throw SyntaxError("len requires one argument", position)
var argument = args[0].constValue(namespace, heap)
if(argument==null) {
val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(namespace)
val arraySize = directMemVar?.arraysize?.size()
if(arraySize != null)
return LiteralValue.optimalInteger(arraySize, position)
if(args[0] !is IdentifierReference)
throw SyntaxError("len over weird argument ${args[0]}", position)
throw SyntaxError("len argument should be an identifier, but is ${args[0]}", position)
val target = (args[0] as IdentifierReference).targetStatement(namespace)
val argValue = (target as? VarDecl)?.value
argument = argValue?.constValue(namespace, heap)
@@ -3,6 +3,7 @@ package prog8.optimizing
import prog8.ast.*
import prog8.compiler.CompilerException
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
import kotlin.math.floor
@@ -24,7 +25,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
override fun process(decl: VarDecl): IStatement {
// the initializer value can't refer to the variable itself (recursive definition)
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arrayspec?.x?.referencesIdentifier(decl.name) == true) {
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.index?.referencesIdentifier(decl.name) == true) {
errors.add(ExpressionError("recursive var declaration", decl.position))
return decl
}
@@ -44,11 +45,34 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
}
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
val rangeExpr = decl.value as? RangeExpr
if(rangeExpr!=null) {
// convert the initializer range expression to an actual array (will be put on heap later)
val declArraySize = decl.arraysize?.size()
if(declArraySize!=null && declArraySize!=rangeExpr.size(heap))
errors.add(ExpressionError("range expression size doesn't match declared array size", decl.value?.position!!))
val constRange = rangeExpr.toConstantIntegerRange(heap)
if(constRange!=null) {
val eltType = rangeExpr.resultingDatatype(namespace, heap)!!
if(eltType in ByteDatatypes) {
decl.value = LiteralValue(decl.datatype,
arrayvalue = constRange.map { LiteralValue(eltType, bytevalue=it.toShort(), position = decl.value!!.position ) }
.toTypedArray(), position=decl.value!!.position)
} else {
decl.value = LiteralValue(decl.datatype,
arrayvalue = constRange.map { LiteralValue(eltType, wordvalue= it, position = decl.value!!.position ) }
.toTypedArray(), position=decl.value!!.position)
}
decl.value!!.linkParents(decl)
}
}
if(litval?.type==DataType.FLOAT)
errors.add(ExpressionError("arrayspec requires only integers here", litval.position))
val size = decl.arrayspec!!.size()
if ((litval==null || !litval.isArray) && size != null) {
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
errors.add(ExpressionError("arraysize requires only integers here", litval.position))
if(decl.arraysize==null)
return decl
val size = decl.arraysize!!.size()
if ((litval==null || !litval.isArray) && size != null && rangeExpr==null) {
// arraysize initializer is empty or a single int, and we know the size; create the arraysize.
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
when(decl.datatype){
DataType.ARRAY_UB -> {
@@ -69,22 +93,22 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
else -> {}
}
val fillArray = IntArray(size) { fillvalue }
val heapId = heap.add(decl.datatype, fillArray)
val heapId = heap.addIntegerArray(decl.datatype, Array(size) { IntegerOrAddressOf(fillvalue, null) })
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
}
}
DataType.ARRAY_F -> {
val size = decl.arrayspec!!.size()
if(decl.arraysize==null)
return decl
val size = decl.arraysize!!.size()
if ((litval==null || !litval.isArray) && size != null) {
// arrayspec initializer is empty or a single int, and we know the size; create the arrayspec.
// arraysize initializer is empty or a single int, and we know the size; create the arraysize.
val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0
if(fillvalue< FLOAT_MAX_NEGATIVE || fillvalue> FLOAT_MAX_POSITIVE)
errors.add(ExpressionError("float value overflow", litval?.position ?: decl.position))
else {
val fillArray = DoubleArray(size) { fillvalue }
val heapId = heap.add(decl.datatype, fillArray)
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
val heapId = heap.addDoublesArray(DoubleArray(size) { fillvalue })
decl.value = LiteralValue(DataType.ARRAY_F, heapId = heapId, position = litval?.position ?: decl.position)
}
}
}
@@ -112,12 +136,12 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
DataType.ARRAY_F -> {
if(array.array!=null) {
// convert a non-float array to floats
val doubleArray = array.array.map { it.toDouble() }.toDoubleArray()
val doubleArray = array.array.map { it.integer!!.toDouble() }.toDoubleArray()
heap.update(heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval.position)
}
}
else -> throw AstException("invalid array vardecl type")
else -> throw FatalAstException("invalid array vardecl type ${decl.datatype}")
}
}
@@ -157,7 +181,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
private fun typeCastConstArguments(functionCall: IFunctionCall) {
val subroutine = functionCall.target.targetStatement(namespace) as? Subroutine
val subroutine = functionCall.target.targetSubroutine(namespace)
if(subroutine!=null) {
// if types differ, try to typecast constant arguments to the function call to the desired data type of the parameter
for(arg in functionCall.arglist.withIndex().zip(subroutine.parameters)) {
@@ -174,6 +198,21 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
}
override fun process(memread: DirectMemoryRead): IExpression {
// @( &thing ) --> thing
val addrOf = memread.addressExpression as? AddressOf
if(addrOf!=null)
return super.process(addrOf.identifier)
return super.process(memread)
}
override fun process(memwrite: DirectMemoryWrite): IExpression {
// @( &thing ) --> thing
val addrOf = memwrite.addressExpression as? AddressOf
if(addrOf!=null)
return super.process(addrOf.identifier)
return super.process(memwrite)
}
/**
* Try to process a unary prefix expression.
@@ -494,7 +533,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
val rangeTo = iterableRange.to as? LiteralValue
if(rangeFrom==null || rangeTo==null) return resultStmt
val loopvar = resultStmt.loopVar!!.targetStatement(namespace) as? VarDecl
val loopvar = resultStmt.loopVar!!.targetVarDecl(namespace)
if(loopvar!=null) {
val stepLiteral = iterableRange.step as? LiteralValue
when(loopvar.datatype) {
@@ -534,7 +573,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
if(literalValue.strvalue(heap).length !in 1..255)
addError(ExpressionError("string literal length must be between 1 and 255", literalValue.position))
else {
val heapId = heap.add(literalValue.type, literalValue.strvalue(heap)) // TODO: we don't know the actual string type yet, STR != STR_S etc...
val heapId = heap.addString(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)
return super.process(newValue)
}
@@ -547,13 +586,25 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
private fun moveArrayToHeap(arraylit: LiteralValue): LiteralValue {
val array: Array<IExpression> = arraylit.arrayvalue!!.map { it.process(this) }.toTypedArray()
val allElementsAreConstant = array.fold(true) { c, expr-> c and (expr is LiteralValue)}
if(!allElementsAreConstant) {
addError(ExpressionError("array literal can contain only constant values", arraylit.position))
val allElementsAreConstantOrAddressOf = array.fold(true) { c, expr-> c and (expr is LiteralValue || expr is AddressOf)}
if(!allElementsAreConstantOrAddressOf) {
addError(ExpressionError("array literal can only consist of constant primitive numerical values or memory pointers", arraylit.position))
return arraylit
} else if(array.any {it is AddressOf}) {
val arrayDt = DataType.ARRAY_UW
val intArrayWithAddressOfs = array.map {
when (it) {
is AddressOf -> IntegerOrAddressOf(null, it)
is LiteralValue -> IntegerOrAddressOf(it.asIntegerValue, null)
else -> throw CompilerException("invalid datatype in array")
}
}
val heapId = heap.addIntegerArray(arrayDt, intArrayWithAddressOfs.toTypedArray())
return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position)
} else {
// array is only constant numerical values
val valuesInArray = array.map { it.constValue(namespace, heap)!!.asNumericValue!! }
val integerArray = valuesInArray.map{it.toInt()}.toIntArray()
val integerArray = valuesInArray.map{ it.toInt() }
val doubleArray = valuesInArray.map{it.toDouble()}.toDoubleArray()
val typesInArray: Set<DataType> = array.mapNotNull { it.resultingDatatype(namespace, heap) }.toSet()
@@ -587,9 +638,9 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
DataType.ARRAY_UB,
DataType.ARRAY_B,
DataType.ARRAY_UW,
DataType.ARRAY_W -> heap.add(arrayDt, integerArray)
DataType.ARRAY_F -> heap.add(arrayDt, doubleArray)
else -> throw CompilerException("invalid arrayspec type")
DataType.ARRAY_W -> heap.addIntegerArray(arrayDt, integerArray.map { IntegerOrAddressOf(it, null) }.toTypedArray())
DataType.ARRAY_F -> heap.addDoublesArray(doubleArray)
else -> throw CompilerException("invalid arraysize type")
}
return LiteralValue(arrayDt, heapId = heapId, position = arraylit.position)
}
@@ -662,5 +713,3 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
return assignment
}
}
@@ -18,6 +18,22 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
return super.process(assignment)
}
override fun process(memread: DirectMemoryRead): IExpression {
// @( &thing ) --> thing
val addrOf = memread.addressExpression as? AddressOf
if(addrOf!=null)
return super.process(addrOf.identifier)
return super.process(memread)
}
override fun process(memwrite: DirectMemoryWrite): IExpression {
// @( &thing ) --> thing
val addrOf = memwrite.addressExpression as? AddressOf
if(addrOf!=null)
return super.process(addrOf.identifier)
return super.process(memwrite)
}
override fun process(expr: PrefixExpression): IExpression {
if (expr.operator == "+") {
// +X --> X
@@ -17,10 +17,10 @@ import kotlin.math.floor
todo remove unused subroutines
todo remove unused strings and arrays from the heap
todo inline subroutines that are called exactly once (regardless of their size)
todo inline subroutines that are only called a few times (3?) and that are "sufficiently small" (0-3 statements)
todo inline subroutines that are only called a few times (max 3?)
todo inline subroutines that are "sufficiently small" (0-3 statements)
todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to)
*/
class StatementOptimizer(private val namespace: INameScope, private val heap: HeapValues) : IAstProcessor {
@@ -76,7 +76,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
var previousAssignmentLine: Int? = null
for (i in 0 until statements.size) {
val stmt = statements[i] as? Assignment
if (stmt != null) {
if (stmt != null && stmt.value is LiteralValue) {
if (previousAssignmentLine == null) {
previousAssignmentLine = i
continue
@@ -101,12 +101,12 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
if(target.memoryAddress!=null)
return false
if(target.arrayindexed!=null) {
val targetStmt = target.arrayindexed.identifier.targetStatement(namespace) as? VarDecl
val targetStmt = target.arrayindexed.identifier.targetVarDecl(namespace)
if(targetStmt!=null)
return targetStmt.type!=VarDeclType.MEMORY
}
if(target.identifier!=null) {
val targetStmt = target.identifier.targetStatement(namespace) as? VarDecl
val targetStmt = target.identifier.targetVarDecl(namespace)
if(targetStmt!=null)
return targetStmt.type!=VarDeclType.MEMORY
}
@@ -156,7 +156,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
// if it calls a subroutine,
// and the first instruction in the subroutine is a jump, call that jump target instead
// if the first instruction in the subroutine is a return statement, replace with a nop instruction
val subroutine = functionCallStatement.target.targetStatement(namespace) as? Subroutine
val subroutine = functionCallStatement.target.targetSubroutine(namespace)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Jump && first.identifier!=null) {
@@ -176,7 +176,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
// if it calls a subroutine,
// and the first instruction in the subroutine is a jump, call that jump target instead
// if the first instruction in the subroutine is a return statement with constant value, replace with the constant value
val subroutine = functionCall.target.targetStatement(namespace) as? Subroutine
val subroutine = functionCall.target.targetSubroutine(namespace)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Jump && first.identifier!=null) {
@@ -341,7 +341,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
}
override fun process(jump: Jump): IStatement {
val subroutine = jump.identifier?.targetStatement(namespace) as? Subroutine
val subroutine = jump.identifier?.targetSubroutine(namespace)
if(subroutine!=null) {
// if the first instruction in the subroutine is another jump, shortcut this one
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
@@ -380,7 +380,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
if (same(target, bexpr.left)) {
// remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
// A = A <operator> B
val vardeclDt = (target.identifier?.targetStatement(namespace) as? VarDecl)?.type
val vardeclDt = (target.identifier?.targetVarDecl(namespace))?.type
when (bexpr.operator) {
"+" -> {
@@ -522,8 +522,8 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
}
if(target1.arrayindexed!=null && target2.arrayindexed!=null) {
if(target1.arrayindexed.identifier.nameInSource == target2.arrayindexed.identifier.nameInSource) {
val x1 = target1.arrayindexed.arrayspec.x.constValue(namespace, heap)
val x2 = target2.arrayindexed.arrayspec.x.constValue(namespace, heap)
val x1 = target1.arrayindexed.arrayspec.index.constValue(namespace, heap)
val x2 = target2.arrayindexed.arrayspec.index.constValue(namespace, heap)
return x1!=null && x2!=null && x1==x2
}
}
@@ -548,7 +548,7 @@ fun same(left: IExpression, right: IExpression): Boolean {
&& same(right.right, left.right))
is ArrayIndexedExpression -> {
return (right is ArrayIndexedExpression && right.identifier.nameInSource == left.identifier.nameInSource
&& same(right.arrayspec.x, left.arrayspec.x))
&& same(right.arrayspec.index, left.arrayspec.index))
}
is LiteralValue -> return (right is LiteralValue && right==left)
}
+24 -4
View File
@@ -2,6 +2,7 @@ package prog8.stackvm
import prog8.ast.*
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.intermediate.*
import java.io.File
import java.util.*
@@ -87,17 +88,29 @@ class Program (val name: String,
}
heapvalues.sortedBy { it.first }.forEach {
when(it.second) {
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, DataType.STR_S -> heap.addString(it.second, unescape(it.third.substring(1, it.third.length-1), Position("<stackvmsource>", 0, 0, 0)))
DataType.ARRAY_UB, DataType.ARRAY_B,
DataType.ARRAY_UW, DataType.ARRAY_W -> {
val numbers = it.third.substring(1, it.third.length-1).split(',')
val intarray = numbers.map{number->number.trim().toInt()}.toIntArray()
heap.add(it.second, intarray)
val intarray = numbers.map{number->
val num=number.trim()
if(num.startsWith("&")) {
// it's AddressOf
val scopedname = num.substring(1)
val iref = IdentifierReference(scopedname.split('.'), Position("<intermediate>", 0,0,0))
val addrOf = AddressOf(iref, Position("<intermediate>", 0,0,0))
addrOf.scopedname=scopedname
IntegerOrAddressOf(null, addrOf)
} else {
IntegerOrAddressOf(num.toInt(), null)
}
}.toTypedArray()
heap.addIntegerArray(it.second, intarray)
}
DataType.ARRAY_F -> {
val numbers = it.third.substring(1, it.third.length-1).split(',')
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
heap.add(it.second, doublearray)
heap.addDoublesArray(doublearray)
}
in NumericDatatypes -> throw VmExecutionException("invalid heap value type ${it.second}")
else -> throw VmExecutionException("weird datatype")
@@ -157,6 +170,13 @@ class Program (val name: String,
}
}
}
Opcode.INCLUDE_FILE -> {
val argparts = args!!.split(' ')
val filename = argparts[0]
val offset = if(argparts.size>=2 && argparts[1]!="null") getArgValue(argparts[1], heap) else null
val length = if(argparts.size>=3 && argparts[2]!="null") getArgValue(argparts[2], heap) else null
Instruction(opcode, offset, length, filename)
}
else -> {
Instruction(opcode, getArgValue(args, heap))
}
+215 -128
View File
@@ -2,6 +2,7 @@ package prog8.stackvm
import prog8.ast.*
import prog8.compiler.HeapValues
import prog8.compiler.IntegerOrAddressOf
import prog8.compiler.intermediate.Instruction
import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value
@@ -69,11 +70,6 @@ enum class Syscall(val callNr: Short) {
FUNC_MIN_UW(122),
FUNC_MIN_W(123),
FUNC_MIN_F(124),
FUNC_AVG_UB(125),
FUNC_AVG_B(126),
FUNC_AVG_UW(127),
FUNC_AVG_W(128),
FUNC_AVG_F(129),
FUNC_SUM_UB(130),
FUNC_SUM_B(131),
FUNC_SUM_UW(132),
@@ -615,38 +611,6 @@ class StackVm(private var traceOutputFile: String?) {
evalstack.push(value)
setFlags(value)
}
Opcode.POW_UB -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.UBYTE)
checkDt(second, DataType.UBYTE)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_UW -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.UWORD)
checkDt(second, DataType.UWORD)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_B -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.BYTE)
checkDt(second, DataType.BYTE)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_W -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.WORD)
checkDt(second, DataType.WORD)
val value=second.pow(top)
evalstack.push(value)
setFlags(value)
}
Opcode.POW_F -> {
val (top, second) = evalstack.pop2()
checkDt(top, DataType.FLOAT)
@@ -1083,24 +1047,48 @@ class StackVm(private var traceOutputFile: String?) {
}
Opcode.POP_REGAX_WORD -> {
val value=evalstack.pop().integerValue()
val valueA=Value(DataType.UBYTE, value and 255)
val valueX=Value(DataType.UBYTE, value shr 8)
val valueA: Value
val valueX: Value
if(value>=0) {
valueA = Value(DataType.UBYTE, value and 255)
valueX = Value(DataType.UBYTE, value shr 8)
} else {
val value2c = 65536+value
valueA = Value(DataType.UBYTE, value2c and 255)
valueX = Value(DataType.UBYTE, value2c shr 8)
}
variables["A"] = valueA
variables["X"] = valueX
setFlags(valueA.bitor(valueX))
}
Opcode.POP_REGAY_WORD -> {
val value=evalstack.pop().integerValue()
val valueA=Value(DataType.UBYTE, value and 255)
val valueY=Value(DataType.UBYTE, value shr 8)
val valueA: Value
val valueY: Value
if(value>=0) {
valueA = Value(DataType.UBYTE, value and 255)
valueY = Value(DataType.UBYTE, value shr 8)
} else {
val value2c = 65536+value
valueA = Value(DataType.UBYTE, value2c and 255)
valueY = Value(DataType.UBYTE, value2c shr 8)
}
variables["A"] = valueA
variables["Y"] = valueY
setFlags(valueA.bitor(valueY))
}
Opcode.POP_REGXY_WORD -> {
val value=evalstack.pop().integerValue()
val valueX=Value(DataType.UBYTE, value and 255)
val valueY=Value(DataType.UBYTE, value shr 8)
val valueX: Value
val valueY: Value
if(value>=0) {
valueX = Value(DataType.UBYTE, value and 255)
valueY = Value(DataType.UBYTE, value shr 8)
} else {
val value2c = 65536+value
valueX = Value(DataType.UBYTE, value2c and 255)
valueY = Value(DataType.UBYTE, value2c shr 8)
}
variables["X"] = valueX
variables["Y"] = valueY
setFlags(valueX.bitor(valueY))
@@ -1110,8 +1098,11 @@ class StackVm(private var traceOutputFile: String?) {
checkDt(value, DataType.UBYTE, DataType.BYTE)
val variable = getVar(ins.callLabel!!)
checkDt(variable, DataType.UBYTE, DataType.BYTE)
if(value.type!=variable.type)
throw VmExecutionException("datatype mismatch")
if(value.type!=variable.type) {
if(ins.callLabel !in Register.values().map { it.name }) {
throw VmExecutionException("datatype mismatch")
}
}
variables[ins.callLabel] = value
setFlags(value)
}
@@ -1631,11 +1622,11 @@ class StackVm(private var traceOutputFile: String?) {
// assume the variable is a pointer (address) and get the ubyte value from that memory location
Value(DataType.UBYTE, mem.getUByte(variable.integerValue()))
} else {
// get indexed byte element from the arrayspec
// get indexed byte element from the arraysize
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UB -> Value(DataType.UBYTE, array.array!![index])
DataType.ARRAY_B -> Value(DataType.BYTE, array.array!![index])
DataType.ARRAY_UB -> Value(DataType.UBYTE, array.array!![index].integer!!)
DataType.ARRAY_B -> Value(DataType.BYTE, array.array!![index].integer!!)
DataType.STR, DataType.STR_S -> Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0])
else -> throw VmExecutionException("not a proper array/string variable with byte elements")
}
@@ -1654,7 +1645,7 @@ class StackVm(private var traceOutputFile: String?) {
when(variable.second) {
DataType.ARRAY_UW -> Value(DataType.UWORD, mem.getUWord(address))
DataType.ARRAY_W -> Value(DataType.WORD, mem.getSWord(address))
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
else -> throw VmExecutionException("not a proper arraysize var with word elements")
}
} else {
// normal variable
@@ -1663,12 +1654,24 @@ class StackVm(private var traceOutputFile: String?) {
// assume the variable is a pointer (address) and get the word value from that memory location
Value(DataType.UWORD, mem.getUWord(variable.integerValue()))
} else {
// get indexed word element from the arrayspec
// get indexed word element from the arraysize
val array = heap.get(variable.heapId)
when(array.type){
DataType.ARRAY_UW -> Value(DataType.UWORD, array.array!![index])
DataType.ARRAY_W -> Value(DataType.WORD, array.array!![index])
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
DataType.ARRAY_UW -> {
val value = array.array!![index]
when {
value.integer!=null -> Value(DataType.UWORD, value.integer)
value.addressOf!=null -> {
val heapId = variables.getValue(value.addressOf.scopedname!!).heapId
if(heapId<0)
throw VmExecutionException("expected variable on heap")
evalstack.push(Value(DataType.UWORD, heapId)) // push the "address" of the string or array variable (this is taken care of properly in the assembly code generator)
}
else -> throw VmExecutionException("strange array value")
}
}
DataType.ARRAY_W -> Value(DataType.WORD, array.array!![index].integer!!)
else -> throw VmExecutionException("not a proper arraysize var with word elements")
}
}
}
@@ -1685,17 +1688,17 @@ class StackVm(private var traceOutputFile: String?) {
if(variable.second==DataType.ARRAY_F)
Value(DataType.FLOAT, mem.getFloat(address))
else
throw VmExecutionException("not a proper arrayspec var with float elements")
throw VmExecutionException("not a proper arraysize var with float elements")
} else {
val variable = getVar(ins.callLabel!!)
if (variable.type == DataType.UWORD) {
// assume the variable is a pointer (address) and get the float value from that memory location
Value(DataType.UWORD, mem.getFloat(variable.integerValue()))
} else {
// get indexed float element from the arrayspec
// get indexed float element from the arraysize
val array = heap.get(variable.heapId)
if (array.type != DataType.ARRAY_F)
throw VmExecutionException("not a proper arrayspec var with float elements")
throw VmExecutionException("not a proper arraysize var with float elements")
Value(DataType.FLOAT, array.doubleArray!![index])
}
}
@@ -1730,11 +1733,11 @@ class StackVm(private var traceOutputFile: String?) {
else
mem.setSByte(variable.integerValue(), value.integerValue().toShort())
} else {
// set indexed byte element in the arrayspec
// set indexed byte element in the arraysize
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UB -> array.array!![index] = value.integerValue()
DataType.ARRAY_B -> array.array!![index] = value.integerValue()
DataType.ARRAY_UB -> array.array!![index] = IntegerOrAddressOf(value.integerValue(), null)
DataType.ARRAY_B -> array.array!![index] = IntegerOrAddressOf(value.integerValue(), null)
DataType.STR, DataType.STR_S -> {
val chars = array.str!!.toCharArray()
val ps = Petscii.decodePetscii(listOf(value.integerValue().toShort()), true)[0]
@@ -1778,12 +1781,12 @@ class StackVm(private var traceOutputFile: String?) {
else
mem.setSWord(variable.integerValue()+index*2, value.integerValue())
} else {
// set indexed word element in the arrayspec
// set indexed word element in the arraysize
val array = heap.get(variable.heapId)
when (array.type) {
DataType.ARRAY_UW -> array.array!![index] = value.integerValue()
DataType.ARRAY_W -> array.array!![index] = value.integerValue()
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
DataType.ARRAY_UW -> array.array!![index] = IntegerOrAddressOf(value.integerValue(), null)
DataType.ARRAY_W -> array.array!![index] = IntegerOrAddressOf(value.integerValue(), null)
else -> throw VmExecutionException("not a proper arraysize var with word elements")
}
}
}
@@ -1807,10 +1810,10 @@ class StackVm(private var traceOutputFile: String?) {
// assume the variable is a pointer (address) and write the float value to that memory location
mem.setFloat(variable.integerValue()+index*5, value.numericValue().toDouble())
} else {
// set indexed float element in the arrayspec
// set indexed float element in the arraysize
val array = heap.get(variable.heapId)
if (array.type != DataType.ARRAY_F)
throw VmExecutionException("not a proper arrayspec var with float elements")
throw VmExecutionException("not a proper arraysize var with float elements")
array.doubleArray!![index] = value.numericValue().toDouble()
}
}
@@ -1833,6 +1836,7 @@ class StackVm(private var traceOutputFile: String?) {
Opcode.RSAVEX -> registerSaveX = variables.getValue("X")
Opcode.RRESTOREX -> variables["X"] = registerSaveX
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code $ins")
Opcode.INCLUDE_FILE -> throw VmExecutionException("stackVm doesn't support including a file $ins")
Opcode.PUSH_ADDR_HEAPVAR -> {
val heapId = variables.getValue(ins.callLabel!!).heapId
if(heapId<0)
@@ -2081,94 +2085,154 @@ class StackVm(private var traceOutputFile: String?) {
else throw VmExecutionException("cannot get ceil of $value")
}
Syscall.FUNC_MAX_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
evalstack.push(Value(DataType.UBYTE, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, value.array.map{it.integer!!}.max() ?: 0))
}
Syscall.FUNC_MAX_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
evalstack.push(Value(DataType.BYTE, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.BYTE, value.array.map{it.integer!!}.max() ?: 0))
}
Syscall.FUNC_MAX_UW -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
evalstack.push(Value(DataType.UWORD, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.max() ?: 0))
}
Syscall.FUNC_MAX_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
evalstack.push(Value(DataType.WORD, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.WORD, value.array.map{it.integer!!}.max() ?: 0))
}
Syscall.FUNC_MAX_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.max() ?: 0
evalstack.push(Value(DataType.FLOAT, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.FLOAT, value.doubleArray.max() ?: 0.0))
}
Syscall.FUNC_MIN_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
evalstack.push(Value(DataType.UBYTE, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, value.array.map{it.integer!!}.min() ?: 0))
}
Syscall.FUNC_MIN_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
evalstack.push(Value(DataType.BYTE, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.BYTE, value.array.map{it.integer!!}.min() ?: 0))
}
Syscall.FUNC_MIN_UW -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
evalstack.push(Value(DataType.UWORD, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.min() ?: 0))
}
Syscall.FUNC_MIN_W -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
evalstack.push(Value(DataType.WORD, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.WORD, value.array.map{it.integer!!}.min() ?: 0))
}
Syscall.FUNC_MIN_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
val result = value.array!!.min() ?: 0
evalstack.push(Value(DataType.FLOAT, result))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.FLOAT, value.doubleArray.min() ?: 0.0))
}
Syscall.FUNC_AVG_UB, Syscall.FUNC_AVG_B, Syscall.FUNC_AVG_UW, Syscall.FUNC_AVG_W, Syscall.FUNC_AVG_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.FLOAT, value.array!!.average()))
Syscall.FUNC_SUM_W, Syscall.FUNC_SUM_B -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.WORD, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_UW -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_UB -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UWORD, value.array!!.sum()))
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.sum()))
}
Syscall.FUNC_SUM_B -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.WORD, value.array!!.sum()))
Syscall.FUNC_SUM_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.FLOAT, value.doubleArray.sum()))
}
Syscall.FUNC_SUM_UW, Syscall.FUNC_SUM_W, Syscall.FUNC_SUM_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.FLOAT, value.array!!.sum()))
Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, if (value.array.any { it.integer != 0 }) 1 else 0))
}
Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W, Syscall.FUNC_ANY_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UBYTE, if (value.array!!.any { v -> v != 0 }) 1 else 0))
Syscall.FUNC_ANY_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, if (value.doubleArray.any { it!=0.0 }) 1 else 0))
}
Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W, Syscall.FUNC_ALL_F -> {
val iterable = evalstack.pop()
val value = heap.get(iterable.heapId)
evalstack.push(Value(DataType.UBYTE, if (value.array!!.all { v -> v != 0 }) 1 else 0))
Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, if (value.array.all { it.integer != 0 }) 1 else 0))
}
Syscall.FUNC_ALL_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(Value(DataType.UBYTE, if (value.doubleArray.all { it != 0.0 }) 1 else 0))
}
Syscall.FUNC_MEMCOPY -> {
val numbytes = evalstack.pop().integerValue()
@@ -2217,12 +2281,35 @@ class StackVm(private var traceOutputFile: String?) {
val num = variables.getValue("A").integerValue()
canvas?.printText(num.toString(), 1, true)
}
Syscall.SYSASM_c64scr_print_b -> {
val num = variables.getValue("A").integerValue()
if(num<=127)
canvas?.printText(num.toString(), 1, true)
else
canvas?.printText("-${256-num}", 1, true)
}
Syscall.SYSASM_c64scr_print_uw -> {
val lo = variables.getValue("A").integerValue()
val hi = variables.getValue("Y").integerValue()
val number = lo+256*hi
canvas?.printText(number.toString(), 1, true)
}
Syscall.SYSASM_c64scr_print_uwhex -> {
val prefix = if(this.P_carry) "$" else ""
val lo = variables.getValue("A").integerValue()
val hi = variables.getValue("Y").integerValue()
val number = lo+256*hi
canvas?.printText("$prefix${number.toString(16).padStart(4, '0')}", 1, true)
}
Syscall.SYSASM_c64scr_print_w -> {
val lo = variables.getValue("A").integerValue()
val hi = variables.getValue("Y").integerValue()
val number = lo+256*hi
if(number<=32767)
canvas?.printText(number.toString(), 1, true)
else
canvas?.printText("-${65536-number}", 1, true)
}
Syscall.SYSASM_c64flt_print_f -> {
val number = variables.getValue("c64flt.print_f.value").numericValue()
canvas?.printText(number.toString(), 1, true)
-2
View File
@@ -330,8 +330,6 @@ class TestStackVmOpcodes {
@Test
fun testPow() {
testBinaryOperator(Value(DataType.UBYTE, 3), Opcode.POW_UB, Value(DataType.UBYTE, 4), Value(DataType.UBYTE, 81))
testBinaryOperator(Value(DataType.UWORD, 3), Opcode.POW_UW, Value(DataType.UWORD, 4), Value(DataType.UWORD, 81))
testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW_F, Value(DataType.FLOAT, 81.0), Value(DataType.FLOAT, 2253.2402360440274))
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
# this script uses the Gradle build to compile the code,
# and then adds the contents of several jar files into one output jar.
./gradlew jar
mkdir -p compiler_jar/extracted
mkdir -p compiler_jar/source
cp compiler/build/libs/compiler.jar parser/build/libs/parser.jar parser/antlr/lib/antlr-runtime-4.7.2.jar compiler_jar/source/
KOTLINLIBS=$(kotlinc -verbose -script 2>&1 | grep home | cut -d ' ' -f 6-)/lib
cp ${KOTLINLIBS}/kotlin-stdlib-jdk8.jar ${KOTLINLIBS}/kotlin-stdlib.jar compiler_jar/source/
pushd compiler_jar/extracted
for i in ../source/*.jar; do jar xf $i; done
cd ..
jar cfe ../prog8compiler.jar prog8.CompilerMainKt -C extracted .
popd
rm -r compiler_jar
ls -l prog8compiler.jar
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

+40 -37
View File
@@ -40,55 +40,58 @@ This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/license
Code example
------------
When this code is compiled::
This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
%import c64lib
%import c64utils
%import c64flt
%zeropage basicsafe
~ main {
ubyte[256] sieve
ubyte candidate_prime = 2
sub start() {
; set text color and activate lowercase charset
c64.COLOR = 13
c64.VMCSB |= 2
memset(sieve, 256, false)
; use optimized routine to write text
c64scr.print("Hello!\n")
; use iteration to write text
str question = "How are you?\n"
for ubyte char in question
c64.CHROUT(char)
; use indexed loop to write characters
str bye = "Goodbye!\n"
for ubyte c in 0 to len(bye)
c64.CHROUT(bye[c])
float clock_seconds = ((mkword(c64.TIME_LO, c64.TIME_MID) as float)
+ (c64.TIME_HI as float)*65536.0)
/ 60
float hours = floor(clock_seconds / 3600)
clock_seconds -= hours*3600
float minutes = floor(clock_seconds / 60)
clock_seconds = floor(clock_seconds - minutes * 60.0)
c64scr.print("system time in ti$ is ")
c64flt.print_f(hours)
c64.CHROUT(':')
c64flt.print_f(minutes)
c64.CHROUT(':')
c64flt.print_f(clock_seconds)
c64scr.print("prime numbers up to 255:\n\n")
ubyte amount=0
while true {
ubyte prime = find_next_prime()
if prime==0
break
c64scr.print_ub(prime)
c64scr.print(", ")
amount++
}
c64.CHROUT('\n')
c64scr.print("number of primes (expected 54): ")
c64scr.print_ub(amount)
c64.CHROUT('\n')
}
sub find_next_prime() -> ubyte {
while sieve[candidate_prime] {
candidate_prime++
if candidate_prime==0
return 0
}
sieve[candidate_prime] = true
uword multiple = candidate_prime
while multiple < len(sieve) {
sieve[lsb(multiple)] = true
multiple += candidate_prime
}
return candidate_prime
}
}
when compiled an ran on a C-64 you'll get:
you get a program that outputs this when loaded on a C-64:
.. image:: _static/hello_screen.png
.. image:: _static/primes_example.png
:align: center
:alt: result when run on C-64
+5 -5
View File
@@ -237,9 +237,9 @@ Arrays
^^^^^^
Array types are also supported. They can be made of bytes, words or floats::
byte[4] array = [1, 2, 3, 4] ; initialize the array
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value
byte[99] array = 255 ; initialize array with 99 times 255 [255, 255, 255, 255, ...]
byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
value = array[3] ; the fourth value in the array (index is 0-based)
char = string[4] ; the fifth character (=byte) in the string
@@ -281,13 +281,13 @@ You'll have to specify the initial value expression. This value is then used
by the compiler everywhere you refer to the constant (and no storage is allocated
for the constant itself). This is only valid for the simple numeric types (byte, word, float).
When using ``memory``, the variable will point to specific location in memory,
When using ``&`` (the address-of operator but now applied to a datatype), the variable will point to specific location in memory,
rather than being newly allocated. The initial value (mandatory) must be a valid
memory address. Reading the variable will read the given data type from the
address you specified, and setting the varible will directly modify that memory location(s)::
const byte max_age = 2000 - 1974 ; max_age will be the constant value 26
memory word SCREENCOLORS = $d020 ; a 16-bit word at the addres $d020-$d021
&word SCREENCOLORS = $d020 ; a 16-bit word at the addres $d020-$d021
.. note::
+30 -31
View File
@@ -123,6 +123,7 @@ Directives
This directive can only be used inside a block.
The assembler will include the file as binary bytes at this point, prog8 will not process this at all.
The optional offset and length can be used to select a particular piece of the file.
The file is located relative to the current working directory!
.. data:: %asminclude "<filename>", "scopelabel"
@@ -133,6 +134,8 @@ Directives
The scopelabel argument will be used as a prefix to access the labels from the included source code,
otherwise you would risk symbol redefinitions or duplications.
If you know what you are doing you can leave it as an empty string to not have a scope prefix.
The compiler first looks for the file relative to the same directory as the module containing this statement is in,
if the file can't be found there it is searched relative to the current directory.
.. data:: %breakpoint
@@ -226,8 +229,8 @@ Various examples::
byte age = 2018 - 1974
float wallet = 55.25
str name = "my name is Irmen"
word address = #counter
byte[5] values = [11, 22, 33, 44, 55]
uword address = &counter
byte[] values = [11, 22, 33, 44, 55]
byte[5] values = 255 ; initialize with five 255 bytes
word @zp zpword = 9999 ; prioritize this when selecting vars for zeropage storage
@@ -251,18 +254,24 @@ type identifier type storage size example var declara
``uword`` unsigned word 2 bytes = 16 bits ``uword myvar = $8fee``
``float`` floating-point 5 bytes = 40 bits ``float myvar = 1.2345``
stored in 5-byte cbm MFLPT format
``byte[x]`` signed byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
``ubyte[x]`` unsigned byte array x bytes ``ubyte[4] myvar = [1, 2, 3, 4]``
``word[x]`` signed word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
``uword[x]`` unsigned word array 2*x bytes ``uword[4] myvar = [1, 2, 3, 4]``
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
``byte[x]`` signed byte array x bytes ``byte[4] myvar``
``ubyte[x]`` unsigned byte array x bytes ``ubyte[4] myvar``
``word[x]`` signed word array 2*x bytes ``word[4] myvar``
``uword[x]`` unsigned word array 2*x bytes ``uword[4] myvar``
``float[x]`` floating-point array 5*x bytes ``float[4] myvar``
``byte[]`` signed byte array depends on value ``byte[] myvar = [1, 2, 3, 4]``
``ubyte[]`` unsigned byte array depends on value ``ubyte[] myvar = [1, 2, 3, 4]``
``word[]`` signed word array depends on value ``word[] myvar = [1, 2, 3, 4]``
``uword[]`` unsigned word array depends on value ``uword[] myvar = [1, 2, 3, 4]``
``float[]`` floating-point array depends on value ``float[] myvar = [1.1, 2.2, 3.3, 4.4]``
``str`` string (petscii) varies ``str myvar = "hello."``
implicitly terminated by a 0-byte
``str_s`` string (screencodes) varies ``str_s myvar = "hello."``
implicitly terminated by a 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. When an initialization
value is given, the array size in the declaration can be omitted.
**hexadecimal numbers:** you can use a dollar prefix to write hexadecimal numbers: ``$20ac``
@@ -282,13 +291,6 @@ of something with an operand starting with 1 or 0, you'll have to add a space in
- You can force a byte value into a word value by adding the ``.w`` datatype suffix to the number: ``$2a.w`` is equivalent to ``$002a``.
.. todo::
omit the array size in the var decl if an initialization array is given?
**@todo pointers/addresses? (as opposed to normal WORDs)**
Data type conversion
^^^^^^^^^^^^^^^^^^^^
Many type conversions are possible by just writing ``as <type>`` at the end of an expression,
@@ -298,11 +300,11 @@ for example ``ubyte ub = floatvalue as ubyte`` will convert the floating point v
Memory mapped variables
^^^^^^^^^^^^^^^^^^^^^^^
The ``memory`` keyword is used in front of a data type keyword, to say that no storage
The ``&`` (address-of operator) used in front of a data type keyword, indicates that no storage
should be allocated by the compiler. Instead, the (mandatory) value assigned to the variable
should be the *memory address* where the value is located::
memory byte BORDER = $d020
&byte BORDERCOLOR = $d020
Direct access to memory locations
@@ -343,7 +345,7 @@ which represents a range of numbers or characters,
from the starting value to (and including) the ending value.
If used in the place of a literal value, it expands into the actual array of values::
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
byte[] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
Array indexing
@@ -360,23 +362,13 @@ Syntax is familiar with brackets: ``arrayvar[x]`` ::
Operators
---------
.. todo::
address-of: ``#`` or ``&`` (to stay close to C)
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: ``+`` ``-`` ``*`` ``/`` ``**`` ``%``
``+``, ``-``, ``*``, ``/`` are the familiar arithmetic operations.
``/`` is division (will result in integer division when using on integer operands, and a floating point division when at least one of the operands is a float)
``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243.
``**`` is the power operator: ``3 ** 5`` is equal to 3*3*3*3*3 and is 243. (it only works on floating point variables)
``%`` is the remainder operator: ``25 % 7`` is 4. Be careful: without a space, %10 will be parsed as the binary number 2
Remainder is only supported on integer operands (not floats).
bitwise arithmetic: ``&`` ``|`` ``^`` ``~`` ``<<`` ``>>``
``&`` is bitwise and, ``|`` is bitwise or, ``^`` is bitwise xor, ``~`` is bitwise invert (this one is an unary operator)
``<<`` is bitwise left shift and ``>>`` is bitwise right shift (both will not change the datatype of the value)
@@ -411,12 +403,19 @@ range creation: ``to``
X = 10
A to X ; range of 5, 6, 7, 8, 9, 10
byte[4] array = 10 to 13 ; sets the array to [1, 2, 3, 4]
byte[] array = 10 to 13 ; sets the array to [1, 2, 3, 4]
for i in 0 to 127 {
; i loops 0, 1, 2, ... 127
}
address of: ``&``
This is a prefix operator that can be applied to a string or array variable or literal value.
It results in the memory address (UWORD) of that string or array in memory: ``uword a = &stringvar``
Sometimes the compiler silently inserts this operator to make it easier for instance
to pass strings or arrays as subroutine call arguments.
This operator can also be used as a prefix to a variable's data type keyword to indicate that
it is a memory mapped variable (for instance: ``&ubyte screencolor = $d021``)
precedence grouping in expressions, or subroutine parameter list: ``(`` *expression* ``)``
Parentheses are used to group parts of an expression to change the order of evaluation.
@@ -517,7 +516,7 @@ For example, this is a for loop using the existing byte variable ``i`` to loop o
And this is a loop over the values of the array ``fibonacci_numbers`` where the loop variable is declared in the loop itself::
word[20] fibonacci_numbers = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
word[] fibonacci_numbers = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
for word fibnr in fibonacci_numbers {
; do something
-4
View File
@@ -173,7 +173,3 @@ as a subroutine ``irq`` in the module ``irq`` so like this::
; ... irq handling here ...
}
}
.. todo::
@todo the irq handler should use its own eval-stack to avoid stack interference issues
+4 -18
View File
@@ -5,7 +5,7 @@ TODO
Memory Block Operations integrated in language?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@todo list,string memory block operations?
list,string memory block operations?
- list operations (whole list, individual element)
operations: set, get, copy (from another list with the same length), shift-N(left,right), rotate-N(left,right)
@@ -15,9 +15,9 @@ Memory Block Operations integrated in language?
- strings: identical operations as on lists.
these should call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
these should call optimized pieces of assembly code, so they run as fast as possible
For now, we have the ``memcopy`` and ``memset`` builtin functions.
For now, we have the ``memcopy``, ``memset`` and ``strlen`` builtin functions.
@@ -52,17 +52,6 @@ Allocate a fixed word in ZP that is the TOS so we can operate on TOS directly
without having to to index into the stack?
More flexible (non-const) arrays?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Currently, array literals can only be constants
Allow for non-const arrays? Such as::
ubyte[16] block1
ubyte[16] block2
ubyte[16] block3
ubyte[3] blocks = [block1, block2, block3]
structs?
^^^^^^^^
@@ -71,7 +60,7 @@ of values together (and use it multiple times). Something like::
struct Point {
ubyte color
word[3] vec = [0,0,0]
word[] vec = [0,0,0]
}
Point p1
@@ -85,7 +74,4 @@ of values together (and use it multiple times). Something like::
Misc
^^^^
- sqrt() should have integer implementation as well, instead of relying on float SQRT for all argument types
- code generation for POW instruction
- are there any other missing instructions in the code generator?
- implement %asmbinary
+2 -2
View File
@@ -56,7 +56,7 @@ sub start() {
; details about the boulderdash music can be found here:
; https://www.elmerproductions.com/sp/peterb/sounds.html#Theme%20tune
uword[128] notes = [
uword[] notes = [
$1622, $1d26, $2229, $252e, $1424, $1f27, $2029, $2730,
$122a, $122c, $1e2e, $1231, $202c, $3337, $212d, $3135,
$1622, $162e, $161d, $1624, $1420, $1430, $1424, $1420,
@@ -76,7 +76,7 @@ sub start() {
]
uword[59] music_freq_table = [
uword[] music_freq_table = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
732, 778, 826, 876, 928, 978, 1042, 1100, 1170, 1238, 1312, 1390, 1464, 1556,
1652, 1752, 1856, 1956, 2084, 2200, 2340, 2476, 2624, 2780, 2928, 3112, 3304,
+3 -3
View File
@@ -8,9 +8,9 @@
const uword height = 25
; vertices
float[8] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
float[8] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ]
float[8] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ]
float[] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
float[] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ]
float[] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ]
; storage for rotated coordinates
float[len(xcoor)] rotatedx=0.0
+5 -5
View File
@@ -6,7 +6,7 @@
; it must start on an address aligned to 64 bytes.
%option force_output ; make sure the data in this block appears in the resulting program
ubyte[128] sprites = [
ubyte[] sprites = [
%00000000,%00000000,%00000000,
%00000000,%00111100,%00000000,
%00000000,%11111111,%00000000,
@@ -64,9 +64,9 @@
const uword height = 200
; vertices
byte[8] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ]
byte[8] ycoor = [ -100, -100, 100, 100, -100, -100, 100, 100 ]
byte[8] zcoor = [ -100, 100, -100, 100, -100, 100, -100, 100 ]
byte[] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ]
byte[] ycoor = [ -100, -100, 100, 100, -100, -100, 100, 100 ]
byte[] zcoor = [ -100, 100, -100, 100, -100, 100, -100, 100 ]
; storage for rotated coordinates
word[len(xcoor)] rotatedx
@@ -146,7 +146,7 @@
}
}
ubyte[8] spritecolors = [1,1,7,15,12,11,9,9]
ubyte[] spritecolors = [1,1,7,15,12,11,9,9]
for ubyte i in 0 to 7 {
word zc = rotatedz[i]
+4 -4
View File
@@ -20,12 +20,12 @@
const uword height = 200
; vertices
float[8] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
float[8] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ]
float[8] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ]
float[] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
float[] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ]
float[] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ]
; edges (msb=from vertex, lsb=to vertex)
uword[12] edges = [$0001, $0103, $0302, $0200, $0405, $0507, $0706, $0604, $0004, $0105, $0206, $0307]
uword[] edges = [$0001, $0103, $0302, $0200, $0405, $0507, $0706, $0604, $0004, $0105, $0206, $0307]
; storage for rotated coordinates
float[len(xcoor)] rotatedx
+4 -4
View File
@@ -7,9 +7,9 @@
const uword height = 25
; vertices
byte[8] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
byte[8] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
byte[8] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
byte[] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
byte[] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
byte[] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
; storage for rotated coordinates
word[len(xcoor)] rotatedx
@@ -68,7 +68,7 @@
}
}
ubyte[6] vertexcolors = [1,7,7,12,11,6]
ubyte[] vertexcolors = [1,7,7,12,11,6]
sub draw_edges() {
+1 -1
View File
@@ -18,7 +18,7 @@
~ irq {
const ubyte barheight = 4
ubyte[13] colors = [6,2,4,5,15,7,1,13,3,12,8,11,9]
ubyte[] colors = [6,2,4,5,15,7,1,13,3,12,8,11,9]
ubyte color = 0
ubyte ypos = 0
+21 -21
View File
@@ -8,27 +8,27 @@
; it must start on an address aligned to 64 bytes.
%option force_output ; make sure the data in this block appears in the resulting program
ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
ubyte[] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
}
~ main {
+32 -46
View File
@@ -205,7 +205,7 @@ waitkey:
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
uword[] scores = [10, 25, 50, 100] ; can never clear more than 4 lines
score += scores[num_lines-1]
speedlevel = 1+lsb(lines/10)
drawScore()
@@ -320,7 +320,7 @@ waitkey:
c64scr.setcc(boardOffsetX+boardWidth, i, 84, 11)
}
ubyte[5] colors = [6,8,7,5,4]
ubyte[] 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])
@@ -387,54 +387,40 @@ waitkey:
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]
ubyte[] 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[] blockJ = [6,0,0,0, ; blue
6,6,6,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockL = [0,0,8,0, ; orange
8,8,8,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockO = [0,7,7,0, ; yellow ; note: no rotation (square)
0,7,7,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockS = [0,5,5,0, ; green
5,5,0,0,
0,0,0,0,
0,0,0,0]
ubyte[] blockT = [0,4,0,0, ; purple
4,4,4,0,
0,0,0,0,
0,0,0,0]
ubyte[] 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]
uword[] 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))
memcopy(blocks[block], currentBlock, len(currentBlock))
}
sub rotateCW() {
+20 -7
View File
@@ -1,15 +1,28 @@
%zeropage basicsafe
%option enable_floats
%import c64flt
~ main {
ubyte @zp var1
float[] fa = [1.1,2.2,3.3]
ubyte[] uba = [10,2,3,4]
byte[] ba = [-10,2,3,4]
uword[] uwa = [100,20,30,40]
word[] wa = [-100,20,30,40]
sub start() {
ubyte @zp var1
A=20
A=var1
Y=main.var1
}
float a
a=avg([1,2,3,4])
c64flt.print_f(a)
c64.CHROUT('\n')
a=avg([100,200,300,400])
c64flt.print_f(a)
c64.CHROUT('\n')
a=avg([1.1,2.2,3.3,4.4])
c64flt.print_f(a)
c64.CHROUT('\n')
}
}
+21 -21
View File
@@ -8,27 +8,27 @@
; it must start on an address aligned to 64 bytes.
%option force_output ; make sure the data in this block appears in the resulting program
ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
ubyte[] balloonsprite = [ %00000000,%01111111,%00000000,
%00000001,%11111111,%11000000,
%00000011,%11111111,%11100000,
%00000011,%11100011,%11100000,
%00000111,%11011100,%11110000,
%00000111,%11011101,%11110000,
%00000111,%11011100,%11110000,
%00000011,%11100011,%11100000,
%00000011,%11111111,%11100000,
%00000011,%11111111,%11100000,
%00000010,%11111111,%10100000,
%00000001,%01111111,%01000000,
%00000001,%00111110,%01000000,
%00000000,%10011100,%10000000,
%00000000,%10011100,%10000000,
%00000000,%01001001,%00000000,
%00000000,%01001001,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00111110,%00000000,
%00000000,%00011100,%00000000 ]
}
~ main {
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
# compile using regular Kotlin sdk command line tool
echo "Compiling the parser..."
java -jar ./parser/antlr/lib/antlr-4.7.2-complete.jar -o ./parser/src/prog8/parser -Xexact-output-dir -no-listener -no-visitor ./parser/antlr/prog8.g4
@@ -12,7 +14,7 @@ mkdir -p ${PARSER_CLASSES}
javac -d ${PARSER_CLASSES} -cp ${ANTLR_RUNTIME} ./parser/src/prog8/parser/prog8Lexer.java ./parser/src/prog8/parser/prog8Parser.java
echo "Compiling the compiler itself..."
kotlinc -verbose -include-runtime -d ${COMPILER_JAR} -cp ${ANTLR_RUNTIME}:${PARSER_CLASSES} ./compiler/src/prog8
JAVA_OPTS="-Xmx3G -Xms300M" kotlinc -verbose -include-runtime -d ${COMPILER_JAR} -jvm-target 1.8 -cp ${ANTLR_RUNTIME}:${PARSER_CLASSES} ./compiler/src/prog8
echo "Finalizing the compiler jar file..."
# add the antlr parser classes
+1 -1
View File
@@ -1,7 +1,7 @@
@echo off
set PROG8CLASSPATH=./out/production/compiler_main;./out/production/parser_main
set KOTLINPATH=%USERPROFILE%/.IdeaIC2018.3/config/plugins/Kotlin
set KOTLINPATH=%USERPROFILE%/.IdeaIC2019.1/config/plugins/Kotlin
set LIBJARS=%KOTLINPATH%/lib/kotlin-stdlib.jar;%KOTLINPATH%/lib/kotlin-reflect.jar;./parser/antlr/lib/antlr-runtime-4.7.2.jar
java -cp %PROG8CLASSPATH%;%LIBJARS% prog8.CompilerMainKt %*
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
PROG8CLASSPATH=./out/production/compiler_main:./out/production/parser_main
KOTLINPATH=${HOME}/.IntelliJIdea2018.3/config/plugins/Kotlin
PROG8CLASSPATH=./compiler/build/classes/kotlin/main:./compiler/build/resources/main:./parser/build/classes/java/main
KOTLINPATH=${HOME}/.IntelliJIdea2019.1/config/plugins/Kotlin
LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar:./parser/antlr/lib/antlr-runtime-4.7.2.jar
java -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.CompilerMainKt $*
+1 -1
View File
@@ -1,7 +1,7 @@
@echo off
set PROG8CLASSPATH=./out/production/compiler_main
set KOTLINPATH=%USERPROFILE%/.IdeaIC2018.3/config/plugins/Kotlin
set KOTLINPATH=%USERPROFILE%/.IdeaIC2019.1/config/plugins/Kotlin
set LIBJARS=%KOTLINPATH%/lib/kotlin-stdlib.jar;%KOTLINPATH%/lib/kotlin-reflect.jar
java -cp %PROG8CLASSPATH%;%LIBJARS% prog8.StackVmMainKt %*
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
PROG8CLASSPATH=./out/production/compiler_main
KOTLINPATH=${HOME}/.IntelliJIdea2018.3/config/plugins/Kotlin
PROG8CLASSPATH=./compiler/build/classes/kotlin/main:./compiler/build/resources/main
KOTLINPATH=${HOME}/.IntelliJIdea2019.1/config/plugins/Kotlin
LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar
java -cp ${PROG8CLASSPATH}:${LIBJARS} prog8.StackVmMainKt $*
+12 -4
View File
@@ -23,6 +23,7 @@ NAME : [a-zA-Z_][a-zA-Z0-9_]* ;
DEC_INTEGER : ('0'..'9') | (('1'..'9')('0'..'9')+);
HEX_INTEGER : '$' (('a'..'f') | ('A'..'F') | ('0'..'9'))+ ;
BIN_INTEGER : '%' ('0' | '1')+ ;
ADDRESS_OF: '&';
FLOAT_NUMBER : FNUMBER (('E'|'e') ('+' | '-')? FNUMBER)? ; // sign comes later from unary expression
fragment FNUMBER : ('0' .. '9') + ('.' ('0' .. '9') +)? ;
@@ -58,6 +59,10 @@ ZEROPAGE :
'@zp'
;
ARRAYSIG :
'[]'
;
module : (modulestatement | EOL)* EOF ;
@@ -103,17 +108,17 @@ directive :
directivearg : stringliteral | identifier | integerliteral ;
vardecl: datatype ZEROPAGE? arrayspec? identifier ;
vardecl: datatype ZEROPAGE? (arrayindex | ARRAYSIG) ? identifier ;
varinitializer : vardecl '=' expression ;
constdecl: 'const' varinitializer ;
memoryvardecl: 'memory' varinitializer;
memoryvardecl: ADDRESS_OF varinitializer;
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_s' ;
arrayspec: '[' expression ']' ;
arrayindex: '[' expression ']' ;
assignment : assign_targets '=' expression ;
@@ -154,6 +159,7 @@ expression :
| scoped_identifier
| arrayindexed
| directmemory
| addressof
| expression typecast
| '(' expression ')'
;
@@ -162,10 +168,12 @@ expression :
typecast : 'as' datatype;
arrayindexed : scoped_identifier arrayspec ;
arrayindexed : scoped_identifier arrayindex ;
directmemory : '@' '(' expression ')';
addressof : <assoc=right> ADDRESS_OF scoped_identifier ;
functioncall : scoped_identifier '(' expression_list? ')' ;
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="antlr-4.7.2-complete" level="project" />
</component>
</module>
+292 -293
View File
@@ -1,4 +1,4 @@
// Generated from ./parser/antlr/prog8.g4 by ANTLR 4.7.2
// Generated from prog8.g4 by ANTLR 4.7.2
package prog8.parser;
@@ -34,9 +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__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__107=108, T__108=109, T__109=110, LINECOMMENT=111, COMMENT=112, WS=113,
EOL=114, NAME=115, DEC_INTEGER=116, HEX_INTEGER=117, BIN_INTEGER=118,
FLOAT_NUMBER=119, STRING=120, INLINEASMBLOCK=121, SINGLECHAR=122, ZEROPAGE=123;
T__107=108, LINECOMMENT=109, COMMENT=110, WS=111, EOL=112, NAME=113, DEC_INTEGER=114,
HEX_INTEGER=115, BIN_INTEGER=116, ADDRESS_OF=117, FLOAT_NUMBER=118, STRING=119,
INLINEASMBLOCK=120, SINGLECHAR=121, ZEROPAGE=122, ARRAYSIG=123;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
@@ -60,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__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__105", "T__106", "T__107", "T__108", "T__109", "LINECOMMENT", "COMMENT",
"WS", "EOL", "NAME", "DEC_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER",
"T__105", "T__106", "T__107", "LINECOMMENT", "COMMENT", "WS", "EOL",
"NAME", "DEC_INTEGER", "HEX_INTEGER", "BIN_INTEGER", "ADDRESS_OF", "FLOAT_NUMBER",
"FNUMBER", "STRING_ESCAPE_SEQ", "STRING", "INLINEASMBLOCK", "SINGLECHAR",
"ZEROPAGE"
"ZEROPAGE", "ARRAYSIG"
};
}
public static final String[] ruleNames = makeRuleNames();
@@ -72,20 +72,20 @@ public class prog8Lexer extends Lexer {
return new String[] {
null, "'~'", "':'", "'goto'", "'%output'", "'%launcher'", "'%zeropage'",
"'%zpreserved'", "'%address'", "'%import'", "'%breakpoint'", "'%asminclude'",
"'%asmbinary'", "'%option'", "','", "'='", "'const'", "'memory'", "'ubyte'",
"'byte'", "'uword'", "'word'", "'float'", "'str'", "'str_s'", "'['",
"']'", "'+='", "'-='", "'/='", "'*='", "'**='", "'&='", "'|='", "'^='",
"'%='", "'<<='", "'>>='", "'++'", "'--'", "'+'", "'-'", "'**'", "'*'",
"'/'", "'%'", "'<<'", "'>>'", "'<'", "'>'", "'<='", "'>='", "'=='", "'!='",
"'&'", "'^'", "'|'", "'to'", "'step'", "'and'", "'or'", "'xor'", "'not'",
"'('", "')'", "'as'", "'@'", "'return'", "'break'", "'continue'", "'.'",
"'A'", "'X'", "'Y'", "'AX'", "'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'",
"'Pv'", "'.w'", "'true'", "'false'", "'%asm'", "'sub'", "'->'", "'{'",
"'}'", "'asmsub'", "'clobbers'", "'stack'", "'if'", "'else'", "'if_cs'",
"'if_cc'", "'if_eq'", "'if_z'", "'if_ne'", "'if_nz'", "'if_pl'", "'if_pos'",
"'if_mi'", "'if_neg'", "'if_vs'", "'if_vc'", "'for'", "'in'", "'while'",
"'repeat'", "'until'", null, null, null, null, null, null, null, null,
null, null, null, null, "'@zp'"
"'%asmbinary'", "'%option'", "','", "'='", "'const'", "'ubyte'", "'byte'",
"'uword'", "'word'", "'float'", "'str'", "'str_s'", "'['", "']'", "'+='",
"'-='", "'/='", "'*='", "'**='", "'&='", "'|='", "'^='", "'%='", "'<<='",
"'>>='", "'++'", "'--'", "'+'", "'-'", "'**'", "'*'", "'/'", "'%'", "'<<'",
"'>>'", "'<'", "'>'", "'<='", "'>='", "'=='", "'!='", "'^'", "'|'", "'to'",
"'step'", "'and'", "'or'", "'xor'", "'not'", "'('", "')'", "'as'", "'@'",
"'return'", "'break'", "'continue'", "'.'", "'A'", "'X'", "'Y'", "'AX'",
"'AY'", "'XY'", "'Pc'", "'Pz'", "'Pn'", "'Pv'", "'.w'", "'true'", "'false'",
"'%asm'", "'sub'", "'->'", "'{'", "'}'", "'asmsub'", "'clobbers'", "'stack'",
"'if'", "'else'", "'if_cs'", "'if_cc'", "'if_eq'", "'if_z'", "'if_ne'",
"'if_nz'", "'if_pl'", "'if_pos'", "'if_mi'", "'if_neg'", "'if_vs'", "'if_vc'",
"'for'", "'in'", "'while'", "'repeat'", "'until'", null, null, null,
null, null, null, null, null, "'&'", null, null, null, null, "'@zp'",
"'[]'"
};
}
private static final String[] _LITERAL_NAMES = makeLiteralNames();
@@ -100,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, "LINECOMMENT", "COMMENT", "WS", "EOL", "NAME", "DEC_INTEGER",
"HEX_INTEGER", "BIN_INTEGER", "FLOAT_NUMBER", "STRING", "INLINEASMBLOCK",
"SINGLECHAR", "ZEROPAGE"
null, "LINECOMMENT", "COMMENT", "WS", "EOL", "NAME", "DEC_INTEGER", "HEX_INTEGER",
"BIN_INTEGER", "ADDRESS_OF", "FLOAT_NUMBER", "STRING", "INLINEASMBLOCK",
"SINGLECHAR", "ZEROPAGE", "ARRAYSIG"
};
}
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
@@ -166,13 +166,13 @@ public class prog8Lexer extends Lexer {
@Override
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
switch (ruleIndex) {
case 121:
case 120:
STRING_action((RuleContext)_localctx, actionIndex);
break;
case 122:
case 121:
INLINEASMBLOCK_action((RuleContext)_localctx, actionIndex);
break;
case 123:
case 122:
SINGLECHAR_action((RuleContext)_localctx, actionIndex);
break;
}
@@ -212,7 +212,7 @@ public class prog8Lexer extends Lexer {
}
public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2}\u0362\b\1\4\2\t"+
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2}\u035e\b\1\4\2\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\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\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\t\31"+
@@ -233,271 +233,270 @@ public class prog8Lexer extends Lexer {
"\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"+
"\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"+
"\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"+
"\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"+
"\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"+
"\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"+
"\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"+
"\36\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\60\3\60\3\60\3\61\3\61\3\62\3\62\3\63\3\63"+
"\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"+
"\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"+
"\3F\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3H\3H\3I\3I\3J\3J\3K\3K\3K\3L\3L\3L"+
"\3M\3M\3M\3N\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3R\3R\3R\3S\3S\3S\3S\3S"+
"\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3V\3V\3V\3V\3W\3W\3W\3X\3X\3Y\3Y\3Z"+
"\3Z\3Z\3Z\3Z\3Z\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`\3a\3a\3a"+
"\3a\3a\3a\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3d\3e\3e\3e"+
"\3e\3e\3e\3f\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3h\3h\3h\3h\3h\3h\3h"+
"\3i\3i\3i\3i\3i\3i\3j\3j\3j\3j\3j\3j\3k\3k\3k\3k\3l\3l\3l\3m\3m\3m\3m"+
"\3m\3m\3n\3n\3n\3n\3n\3n\3n\3o\3o\3o\3o\3o\3o\3p\3p\7p\u02ed\np\fp\16"+
"p\u02f0\13p\3p\3p\3p\3p\3q\3q\7q\u02f8\nq\fq\16q\u02fb\13q\3q\3q\3r\3"+
"r\3r\3r\3s\6s\u0304\ns\rs\16s\u0305\3t\3t\7t\u030a\nt\ft\16t\u030d\13"+
"t\3u\3u\3u\6u\u0312\nu\ru\16u\u0313\5u\u0316\nu\3v\3v\6v\u031a\nv\rv\16"+
"v\u031b\3w\3w\6w\u0320\nw\rw\16w\u0321\3x\3x\3x\5x\u0327\nx\3x\5x\u032a"+
"\nx\3y\6y\u032d\ny\ry\16y\u032e\3y\3y\6y\u0333\ny\ry\16y\u0334\5y\u0337"+
"\ny\3z\3z\3z\3z\5z\u033d\nz\3{\3{\3{\7{\u0342\n{\f{\16{\u0345\13{\3{\3"+
"{\3{\3|\3|\3|\3|\6|\u034e\n|\r|\16|\u034f\3|\3|\3|\3|\3|\3}\3}\3}\5}\u035a"+
"\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"+
"\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30"+
"/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.["+
"/]\60_\61a\62c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083"+
"C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097"+
"M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00ab"+
"W\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bf"+
"a\u00c1b\u00c3c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3"+
"k\u00d5l\u00d7m\u00d9n\u00dbo\u00ddp\u00dfq\u00e1r\u00e3s\u00e5t\u00e7"+
"u\u00e9v\u00ebw\u00edx\u00efy\u00f1\2\u00f3\2\u00f5z\u00f7{\u00f9|\u00fb"+
"}\3\2\n\4\2\f\f\17\17\4\2\13\13\"\"\5\2C\\aac|\6\2\62;C\\aac|\5\2\62;"+
"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"+
"\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"+
"\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\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\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\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\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"+
"\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"+
"\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\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"+
"\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"+
"\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\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"+
"\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\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"+
"\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\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"+
"\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\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"+
"\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\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"+
"\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\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"+
"\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"+
"\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"+
"\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"+
"\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\31\u0157\3\2\2\2\33\u0162\3\2\2\2\35\u016a\3\2\2\2\37\u016c\3\2\2\2"+
"!\u016e\3\2\2\2#\u0174\3\2\2\2%\u017b\3\2\2\2\'\u0181\3\2\2\2)\u0186\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"+
"\u01a1\3\2\2\2\65\u01a3\3\2\2\2\67\u01a5\3\2\2\29\u01a8\3\2\2\2;\u01ab"+
"\3\2\2\2=\u01ae\3\2\2\2?\u01b1\3\2\2\2A\u01b5\3\2\2\2C\u01b8\3\2\2\2E"+
"\u01bb\3\2\2\2G\u01be\3\2\2\2I\u01c1\3\2\2\2K\u01c5\3\2\2\2M\u01c9\3\2"+
"\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\2Y\u01d8\3\2\2\2[\u01da\3\2\2\2]\u01dc\3\2\2\2_\u01df\3\2\2\2a"+
"\u01e2\3\2\2\2c\u01e4\3\2\2\2e\u01e6\3\2\2\2g\u01e9\3\2\2\2i\u01ec\3\2"+
"\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\2u\u01fb\3\2\2\2w\u0200\3\2\2\2y\u0204\3\2\2\2{\u0207\3\2\2\2}"+
"\u020b\3\2\2\2\177\u020f\3\2\2\2\u0081\u0211\3\2\2\2\u0083\u0213\3\2\2"+
"\2\u0085\u0216\3\2\2\2\u0087\u0218\3\2\2\2\u0089\u021f\3\2\2\2\u008b\u0225"+
"\3\2\2\2\u008d\u022e\3\2\2\2\u008f\u0230\3\2\2\2\u0091\u0232\3\2\2\2\u0093"+
"\u0234\3\2\2\2\u0095\u0236\3\2\2\2\u0097\u0239\3\2\2\2\u0099\u023c\3\2"+
"\2\2\u009b\u023f\3\2\2\2\u009d\u0242\3\2\2\2\u009f\u0245\3\2\2\2\u00a1"+
"\u0248\3\2\2\2\u00a3\u024b\3\2\2\2\u00a5\u024e\3\2\2\2\u00a7\u0253\3\2"+
"\2\2\u00a9\u0259\3\2\2\2\u00ab\u025e\3\2\2\2\u00ad\u0262\3\2\2\2\u00af"+
"\u0265\3\2\2\2\u00b1\u0267\3\2\2\2\u00b3\u0269\3\2\2\2\u00b5\u0270\3\2"+
"\2\2\u00b7\u0279\3\2\2\2\u00b9\u027f\3\2\2\2\u00bb\u0282\3\2\2\2\u00bd"+
"\u0287\3\2\2\2\u00bf\u028d\3\2\2\2\u00c1\u0293\3\2\2\2\u00c3\u0299\3\2"+
"\2\2\u00c5\u029e\3\2\2\2\u00c7\u02a4\3\2\2\2\u00c9\u02aa\3\2\2\2\u00cb"+
"\u02b0\3\2\2\2\u00cd\u02b7\3\2\2\2\u00cf\u02bd\3\2\2\2\u00d1\u02c4\3\2"+
"\2\2\u00d3\u02ca\3\2\2\2\u00d5\u02d0\3\2\2\2\u00d7\u02d4\3\2\2\2\u00d9"+
"\u02d7\3\2\2\2\u00db\u02dd\3\2\2\2\u00dd\u02e4\3\2\2\2\u00df\u02ea\3\2"+
"\2\2\u00e1\u02f5\3\2\2\2\u00e3\u02fe\3\2\2\2\u00e5\u0303\3\2\2\2\u00e7"+
"\u0307\3\2\2\2\u00e9\u0315\3\2\2\2\u00eb\u0317\3\2\2\2\u00ed\u031d\3\2"+
"\2\2\u00ef\u0323\3\2\2\2\u00f1\u032c\3\2\2\2\u00f3\u033c\3\2\2\2\u00f5"+
"\u033e\3\2\2\2\u00f7\u0349\3\2\2\2\u00f9\u0356\3\2\2\2\u00fb\u035e\3\2"+
"\2\2\u00fd\u00fe\7\u0080\2\2\u00fe\4\3\2\2\2\u00ff\u0100\7<\2\2\u0100"+
"\6\3\2\2\2\u0101\u0102\7i\2\2\u0102\u0103\7q\2\2\u0103\u0104\7v\2\2\u0104"+
"\u0105\7q\2\2\u0105\b\3\2\2\2\u0106\u0107\7\'\2\2\u0107\u0108\7q\2\2\u0108"+
"\u0109\7w\2\2\u0109\u010a\7v\2\2\u010a\u010b\7r\2\2\u010b\u010c\7w\2\2"+
"\u010c\u010d\7v\2\2\u010d\n\3\2\2\2\u010e\u010f\7\'\2\2\u010f\u0110\7"+
"n\2\2\u0110\u0111\7c\2\2\u0111\u0112\7w\2\2\u0112\u0113\7p\2\2\u0113\u0114"+
"\7e\2\2\u0114\u0115\7j\2\2\u0115\u0116\7g\2\2\u0116\u0117\7t\2\2\u0117"+
"\f\3\2\2\2\u0118\u0119\7\'\2\2\u0119\u011a\7|\2\2\u011a\u011b\7g\2\2\u011b"+
"\u011c\7t\2\2\u011c\u011d\7q\2\2\u011d\u011e\7r\2\2\u011e\u011f\7c\2\2"+
"\u011f\u0120\7i\2\2\u0120\u0121\7g\2\2\u0121\16\3\2\2\2\u0122\u0123\7"+
"\'\2\2\u0123\u0124\7|\2\2\u0124\u0125\7r\2\2\u0125\u0126\7t\2\2\u0126"+
"\u0127\7g\2\2\u0127\u0128\7u\2\2\u0128\u0129\7g\2\2\u0129\u012a\7t\2\2"+
"\u012a\u012b\7x\2\2\u012b\u012c\7g\2\2\u012c\u012d\7f\2\2\u012d\20\3\2"+
"\2\2\u012e\u012f\7\'\2\2\u012f\u0130\7c\2\2\u0130\u0131\7f\2\2\u0131\u0132"+
"\7f\2\2\u0132\u0133\7t\2\2\u0133\u0134\7g\2\2\u0134\u0135\7u\2\2\u0135"+
"\u0136\7u\2\2\u0136\22\3\2\2\2\u0137\u0138\7\'\2\2\u0138\u0139\7k\2\2"+
"\u0139\u013a\7o\2\2\u013a\u013b\7r\2\2\u013b\u013c\7q\2\2\u013c\u013d"+
"\7t\2\2\u013d\u013e\7v\2\2\u013e\24\3\2\2\2\u013f\u0140\7\'\2\2\u0140"+
"\u0141\7d\2\2\u0141\u0142\7t\2\2\u0142\u0143\7g\2\2\u0143\u0144\7c\2\2"+
"\u0144\u0145\7m\2\2\u0145\u0146\7r\2\2\u0146\u0147\7q\2\2\u0147\u0148"+
"\7k\2\2\u0148\u0149\7p\2\2\u0149\u014a\7v\2\2\u014a\26\3\2\2\2\u014b\u014c"+
"\7\'\2\2\u014c\u014d\7c\2\2\u014d\u014e\7u\2\2\u014e\u014f\7o\2\2\u014f"+
"\u0150\7k\2\2\u0150\u0151\7p\2\2\u0151\u0152\7e\2\2\u0152\u0153\7n\2\2"+
"\u0153\u0154\7w\2\2\u0154\u0155\7f\2\2\u0155\u0156\7g\2\2\u0156\30\3\2"+
"\2\2\u0157\u0158\7\'\2\2\u0158\u0159\7c\2\2\u0159\u015a\7u\2\2\u015a\u015b"+
"\7o\2\2\u015b\u015c\7d\2\2\u015c\u015d\7k\2\2\u015d\u015e\7p\2\2\u015e"+
"\u015f\7c\2\2\u015f\u0160\7t\2\2\u0160\u0161\7{\2\2\u0161\32\3\2\2\2\u0162"+
"\u0163\7\'\2\2\u0163\u0164\7q\2\2\u0164\u0165\7r\2\2\u0165\u0166\7v\2"+
"\2\u0166\u0167\7k\2\2\u0167\u0168\7q\2\2\u0168\u0169\7p\2\2\u0169\34\3"+
"\2\2\2\u016a\u016b\7.\2\2\u016b\36\3\2\2\2\u016c\u016d\7?\2\2\u016d \3"+
"\2\2\2\u016e\u016f\7e\2\2\u016f\u0170\7q\2\2\u0170\u0171\7p\2\2\u0171"+
"\u0172\7u\2\2\u0172\u0173\7v\2\2\u0173\"\3\2\2\2\u0174\u0175\7o\2\2\u0175"+
"\u0176\7g\2\2\u0176\u0177\7o\2\2\u0177\u0178\7q\2\2\u0178\u0179\7t\2\2"+
"\u0179\u017a\7{\2\2\u017a$\3\2\2\2\u017b\u017c\7w\2\2\u017c\u017d\7d\2"+
"\2\u017d\u017e\7{\2\2\u017e\u017f\7v\2\2\u017f\u0180\7g\2\2\u0180&\3\2"+
"\2\2\u0181\u0182\7d\2\2\u0182\u0183\7{\2\2\u0183\u0184\7v\2\2\u0184\u0185"+
"\7g\2\2\u0185(\3\2\2\2\u0186\u0187\7w\2\2\u0187\u0188\7y\2\2\u0188\u0189"+
"\7q\2\2\u0189\u018a\7t\2\2\u018a\u018b\7f\2\2\u018b*\3\2\2\2\u018c\u018d"+
"\7y\2\2\u018d\u018e\7q\2\2\u018e\u018f\7t\2\2\u018f\u0190\7f\2\2\u0190"+
",\3\2\2\2\u0191\u0192\7h\2\2\u0192\u0193\7n\2\2\u0193\u0194\7q\2\2\u0194"+
"\u0195\7c\2\2\u0195\u0196\7v\2\2\u0196.\3\2\2\2\u0197\u0198\7u\2\2\u0198"+
"\u0199\7v\2\2\u0199\u019a\7t\2\2\u019a\60\3\2\2\2\u019b\u019c\7u\2\2\u019c"+
"\u019d\7v\2\2\u019d\u019e\7t\2\2\u019e\u019f\7a\2\2\u019f\u01a0\7u\2\2"+
"\u01a0\62\3\2\2\2\u01a1\u01a2\7]\2\2\u01a2\64\3\2\2\2\u01a3\u01a4\7_\2"+
"\2\u01a4\66\3\2\2\2\u01a5\u01a6\7-\2\2\u01a6\u01a7\7?\2\2\u01a78\3\2\2"+
"\2\u01a8\u01a9\7/\2\2\u01a9\u01aa\7?\2\2\u01aa:\3\2\2\2\u01ab\u01ac\7"+
"\61\2\2\u01ac\u01ad\7?\2\2\u01ad<\3\2\2\2\u01ae\u01af\7,\2\2\u01af\u01b0"+
"\7?\2\2\u01b0>\3\2\2\2\u01b1\u01b2\7,\2\2\u01b2\u01b3\7,\2\2\u01b3\u01b4"+
"\7?\2\2\u01b4@\3\2\2\2\u01b5\u01b6\7(\2\2\u01b6\u01b7\7?\2\2\u01b7B\3"+
"\2\2\2\u01b8\u01b9\7~\2\2\u01b9\u01ba\7?\2\2\u01baD\3\2\2\2\u01bb\u01bc"+
"\7`\2\2\u01bc\u01bd\7?\2\2\u01bdF\3\2\2\2\u01be\u01bf\7\'\2\2\u01bf\u01c0"+
"\7?\2\2\u01c0H\3\2\2\2\u01c1\u01c2\7>\2\2\u01c2\u01c3\7>\2\2\u01c3\u01c4"+
"\7?\2\2\u01c4J\3\2\2\2\u01c5\u01c6\7@\2\2\u01c6\u01c7\7@\2\2\u01c7\u01c8"+
"\7?\2\2\u01c8L\3\2\2\2\u01c9\u01ca\7-\2\2\u01ca\u01cb\7-\2\2\u01cbN\3"+
"\2\2\2\u01cc\u01cd\7/\2\2\u01cd\u01ce\7/\2\2\u01ceP\3\2\2\2\u01cf\u01d0"+
"\7-\2\2\u01d0R\3\2\2\2\u01d1\u01d2\7/\2\2\u01d2T\3\2\2\2\u01d3\u01d4\7"+
",\2\2\u01d4\u01d5\7,\2\2\u01d5V\3\2\2\2\u01d6\u01d7\7,\2\2\u01d7X\3\2"+
"\2\2\u01d8\u01d9\7\61\2\2\u01d9Z\3\2\2\2\u01da\u01db\7\'\2\2\u01db\\\3"+
"\2\2\2\u01dc\u01dd\7>\2\2\u01dd\u01de\7>\2\2\u01de^\3\2\2\2\u01df\u01e0"+
"\7@\2\2\u01e0\u01e1\7@\2\2\u01e1`\3\2\2\2\u01e2\u01e3\7>\2\2\u01e3b\3"+
"\2\2\2\u01e4\u01e5\7@\2\2\u01e5d\3\2\2\2\u01e6\u01e7\7>\2\2\u01e7\u01e8"+
"\7?\2\2\u01e8f\3\2\2\2\u01e9\u01ea\7@\2\2\u01ea\u01eb\7?\2\2\u01ebh\3"+
"\2\2\2\u01ec\u01ed\7?\2\2\u01ed\u01ee\7?\2\2\u01eej\3\2\2\2\u01ef\u01f0"+
"\7#\2\2\u01f0\u01f1\7?\2\2\u01f1l\3\2\2\2\u01f2\u01f3\7(\2\2\u01f3n\3"+
"\2\2\2\u01f4\u01f5\7`\2\2\u01f5p\3\2\2\2\u01f6\u01f7\7~\2\2\u01f7r\3\2"+
"\2\2\u01f8\u01f9\7v\2\2\u01f9\u01fa\7q\2\2\u01fat\3\2\2\2\u01fb\u01fc"+
"\7u\2\2\u01fc\u01fd\7v\2\2\u01fd\u01fe\7g\2\2\u01fe\u01ff\7r\2\2\u01ff"+
"v\3\2\2\2\u0200\u0201\7c\2\2\u0201\u0202\7p\2\2\u0202\u0203\7f\2\2\u0203"+
"x\3\2\2\2\u0204\u0205\7q\2\2\u0205\u0206\7t\2\2\u0206z\3\2\2\2\u0207\u0208"+
"\7z\2\2\u0208\u0209\7q\2\2\u0209\u020a\7t\2\2\u020a|\3\2\2\2\u020b\u020c"+
"\7p\2\2\u020c\u020d\7q\2\2\u020d\u020e\7v\2\2\u020e~\3\2\2\2\u020f\u0210"+
"\7*\2\2\u0210\u0080\3\2\2\2\u0211\u0212\7+\2\2\u0212\u0082\3\2\2\2\u0213"+
"\u0214\7c\2\2\u0214\u0215\7u\2\2\u0215\u0084\3\2\2\2\u0216\u0217\7B\2"+
"\2\u0217\u0086\3\2\2\2\u0218\u0219\7t\2\2\u0219\u021a\7g\2\2\u021a\u021b"+
"\7v\2\2\u021b\u021c\7w\2\2\u021c\u021d\7t\2\2\u021d\u021e\7p\2\2\u021e"+
"\u0088\3\2\2\2\u021f\u0220\7d\2\2\u0220\u0221\7t\2\2\u0221\u0222\7g\2"+
"\2\u0222\u0223\7c\2\2\u0223\u0224\7m\2\2\u0224\u008a\3\2\2\2\u0225\u0226"+
"\7e\2\2\u0226\u0227\7q\2\2\u0227\u0228\7p\2\2\u0228\u0229\7v\2\2\u0229"+
"\u022a\7k\2\2\u022a\u022b\7p\2\2\u022b\u022c\7w\2\2\u022c\u022d\7g\2\2"+
"\u022d\u008c\3\2\2\2\u022e\u022f\7\60\2\2\u022f\u008e\3\2\2\2\u0230\u0231"+
"\7C\2\2\u0231\u0090\3\2\2\2\u0232\u0233\7Z\2\2\u0233\u0092\3\2\2\2\u0234"+
"\u0235\7[\2\2\u0235\u0094\3\2\2\2\u0236\u0237\7C\2\2\u0237\u0238\7Z\2"+
"\2\u0238\u0096\3\2\2\2\u0239\u023a\7C\2\2\u023a\u023b\7[\2\2\u023b\u0098"+
"\3\2\2\2\u023c\u023d\7Z\2\2\u023d\u023e\7[\2\2\u023e\u009a\3\2\2\2\u023f"+
"\u0240\7R\2\2\u0240\u0241\7e\2\2\u0241\u009c\3\2\2\2\u0242\u0243\7R\2"+
"\2\u0243\u0244\7|\2\2\u0244\u009e\3\2\2\2\u0245\u0246\7R\2\2\u0246\u0247"+
"\7p\2\2\u0247\u00a0\3\2\2\2\u0248\u0249\7R\2\2\u0249\u024a\7x\2\2\u024a"+
"\u00a2\3\2\2\2\u024b\u024c\7\60\2\2\u024c\u024d\7y\2\2\u024d\u00a4\3\2"+
"\2\2\u024e\u024f\7v\2\2\u024f\u0250\7t\2\2\u0250\u0251\7w\2\2\u0251\u0252"+
"\7g\2\2\u0252\u00a6\3\2\2\2\u0253\u0254\7h\2\2\u0254\u0255\7c\2\2\u0255"+
"\u0256\7n\2\2\u0256\u0257\7u\2\2\u0257\u0258\7g\2\2\u0258\u00a8\3\2\2"+
"\2\u0259\u025a\7\'\2\2\u025a\u025b\7c\2\2\u025b\u025c\7u\2\2\u025c\u025d"+
"\7o\2\2\u025d\u00aa\3\2\2\2\u025e\u025f\7u\2\2\u025f\u0260\7w\2\2\u0260"+
"\u0261\7d\2\2\u0261\u00ac\3\2\2\2\u0262\u0263\7/\2\2\u0263\u0264\7@\2"+
"\2\u0264\u00ae\3\2\2\2\u0265\u0266\7}\2\2\u0266\u00b0\3\2\2\2\u0267\u0268"+
"\7\177\2\2\u0268\u00b2\3\2\2\2\u0269\u026a\7c\2\2\u026a\u026b\7u\2\2\u026b"+
"\u026c\7o\2\2\u026c\u026d\7u\2\2\u026d\u026e\7w\2\2\u026e\u026f\7d\2\2"+
"\u026f\u00b4\3\2\2\2\u0270\u0271\7e\2\2\u0271\u0272\7n\2\2\u0272\u0273"+
"\7q\2\2\u0273\u0274\7d\2\2\u0274\u0275\7d\2\2\u0275\u0276\7g\2\2\u0276"+
"\u0277\7t\2\2\u0277\u0278\7u\2\2\u0278\u00b6\3\2\2\2\u0279\u027a\7u\2"+
"\2\u027a\u027b\7v\2\2\u027b\u027c\7c\2\2\u027c\u027d\7e\2\2\u027d\u027e"+
"\7m\2\2\u027e\u00b8\3\2\2\2\u027f\u0280\7k\2\2\u0280\u0281\7h\2\2\u0281"+
"\u00ba\3\2\2\2\u0282\u0283\7g\2\2\u0283\u0284\7n\2\2\u0284\u0285\7u\2"+
"\2\u0285\u0286\7g\2\2\u0286\u00bc\3\2\2\2\u0287\u0288\7k\2\2\u0288\u0289"+
"\7h\2\2\u0289\u028a\7a\2\2\u028a\u028b\7e\2\2\u028b\u028c\7u\2\2\u028c"+
"\u00be\3\2\2\2\u028d\u028e\7k\2\2\u028e\u028f\7h\2\2\u028f\u0290\7a\2"+
"\2\u0290\u0291\7e\2\2\u0291\u0292\7e\2\2\u0292\u00c0\3\2\2\2\u0293\u0294"+
"\7k\2\2\u0294\u0295\7h\2\2\u0295\u0296\7a\2\2\u0296\u0297\7g\2\2\u0297"+
"\u0298\7s\2\2\u0298\u00c2\3\2\2\2\u0299\u029a\7k\2\2\u029a\u029b\7h\2"+
"\2\u029b\u029c\7a\2\2\u029c\u029d\7|\2\2\u029d\u00c4\3\2\2\2\u029e\u029f"+
"\7k\2\2\u029f\u02a0\7h\2\2\u02a0\u02a1\7a\2\2\u02a1\u02a2\7p\2\2\u02a2"+
"\u02a3\7g\2\2\u02a3\u00c6\3\2\2\2\u02a4\u02a5\7k\2\2\u02a5\u02a6\7h\2"+
"\2\u02a6\u02a7\7a\2\2\u02a7\u02a8\7p\2\2\u02a8\u02a9\7|\2\2\u02a9\u00c8"+
"\3\2\2\2\u02aa\u02ab\7k\2\2\u02ab\u02ac\7h\2\2\u02ac\u02ad\7a\2\2\u02ad"+
"\u02ae\7r\2\2\u02ae\u02af\7n\2\2\u02af\u00ca\3\2\2\2\u02b0\u02b1\7k\2"+
"\2\u02b1\u02b2\7h\2\2\u02b2\u02b3\7a\2\2\u02b3\u02b4\7r\2\2\u02b4\u02b5"+
"\7q\2\2\u02b5\u02b6\7u\2\2\u02b6\u00cc\3\2\2\2\u02b7\u02b8\7k\2\2\u02b8"+
"\u02b9\7h\2\2\u02b9\u02ba\7a\2\2\u02ba\u02bb\7o\2\2\u02bb\u02bc\7k\2\2"+
"\u02bc\u00ce\3\2\2\2\u02bd\u02be\7k\2\2\u02be\u02bf\7h\2\2\u02bf\u02c0"+
"\7a\2\2\u02c0\u02c1\7p\2\2\u02c1\u02c2\7g\2\2\u02c2\u02c3\7i\2\2\u02c3"+
"\u00d0\3\2\2\2\u02c4\u02c5\7k\2\2\u02c5\u02c6\7h\2\2\u02c6\u02c7\7a\2"+
"\2\u02c7\u02c8\7x\2\2\u02c8\u02c9\7u\2\2\u02c9\u00d2\3\2\2\2\u02ca\u02cb"+
"\7k\2\2\u02cb\u02cc\7h\2\2\u02cc\u02cd\7a\2\2\u02cd\u02ce\7x\2\2\u02ce"+
"\u02cf\7e\2\2\u02cf\u00d4\3\2\2\2\u02d0\u02d1\7h\2\2\u02d1\u02d2\7q\2"+
"\2\u02d2\u02d3\7t\2\2\u02d3\u00d6\3\2\2\2\u02d4\u02d5\7k\2\2\u02d5\u02d6"+
"\7p\2\2\u02d6\u00d8\3\2\2\2\u02d7\u02d8\7y\2\2\u02d8\u02d9\7j\2\2\u02d9"+
"\u02da\7k\2\2\u02da\u02db\7n\2\2\u02db\u02dc\7g\2\2\u02dc\u00da\3\2\2"+
"\2\u02dd\u02de\7t\2\2\u02de\u02df\7g\2\2\u02df\u02e0\7r\2\2\u02e0\u02e1"+
"\7g\2\2\u02e1\u02e2\7c\2\2\u02e2\u02e3\7v\2\2\u02e3\u00dc\3\2\2\2\u02e4"+
"\u02e5\7w\2\2\u02e5\u02e6\7p\2\2\u02e6\u02e7\7v\2\2\u02e7\u02e8\7k\2\2"+
"\u02e8\u02e9\7n\2\2\u02e9\u00de\3\2\2\2\u02ea\u02ee\t\2\2\2\u02eb\u02ed"+
"\t\3\2\2\u02ec\u02eb\3\2\2\2\u02ed\u02f0\3\2\2\2\u02ee\u02ec\3\2\2\2\u02ee"+
"\u02ef\3\2\2\2\u02ef\u02f1\3\2\2\2\u02f0\u02ee\3\2\2\2\u02f1\u02f2\5\u00e1"+
"q\2\u02f2\u02f3\3\2\2\2\u02f3\u02f4\bp\2\2\u02f4\u00e0\3\2\2\2\u02f5\u02f9"+
"\7=\2\2\u02f6\u02f8\n\2\2\2\u02f7\u02f6\3\2\2\2\u02f8\u02fb\3\2\2\2\u02f9"+
"\u02f7\3\2\2\2\u02f9\u02fa\3\2\2\2\u02fa\u02fc\3\2\2\2\u02fb\u02f9\3\2"+
"\2\2\u02fc\u02fd\bq\2\2\u02fd\u00e2\3\2\2\2\u02fe\u02ff\t\3\2\2\u02ff"+
"\u0300\3\2\2\2\u0300\u0301\br\3\2\u0301\u00e4\3\2\2\2\u0302\u0304\t\2"+
"\2\2\u0303\u0302\3\2\2\2\u0304\u0305\3\2\2\2\u0305\u0303\3\2\2\2\u0305"+
"\u0306\3\2\2\2\u0306\u00e6\3\2\2\2\u0307\u030b\t\4\2\2\u0308\u030a\t\5"+
"\2\2\u0309\u0308\3\2\2\2\u030a\u030d\3\2\2\2\u030b\u0309\3\2\2\2\u030b"+
"\u030c\3\2\2\2\u030c\u00e8\3\2\2\2\u030d\u030b\3\2\2\2\u030e\u0316\4\62"+
";\2\u030f\u0311\4\63;\2\u0310\u0312\4\62;\2\u0311\u0310\3\2\2\2\u0312"+
"\u0313\3\2\2\2\u0313\u0311\3\2\2\2\u0313\u0314\3\2\2\2\u0314\u0316\3\2"+
"\2\2\u0315\u030e\3\2\2\2\u0315\u030f\3\2\2\2\u0316\u00ea\3\2\2\2\u0317"+
"\u0319\7&\2\2\u0318\u031a\t\6\2\2\u0319\u0318\3\2\2\2\u031a\u031b\3\2"+
"\2\2\u031b\u0319\3\2\2\2\u031b\u031c\3\2\2\2\u031c\u00ec\3\2\2\2\u031d"+
"\u031f\7\'\2\2\u031e\u0320\4\62\63\2\u031f\u031e\3\2\2\2\u0320\u0321\3"+
"\2\2\2\u0321\u031f\3\2\2\2\u0321\u0322\3\2\2\2\u0322\u00ee\3\2\2\2\u0323"+
"\u0329\5\u00f1y\2\u0324\u0326\t\7\2\2\u0325\u0327\t\b\2\2\u0326\u0325"+
"\3\2\2\2\u0326\u0327\3\2\2\2\u0327\u0328\3\2\2\2\u0328\u032a\5\u00f1y"+
"\2\u0329\u0324\3\2\2\2\u0329\u032a\3\2\2\2\u032a\u00f0\3\2\2\2\u032b\u032d"+
"\4\62;\2\u032c\u032b\3\2\2\2\u032d\u032e\3\2\2\2\u032e\u032c\3\2\2\2\u032e"+
"\u032f\3\2\2\2\u032f\u0336\3\2\2\2\u0330\u0332\7\60\2\2\u0331\u0333\4"+
"\62;\2\u0332\u0331\3\2\2\2\u0333\u0334\3\2\2\2\u0334\u0332\3\2\2\2\u0334"+
"\u0335\3\2\2\2\u0335\u0337\3\2\2\2\u0336\u0330\3\2\2\2\u0336\u0337\3\2"+
"\2\2\u0337\u00f2\3\2\2\2\u0338\u0339\7^\2\2\u0339\u033d\13\2\2\2\u033a"+
"\u033b\7^\2\2\u033b\u033d\5\u00e5s\2\u033c\u0338\3\2\2\2\u033c\u033a\3"+
"\2\2\2\u033d\u00f4\3\2\2\2\u033e\u0343\7$\2\2\u033f\u0342\5\u00f3z\2\u0340"+
"\u0342\n\t\2\2\u0341\u033f\3\2\2\2\u0341\u0340\3\2\2\2\u0342\u0345\3\2"+
"\2\2\u0343\u0341\3\2\2\2\u0343\u0344\3\2\2\2\u0344\u0346\3\2\2\2\u0345"+
"\u0343\3\2\2\2\u0346\u0347\7$\2\2\u0347\u0348\b{\4\2\u0348\u00f6\3\2\2"+
"\2\u0349\u034a\7}\2\2\u034a\u034b\7}\2\2\u034b\u034d\3\2\2\2\u034c\u034e"+
"\13\2\2\2\u034d\u034c\3\2\2\2\u034e\u034f\3\2\2\2\u034f\u0350\3\2\2\2"+
"\u034f\u034d\3\2\2\2\u0350\u0351\3\2\2\2\u0351\u0352\7\177\2\2\u0352\u0353"+
"\7\177\2\2\u0353\u0354\3\2\2\2\u0354\u0355\b|\5\2\u0355\u00f8\3\2\2\2"+
"\u0356\u0359\7)\2\2\u0357\u035a\5\u00f3z\2\u0358\u035a\n\t\2\2\u0359\u0357"+
"\3\2\2\2\u0359\u0358\3\2\2\2\u035a\u035b\3\2\2\2\u035b\u035c\7)\2\2\u035c"+
"\u035d\b}\6\2\u035d\u00fa\3\2\2\2\u035e\u035f\7B\2\2\u035f\u0360\7|\2"+
"\2\u0360\u0361\7r\2\2\u0361\u00fc\3\2\2\2\26\2\u02ee\u02f9\u0305\u030b"+
"\u0313\u0315\u0319\u031b\u0321\u0326\u0329\u032e\u0334\u0336\u033c\u0341"+
"\u0343\u034f\u0359\7\2\3\2\b\2\2\3{\2\3|\3\3}\4";
"\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3"+
"\24\3\24\3\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3"+
"\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3"+
"\33\3\33\3\34\3\34\3\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\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\60\3\60\3\61\3\61\3\62\3\62\3\62\3\63\3\63\3\63\3\64\3\64\3\64"+
"\3\65\3\65\3\65\3\66\3\66\3\67\3\67\38\38\38\39\39\39\39\39\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\3"+
"B\3B\3B\3B\3B\3C\3C\3C\3C\3C\3C\3D\3D\3D\3D\3D\3D\3D\3D\3D\3E\3E\3F\3"+
"F\3G\3G\3H\3H\3I\3I\3I\3J\3J\3J\3K\3K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3"+
"O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3Q\3Q\3R\3R\3R\3R\3R\3R\3S\3S\3S\3S\3S\3T\3"+
"T\3T\3T\3U\3U\3U\3V\3V\3W\3W\3X\3X\3X\3X\3X\3X\3X\3Y\3Y\3Y\3Y\3Y\3Y\3"+
"Y\3Y\3Y\3Z\3Z\3Z\3Z\3Z\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`\3a\3a\3a\3a\3a"+
"\3a\3b\3b\3b\3b\3b\3b\3c\3c\3c\3c\3c\3c\3d\3d\3d\3d\3d\3d\3d\3e\3e\3e"+
"\3e\3e\3e\3f\3f\3f\3f\3f\3f\3f\3g\3g\3g\3g\3g\3g\3h\3h\3h\3h\3h\3h\3i"+
"\3i\3i\3i\3j\3j\3j\3k\3k\3k\3k\3k\3k\3l\3l\3l\3l\3l\3l\3l\3m\3m\3m\3m"+
"\3m\3m\3n\3n\7n\u02e4\nn\fn\16n\u02e7\13n\3n\3n\3n\3n\3o\3o\7o\u02ef\n"+
"o\fo\16o\u02f2\13o\3o\3o\3p\3p\3p\3p\3q\6q\u02fb\nq\rq\16q\u02fc\3r\3"+
"r\7r\u0301\nr\fr\16r\u0304\13r\3s\3s\3s\6s\u0309\ns\rs\16s\u030a\5s\u030d"+
"\ns\3t\3t\6t\u0311\nt\rt\16t\u0312\3u\3u\6u\u0317\nu\ru\16u\u0318\3v\3"+
"v\3w\3w\3w\5w\u0320\nw\3w\5w\u0323\nw\3x\6x\u0326\nx\rx\16x\u0327\3x\3"+
"x\6x\u032c\nx\rx\16x\u032d\5x\u0330\nx\3y\3y\3y\3y\5y\u0336\ny\3z\3z\3"+
"z\7z\u033b\nz\fz\16z\u033e\13z\3z\3z\3z\3{\3{\3{\3{\6{\u0347\n{\r{\16"+
"{\u0348\3{\3{\3{\3{\3{\3|\3|\3|\5|\u0353\n|\3|\3|\3|\3}\3}\3}\3}\3~\3"+
"~\3~\3\u0348\2\177\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r"+
"\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33"+
"\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63"+
"e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089"+
"F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d"+
"P\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00afY\u00b1"+
"Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3c\u00c5"+
"d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3k\u00d5l\u00d7m\u00d9"+
"n\u00dbo\u00ddp\u00dfq\u00e1r\u00e3s\u00e5t\u00e7u\u00e9v\u00ebw\u00ed"+
"x\u00ef\2\u00f1\2\u00f3y\u00f5z\u00f7{\u00f9|\u00fb}\3\2\n\4\2\f\f\17"+
"\17\4\2\13\13\"\"\5\2C\\aac|\6\2\62;C\\aac|\5\2\62;CHch\4\2GGgg\4\2--"+
"//\6\2\f\f\16\17$$^^\2\u036d\2\3\3\2\2\2\2\5\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\3\2\2\2\2\u00ed"+
"\3\2\2\2\2\u00f3\3\2\2\2\2\u00f5\3\2\2\2\2\u00f7\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\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\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\31\u0157\3\2"+
"\2\2\33\u0162\3\2\2\2\35\u016a\3\2\2\2\37\u016c\3\2\2\2!\u016e\3\2\2\2"+
"#\u0174\3\2\2\2%\u017a\3\2\2\2\'\u017f\3\2\2\2)\u0185\3\2\2\2+\u018a\3"+
"\2\2\2-\u0190\3\2\2\2/\u0194\3\2\2\2\61\u019a\3\2\2\2\63\u019c\3\2\2\2"+
"\65\u019e\3\2\2\2\67\u01a1\3\2\2\29\u01a4\3\2\2\2;\u01a7\3\2\2\2=\u01aa"+
"\3\2\2\2?\u01ae\3\2\2\2A\u01b1\3\2\2\2C\u01b4\3\2\2\2E\u01b7\3\2\2\2G"+
"\u01ba\3\2\2\2I\u01be\3\2\2\2K\u01c2\3\2\2\2M\u01c5\3\2\2\2O\u01c8\3\2"+
"\2\2Q\u01ca\3\2\2\2S\u01cc\3\2\2\2U\u01cf\3\2\2\2W\u01d1\3\2\2\2Y\u01d3"+
"\3\2\2\2[\u01d5\3\2\2\2]\u01d8\3\2\2\2_\u01db\3\2\2\2a\u01dd\3\2\2\2c"+
"\u01df\3\2\2\2e\u01e2\3\2\2\2g\u01e5\3\2\2\2i\u01e8\3\2\2\2k\u01eb\3\2"+
"\2\2m\u01ed\3\2\2\2o\u01ef\3\2\2\2q\u01f2\3\2\2\2s\u01f7\3\2\2\2u\u01fb"+
"\3\2\2\2w\u01fe\3\2\2\2y\u0202\3\2\2\2{\u0206\3\2\2\2}\u0208\3\2\2\2\177"+
"\u020a\3\2\2\2\u0081\u020d\3\2\2\2\u0083\u020f\3\2\2\2\u0085\u0216\3\2"+
"\2\2\u0087\u021c\3\2\2\2\u0089\u0225\3\2\2\2\u008b\u0227\3\2\2\2\u008d"+
"\u0229\3\2\2\2\u008f\u022b\3\2\2\2\u0091\u022d\3\2\2\2\u0093\u0230\3\2"+
"\2\2\u0095\u0233\3\2\2\2\u0097\u0236\3\2\2\2\u0099\u0239\3\2\2\2\u009b"+
"\u023c\3\2\2\2\u009d\u023f\3\2\2\2\u009f\u0242\3\2\2\2\u00a1\u0245\3\2"+
"\2\2\u00a3\u024a\3\2\2\2\u00a5\u0250\3\2\2\2\u00a7\u0255\3\2\2\2\u00a9"+
"\u0259\3\2\2\2\u00ab\u025c\3\2\2\2\u00ad\u025e\3\2\2\2\u00af\u0260\3\2"+
"\2\2\u00b1\u0267\3\2\2\2\u00b3\u0270\3\2\2\2\u00b5\u0276\3\2\2\2\u00b7"+
"\u0279\3\2\2\2\u00b9\u027e\3\2\2\2\u00bb\u0284\3\2\2\2\u00bd\u028a\3\2"+
"\2\2\u00bf\u0290\3\2\2\2\u00c1\u0295\3\2\2\2\u00c3\u029b\3\2\2\2\u00c5"+
"\u02a1\3\2\2\2\u00c7\u02a7\3\2\2\2\u00c9\u02ae\3\2\2\2\u00cb\u02b4\3\2"+
"\2\2\u00cd\u02bb\3\2\2\2\u00cf\u02c1\3\2\2\2\u00d1\u02c7\3\2\2\2\u00d3"+
"\u02cb\3\2\2\2\u00d5\u02ce\3\2\2\2\u00d7\u02d4\3\2\2\2\u00d9\u02db\3\2"+
"\2\2\u00db\u02e1\3\2\2\2\u00dd\u02ec\3\2\2\2\u00df\u02f5\3\2\2\2\u00e1"+
"\u02fa\3\2\2\2\u00e3\u02fe\3\2\2\2\u00e5\u030c\3\2\2\2\u00e7\u030e\3\2"+
"\2\2\u00e9\u0314\3\2\2\2\u00eb\u031a\3\2\2\2\u00ed\u031c\3\2\2\2\u00ef"+
"\u0325\3\2\2\2\u00f1\u0335\3\2\2\2\u00f3\u0337\3\2\2\2\u00f5\u0342\3\2"+
"\2\2\u00f7\u034f\3\2\2\2\u00f9\u0357\3\2\2\2\u00fb\u035b\3\2\2\2\u00fd"+
"\u00fe\7\u0080\2\2\u00fe\4\3\2\2\2\u00ff\u0100\7<\2\2\u0100\6\3\2\2\2"+
"\u0101\u0102\7i\2\2\u0102\u0103\7q\2\2\u0103\u0104\7v\2\2\u0104\u0105"+
"\7q\2\2\u0105\b\3\2\2\2\u0106\u0107\7\'\2\2\u0107\u0108\7q\2\2\u0108\u0109"+
"\7w\2\2\u0109\u010a\7v\2\2\u010a\u010b\7r\2\2\u010b\u010c\7w\2\2\u010c"+
"\u010d\7v\2\2\u010d\n\3\2\2\2\u010e\u010f\7\'\2\2\u010f\u0110\7n\2\2\u0110"+
"\u0111\7c\2\2\u0111\u0112\7w\2\2\u0112\u0113\7p\2\2\u0113\u0114\7e\2\2"+
"\u0114\u0115\7j\2\2\u0115\u0116\7g\2\2\u0116\u0117\7t\2\2\u0117\f\3\2"+
"\2\2\u0118\u0119\7\'\2\2\u0119\u011a\7|\2\2\u011a\u011b\7g\2\2\u011b\u011c"+
"\7t\2\2\u011c\u011d\7q\2\2\u011d\u011e\7r\2\2\u011e\u011f\7c\2\2\u011f"+
"\u0120\7i\2\2\u0120\u0121\7g\2\2\u0121\16\3\2\2\2\u0122\u0123\7\'\2\2"+
"\u0123\u0124\7|\2\2\u0124\u0125\7r\2\2\u0125\u0126\7t\2\2\u0126\u0127"+
"\7g\2\2\u0127\u0128\7u\2\2\u0128\u0129\7g\2\2\u0129\u012a\7t\2\2\u012a"+
"\u012b\7x\2\2\u012b\u012c\7g\2\2\u012c\u012d\7f\2\2\u012d\20\3\2\2\2\u012e"+
"\u012f\7\'\2\2\u012f\u0130\7c\2\2\u0130\u0131\7f\2\2\u0131\u0132\7f\2"+
"\2\u0132\u0133\7t\2\2\u0133\u0134\7g\2\2\u0134\u0135\7u\2\2\u0135\u0136"+
"\7u\2\2\u0136\22\3\2\2\2\u0137\u0138\7\'\2\2\u0138\u0139\7k\2\2\u0139"+
"\u013a\7o\2\2\u013a\u013b\7r\2\2\u013b\u013c\7q\2\2\u013c\u013d\7t\2\2"+
"\u013d\u013e\7v\2\2\u013e\24\3\2\2\2\u013f\u0140\7\'\2\2\u0140\u0141\7"+
"d\2\2\u0141\u0142\7t\2\2\u0142\u0143\7g\2\2\u0143\u0144\7c\2\2\u0144\u0145"+
"\7m\2\2\u0145\u0146\7r\2\2\u0146\u0147\7q\2\2\u0147\u0148\7k\2\2\u0148"+
"\u0149\7p\2\2\u0149\u014a\7v\2\2\u014a\26\3\2\2\2\u014b\u014c\7\'\2\2"+
"\u014c\u014d\7c\2\2\u014d\u014e\7u\2\2\u014e\u014f\7o\2\2\u014f\u0150"+
"\7k\2\2\u0150\u0151\7p\2\2\u0151\u0152\7e\2\2\u0152\u0153\7n\2\2\u0153"+
"\u0154\7w\2\2\u0154\u0155\7f\2\2\u0155\u0156\7g\2\2\u0156\30\3\2\2\2\u0157"+
"\u0158\7\'\2\2\u0158\u0159\7c\2\2\u0159\u015a\7u\2\2\u015a\u015b\7o\2"+
"\2\u015b\u015c\7d\2\2\u015c\u015d\7k\2\2\u015d\u015e\7p\2\2\u015e\u015f"+
"\7c\2\2\u015f\u0160\7t\2\2\u0160\u0161\7{\2\2\u0161\32\3\2\2\2\u0162\u0163"+
"\7\'\2\2\u0163\u0164\7q\2\2\u0164\u0165\7r\2\2\u0165\u0166\7v\2\2\u0166"+
"\u0167\7k\2\2\u0167\u0168\7q\2\2\u0168\u0169\7p\2\2\u0169\34\3\2\2\2\u016a"+
"\u016b\7.\2\2\u016b\36\3\2\2\2\u016c\u016d\7?\2\2\u016d \3\2\2\2\u016e"+
"\u016f\7e\2\2\u016f\u0170\7q\2\2\u0170\u0171\7p\2\2\u0171\u0172\7u\2\2"+
"\u0172\u0173\7v\2\2\u0173\"\3\2\2\2\u0174\u0175\7w\2\2\u0175\u0176\7d"+
"\2\2\u0176\u0177\7{\2\2\u0177\u0178\7v\2\2\u0178\u0179\7g\2\2\u0179$\3"+
"\2\2\2\u017a\u017b\7d\2\2\u017b\u017c\7{\2\2\u017c\u017d\7v\2\2\u017d"+
"\u017e\7g\2\2\u017e&\3\2\2\2\u017f\u0180\7w\2\2\u0180\u0181\7y\2\2\u0181"+
"\u0182\7q\2\2\u0182\u0183\7t\2\2\u0183\u0184\7f\2\2\u0184(\3\2\2\2\u0185"+
"\u0186\7y\2\2\u0186\u0187\7q\2\2\u0187\u0188\7t\2\2\u0188\u0189\7f\2\2"+
"\u0189*\3\2\2\2\u018a\u018b\7h\2\2\u018b\u018c\7n\2\2\u018c\u018d\7q\2"+
"\2\u018d\u018e\7c\2\2\u018e\u018f\7v\2\2\u018f,\3\2\2\2\u0190\u0191\7"+
"u\2\2\u0191\u0192\7v\2\2\u0192\u0193\7t\2\2\u0193.\3\2\2\2\u0194\u0195"+
"\7u\2\2\u0195\u0196\7v\2\2\u0196\u0197\7t\2\2\u0197\u0198\7a\2\2\u0198"+
"\u0199\7u\2\2\u0199\60\3\2\2\2\u019a\u019b\7]\2\2\u019b\62\3\2\2\2\u019c"+
"\u019d\7_\2\2\u019d\64\3\2\2\2\u019e\u019f\7-\2\2\u019f\u01a0\7?\2\2\u01a0"+
"\66\3\2\2\2\u01a1\u01a2\7/\2\2\u01a2\u01a3\7?\2\2\u01a38\3\2\2\2\u01a4"+
"\u01a5\7\61\2\2\u01a5\u01a6\7?\2\2\u01a6:\3\2\2\2\u01a7\u01a8\7,\2\2\u01a8"+
"\u01a9\7?\2\2\u01a9<\3\2\2\2\u01aa\u01ab\7,\2\2\u01ab\u01ac\7,\2\2\u01ac"+
"\u01ad\7?\2\2\u01ad>\3\2\2\2\u01ae\u01af\7(\2\2\u01af\u01b0\7?\2\2\u01b0"+
"@\3\2\2\2\u01b1\u01b2\7~\2\2\u01b2\u01b3\7?\2\2\u01b3B\3\2\2\2\u01b4\u01b5"+
"\7`\2\2\u01b5\u01b6\7?\2\2\u01b6D\3\2\2\2\u01b7\u01b8\7\'\2\2\u01b8\u01b9"+
"\7?\2\2\u01b9F\3\2\2\2\u01ba\u01bb\7>\2\2\u01bb\u01bc\7>\2\2\u01bc\u01bd"+
"\7?\2\2\u01bdH\3\2\2\2\u01be\u01bf\7@\2\2\u01bf\u01c0\7@\2\2\u01c0\u01c1"+
"\7?\2\2\u01c1J\3\2\2\2\u01c2\u01c3\7-\2\2\u01c3\u01c4\7-\2\2\u01c4L\3"+
"\2\2\2\u01c5\u01c6\7/\2\2\u01c6\u01c7\7/\2\2\u01c7N\3\2\2\2\u01c8\u01c9"+
"\7-\2\2\u01c9P\3\2\2\2\u01ca\u01cb\7/\2\2\u01cbR\3\2\2\2\u01cc\u01cd\7"+
",\2\2\u01cd\u01ce\7,\2\2\u01ceT\3\2\2\2\u01cf\u01d0\7,\2\2\u01d0V\3\2"+
"\2\2\u01d1\u01d2\7\61\2\2\u01d2X\3\2\2\2\u01d3\u01d4\7\'\2\2\u01d4Z\3"+
"\2\2\2\u01d5\u01d6\7>\2\2\u01d6\u01d7\7>\2\2\u01d7\\\3\2\2\2\u01d8\u01d9"+
"\7@\2\2\u01d9\u01da\7@\2\2\u01da^\3\2\2\2\u01db\u01dc\7>\2\2\u01dc`\3"+
"\2\2\2\u01dd\u01de\7@\2\2\u01deb\3\2\2\2\u01df\u01e0\7>\2\2\u01e0\u01e1"+
"\7?\2\2\u01e1d\3\2\2\2\u01e2\u01e3\7@\2\2\u01e3\u01e4\7?\2\2\u01e4f\3"+
"\2\2\2\u01e5\u01e6\7?\2\2\u01e6\u01e7\7?\2\2\u01e7h\3\2\2\2\u01e8\u01e9"+
"\7#\2\2\u01e9\u01ea\7?\2\2\u01eaj\3\2\2\2\u01eb\u01ec\7`\2\2\u01ecl\3"+
"\2\2\2\u01ed\u01ee\7~\2\2\u01een\3\2\2\2\u01ef\u01f0\7v\2\2\u01f0\u01f1"+
"\7q\2\2\u01f1p\3\2\2\2\u01f2\u01f3\7u\2\2\u01f3\u01f4\7v\2\2\u01f4\u01f5"+
"\7g\2\2\u01f5\u01f6\7r\2\2\u01f6r\3\2\2\2\u01f7\u01f8\7c\2\2\u01f8\u01f9"+
"\7p\2\2\u01f9\u01fa\7f\2\2\u01fat\3\2\2\2\u01fb\u01fc\7q\2\2\u01fc\u01fd"+
"\7t\2\2\u01fdv\3\2\2\2\u01fe\u01ff\7z\2\2\u01ff\u0200\7q\2\2\u0200\u0201"+
"\7t\2\2\u0201x\3\2\2\2\u0202\u0203\7p\2\2\u0203\u0204\7q\2\2\u0204\u0205"+
"\7v\2\2\u0205z\3\2\2\2\u0206\u0207\7*\2\2\u0207|\3\2\2\2\u0208\u0209\7"+
"+\2\2\u0209~\3\2\2\2\u020a\u020b\7c\2\2\u020b\u020c\7u\2\2\u020c\u0080"+
"\3\2\2\2\u020d\u020e\7B\2\2\u020e\u0082\3\2\2\2\u020f\u0210\7t\2\2\u0210"+
"\u0211\7g\2\2\u0211\u0212\7v\2\2\u0212\u0213\7w\2\2\u0213\u0214\7t\2\2"+
"\u0214\u0215\7p\2\2\u0215\u0084\3\2\2\2\u0216\u0217\7d\2\2\u0217\u0218"+
"\7t\2\2\u0218\u0219\7g\2\2\u0219\u021a\7c\2\2\u021a\u021b\7m\2\2\u021b"+
"\u0086\3\2\2\2\u021c\u021d\7e\2\2\u021d\u021e\7q\2\2\u021e\u021f\7p\2"+
"\2\u021f\u0220\7v\2\2\u0220\u0221\7k\2\2\u0221\u0222\7p\2\2\u0222\u0223"+
"\7w\2\2\u0223\u0224\7g\2\2\u0224\u0088\3\2\2\2\u0225\u0226\7\60\2\2\u0226"+
"\u008a\3\2\2\2\u0227\u0228\7C\2\2\u0228\u008c\3\2\2\2\u0229\u022a\7Z\2"+
"\2\u022a\u008e\3\2\2\2\u022b\u022c\7[\2\2\u022c\u0090\3\2\2\2\u022d\u022e"+
"\7C\2\2\u022e\u022f\7Z\2\2\u022f\u0092\3\2\2\2\u0230\u0231\7C\2\2\u0231"+
"\u0232\7[\2\2\u0232\u0094\3\2\2\2\u0233\u0234\7Z\2\2\u0234\u0235\7[\2"+
"\2\u0235\u0096\3\2\2\2\u0236\u0237\7R\2\2\u0237\u0238\7e\2\2\u0238\u0098"+
"\3\2\2\2\u0239\u023a\7R\2\2\u023a\u023b\7|\2\2\u023b\u009a\3\2\2\2\u023c"+
"\u023d\7R\2\2\u023d\u023e\7p\2\2\u023e\u009c\3\2\2\2\u023f\u0240\7R\2"+
"\2\u0240\u0241\7x\2\2\u0241\u009e\3\2\2\2\u0242\u0243\7\60\2\2\u0243\u0244"+
"\7y\2\2\u0244\u00a0\3\2\2\2\u0245\u0246\7v\2\2\u0246\u0247\7t\2\2\u0247"+
"\u0248\7w\2\2\u0248\u0249\7g\2\2\u0249\u00a2\3\2\2\2\u024a\u024b\7h\2"+
"\2\u024b\u024c\7c\2\2\u024c\u024d\7n\2\2\u024d\u024e\7u\2\2\u024e\u024f"+
"\7g\2\2\u024f\u00a4\3\2\2\2\u0250\u0251\7\'\2\2\u0251\u0252\7c\2\2\u0252"+
"\u0253\7u\2\2\u0253\u0254\7o\2\2\u0254\u00a6\3\2\2\2\u0255\u0256\7u\2"+
"\2\u0256\u0257\7w\2\2\u0257\u0258\7d\2\2\u0258\u00a8\3\2\2\2\u0259\u025a"+
"\7/\2\2\u025a\u025b\7@\2\2\u025b\u00aa\3\2\2\2\u025c\u025d\7}\2\2\u025d"+
"\u00ac\3\2\2\2\u025e\u025f\7\177\2\2\u025f\u00ae\3\2\2\2\u0260\u0261\7"+
"c\2\2\u0261\u0262\7u\2\2\u0262\u0263\7o\2\2\u0263\u0264\7u\2\2\u0264\u0265"+
"\7w\2\2\u0265\u0266\7d\2\2\u0266\u00b0\3\2\2\2\u0267\u0268\7e\2\2\u0268"+
"\u0269\7n\2\2\u0269\u026a\7q\2\2\u026a\u026b\7d\2\2\u026b\u026c\7d\2\2"+
"\u026c\u026d\7g\2\2\u026d\u026e\7t\2\2\u026e\u026f\7u\2\2\u026f\u00b2"+
"\3\2\2\2\u0270\u0271\7u\2\2\u0271\u0272\7v\2\2\u0272\u0273\7c\2\2\u0273"+
"\u0274\7e\2\2\u0274\u0275\7m\2\2\u0275\u00b4\3\2\2\2\u0276\u0277\7k\2"+
"\2\u0277\u0278\7h\2\2\u0278\u00b6\3\2\2\2\u0279\u027a\7g\2\2\u027a\u027b"+
"\7n\2\2\u027b\u027c\7u\2\2\u027c\u027d\7g\2\2\u027d\u00b8\3\2\2\2\u027e"+
"\u027f\7k\2\2\u027f\u0280\7h\2\2\u0280\u0281\7a\2\2\u0281\u0282\7e\2\2"+
"\u0282\u0283\7u\2\2\u0283\u00ba\3\2\2\2\u0284\u0285\7k\2\2\u0285\u0286"+
"\7h\2\2\u0286\u0287\7a\2\2\u0287\u0288\7e\2\2\u0288\u0289\7e\2\2\u0289"+
"\u00bc\3\2\2\2\u028a\u028b\7k\2\2\u028b\u028c\7h\2\2\u028c\u028d\7a\2"+
"\2\u028d\u028e\7g\2\2\u028e\u028f\7s\2\2\u028f\u00be\3\2\2\2\u0290\u0291"+
"\7k\2\2\u0291\u0292\7h\2\2\u0292\u0293\7a\2\2\u0293\u0294\7|\2\2\u0294"+
"\u00c0\3\2\2\2\u0295\u0296\7k\2\2\u0296\u0297\7h\2\2\u0297\u0298\7a\2"+
"\2\u0298\u0299\7p\2\2\u0299\u029a\7g\2\2\u029a\u00c2\3\2\2\2\u029b\u029c"+
"\7k\2\2\u029c\u029d\7h\2\2\u029d\u029e\7a\2\2\u029e\u029f\7p\2\2\u029f"+
"\u02a0\7|\2\2\u02a0\u00c4\3\2\2\2\u02a1\u02a2\7k\2\2\u02a2\u02a3\7h\2"+
"\2\u02a3\u02a4\7a\2\2\u02a4\u02a5\7r\2\2\u02a5\u02a6\7n\2\2\u02a6\u00c6"+
"\3\2\2\2\u02a7\u02a8\7k\2\2\u02a8\u02a9\7h\2\2\u02a9\u02aa\7a\2\2\u02aa"+
"\u02ab\7r\2\2\u02ab\u02ac\7q\2\2\u02ac\u02ad\7u\2\2\u02ad\u00c8\3\2\2"+
"\2\u02ae\u02af\7k\2\2\u02af\u02b0\7h\2\2\u02b0\u02b1\7a\2\2\u02b1\u02b2"+
"\7o\2\2\u02b2\u02b3\7k\2\2\u02b3\u00ca\3\2\2\2\u02b4\u02b5\7k\2\2\u02b5"+
"\u02b6\7h\2\2\u02b6\u02b7\7a\2\2\u02b7\u02b8\7p\2\2\u02b8\u02b9\7g\2\2"+
"\u02b9\u02ba\7i\2\2\u02ba\u00cc\3\2\2\2\u02bb\u02bc\7k\2\2\u02bc\u02bd"+
"\7h\2\2\u02bd\u02be\7a\2\2\u02be\u02bf\7x\2\2\u02bf\u02c0\7u\2\2\u02c0"+
"\u00ce\3\2\2\2\u02c1\u02c2\7k\2\2\u02c2\u02c3\7h\2\2\u02c3\u02c4\7a\2"+
"\2\u02c4\u02c5\7x\2\2\u02c5\u02c6\7e\2\2\u02c6\u00d0\3\2\2\2\u02c7\u02c8"+
"\7h\2\2\u02c8\u02c9\7q\2\2\u02c9\u02ca\7t\2\2\u02ca\u00d2\3\2\2\2\u02cb"+
"\u02cc\7k\2\2\u02cc\u02cd\7p\2\2\u02cd\u00d4\3\2\2\2\u02ce\u02cf\7y\2"+
"\2\u02cf\u02d0\7j\2\2\u02d0\u02d1\7k\2\2\u02d1\u02d2\7n\2\2\u02d2\u02d3"+
"\7g\2\2\u02d3\u00d6\3\2\2\2\u02d4\u02d5\7t\2\2\u02d5\u02d6\7g\2\2\u02d6"+
"\u02d7\7r\2\2\u02d7\u02d8\7g\2\2\u02d8\u02d9\7c\2\2\u02d9\u02da\7v\2\2"+
"\u02da\u00d8\3\2\2\2\u02db\u02dc\7w\2\2\u02dc\u02dd\7p\2\2\u02dd\u02de"+
"\7v\2\2\u02de\u02df\7k\2\2\u02df\u02e0\7n\2\2\u02e0\u00da\3\2\2\2\u02e1"+
"\u02e5\t\2\2\2\u02e2\u02e4\t\3\2\2\u02e3\u02e2\3\2\2\2\u02e4\u02e7\3\2"+
"\2\2\u02e5\u02e3\3\2\2\2\u02e5\u02e6\3\2\2\2\u02e6\u02e8\3\2\2\2\u02e7"+
"\u02e5\3\2\2\2\u02e8\u02e9\5\u00ddo\2\u02e9\u02ea\3\2\2\2\u02ea\u02eb"+
"\bn\2\2\u02eb\u00dc\3\2\2\2\u02ec\u02f0\7=\2\2\u02ed\u02ef\n\2\2\2\u02ee"+
"\u02ed\3\2\2\2\u02ef\u02f2\3\2\2\2\u02f0\u02ee\3\2\2\2\u02f0\u02f1\3\2"+
"\2\2\u02f1\u02f3\3\2\2\2\u02f2\u02f0\3\2\2\2\u02f3\u02f4\bo\2\2\u02f4"+
"\u00de\3\2\2\2\u02f5\u02f6\t\3\2\2\u02f6\u02f7\3\2\2\2\u02f7\u02f8\bp"+
"\3\2\u02f8\u00e0\3\2\2\2\u02f9\u02fb\t\2\2\2\u02fa\u02f9\3\2\2\2\u02fb"+
"\u02fc\3\2\2\2\u02fc\u02fa\3\2\2\2\u02fc\u02fd\3\2\2\2\u02fd\u00e2\3\2"+
"\2\2\u02fe\u0302\t\4\2\2\u02ff\u0301\t\5\2\2\u0300\u02ff\3\2\2\2\u0301"+
"\u0304\3\2\2\2\u0302\u0300\3\2\2\2\u0302\u0303\3\2\2\2\u0303\u00e4\3\2"+
"\2\2\u0304\u0302\3\2\2\2\u0305\u030d\4\62;\2\u0306\u0308\4\63;\2\u0307"+
"\u0309\4\62;\2\u0308\u0307\3\2\2\2\u0309\u030a\3\2\2\2\u030a\u0308\3\2"+
"\2\2\u030a\u030b\3\2\2\2\u030b\u030d\3\2\2\2\u030c\u0305\3\2\2\2\u030c"+
"\u0306\3\2\2\2\u030d\u00e6\3\2\2\2\u030e\u0310\7&\2\2\u030f\u0311\t\6"+
"\2\2\u0310\u030f\3\2\2\2\u0311\u0312\3\2\2\2\u0312\u0310\3\2\2\2\u0312"+
"\u0313\3\2\2\2\u0313\u00e8\3\2\2\2\u0314\u0316\7\'\2\2\u0315\u0317\4\62"+
"\63\2\u0316\u0315\3\2\2\2\u0317\u0318\3\2\2\2\u0318\u0316\3\2\2\2\u0318"+
"\u0319\3\2\2\2\u0319\u00ea\3\2\2\2\u031a\u031b\7(\2\2\u031b\u00ec\3\2"+
"\2\2\u031c\u0322\5\u00efx\2\u031d\u031f\t\7\2\2\u031e\u0320\t\b\2\2\u031f"+
"\u031e\3\2\2\2\u031f\u0320\3\2\2\2\u0320\u0321\3\2\2\2\u0321\u0323\5\u00ef"+
"x\2\u0322\u031d\3\2\2\2\u0322\u0323\3\2\2\2\u0323\u00ee\3\2\2\2\u0324"+
"\u0326\4\62;\2\u0325\u0324\3\2\2\2\u0326\u0327\3\2\2\2\u0327\u0325\3\2"+
"\2\2\u0327\u0328\3\2\2\2\u0328\u032f\3\2\2\2\u0329\u032b\7\60\2\2\u032a"+
"\u032c\4\62;\2\u032b\u032a\3\2\2\2\u032c\u032d\3\2\2\2\u032d\u032b\3\2"+
"\2\2\u032d\u032e\3\2\2\2\u032e\u0330\3\2\2\2\u032f\u0329\3\2\2\2\u032f"+
"\u0330\3\2\2\2\u0330\u00f0\3\2\2\2\u0331\u0332\7^\2\2\u0332\u0336\13\2"+
"\2\2\u0333\u0334\7^\2\2\u0334\u0336\5\u00e1q\2\u0335\u0331\3\2\2\2\u0335"+
"\u0333\3\2\2\2\u0336\u00f2\3\2\2\2\u0337\u033c\7$\2\2\u0338\u033b\5\u00f1"+
"y\2\u0339\u033b\n\t\2\2\u033a\u0338\3\2\2\2\u033a\u0339\3\2\2\2\u033b"+
"\u033e\3\2\2\2\u033c\u033a\3\2\2\2\u033c\u033d\3\2\2\2\u033d\u033f\3\2"+
"\2\2\u033e\u033c\3\2\2\2\u033f\u0340\7$\2\2\u0340\u0341\bz\4\2\u0341\u00f4"+
"\3\2\2\2\u0342\u0343\7}\2\2\u0343\u0344\7}\2\2\u0344\u0346\3\2\2\2\u0345"+
"\u0347\13\2\2\2\u0346\u0345\3\2\2\2\u0347\u0348\3\2\2\2\u0348\u0349\3"+
"\2\2\2\u0348\u0346\3\2\2\2\u0349\u034a\3\2\2\2\u034a\u034b\7\177\2\2\u034b"+
"\u034c\7\177\2\2\u034c\u034d\3\2\2\2\u034d\u034e\b{\5\2\u034e\u00f6\3"+
"\2\2\2\u034f\u0352\7)\2\2\u0350\u0353\5\u00f1y\2\u0351\u0353\n\t\2\2\u0352"+
"\u0350\3\2\2\2\u0352\u0351\3\2\2\2\u0353\u0354\3\2\2\2\u0354\u0355\7)"+
"\2\2\u0355\u0356\b|\6\2\u0356\u00f8\3\2\2\2\u0357\u0358\7B\2\2\u0358\u0359"+
"\7|\2\2\u0359\u035a\7r\2\2\u035a\u00fa\3\2\2\2\u035b\u035c\7]\2\2\u035c"+
"\u035d\7_\2\2\u035d\u00fc\3\2\2\2\26\2\u02e5\u02f0\u02fc\u0302\u030a\u030c"+
"\u0310\u0312\u0318\u031f\u0322\u0327\u032d\u032f\u0335\u033a\u033c\u0348"+
"\u0352\7\2\3\2\b\2\2\3z\2\3{\3\3|\4";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
File diff suppressed because it is too large. Load diff
-16
View File
@@ -1,16 +0,0 @@
<?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">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/docs/build" />
<excludeFolder url="file://$MODULE_DIR$/gradle" />
<excludeFolder url="file://$MODULE_DIR$/out" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>