1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-12 06:29:34 +00:00

Added alias support

This commit is contained in:
Karol Stasiak 2018-07-12 01:23:38 +02:00
parent af1e6d9c9f
commit 35f3638a4f
8 changed files with 72 additions and 4 deletions

View File

@ -8,6 +8,8 @@
* Unified the syntax of commandline switches.
* Added aliases.
* Automatic selection of text encoding based on target platform.
* **Potentially breaking change!** `scr` now refers to the default screencodes as defined for the platform.

View File

@ -60,6 +60,28 @@ For every variable `x` larger than a byte, extra subvariables are defined:
TODO
### Alias definitions
`alias <alias> = <name>`
Sets an alias for a global name.
Unless shadowed by a local name, the alias will point to the given global object:
byte x
alias a = x
void f() {
a = 5 // writes to the global variable x
}
void f() {
byte a
a = 5 // writes to the local variable a
}
Aliases can be used for variables, arrays, constants, functions, and types,
but not for text encodings, array formats or keywords.
### Array declarations
An array is a continuous sequence of bytes in memory.

View File

@ -228,7 +228,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
if ((t ne null) && clazz.isInstance(t)) {
t.asInstanceOf[T]
} else {
ErrorReporting.fatal(s"`$name` is not a ${clazz.getSimpleName}", position)
t match {
case Alias(_, target) => root.get[T](target)
case _ => ErrorReporting.fatal(s"`$name` is not a ${clazz.getSimpleName}", position)
}
}
} else parent.fold {
ErrorReporting.fatal(s"${clazz.getSimpleName} `$name` is not defined", position)
@ -236,6 +239,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
_.get[T](name, position)
}
}
private def root: Environment = parent.fold(this)(_.root)
def maybeGet[T <: Thing : Manifest](name: String): Option[T] = {
if (things.contains(name)) {
@ -244,7 +249,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
if ((t ne null) && clazz.isInstance(t)) {
Some(t.asInstanceOf[T])
} else {
None
t match {
case Alias(_, target) => root.maybeGet[T](target)
case _ => None
}
}
} else parent.flatMap {
_.maybeGet[T](name)
@ -568,6 +576,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
}
def registerAlias(stmt: AliasDefinitionStatement): Unit = {
addThing(Alias(stmt.name, stmt.target), stmt.position)
}
def registerFunction(stmt: FunctionDeclarationStatement, options: CompilationOptions): Unit = {
val w = get[Type]("word")
val name = stmt.name
@ -1062,6 +1074,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case f: FunctionDeclarationStatement => registerFunction(f, options)
case v: VariableDeclarationStatement => registerVariable(v, options)
case a: ArrayDeclarationStatement => registerArray(a, options)
case a: AliasDefinitionStatement => registerAlias(a)
case i: ImportStatement => ()
}
if (options.zpRegisterSize > 0 && !things.contains("__reg")) {

View File

@ -9,6 +9,8 @@ sealed trait Thing {
def name: String
}
case class Alias(name: String, target: String) extends Thing
sealed trait CallableThing extends Thing
sealed trait VariableLikeThing extends Thing

View File

@ -218,6 +218,10 @@ case class ProcessedContents(processor: String, values: ArrayContents) extends A
ProcessedContents(processor, values.replaceVariable(variableToReplace, expression))
}
case class AliasDefinitionStatement(name: String, target: String) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = Nil
}
case class ArrayDeclarationStatement(name: String,
bank: Option[String],
length: Option[Expression],

View File

@ -163,6 +163,12 @@ abstract class MfParser[T](filename: String, input: String, currentDirectory: St
def arrayContentsForAsm: P[RawBytesStatement] = (arrayListContents | arrayStringContents).map(RawBytesStatement)
val aliasDefinition: P[Seq[AliasDefinitionStatement]] = for {
p <- position()
name <- "alias" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
target <- "=" ~/ HWS ~/ identifier ~/ HWS
} yield Seq(AliasDefinitionStatement(name, target).pos(p))
val arrayDefinition: P[Seq[ArrayDeclarationStatement]] = for {
p <- position()
bank <- bankDeclaration
@ -366,7 +372,7 @@ abstract class MfParser[T](filename: String, input: String, currentDirectory: St
val program: Parser[Program] = for {
_ <- Start ~/ AWS ~/ Pass
definitions <- (importStatement | arrayDefinition | functionDefinition | globalVariableDefinition).rep(sep = EOL)
definitions <- (importStatement | arrayDefinition | aliasDefinition | functionDefinition | globalVariableDefinition).rep(sep = EOL)
_ <- AWS ~ End
} yield Program(definitions.flatten.toList)

View File

@ -74,7 +74,7 @@ public class CPURAM {
public final void write(int addr, int data) {
addr &= 0xffff;
if (!mem.writeable()[addr]) {
throw new RuntimeException("Can't write to $" + Integer.toHexString(addr));
throw new RuntimeException("Can't write $" + Integer.toHexString(data & 0xff) + "to $" + Integer.toHexString(addr));
}
mem.output()[addr] = (byte) data;
}

View File

@ -149,4 +149,23 @@ class BasicSymonTest extends FunSuite with Matchers {
| }
""".stripMargin){ m => () }
}
test("Alias test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos)(
"""
| alias small = byte
| alias big = word
| byte crash @$bfff
| void main () {
| big w
| small b
| b = 1
| w = 1
| b <<= 8
| w <<= 8
| if b != 0 { crash = 1 }
| if w == 0 { crash = 2 }
| }
""".stripMargin){ m => () }
}
}