Compare commits

..
32 Commits
Author SHA1 Message Date
Irmen de Jong d05d8de447 optimize math from Soci's suggestions 2019-02-12 23:16:13 +01:00
Irmen de Jong 29b7d91293 improved tracking of module file locations, fixed relative importing of submodules from same directory as source module 2019-02-12 21:44:56 +01:00
Irmen de Jong bcdf3f2b83 improved zero page address addresses for floating point support mode 2019-02-09 17:55:18 +01:00
Irmen de Jong ee497d2ffb improved zero page address addresses for floating point support mode 2019-02-09 17:29:59 +01:00
Irmen de Jong 9f8ae485c3 fix windows path issue 2019-02-04 22:04:31 +01:00
Irmen de Jong 3b32fb74f7 suggest non-Oracle jdk 2019-02-03 22:23:17 +01:00
Irmen de Jong 7ff1af3934 avoid zp corruption issues and added zp mode for floating point (todo: allocate) 2019-02-03 00:26:07 +01:00
Irmen de Jong ae21e03e1d attempt at optimization to register parameter passing 2019-02-01 22:51:30 +01:00
Irmen de Jong f0a504baec replaced cube3d compiled program with more optimized version 2019-02-01 01:42:20 +01:00
Irmen de Jong f83b9732ee User defined blocks are sorted first, before library blocks. This prioritizes zero page allocation to user code (and makes reading the program easier) 2019-02-01 01:22:27 +01:00
Irmen de Jong 86ff08e854 fix abs() and also try to convert const arguments to the desired datatype of subroutine params 2019-02-01 00:51:49 +01:00
Irmen de Jong b911a95fc2 fix compiler crash for non-const array literals 2019-01-31 23:47:48 +01:00
Irmen de Jong 73b0cc4056 docs 2019-01-31 23:46:58 +01:00
Irmen de Jong 8e36a64d49 error message for invalid operand types for logical or bitwise operators 2019-01-31 21:38:45 +01:00
Irmen de Jong 255c808b16 Merge pull request #2 from fboldog/gradle-fatjar
Create prog8compiler.jar with fatjar like jar process
2019-01-31 21:15:23 +01:00
Irmen de Jong b311b5ef4a scripts paths fixes 2019-01-31 00:09:22 +01:00
Irmen de Jong 9a8ada7e75 fixed scripts, type check bug fixed, improved some argument error messages 2019-01-30 23:51:46 +01:00
Irmen de Jong 32a9ab30fb fixed stack bug in print_ub, applied Soci's optimizations to prog8lib.asm 2019-01-30 23:43:21 +01:00
Ferenc Boldog 5c8d7c1255 Create prog8compiler.jar with fatjar like jar process 2019-01-30 22:39:43 +01:00
Irmen de Jong 53045b9e36 idea 2019-01-29 23:48:26 +01:00
Irmen de Jong d35d28ac5a docs about gradle and building the compiler, fix shell build script 2019-01-29 23:32:43 +01:00
Irmen de Jong 993dcde985 Merge pull request #1 from fboldog/gradle-build
Gradle build.

Thanks for contributing!
2019-01-29 22:25:16 +01:00
Ferenc Boldog 0ecef00b13 enable cmdline build cache
more information: https://blog.jetbrains.com/kotlin/2018/02/using-gradle-build-cache-with-kotlin/
2019-01-29 12:14:08 +01:00
Ferenc Boldog 13a5eabc09 ignore gradle build related folders 2019-01-29 12:12:07 +01:00
Ferenc Boldog b8624c72d9 generate p8compiler and p8vm scripts 2019-01-29 12:11:47 +01:00
Ferenc Boldog 49c5b2b107 java, resources and test source directories 2019-01-29 12:10:59 +01:00
Ferenc Boldog 1e89bea288 just changed by build 2019-01-29 12:10:09 +01:00
Ferenc Boldog 2c64f95b06 set antlr source (grammar) directory 2019-01-29 12:09:39 +01:00
Ferenc Boldog 037c78cfaf set current java source directory 2019-01-29 12:09:18 +01:00
Ferenc Boldog de777b1308 initial version of compiler and parser gradle module 2019-01-29 12:08:21 +01:00
Ferenc Boldog b3df3c999d package definition for antlr 2019-01-29 12:06:33 +01:00
Ferenc Boldog 4790c3a793 gradle wrapper 2019-01-29 12:06:10 +01:00
63 changed files with 1152 additions and 446 deletions

No files matched your search

+3
View File
@@ -29,3 +29,6 @@ compiler/src/prog8_kotlin.jar
compiler/src/compiled_java
.attach_pid*
.gradle
build/
/prog8compiler.jar
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
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 -package prog8.parser ./parser/antlr/prog8.g4
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
PARSER_CLASSES=./out/production/parser
+68
View File
@@ -0,0 +1,68 @@
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.20"
id 'application'
}
repositories {
mavenCentral()
jcenter()
}
def kotlinVersion = '1.3.20'
dependencies {
implementation project(':parser')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
runtime "org.jetbrains.kotlin:kotlin-reflect:$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'
}
sourceSets {
main {
java {
srcDirs = ["${project.projectDir}/src"]
}
resources {
srcDirs = ["${project.projectDir}/res"]
}
}
test {
java {
srcDirs = ["${project.projectDir}/test"]
}
}
}
application {
mainClassName = 'prog8.CompilerMainKt'
applicationName = 'p8compile'
}
task p8vmScript(type: CreateStartScripts) {
mainClassName = "prog8.StackVmMainKt"
applicationName = "p8vm"
outputDir = new File(project.buildDir, 'scripts')
classpath = jar.outputs.files + project.configurations.runtime
}
applicationDistribution.into("bin") {
from(p8vmScript)
fileMode = 0755
}
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'prog8.CompilerMainKt'
}
archiveBaseName = 'prog8compiler'
destinationDir = rootProject.projectDir
from { project.configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
// build.finalizedBy(fatJar)
+2 -3
View File
@@ -763,13 +763,12 @@ _print_byte_digits
bne _print_hundreds
cpx #'0'
bne _print_tens
pla
jmp c64.CHROUT
jmp _end
_print_hundreds tya
jsr c64.CHROUT
_print_tens txa
jsr c64.CHROUT
pla
_end pla
jsr c64.CHROUT
ldx c64.SCRATCH_ZPREGX
rts
+169 -228
View File
@@ -241,26 +241,24 @@ mul_byte_3 .proc
.pend
mul_word_3 .proc
; W + W*2
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; W*2 + W
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_5 .proc
; X + X*4
; X*4 + X
lda c64.ESTACK_LO+1,x
asl a
asl a
@@ -271,58 +269,49 @@ mul_byte_5 .proc
.pend
mul_word_5 .proc
; W + W*4
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; W*4 + W
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_6 .proc
; X*2 + X*4
; (X*2 + X)*2
lda c64.ESTACK_LO+1,x
asl a
sta c64.SCRATCH_ZPREG
clc
adc c64.ESTACK_LO+1,x
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_6 .proc
; W*2 + W*4
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; (W*2 + W)*2
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
asl c64.ESTACK_LO+1,x
rol a
sta c64.ESTACK_HI+1,x
rts
.pend
@@ -341,29 +330,26 @@ mul_byte_7 .proc
mul_word_7 .proc
; W*8 - W
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
sec
lda c64.SCRATCH_ZPWORD1
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
sbc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_9 .proc
; X + X*8
; X*8 + X
lda c64.ESTACK_LO+1,x
asl a
asl a
@@ -375,80 +361,67 @@ mul_byte_9 .proc
.pend
mul_word_9 .proc
; W + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; W*8 + W
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_10 .proc
; X + X + X*8
; (X*4 + X)*2
lda c64.ESTACK_LO+1,x
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
asl a
clc
adc c64.ESTACK_LO+1,x
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_10 .proc
; W*2 + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; (W*4 + W)*2
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
asl c64.ESTACK_LO+1,x
rol a
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_11 .proc
; X + X + X + X*8
; (X*2 + X)*4 - X
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
clc
adc c64.SCRATCH_ZPREG
clc
adc c64.SCRATCH_ZPREG
adc c64.ESTACK_LO+1,x
asl a
asl a
sec
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
@@ -456,58 +429,47 @@ mul_byte_11 .proc
; mul_word_11 is skipped (too much code)
mul_byte_12 .proc
; X*4 + X*8
; (X*2 + X)*4
lda c64.ESTACK_LO+1,x
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.SCRATCH_ZPREG
adc c64.ESTACK_LO+1,x
asl a
asl a
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_12 .proc
; W*4 + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; (W*2 + W)*4
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
asl c64.ESTACK_LO+1,x
rol a
asl c64.ESTACK_LO+1,x
rol a
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_13 .proc
; X*16 - X -X -X
; (X*2 + X)*4 + X
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.ESTACK_LO+1,x
asl a
asl a
asl a
asl a
sec
sbc c64.SCRATCH_ZPREG
sec
sbc c64.SCRATCH_ZPREG
sec
sbc c64.SCRATCH_ZPREG
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
@@ -515,16 +477,14 @@ mul_byte_13 .proc
; mul_word_13 is skipped (too much code)
mul_byte_14 .proc
; X*16 - X -X
; (X*8 - X)*2
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
asl a
sec
sbc c64.ESTACK_LO+1,x
sec
sec
sbc c64.ESTACK_LO+1,x
asl a
sta c64.ESTACK_LO+1,x
rts
.pend
@@ -534,7 +494,6 @@ mul_byte_14 .proc
mul_byte_15 .proc
; X*16 - X
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
asl a
asl a
@@ -547,80 +506,70 @@ mul_byte_15 .proc
mul_word_15 .proc
; W*16 - W
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
sec
lda c64.SCRATCH_ZPWORD1
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
sbc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_20 .proc
; X*4 + X*16
; (X*4 + X)*4
lda c64.ESTACK_LO+1,x
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
adc c64.ESTACK_LO+1,x
asl a
asl a
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_20 .proc
; W*4 + W*16
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; (W*4 + W)*4
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
asl c64.ESTACK_LO+1,x
rol a
asl c64.ESTACK_LO+1,x
rol a
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_25 .proc
; X + X*8 + X*16
; (X*2 + X)*8 + X
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.SCRATCH_ZPREG
adc c64.ESTACK_LO+1,x
asl a
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
@@ -629,76 +578,68 @@ mul_byte_25 .proc
mul_word_25 .proc
; W + W*8 + W*16
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
asl a
rol c64.SCRATCH_ZPWORD1+1
asl a
rol c64.SCRATCH_ZPWORD1+1
asl a
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD1
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1+1
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
asl c64.SCRATCH_ZPWORD1
lda c64.SCRATCH_ZPWORD1
asl a
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1+1
adc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_40 .proc
; X*8 + X*32
; (X*4 + X)*8
lda c64.ESTACK_LO+1,x
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
asl a
sta c64.SCRATCH_ZPREG
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_40 .proc
; W*8 + W*32
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
; (W*4 + W)*8
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPREG
lda c64.ESTACK_LO+1,x
asl a
rol c64.SCRATCH_ZPREG
asl a
rol c64.SCRATCH_ZPREG
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPREG
adc c64.ESTACK_HI+1,x
asl c64.ESTACK_LO+1,x
rol a
asl c64.ESTACK_LO+1,x
rol a
asl c64.ESTACK_LO+1,x
rol a
sta c64.ESTACK_HI+1,x
rts
.pend
+26 -39
View File
@@ -49,19 +49,17 @@ add_a_to_zpword .proc
pop_index_times_5 .proc
inx
lda c64.ESTACK_LO,x
sta c64.SCRATCH_ZPB1
asl a
asl a
clc
adc c64.SCRATCH_ZPB1 ; A*=5
adc c64.ESTACK_LO,x
rts
.pend
neg_b .proc
lda c64.ESTACK_LO+1,x
eor #255
clc
adc #1
lda #0
sec
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
@@ -90,10 +88,9 @@ inv_word .proc
not_byte .proc
lda c64.ESTACK_LO+1,x
beq +
lda #0
beq ++
+ lda #1
+ sta c64.ESTACK_LO+1,x
lda #1
+ eor #1
sta c64.ESTACK_LO+1,x
rts
.pend
@@ -101,10 +98,10 @@ not_word .proc
lda c64.ESTACK_LO + 1,x
ora c64.ESTACK_HI + 1,x
beq +
lda #0
beq ++
+ lda #1
+ sta c64.ESTACK_LO + 1,x
lda #1
+ eor #1
sta c64.ESTACK_LO + 1,x
lsr a
sta c64.ESTACK_HI + 1,x
rts
.pend
@@ -300,25 +297,18 @@ equal_w .proc
notequal_b .proc
; -- are the two bytes on the stack different?
inx
lda c64.ESTACK_LO,x
eor c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
beq equal_b._equal_b_false
bne equal_b._equal_b_true
.pend
notequal_w .proc
; -- are the two words on the stack different?
inx
lda c64.ESTACK_LO,x
eor c64.ESTACK_LO+1,x
beq +
sta c64.ESTACK_LO+1,x
rts
+ lda c64.ESTACK_HI,x
eor c64.ESTACK_HI+1,x
sta c64.ESTACK_LO+1,x
rts
lda c64.ESTACK_HI+1,x
cmp c64.ESTACK_HI+2,x
beq notequal_b
bne equal_b._equal_b_true
.pend
less_ub .proc
@@ -375,11 +365,10 @@ _equal_b_false lda #0
.pend
lesseq_ub .proc
lda c64.ESTACK_LO+2,x
cmp c64.ESTACK_LO+1,x
bcc equal_b._equal_b_true
beq equal_b._equal_b_true
bcs equal_b._equal_b_false
lda c64.ESTACK_LO+1,x
cmp c64.ESTACK_LO+2,x
bcs equal_b._equal_b_true
bcc equal_b._equal_b_false
.pend
lesseq_b .proc
@@ -790,17 +779,15 @@ _loop lda (c64.SCRATCH_ZPWORD1),y
func_sum_ub .proc
jsr pop_array_and_lengthmin1Y
lda #0
sta c64.ESTACK_LO,x
sta c64.ESTACK_HI,x
- lda (c64.SCRATCH_ZPWORD1),y
clc
adc c64.ESTACK_LO,x
sta c64.ESTACK_LO,x
- clc
adc (c64.SCRATCH_ZPWORD1),y
bcc +
inc c64.ESTACK_HI,x
+ dey
cpy #255
bne -
sta c64.ESTACK_LO,x
dex
rts
.pend
+1 -1
View File
@@ -1 +1 @@
1.1 (beta)
1.2 (beta)
+1 -1
View File
@@ -182,7 +182,7 @@ fun determineCompilationOptions(moduleAst: Module): CompilationOptions {
val floatsEnabled = options.any { it.name == "enable_floats" }
val zpType: ZeropageType =
if (zpoption == null)
if(floatsEnabled) ZeropageType.BASICSAFE else ZeropageType.KERNALSAFE
if(floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
else
try {
ZeropageType.valueOf(zpoption)
+67 -28
View File
@@ -9,6 +9,7 @@ import prog8.compiler.target.c64.Petscii
import prog8.functions.BuiltinFunctions
import prog8.functions.NotConstArgumentException
import prog8.functions.builtinFunctionReturnType
import prog8.parser.CustomLexer
import prog8.parser.prog8Parser
import java.io.File
import java.nio.file.Path
@@ -37,20 +38,20 @@ enum class DataType {
fun assignableTo(targetType: DataType) =
// what types are assignable to others without loss of precision?
when(this) {
UBYTE -> targetType == BYTE || targetType == UBYTE || targetType == UWORD || targetType==WORD || targetType == FLOAT
BYTE -> targetType == BYTE || targetType == UBYTE || targetType == WORD || targetType == FLOAT
UBYTE -> targetType == UBYTE || targetType == UWORD || targetType==WORD || targetType == FLOAT
BYTE -> targetType == BYTE || targetType == UBYTE || targetType == UWORD || targetType==WORD || targetType == FLOAT
UWORD -> targetType == UWORD || targetType == FLOAT
WORD -> targetType == WORD || targetType == FLOAT
WORD -> targetType == WORD || targetType==UWORD || targetType == FLOAT
FLOAT -> targetType == FLOAT
STR -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_P -> targetType == STR_P || targetType==STR_PS || targetType == UWORD
STR_S -> targetType == STR || targetType==STR_S || targetType == UWORD
STR_PS -> targetType == STR_P || targetType==STR_PS || targetType == UWORD
ARRAY_UB -> targetType == UWORD
ARRAY_B -> targetType == UWORD
ARRAY_UW -> targetType == UWORD
ARRAY_W -> targetType == UWORD
ARRAY_F -> 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
}
@@ -174,9 +175,9 @@ interface IAstProcessor {
return functionCall
}
fun process(functionCall: FunctionCallStatement): IStatement {
functionCall.arglist = functionCall.arglist.map { it.process(this) }.toMutableList()
return functionCall
fun process(functionCallStatement: FunctionCallStatement): IStatement {
functionCallStatement.arglist = functionCallStatement.arglist.map { it.process(this) }.toMutableList()
return functionCallStatement
}
fun process(identifier: IdentifierReference): IExpression {
@@ -506,11 +507,11 @@ private class GlobalNamespace(override val name: String,
class Block(override val name: String,
val address: Int?,
override var statements: MutableList<IStatement>,
val isInLibrary: Boolean,
override val position: Position) : IStatement, INameScope {
override lateinit var parent: Node
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
override fun linkParents(parent: Node) {
this.parent = parent
statements.forEach {it.linkParents(this)}
@@ -1647,6 +1648,40 @@ class Subroutine(override val name: String,
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it }
val canBeAsmSubroutine =false // TODO see below
// !isAsmSubroutine
// && ((parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD))
// || (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE }))
fun intoAsmSubroutine(): Subroutine {
// TODO turn subroutine into asm calling convention. Requires rethinking of how parameters are handled (conflicts with local vardefs now, see AstIdentifierChecker...)
return this // TODO
// println("TO ASM $this") // TODO
// val paramregs = if (parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE))
// listOf(RegisterOrStatusflag(RegisterOrPair.Y, null, null))
// else if (parameters.size == 1 && parameters[0].type in setOf(DataType.WORD, DataType.UWORD))
// listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, null))
// else if (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE })
// listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null), RegisterOrStatusflag(RegisterOrPair.Y, null, null))
// else throw FatalAstException("cannot convert subroutine to asm parameters")
//
// val asmsub=Subroutine(
// name,
// parameters,
// returntypes,
// paramregs,
// emptyList(),
// emptySet(),
// null,
// true,
// statements,
// position
// )
// asmsub.linkParents(parent)
// return asmsub
}
}
@@ -1753,34 +1788,38 @@ class RepeatLoop(var body: AnonymousScope,
/***************** Antlr Extension methods to create AST ****************/
fun prog8Parser.ModuleContext.toAst(name: String, isLibrary: Boolean, importedFrom: Path) : Module =
Module(name, modulestatement().asSequence().map { it.toAst() }.toMutableList(), toPosition(), isLibrary, importedFrom)
private fun ParserRuleContext.toPosition() : Position {
val file =
if(start.inputStream.sourceName == IntStream.UNKNOWN_SOURCE_NAME)
"<internal>"
else
File(start.inputStream.sourceName).name
// note: be ware of TAB characters in the source text, they count as 1 column...
return Position(file, start.line, start.charPositionInLine, stop.charPositionInLine+stop.text.length)
fun prog8Parser.ModuleContext.toAst(name: String, isLibrary: Boolean, importedFrom: Path) : Module {
val nameWithoutSuffix = if(name.endsWith(".p8")) name.substringBeforeLast('.') else name
return Module(nameWithoutSuffix, modulestatement().asSequence().map { it.toAst(isLibrary) }.toMutableList(), toPosition(), isLibrary, importedFrom)
}
private fun prog8Parser.ModulestatementContext.toAst() : IStatement {
private fun ParserRuleContext.toPosition() : Position {
val customTokensource = this.start.tokenSource as? CustomLexer
val filename =
when {
customTokensource!=null -> customTokensource.modulePath.fileName.toString()
start.tokenSource.sourceName == IntStream.UNKNOWN_SOURCE_NAME -> "@internal@"
else -> File(start.inputStream.sourceName).name
}
// note: be ware of TAB characters in the source text, they count as 1 column...
return Position(filename, start.line, start.charPositionInLine, stop.charPositionInLine+stop.text.length)
}
private fun prog8Parser.ModulestatementContext.toAst(isInLibrary: Boolean) : IStatement {
val directive = directive()?.toAst()
if(directive!=null) return directive
val block = block()?.toAst()
val block = block()?.toAst(isInLibrary)
if(block!=null) return block
throw FatalAstException(text)
}
private fun prog8Parser.BlockContext.toAst() : IStatement =
Block(identifier().text, integerliteral()?.toAst()?.number?.toInt(), statement_block().toAst(), toPosition())
private fun prog8Parser.BlockContext.toAst(isInLibrary: Boolean) : IStatement =
Block(identifier().text, integerliteral()?.toAst()?.number?.toInt(), statement_block().toAst(), isInLibrary, toPosition())
private fun prog8Parser.Statement_blockContext.toAst(): MutableList<IStatement> =
+16 -8
View File
@@ -592,9 +592,10 @@ private class AstChecker(private val namespace: INameScope,
if(directive.parent !is Module) err("this directive may only occur at module level")
if(directive.args.size!=1 ||
directive.args[0].name != "basicsafe" &&
directive.args[0].name != "floatsafe" &&
directive.args[0].name != "kernalsafe" &&
directive.args[0].name != "full")
err("invalid zp type, expected basicsafe, kernalsafe, or full")
err("invalid zp type, expected basicsafe, floatsafe, kernalsafe, or full")
}
"%zpreserved" -> {
if(directive.parent !is Module) err("this directive may only occur at module level")
@@ -694,6 +695,13 @@ private class AstChecker(private val namespace: INameScope,
checkResult.add(ExpressionError("remainder can only be used on unsigned integer operands", expr.right.position))
}
}
"and", "or", "xor", "&", "|", "^" -> {
// 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("logical or bitwise operator can only be used on integer operands", expr.right.position))
}
}
val leftDt = expr.left.resultingDatatype(namespace, heap)!!
@@ -769,13 +777,13 @@ private class AstChecker(private val namespace: INameScope,
return super.process(functionCall)
}
override fun process(functionCall: FunctionCallStatement): IStatement {
val targetStatement = checkFunctionOrLabelExists(functionCall.target, functionCall)
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
val targetStatement = checkFunctionOrLabelExists(functionCallStatement.target, functionCallStatement)
if(targetStatement!=null)
checkFunctionCall(targetStatement, functionCall.arglist, functionCall.position)
checkFunctionCall(targetStatement, functionCallStatement.arglist, functionCallStatement.position)
if(targetStatement is Subroutine && targetStatement.returntypes.isNotEmpty())
printWarning("result value of subroutine call is discarded", functionCall.position)
return super.process(functionCall)
printWarning("result value of subroutine call is discarded", functionCallStatement.position)
return super.process(functionCallStatement)
}
private fun checkFunctionCall(target: IStatement, args: List<IExpression>, position: Position) {
@@ -791,7 +799,7 @@ private class AstChecker(private val namespace: INameScope,
for (arg in args.withIndex().zip(func.parameters)) {
val argDt=arg.first.value.resultingDatatype(namespace, heap)
if(argDt!=null && !argDt.assignableTo(arg.second.possibleDatatypes)) {
checkResult.add(ExpressionError("builtin function argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.possibleDatatypes}", position))
checkResult.add(ExpressionError("builtin function '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.possibleDatatypes}", position))
}
}
if(target.name=="swap") {
@@ -815,7 +823,7 @@ private class AstChecker(private val namespace: INameScope,
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 argument ${arg.first.index+1} has invalid type $argDt, expected ${arg.second.type}", position))
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)) {
@@ -124,7 +124,8 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
// NOTE:
// - numeric types BYTE and WORD and FLOAT are passed by value;
// - strings, arrays, matrices are passed by reference (their 16-bit address is passed as an uword parameter)
if(subroutine.asmAddress==null) {
// - do NOT do this is the statement can be transformed into an asm subroutine later!
if(subroutine.asmAddress==null && !subroutine.canBeAsmSubroutine) {
if(subroutine.asmParameterRegisters.isEmpty()) {
subroutine.parameters
.filter { it.name !in allDefinedNames }
@@ -92,9 +92,9 @@ private class AstRecursionChecker(private val namespace: INameScope) : IAstProce
return listOf(AstException("Program contains recursive subroutine calls, this is not supported. Recursive chain:\n (a subroutine call in) $chain"))
}
override fun process(functionCall: FunctionCallStatement): IStatement {
val scope = functionCall.definingScope()
val targetStatement = functionCall.target.targetStatement(namespace)
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
val scope = functionCallStatement.definingScope()
val targetStatement = functionCallStatement.target.targetStatement(namespace)
if(targetStatement!=null) {
val targetScope = when (targetStatement) {
is Subroutine -> targetStatement
@@ -102,7 +102,7 @@ private class AstRecursionChecker(private val namespace: INameScope) : IAstProce
}
callGraph.add(scope, targetScope)
}
return super.process(functionCall)
return super.process(functionCallStatement)
}
override fun process(functionCall: FunctionCall): IExpression {
+10 -2
View File
@@ -33,11 +33,21 @@ private class StatementReorderer(private val namespace: INameScope, private val
val (blocks, other) = module.statements.partition { it is Block }
module.statements = other.asSequence().plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList()
// make sure user-defined blocks come BEFORE library blocks, and move the "main" block to the top of everything
val nonLibraryBlocks = module.statements.withIndex()
.filter { it.value is Block && !(it.value as Block).isInLibrary }
.map { it.index to it.value }
.reversed()
for(nonLibBlock in nonLibraryBlocks)
module.statements.removeAt(nonLibBlock.first)
for(nonLibBlock in nonLibraryBlocks)
module.statements.add(0, nonLibBlock.second)
val mainBlock = module.statements.single { it is Block && it.name=="main" }
if((mainBlock as Block).address==null) {
module.statements.remove(mainBlock)
module.statements.add(0, mainBlock)
}
val varDecls = module.statements.filterIsInstance<VarDecl>()
module.statements.removeAll(varDecls)
module.statements.addAll(0, varDecls)
@@ -46,8 +56,6 @@ private class StatementReorderer(private val namespace: INameScope, private val
module.statements.removeAll(directives)
module.statements.addAll(0, directives)
// TODO make sure user-defined blocks come BEFORE library blocks
sortConstantAssignments(module.statements)
}
+1
View File
@@ -132,6 +132,7 @@ enum class LauncherType {
enum class ZeropageType {
BASICSAFE,
FLOATSAFE,
KERNALSAFE,
FULL
}
+9 -1
View File
@@ -6,7 +6,7 @@ import prog8.ast.*
class ZeropageDepletedError(message: String) : Exception(message)
abstract class Zeropage(private val options: CompilationOptions) {
abstract class Zeropage(protected val options: CompilationOptions) {
private val allocations = mutableMapOf<Int, Pair<String, DataType>>()
val free = mutableListOf<Int>() // subclasses must set this to the appropriate free locations.
@@ -61,4 +61,12 @@ abstract class Zeropage(private val options: CompilationOptions) {
private fun loneByte(address: Int) = address in free && address-1 !in free && address+1 !in free
private fun sequentialFree(address: Int, size: Int) = free.containsAll((address until address+size).toList())
enum class ExitProgramStrategy {
CLEAN_EXIT,
SYSTEM_RESET
}
abstract val exitProgramStrategy: ExitProgramStrategy
}
@@ -186,6 +186,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
if(zeropage.exitProgramStrategy!=Zeropage.ExitProgramStrategy.CLEAN_EXIT) {
// disable shift-commodore charset switching and run/stop key
out(" lda #$80")
out(" lda #$80")
out(" sta 657\t; disable charset switching")
out(" lda #239")
out(" sta 808\t; disable run/stop key")
}
out(" ldx #\$ff\t; init estack pointer")
out(" ; initialize the variables in each block")
for(block in program.blocks) {
@@ -194,7 +203,15 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
out(" jsr ${block.scopedname}.${initVarsLabel.name}")
}
out(" clc")
out(" jmp main.start\t; jump to program entrypoint")
when(zeropage.exitProgramStrategy) {
Zeropage.ExitProgramStrategy.CLEAN_EXIT -> {
out(" jmp main.start\t; jump to program entrypoint")
}
Zeropage.ExitProgramStrategy.SYSTEM_RESET -> {
out(" jsr main.start\t; call program entrypoint")
out(" jmp (c64.RESET_VEC)\t; cold reset")
}
}
out("")
// the global list of all floating point constants for the whole program
@@ -29,27 +29,56 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
const val SCRATCH_B1 = 0x02
const val SCRATCH_REG = 0x03 // temp storage for a register
const val SCRATCH_REG_X = 0xfa // temp storage for register X (the evaluation stack pointer)
const val SCRATCH_W1 = 0xfb // $fb/$fc
const val SCRATCH_W2 = 0xfd // $fd/$fe
const val SCRATCH_W1 = 0xfb // $fb+$fc
const val SCRATCH_W2 = 0xfd // $fd+$fe
}
override val exitProgramStrategy: ExitProgramStrategy = when(options.zeropage) {
ZeropageType.BASICSAFE -> ExitProgramStrategy.CLEAN_EXIT
ZeropageType.FLOATSAFE, ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET
}
init {
if(options.zeropage== ZeropageType.FULL) {
if(options.floats && options.zeropage!=ZeropageType.FLOATSAFE && options.zeropage!=ZeropageType.BASICSAFE)
throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe'")
if(options.zeropage == ZeropageType.FULL) {
free.addAll(0x04 .. 0xf9)
free.add(0xff)
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1+1, SCRATCH_W2, SCRATCH_W2+1))
free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ
} else {
if(options.zeropage== ZeropageType.KERNALSAFE) {
// add the Zp addresses that are just used by BASIC routines to the free list
free.addAll(listOf(0x09, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
if(options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
free.addAll(listOf(0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
0x22, 0x23, 0x24, 0x25,
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53, 0x6f, 0x70))
0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
// 0x90-0xfa is 'kernel work storage area'
))
}
// add the other free Zp addresses
// these are valid for the C-64 (when no RS232 I/O is performed):
free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0d, 0x0e,
if(options.zeropage == ZeropageType.FLOATSAFE) {
// remove the zero page locations used for floating point operations from the free list
free.removeAll(listOf(
0x12, 0x26, 0x27, 0x28, 0x29, 0x2a,
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xf
))
}
// add the other free Zp addresses,
// these are valid for the C-64 (when no RS232 I/O is performed) but to keep BASIC running fully:
free.addAll(listOf(0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x0e,
0x94, 0x95, 0xa7, 0xa8, 0xa9, 0xaa,
0xb5, 0xb6, 0xf7, 0xf8, 0xf9))
}
@@ -111,7 +111,7 @@ val BuiltinFunctions = mapOf(
fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespace: INameScope, heap: HeapValues): DataType? {
fun datatypeFromListArg(arglist: IExpression): DataType {
fun datatypeFromIterableArg(arglist: IExpression): DataType {
if(arglist is LiteralValue) {
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)}
@@ -133,10 +133,10 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
DataType.ARRAY_UW -> DataType.UWORD
DataType.ARRAY_W -> DataType.WORD
DataType.ARRAY_F -> DataType.FLOAT
null -> throw FatalAstException("function requires one argument which is an arrayspec $function")
null -> throw FatalAstException("function '$function' requires one argument which is an iterable")
}
}
throw FatalAstException("function requires one argument which is an arrayspec $function")
throw FatalAstException("function '$function' requires one argument which is an iterable")
}
val func = BuiltinFunctions.getValue(function)
@@ -145,8 +145,17 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
// function has return values, but the return type depends on the arguments
return when (function) {
"max", "min", "abs" -> {
val dt = datatypeFromListArg(args.single())
"abs" -> {
val dt = args.single().resultingDatatype(namespace, heap)
when(dt) {
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE
DataType.UWORD, DataType.WORD -> DataType.UWORD
DataType.FLOAT -> DataType.FLOAT
else -> throw FatalAstException("weird datatype passed to abs $dt")
}
}
"max", "min" -> {
val dt = datatypeFromIterableArg(args.single())
when(dt) {
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> dt
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.UBYTE
@@ -158,7 +167,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
}
}
"sum" -> {
val dt=datatypeFromListArg(args.single())
val dt=datatypeFromIterableArg(args.single())
when(dt) {
DataType.UBYTE, DataType.UWORD -> DataType.UWORD
DataType.BYTE, DataType.WORD -> DataType.WORD
@@ -33,7 +33,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) {
val litval = decl.value as? LiteralValue
if(litval!=null && litval.isArray)
if(litval!=null && litval.isArray && litval.heapId!=null)
fixupArrayTypeOnHeap(decl, litval)
when(decl.datatype) {
DataType.FLOAT -> {
@@ -97,9 +97,10 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
private fun fixupArrayTypeOnHeap(decl: VarDecl, litval: LiteralValue) {
// fix the type of the array value that's on the heap, to match the vardecl.
// notice that checking the bounds of the actual values is not done here, but in the AstChecker later.
if(decl.datatype==litval.type)
return // already correct datatype
val heapId = litval.heapId!!
val heapId = litval.heapId ?: throw FatalAstException("expected array to be on heap $litval")
val array=heap.get(heapId)
when(decl.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> {
@@ -141,6 +142,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
override fun process(functionCall: FunctionCall): IExpression {
return try {
super.process(functionCall)
typeCastConstArguments(functionCall)
functionCall.constValue(namespace, heap) ?: functionCall
} catch (ax: AstException) {
addError(ax)
@@ -148,6 +150,31 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
}
}
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
super.process(functionCallStatement)
typeCastConstArguments(functionCallStatement)
return functionCallStatement
}
private fun typeCastConstArguments(functionCall: IFunctionCall) {
val subroutine = functionCall.target.targetStatement(namespace) as? Subroutine
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)) {
val expectedDt = arg.second.type
val argConst = arg.first.value.constValue(namespace, heap)
if(argConst!=null && argConst.type!=expectedDt) {
val convertedValue = argConst.intoDatatype(expectedDt)
if(convertedValue!=null) {
functionCall.arglist[arg.first.index] = convertedValue
optimizationsDone++
}
}
}
}
}
/**
* Try to process a unary prefix expression.
* Compile-time constant sub expressions will be evaluated on the spot.
@@ -8,6 +8,9 @@ import kotlin.math.floor
/*
todo: subroutines with 1 or 2 byte args or 1 word arg can be converted to asm sub calling convention (args in registers)
todo: implement usage counters for blocks, variables, subroutines, heap variables. Then:
todo remove unused blocks
todo remove unused variables
@@ -52,6 +55,18 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
}
if(subroutine.canBeAsmSubroutine) {
optimizationsDone++
return subroutine.intoAsmSubroutine() // TODO this doesn't work yet due to parameter vardecl issue
// TODO fix parameter passing so this also works:
// asmsub aa(byte arg @ Y) -> clobbers() -> () {
// byte local = arg ; @todo fix 'undefined symbol arg' by some sort of alias name for the parameter
// A=44
// }
}
return subroutine
}
@@ -80,16 +95,6 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
return linesToRemove
}
private fun returnregisters(subroutine: Subroutine): List<RegisterOrStatusflag> {
return when {
subroutine.returntypes.isEmpty() -> listOf()
subroutine.returntypes.size==1 && subroutine.returntypes[0] in setOf(DataType.BYTE, DataType.UBYTE) -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null))
subroutine.returntypes.size==1 && subroutine.returntypes[0] in setOf(DataType.WORD, DataType.UWORD) -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, null))
subroutine.returntypes.size==2 && subroutine.returntypes.all { it in setOf(DataType.BYTE, DataType.UBYTE)} -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null), RegisterOrStatusflag(RegisterOrPair.Y, null, null))
else -> throw FatalAstException("can't convert return values to registers")
}
}
private fun isNotMemory(target: AssignTarget): Boolean {
if(target.register!=null)
return true
@@ -109,39 +114,39 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
}
override fun process(functionCall: FunctionCallStatement): IStatement {
if(functionCall.target.nameInSource.size==1 && functionCall.target.nameInSource[0] in BuiltinFunctions) {
val functionName = functionCall.target.nameInSource[0]
override fun process(functionCallStatement: FunctionCallStatement): IStatement {
if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in BuiltinFunctions) {
val functionName = functionCallStatement.target.nameInSource[0]
if (functionName in pureBuiltinFunctions) {
printWarning("statement has no effect (function return value is discarded)", functionCall.position)
statementsToRemove.add(functionCall)
return functionCall
printWarning("statement has no effect (function return value is discarded)", functionCallStatement.position)
statementsToRemove.add(functionCallStatement)
return functionCallStatement
}
}
if(functionCall.target.nameInSource==listOf("c64scr", "print") ||
functionCall.target.nameInSource==listOf("c64scr", "print_p")) {
if(functionCallStatement.target.nameInSource==listOf("c64scr", "print") ||
functionCallStatement.target.nameInSource==listOf("c64scr", "print_p")) {
// printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters
if(functionCall.arglist.single() is LiteralValue)
if(functionCallStatement.arglist.single() is LiteralValue)
throw AstException("string argument should be on heap already")
val stringVar = functionCall.arglist.single() as? IdentifierReference
val stringVar = functionCallStatement.arglist.single() as? IdentifierReference
if(stringVar!=null) {
val heapId = stringVar.heapId(namespace)
val string = heap.get(heapId).str!!
if(string.length==1) {
val petscii = Petscii.encodePetscii(string, true)[0]
functionCall.arglist.clear()
functionCall.arglist.add(LiteralValue.optimalInteger(petscii, functionCall.position))
functionCall.target = IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position)
functionCallStatement.arglist.clear()
functionCallStatement.arglist.add(LiteralValue.optimalInteger(petscii, functionCallStatement.position))
functionCallStatement.target = IdentifierReference(listOf("c64", "CHROUT"), functionCallStatement.target.position)
optimizationsDone++
return functionCall
return functionCallStatement
} else if(string.length==2) {
val petscii = Petscii.encodePetscii(string, true)
val scope = AnonymousScope(mutableListOf(), functionCall.position)
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position),
mutableListOf(LiteralValue.optimalInteger(petscii[0], functionCall.position)), functionCall.position))
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position),
mutableListOf(LiteralValue.optimalInteger(petscii[1], functionCall.position)), functionCall.position))
val scope = AnonymousScope(mutableListOf(), functionCallStatement.position)
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCallStatement.target.position),
mutableListOf(LiteralValue.optimalInteger(petscii[0], functionCallStatement.position)), functionCallStatement.position))
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCallStatement.target.position),
mutableListOf(LiteralValue.optimalInteger(petscii[1], functionCallStatement.position)), functionCallStatement.position))
optimizationsDone++
return scope
}
@@ -151,20 +156,20 @@ 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 = functionCall.target.targetStatement(namespace) as? Subroutine
val subroutine = functionCallStatement.target.targetStatement(namespace) as? Subroutine
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Jump && first.identifier!=null) {
optimizationsDone++
return FunctionCallStatement(first.identifier, functionCall.arglist, functionCall.position)
return FunctionCallStatement(first.identifier, functionCallStatement.arglist, functionCallStatement.position)
}
if(first is ReturnFromIrq || first is Return) {
optimizationsDone++
return NopStatement(functionCall.position)
return NopStatement(functionCallStatement.position)
}
}
return super.process(functionCall)
return super.process(functionCallStatement)
}
override fun process(functionCall: FunctionCall): IExpression {
+12 -8
View File
@@ -5,6 +5,7 @@ import prog8.ast.*
import prog8.compiler.LauncherType
import prog8.compiler.OutputType
import prog8.determineCompilationOptions
import java.io.File
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
@@ -26,8 +27,12 @@ private class LexerErrorListener: BaseErrorListener() {
}
fun importModule(stream: CharStream, moduleName: String, isLibrary: Boolean): Module {
val lexer = prog8Lexer(stream)
internal class CustomLexer(val modulePath: Path, input: CharStream?) : prog8Lexer(input)
fun importModule(stream: CharStream, modulePath: Path, isLibrary: Boolean): Module {
val moduleName = modulePath.fileName
val lexer = CustomLexer(modulePath, stream)
val lexerErrors = LexerErrorListener()
lexer.addErrorListener(lexerErrors)
val tokens = CommentHandlingTokenStream(lexer)
@@ -35,13 +40,13 @@ fun importModule(stream: CharStream, moduleName: String, isLibrary: Boolean): Mo
val parseTree = parser.module()
val numberOfErrors = parser.numberOfSyntaxErrors + lexerErrors.numberOfErrors
if(numberOfErrors > 0)
throw ParsingFailedError("There are $numberOfErrors errors in '$moduleName.p8'.")
throw ParsingFailedError("There are $numberOfErrors errors in '$moduleName'.")
// You can do something with the parsed comments:
// tokens.commentTokens().forEach { println(it) }
// convert to Ast
val moduleAst = parseTree.toAst(moduleName, isLibrary, Paths.get(stream.sourceName))
val moduleAst = parseTree.toAst(moduleName.toString(), isLibrary, modulePath)
importedModules[moduleAst.name] = moduleAst
// process imports
@@ -63,7 +68,7 @@ fun importModule(stream: CharStream, moduleName: String, isLibrary: Boolean): Mo
.asSequence()
.mapIndexed { i, it -> Pair(i, it) }
.filter { (it.second as? Directive)?.directive == "%import" }
.map { Pair(it.first, executeImportDirective(it.second as Directive, Paths.get("$moduleName.p8"))) }
.map { Pair(it.first, executeImportDirective(it.second as Directive, modulePath)) }
.toList()
imports.reversed().forEach {
@@ -95,9 +100,8 @@ fun importModule(filePath: Path) : Module {
if(!Files.isReadable(filePath))
throw ParsingFailedError("No such file: $filePath")
val moduleName = filePath.fileName.toString().substringBeforeLast('.')
val input = CharStreams.fromPath(filePath)
return importModule(input, moduleName, filePath.parent==null)
return importModule(input, filePath, filePath.parent==null)
}
@@ -136,7 +140,7 @@ private fun executeImportDirective(import: Directive, importedFrom: Path): Modul
// load the module from the embedded resource
resource.use {
println("importing '$moduleName' (embedded library)")
importModule(CharStreams.fromStream(it), moduleName, true)
importModule(CharStreams.fromStream(it), Paths.get("@embedded@/$moduleName"), true)
}
} else {
val modulePath = discoverImportedModuleFile(moduleName, importedFrom, import.position)
+37 -23
View File
@@ -138,23 +138,41 @@ class TestZeropage {
assertFailsWith<CompilerException> {
zp.allocate("", DataType.FLOAT, null)
}
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
zp2.allocate("", DataType.FLOAT, null)
}
@Test
fun testZpModesWithFloats() {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
assertFailsWith<CompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
}
assertFailsWith<CompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true))
}
}
@Test
fun testFreeSpaces() {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
assertEquals(19, zp1.available())
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true))
assertEquals(67, zp2.available())
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
assertEquals(238, zp3.available())
assertEquals(20, zp1.available())
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
assertEquals(95, zp2.available())
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
assertEquals(129, zp3.available())
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
assertEquals(238, zp4.available())
}
@Test
fun testReservedSpace() {
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
assertEquals(238, zp1.available())
assertTrue(50 in zp1.free)
assertTrue(100 in zp1.free)
@@ -163,8 +181,7 @@ class TestZeropage {
assertTrue(200 in zp1.free)
assertTrue(255 in zp1.free)
assertTrue(199 in zp1.free)
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL,
listOf(50 .. 100, 200..255), true))
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false))
assertEquals(139, zp2.available())
assertFalse(50 in zp2.free)
assertFalse(100 in zp2.free)
@@ -178,7 +195,7 @@ class TestZeropage {
@Test
fun testBasicsafeAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
assertEquals(19, zp.available())
assertEquals(20, zp.available())
zp.allocate("", DataType.FLOAT, null)
assertFailsWith<ZeropageDepletedError> {
@@ -201,32 +218,28 @@ class TestZeropage {
@Test
fun testFullAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
assertEquals(238, zp.available())
val loc = zp.allocate("", DataType.FLOAT, null)
val loc = zp.allocate("", DataType.UWORD, null)
assertTrue(loc > 3)
assertFalse(loc in zp.free)
val num = zp.available() / 5
val rest = zp.available() % 5
val num = zp.available() / 2
for(i in 0..num-4) {
zp.allocate("", DataType.FLOAT, null)
zp.allocate("", DataType.UWORD, null)
}
assertEquals(18,zp.available())
assertEquals(6,zp.available())
assertFailsWith<ZeropageDepletedError> {
// can't allocate because no more sequential bytes, only fragmented
zp.allocate("", DataType.FLOAT, null)
zp.allocate("", DataType.UWORD, null)
}
for(i in 0..13) {
for(i in 0..5) {
zp.allocate("", DataType.UBYTE, null)
}
zp.allocate("", DataType.UWORD, null)
assertEquals(2, zp.available())
zp.allocate("", DataType.UBYTE, null)
zp.allocate("", DataType.UBYTE, null)
assertEquals(0, zp.available())
assertFailsWith<ZeropageDepletedError> {
// no more space
zp.allocate("", DataType.UBYTE, null)
@@ -236,7 +249,7 @@ class TestZeropage {
@Test
fun testEfficientAllocation() {
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
assertEquals(19, zp.available())
assertEquals(20, zp.available())
assertEquals(0x04, zp.allocate("", DataType.FLOAT, null))
assertEquals(0x09, zp.allocate("", DataType.UBYTE, null))
assertEquals(0x0d, zp.allocate("", DataType.UWORD, null))
@@ -245,6 +258,7 @@ class TestZeropage {
assertEquals(0xa9, zp.allocate("", DataType.UWORD, null))
assertEquals(0xb5, zp.allocate("", DataType.UWORD, null))
assertEquals(0xf7, zp.allocate("", DataType.UWORD, null))
assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null))
assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null))
assertEquals(0, zp.available())
}
+27 -2
View File
@@ -2,8 +2,33 @@
Writing and building a program
==============================
What is a "Program" anyway?
---------------------------
First, getting a working compiler
---------------------------------
Before you can compile Prog8 programs, you'll have to build the compiler itself.
First make sure you have installed the :ref:`requirements`.
Then you can choose a few ways to create the compiler:
**Using the shell script:**
#. run the "build_the_compiler.sh" shell script
#. it will create a "prog8compiler.jar" file which contains everything.
#. run the compiler with "java -jar prog8compiler.jar" to see how you can use it.
**using the Gradle build system:**
#. run the command "./gradlew installDist"
#. it will create the commands and required libraries in the "./compiler/build/install/p8compile/" directory
#. run the compiler with the "./compiler/build/install/p8compile/bin/p8compile" command to see how you can use it.
**download a precompiled version from github:**
#. download a recent "prog8compiler.jar" from `the releases on Github <https://github.com/irmen/prog8/releases>`_
#. run the compiler with "java -jar prog8compiler.jar" to see how you can use it.
What is a Prog8 "Program" anyway?
---------------------------------
A "complete runnable program" is a compiled, assembled, and linked together single unit.
It contains all of the program's code and data and has a certain file format that
+12 -3
View File
@@ -120,8 +120,12 @@ A recent .exe version of this tool for Windows can be obtained from my `clone <h
For other platforms it is very easy to compile it yourself (make ; make install).
A **Java runtime (jre or jdk), version 8 or newer** is required to run the packaged compiler.
If you're scared of Oracle's licensing terms, most Linux distributions ship OpenJDK instead
and for Windows it's possible to get that as well: for instance,
`Azul's Zulu <https://www.azul.com/downloads/zulu/>`_ is a certified OpenJDK
implementation available for various platforms.
A C-64 emulator or a real C-64 to run the programs on. The compiler assumes the presence
Finally: a **C-64 emulator** (or a real C-64 ofcourse) to run the programs on. The compiler assumes the presence
of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
.. hint::
@@ -130,11 +134,16 @@ of the `Vice emulator <http://vice-emu.sourceforge.net/>`_.
packaged jar file.
.. note::
To build the compiler from source, Kotlin SDK version 1.3 or newer is needed.
Building the compiler itself:
(re)building the compiler itself requires a Kotlin SDK version 1.3.
The compiler is developed using the `IntelliJ IDEA <https://www.jetbrains.com/idea/>`_
IDE from Jetbrains, with the Kotlin plugin (free community edition of this IDE is available).
But a bare Kotlin SDK installation should work just as well.
A shell script is provided to build and package the compiler from the command line.
A shell script (``build_the_compiler.sh``) is provided to build and package the compiler from the command line.
You can also use the Gradle build system to build the compiler (it will take care of
downloading all required libraries for you) by typing ``gradle installDist`` for instance.
The output of this gradle build will appear in the "./compiler/build/install/p8compile/" directory.
.. note::
Development and testing is done on Linux, but the compiler should run on most
+3 -2
View File
@@ -505,7 +505,6 @@ Subroutines are parts of the code that can be repeatedly invoked using a subrout
Their definition, using the ``sub`` statement, includes the specification of the required parameters and return value.
Subroutines can be defined in a Block, but also nested inside another subroutine. Everything is scoped accordingly.
Calling a subroutine
^^^^^^^^^^^^^^^^^^^^
@@ -514,9 +513,11 @@ It is possible to not store the return value but the compiler
will issue a warning then telling you the result values of a subroutine call are discarded.
.. caution::
Note that *recursive* subroutine calls are not supported at this time.
Note that due to the way parameters are processed by the compiler,
subroutines are *non-reentrant*. This means you cannot create recursive calls.
If you do need a recursive algorithm, you'll have to hand code it in embedded assembly for now,
or rewrite it into an iterative algorithm.
Also, subroutines used in the main program should not be used from an IRQ handler.
.. _builtinfunctions:
+7 -3
View File
@@ -60,16 +60,20 @@ Directives
- style ``kernalsafe`` -- use the part of the ZP that is 'free' or only used by BASIC routines,
and don't change anything else. This allows full use of KERNAL ROM routines (but not BASIC routines),
including default IRQs during normal system operation.
When the program exits, a system reset is performed (because BASIC will be in a corrupt state).
- style ``floatsafe`` -- like the previous one but also reserves the addresses that
are required to perform floating point operations (from the BASIC kernel). No clean exit is possible.
- style ``basicsafe`` -- the most restricted mode; only use the handful 'free' addresses in the ZP, and don't
touch change anything else. This allows full use of BASIC and KERNAL ROM routines including default IRQs
during normal system operation.
When the program exits, it simply returns to the BASIC ready prompt.
- style ``full`` -- claim the whole ZP for variables for the program, overwriting everything,
except the few addresses mentioned above that are used by the system's IRQ routine.
Even though the default IRQ routine is still active, it is impossible to use most BASIC and KERNAL ROM routines.
This includes many floating point operations and several utility routines that do I/O, such as ``print_string``.
It is also not possible to cleanly exit the program, other than resetting the machine.
This option makes programs smaller and faster because many more variables can
be stored in the ZP, which is more efficient.
As with ``kernalsafe``, it is not possible to cleanly exit the program, other than to reset the machine.
This option makes programs smaller and faster because even more variables can
be stored in the ZP (which allows for more efficient assembly code).
Also read :ref:`zeropage`.
+1 -5
View File
@@ -77,11 +77,6 @@ Theoretically they can all be used in a program, with the follwoing limitations:
- it's more convenient and safe to let the compiler allocate these addresses for you and just
use symbolic names in the program code.
.. todo::
There must be a way to tell the compiler which variables you require to be in Zeropage:
``zeropage`` modifier keyword on vardecl perhaps?
Prog8 knows what addresses are safe to use in the various ZP handling configurations.
It will use the free ZP addresses to place its ZP variables in,
until they're all used up. If instructed to output a program that takes over the entire
@@ -93,6 +88,7 @@ treats the ZP for the program. The default is to be reasonably restrictive to us
part of the ZP that is not used by the C64's kernal routines.
It's possible to claim the whole ZP as well (by disabling the operating system or kernal).
If you want, it's also possible to be more restricive and stay clear of the addresses used by BASIC routines too.
This allows the program to exit cleanly back to a BASIC ready prompt - something that is not possible in the other modes.
IRQs and the ZeroPage
+50 -1
View File
@@ -29,14 +29,63 @@ Add more compiler optimizations to the existing ones.
- on the language AST level
- on the StackVM intermediate code level
- on the final assembly source level
- can the parameter passing to subroutines be optimized to avoid copying?
- subroutines with 1 or 2 byte args (or 1 word arg) should be converted to asm calling convention with the args in A/Y register
this requires rethinking the way parameters are represented, simply injecting vardecls to
declare local variables for them is not always correct anymore
Also some library routines and code patterns could perhaps be optimized further
Eval stack redesign? (lot of work)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The eval stack is now a split lsb/msb stack using X as the stackpointer.
Is it easier/faster to just use a single page unsplit stack?
It could then even be moved into the zeropage to greatly reduce code size and slowness.
Or just move the LSB portion into a slab of the zeropage.
Allocate a fixed word in ZP that is the TOS so we can 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?
^^^^^^^^
A user defined struct type would be nice to group a bunch
of values together (and use it multiple times). Something like::
struct Point {
ubyte color
word[3] vec = [0,0,0]
}
Point p1
Point p2
Point p3
p1.color = 3
p1.vec[2] = 2
Misc
^^^^
- sqrt() should have integer implementation as well, instead of relying on float SQRT for all argument types
- code generation for POW instruction
- make sure user-defined blocks come BEFORE library blocks (this helps zeropage variable allocations)
- are there any other missing instructions in the code generator?
- implement %asmbinary
+2
View File
@@ -1,4 +1,6 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,5 +1,6 @@
%import c64utils
%import c64flt
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,5 +1,6 @@
%import c64utils
%import c64flt
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
Binary file not shown.
Binary file not shown.
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
; This example computes the first 20 values of the Fibonacci sequence.
; It uses the feature that variables that don't have an initialization value,
+1
View File
@@ -1,6 +1,7 @@
%import c64lib
%import c64utils
%import c64flt
%zeropage basicsafe
~ main {
+1
View File
@@ -1,5 +1,6 @@
%import c64utils
%import c64lib
%zeropage basicsafe
; The classic number guessing game.
; This version uses mostly high level subroutine calls and loops.
+1
View File
@@ -1,4 +1,5 @@
%import c64utils
%zeropage basicsafe
~ main {
+1
View File
@@ -1,5 +1,6 @@
%import c64utils
%import c64lib
%zeropage basicsafe
~ spritedata $0a00 {
+100
View File
@@ -0,0 +1,100 @@
~ main {
const ubyte boardOffsetX = 14
const ubyte boardOffsetY = 3
const ubyte boardWidth = 10
const ubyte boardHeight = 20
; 3x3, rotating around their center square:
ubyte[4] blockJ = [0, 4, 5, 6]
ubyte[4] blockL = [2, 4, 5, 6]
ubyte[4] blockS = [1, 2, 4, 5]
ubyte[4] blockT = [1, 4, 5, 6]
ubyte[4] blockZ = [0, 1, 5, 6]
;4x4, rotating around center:
ubyte[4] blockI = [4, 5, 6, 7]
ubyte[4] blockO = [1, 2, 5, 6]
; block colors I, J, L, O, S, T, Z: cyan, blue, orange, yellow, green, purple, red
ubyte[7] blockColors = [3, 6, 8, 7, 5, 4, 2]
ubyte[7] blockSizes = [4, 3, 3, 4, 3, 3, 3] ; needed for proper rotation? (or just use block num?)
ubyte[16] currentBlock
ubyte currentBlockSize ; 3 or 4
ubyte currentBlockNum
sub start() {
drawBoard()
for ubyte b in 7 to 0 step -1 {
newCurrentBlock(b)
drawBlock(3, 2+b*3, 102) ; 102 = stipple
drawBlock(boardOffsetX+3, 1+b*3, 160) ; 160 = block, 32 = erase (space)
}
while(true) {
; loop
}
}
sub drawBoard() {
c64scr.PLOT(1,1)
c64scr.print("teh▁triz")
c64scr.setcc(boardOffsetX-1, boardOffsetY+boardHeight, 124, 12)
c64scr.setcc(boardOffsetX+boardWidth, boardOffsetY+boardHeight, 126, 12)
ubyte i
for i in boardOffsetX+boardWidth-1 to boardOffsetX step -1
c64scr.setcc(i, boardOffsetY+boardHeight, 69, 11)
for i in boardOffsetY+boardHeight-1 to boardOffsetY step -1 {
c64scr.setcc(boardOffsetX-1, i, 89, 11)
c64scr.setcc(boardOffsetX+boardWidth, i, 84, 11)
}
}
sub newCurrentBlock(ubyte block) {
memset(currentBlock, len(currentBlock), 0)
currentBlockNum = block
currentBlockSize = blockSizes[block]
; @todo would be nice to have an explicit pointer type to reference the array, and code the loop only once...
ubyte blockCol = blockColors[block]
ubyte i
if block==0 { ; I
for i in blockI
currentBlock[i] = blockCol
}
else if block==1 { ; J
for i in blockJ
currentBlock[i] = blockCol
}
else if block==2 { ; L
for i in blockL
currentBlock[i] = blockCol
}
else if block==3 { ; O
for i in blockO
currentBlock[i] = blockCol
}
else if block==4 { ; S
for i in blockS
currentBlock[i] = blockCol
}
else if block==5 { ; T
for i in blockT
currentBlock[i] = blockCol
}
else if block==6 { ; Z
for i in blockZ
currentBlock[i] = blockCol
}
}
sub drawBlock(ubyte x, ubyte y, ubyte character) {
for ubyte i in 15 to 0 step -1 {
ubyte c=currentBlock[i]
if c
c64scr.setcc((i&3)+x, (i/4)+y, character, c)
}
}
}
+31 -24
View File
@@ -1,35 +1,42 @@
%import c64utils
%option enable_floats
%zeropage basicsafe
~ main {
; mul_word_3
sub start() {
ubyte @zp ub = 22
byte @zp b = 22
word @zp w = 2222
uword @zp uw = 2222
byte b1
byte b2 = -3
ubyte ub1
ubyte ub2 = 4
word w1
word w2 = -499
uword uw1
uword uw2 = 1199
b1 = b2*40
ub1 = ub2*40
w1 = w2*40
uw1 = uw2*40
c64scr.print_b(b1)
c64.CHROUT('\n')
c64scr.print_ub(ub1)
c64.CHROUT('\n')
c64scr.print_w(w1)
c64.CHROUT('\n')
c64scr.print_uw(uw1)
c64.CHROUT('\n')
c64.CHROUT('\n')
byte nonzp1 = 42
byte nonzp2 = 42
byte nonzp3 = 42
foo.bar()
c64scr.print_ub(X)
c64.CHROUT('\n')
}
}
~ foo {
sub bar() {
ubyte @zp ub = 33
byte @zp b = 33
word @zp w = 3333
uword @zp uw = 3333
word nonzp1 = 4444
word nonzp2 = 4444
word nonzp3 = 4444
A=55
}
}
+1
View File
@@ -1,5 +1,6 @@
%import c64utils
%import c64lib
%zeropage basicsafe
~ spritedata $0a00 {
+2
View File
@@ -0,0 +1,2 @@
org.gradle.caching=true
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+84
View File
@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+3 -1
View File
@@ -1,4 +1,6 @@
set PROG8CLASSPATH=./out/production/compiler;./out/production/parser
@echo off
set PROG8CLASSPATH=./out/production/compiler_main;./out/production/parser_main
set KOTLINPATH=%USERPROFILE%/.IdeaIC2018.3/config/plugins/Kotlin
set LIBJARS=%KOTLINPATH%/lib/kotlin-stdlib.jar;%KOTLINPATH%/lib/kotlin-reflect.jar;./parser/antlr/lib/antlr-runtime-4.7.2.jar
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env sh
PROG8CLASSPATH=./out/production/compiler:./out/production/parser
PROG8CLASSPATH=./out/production/compiler_main:./out/production/parser_main
KOTLINPATH=${HOME}/.IntelliJIdea2018.3/config/plugins/Kotlin
LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar:./parser/antlr/lib/antlr-runtime-4.7.2.jar
+3 -1
View File
@@ -1,4 +1,6 @@
set PROG8CLASSPATH=./out/production/compiler
@echo off
set PROG8CLASSPATH=./out/production/compiler_main
set KOTLINPATH=%USERPROFILE%/.IdeaIC2018.3/config/plugins/Kotlin
set LIBJARS=%KOTLINPATH%/lib/kotlin-stdlib.jar;%KOTLINPATH%/lib/kotlin-reflect.jar
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env sh
PROG8CLASSPATH=./out/production/compiler
PROG8CLASSPATH=./out/production/compiler_main
KOTLINPATH=${HOME}/.IntelliJIdea2018.3/config/plugins/Kotlin
LIBJARS=${KOTLINPATH}/lib/kotlin-stdlib.jar:${KOTLINPATH}/lib/kotlin-reflect.jar
+3
View File
@@ -10,6 +10,9 @@ NOTES:
grammar prog8;
@header {
package prog8.parser;
}
LINECOMMENT : [\r\n][ \t]* COMMENT -> channel(HIDDEN);
COMMENT : ';' ~[\r\n]* -> channel(HIDDEN) ;
+32
View File
@@ -0,0 +1,32 @@
plugins {
id 'antlr'
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
antlr 'org.antlr:antlr4:4.7.2'
}
compileJava {
dependsOn tasks.withType(AntlrTask)
}
generateGrammarSource {
outputDirectory = file("src/prog8/parser")
arguments += ["-no-listener","-no-visitor"]
}
sourceSets {
main {
java {
srcDirs = ["${project.projectDir}/src"]
}
antlr {
srcDirs = ["${project.projectDir}/antlr"]
}
}
}
+3 -1
View File
@@ -1,5 +1,7 @@
// Generated from /home/irmen/Projects/prog8/parser/antlr/prog8.g4 by ANTLR 4.7.2
// Generated from prog8.g4 by ANTLR 4.7.2
package prog8.parser;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
+3 -1
View File
@@ -1,5 +1,7 @@
// Generated from /home/irmen/Projects/prog8/parser/antlr/prog8.g4 by ANTLR 4.7.2
// Generated from prog8.g4 by ANTLR 4.7.2
package prog8.parser;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
+22
View File
@@ -0,0 +1,22 @@
<?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="FacetManager">
<facet type="Python" name="Python">
<configuration sdkName="Python 3.7" />
</facet>
</component>
<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" />
<orderEntry type="library" name="Python 3.7 interpreter library" level="application" />
</component>
</module>
+2
View File
@@ -0,0 +1,2 @@
include ':parser'
include ':compiler'