matrix decl parsing and fixes

This commit is contained in:
Irmen de Jong 2018-09-12 00:51:48 +02:00
parent e71fef709a
commit efd3b1f5c6
13 changed files with 304 additions and 168 deletions

View File

@ -164,18 +164,20 @@ Values will usually be part of an expression or assignment statement::
byte counter = 42 ; variable of size 8 bits, with initial value 42
byte[4] array = [1, 2, 3, 4] ; initialize the array
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
Array and Matrix (2-dimensional array) types are also supported in a limited way::
byte[4] array = [1, 2, 3, 4] ; initialize the array
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
byte[100] array = 100 to 199 ; initialize array with [100, 101, ..., 198, 199]
byte[2,3] matrix = 1 ; a matrix of 2*3=6 bytes all with value 1
byte[2,3] matrix = [1,2,3,4,5,6] ; a 2*3 matrix with value |(1,2) (3,4) (5,6)|
Note that the various keywords for the data type and variable type (``byte``, ``word``, ``const``, etc.)
cannot be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte``
for instance.
.. todo::
matrix datatype
.. todo::
There must be a way to tell the compiler which variables you require to be in Zeropage:
``zeropage`` modifier keyword on vardecl perhaps?

View File

@ -197,22 +197,23 @@ Variable declarations
^^^^^^^^^^^^^^^^^^^^^
Variables should be declared with their exact type and size so the compiler can allocate storage
for them. You can give them an initial value as well. That value can be a simple literal value,
but you can put a (constant) expression there as well. The syntax is::
for them. You must give them an initial value as well. That value can be a simple literal value,
or a (constant) expression. The syntax is::
<datatype> <variable name> [ = <initial value> ]
Various examples::
word thing
byte counter = 0
byte age = 2018 - 1974
float wallet = 55.25
str name = "my name is Irmen"
word address = #counter
byte[5] values = [11, 22, 33, 44, 55]
byte[5] values = 255 ; initialize with five 255 bytes
byte[5][6] empty_matrix
word thing = 0
byte counter = len([1, 2, 3]) * 20
byte age = 2018 - 1974
float wallet = 55.25
str name = "my name is Irmen"
word address = #counter
byte[5] values = [11, 22, 33, 44, 55]
byte[5] values = 255 ; initialize with five 255 bytes
byte[5][6] empty_matrix = 0 ; initialize with 30 zero bytes
byte[2][3] other_matrix = [1,2,3,4,5,6] ; 2*3 matrix with value | (1,2) (3,4) (5,6) |
@ -348,11 +349,12 @@ range creation: ``to``
}
array indexing: ``[`` *index* ``]``
When put after a sequence type (array, string or matrix) it means to point to the given element in that sequence::
.. todo::
array indexing: ``[`` *index* ``]``
When put after a sequence type (array, string or matrix) it means to point to the given element in that sequence::
array[2] ; the third byte in the array (index is 0-based)
matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
array[2] ; the third byte in the array (index is 0-based)
matrix[4,2] ; the byte at the 5th column and 3rd row in the matrix
precedence grouping in expressions, or subroutine parameter list: ``(`` *expression* ``)``

View File

@ -20,10 +20,10 @@ input.result word 0
nop
syscall WRITE_MEMSTR w:1000
loop:
inc_var "main.textcolor"
inc_var main.textcolor
syscall RANDOM
syscall RANDOM
push_var "main.textcolor"
push_var main.textcolor
syscall GFX_PIXEL
; syscall WRITE_VAR "input.prompt"
; syscall INPUT_VAR "input.result"

View File

@ -4,10 +4,20 @@
%import c64lib
~ not_main $d000 {
const float len1 = 111 ;len([1,2,3])
const float round1 = 111 ;len([1,2,3])
const float sin1 = 111 ;len([1,2,3])
float cos1 = 111 ;len([1,2,3])
byte [100] array1 = 0
word [100] array2 = 1
byte [2,3] matrix1 = 2
byte [2,3] matrix2 = [1,2,3,4,5,6]
const byte [100] carray1 = 0
const word [100] carray2 = 1
const byte [2,3] cmatrix1 = [1,2,3,4,5,255]
const float len1 = len([1,2,3])
const float round1 = len([1,2,3])
const float sin1 = len([1,2,3])
float cos1 = len([1,2,3])
}
~ main $c003 {

View File

@ -62,6 +62,7 @@ fun main(args: Array<String>) {
val compiler = Compiler(compilerOptions)
val intermediate = compiler.compile(moduleAst)
intermediate.optimize()
intermediate.toTextLines().forEach { println(it) }
// val assembly = stackvmProg.compileToAssembly()
//

View File

@ -68,15 +68,15 @@ class NameError(override var message: String, val position: Position?) : AstExce
}
}
open class ExpressionException(message: String, val position: Position?) : AstException(message) {
open class ExpressionError(message: String, val position: Position?) : AstException(message) {
override fun toString(): String {
val location = position?.toString() ?: ""
return "$location Error: $message"
}
}
class UndefinedSymbolException(symbol: IdentifierReference)
: ExpressionException("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)
class UndefinedSymbolError(symbol: IdentifierReference)
: ExpressionError("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
@ -514,26 +514,17 @@ enum class VarDeclType {
}
class VarDecl(val type: VarDeclType,
declaredDatatype: DataType,
private val declaredDatatype: DataType,
val arrayspec: ArraySpec?,
val name: String,
var value: IExpression?) : IStatement {
override var position: Position? = null
override lateinit var parent: Node
val datatype: DataType
init {
datatype = when {
arrayspec!=null -> // it's not a scalar, adjust the datatype
when(declaredDatatype) {
DataType.BYTE -> DataType.ARRAY
DataType.WORD -> DataType.ARRAY_W
DataType.MATRIX -> TODO()
else -> throw FatalAstException("invalid vardecl array datatype $declaredDatatype at $position")
}
else -> declaredDatatype
}
}
// note: the actual datatype will be determined somewhat later (in the ast checker phase)
// (we don't do it at init time, because we have to have a way to create a proper syntax error instead of a crash)
lateinit var datatype: DataType
override fun linkParents(parent: Node) {
this.parent = parent
arrayspec?.linkParents(this)
@ -543,10 +534,52 @@ class VarDecl(val type: VarDeclType,
override fun process(processor: IAstProcessor) = processor.process(this)
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
val memorySize: Int
get() = when(datatype) {
DataType.BYTE -> 1
DataType.WORD -> 2
DataType.FLOAT -> 5 // MFLPT5
DataType.STR,
DataType.STR_P,
DataType.STR_S,
DataType.STR_PS -> {
val lv = value as? LiteralValue ?: throw ExpressionError("need constant initializer value expression", position)
lv.strvalue!!.length + 1
}
DataType.ARRAY -> {
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
aX.intvalue!!
}
DataType.ARRAY_W -> {
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
2*aX.intvalue!!
}
DataType.MATRIX -> {
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
val aY = arrayspec.y as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
aX.intvalue!! * aY.intvalue!!
}
}
override fun toString(): String {
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
}
fun setDatatype() {
datatype =
when {
arrayspec == null -> declaredDatatype
arrayspec.y!=null -> when (declaredDatatype) {
DataType.BYTE -> DataType.MATRIX
else -> throw SyntaxError("matrix can only contain bytes", position)
}
else -> when (declaredDatatype) {
DataType.BYTE -> DataType.ARRAY
DataType.WORD -> DataType.ARRAY_W
else -> throw SyntaxError("array can only contain bytes or words", position)
}
}
}
}
@ -719,10 +752,10 @@ data class IdentifierReference(val nameInSource: List<String>) : IExpression {
override fun constValue(namespace: INameScope): LiteralValue? {
val node = namespace.lookup(nameInSource, this)
?: throw UndefinedSymbolException(this)
?: throw UndefinedSymbolError(this)
val vardecl = node as? VarDecl
if(vardecl==null) {
throw ExpressionException("name should be a constant, instead of: ${node::class.simpleName}", position)
throw ExpressionError("name should be a constant, instead of: ${node::class.simpleName}", position)
} else if(vardecl.type!=VarDeclType.CONST) {
return null
}
@ -813,12 +846,12 @@ class FunctionCall(override var target: IdentifierReference, override var arglis
"ceil" -> builtinCeil(arglist, position, namespace)
"lsl" -> builtinLsl(arglist, position, namespace)
"lsr" -> builtinLsr(arglist, position, namespace)
"rol" -> throw ExpressionException("builtin function rol can't be used in expressions because it doesn't return a value", position)
"rol2" -> throw ExpressionException("builtin function rol2 can't be used in expressions because it doesn't return a value", position)
"ror" -> throw ExpressionException("builtin function ror can't be used in expressions because it doesn't return a value", position)
"ror2" -> throw ExpressionException("builtin function ror2 can't be used in expressions because it doesn't return a value", position)
"P_carry" -> throw ExpressionException("builtin function P_carry can't be used in expressions because it doesn't return a value", position)
"P_irqd" -> throw ExpressionException("builtin function P_irqd can't be used in expressions because it doesn't return a value", position)
"rol" -> throw ExpressionError("builtin function rol can't be used in expressions because it doesn't return a value", position)
"rol2" -> throw ExpressionError("builtin function rol2 can't be used in expressions because it doesn't return a value", position)
"ror" -> throw ExpressionError("builtin function ror can't be used in expressions because it doesn't return a value", position)
"ror2" -> throw ExpressionError("builtin function ror2 can't be used in expressions because it doesn't return a value", position)
"P_carry" -> throw ExpressionError("builtin function P_carry can't be used in expressions because it doesn't return a value", position)
"P_irqd" -> throw ExpressionError("builtin function P_irqd can't be used in expressions because it doesn't return a value", position)
else -> null
}
}

View File

@ -26,9 +26,9 @@ fun Module.checkValid(globalNamespace: INameScope, compilerOptions: CompilationO
*/
class AstChecker(private val namespace: INameScope, private val compilerOptions: CompilationOptions) : IAstProcessor {
private val checkResult: MutableList<SyntaxError> = mutableListOf()
private val checkResult: MutableList<AstException> = mutableListOf()
fun result(): List<SyntaxError> {
fun result(): List<AstException> {
return checkResult
}
@ -122,13 +122,21 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
*/
override fun process(assignment: Assignment): IStatement {
if(assignment.target.identifier!=null) {
val targetSymbol = namespace.lookup(assignment.target.identifier!!.nameInSource, assignment)
if(targetSymbol !is VarDecl) {
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
return super.process(assignment)
} else if(targetSymbol.type==VarDeclType.CONST) {
checkResult.add(SyntaxError("cannot assign new value to a constant", assignment.position))
return super.process(assignment)
val targetName = assignment.target.identifier!!.nameInSource
val targetSymbol = namespace.lookup(targetName, assignment)
when {
targetSymbol == null -> {
checkResult.add(ExpressionError("undefined symbol: ${targetName.joinToString(".")}", assignment.position))
return super.process(assignment)
}
targetSymbol !is VarDecl -> {
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
return super.process(assignment)
}
targetSymbol.type == VarDeclType.CONST -> {
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return super.process(assignment)
}
}
}
@ -361,7 +369,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
private fun checkValueTypeAndRange(datatype: DataType, arrayspec: ArraySpec?, value: LiteralValue, position: Position?) : Boolean {
fun err(msg: String) : Boolean {
checkResult.add(SyntaxError(msg, position))
checkResult.add(ExpressionError(msg, position))
return false
}
when (datatype) {
@ -417,7 +425,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
val number = (av as LiteralValue).intvalue
?: return err("array must be all words")
val expectedSize = arrayspec?.x?.constValue(namespace)?.intvalue
val expectedSize = arrayspec!!.x.constValue(namespace)?.intvalue!!
if (value.arrayvalue.size != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
@ -431,7 +439,29 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
return err("value '$number' out of range for unsigned word")
}
}
DataType.MATRIX -> TODO()
DataType.MATRIX -> {
// value can only be a single byte, or a byte array (which represents the matrix)
if(value.isArray) {
for (av in value.arrayvalue!!) {
val number = (av as LiteralValue).intvalue
?: return err("array must be all bytes")
val expectedSizeX = arrayspec!!.x.constValue(namespace)?.intvalue!!
val expectedSizeY = arrayspec.y!!.constValue(namespace)?.intvalue!!
val expectedSize = expectedSizeX * expectedSizeY
if (value.arrayvalue.size != expectedSize)
return err("initializer array size mismatch (expecting $expectedSize, got ${value.arrayvalue.size})")
if (number < 0 || number > 255)
return err("value '$number' in byte array is out of range for unsigned byte")
}
} else {
val number = value.intvalue
?: return err("byte integer value expected")
if (number < 0 || number > 255)
return err("value '$number' out of range for unsigned byte")
}
}
}
return true
}

View File

@ -6,6 +6,7 @@ import il65.parser.ParsingFailedError
/**
* Checks the validity of all identifiers (no conflicts)
* Also builds a list of all (scoped) symbol definitions
* Finally, it also makes sure the datatype of all Var decls is set correctly.
*/
fun Module.checkIdentifiers(): MutableMap<String, IStatement> {
@ -47,6 +48,14 @@ class AstIdentifiersChecker : IAstProcessor {
}
override fun process(decl: VarDecl): IStatement {
// first, set the datatype
try {
decl.setDatatype()
} catch(ax: AstException) {
checkResult.add(ax)
}
// now check the identifier
if(BuiltinFunctionNames.contains(decl.name))
// the builtin functions can't be redefined
checkResult.add(NameError("builtin function cannot be redefined", decl.position))

View File

@ -85,39 +85,6 @@ data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, va
}
}
/*
; source code for a stackvm program
; init memory bytes/words/strings
%memory
0400 01 02 03 04 05 06 07 08 09 22 33 44 55 66
0500 1111 2222 3333 4444
1000 "Hello world!\n"
%end_memory
; init global var table with bytes/words/floats/strings
%variables
main.var1 str "This is main.var1"
main.var2 byte aa
main.var3 word ea44
main.var4 float 3.1415927
input.prompt str "Enter a number: "
input.result word 0
%end_variables
; instructions and labels
%instructions
nop
syscall WRITE_MEMSTR word:1000
loop:
syscall WRITE_VAR str:"input.prompt"
syscall INPUT_VAR str:"input.result"
syscall WRITE_VAR str:"input.result"
push byte:8d
syscall WRITE_CHAR
jump loop
%end_instructions
*/
class Compiler(private val options: CompilationOptions) {
fun compile(module: Module) : StackVmProgram {
@ -125,19 +92,19 @@ class Compiler(private val options: CompilationOptions) {
val namespace = module.definingScope()
// todo
val intermediate = StackVmProgram(module.name)
namespace.debugPrint()
// create the pool of all variables used in all blocks and scopes
val varGather = VarGatherer(intermediate)
varGather.process(module)
println("Number of allocated variables and constants: ${intermediate.variables.size} (${intermediate.variablesMemSize} bytes)")
val stmtGatherer = StatementGatherer(intermediate, namespace)
stmtGatherer.process(module)
val translator = StatementTranslator(intermediate, namespace)
translator.process(module)
println("Number of source statements: ${translator.stmtUniqueSequenceNr}")
println("Number of vm instructions: ${intermediate.instructions.size}")
intermediate.toTextLines().forEach { System.out.println(it) }
return intermediate
}
@ -151,7 +118,10 @@ class Compiler(private val options: CompilationOptions) {
}
}
class StatementGatherer(val stackvmProg: StackVmProgram, val namespace: INameScope): IAstProcessor {
class StatementTranslator(val stackvmProg: StackVmProgram, val namespace: INameScope): IAstProcessor {
var stmtUniqueSequenceNr = 0
private set
override fun process(subroutine: Subroutine): IStatement {
translate(subroutine.statements)
return super.process(subroutine)
@ -164,6 +134,7 @@ class Compiler(private val options: CompilationOptions) {
private fun translate(statements: List<IStatement>) {
for (stmt: IStatement in statements) {
stmtUniqueSequenceNr++
when (stmt) {
is AnonymousStatementList -> translate(stmt.statements)
is BuiltinFunctionStatementPlaceholder -> translate(stmt)
@ -176,30 +147,90 @@ class Compiler(private val options: CompilationOptions) {
is InlineAssembly -> translate(stmt)
is IfStatement -> translate(stmt)
is BranchStatement -> translate(stmt)
is Directive, is VarDecl, is Subroutine -> {}
is Directive, is VarDecl, is Subroutine -> {} // skip this, already processed these.
else -> TODO("translate statement $stmt")
}
}
}
private fun translate(stmt: BranchStatement) {
println("translate: $stmt")
// todo
private fun translate(branch: BranchStatement) {
/*
* A branch: IF_CC { stuff } else { other_stuff }
* Which is desugared into:
* BCS _stmt_999_else
* stuff
* JUMP _stmt_999_continue
* _stmt_999_else:
* other_stuff ;; optional
* _stmt_999_continue:
* ...
*/
val labelElse = makeLabel("else")
val labelContinue = makeLabel("continue")
val opcode = when(branch.condition) {
BranchCondition.CS -> "bcc"
BranchCondition.CC -> "bcs"
BranchCondition.EQ -> "bne"
BranchCondition.NE -> "beq"
BranchCondition.VS -> "bvc"
BranchCondition.VC -> "bvs"
BranchCondition.MI -> "bpl"
BranchCondition.PL -> "bmi"
}
if(branch.elsepart.isEmpty()) {
stackvmProg.instruction("$opcode $labelContinue")
translate(branch.statements)
stackvmProg.label(labelContinue)
} else {
stackvmProg.instruction("$opcode $labelElse")
translate(branch.statements)
stackvmProg.instruction("jump $labelContinue")
stackvmProg.label(labelElse)
translate(branch.elsepart)
stackvmProg.label(labelContinue)
}
}
private fun makeLabel(postfix: String): String = "_il65stmt_${stmtUniqueSequenceNr}_$postfix"
private fun translate(stmt: IfStatement) {
println("translate: $stmt")
// todo
println("@todo translate: #$stmtUniqueSequenceNr : $stmt")
stackvmProg.instruction("nop") // todo translate if statement
}
private fun translate(stmt: InlineAssembly) {
println("translate: $stmt")
println("@todo translate: #$stmtUniqueSequenceNr : $stmt")
TODO("inline assembly not supported yet by stackvm")
}
private fun translate(stmt: FunctionCallStatement) {
println("translate: $stmt")
// todo
val targetStmt = stmt.target.targetStatement(namespace)!!
if(targetStmt is BuiltinFunctionStatementPlaceholder) {
// call to a builtin function
TODO("BUILTIN_${stmt.target.nameInSource[0]}") // TODO
return
}
val targetname = when(targetStmt) {
is Label -> targetStmt.scopedname
is Subroutine -> targetStmt.scopedname
else -> throw AstException("invalid call target node type: ${targetStmt::class}")
}
for (arg in stmt.arglist) {
val lv = arg.constValue(namespace)
if(lv==null) TODO("argument must be constant for now") // TODO non-const args
stackvmProg.instruction("push ${makeValue(lv)}")
}
stackvmProg.instruction("call $targetname")
}
private fun makeValue(value: LiteralValue): String {
return when {
value.isString -> "\"${value.strvalue}\""
value.isNumeric -> value.asNumericValue.toString()
else -> TODO("stackvm value for $value")
}
}
private fun translate(stmt: Jump) {
@ -230,8 +261,8 @@ class Compiler(private val options: CompilationOptions) {
}
private fun translate(stmt: Assignment) {
println("translate: $stmt")
// todo
println("@todo translate: #$stmtUniqueSequenceNr : $stmt")
stackvmProg.instruction("nop") // todo translate assignment
}
private fun translate(stmt: Return) {
@ -246,8 +277,8 @@ class Compiler(private val options: CompilationOptions) {
}
private fun translate(stmt: BuiltinFunctionStatementPlaceholder) {
println("translate: $stmt")
// todo
println("@todo translate: #$stmtUniqueSequenceNr : $stmt")
stackvmProg.instruction("nop") // todo translate builtinfunction placeholder
}
}
}
@ -258,20 +289,23 @@ class StackVmProgram(val name: String) {
val variables = mutableMapOf<String, VarDecl>()
val instructions = mutableListOf<String>()
val variablesMemSize: Int
get() {
return variables.values.fold(0) { acc, vardecl -> acc+vardecl.memorySize}
}
fun optimize() {
println("\nOptimizing stackvmProg code...")
// todo
// todo optimize stackvm code
}
fun compileToAssembly(): AssemblyResult {
println("\nGenerating assembly code from stackvmProg code... ")
// todo
// todo generate 6502 assembly
return AssemblyResult(name)
}
fun blockvar(scopedname: String, decl: VarDecl) {
println("$scopedname $decl")
variables[scopedname] = decl
}
@ -295,7 +329,7 @@ class StackVmProgram(val name: String) {
result.add("%end_variables")
result.add("%instructions")
result.addAll(instructions)
result.add("%end_nstructions")
result.add("%end_instructions")
return result
}

View File

@ -69,7 +69,7 @@ class Zeropage(private val options: CompilationOptions) {
// 2 dimensional matrix (only bytes for now)
when(vardecl.datatype) {
DataType.BYTE -> (vardecl.arrayspec.x as LiteralValue).intvalue!! * y
else -> throw CompilerException("matrix can only be of byte")
else -> throw CompilerException("matrix can only contain bytes")
}
}
} else {

View File

@ -71,7 +71,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
if(decl.value?.referencesIdentifier(decl.name) == true||
decl.arrayspec?.x?.referencesIdentifier(decl.name) == true ||
decl.arrayspec?.y?.referencesIdentifier(decl.name) == true) {
errors.add(ExpressionException("recursive var declaration", decl.position))
errors.add(ExpressionError("recursive var declaration", decl.position))
return decl
}
@ -148,14 +148,14 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
optimizationsDone++
LiteralValue(floatvalue = -subexpr.floatvalue)
}
else -> throw ExpressionException("can only take negative of int or float", subexpr.position)
else -> throw ExpressionError("can only take negative of int or float", subexpr.position)
}
expr.operator == "~" -> when {
subexpr.intvalue != null -> {
optimizationsDone++
LiteralValue(intvalue = subexpr.intvalue.inv())
}
else -> throw ExpressionException("can only take bitwise inversion of int", subexpr.position)
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)
}
expr.operator == "not" -> when {
subexpr.intvalue != null -> {
@ -166,9 +166,9 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
optimizationsDone++
LiteralValue(intvalue = if (subexpr.floatvalue == 0.0) 1 else 0)
}
else -> throw ExpressionException("can not take logical not of $subexpr", subexpr.position)
else -> throw ExpressionError("can not take logical not of $subexpr", subexpr.position)
}
else -> throw ExpressionException(expr.operator, subexpr.position)
else -> throw ExpressionError(expr.operator, subexpr.position)
}
result.position = subexpr.position
return result
@ -216,7 +216,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
// int range
val rangevalue = from.intvalue.rangeTo(to.intvalue)
if (rangevalue.last - rangevalue.first > 65535) {
throw ExpressionException("amount of values in range exceeds 65535", range.position)
throw ExpressionError("amount of values in range exceeds 65535", range.position)
}
return LiteralValue(arrayvalue = rangevalue.map {
val v = LiteralValue(intvalue = it)
@ -229,7 +229,7 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
// char range
val rangevalue = from.strvalue[0].rangeTo(to.strvalue[0])
if (rangevalue.last - rangevalue.first > 65535) {
throw ExpressionException("amount of characters in range exceeds 65535", range.position)
throw ExpressionError("amount of characters in range exceeds 65535", range.position)
}
val newval = LiteralValue(strvalue = rangevalue.toList().joinToString(""))
newval.position = range.position
@ -316,16 +316,16 @@ class ConstExprEvaluator {
intvalue = if (left.intvalue >= right.intvalue) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.intvalue >= right.floatvalue) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue >= right.intvalue) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue >= right.floatvalue) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -339,16 +339,16 @@ class ConstExprEvaluator {
intvalue = if (left.intvalue <= right.intvalue) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.intvalue <= right.floatvalue) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue <= right.intvalue) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue <= right.floatvalue) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -376,16 +376,16 @@ class ConstExprEvaluator {
intvalue = if ((left.intvalue != 0).xor(right.intvalue != 0)) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if ((left.intvalue != 0).xor(right.floatvalue != 0.0)) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(
intvalue = if ((left.floatvalue != 0.0).xor(right.intvalue != 0)) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if ((left.floatvalue != 0.0).xor(right.floatvalue != 0.0)) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -399,16 +399,16 @@ class ConstExprEvaluator {
intvalue = if (left.intvalue != 0 || right.intvalue != 0) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.intvalue != 0 || right.floatvalue != 0.0) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue != 0.0 || right.intvalue != 0) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue != 0.0 || right.floatvalue != 0.0) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -422,16 +422,16 @@ class ConstExprEvaluator {
intvalue = if (left.intvalue != 0 && right.intvalue != 0) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.intvalue != 0 && right.floatvalue != 0.0) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue != 0.0 && right.intvalue != 0) 1 else 0)
right.floatvalue!=null -> LiteralValue(
intvalue = if (left.floatvalue != 0.0 && right.floatvalue != 0.0) 1 else 0)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -443,7 +443,7 @@ class ConstExprEvaluator {
litval.position = left.position
return litval
}
throw ExpressionException("cannot calculate $left ^ $right", left.position)
throw ExpressionError("cannot calculate $left ^ $right", left.position)
}
private fun bitwiseor(left: LiteralValue, right: LiteralValue): LiteralValue {
@ -452,7 +452,7 @@ class ConstExprEvaluator {
litval.position = left.position
return litval
}
throw ExpressionException("cannot calculate $left | $right", left.position)
throw ExpressionError("cannot calculate $left | $right", left.position)
}
private fun bitwiseand(left: LiteralValue, right: LiteralValue): LiteralValue {
@ -461,7 +461,7 @@ class ConstExprEvaluator {
litval.position = left.position
return litval
}
throw ExpressionException("cannot calculate $left & $right", left.position)
throw ExpressionError("cannot calculate $left & $right", left.position)
}
private fun power(left: LiteralValue, right: LiteralValue): LiteralValue {
@ -470,14 +470,14 @@ class ConstExprEvaluator {
left.intvalue!=null -> when {
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue.toDouble().pow(right.intvalue).toInt())
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue.toDouble().pow(right.floatvalue))
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.intvalue))
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.floatvalue))
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -489,14 +489,14 @@ class ConstExprEvaluator {
left.intvalue!=null -> when {
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue + right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue + right.floatvalue)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.floatvalue)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -508,14 +508,14 @@ class ConstExprEvaluator {
left.intvalue!=null -> when {
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue - right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue - right.floatvalue)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.floatvalue)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -528,24 +528,24 @@ class ConstExprEvaluator {
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue * right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue * right.floatvalue)
right.strvalue!=null -> {
if(right.strvalue.length * left.intvalue > 65535) throw ExpressionException("string too large", left.position)
if(right.strvalue.length * left.intvalue > 65535) throw ExpressionError("string too large", left.position)
LiteralValue(strvalue = right.strvalue.repeat(left.intvalue))
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.intvalue)
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.floatvalue)
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.strvalue!=null -> when {
right.intvalue!=null -> {
if(left.strvalue.length * right.intvalue > 65535) throw ExpressionException("string too large", left.position)
if(left.strvalue.length * right.intvalue > 65535) throw ExpressionError("string too large", left.position)
LiteralValue(strvalue = left.strvalue.repeat(right.intvalue))
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval
@ -556,27 +556,27 @@ class ConstExprEvaluator {
val litval = when {
left.intvalue!=null -> when {
right.intvalue!=null -> {
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero", left.position)
if(right.intvalue==0) throw ExpressionError("attempt to divide by zero", left.position)
LiteralValue(intvalue = left.intvalue / right.intvalue)
}
right.floatvalue!=null -> {
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero", left.position)
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
LiteralValue(floatvalue = left.intvalue / right.floatvalue)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
left.floatvalue!=null -> when {
right.intvalue!=null -> {
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero", left.position)
if(right.intvalue==0) throw ExpressionError("attempt to divide by zero", left.position)
LiteralValue(floatvalue = left.floatvalue / right.intvalue)
}
right.floatvalue!=null -> {
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero", left.position)
if(right.floatvalue==0.0) throw ExpressionError("attempt to divide by zero", left.position)
LiteralValue(floatvalue = left.floatvalue / right.floatvalue)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
else -> throw ExpressionException(error, left.position)
else -> throw ExpressionError(error, left.position)
}
litval.position = left.position
return litval

View File

@ -495,6 +495,14 @@ class Program (prog: MutableList<Instruction>,
Opcode.JUMP -> {
Instruction(opcode, callLabel = args)
}
Opcode.INC_VAR, Opcode.DEC_VAR,
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR -> {
val withoutQuotes =
if(args!!.startsWith('"') && args.endsWith('"'))
args.substring(1, args.length-1) else args
Instruction(opcode, Value(DataType.STR, null, withoutQuotes))
}
Opcode.SYSCALL -> {
val syscallparts = args!!.split(' ')
val call = Syscall.valueOf(syscallparts[0])

7
il65/stackvm.sh Executable file
View File

@ -0,0 +1,7 @@
#/bin/env sh
IL65_LIBDIR=../lib65
IL65CLASSPATH=out/production/il65
LIBJARS=/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-stdlib.jar:/opt/irmen/idea-2018/plugins/Kotlin/lib/kotlin-reflect.jar:antlr/lib/antlr-runtime-4.7.1.jar
java -cp ${IL65CLASSPATH}:${LIBJARS} il65.stackvm.StackVmKt $*