mirror of
https://github.com/irmen/prog8.git
synced 2025-02-18 05:30:34 +00:00
restructuring more things
This commit is contained in:
parent
ade7a4c398
commit
1794f704e7
@ -30,7 +30,7 @@ compileKotlin {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
verbose = true
|
verbose = true
|
||||||
freeCompilerArgs += "-XXLanguage:+NewInference -verbose"
|
// freeCompilerArgs += "-XXLanguage:+NewInference"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,30 +1,10 @@
|
|||||||
package prog8
|
package prog8
|
||||||
|
|
||||||
import prog8.ast.*
|
|
||||||
import prog8.ast.base.*
|
|
||||||
import prog8.ast.base.checkIdentifiers
|
|
||||||
import prog8.ast.base.checkRecursion
|
|
||||||
import prog8.ast.base.checkValid
|
|
||||||
import prog8.ast.base.reorderStatements
|
|
||||||
import prog8.ast.statements.Directive
|
|
||||||
import prog8.vm.astvm.AstVm
|
import prog8.vm.astvm.AstVm
|
||||||
import prog8.compiler.*
|
|
||||||
import prog8.compiler.target.c64.AsmGen
|
|
||||||
import prog8.compiler.target.c64.C64Zeropage
|
|
||||||
import prog8.optimizer.constantFold
|
|
||||||
import prog8.optimizer.optimizeStatements
|
|
||||||
import prog8.optimizer.simplifyExpressions
|
|
||||||
import prog8.parser.ParsingFailedError
|
|
||||||
import prog8.parser.importLibraryModule
|
|
||||||
import prog8.parser.importModule
|
|
||||||
import prog8.parser.moduleName
|
|
||||||
import prog8.vm.stackvm.stackVmMain
|
import prog8.vm.stackvm.stackVmMain
|
||||||
import java.io.File
|
import prog8.compiler.*
|
||||||
import java.io.PrintStream
|
|
||||||
import java.lang.Exception
|
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
@ -82,115 +62,8 @@ private fun compileMain(args: Array<String>) {
|
|||||||
usage()
|
usage()
|
||||||
|
|
||||||
val filepath = Paths.get(moduleFile).normalize()
|
val filepath = Paths.get(moduleFile).normalize()
|
||||||
var programname = "?"
|
|
||||||
lateinit var programAst: Program
|
|
||||||
|
|
||||||
try {
|
val (programAst, programName) = compileProgram(filepath, optimize, optimizeInlining, writeVmCode, writeAssembly)
|
||||||
val totalTime = measureTimeMillis {
|
|
||||||
// import main module and everything it needs
|
|
||||||
println("Parsing...")
|
|
||||||
programAst = Program(moduleName(filepath.fileName), mutableListOf())
|
|
||||||
importModule(programAst, filepath)
|
|
||||||
|
|
||||||
val compilerOptions = determineCompilationOptions(programAst)
|
|
||||||
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
|
||||||
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
|
||||||
|
|
||||||
// if we're producing a PRG or BASIC program, include the c64utils and c64lib libraries
|
|
||||||
if(compilerOptions.launcher==LauncherType.BASIC || compilerOptions.output==OutputType.PRG) {
|
|
||||||
importLibraryModule(programAst, "c64lib")
|
|
||||||
importLibraryModule(programAst, "c64utils")
|
|
||||||
}
|
|
||||||
|
|
||||||
// always import prog8lib and math
|
|
||||||
importLibraryModule(programAst, "math")
|
|
||||||
importLibraryModule(programAst, "prog8lib")
|
|
||||||
|
|
||||||
|
|
||||||
// perform initial syntax checks and constant folding
|
|
||||||
println("Syntax check...")
|
|
||||||
val time1= measureTimeMillis {
|
|
||||||
programAst.checkIdentifiers()
|
|
||||||
}
|
|
||||||
//println(" time1: $time1")
|
|
||||||
val time2 = measureTimeMillis {
|
|
||||||
programAst.constantFold()
|
|
||||||
}
|
|
||||||
//println(" time2: $time2")
|
|
||||||
val time3 = measureTimeMillis {
|
|
||||||
programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later
|
|
||||||
}
|
|
||||||
//println(" time3: $time3")
|
|
||||||
val time4 = measureTimeMillis {
|
|
||||||
programAst.checkValid(compilerOptions) // check if tree is valid
|
|
||||||
}
|
|
||||||
//println(" time4: $time4")
|
|
||||||
|
|
||||||
programAst.checkIdentifiers()
|
|
||||||
if(optimize) {
|
|
||||||
// optimize the parse tree
|
|
||||||
println("Optimizing...")
|
|
||||||
while (true) {
|
|
||||||
// keep optimizing expressions and statements until no more steps remain
|
|
||||||
val optsDone1 = programAst.simplifyExpressions()
|
|
||||||
val optsDone2 = programAst.optimizeStatements(optimizeInlining)
|
|
||||||
if (optsDone1 + optsDone2 == 0)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
programAst.checkValid(compilerOptions) // check if final tree is valid
|
|
||||||
programAst.checkRecursion() // check if there are recursive subroutine calls
|
|
||||||
|
|
||||||
// namespace.debugPrint()
|
|
||||||
|
|
||||||
// compile the syntax tree into stackvmProg form, and optimize that
|
|
||||||
val compiler = Compiler(programAst)
|
|
||||||
val intermediate = compiler.compile(compilerOptions)
|
|
||||||
if(optimize)
|
|
||||||
intermediate.optimize()
|
|
||||||
|
|
||||||
if(writeVmCode) {
|
|
||||||
val stackVmFilename = intermediate.name + ".vm.txt"
|
|
||||||
val stackvmFile = PrintStream(File(stackVmFilename), "utf-8")
|
|
||||||
intermediate.writeCode(stackvmFile)
|
|
||||||
stackvmFile.close()
|
|
||||||
println("StackVM program code written to '$stackVmFilename'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if(writeAssembly) {
|
|
||||||
val zeropage = C64Zeropage(compilerOptions)
|
|
||||||
intermediate.allocateZeropage(zeropage)
|
|
||||||
val assembly = AsmGen(compilerOptions, intermediate, programAst.heap, zeropage).compileToAssembly(optimize)
|
|
||||||
assembly.assemble(compilerOptions)
|
|
||||||
programname = assembly.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
|
|
||||||
|
|
||||||
} catch (px: ParsingFailedError) {
|
|
||||||
System.err.print("\u001b[91m") // bright red
|
|
||||||
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 *")
|
|
||||||
print("\u001b[0m") // reset
|
|
||||||
System.out.flush()
|
|
||||||
throw x
|
|
||||||
} catch (x: NotImplementedError) {
|
|
||||||
print("\u001b[91m") // bright red
|
|
||||||
println("\n* internal error: missing feature/code *")
|
|
||||||
print("\u001b[0m") // reset
|
|
||||||
System.out.flush()
|
|
||||||
throw x
|
|
||||||
}
|
|
||||||
|
|
||||||
if(launchAstVm) {
|
if(launchAstVm) {
|
||||||
println("\nLaunching AST-based vm...")
|
println("\nLaunching AST-based vm...")
|
||||||
@ -199,51 +72,19 @@ private fun compileMain(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(emulatorToStart.isNotEmpty()) {
|
if(emulatorToStart.isNotEmpty()) {
|
||||||
println("\nStarting C-64 emulator $emulatorToStart...")
|
if(programName==null)
|
||||||
val cmdline = listOf(emulatorToStart, "-silent", "-moncommands", "$programname.vice-mon-list",
|
println("\nCan't start emulator because no program was assembled.")
|
||||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programname+".prg")
|
else {
|
||||||
val process = ProcessBuilder(cmdline).inheritIO().start()
|
println("\nStarting C-64 emulator $emulatorToStart...")
|
||||||
process.waitFor()
|
val cmdline = listOf(emulatorToStart, "-silent", "-moncommands", "$programName.vice-mon-list",
|
||||||
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programName + ".prg")
|
||||||
|
val process = ProcessBuilder(cmdline).inheritIO().start()
|
||||||
|
process.waitFor()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun determineCompilationOptions(program: Program): CompilationOptions {
|
|
||||||
val mainModule = program.modules.first()
|
|
||||||
val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" }
|
|
||||||
as? Directive)?.args?.single()?.name?.toUpperCase()
|
|
||||||
val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" }
|
|
||||||
as? Directive)?.args?.single()?.name?.toUpperCase()
|
|
||||||
mainModule.loadAddress = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%address" }
|
|
||||||
as? Directive)?.args?.single()?.int ?: 0
|
|
||||||
val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" }
|
|
||||||
as? Directive)?.args?.single()?.name?.toUpperCase()
|
|
||||||
val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet()
|
|
||||||
val floatsEnabled = allOptions.any { it.name == "enable_floats" }
|
|
||||||
val zpType: ZeropageType =
|
|
||||||
if (zpoption == null)
|
|
||||||
if(floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
|
|
||||||
else
|
|
||||||
try {
|
|
||||||
ZeropageType.valueOf(zpoption)
|
|
||||||
} catch (x: IllegalArgumentException) {
|
|
||||||
ZeropageType.KERNALSAFE
|
|
||||||
// error will be printed by the astchecker
|
|
||||||
}
|
|
||||||
val zpReserved = mainModule.statements
|
|
||||||
.asSequence()
|
|
||||||
.filter { it is Directive && it.directive == "%zpreserved" }
|
|
||||||
.map { (it as Directive).args }
|
|
||||||
.map { it[0].int!!..it[1].int!! }
|
|
||||||
.toList()
|
|
||||||
|
|
||||||
return CompilationOptions(
|
|
||||||
if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType),
|
|
||||||
if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
|
|
||||||
zpType, zpReserved, floatsEnabled
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun usage() {
|
private fun usage() {
|
||||||
System.err.println("Missing argument(s):")
|
System.err.println("Missing argument(s):")
|
||||||
System.err.println(" [-emu] auto-start the 'x64' C-64 emulator after successful compilation")
|
System.err.println(" [-emu] auto-start the 'x64' C-64 emulator after successful compilation")
|
||||||
|
@ -6,7 +6,6 @@ import prog8.ast.processing.IAstProcessor
|
|||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.IntegerOrAddressOf
|
import prog8.compiler.IntegerOrAddressOf
|
||||||
import prog8.compiler.RuntimeValue
|
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import prog8.functions.NotConstArgumentException
|
import prog8.functions.NotConstArgumentException
|
||||||
@ -14,6 +13,10 @@ import prog8.functions.builtinFunctionReturnType
|
|||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
|
||||||
|
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
||||||
|
|
||||||
|
|
||||||
class PrefixExpression(val operator: String, var expression: IExpression, override val position: Position) : IExpression {
|
class PrefixExpression(val operator: String, var expression: IExpression, override val position: Position) : IExpression {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
@ -253,8 +256,9 @@ class TypecastExpression(var expression: IExpression, var type: DataType, val im
|
|||||||
override fun inferType(program: Program): DataType? = type
|
override fun inferType(program: Program): DataType? = type
|
||||||
override fun constValue(program: Program): LiteralValue? {
|
override fun constValue(program: Program): LiteralValue? {
|
||||||
val cv = expression.constValue(program) ?: return null
|
val cv = expression.constValue(program) ?: return null
|
||||||
val value = RuntimeValue(cv.type, cv.asNumericValue!!).cast(type)
|
return cv.cast(type)
|
||||||
return LiteralValue.fromNumber(value.numericValue(), value.type, position)
|
// val value = RuntimeValue(cv.type, cv.asNumericValue!!).cast(type)
|
||||||
|
// return LiteralValue.fromNumber(value.numericValue(), value.type, position).cast(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
@ -481,7 +485,7 @@ open class LiteralValue(val type: DataType,
|
|||||||
throw ExpressionError("cannot order compare type $type with ${other.type}", other.position)
|
throw ExpressionError("cannot order compare type $type with ${other.type}", other.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun intoDatatype(targettype: DataType): LiteralValue? {
|
fun cast(targettype: DataType): LiteralValue? {
|
||||||
if(type==targettype)
|
if(type==targettype)
|
||||||
return this
|
return this
|
||||||
when(type) {
|
when(type) {
|
||||||
|
@ -177,7 +177,7 @@ internal class AstIdentifiersChecker(private val namespace: INameScope) : IAstPr
|
|||||||
for(returnvalue in returnStmt.values.zip(subroutine.returntypes)) {
|
for(returnvalue in returnStmt.values.zip(subroutine.returntypes)) {
|
||||||
val lval = returnvalue.first as? LiteralValue
|
val lval = returnvalue.first as? LiteralValue
|
||||||
if(lval!=null) {
|
if(lval!=null) {
|
||||||
val adjusted = lval.intoDatatype(returnvalue.second)
|
val adjusted = lval.cast(returnvalue.second)
|
||||||
if(adjusted!=null && adjusted !== lval)
|
if(adjusted!=null && adjusted !== lval)
|
||||||
newValues.add(adjusted)
|
newValues.add(adjusted)
|
||||||
else
|
else
|
||||||
|
@ -46,7 +46,7 @@ internal class VarInitValueAndAddressOfCreator(private val namespace: INameScope
|
|||||||
val declvalue = decl.value!!
|
val declvalue = decl.value!!
|
||||||
val value =
|
val value =
|
||||||
if(declvalue is LiteralValue) {
|
if(declvalue is LiteralValue) {
|
||||||
val converted = declvalue.intoDatatype(decl.datatype)
|
val converted = declvalue.cast(decl.datatype)
|
||||||
converted ?: declvalue
|
converted ?: declvalue
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -11,6 +11,7 @@ import prog8.compiler.intermediate.Opcode
|
|||||||
import prog8.compiler.intermediate.branchOpcodes
|
import prog8.compiler.intermediate.branchOpcodes
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import prog8.parser.tryGetEmbeddedResource
|
import prog8.parser.tryGetEmbeddedResource
|
||||||
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.vm.stackvm.Syscall
|
import prog8.vm.stackvm.Syscall
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
175
compiler/src/prog8/compiler/Main.kt
Normal file
175
compiler/src/prog8/compiler/Main.kt
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package prog8.compiler
|
||||||
|
|
||||||
|
import prog8.ast.Program
|
||||||
|
import prog8.ast.base.*
|
||||||
|
import prog8.ast.base.checkIdentifiers
|
||||||
|
import prog8.ast.base.checkValid
|
||||||
|
import prog8.ast.base.reorderStatements
|
||||||
|
import prog8.ast.statements.Directive
|
||||||
|
import prog8.compiler.target.c64.AsmGen
|
||||||
|
import prog8.compiler.target.c64.C64Zeropage
|
||||||
|
import prog8.optimizer.constantFold
|
||||||
|
import prog8.optimizer.optimizeStatements
|
||||||
|
import prog8.optimizer.simplifyExpressions
|
||||||
|
import prog8.parser.ParsingFailedError
|
||||||
|
import prog8.parser.importLibraryModule
|
||||||
|
import prog8.parser.importModule
|
||||||
|
import prog8.parser.moduleName
|
||||||
|
import java.io.File
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
fun compileProgram(filepath: Path,
|
||||||
|
optimize: Boolean, optimizeInlining: Boolean,
|
||||||
|
writeVmCode: Boolean, writeAssembly: Boolean): Pair<Program, String?> {
|
||||||
|
lateinit var programAst: Program
|
||||||
|
var programName: String? = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
val totalTime = measureTimeMillis {
|
||||||
|
// import main module and everything it needs
|
||||||
|
println("Parsing...")
|
||||||
|
programAst = Program(moduleName(filepath.fileName), mutableListOf())
|
||||||
|
importModule(programAst, filepath)
|
||||||
|
|
||||||
|
val compilerOptions = determineCompilationOptions(programAst)
|
||||||
|
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
||||||
|
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
||||||
|
|
||||||
|
// if we're producing a PRG or BASIC program, include the c64utils and c64lib libraries
|
||||||
|
if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) {
|
||||||
|
importLibraryModule(programAst, "c64lib")
|
||||||
|
importLibraryModule(programAst, "c64utils")
|
||||||
|
}
|
||||||
|
|
||||||
|
// always import prog8lib and math
|
||||||
|
importLibraryModule(programAst, "math")
|
||||||
|
importLibraryModule(programAst, "prog8lib")
|
||||||
|
|
||||||
|
|
||||||
|
// perform initial syntax checks and constant folding
|
||||||
|
println("Syntax check...")
|
||||||
|
val time1 = measureTimeMillis {
|
||||||
|
programAst.checkIdentifiers()
|
||||||
|
}
|
||||||
|
//println(" time1: $time1")
|
||||||
|
val time2 = measureTimeMillis {
|
||||||
|
programAst.constantFold()
|
||||||
|
}
|
||||||
|
//println(" time2: $time2")
|
||||||
|
val time3 = measureTimeMillis {
|
||||||
|
programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later
|
||||||
|
}
|
||||||
|
//println(" time3: $time3")
|
||||||
|
val time4 = measureTimeMillis {
|
||||||
|
programAst.checkValid(compilerOptions) // check if tree is valid
|
||||||
|
}
|
||||||
|
//println(" time4: $time4")
|
||||||
|
|
||||||
|
programAst.checkIdentifiers()
|
||||||
|
if (optimize) {
|
||||||
|
// optimize the parse tree
|
||||||
|
println("Optimizing...")
|
||||||
|
while (true) {
|
||||||
|
// keep optimizing expressions and statements until no more steps remain
|
||||||
|
val optsDone1 = programAst.simplifyExpressions()
|
||||||
|
val optsDone2 = programAst.optimizeStatements(optimizeInlining)
|
||||||
|
if (optsDone1 + optsDone2 == 0)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
programAst.checkValid(compilerOptions) // check if final tree is valid
|
||||||
|
programAst.checkRecursion() // check if there are recursive subroutine calls
|
||||||
|
|
||||||
|
// namespace.debugPrint()
|
||||||
|
|
||||||
|
// compile the syntax tree into stackvmProg form, and optimize that
|
||||||
|
val compiler = Compiler(programAst)
|
||||||
|
val intermediate = compiler.compile(compilerOptions)
|
||||||
|
if (optimize)
|
||||||
|
intermediate.optimize()
|
||||||
|
|
||||||
|
if (writeVmCode) {
|
||||||
|
val stackVmFilename = intermediate.name + ".vm.txt"
|
||||||
|
val stackvmFile = PrintStream(File(stackVmFilename), "utf-8")
|
||||||
|
intermediate.writeCode(stackvmFile)
|
||||||
|
stackvmFile.close()
|
||||||
|
println("StackVM program code written to '$stackVmFilename'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeAssembly) {
|
||||||
|
val zeropage = C64Zeropage(compilerOptions)
|
||||||
|
intermediate.allocateZeropage(zeropage)
|
||||||
|
val assembly = AsmGen(compilerOptions, intermediate, programAst.heap, zeropage).compileToAssembly(optimize)
|
||||||
|
assembly.assemble(compilerOptions)
|
||||||
|
programName = assembly.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
|
||||||
|
|
||||||
|
} catch (px: ParsingFailedError) {
|
||||||
|
System.err.print("\u001b[91m") // bright red
|
||||||
|
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 *")
|
||||||
|
print("\u001b[0m") // reset
|
||||||
|
System.out.flush()
|
||||||
|
throw x
|
||||||
|
} catch (x: NotImplementedError) {
|
||||||
|
print("\u001b[91m") // bright red
|
||||||
|
println("\n* internal error: missing feature/code *")
|
||||||
|
print("\u001b[0m") // reset
|
||||||
|
System.out.flush()
|
||||||
|
throw x
|
||||||
|
}
|
||||||
|
return Pair(programAst, programName)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun determineCompilationOptions(program: Program): CompilationOptions {
|
||||||
|
val mainModule = program.modules.first()
|
||||||
|
val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" }
|
||||||
|
as? Directive)?.args?.single()?.name?.toUpperCase()
|
||||||
|
val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" }
|
||||||
|
as? Directive)?.args?.single()?.name?.toUpperCase()
|
||||||
|
mainModule.loadAddress = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%address" }
|
||||||
|
as? Directive)?.args?.single()?.int ?: 0
|
||||||
|
val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" }
|
||||||
|
as? Directive)?.args?.single()?.name?.toUpperCase()
|
||||||
|
val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet()
|
||||||
|
val floatsEnabled = allOptions.any { it.name == "enable_floats" }
|
||||||
|
val zpType: ZeropageType =
|
||||||
|
if (zpoption == null)
|
||||||
|
if(floatsEnabled) ZeropageType.FLOATSAFE else ZeropageType.KERNALSAFE
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
ZeropageType.valueOf(zpoption)
|
||||||
|
} catch (x: IllegalArgumentException) {
|
||||||
|
ZeropageType.KERNALSAFE
|
||||||
|
// error will be printed by the astchecker
|
||||||
|
}
|
||||||
|
val zpReserved = mainModule.statements
|
||||||
|
.asSequence()
|
||||||
|
.filter { it is Directive && it.directive == "%zpreserved" }
|
||||||
|
.map { (it as Directive).args }
|
||||||
|
.map { it[0].int!!..it[1].int!! }
|
||||||
|
.toList()
|
||||||
|
|
||||||
|
return CompilationOptions(
|
||||||
|
if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType),
|
||||||
|
if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
|
||||||
|
zpType, zpReserved, floatsEnabled
|
||||||
|
)
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package prog8.compiler.intermediate
|
package prog8.compiler.intermediate
|
||||||
|
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.vm.stackvm.Syscall
|
import prog8.vm.stackvm.Syscall
|
||||||
|
|
||||||
open class Instruction(val opcode: Opcode,
|
open class Instruction(val opcode: Opcode,
|
||||||
|
@ -5,7 +5,7 @@ import prog8.ast.base.*
|
|||||||
import prog8.ast.base.printWarning
|
import prog8.ast.base.printWarning
|
||||||
import prog8.ast.expressions.LiteralValue
|
import prog8.ast.expressions.LiteralValue
|
||||||
import prog8.ast.statements.VarDecl
|
import prog8.ast.statements.VarDecl
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.CompilerException
|
import prog8.compiler.CompilerException
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.Zeropage
|
import prog8.compiler.Zeropage
|
||||||
|
@ -7,7 +7,7 @@ import prog8.ast.antlr.escape
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.initvarsSubName
|
import prog8.ast.base.initvarsSubName
|
||||||
import prog8.ast.base.printWarning
|
import prog8.ast.base.printWarning
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
import prog8.compiler.intermediate.*
|
import prog8.compiler.intermediate.*
|
||||||
import prog8.vm.stackvm.Syscall
|
import prog8.vm.stackvm.Syscall
|
||||||
|
@ -9,9 +9,6 @@ import prog8.ast.expressions.LiteralValue
|
|||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
|
||||||
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
|
||||||
|
|
||||||
|
|
||||||
class ConstExprEvaluator {
|
class ConstExprEvaluator {
|
||||||
|
|
||||||
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression {
|
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression {
|
||||||
|
@ -222,7 +222,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
|
|||||||
val expectedDt = arg.second.type
|
val expectedDt = arg.second.type
|
||||||
val argConst = arg.first.value.constValue(program)
|
val argConst = arg.first.value.constValue(program)
|
||||||
if(argConst!=null && argConst.type!=expectedDt) {
|
if(argConst!=null && argConst.type!=expectedDt) {
|
||||||
val convertedValue = argConst.intoDatatype(expectedDt)
|
val convertedValue = argConst.cast(expectedDt)
|
||||||
if(convertedValue!=null) {
|
if(convertedValue!=null) {
|
||||||
functionCall.arglist[arg.first.index] = convertedValue
|
functionCall.arglist[arg.first.index] = convertedValue
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
@ -550,11 +550,11 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
|
|||||||
override fun process(forLoop: ForLoop): IStatement {
|
override fun process(forLoop: ForLoop): IStatement {
|
||||||
|
|
||||||
fun adjustRangeDt(rangeFrom: LiteralValue, targetDt: DataType, rangeTo: LiteralValue, stepLiteral: LiteralValue?, range: RangeExpr): RangeExpr {
|
fun adjustRangeDt(rangeFrom: LiteralValue, targetDt: DataType, rangeTo: LiteralValue, stepLiteral: LiteralValue?, range: RangeExpr): RangeExpr {
|
||||||
val newFrom = rangeFrom.intoDatatype(targetDt)
|
val newFrom = rangeFrom.cast(targetDt)
|
||||||
val newTo = rangeTo.intoDatatype(targetDt)
|
val newTo = rangeTo.cast(targetDt)
|
||||||
if (newFrom != null && newTo != null) {
|
if (newFrom != null && newTo != null) {
|
||||||
val newStep: IExpression =
|
val newStep: IExpression =
|
||||||
if (stepLiteral != null) (stepLiteral.intoDatatype(targetDt) ?: stepLiteral) else range.step
|
if (stepLiteral != null) (stepLiteral.cast(targetDt) ?: stepLiteral) else range.step
|
||||||
return RangeExpr(newFrom, newTo, newStep, range.position)
|
return RangeExpr(newFrom, newTo, newStep, range.position)
|
||||||
}
|
}
|
||||||
return range
|
return range
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package prog8.compiler
|
package prog8.vm
|
||||||
|
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.LiteralValue
|
import prog8.ast.expressions.LiteralValue
|
||||||
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
@ -6,8 +6,8 @@ import prog8.ast.base.initvarsSubName
|
|||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.expressions.LiteralValue
|
import prog8.ast.expressions.LiteralValue
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.RuntimeValueRange
|
import prog8.vm.RuntimeValueRange
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import java.awt.EventQueue
|
import java.awt.EventQueue
|
||||||
import kotlin.NoSuchElementException
|
import kotlin.NoSuchElementException
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package prog8.vm.astvm
|
package prog8.vm.astvm
|
||||||
|
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import java.lang.Math.toDegrees
|
import java.lang.Math.toDegrees
|
||||||
import java.lang.Math.toRadians
|
import java.lang.Math.toRadians
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -9,8 +9,8 @@ import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
|
|||||||
import prog8.ast.statements.Label
|
import prog8.ast.statements.Label
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
import prog8.ast.statements.VarDecl
|
import prog8.ast.statements.VarDecl
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.RuntimeValueRange
|
import prog8.vm.RuntimeValueRange
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
|
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
|
||||||
@ -106,8 +106,8 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
|||||||
DataType.UWORD -> RuntimeValue(DataType.UWORD, ctx.mem.getUWord(address))
|
DataType.UWORD -> RuntimeValue(DataType.UWORD, ctx.mem.getUWord(address))
|
||||||
DataType.WORD -> RuntimeValue(DataType.WORD, ctx.mem.getSWord(address))
|
DataType.WORD -> RuntimeValue(DataType.WORD, ctx.mem.getSWord(address))
|
||||||
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, ctx.mem.getFloat(address))
|
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, ctx.mem.getFloat(address))
|
||||||
DataType.STR -> RuntimeValue(DataType.STR, str=ctx.mem.getString(address))
|
DataType.STR -> RuntimeValue(DataType.STR, str = ctx.mem.getString(address))
|
||||||
DataType.STR_S -> RuntimeValue(DataType.STR_S, str=ctx.mem.getScreencodeString(address))
|
DataType.STR_S -> RuntimeValue(DataType.STR_S, str = ctx.mem.getScreencodeString(address))
|
||||||
else -> TODO("memvar $variable")
|
else -> TODO("memvar $variable")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import prog8.ast.expressions.LiteralValue
|
|||||||
import prog8.ast.processing.IAstProcessor
|
import prog8.ast.processing.IAstProcessor
|
||||||
import prog8.ast.statements.VarDecl
|
import prog8.ast.statements.VarDecl
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
|
|
||||||
class VariablesCreator(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstProcessor {
|
class VariablesCreator(private val runtimeVariables: RuntimeVariables, private val heap: HeapValues) : IAstProcessor {
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import prog8.ast.antlr.unescape
|
|||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.AddressOf
|
import prog8.ast.expressions.AddressOf
|
||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.IntegerOrAddressOf
|
import prog8.compiler.IntegerOrAddressOf
|
||||||
import prog8.compiler.intermediate.*
|
import prog8.compiler.intermediate.*
|
||||||
|
@ -7,7 +7,7 @@ import prog8.ast.base.Register
|
|||||||
import prog8.ast.base.initvarsSubName
|
import prog8.ast.base.initvarsSubName
|
||||||
import prog8.vm.astvm.BitmapScreenPanel
|
import prog8.vm.astvm.BitmapScreenPanel
|
||||||
import prog8.vm.astvm.Memory
|
import prog8.vm.astvm.Memory
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.IntegerOrAddressOf
|
import prog8.compiler.IntegerOrAddressOf
|
||||||
import prog8.compiler.intermediate.Instruction
|
import prog8.compiler.intermediate.Instruction
|
||||||
|
@ -3,7 +3,7 @@ package prog8tests
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import prog8.ast.base.ByteDatatypes
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.IterableDatatypes
|
import prog8.ast.base.IterableDatatypes
|
||||||
import prog8.ast.base.WordDatatypes
|
import prog8.ast.base.WordDatatypes
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.intermediate.Instruction
|
import prog8.compiler.intermediate.Instruction
|
||||||
import prog8.compiler.intermediate.Opcode
|
import prog8.compiler.intermediate.Opcode
|
||||||
|
@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.LiteralValue
|
import prog8.ast.expressions.LiteralValue
|
||||||
import prog8.compiler.RuntimeValue
|
import prog8.vm.RuntimeValue
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
import prog8.compiler.target.c64.*
|
import prog8.compiler.target.c64.*
|
||||||
import java.io.CharConversionException
|
import java.io.CharConversionException
|
||||||
|
Loading…
x
Reference in New Issue
Block a user