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

Preprocessor: add #use A=B and if(i,t,e)

This commit is contained in:
Karol Stasiak 2019-06-14 12:00:45 +02:00
parent 3852b2dbe9
commit 51a6ec9d73
4 changed files with 41 additions and 11 deletions

View File

@ -44,6 +44,10 @@
* 6502: Fixed optimizations of comparisons.
* Preprocessor: Added `#use A=B` directive
* Preprocessor: Added `if` function
* Fixed volatile-related bugs.
* Fixed optimizations removing jumps to jumps.

View File

@ -103,7 +103,14 @@ The following features are defined based on the chosen CPU and compilation optio
The `defined` function returns 1 if the feature is defined, 0 otherwise.
All the other functions and operators treat undefined features as if they were defined as 0.
TODO
The `if` function returns its second parameter if the first parameter is defined and non-zero, and the third parameter otherwise:
// prints 400:
#infoeval if(1, 400, 500)
// prints 500:
#infoeval if(0, 400, 500)
TODO
`not`, `lo`, `hi`, `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
The following Millfork operators and functions are not available in the preprocessor:
@ -140,11 +147,22 @@ Evaluates an expression and emits the result as a diagnostic message.
### `#use`
Exports a feature value under its name to the parser.
The parser will substitute every use of that name as a variable or constant
#use <ident> = <expr>
#use <feature>
// equivalent to #use <feature> = <feature>
Exports a value to the parser.
The parser will substitute every use of the given identifier as a variable or constant
with the numeric value of the feature.
#use CPU_MODEL = if(CPU_65816 | ARCH_X86, 16, 8)
putstrz("Your CPU is "z)
putword(CPU_MODEL)
putstrz("-bit."z)
The substitution will happen only within the current file.
To use such value in other files, consider this:
To use such value in other files, consider using a normal constant:
#use WIDESCREEN
const byte is_widescreen = WIDESCREEN

View File

@ -59,10 +59,14 @@ object Preprocessor {
keyword match {
case "use" => if (enabled) {
if (param == "") log.error("#use should have a parameter", pos)
featureConstants += param -> options.features.getOrElse(param, {
log.warn(s"Undefined parameter $param, assuming 0", pos)
0L
})
param.split("=", 2) match {
case Array(p) =>
featureConstants += param -> options.features.getOrElse(param, {
log.warn(s"Undefined parameter $param, assuming 0", pos)
0L
})
case Array(p0,p1) => featureConstants += p0.trim() -> evalParam(p1, pos)
}
}
case "fatal" => if (enabled) log.fatal(param, pos)
case "error" => if (enabled) log.error(param, pos)
@ -167,7 +171,8 @@ class PreprocessorParser(options: CompilationOptions) {
case ("not", List(p)) => {m:M => Some(if (p(m).getOrElse(0L) == 0) 1 else 0)}
case ("lo", List(p)) => {m:M => Some(p(m).getOrElse(0L) & 0xff)}
case ("hi", List(p)) => {m:M => Some(p(m).getOrElse(0L).>>(8).&(0xff))}
case ("defined" | "lo" | "hi" | "not", ps) =>
case ("if", List(i, t, e)) => {m:M => if (i(m).getOrElse(0L) != 0) t(m) else e(m)}
case ("defined" | "lo" | "hi" | "not" | "if", ps) =>
log.error(s"Invalid number of parameters to $name: ${ps.length}")
alwaysNone
case _ =>

View File

@ -195,14 +195,17 @@ class BasicSymonTest extends FunSuite with Matchers {
| #use ARCH_6502
| #use ARCH_I80
|
| #use HORSE = ARCH_6502
| #use COW = ARCH_I80
|
| #if 1
| asm void main () {
| #if ARCH_6502
| lda #ARCH_6502
| lda #HORSE
| sta output
| rts
| #elseif ARCH_I80
| ld a,ARCH_I80
| ld a,COW
| ld (output),a
| ret
| #else