tweaking multiple assignment targets

This commit is contained in:
Irmen de Jong 2018-11-14 01:50:16 +01:00
parent 4ade45f51f
commit 23c1167d7f
8 changed files with 840 additions and 764 deletions

View File

@ -107,7 +107,9 @@ datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_p' | 'st
arrayspec: '[' expression ']' ;
assignment : assign_target '=' expression ;
assignment : assign_targets '=' expression ;
assign_targets : assign_target (',' assign_target)* ;
augassignment :
assign_target operator=('+=' | '-=' | '/=' | '//=' | '*=' | '**=' | '&=' | '|=' | '^=') expression

View File

@ -7,11 +7,13 @@
sub start() {
ubyte derp
ubyte v1
ubyte v2
derp=foo()
derp=c64.GETADR()
v1=foo()
v1 , v2 =c64.GETADR()
return
}

View File

@ -191,7 +191,7 @@ interface IAstProcessor {
}
fun process(assignment: Assignment): IStatement {
assignment.target = assignment.target.process(this)
assignment.targets = assignment.targets.map { it.process(this) }
assignment.value = assignment.value.process(this)
return assignment
}
@ -641,26 +641,31 @@ class VarDecl(val type: VarDeclType,
}
open class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExpression, override val position: Position) : IStatement {
open class Assignment(var targets: List<AssignTarget>, val aug_op : String?, var value: IExpression, override val position: Position) : IStatement {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
target.linkParents(this)
targets.forEach { it.linkParents(this) }
value.linkParents(this)
}
override fun process(processor: IAstProcessor) = processor.process(this)
override fun toString(): String {
return("Assignment(augop: $aug_op, target: $target, value: $value, pos=$position)")
return("Assignment(augop: $aug_op, targets: $targets, value: $value, pos=$position)")
}
val singleTarget: AssignTarget?
get() {
return targets.singleOrNull() // common case
}
}
// This is a special class so the compiler can see if the assignments are for initializing the vars in the scope,
// or just a regular assignment. It may optimize the initialization step from this.
class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, value: IExpression, position: Position)
: Assignment(target, aug_op, value, position)
: Assignment(listOf(target), aug_op, value, position)
data class AssignTarget(val register: Register?,
@ -1645,11 +1650,11 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
}
assignment()?.let {
return Assignment(it.assign_target().toAst(),null, it.expression().toAst(), it.toPosition())
return Assignment(it.assign_targets().toAst(), null, it.expression().toAst(), it.toPosition())
}
augassignment()?.let {
return Assignment(it.assign_target().toAst(),
return Assignment(listOf(it.assign_target().toAst()),
it.operator.text,
it.expression().toAst(),
it.toPosition())
@ -1707,6 +1712,8 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
throw FatalAstException("unprocessed source text (are we missing ast conversion rules for parser elements?): $text")
}
private fun prog8Parser.Assign_targetsContext.toAst(): List<AssignTarget> = assign_target().map { it.toAst() }
private fun prog8Parser.AsmsubroutineContext.toAst(): IStatement {
val name = identifier().text

View File

@ -303,22 +303,31 @@ class AstChecker(private val namespace: INameScope,
* Also check data type compatibility
*/
override fun process(assignment: Assignment): IStatement {
if(assignment.target.identifier!=null) {
val targetName = assignment.target.identifier!!.nameInSource
var resultingAssignment = assignment
for (target in assignment.targets) {
resultingAssignment = processAssignmentTarget(resultingAssignment, target)
}
return super.process(resultingAssignment)
}
private fun processAssignmentTarget(assignment: Assignment, target: AssignTarget): Assignment {
if(target.identifier!=null) {
val targetName = 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)
return assignment
}
targetSymbol !is VarDecl -> {
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
return super.process(assignment)
return assignment
}
targetSymbol.type == VarDeclType.CONST -> {
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
return super.process(assignment)
return assignment
}
else -> {}
}
}
@ -329,27 +338,27 @@ class AstChecker(private val namespace: INameScope,
if(assignment.aug_op!=null) {
// check augmented assignment:
// A /= 3 -> check as if it was A = A / 3
val target: IExpression =
val newTarget: IExpression =
when {
assignment.target.register!=null -> RegisterExpr(assignment.target.register!!, assignment.target.position)
assignment.target.identifier!=null -> assignment.target.identifier!!
assignment.target.arrayindexed!=null -> assignment.target.arrayindexed!!
target.register!=null -> RegisterExpr(target.register, target.position)
target.identifier!=null -> target.identifier
target.arrayindexed!=null -> target.arrayindexed
else -> throw FatalAstException("strange assignment")
}
val expression = BinaryExpression(target, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
val expression = BinaryExpression(newTarget, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
expression.linkParents(assignment.parent)
val assignment2 = Assignment(assignment.target, null, expression, assignment.position)
val assignment2 = Assignment(listOf(target), null, expression, assignment.position)
assignment2.linkParents(assignment.parent)
return process(assignment2)
return assignment2
}
val targetDatatype = assignment.target.determineDatatype(namespace, heap, assignment)
val targetDatatype = target.determineDatatype(namespace, heap, assignment)
if(targetDatatype!=null) {
val constVal = assignment.value.constValue(namespace, heap)
if(constVal!=null) {
val arrayspec = if(assignment.target.identifier!=null) {
val targetVar = namespace.lookup(assignment.target.identifier!!.nameInSource, assignment) as? VarDecl
val arrayspec = if(target.identifier!=null) {
val targetVar = namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
targetVar?.arrayspec
} else null
checkValueTypeAndRange(targetDatatype,
@ -375,8 +384,7 @@ class AstChecker(private val namespace: INameScope,
}
}
}
return super.process(assignment)
return assignment
}

View File

@ -1089,10 +1089,11 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
private fun translate(stmt: Assignment) {
val assignTarget= stmt.singleTarget ?: throw CompilerException("cannot use assignment to multiple assignment targets ${stmt.position}")
prog.line(stmt.position)
translate(stmt.value)
val valueDt = stmt.value.resultingDatatype(namespace, heap)
val targetDt = stmt.target.determineDatatype(namespace, heap, stmt)
val targetDt = assignTarget.determineDatatype(namespace, heap, stmt)
if(valueDt!=targetDt) {
// convert value to target datatype if possible
when(targetDt) {
@ -1124,26 +1125,26 @@ private class StatementTranslator(private val prog: IntermediateProgram,
if(stmt.aug_op!=null) {
// augmented assignment
when {
stmt.target.identifier!=null -> {
val target = stmt.target.identifier!!.targetStatement(namespace)!!
assignTarget.identifier!=null -> {
val target = assignTarget.identifier.targetStatement(namespace)!!
when(target) {
is VarDecl -> {
val opcode = opcodePushvar(stmt.target.determineDatatype(namespace, heap, stmt)!!)
val opcode = opcodePushvar(assignTarget.determineDatatype(namespace, heap, stmt)!!)
prog.instr(opcode, callLabel = target.scopedname)
}
else -> throw CompilerException("invalid assignment target type ${target::class}")
}
}
stmt.target.register!=null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = stmt.target.register.toString())
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
assignTarget.register!=null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = assignTarget.register.toString())
assignTarget.arrayindexed!=null -> translate(assignTarget.arrayindexed, false)
}
translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap))
}
// pop the result value back into the assignment target
val datatype = stmt.target.determineDatatype(namespace, heap, stmt)!!
popValueIntoTarget(stmt.target, datatype)
val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!!
popValueIntoTarget(assignTarget, datatype)
}
private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) {
@ -1394,7 +1395,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
else
AssignTarget(null, loop.loopVar!!.copy(), null, loop.position)
val arrayspec = ArraySpec(RegisterExpr(Register.X, loop.position), loop.position)
val assignLv = Assignment(assignTarget, null, ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), arrayspec, loop.position), loop.position)
val assignLv = Assignment(listOf(assignTarget), null, ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), arrayspec, loop.position), loop.position)
assignLv.linkParents(loop.body)
translate(assignLv)
translate(loop.body)
@ -1519,7 +1520,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
AssignTarget(register, null, null, range.position)
}
val startAssignment = Assignment(makeAssignmentTarget(), null, range.from, range.position)
val startAssignment = Assignment(listOf(makeAssignmentTarget()), null, range.from, range.position)
startAssignment.linkParents(range.parent)
translate(startAssignment)

View File

@ -536,7 +536,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
super.process(assignment)
val lv = assignment.value as? LiteralValue
if(lv!=null) {
val targetDt = assignment.target.determineDatatype(namespace, heap, assignment)
val targetDt = assignment.singleTarget?.determineDatatype(namespace, heap, assignment)
// see if we can promote/convert a literal value to the required datatype
when(targetDt) {
DataType.UWORD -> {

View File

@ -105,7 +105,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
if(range.size()==1) {
// for loop over a (constant) range of just a single value-- optimize the loop away
// loopvar/reg = range value , follow by block
val assignment = Assignment(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position), null, range.from, forLoop.position)
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position)
forLoop.body.statements.add(0, assignment)
optimizationsDone++
return forLoop.body
@ -174,4 +174,4 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
}
return jump
}
}
}

File diff suppressed because it is too large Load Diff