# Expressions

Ophis permits a reasonably rich set of arithmetic operations to be done at assemble time. So far, all of our arguments and values have either been constants or label names. In this chapter, we will modify the `print` macro so that it calls a subroutine to do the actual printing. This will shrink the final code size a fair bit.

Here's our printing routine. It's fairly straightforward.

    ; PRINTSTR routine.  Accumulator stores the low byte of the address,
    ; X register stores the high byte.  Destroys the values of $10 and
    ; $11.

    .scope
    printstr:
            sta $10
            stx $11
            ldy #$00
    _lp:    lda ($10), y
            beq _done
            jsr chrout
            iny
            bne _lp
    _done:  rts
    .scend

However, now we are faced with the problem of what to do with the `print` macro. We need to take a 16-bit value and store it in two 8-bit registers. We can use the `<` and `>` operators to take the low or high byte of a word, respectively. The `print` macro becomes:

    .macro print
            lda #<_1
            ldx #>_1
            jsr printstr
    .macend

Also, since BASIC uses the locations $10 and $11, we should really cache them at the start of the program and restore them at the end:

    .data
    .org $C000
    .space cache 2
    .text

            ; Save the zero page locations that printstr uses.
            lda $10
            sta cache
            lda $11
            sta cache+1

            ; ... main program goes here ...

            ; Restore the zero page values printstr uses.
            lda cache
            sta $10
            lda cache+1
            sta $11

Note that we only have to name `cache` once, but can use addition to refer to any offset from it.

We could spare ourselves some trouble here and use $fb instead of $10, which BASIC does not use, but the example is more thorough this way.

Ophis supports following operations, with the following precedence levels (higher entries bind more tightly):

## Ophis Operators

Operators | Description
`[ ]` | Parenthesized expressions
`< >` | Byte selection (low, high)
`* /` | Multiply, divide
`+ -` | Add, subtract
`| & ^` | Bitwise OR, AND, XOR

Note that brackets, not parentheses, are used to group arithmetic operations. Parentheses are reserved for the indirect addressing modes.

The code for this version of the code is in tutor6-fname.