Next Previous Contents

## 10. Pseudo functions

Pseudo functions expect their arguments in parenthesis, and they have a result, either a string or an expression.

## 10.1 `.BANKBYTE`

The function returns the bank byte (that is, bits 16-23) of its argument. It works identical to the '^' operator.

See: `.HIBYTE`, `.LOBYTE`

## 10.2 `.BLANK`

Builtin function. The function evaluates its argument in braces and yields "false" if the argument is non blank (there is an argument), and "true" if there is no argument. The token list that makes up the function argument may optionally be enclosed in curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right parenthesis). The curly braces are not considered part of the list, a list just consisting of curly braces is considered to be empty.

As an example, the `.IFBLANK` statement may be replaced by

> `

>             .if     .blank({arg})

> `

## 10.3 `.CONCAT`

Builtin string function. The function allows to concatenate a list of string constants separated by commas. The result is a string constant that is the concatenation of all arguments. This function is most useful in macros and when used together with the `.STRING` builtin function. The function may be used in any case where a string constant is expected.

Example:

> `

>             .include        .concat ("myheader", ".", "inc")

> `

This is the same as the command

> `

>             .include        "myheader.inc"

> `

## 10.4 `.CONST`

Builtin function. The function evaluates its argument in braces and yields "true" if the argument is a constant expression (that is, an expression that yields a constant value at assembly time) and "false" otherwise. As an example, the .IFCONST statement may be replaced by

> `

>             .if     .const(a + 3)

> `

## 10.5 `.HIBYTE`

The function returns the high byte (that is, bits 8-15) of its argument. It works identical to the '>' operator.

See: `.LOBYTE`, `.BANKBYTE`

## 10.6 `.HIWORD`

The function returns the high word (that is, bits 16-31) of its argument.

See: `.LOWORD`

## 10.7 `.IDENT`

The function expects a string as its argument, and converts this argument into an identifier. If the string starts with the current `.LOCALCHAR`, it will be converted into a cheap local identifier, otherwise it will be converted into a normal identifier.

Example:

> `

>             .macro  makelabel       arg1, arg2
>                     .ident (.concat (arg1, arg2)):
>             .endmacro

>                     makelabel       "foo", "bar"

>                     .word           foobar          ; Valid label

> `

## 10.8 `.LEFT`

Builtin function. Extracts the left part of a given token list.

Syntax:

> `

>             .LEFT (<int expr>, <token list>)

> `

The first integer expression gives the number of tokens to extract from the token list. The second argument is the token list itself. The token list may optionally be enclosed into curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case).

Example:

To check in a macro if the given argument has a '#' as first token (immediate addressing mode), use something like this:

> `

>             .macro  ldax    arg
>                     ...
>                     .if (.match (.left (1, {arg}), #))

>                     ; ldax called with immediate operand
>                     ...

>                     .endif
>                     ...
>             .endmacro

> `

See also the `.MID` and `.RIGHT` builtin functions.

## 10.9 `.LOBYTE`

The function returns the low byte (that is, bits 0-7) of its argument. It works identical to the '<' operator.

See: `.HIBYTE`, `.BANKBYTE`

## 10.10 `.LOWORD`

The function returns the low word (that is, bits 0-15) of its argument.

See: `.HIWORD`

## 10.11 `.MATCH`

Builtin function. Matches two token lists against each other. This is most useful within macros, since macros are not stored as strings, but as lists of tokens.

The syntax is

> `

>             .MATCH(<token list #1>, <token list #2>)

> `

Both token list may contain arbitrary tokens with the exception of the terminator token (comma resp. right parenthesis) and

- end-of-line
- end-of-file

The token lists may optionally be enclosed into curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case). Often a macro parameter is used for any of the token lists.

Please note that the function does only compare tokens, not token attributes. So any number is equal to any other number, regardless of the actual value. The same is true for strings. If you need to compare tokens and token attributes, use the `.XMATCH` function.

Example:

Assume the macro `ASR`, that will shift right the accumulator by one, while honoring the sign bit. The builtin processor instructions will allow an optional "A" for accu addressing for instructions like `ROL` and `ROR`. We will use the `.MATCH` function to check for this and print and error for invalid calls.

> `

>             .macro  asr     arg

>                     .if (.not .blank(arg)) .and (.not .match ({arg}, a))
>                     .error "Syntax error"
>                     .endif

>                     cmp     #$80            ; Bit 7 into carry
>                     lsr     a               ; Shift carry into bit 7

>             .endmacro

> `

The macro will only accept no arguments, or one argument that must be the reserved keyword "A".

See: `.XMATCH`

## 10.12 `.MID`

Builtin function. Takes a starting index, a count and a token list as arguments. Will return part of the token list.

Syntax:

> `

>             .MID (<int expr>, <int expr>, <token list>)

> `

The first integer expression gives the starting token in the list (the first token has index 0). The second integer expression gives the number of tokens to extract from the token list. The third argument is the token list itself. The token list may optionally be enclosed into curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case).

Example:

To check in a macro if the given argument has a '`#`' as first token (immediate addressing mode), use something like this:

> `

>             .macro  ldax    arg
>                     ...
>                     .if (.match (.mid (0, 1, {arg}), #))

>                     ; ldax called with immediate operand
>                     ...

>                     .endif
>                     ...
>             .endmacro

> `

See also the `.LEFT` and `.RIGHT` builtin functions.

## 10.13 `.REF, .REFERENCED`

Builtin function. The function expects an identifier as argument in braces. The argument is evaluated, and the function yields "true" if the identifier is a symbol that has already been referenced somewhere in the source file up to the current position. Otherwise the function yields false. As an example, the `.IFREF` statement may be replaced by

> `

>             .if     .referenced(a)

> `

See: `.DEFINED`

## 10.14 `.RIGHT`

Builtin function. Extracts the right part of a given token list.

Syntax:

> `

>             .RIGHT (<int expr>, <token list>)

> `

The first integer expression gives the number of tokens to extract from the token list. The second argument is the token list itself. The token list may optionally be enclosed into curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case).

See also the `.LEFT` and `.MID` builtin functions.

## 10.15 `.SIZEOF`

`.SIZEOF` is a pseudo function that returns the size of its argument. The argument can be a struct/union, a struct member, a procedure, or a label. In case of a procedure or label, its size is defined by the amount of data placed in the segment where the label is relative to. If a line of code switches segments (for example in a macro) data placed in other segments does not count for the size.

Please note that a symbol or scope must exist, before it is used together with `.SIZEOF` (this may get relaxed later, but will always be true for scopes). A scope has preference over a symbol with the same name, so if the last part of a name represents both, a scope and a symbol, the scope is chosen over the symbol.

After the following code:

> `

>             .struct Point                   ; Struct size = 4
>                     xcoord  .word
>                     xcoord  .word
>             .endstruct

>             P:      .tag    Point           ; Declare a point
>             @P:     .tag    Point           ; Declare another point

>             .code
>             .proc   Code
>                     nop
>                     .proc   Inner
>                             nop
>                     .endproc
>                     nop
>             .endproc

>             .proc   Data
>             .data                           ; Segment switch!!!
>                     .res    4
>             .endproc

> `

`.sizeof(Point)`

  will have the value 4, because this is the size of struct `Point`.

`.sizeof(Point::xcoord)`

  will have the value 2, because this is the size of the member `xcoord` in struct `Point`.

`.sizeof(P)`

  will have the value 4, this is the size of the data declared on the same source line as the label `P`, which is in the same segment that `P` is relative to.

`.sizeof(@P)`

  will have the value 4, see above. The example demonstrates that `.SIZEOF` does also work for cheap local symbols.

`.sizeof(Code)`

  will have the value 3, since this is amount of data emitted into the code segment, the segment that was active when `Code` was entered. Note that this value includes the amount of data emitted in child scopes (in this case `Code::Inner`).

`.sizeof(Code::Inner)`

  will have the value 1 as expected.

`.sizeof(Data)`

  will have the value 0. Data is emitted within the scope `Data`, but since the segment is switched after entry, this data is emitted into another segment.

## 10.16 `.STRAT`

Builtin function. The function accepts a string and an index as arguments and returns the value of the character at the given position as an integer value. The index is zero based.

Example:

> `

>             .macro  M       Arg
>                     ; Check if the argument string starts with '#'
>                     .if (.strat (Arg, 0) = '#')
>                     ...
>                     .endif
>             .endmacro

> `

## 10.17 `.SPRINTF`

Builtin function. It expects a format string as first argument. The number and type of the following arguments depend on the format string. The format string is similar to the one of the C `printf` function. Missing things are: Length modifiers, variable width.

The result of the function is a string.

Example:

> `

>             num     = 3

>             ; Generate an identifier:
>             .ident (.sprintf ("%s%03d", "label", num)):

> `

## 10.18 `.STRING`

Builtin function. The function accepts an argument in braces and converts this argument into a string constant. The argument may be an identifier, or a constant numeric value.

Since you can use a string in the first place, the use of the function may not be obvious. However, it is useful in macros, or more complex setups.

Example:

> `

>             ; Emulate other assemblers:
>             .macro  section name
>                     .segment        .string(name)
>             .endmacro

> `

## 10.19 `.STRLEN`

Builtin function. The function accepts a string argument in braces and evaluates to the length of the string.

Example:

The following macro encodes a string as a pascal style string with a leading length byte.

> `

>             .macro  PString Arg
>                     .byte   .strlen(Arg), Arg
>             .endmacro

> `

## 10.20 `.TCOUNT`

Builtin function. The function accepts a token list in braces. The function result is the number of tokens given as argument. The token list may optionally be enclosed into curly braces which are not considered part of the list and not counted. Enclosement in curly braces allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case).

Example:

The `ldax` macro accepts the '#' token to denote immediate addressing (as with the normal 6502 instructions). To translate it into two separate 8 bit load instructions, the '#' token has to get stripped from the argument:

> `

>             .macro  ldax    arg
>                     .if (.match (.mid (0, 1, {arg}), #))
>                     ; ldax called with immediate operand
>                     lda     #<(.right (.tcount ({arg})-1, {arg}))
>                     ldx     #>(.right (.tcount ({arg})-1, {arg}))
>                     .else
>                     ...
>                     .endif
>             .endmacro

> `

## 10.21 `.XMATCH`

Builtin function. Matches two token lists against each other. This is most useful within macros, since macros are not stored as strings, but as lists of tokens.

The syntax is

> `

>             .XMATCH(<token list #1>, <token list #2>)

> `

Both token list may contain arbitrary tokens with the exception of the terminator token (comma resp. right parenthesis) and

- end-of-line
- end-of-file

The token lists may optionally be enclosed into curly braces. This allows the inclusion of tokens that would otherwise terminate the list (the closing right paren in the given case). Often a macro parameter is used for any of the token lists.

The function compares tokens and token values. If you need a function that just compares the type of tokens, have a look at the `.MATCH` function.

See: `.MATCH`

Next Previous Contents