SIMP-C语言
现在是大一第二学期,跟着学校的进度,这学期用Scheme写了一个新的编程语言,叫SIMP,取义Simple Imperative Programming Language。觉得过程非常爽,同时也了解了机器底层的数据架构。
现在这个学期快结束了,我想把这个SIMP语言改进一下,使之更贴近C语言,改名Simple C Language(SIMP-C),目的是在为其写编译器(Compiler)的过程中,能够对C语言、汇编及机器底层架构有更深入的理解。
SIMP-C语法(目前)
先说我想写的这个新语言的语法,如下:
英文版
program = (main [(id init) ...] stmt)
id = l_id ; id is bound to a memory address, ie. id is a pointer
| r_id ; id is bound to a r_val
value = l_val ; a memory address
| r_val ; an expression value
r_val = number
| boolean
| char
| exp
l_val = addr
init = value
| id
| (array exp ...) ; as in int id[] = {1,2,3};
| (make-array nature exp) ; as in int id[nat];
stmt = (print exp) ; print("%d", id);
| (= exp exp) ; value assignment
| (seq stmt ...) ; as a pair of sqare brackets
| (iif exp stmt) ; if (condition) {when ture};
| (iif exp stmt else stmt) ; if (condition) {when true}; else {when false};
| (while exp stmt) ; while (condition) {program};
| (array-ref l_id exp) ; as the a[3] in printf("%c",a[3]);
| (array-set l_id exp exp) ; a[1+2] = 0;
exp = (> exp exp)
| (>= exp exp)
| (< exp exp)
| (<= exp exp)
| (== exp exp)
| (!= exp exp)
| (&& exp exp)
| (|| exp exp)
| (+ exp exp)
| (- exp exp)
| (* exp exp)
| (/ exp exp) ; quotient
| (% exp exp) ; remainder
| value
| id
中文版
声明 = (main [(id init) ...] stmt) ; 程序格式为,比如 (main [(a 1) (b 2)] (print (+ a b))), 将会输出"3"。[(a 1) (b 2)]是赋值。相当于 int main() {int a = 1; int b = 2; printf("%d",a+b);}
变量名 = l_id ; 变量名可以被赋予一个内存地址,换句话说变量名可以是指针。
| r_id ; 变量名可以是普通变量,比如char, int。
值 = l_val ; 一个"值", 可以是内存地址(叫做"l_val")。
| r_val ; 也可以是普通意义的数值(叫做"r_val"),比如char, int。
r_val = number
| boolean
| char
| exp ; exp == expression, “表达式”的缩写。“值”可以是表达式的返回值。
l_val = addr ; addr == address, 内存地址。
初始值 = 值
| 变量名
| (array exp ...) ; 创建一个新数组,对应C语言中的,比如 int id[] = {1,2,3};
| (make-array nature exp) ; 创建新数组,对应C语言中的,比如 int id[长度];
结构句 = (print exp) ; 打印一个id,对应print("%d", id); 为了简化,print也可以直接打印指针
| (= exp exp) ; 赋值语句
| (seq stmt ...) ; seq的作用对应C语言里的方括号,"{","}",seq里面的语句依次执行
| (iif exp stmt) ; 对应 if (condition) {when ture};
| (iif exp stmt else stmt) ; 对应 if (condition) {when true}; else {when false};
| (while exp stmt) ; 对应 while (condition) {program};
| (array-ref l_id exp) ; 返回数组中的一个值,对应,比如 printf("%c",a[3]);
| (array-set l_id exp exp) ; 给数组的某项赋值,对应,比如 a[1+2] = 0;
表达式 = (> exp exp)
| (>= exp exp)
| (< exp exp)
| (<= exp exp)
| (== exp exp)
| (!= exp exp)
| (&& exp exp)
| (|| exp exp)
| (+ exp exp)
| (- exp exp)
| (* exp exp)
| (/ exp exp) ; 求商数
| (% exp exp) ; 求余数
| 值
| 变量名
注: " = " 表示等号左边数据类型可以是右边的其中一个,“ | ” 表示或,比如 初始值可以是 "值,或变量名,或新数组..."
待定添加语法(目前)
函数声明 = (func [(id init) ...] /* program */)
SIMP-C汇编语法
要写编译器,就必须得有汇编语法。虚拟机和汇编器我们这个学期也都已经写好了。现在我想写的这个project主要写的是编译器,把SIMP-C翻译到对应的汇编语言去。将来我也会重写这个汇编语言,到时再改。
我直接用这学期自己写过的编译器,叫PRIMP(Primitive Imperative Language)。
; program = stmt-or-value ...
;汇编语法 =
;加减乘除 (add nat nat nat) ; 这里"nat"表示的全都是内存地址,为简化,用自然数代替(Nat == Nature Number)
; | (sub nat nat nat) ; 所有nat nat nat... 都表示,从后面n个地址里分别取出n个值,运算,然后把结果放到第1个nat表示的地址去。
; | (mul nat nat nat) ; 'add, 'sub, 'mul ...等等表示运算方式
; | (div nat nat nat)
; | (mod nat nat nat) ; 求余数
;逻辑判断
; | (gt nat nat nat) ; gt == greater than
; | (ge nat nat nat) ; ge == greater than or equal to
; | (lt nat nat nat) ; lt == less than
; | (le nat nat nat) ; le == less than or equal to
; | (equal nat nat nat)
; | (not-equal nat nat nat)
; | (land nat nat nat) ; land == &&
; | (lor nat nat nat) ; lor == ||
; | (lnot nat nat) ; lnot == !
;其它
; | (branch nat nat) ; 取第一个地址的值,如果值为true,跳转到第二个地址,否则不跳转
; | (move nat nat) ; 取第二个地址的值,复制到第一个地址里去
; | (move-imm nat number) ; 直接取第二个数,复制到第一个地址里去
; | (jump-imm nat) ; goto 内存地址
; | (print-imm value) ; 直接打印一个值
; | (print-mem nat) ; 打印内存地址里存的值
; A-PRIMP:
; stmt = (halt) ; 停机,程序终止
; | (const psymbol psymbol-or-value) ; 定义一个汇编语言里的id(psymbol),类型为常量,值为另一个id的值, 或数值,char,bool
; | (data psymbol psymbol-or-value ...) ; 在内存里顺次载入n个(不同的或相同)值,并将psymbol赋值为其中第一个值的内存地址
; | (data psymbol (number psymbol-or-value)) ; 同上,不过,是在内存里顺次载入number个相同值。
; | (lit psymbol-or-value) ; 没用,lit == literal,用来表示PRIMP里的一个值,和Scheme里的值区分开。
; | (label psymbol) ; 用来标记GOTO(jump-imm)的地址