%YAML 1.2 --- name: Z80 Assembly uuid: EDE7FFE3-F4DD-4BE1-94D9-ED7F973D2237 file_extensions: [asm, s, ASM, S] scope: source.z80 variables: address: '(?:&[HX][0-9a-fA-F]{4}|[$#&][0-9a-fA-F]{4}|\b0X[0-9a-fA-F]{4}|\b0[a-fA-F]{4}H|\b[0-9]{4}H|[0-9]{4,5}D)\b' binary: '(?:%[01]+|[01]+B)\b' comment: '(?:;.+)' conditionals: '(?i)\b(?:NC|NZ|PE|PO|C|M|P|Z)\b' decimal: '(?:[0-9]+D|[0-9]+)' hexidecimal: '(?:&[HX][0-9a-fA-F]{2}|[$#&][0-9a-fA-F]{2}|\b0X[0-9a-fA-F]{2}|\b0[a-fA-F]{2}H|\b[0-9]{2}H)\b' label: '\b[a-zA-Z][a-zA-Z0-9_]*[a-zA-Z0-9]\b' label_multi: '{{label}}(?:[~&^|+-]{{label}})*' number: '(?:{{binary}}|{{octal}}|{{hexidecimal}}|{{decimal}})' octal: '(?:&O[0-7]+|[0-7]+[OQ])\b' contexts: # The prototype context is prepended to all contexts but those setting # meta_include_prototype: false. prototype: - include: comments main: # The main context is the initial starting point of our syntax. # Include other contexts from here (or specify them directly). - include: strings - include: identifiers - include: directives - include: directives_data - include: opcodes - include: operators - include: registers - include: labels - include: addresses - include: numbers registers: - match: '(?i)\b(AF|BC|DE|HL)''' comment: '16-bit shadow registers (note: escaped single quote)' scope: variable.other.z80 - match: '(?i)\b(AF|BC|DE|HL|PC|SP|IX|IY)\b' comment: '16-bit registers' scope: variable.other.z80 - match: '(?i)\((AF|BC|DE|HL|SP|IX|IY|{{number}}|{{label}})(?:[+-]{{number}})?\)' comment: 'Pointer to 16-bit register/address (incl. offsets)' scope: variable.parameter.z80 - match: '(?i)\b(HX|HY|LX|LY)\b' comment: 'Undocumented 8-bit registers' scope: variable.other.z80 - match: '(?i)\b([ABCDEFHILR]|IXH|IXL|IYH|IYL|LX|LY|YL|YH)\b' comment: '8-bit registers' scope: variable.other.z80 opcodes: - match: '(?i)\b(CALL|JP|JR|DJNZ)\s+({{conditionals}}), ?({{address}}|{{label}})\b' comment: 'Calls and jumps, with a condition' captures: 1: keyword.control.z80 2: keyword.control.conditional.z80 3: variable.function.z80 - match: '(?i)\b(CALL|JP|JR|DJNZ)\s+({{address}}|{{label}})\b' captures: 1: keyword.control.z80 2: variable.function.z80 - match: '(?i)\b(JP)\s+(\((HL|IX|IY)\))' comment: 'Jumps using 16-bit registers' captures: 1: keyword.control.z80 2: variable.parameter.z80 - match: '(?i)\b(RET)(\s+{{conditionals}})?\b' comment: 'RETurn, with an optional condition' captures: 1: keyword.control.z80 2: keyword.control.conditional.z80 - match: '(?i)\b(RST) +(?:({{number}})|({{label}}))\b' captures: 1: keyword.control.z80 2: constant.numeric 3: variable.function.z80 - match: '(?i)\b(ADC|ADD|BIT|CCF|CP|CPL|CPD|CPDR|CPI|CPIR|DAA|DEC|DI|DJNZ|EI|EX|EXX|HALT|IM|IN|INC|IND|INDR|INF|INI|INIR||NEG|NOP|EXX|OR|OTDR|OTIR|OUT|OUTD|OUTI|POP|PUSH|RES|RETI|RETN|RL|RLA|RLC|RLCA|RLD|RR|RRA|RRC|RRCA|RRD|SBC|SCF|SET|SLA|SLI|SLL|SRA|SRL|SUB)\b' scope: keyword.control.z80 - match: '(?i)\b(LD|LDD|LDDR|LDI|LDIR)\b' scope: keyword.control.z80 operators: - match: '(?i)\b(AND|DEFINED|EQ|GE|GT|HIGH|LE|LOW|LT|MOD|NE|NOT|NUL|OR|SHL|SHR|XOR)\b' scope: keyword.control.z80 - match: '\s(!=|##|&&|<<|<=|>>|>=|\|\||[&$%*+/=?~><|!-])\s' scope: keyword.control.z80 identifiers: - match: '(?i)(^|\s+)(DEFL|MACRO|IRP|REPT|EXITM|ENDM)\s' scope: keyword.control.z80 directives: - match: '(?i)(^|\s+)(INCBIN|INCLUDE)\s' scope: keyword.control.import.z80 - match: '(?i)(^|\s+)(LOCAL|ORG|END|PUBLIC)\s' scope: keyword.control.z80 - match: '(?i)(^|\s+)(PROC|ENDP)\s' scope: keyword.control.z80 - match: '(?i)(^|\s+)\.(ERROR|SHIFT|WARNING)\s' scope: keyword.control.z80 - match: '(?i)^\s*(IFNDEF|IFDEF|IF) +({{label}})\s+({{comment}})?$' captures: 1: keyword.control.z80 2: variable.parameter.z80 3: comment.line.z80 - match: '(?i)(^|\s+)(ELSE|ENDIF)\s' scope: keyword.control.z80 - match: '(?i)^(.+?)\s+(EQU)\s+(.+?)(\s+{{comment}})?$' captures: 1: variable.parameter.z80 2: keyword.control.z80 3: constant.numeric 4: comment.line.z80 directives_data: - match: '(?i)\b(DEF[BMSW]|DB|DS|DW) ({{label}}(,{{label}})*)\b' captures: 1: storage.type.z80 2: variable.parameter.z80 - match: '(?i)\b(?:DEF[BMSW]|DB|DS|DW)\b' scope: storage.type.z80 addresses: - match: '{{address}}' scope: constant.other.address.z80 numbers: - match: '{{binary}}' scope: constant.other.binary.z80 - match: '{{octal}}' scope: constant.numeric.octal.z80 - match: '{{hexidecimal}}' scope: constant.numeric.hex.z80 - match: '{{decimal}}' scope: constant.numeric.integer.z80 strings: - match: '"' comment: 'Strings begin/end with double quotes' scope: punctuation.definition.string.begin.z80 push: inside_string inside_string: - meta_include_prototype: false - meta_scope: string.quoted.double.z80 - match: '\\.' scope: constant.character.escape.z80 - match: '"' scope: punctuation.definition.string.end.z80 pop: true labels: - match: '^({{label}}):?' comment: 'Label definition' captures: 1: entity.name.function.z80 - match: '^ +({{label}}):' comment: 'Indented label definition' captures: 1: entity.name.function.z80 - match: '\({{label_multi}}\)' comment: 'Address of label' scope: variable.parameter.z80 - match: ', ?({{label_multi}})\b' comment: 'Labels used in instructions' captures: 1: variable.function.z80 comments: - match: ';' comment: 'Comments begin with a ";" and finish at EOL' scope: punctuation.definition.comment.z80 push: # This is an anonymous context push for brevity. - meta_scope: comment.line.z80 - match: $\n? pop: true - match: '//' comment: 'Comments can also begin with a "//", and finish at EOL' scope: punctuation.definition.comment.z80 push: # This is an anonymous context push for brevity. - meta_scope: comment.line.z80 - match: $\n? pop: true