# 全能编译器
**Repository Path**: SA-1/zg-assembler-next
## Basic Information
- **Project Name**: 全能编译器
- **Description**: 一个VSCode的插件,支持 6502 / 65c816 / z80-gb / spc700 汇编指令
- **Primary Language**: TypeScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2024-12-09
- **Last Updated**: 2024-12-09
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Zeng Ge Assembler
[English](./doc/README-en.md)
> 注意:编译器只监视 `*.asm` 文件,并不是 `*.65s` 文件
## 所有编译器命令
1. [.BASE](#base)
2. [.ORG](#org)
3. [.DEF](#def)
4. [.ENUM .ENDE](#enum-ende)
5. [.DB .DW .DL](#db-dw-dl)
6. [.DBG .DWG .DLG .ENDD](#dbg-dwg-dlg-endd)
7. [.HEX](#hex)
8. [.IF .ELSEIF .ELSE .ENDIF](#if-elseif-else-endif)
9. [.IFDEF .IFNDEF .ELSE .ENDIF](#ifdef-ifndef-else-endif)
10. [.INCBIN](#incbin)
11. [.INCLUDE](#include)
12. [.MACRO .ENDM](#macro-endm)
13. [.REPEAT .ENDR](#repeat-endr)
14. [.MSG .ERROR](#msg-error)
---
## 配置文件
* [编译器插件地址](https://marketplace.visualstudio.com/items?itemName=ZENG-GE.zg-assembler)
* 或者可以在 VSCode 插件里搜索 `ZG Assembler` 即可找到插件
* 一个 [VSCode](https://code.visualstudio.com/) 的可扩展的编译器,目前支持 `6502` `65c816`(感谢Thirteen) `z80-gb`,将来会加入更多适应平台。
* 配置文件,当打开汇编文件会在目录下创建 `project-settings.json` 文件,默认以下配置
* 如果你想单独编译内核,请使用 `npm run build-core`,详情请查看 [内核单独编译方法](doc/内核单独编译方法.md)
```json
{
"platform": "6502", // 选择平台
"intellisense": true, // 是否开启智能提示
"outOfRangeWarning": true, // 编译结果越界警告
"entry": "main.asm", // 入口文件
"compileTimes": 2, // 编译次数,至少两次,否则会出错
"outputEntryFile": "", // 输出入口文件,不写则不输出
"outputSingleFile": "", // 单个文件输出,不写则不输出
"copyToClipboard": true, // 结果是否复制到剪贴板
"includes": ["**/*.asm"], // 项目包含的文件
"excludes": [] // 项目排除的文件
}
```
---
## 功能介绍
### 编译
* 在`asm`文件下的编辑器内,点击鼠标右键则会出现编译菜单。
---
### 标签
* 在这个版本增加了子标签的功能,可以使用例如 `player.x` `player.y` 这样的子标签,并且智能提示能更好的协助你。
* 按 vscode 的查找定义快捷键(默认F12)可直接找到标签定义位置。
* 编译器定义的 `xx = yy` 是作为变量,编译器将不会检查重复定义的变量。如要定义常量,请使用 `.DEF` 命令。
---
### 局部标签
* 若文件内使用标签(非编译器指令)以.(点)开头,则该标签的有效范围仅仅于本文件。
* 这样有利于可以在不同文件使用相同名称的标签。
---
### 简易标签
* 当标签以全部是+号或全部是-号的时候,则是简易标签。例如:
```
-- LDA $2002
BPL --
LDA $0
BEQ +
BPL ++
JMP $9000
+ JMP $8000
++ JMP $A000
; AD 02 20 10 FB A5 00 F0 05 10 06 4C 00 90 4C 00 80 4C 00 A0
```
---
### 运算符
> 注意:由于内核使用的是JS,所有运算符是以JS的运算符计算方法进行计算。例如: ~$A -> -11
```
+ - * / & | ~ ^
>> << && || !
== != >= <=
```
---
### 特殊运算符
1. `>` 与 `<` 都有特殊的意义,例如 `>$1234` 即取高位 ($12), `<$1234` 取低位 ($34)
2. `*` 有当不作为乘号时有特殊的意义,表示当前行的 `ORG` 地址
3. `$` 作为单独符号出现(即不为16进制标识符),表示当前行的 `BASE` 地址
### 字符串
有时候数据以字符串形式出现,例如 `.DB "HELLO WORLD"`
但是由于一些特殊限制,比如此字符串中的空格是十六进制 `00`,可以通过简单的变换,结果如下:
`.DB "HELLO\x00WORLD`
Unicode形式
`.DB "HELLO\u{00}WORLD"`
---
### 注释与折叠
* 当包含 `;` 字符,该行 `;` 之后所有内容都是注释
* 注释为 `;+` `;-` 则为折叠,方便折叠部分代码
---
## 编译器命令
> 以下命令内中括号为可选参数
---
.BASE
### `.BASE`
```
.BASE 文件起始位置
```
* 设置生成文件地址,**默认为 `.BASE 0` **,这里不等同与 `.ORG`。
* 例如:若 `.BASE $10` ,则生成的文件编译内容从 `$10` 开始写入,之前的 `$F` 个地址为 `0`。
> 注意
> 1. 编译自上而下,一些第一次编译需要赋值的变量如果第一次编译未知则编译不成功。
> 2. 如果使用`.BASE`命令,则在`.ORG`之后,否则编译错误。
---
.ORG
### `.ORG`
```
.ORG 编译起始位置
```
* 设置开始编译地址,例如:`.ORG $8000`,则编译将从$8000开始。
* 也可以使用`.ORG *`,表示从当前地址开始编译。不过要知道当前地址,否则编译器报错。
* 注意:如果使用 `.BASE` 命令,则在 `.ORG` 之后,否则编译错误。
---
.DEF
### `.DEF`
```
.DEF 标签, 表达式
```
* 定义一个常量,例如:`.DEF idefined, $12`。
> 注意:`temp = $12` 虽然也能定义,用等号可重复定义。
---
.ENUM .ENDE
### `.ENUM` `.ENDE`
```
.ENUM 起始地址
标签, 字节长度
...
.ENDE
```
* 定义一系列连续的地址,通常用于定义一系列内存地址
* 例如:
```
.ENUM $300
music.counter, 1 ; 类似 .DEF music.counter, $300
music.addrHigh, 2 ; 类似 .DEF music.addrHigh, $301 (music.counter + 1)
music.addrLow, 3 ; 类似 .DEF music.addrLow, $303 (music.addrHigh + 2)
.ENDE
```
---
.DB .DW .DL
### `.DB` `.DW` `.DL`
```
.DB 数据1 [, 数据2, 数据3...] ;1字节
.DW 数据1 [, 数据2, 数据3...] ;2字节
.DL 数据1 [, 数据2, 数据3...] ;4字节
```
* 一系列数据。
---
.DBG .DWG .DLG .ENDD
### `.DBG` `.DWG` `.DLG` `.ENDD`
* 数据组,用于定位数据位置。
```
.DWG 标签
.data1, .data2, .data3, .data1
.ENDD
LDA data:.data1 ;0
LDA data:.data3 ;2
LDA data:.data1:1 ;3
```
-----
.HEX
### `.HEX`
```
.HEX 16进制字符串
.HEX 12 34567 89 ;12 34 56 07 89
```
* 一段16进制数据,可以用空格隔开。
> 注意:之后只能输入16进制数据,否则编译器会报错。
---
.IF .ELSEIF .ELSE .ENDIF
### `.IF` `.ELSEIF` `.ELSE` `.ENDIF`
* 这里是一套判断条件,根据条件是否成立是否编译相应内容。
> 注意:必须要在使用这些之前知道参数的信息,否则编译报错
```
.IF a == 5
.....
.ELSEIF b >= 5
.....
.ELSEIF c != 3
.....
.ELSE
.....
.ENDIF
```
-----
.IFDEF .IFNDEF .ELSE .ENDIF
### `.IFDEF` `.IFNDEF` `.ELSE` `.ENDIF`
```
.IFDEF 标签或自定义函数
.....
.ELSE
.....
.ENDIF
```
* 这里是一套判断条件,根据条件是否成立是否编译相应内容。
* 用法同 `.IF` 的命令类似,后面可以用 `.ELSE` `.ENDIF`
* 这里是判断变量或自定义函数是否存在,`.IFDEF`为判断变量或自定义函数存在,`.IFNDEF`为判断变量或自定义函数不存在。
> 注:必须要在使用这些之前知道参数的信息,否则编译报错
---
.INCBIN
### `.INCBIN`
```
.INCBIN 文件相对路径[, 读取文件起始位置, 读取长度]
```
* 可以读取引用文件的二进制内容,后面双引号内请填写本文件的相对路径。
例如:
```
.INCBIN "文件夹\文件.bin", 0, 100
```
-----
.INCLUDE
### `.INCLUDE`
```
.INCLUDE 文件相对路径
```
* 可以引用文件,后面双引号内请填写本文件的相对路径。
* 如果引用文件内也有引用文件,请相对于主编译文件路径填写。
例如:
```
.INCLUDE "文件夹\文件.asm"。
```
-----
.MACRO .ENDM
### `.MACRO` `.ENDM`
```
.MACRO 自定义函数名称[, 参数1, 参数2...]
.....
.ENDM
```
> 注意:用这里的指令可以自定义函数,所要使用的函数要在编译之前定义好,否则编译器会报错。
> 注意:所有自定义函数内的 **标签** 属于 **局部变量**,请勿在函数外部使用。
> 注意:所有自定义函数内定义的 **变量** 均为 **全局变量**。
实例1:
```
.MACRO TXY
TXA
TAY
.ENDM
TXY
```
* 编译之后结果为:`8A A8`
实例2:
```
.MACRO test, a, b
.IF 3 == a
LDA 3
.ELSEIF 4 == a
LDX 4
.ELSEIF 5 == a && 5 == b
LDY 5
.ELSE
LDA 6
STA 6
.ENDIF
.ENDM
test 3,3
test 4,3
test 5,4
test 5,5
```
* 编译之后结果为:`A5 03 A6 04 A5 06 85 06 A4 05`
-----
.REPEAT .ENDR
### `.REPEAT` `.ENDR`
```
.REPEAT 重复次数
.....
.ENDR
```
* 可以重复某个指令多次,在 `.REPEAT` 后输入表达式即可。
> 注意:每个 `.REPEAT` 和 `.ENDR` 必须成对出现,可以嵌套。
```
.REPEAT 2
NOP
.REPEAT 3
ASL
.ENDR
.ENDR
```
* 对应编译的结果相当于:`NOP ASL ASL ASL NOP ASL ASL ASL`
-----
.MSG .ERROR
### `.MSG` `.ERROR`
```
.MSG 输出信息[, 参数1, 参数2...]
.ERROR 输出信息[, 参数1, 参数2...]
```
* MSG为可输出一条信息
* ERROR为输出一条信息并停止编译
```
.ORG $8000
.DEF test1, 10
.DEF test2, 11
.MSG "测试案例 {0}, ${1}, @{0}", test1, test2
.IF test1 == 10
.ERROR "这里的 test1: {0}", test1
.ENDIF
```
* 这里输出的信息是:
> 测试案例 10, $B, @0000 1010
>
> 这里的 test1: 10