Skip to content

Preprocessor Documentation

Lucas Eduardo Gulka Pulcinelli edited this page Sep 23, 2022 · 2 revisions

The Problem with ICMC Assembly

Because the assembly is based on a RISC architecture, there are many userful instructions not present in other processors that make writing code more difficult. Notably, the lack of comparisions between registers and constants or registers and memory values, as well as the way colorful string variables are created, creates an unneded difficulty during the development of projects. Because of that, and to make code more readable, the ICMC assembly preprocessor was created.

How to Use the Preprocessor

As the preprocessor is a simple python script, python 3 is necessary, however no modules need to be installed with it. The usage is

preprocessor.py <charmap.json> <input.asm> <output.asm>

Where the charmap.json defines the name to ascii mapping (for instance, to use "questionmark" as a definiton for colors), as well as the color names available (there is an example in res/), input.asm is the file that needs to be preprocessed, and output.asm is the output file (Note that there should be a single input and a single output, this was made because the ICMC assembler does not support more than one file as well).

Description of All Capabilities

The ICMC assembly preprocessor has two main capabilites, both used for constant values and character manipulation envisioning readability and more compile-time processing, rather than run-time workarounds.

Defines

Definitions work almost the same way as in C: a line should be started with a #define, followed by a definition name and a numeric value (string defines are not supported, and won't be until a good use case arrives). The name should follow the regular expression [a-zA-Z0-9_]+, meaning any combination of letters and numbers with underscores. The value follows the same regex, including '#' because of constant numeric values in the assembly language means that the space character is not valid.

The defines shoud be used inside the code using the definiton name precedded by a '$'.

Pre-Made Definitions

some defines are already included by default: chacters with colors and the screen size.

Characters can be used in the format $_, for instance $green_a, $yellow_Z, $poolgreen_vslash, etc. All possible characters and colors are defined in the charmap.json. Also, definitions in the format $ default to white, and $ is a value that can be added to white characters to generate the same character but in the color specified.

The screen size definitions are $screen_width and $screen_height, with values 40 and 30 by default to follow the ICMC assembly emulator's screen.

'Macros'

'Macros' (notice the quotes) are functions to generate constant values given an input. They can be created the same way as defines, but with parenthesis and a more complex value field, using #define <macro_name>() <expression>. Notice the macro is followed by an open and close parenthesis always, meaning no argument names should be passed (different from most languages).

The expression can be any python code (without spaces) that can be passed into eval(). Some variables are available: arg is a list with all arguments passed into the macro call (arg[0] is the first argument, arg[1] is the second, and so on), sw and sh are the screen width and height, and defs is a dictionary containing all definitions; for instance: defs["screen_width"] == sw is always true.

Pre-Made 'Macros'

sum() is a simple macro that just sums any elements passed to it, defined as sum(arg). position uses two arguments to describe an exact position on the screen, defined as arg[0]+arg[1]*sw. And there is the special eval() macro, that will be detailed shortly.

The eval 'Macro'

This is a special macro that just call for the evaluation of another expression inside it. It's main use is to enable simple in place evaluation instead of forcing the creation of a dedicated macro (for instance, the macro half(), defined as arg[0]//2, can be substituted by a simple call to $eval(arg[0]//2) if it is used only one or twice).

Other Details

One important detail is that macros can call macros inside them (except for eval), or use definitions inside them, without a leading '$'. For instance, loadn r0, $position(0,eval(sh//2)) will evaluate to #600, or the first character in the middle line of the screen.

The formal name of this preprocessor function is 'macro' because it can only generate numbers as outputs, not expressions containing the arguments text values as in C.

Examples of uses

Many examples are in the examples/ directory, the most advanced one is hello_world.asm, that uses some macro manipulation to print a "Hello, World!" message in the center of the screen, filled by some characters around it in the same line. This seems like a simple example, and it is, but it would be exponentially harder to undestand without any context and just random values being loadn'd in registers.