mirror of
https://github.com/KarolS/millfork.git
synced 2026-04-20 18:16:35 +00:00
Module templates
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
* [Preprocessor](lang/preprocessor.md)
|
||||
|
||||
* [Modules](lang/modules.md)
|
||||
|
||||
* [Syntax](lang/syntax.md)
|
||||
|
||||
* [Types](lang/types.md)
|
||||
|
||||
@@ -60,7 +60,8 @@ See [the list of available encodings](../lang/text.md).
|
||||
* `screen_encoding` – default encoding for screencodes (literals with encoding specified as `scr`).
|
||||
Default: the same as `encoding`.
|
||||
|
||||
* `modules` – comma-separated list of modules that will be automatically imported
|
||||
* `modules` – comma-separated list of modules that will be automatically imported.
|
||||
This list cannot contain module template instantiations.
|
||||
|
||||
* other compilation options (they can be overridden using commandline options):
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
* [Preprocessor](lang/preprocessor.md)
|
||||
|
||||
* [Modules](lang/modules.md)
|
||||
|
||||
* [Syntax](lang/syntax.md)
|
||||
|
||||
* [Types](lang/types.md)
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
[< back to index](../doc_index.md)
|
||||
|
||||
# Program structure
|
||||
|
||||
A Millfork program is build from one or more modules.
|
||||
|
||||
Each module is stored in a single file.
|
||||
All source filenames passed to the compiler are considered to be modules of that program, called _root modules_.
|
||||
|
||||
Each module has a name, which is its unique identifier.
|
||||
A module name is a sequence of slash-separated valid Millfork identifiers.
|
||||
The name also defines where the module is located:
|
||||
a module named `a/b` is presumed to exist in `a/b.mfk`
|
||||
and it's looked up first in the current working directory,
|
||||
and then in the include directories.
|
||||
|
||||
A module can import other modules, using the `import` statement.
|
||||
Importing the same module multiple times merely marks it as imported by multiple modules,
|
||||
but the program will still contain only one copy of it.
|
||||
Examples:
|
||||
|
||||
import string
|
||||
import cbm_file
|
||||
|
||||
Usually, the imported module will undergo the first phase of compilation first.
|
||||
This means that the constants in the imported module will be resolved first, allowing you to use them in the importing module.
|
||||
|
||||
|
||||
The only exception to this rule is when the importing graph has a cycle, in which case the order of modules within the cycle is unspecified.
|
||||
|
||||
A platform may define starting modules using the `modules=` directive of the `[compilation]` section.
|
||||
All starting modules are considered to be imported by all source files explicitly mentioned on the command line.
|
||||
|
||||
### Module templates
|
||||
|
||||
If the first line of a source file starts with the `#template` directive,
|
||||
then the source is considered to be a _module template_.
|
||||
Module templates are a tool for generating repetitive code, similar to COBOL copybooks or Go Generate.
|
||||
|
||||
The template directive contains a comma-separated list of parameters.
|
||||
It's recommended that the names of parameters begin and end with non-alphanumeric characters:
|
||||
|
||||
#template $P1$, $P2$
|
||||
|
||||
A module template cannot be imported as-is.
|
||||
When importing a module template, you import a concrete instantiation of it.
|
||||
|
||||
For example, if the file `temp.mfk` contains the `#template` from above,
|
||||
you can import it by providing a list of numeric literals or identifiers:
|
||||
|
||||
import temp<1, 2>
|
||||
|
||||
This instantiates a new module named `temp<1,2>` (if it hasn't been instantiated anywhere else).
|
||||
The code in that module is generated by replacing every instance of the parameter names with the actual argument content.
|
||||
Parameters that are numeric literals are normalized to their decimal representations.
|
||||
|
||||
Your program may contain multiple modules created from the same template with different parameters. For example,
|
||||
|
||||
import temp<3, 4>
|
||||
import temp<5, 6>
|
||||
import temp<$5, $6>
|
||||
|
||||
instantiates and imports two similar, yet different modules: `temp<3,4>` and `temp<5,6>`.
|
||||
The third import imports a module that has already been instantiated and imported, so it's redundant.
|
||||
|
||||
The instantiation works through simple text replacement. For example, if `temp.mfk` contains:
|
||||
|
||||
#template $P1$, $P2$
|
||||
const byte a$P1$ = $P2$
|
||||
|
||||
then the `temp<1,2>` module will contain
|
||||
|
||||
const byte a1 = 2
|
||||
|
||||
This substitution is performed before preprocessing, so those substitutions are available for the preprocessor directives.
|
||||
It applies to identifiers, string literals, keywords, preprocesor directives etc.
|
||||
|
||||
**Warning:** This mechanism provides no direct way for preventing duplicates of code
|
||||
that does not depend on the template parameters, or depends on only some template parameters.
|
||||
In such situations, it might be advisable to put the non-dependent definitions in another module that is not a template,
|
||||
or in a module template with fewer parameters. For example, instead of writing:
|
||||
|
||||
#template $N$
|
||||
const byte X = 50
|
||||
array a$N$ [X]
|
||||
|
||||
(which would define duplicate `X`s if imported multiple times), consider writing two files:
|
||||
|
||||
#template $N$
|
||||
import define_X
|
||||
array a$N$ [X]
|
||||
>
|
||||
|
||||
//define_X.mfk:
|
||||
const byte X = 50
|
||||
|
||||
|
||||
@@ -129,6 +129,16 @@ These features are used to identify the target machine in multiplatform programs
|
||||
|
||||
### Built-in preprocessor functions and operators
|
||||
|
||||
The `same` function returns 1 if given identical identifiers and 0 otherwise.
|
||||
It is the only function that does not support any other kind of parameters, and it's only useful in module templates.
|
||||
|
||||
// prints 1:
|
||||
#infoeval same(a,a)
|
||||
// prints 0:
|
||||
#infoeval same(a,b)
|
||||
// fails to compile
|
||||
#infoeval same(a,1)
|
||||
|
||||
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.
|
||||
|
||||
@@ -145,6 +155,11 @@ TODO
|
||||
The following Millfork operators and functions are not available in the preprocessor:
|
||||
`+'`, `-'`, `*'`, `<<'`, `>>'`, `:`, `>>>>`, `nonet`, all the assignment operators
|
||||
|
||||
### `#template`
|
||||
|
||||
Defines the source to be a module template. See [Modules](./modules.md) for more information.
|
||||
|
||||
|
||||
### `#if/#elseif/#else/#endif`
|
||||
|
||||
#if <expr>
|
||||
|
||||
Reference in New Issue
Block a user