diff --git a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala index 4373b6ad..523454eb 100644 --- a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala +++ b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala @@ -61,11 +61,8 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements val pos = stmt.position // generic warnings: stmt match { - case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz", List(TextLiteralExpression(ch)))) => - ch.last match { - case LiteralExpression(0, _) => //ok - case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position) - } + case ExpressionStatement(expr@FunctionCallExpression("strzlen" | "putstrz" | "strzcmp" | "strzcopy", params)) => + for (param <- params) checkIfNullTerminated(stmt, param) case ExpressionStatement(VariableExpression(v)) => val volatile = ctx.env.maybeGet[ThingInMemory](v).fold(false)(_.isVolatile) if (!volatile) ctx.log.warn("Pointless expression.", stmt.position) @@ -133,6 +130,17 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements } } + private def checkIfNullTerminated(stmt: ExecutableStatement, param: Expression): Unit = { + param match { + case TextLiteralExpression(ch) => + ch.last match { + case LiteralExpression(0, _) => //ok + case _ => ctx.log.warn("Passing a non-null-terminated string to a function that expects a null-terminated string.", stmt.position) + } + case _ => + } + } + def search(expr: Expression, cv: VV): VV = { expr match { case FunctionCallExpression(op, List(VariableExpression(v), arg)) if op.endsWith("=") && op != "<=" && op != ">=" => diff --git a/src/main/scala/millfork/compiler/mos/BuiltIns.scala b/src/main/scala/millfork/compiler/mos/BuiltIns.scala index cbad7ad7..72f85263 100644 --- a/src/main/scala/millfork/compiler/mos/BuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/BuiltIns.scala @@ -613,7 +613,7 @@ object BuiltIns { AssemblyLine.variable(ctx, CMP, rva, 0)) case _ => // TODO comparing expressions - ctx.log.error("Too complex expressions in comparison", lhs.position) + ctx.log.error("Too complex expressions in comparison", lhs.position.orElse(rhs.position)) (Nil, Nil, Nil, Nil) } val lType = MosExpressionCompiler.getExpressionType(ctx, lhs) diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index e2b23148..dc6ad32e 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -798,7 +798,26 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa case e: ExecutableStatement => Some(e) case _ => None } - val needsExtraRTS = !stmt.isMacro && !stmt.assembly && (statements.isEmpty || !statements.last.isInstanceOf[ReturnStatement]) + val paramForAutomaticReturn: List[Option[Expression]] = if (stmt.isMacro || stmt.assembly) { + Nil + } else if (statements.isEmpty) { + List(None) + } else { + statements.last match { + case _: ReturnStatement => Nil + case WhileStatement(VariableExpression(tr), _, _, _) => + if (resultType.size > 0 && env.getBooleanConstant(tr).contains(true)) { + List(Some(LiteralExpression(0, 1))) // TODO: what if the loop is breakable? + } else List(None) + case DoWhileStatement(_, _, VariableExpression(tr), _) => + if (resultType.size > 0 && env.getBooleanConstant(tr).contains(true)) { + List(Some(LiteralExpression(0, 1))) // TODO: what if the loop is breakable? + } else List(None) + case _ => + // None so the compiler warns + List(None) + } + } if (stmt.isMacro) { if (stmt.bank.isDefined) { log.error("Macro functions cannot be in a defined segment", stmt.position) @@ -823,7 +842,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa env, stackVariablesSize, stmt.address.map(a => this.eval(a).getOrElse(errorConstant(s"Address of `${stmt.name}` is not a constant"))), - executableStatements ++ (if (needsExtraRTS) List(ReturnStatement(None).pos(executableStatements.lastOption.fold(stmt.position)(_.position))) else Nil), + executableStatements ++ paramForAutomaticReturn.map(param => ReturnStatement(param).pos(executableStatements.lastOption.fold(stmt.position)(_.position))), interrupt = stmt.interrupt, kernalInterrupt = stmt.kernalInterrupt, reentrant = stmt.reentrant,