mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-06 09:33:22 +00:00
Better tracking of the original source
This commit is contained in:
parent
4fb786522d
commit
8fcf628c8f
@ -49,6 +49,8 @@ Choose syntax for assembly output on 8080-like targets.
|
|||||||
|
|
||||||
* `-fline-numbers`, `-fno-line-numbers` – Whether should show source line numbers in assembly output.
|
* `-fline-numbers`, `-fno-line-numbers` – Whether should show source line numbers in assembly output.
|
||||||
|
|
||||||
|
* `-fline-numbers`, `-fno-line-numbers` – Whether should show the original source in assembly output. Implies `-fline-numbers`
|
||||||
|
|
||||||
## Verbosity options
|
## Verbosity options
|
||||||
|
|
||||||
* `-q` – Suppress all messages except for errors.
|
* `-q` – Suppress all messages except for errors.
|
||||||
|
@ -50,6 +50,8 @@ You may be also interested in the following:
|
|||||||
* `-s` – additionally generate assembly output
|
* `-s` – additionally generate assembly output
|
||||||
(if targeting Intel 8080, use `--syntax=intel` or `--syntax=zilog` to choose the preferred assembly syntax)
|
(if targeting Intel 8080, use `--syntax=intel` or `--syntax=zilog` to choose the preferred assembly syntax)
|
||||||
|
|
||||||
|
* `-fsource-in-asm` – show original Millfork source in the assembly output
|
||||||
|
|
||||||
* `-g` – additionally generate a label file, in format compatible with VICE emulator
|
* `-g` – additionally generate a label file, in format compatible with VICE emulator
|
||||||
|
|
||||||
* `-r PROGRAM` – automatically launch given program after successful compilation
|
* `-r PROGRAM` – automatically launch given program after successful compilation
|
||||||
|
@ -304,7 +304,7 @@ object Cpu extends Enumeration {
|
|||||||
object CompilationFlag extends Enumeration {
|
object CompilationFlag extends Enumeration {
|
||||||
val
|
val
|
||||||
// common compilation options:
|
// common compilation options:
|
||||||
EmitIllegals, DecimalMode, ReadOnlyArrays, LenientTextEncoding, LineNumbersInAssembly,
|
EmitIllegals, DecimalMode, ReadOnlyArrays, LenientTextEncoding, LineNumbersInAssembly, SourceInAssembly,
|
||||||
// compilation options for MOS:
|
// compilation options for MOS:
|
||||||
EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes,
|
EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes,
|
||||||
PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack,
|
PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack,
|
||||||
|
@ -239,6 +239,7 @@ object Main {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection NameBooleanParameters
|
||||||
private def parser(errorReporting: Logger): CliParser[Context] = new CliParser[Context] {
|
private def parser(errorReporting: Logger): CliParser[Context] = new CliParser[Context] {
|
||||||
|
|
||||||
fluff("Main options:", "")
|
fluff("Main options:", "")
|
||||||
@ -302,6 +303,14 @@ object Main {
|
|||||||
c.changeFlag(CompilationFlag.LineNumbersInAssembly, v)
|
c.changeFlag(CompilationFlag.LineNumbersInAssembly, v)
|
||||||
).description("Show source line numbers in assembly.")
|
).description("Show source line numbers in assembly.")
|
||||||
|
|
||||||
|
boolean("-fsource-in-asm", "-fno-source-in-asm").action((c,v) =>
|
||||||
|
if (v) {
|
||||||
|
c.changeFlag(CompilationFlag.SourceInAssembly, true).changeFlag(CompilationFlag.LineNumbersInAssembly, true)
|
||||||
|
} else {
|
||||||
|
c.changeFlag(CompilationFlag.LineNumbersInAssembly, false)
|
||||||
|
}
|
||||||
|
).description("Show source in assembly.")
|
||||||
|
|
||||||
endOfFlags("--").description("Marks the end of options.")
|
endOfFlags("--").description("Marks the end of options.")
|
||||||
|
|
||||||
fluff("", "Verbosity options:", "")
|
fluff("", "Verbosity options:", "")
|
||||||
|
@ -222,6 +222,8 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
|||||||
|
|
||||||
def position(s: Option[Position]): ZLine = pos(SourceLine.of(s))
|
def position(s: Option[Position]): ZLine = pos(SourceLine.of(s))
|
||||||
|
|
||||||
|
def positionIfEmpty(s: Option[Position]): ZLine = if (s.isEmpty || source.isDefined) this else pos(SourceLine.of(s))
|
||||||
|
|
||||||
def pos(s: Seq[Option[SourceLine]]): ZLine = pos(SourceLine.merge(s))
|
def pos(s: Seq[Option[SourceLine]]): ZLine = pos(SourceLine.merge(s))
|
||||||
|
|
||||||
def mergePos(s: Seq[Option[SourceLine]]): ZLine = if (s.isEmpty) this else pos(SourceLine.merge(this.source, s))
|
def mergePos(s: Seq[Option[SourceLine]]): ZLine = if (s.isEmpty) this else pos(SourceLine.merge(this.source, s))
|
||||||
|
@ -25,7 +25,7 @@ abstract class MacroExpander[T <: AbstractCode] {
|
|||||||
|
|
||||||
def h(s: String) = if (s == paramName) target.asInstanceOf[VariableExpression].name else s
|
def h(s: String) = if (s == paramName) target.asInstanceOf[VariableExpression].name else s
|
||||||
|
|
||||||
stmt match {
|
(stmt match {
|
||||||
case RawBytesStatement(contents) => RawBytesStatement(contents.replaceVariable(paramName, target))
|
case RawBytesStatement(contents) => RawBytesStatement(contents.replaceVariable(paramName, target))
|
||||||
case ExpressionStatement(e) => ExpressionStatement(e.replaceVariable(paramName, target))
|
case ExpressionStatement(e) => ExpressionStatement(e.replaceVariable(paramName, target))
|
||||||
case ReturnStatement(e) => ReturnStatement(e.map(f))
|
case ReturnStatement(e) => ReturnStatement(e.map(f))
|
||||||
@ -45,7 +45,7 @@ abstract class MacroExpander[T <: AbstractCode] {
|
|||||||
case _ =>
|
case _ =>
|
||||||
println(stmt)
|
println(stmt)
|
||||||
???
|
???
|
||||||
}
|
}).pos(stmt.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
def inlineFunction(ctx: CompilationContext, i: MacroFunction, params: List[Expression], position: Option[Position]): (List[T], List[ExecutableStatement]) = {
|
def inlineFunction(ctx: CompilationContext, i: MacroFunction, params: List[Expression], position: Option[Position]): (List[T], List[ExecutableStatement]) = {
|
||||||
|
@ -192,7 +192,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
|
|||||||
case _ => reg
|
case _ => reg
|
||||||
}
|
}
|
||||||
List(ZLine(op, registers, param, elidability))
|
List(ZLine(op, registers, param, elidability))
|
||||||
}).map(_.position(statement.position))
|
}).map(_.positionIfEmpty(statement.position))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fixStackOnReturn(ctx: CompilationContext): List[ZLine] = {
|
private def fixStackOnReturn(ctx: CompilationContext): List[ZLine] = {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package millfork.error
|
package millfork.error
|
||||||
|
|
||||||
|
import millfork.assembly.SourceLine
|
||||||
import millfork.node.Position
|
import millfork.node.Position
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
@ -117,4 +118,8 @@ class ConsoleLogger extends Logger {
|
|||||||
sourceLines(filename) = lines
|
sourceLines(filename) = lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def getLine(line: SourceLine): Option[String] = for {
|
||||||
|
file <- sourceLines.get(line.moduleName)
|
||||||
|
line <- file.lift(line.line - 1)
|
||||||
|
} yield line
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package millfork.error
|
package millfork.error
|
||||||
|
|
||||||
|
import millfork.assembly.SourceLine
|
||||||
import millfork.node.Position
|
import millfork.node.Position
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,4 +28,6 @@ class ErrorsOnlyLogger(inner: Logger) extends Logger {
|
|||||||
override def assertNoErrors(msg: String): Unit = inner.assertNoErrors(msg)
|
override def assertNoErrors(msg: String): Unit = inner.assertNoErrors(msg)
|
||||||
|
|
||||||
override def addSource(filename: String, lines: IndexedSeq[String]): Unit = ()
|
override def addSource(filename: String, lines: IndexedSeq[String]): Unit = ()
|
||||||
|
|
||||||
|
override def getLine(line: SourceLine): Option[String] = None
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package millfork.error
|
package millfork.error
|
||||||
|
|
||||||
|
import millfork.assembly.SourceLine
|
||||||
import millfork.node.Position
|
import millfork.node.Position
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,4 +29,6 @@ trait Logger {
|
|||||||
def assertNoErrors(msg: String): Unit
|
def assertNoErrors(msg: String): Unit
|
||||||
|
|
||||||
def addSource(filename: String, lines: IndexedSeq[String]): Unit
|
def addSource(filename: String, lines: IndexedSeq[String]): Unit
|
||||||
|
|
||||||
|
def getLine(line: SourceLine): Option[String]
|
||||||
}
|
}
|
@ -82,7 +82,7 @@ case class SeparateBytesExpression(hi: Expression, lo: Expression) extends LhsEx
|
|||||||
def replaceVariable(variable: String, actualParam: Expression): Expression =
|
def replaceVariable(variable: String, actualParam: Expression): Expression =
|
||||||
SeparateBytesExpression(
|
SeparateBytesExpression(
|
||||||
hi.replaceVariable(variable, actualParam),
|
hi.replaceVariable(variable, actualParam),
|
||||||
lo.replaceVariable(variable, actualParam))
|
lo.replaceVariable(variable, actualParam)).pos(position)
|
||||||
override def containsVariable(variable: String): Boolean = hi.containsVariable(variable) || lo.containsVariable(variable)
|
override def containsVariable(variable: String): Boolean = hi.containsVariable(variable) || lo.containsVariable(variable)
|
||||||
override def isPure: Boolean = hi.isPure && lo.isPure
|
override def isPure: Boolean = hi.isPure && lo.isPure
|
||||||
override def getAllIdentifiers: Set[String] = hi.getAllIdentifiers ++ lo.getAllIdentifiers
|
override def getAllIdentifiers: Set[String] = hi.getAllIdentifiers ++ lo.getAllIdentifiers
|
||||||
@ -90,7 +90,7 @@ case class SeparateBytesExpression(hi: Expression, lo: Expression) extends LhsEx
|
|||||||
|
|
||||||
case class SumExpression(expressions: List[(Boolean, Expression)], decimal: Boolean) extends Expression {
|
case class SumExpression(expressions: List[(Boolean, Expression)], decimal: Boolean) extends Expression {
|
||||||
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
||||||
SumExpression(expressions.map { case (n, e) => n -> e.replaceVariable(variable, actualParam) }, decimal)
|
SumExpression(expressions.map { case (n, e) => n -> e.replaceVariable(variable, actualParam) }, decimal).pos(position)
|
||||||
override def containsVariable(variable: String): Boolean = expressions.exists(_._2.containsVariable(variable))
|
override def containsVariable(variable: String): Boolean = expressions.exists(_._2.containsVariable(variable))
|
||||||
override def isPure: Boolean = expressions.forall(_._2.isPure)
|
override def isPure: Boolean = expressions.forall(_._2.isPure)
|
||||||
override def getAllIdentifiers: Set[String] = expressions.map(_._2.getAllIdentifiers).fold(Set[String]())(_ ++ _)
|
override def getAllIdentifiers: Set[String] = expressions.map(_._2.getAllIdentifiers).fold(Set[String]())(_ ++ _)
|
||||||
@ -100,7 +100,7 @@ case class FunctionCallExpression(functionName: String, expressions: List[Expres
|
|||||||
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
||||||
FunctionCallExpression(functionName, expressions.map {
|
FunctionCallExpression(functionName, expressions.map {
|
||||||
_.replaceVariable(variable, actualParam)
|
_.replaceVariable(variable, actualParam)
|
||||||
})
|
}).pos(position)
|
||||||
override def containsVariable(variable: String): Boolean = expressions.exists(_.containsVariable(variable))
|
override def containsVariable(variable: String): Boolean = expressions.exists(_.containsVariable(variable))
|
||||||
override def isPure: Boolean = false // TODO
|
override def isPure: Boolean = false // TODO
|
||||||
override def getAllIdentifiers: Set[String] = expressions.map(_.getAllIdentifiers).fold(Set[String]())(_ ++ _) + functionName
|
override def getAllIdentifiers: Set[String] = expressions.map(_.getAllIdentifiers).fold(Set[String]())(_ ++ _) + functionName
|
||||||
@ -108,7 +108,7 @@ case class FunctionCallExpression(functionName: String, expressions: List[Expres
|
|||||||
|
|
||||||
case class HalfWordExpression(expression: Expression, hiByte: Boolean) extends Expression {
|
case class HalfWordExpression(expression: Expression, hiByte: Boolean) extends Expression {
|
||||||
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
||||||
HalfWordExpression(expression.replaceVariable(variable, actualParam), hiByte)
|
HalfWordExpression(expression.replaceVariable(variable, actualParam), hiByte).pos(position)
|
||||||
override def containsVariable(variable: String): Boolean = expression.containsVariable(variable)
|
override def containsVariable(variable: String): Boolean = expression.containsVariable(variable)
|
||||||
override def isPure: Boolean = expression.isPure
|
override def isPure: Boolean = expression.isPure
|
||||||
override def getAllIdentifiers: Set[String] = expression.getAllIdentifiers
|
override def getAllIdentifiers: Set[String] = expression.getAllIdentifiers
|
||||||
@ -178,10 +178,11 @@ case class IndexedExpression(name: String, index: Expression) extends LhsExpress
|
|||||||
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
override def replaceVariable(variable: String, actualParam: Expression): Expression =
|
||||||
if (name == variable) {
|
if (name == variable) {
|
||||||
actualParam match {
|
actualParam match {
|
||||||
case VariableExpression(actualVariable) => IndexedExpression(actualVariable, index.replaceVariable(variable, actualParam))
|
case VariableExpression(actualVariable) =>
|
||||||
|
IndexedExpression(actualVariable, index.replaceVariable(variable, actualParam)).pos(position)
|
||||||
case _ => ??? // TODO
|
case _ => ??? // TODO
|
||||||
}
|
}
|
||||||
} else IndexedExpression(name, index.replaceVariable(variable, actualParam))
|
} else IndexedExpression(name, index.replaceVariable(variable, actualParam)).pos(position)
|
||||||
override def containsVariable(variable: String): Boolean = name == variable || index.containsVariable(variable)
|
override def containsVariable(variable: String): Boolean = name == variable || index.containsVariable(variable)
|
||||||
override def isPure: Boolean = index.isPure
|
override def isPure: Boolean = index.isPure
|
||||||
override def getAllIdentifiers: Set[String] = index.getAllIdentifiers + name
|
override def getAllIdentifiers: Set[String] = index.getAllIdentifiers + name
|
||||||
|
@ -10,15 +10,15 @@ object UnreachableCode extends NodeOptimization {
|
|||||||
|
|
||||||
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = nodes match {
|
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = nodes match {
|
||||||
case (x:FunctionDeclarationStatement)::xs =>
|
case (x:FunctionDeclarationStatement)::xs =>
|
||||||
x.copy(statements = x.statements.map(optimizeStatements(_, options))) :: optimize(xs, options)
|
x.copy(statements = x.statements.map(optimizeStatements(_, options))).pos(x.position) :: optimize(xs, options)
|
||||||
case (x:IfStatement)::xs =>
|
case (x:IfStatement)::xs =>
|
||||||
x.copy(
|
x.copy(
|
||||||
thenBranch = optimizeExecutableStatements(x.thenBranch, options),
|
thenBranch = optimizeExecutableStatements(x.thenBranch, options),
|
||||||
elseBranch = optimizeExecutableStatements(x.elseBranch, options)) :: optimize(xs, options)
|
elseBranch = optimizeExecutableStatements(x.elseBranch, options)).pos(x.position) :: optimize(xs, options)
|
||||||
case (x:WhileStatement)::xs =>
|
case (x:WhileStatement)::xs =>
|
||||||
x.copy(body = optimizeExecutableStatements(x.body, options)) :: optimize(xs, options)
|
x.copy(body = optimizeExecutableStatements(x.body, options)).pos(x.position) :: optimize(xs, options)
|
||||||
case (x:DoWhileStatement)::xs =>
|
case (x:DoWhileStatement)::xs =>
|
||||||
x.copy(body = optimizeExecutableStatements(x.body, options)) :: optimize(xs, options)
|
x.copy(body = optimizeExecutableStatements(x.body, options)).pos(x.position) :: optimize(xs, options)
|
||||||
case (x:ReturnStatement) :: xs =>
|
case (x:ReturnStatement) :: xs =>
|
||||||
x :: Nil
|
x :: Nil
|
||||||
case x :: xs =>
|
case x :: xs =>
|
||||||
|
@ -72,7 +72,7 @@ object UnusedGlobalVariables extends NodeOptimization {
|
|||||||
params.flatMap {
|
params.flatMap {
|
||||||
case VariableExpression(_) => None
|
case VariableExpression(_) => None
|
||||||
case LiteralExpression(_, _) => None
|
case LiteralExpression(_, _) => None
|
||||||
case x => Some(ExpressionStatement(x))
|
case x => Some(ExpressionStatement(x).pos(s.position))
|
||||||
}
|
}
|
||||||
} else Some(s)
|
} else Some(s)
|
||||||
case s@Assignment(VariableExpression(n), VariableExpression(_)) =>
|
case s@Assignment(VariableExpression(n), VariableExpression(_)) =>
|
||||||
@ -80,35 +80,35 @@ object UnusedGlobalVariables extends NodeOptimization {
|
|||||||
case s@Assignment(VariableExpression(n), LiteralExpression(_, _)) =>
|
case s@Assignment(VariableExpression(n), LiteralExpression(_, _)) =>
|
||||||
if (globalsToRemove(n)) Nil else Some(s)
|
if (globalsToRemove(n)) Nil else Some(s)
|
||||||
case s@Assignment(VariableExpression(n), expr) =>
|
case s@Assignment(VariableExpression(n), expr) =>
|
||||||
if (globalsToRemove(n)) Some(ExpressionStatement(expr)) else Some(s)
|
if (globalsToRemove(n)) Some(ExpressionStatement(expr).pos(s.position)) else Some(s)
|
||||||
case s@Assignment(SeparateBytesExpression(VariableExpression(h), VariableExpression(l)), expr) =>
|
case s@Assignment(SeparateBytesExpression(he@VariableExpression(h), le@VariableExpression(l)), expr) =>
|
||||||
if (globalsToRemove(h)) {
|
if (globalsToRemove(h)) {
|
||||||
if (globalsToRemove(l))
|
if (globalsToRemove(l))
|
||||||
Some(ExpressionStatement(expr))
|
Some(ExpressionStatement(expr).pos(s.position))
|
||||||
else
|
else
|
||||||
Some(Assignment(SeparateBytesExpression(BlackHoleExpression, VariableExpression(l)), expr))
|
Some(Assignment(SeparateBytesExpression(BlackHoleExpression, le).pos(he.position), expr).pos(s.position))
|
||||||
} else {
|
} else {
|
||||||
if (globalsToRemove(l))
|
if (globalsToRemove(l))
|
||||||
Some(Assignment(SeparateBytesExpression(VariableExpression(h), BlackHoleExpression), expr))
|
Some(Assignment(SeparateBytesExpression(he, BlackHoleExpression).pos(he.position), expr).pos(s.position))
|
||||||
else
|
else
|
||||||
Some(s)
|
Some(s)
|
||||||
}
|
}
|
||||||
case s@Assignment(SeparateBytesExpression(h, VariableExpression(l)), expr) =>
|
case s@Assignment(SeparateBytesExpression(h, le@VariableExpression(l)), expr) =>
|
||||||
if (globalsToRemove(l)) Some(Assignment(SeparateBytesExpression(h, BlackHoleExpression), expr))
|
if (globalsToRemove(l)) Some(Assignment(SeparateBytesExpression(h, BlackHoleExpression).pos(h.position), expr).pos(s.position))
|
||||||
else Some(s)
|
else Some(s)
|
||||||
case s@Assignment(SeparateBytesExpression(VariableExpression(h), l), expr) =>
|
case s@Assignment(SeparateBytesExpression(he@VariableExpression(h), l), expr) =>
|
||||||
if (globalsToRemove(h)) Some(Assignment(SeparateBytesExpression(BlackHoleExpression, l), expr))
|
if (globalsToRemove(h)) Some(Assignment(SeparateBytesExpression(BlackHoleExpression, l).pos(he.position), expr).pos(s.position))
|
||||||
else Some(s)
|
else Some(s)
|
||||||
case s: IfStatement =>
|
case s: IfStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
thenBranch = removeVariablesFromStatement(s.thenBranch, globalsToRemove).asInstanceOf[List[ExecutableStatement]],
|
thenBranch = removeVariablesFromStatement(s.thenBranch, globalsToRemove).asInstanceOf[List[ExecutableStatement]],
|
||||||
elseBranch = removeVariablesFromStatement(s.elseBranch, globalsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
elseBranch = removeVariablesFromStatement(s.elseBranch, globalsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s: WhileStatement =>
|
case s: WhileStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
body = removeVariablesFromStatement(s.body, globalsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
body = removeVariablesFromStatement(s.body, globalsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s: DoWhileStatement =>
|
case s: DoWhileStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
body = removeVariablesFromStatement(s.body, globalsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
body = removeVariablesFromStatement(s.body, globalsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s => Some(s)
|
case s => Some(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ object UnusedLocalVariables extends NodeOptimization {
|
|||||||
params.flatMap {
|
params.flatMap {
|
||||||
case VariableExpression(_) => None
|
case VariableExpression(_) => None
|
||||||
case LiteralExpression(_, _) => None
|
case LiteralExpression(_, _) => None
|
||||||
case x => Some(ExpressionStatement(x))
|
case x => Some(ExpressionStatement(x).pos(s.position))
|
||||||
}
|
}
|
||||||
} else Some(s)
|
} else Some(s)
|
||||||
case s@Assignment(VariableExpression(n), VariableExpression(_)) =>
|
case s@Assignment(VariableExpression(n), VariableExpression(_)) =>
|
||||||
@ -88,35 +88,52 @@ object UnusedLocalVariables extends NodeOptimization {
|
|||||||
case s@Assignment(VariableExpression(n), LiteralExpression(_, _)) =>
|
case s@Assignment(VariableExpression(n), LiteralExpression(_, _)) =>
|
||||||
if (localsToRemove(n)) Nil else Some(s)
|
if (localsToRemove(n)) Nil else Some(s)
|
||||||
case s@Assignment(VariableExpression(n), expr) =>
|
case s@Assignment(VariableExpression(n), expr) =>
|
||||||
if (localsToRemove(n)) Some(ExpressionStatement(expr)) else Some(s)
|
if (localsToRemove(n)) Some(ExpressionStatement(expr).pos(s.position)) else Some(s)
|
||||||
case s@Assignment(SeparateBytesExpression(VariableExpression(h), VariableExpression(l)), expr) =>
|
case s@Assignment(SeparateBytesExpression(he@VariableExpression(h), le@VariableExpression(l)), expr) =>
|
||||||
if (localsToRemove(h)) {
|
if (localsToRemove(h)) {
|
||||||
if (localsToRemove(l))
|
if (localsToRemove(l))
|
||||||
Some(ExpressionStatement(expr))
|
Some(ExpressionStatement(expr).pos(s.position))
|
||||||
else
|
else
|
||||||
Some(Assignment(SeparateBytesExpression(BlackHoleExpression, VariableExpression(l)), expr))
|
Some(Assignment(
|
||||||
|
SeparateBytesExpression(
|
||||||
|
BlackHoleExpression,
|
||||||
|
VariableExpression(l).pos(le.position)
|
||||||
|
).pos(he.position),
|
||||||
|
expr
|
||||||
|
).pos(s.position))
|
||||||
} else {
|
} else {
|
||||||
if (localsToRemove(l))
|
if (localsToRemove(l))
|
||||||
Some(Assignment(SeparateBytesExpression(VariableExpression(h), BlackHoleExpression), expr))
|
Some(Assignment(
|
||||||
|
SeparateBytesExpression(
|
||||||
|
VariableExpression(h).pos(he.position),
|
||||||
|
BlackHoleExpression
|
||||||
|
).pos(he.position),
|
||||||
|
expr
|
||||||
|
).pos(s.position))
|
||||||
else
|
else
|
||||||
Some(s)
|
Some(s)
|
||||||
}
|
}
|
||||||
case s@Assignment(SeparateBytesExpression(h, VariableExpression(l)), expr) =>
|
case s@Assignment(SeparateBytesExpression(h, VariableExpression(l)), expr) =>
|
||||||
if (localsToRemove(l)) Some(Assignment(SeparateBytesExpression(h, BlackHoleExpression), expr))
|
if (localsToRemove(l)) Some(Assignment(
|
||||||
|
SeparateBytesExpression(h, BlackHoleExpression).pos(h.position),
|
||||||
|
expr
|
||||||
|
).pos(s.position))
|
||||||
else Some(s)
|
else Some(s)
|
||||||
case s@Assignment(SeparateBytesExpression(VariableExpression(h), l), expr) =>
|
case s@Assignment(SeparateBytesExpression(he@VariableExpression(h), l), expr) =>
|
||||||
if (localsToRemove(h)) Some(Assignment(SeparateBytesExpression(BlackHoleExpression, l), expr))
|
if (localsToRemove(h)) Some(Assignment(
|
||||||
|
SeparateBytesExpression(BlackHoleExpression, l).pos(he.position), expr
|
||||||
|
).pos(s.position))
|
||||||
else Some(s)
|
else Some(s)
|
||||||
case s: IfStatement =>
|
case s: IfStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
thenBranch = removeVariables(s.thenBranch, localsToRemove).asInstanceOf[List[ExecutableStatement]],
|
thenBranch = removeVariables(s.thenBranch, localsToRemove).asInstanceOf[List[ExecutableStatement]],
|
||||||
elseBranch = removeVariables(s.elseBranch, localsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
elseBranch = removeVariables(s.elseBranch, localsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s: WhileStatement =>
|
case s: WhileStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
body = removeVariables(s.body, localsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
body = removeVariables(s.body, localsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s: DoWhileStatement =>
|
case s: DoWhileStatement =>
|
||||||
Some(s.copy(
|
Some(s.copy(
|
||||||
body = removeVariables(s.body, localsToRemove).asInstanceOf[List[ExecutableStatement]]))
|
body = removeVariables(s.body, localsToRemove).asInstanceOf[List[ExecutableStatement]]).pos(s.position))
|
||||||
case s => Some(s)
|
case s => Some(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +482,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
|||||||
|
|
||||||
private def outputFunction(bank: String, code: List[T], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
private def outputFunction(bank: String, code: List[T], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
||||||
val printLineNumbers = options.flag(CompilationFlag.LineNumbersInAssembly)
|
val printLineNumbers = options.flag(CompilationFlag.LineNumbersInAssembly)
|
||||||
|
val sourceInAssembly = options.flag(CompilationFlag.SourceInAssembly)
|
||||||
var index = startFrom
|
var index = startFrom
|
||||||
|
assOut.append(" ")
|
||||||
assOut.append("* = $" + startFrom.toHexString)
|
assOut.append("* = $" + startFrom.toHexString)
|
||||||
var lastSource = Option.empty[SourceLine]
|
var lastSource = Option.empty[SourceLine]
|
||||||
for (instr <- code) {
|
for (instr <- code) {
|
||||||
@ -491,9 +493,18 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
|||||||
lastSource = instr.source
|
lastSource = instr.source
|
||||||
if (printLineNumbers) {
|
if (printLineNumbers) {
|
||||||
lastSource match {
|
lastSource match {
|
||||||
case Some(SourceLine(moduleName, line)) if line > 0 =>
|
case Some(sl@SourceLine(moduleName, line)) if line > 0 =>
|
||||||
|
if (sourceInAssembly) {
|
||||||
|
assOut.append("; ")
|
||||||
|
}
|
||||||
assOut.append(s";line:$line:$moduleName")
|
assOut.append(s";line:$line:$moduleName")
|
||||||
|
if (sourceInAssembly) {
|
||||||
|
log.getLine(sl).foreach(l => assOut.append("; " + l))
|
||||||
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
if (sourceInAssembly) {
|
||||||
|
assOut.append("; ")
|
||||||
|
}
|
||||||
assOut.append(s";line")
|
assOut.append(s";line")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,6 +528,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
|||||||
index = emitInstruction(bank, options, index, instr)
|
index = emitInstruction(bank, options, index, instr)
|
||||||
}
|
}
|
||||||
if (printLineNumbers && lastSource.isDefined){
|
if (printLineNumbers && lastSource.isDefined){
|
||||||
|
if (sourceInAssembly) assOut.append("; ")
|
||||||
assOut.append(s";line")
|
assOut.append(s";line")
|
||||||
}
|
}
|
||||||
index
|
index
|
||||||
|
@ -64,17 +64,25 @@ object MosInliningCalculator extends AbstractInliningCalculator[AssemblyLine] {
|
|||||||
|
|
||||||
def inline(code: List[AssemblyLine], inlinedFunctions: Map[String, List[AssemblyLine]], jobContext: JobContext): List[AssemblyLine] = {
|
def inline(code: List[AssemblyLine], inlinedFunctions: Map[String, List[AssemblyLine]], jobContext: JobContext): List[AssemblyLine] = {
|
||||||
code.flatMap {
|
code.flatMap {
|
||||||
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
case callInstr@AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||||
val labelPrefix = jobContext.nextLabel("ai")
|
val labelPrefix = jobContext.nextLabel("ai")
|
||||||
inlinedFunctions(p.toString).map {
|
var inlinedCode = inlinedFunctions(p.toString)
|
||||||
|
if (inlinedCode.forall(_.source.isEmpty)) {
|
||||||
|
inlinedCode = inlinedCode.map(_.copy(source = callInstr.source))
|
||||||
|
}
|
||||||
|
inlinedCode.map {
|
||||||
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
line.copy(parameter = newLabel)
|
line.copy(parameter = newLabel)
|
||||||
case l => l
|
case l => l
|
||||||
}
|
}
|
||||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
case callInstr@AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||||
val labelPrefix = jobContext.nextLabel("ai")
|
val labelPrefix = jobContext.nextLabel("ai")
|
||||||
inlinedFunctions(p.toString).map {
|
var inlinedCode = inlinedFunctions(p.toString)
|
||||||
|
if (inlinedCode.forall(_.source.isEmpty)) {
|
||||||
|
inlinedCode = inlinedCode.map(_.copy(source = callInstr.source))
|
||||||
|
}
|
||||||
|
inlinedCode.map {
|
||||||
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
line.copy(parameter = newLabel)
|
line.copy(parameter = newLabel)
|
||||||
|
@ -56,24 +56,34 @@ object Z80InliningCalculator extends AbstractInliningCalculator[ZLine] {
|
|||||||
|
|
||||||
override def inline(code: List[ZLine], inlinedFunctions: Map[String, List[ZLine]], jobContext: JobContext): List[ZLine] = {
|
override def inline(code: List[ZLine], inlinedFunctions: Map[String, List[ZLine]], jobContext: JobContext): List[ZLine] = {
|
||||||
code.flatMap {
|
code.flatMap {
|
||||||
case ZLine(CALL, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
case callInstr@ZLine(CALL, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||||
val labelPrefix = jobContext.nextLabel("ai")
|
val labelPrefix = jobContext.nextLabel("ai")
|
||||||
wrap(registers, jobContext,
|
wrap(registers, jobContext, {
|
||||||
inlinedFunctions(p.toString).map {
|
var inlinedCode = inlinedFunctions(p.toString)
|
||||||
|
if (inlinedCode.forall(_.source.isEmpty)) {
|
||||||
|
inlinedCode = inlinedCode.map(_.copy(source = callInstr.source))
|
||||||
|
}
|
||||||
|
inlinedCode.map {
|
||||||
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
line.copy(parameter = newLabel)
|
line.copy(parameter = newLabel)
|
||||||
case l => l
|
case l => l
|
||||||
})
|
}
|
||||||
case ZLine(JP | JR, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
})
|
||||||
|
case callInstr@ZLine(JP | JR, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||||
val labelPrefix = jobContext.nextLabel("ai")
|
val labelPrefix = jobContext.nextLabel("ai")
|
||||||
wrap(registers, jobContext,
|
wrap(registers, jobContext, {
|
||||||
inlinedFunctions(p.toString).map {
|
var inlinedCode = inlinedFunctions(p.toString)
|
||||||
|
if (inlinedCode.forall(_.source.isEmpty)) {
|
||||||
|
inlinedCode = inlinedCode.map(_.copy(source = callInstr.source))
|
||||||
|
}
|
||||||
|
inlinedCode.map {
|
||||||
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||||
line.copy(parameter = newLabel)
|
line.copy(parameter = newLabel)
|
||||||
case l => l
|
case l => l
|
||||||
} :+ ZLine.implied(RET))
|
} :+ ZLine.implied(RET)
|
||||||
|
})
|
||||||
case x => List(x)
|
case x => List(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user