Skip to content

Catium2006/CASM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CASM

CASM的全称是Catium Self Made language.
并且部分指令类似汇编语言, 因此有ASM成分(大雾).

解释器的使用:

参考build.bat编译, 编译出来的可执行程序casm.exe(windows下).

CASM目前没有使用任何平台相关代码, 因此她是跨平台的.

运行可执行文件时, 您可以在标准输入流中输入您的CASM代码, 或者您也可以在命令提示符中用管道符将文件重定向至标准输入流.
标准输入流结束后, CASM将尝试解释您的代码.
如果解释过程中发现语法错误, 将会报错.

Hello, World! 例程

CASM代码文件后缀应为.casm

语法

一般的操作语法为 操作符 [操作字节数] 操作数 [操作数 ...]

注释

注释要求单独成行或位于行尾, 主要是不能出现在其他语句的操作数位置, 以#开始

CASM没有函数, 也不需要显式循环

我们并未采用函数, 而是引入了"代码块"的概念.
作为循环的替代品, 代码块默认是循环执行的.
如果代码块内没有显式跳出/返回指令(如ret,rez等), 则会循环执行代码块主体内容.

代码块

see at block.cpp
代码块由block关键字声明, 以endblock关键字结束, 不得相交或嵌套.
举个例子:

block loop
    sub     4       cnt     1
    rez     cnt
endblock

block main
    var     4       cnt     0xff
    call    loop
    ret
endblock

上述代码会在main块中声明一个4字节变量cnt, 然后调用loop块, 每次循环令cnt减一, 直到cnt为零时返回main块, 最后退出main块.
整个程序由名为main的代码块开始执行, 如果不存在则不会有代码被执行
在任何情况下, 如果有某个代码块的名字被声明了多于1次, 则后面的同名代码块会覆盖前面的同名代码块.
CASM允许块的内容在运行时改变, 因此她是动态语言.

内存管理

CASM采用堆栈模式管理内存:

总的可用于解释代码的内存在编译解释器时定义(默认为128MB). 参考build.bat

堆: 内存分配与回收

栈: push

  • 接受1个操作数
  • 不需要指定数据长度
    push aa入栈, 即在栈顶按字节复制a
  • a必须为变量
    注意, 不需要显式的指定数据长度, 是因为数据长度根据变量名判断.

栈: pop

  • 接受1个操作数
  • 不需要指定数据长度
    pop a 出栈到a, 即从栈顶按字节复制数据到a
  • a必须为变量
  • 栈大小小于变量大小时忽略本次操作(a中值不变)
    注意, 不需要显式的指定数据长度, 是因为数据长度根据变量名判断.

数据类型

立即数

  • 格式为10进制整数或16进制整数
  • 十进制整数可以为负数
  • 16进制整数格式类似0x0123456789abcdef, 且不允许负数
  • 超出目标操作数容量的, 高位将被舍去(在小端字节序下).

变量

see at var.cpp

CASM不强制区分变量内容的类型, 因此她是一种弱类型语言.

  • 变量的生存周期是从它被声明到他被销毁.
  • 在生存周期内, 变量的作用域是全局.
  • 只能使用a~z,A~Z,0~9,_作为标识符(经测试 unicode字符或许也能用)
  • 区分大小写
  • 不允许0~9作为标识符首字母

变量的声明: var关键字

  • 接受2个操作数
  • 需要指定数据长度

var a b c 创建一个a字节的变量, 变量名为b, 初始值为c

  • a的大小不限制, 当堆空间不足以创建时, 产生错误.
  • b的要求见变量名格式
  • c只能为立即数,或其他变量.
  • c为变量时, 初始化操作将按字节复制c的内容到b, 多退少补
  • c为立即数时, 如果a小于等于4则按值复制, 否则按字节填充c的最低字节.
  • 特别地, 0字节变量允许被声明, 但可能无法被正常使用
  • 长度为负的变量可能会导致未定义行为

小于等于4字节的变量在其他运算中会被优先视为整数.
3字节整数变量不区分正负.
注意, 在循环块中创建变量而不删除变量是不明智的, 因为循环执行至第二次的时候就会产生重名变量的错误.

变量的销毁: del关键字

  • 接受1个操作数
  • 不需要指定数据长度
    del a 销毁一个名为a的变量.
    销毁后内存会被释放进中(详见vmem_heap.cpp).
    目前回收机制比较简陋, 对长度是二的幂的内存进行整块回收, 否则拆分后回收.

内存地址

格式为[addr]
其中addr可以是变量名,立即数,但不可以是另一个内存地址
表示内存中addr位置的内容, 元素字节数另外指定.
如果addr是一个长度大于4的变量, 将产生错误.

CASM是不进行内存保护的, 您可以用[]操作符访问任意地址的数据(限制在解释器提供的虚拟内存范围里).

指令

指令分为块内指令和块外指令.

块内指令

call

用于跳转到某个代码块, 在目标代码块显式返回时回到call所在代码块继续执行后续代码.

ret

用于无条件跳出代码块.

rez

  • 接受一个操作数
  • 操作数必须为变量
    用于有条件跳出代码块, 操作数值为0时跳出代码块, 否则继续执行块内其后的语句.

举个例子:

block loop
    sub     4       cnt     1       # 1
    rez     cnt                     # 2
endblock

block main
    var     4       cnt     0xff
    call    loop
    ret                             # 3
endblock

上述代码会循环执行loop块的内容(#1 & #2), 直到cnt值为0时跳出, 继续执行#3.

exit

用于无条件结束整个程序(强制令解释器退出).

mov

mov a b cc复制a字节的数据到b位置

  • 接受2个操作数
  • 需要指定数据长度
  • a必须是一个正立即数.
  • b,c可以是内存地址, 可以是变量名
  • c可以为立即数
  • b不得为立即数

整数运算

注: 3字节运算视为4字节运算并自然溢出为3字节

add

add a b c 进行一次a字节加法, 把c加在b

  • 接受2个操作数
  • 需要指定数据长度(不超过4)
  • b必须为变量
  • c可以是立即数,变量

sub

sub a b c 进行一次a字节减法, 把b减去c

  • 接受2个操作数
  • 需要指定数据长度(不超过4)
  • b必须为变量
  • c可以是立即数,变量

mul

mul a b c 进行一次a字节乘法, 把c乘在b

  • 接受2个操作数
  • 需要指定数据长度(不超过4)
  • b必须为变量
  • c可以是立即数,变量

div

div a b c 进行一次a字节除法, 把c除在b上.

  • 接受2个操作数
  • 需要指定数据长度(不超过4)
  • b必须为变量
  • c可以是立即数,变量
  • 下取整.

内存指令

addr

取地址运算.
addr a b 获取b的内存地址并写到a

  • 接受2个操作数
  • 不需要指定数据长度
  • 要求a,b均为变量
  • a最好为4字节变量, 少于字节的将会截取低位, 多于4字节的只填充低4字节.

size

取长度运算.
size a b 获取b的内存大小并写到a

  • 接受2个操作数
  • 不需要指定数据长度
  • 要求a,b均为变量.
  • a最好为4字节变量, 少于字节的将会截取低位, 多于4字节的只填充低4字节.

IO指令

pchar

pchar aa当做一个ASCII字符输出到标准输出流(stdout)

  • 接受1个操作数
  • 不需要指定数据长度
  • a可以为变量, 内存地址, 立即数
  • 如果a是变量, 则取其最低字节
  • 如果a是内存地址, 则取该位置1字节
  • 如果a是立即数, 则取其最低字节

pint

pint aa当做一个有符号整数输出到标准输出流(stdout)

  • 接受1个操作数
  • 不需要指定数据长度
  • a可以为变量, 立即数
  • 如果a是变量, 则最多取其低4字节
  • 如果a是立即数, 则直接输出
  • 特别地, 如果a是3字节变量则被视为一个仅有低3位的4字节有符号整数.

块外指令

include

用于包含另外一个文件.
include a.casma.casm文件的内容加入当前程序, 要求a.casm必须是一个可以读取的合法casm文件, 其内容格式依照本文其他要求.
比如说,1.casm中有一个block, 想要在2.casm执行时被调用, 就可以在2.casm中加入一句include 1.casm.
include连接的若干代码文件共享变量,内存,堆栈.

一般情况下, 由于CASM对块的处理是顺序无关的, include可以位于任何块外部的位置, 文件头部, 尾部, 中间均不影响被包含代码的执行.
特别地, 如果重定义了同名代码块, 那么include的位置会影响到代码块的内容, 参见block.

include会吧目标文件当做一个新的流交给流解释器处理.

block

用于标记某个代码块开始.

endblock

用于标记某个代码块结束.

宏定义

宏定义是对CASM代码内容的文本替换, 流解释器不会进行语法检查.
宏定义的生存周期是从被定义到被取消定义(如果取消的话, 否则就是到程序结束).
宏定义不可以嵌套, 虽然我完全有能力写一个解释嵌套宏定义的, 而且我以前也在考场上写过, 但是我不想再写了x
宏定义不可以递归,理由同上.

不会被宏定义替换的:

  • 其他块外指令
  • 其他宏定义

define

define a b 定义ab, 在该宏定义的生存周期内, 代码中所有的a字符串将被替换为b.

  • b 只能为一个不断字的目标.
  • 如果出现重名的宏定义, 则按后出现的会替换先出现的.

undef

undef a 取消a的已有宏定义.

About

自创解释型语言

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published