自制简易编程语言 个人笔记(1)

(写博客是提醒自己挖了坑一定要填)

github地址https://github.com/lucyTheSlayer/orange

趁着空闲时间,准备学习自己搞一套编程语言出来,就命名为Orange。

Orange的最终目标是python的简化版,具有oop的支持(希望能坚持到这步)

于是翻出好几年前的老书《编译原理及实践》,照着书后源码就是一顿敲。书中的TINY语言格式是在是太丑了,所以必须对其源码进行相应的修改,主要是增加了几个关键词,把REPEAT语句改成了现代感更强的WHILE等。目前Orange的代码样例如下:

apple := 200;
banana := 100;#ohoh123
if(apple0){
	write i;
	i := i - 1;
}

这里面的赋值号为:=,这种老式的方式也让人看了很难受,留待以后(真的有以后吗?)再改吧。

目前的进度是能把上述代码转换为字节码,但由于解释器还没搞,所以到底这字节码对不对还不好说。以下是整个编译过程的简记:

1)lexer 词法分析

该模块负责从文件中读取源码,并将其以token的形式返回给上层parser使用,于是上述代码经过lexer后变成以下形式。

ID, name= apple
:=
NUM, val= 200
;
ID, name= banana
:=
NUM, val= 100
;
reserved word: if
(
ID, name= apple
<
ID, name= banana
)
{
ID, name= orange
:=
ID, name= apple
*
ID, name= banana
;
ID, name= banana
:=
NUM, val= 12
*
ID, name= apple
-
NUM, val= 32
;
}
ID, name= i
:=
NUM, val= 10
;
reserved word: while
(
ID, name= i
>
NUM, val= 0
)
{
reserved word: write
ID, name= i
;
ID, name= i
:=
ID, name= i
-
NUM, val= 1
;
}

当然,词法分析器不是一下子便将所有内容全部token化,而是需要parser主动调用获取token。

2)parser 语法分析

语法分析是最重要的一环,此处采用的是自顶向下的方法,它将源代码转换为一棵语法树。

  Assign to : apple
    Const: 200
  Assign to : banana
    Const: 100
  If
    Op: <
      Id: apple
      Id: banana
    Assign to : orange
      Op: *
        Id: apple
        Id: banana
    Assign to : banana
      Op: -
        Op: *
          Const: 12
          Id: apple
        Const: 32
  Assign to : i
    Const: 10
  While
    Op: >
      Id: i
      Const: 0
    Write
      Id: i
    Assign to : i
      Op: -
        Id: i
        Const: 1

3)语义分析

有了语法树,就可以为所欲为了,在这一步建立了符号表,以及在此做类型检查,譬如c语言里的int a = "abc"这种具有明显的类型错误,那再这一步就必须检查出来了。

Building Symbol Table...

Symbol table:

Variable Name  Location  Line Numbers

banana         1            2    3    4    5
orange         2            4
i              3            7    8    9   10   10
apple          0            1    3    4    5

 Checking Types...

 Type Checking Finished

4)代码生成

这是最激动人心的时刻,也是编译器部分最终成果的展示部分。最终我的Orange源代码转变为了以下字节码

* TINY Compilation to TM Code
* File: hello.orangebc
* Standard prelude:
  0:     LD  6,0(0) 	load maxaddress from location 0
  1:     ST  0,0(0) 	clear location 0
* End of standard prelude.
* -> assign
* -> Const
  2:    LDC  0,200(0) 	load const
* <- Const
  3:     ST  0,0(5) 	assign: store value
* <- assign
* -> assign
* -> Const
  4:    LDC  0,100(0) 	load const
* <- Const
  5:     ST  0,1(5) 	assign: store value
* <- assign
* -> if
* -> Op
* -> Id
  6:     LD  0,0(5) 	load id value
* <- Id
  7:     ST  0,0(6) 	op: push left
* -> Id
  8:     LD  0,1(5) 	load id value
* <- Id
  9:     LD  1,0(6) 	op: load left
 10:    SUB  0,1,0 	op <
 11:    JLT  0,2(7) 	br if true
 12:    LDC  0,0(0) 	false case
 13:    LDA  7,1(7) 	unconditional jmp
 14:    LDC  0,1(0) 	true case
* <- Op
* if: jump to else belongs here
* -> assign
* -> Op
* -> Id
 16:     LD  0,0(5) 	load id value
* <- Id
 17:     ST  0,0(6) 	op: push left
* -> Id
 18:     LD  0,1(5) 	load id value
* <- Id
 19:     LD  1,0(6) 	op: load left
 20:    MUL  0,1,0 	op *
* <- Op
 21:     ST  0,2(5) 	assign: store value
* <- assign
* -> assign
* -> Op
* -> Op
* -> Const
 22:    LDC  0,12(0) 	load const
* <- Const
 23:     ST  0,0(6) 	op: push left
* -> Id
 24:     LD  0,0(5) 	load id value
* <- Id
 25:     LD  1,0(6) 	op: load left
 26:    MUL  0,1,0 	op *
* <- Op
 27:     ST  0,0(6) 	op: push left
* -> Const
 28:    LDC  0,32(0) 	load const
* <- Const
 29:     LD  1,0(6) 	op: load left
 30:    SUB  0,1,0 	op -
* <- Op
 31:     ST  0,1(5) 	assign: store value
* <- assign
* if: jump to end belongs here
 15:    JEQ  0,17(7) 	if: jmp to else
 32:    LDA  7,0(7) 	jmp to end
* <- if
* -> assign
* -> Const
 33:    LDC  0,10(0) 	load const
* <- Const
 34:     ST  0,3(5) 	assign: store value
* <- assign
* -> while
* -> Op
* -> Id
 35:     LD  0,3(5) 	load id value
* <- Id
 36:     ST  0,0(6) 	op: push left
* -> Const
 37:    LDC  0,0(0) 	load const
* <- Const
 38:     LD  1,0(6) 	op: load left
 39:    SUB  0,1,0 	op >
 40:    JLT  0,2(7) 	br if false
 41:    LDC  0,1(0) 	true case
 42:    LDA  7,1(7) 	unconditional jmp
 43:    LDC  0,0(0) 	false case
* <- Op
* while: jump to end belongs here
* -> Id
 45:     LD  0,3(5) 	load id value
* <- Id
 46:    OUT  0,0,0 	write ac
* -> assign
* -> Op
* -> Id
 47:     LD  0,3(5) 	load id value
* <- Id
 48:     ST  0,0(6) 	op: push left
* -> Const
 49:    LDC  0,1(0) 	load const
* <- Const
 50:     LD  1,0(6) 	op: load left
 51:    SUB  0,1,0 	op -
* <- Op
 52:     ST  0,3(5) 	assign: store value
* <- assign
 53:    LDA  7,-19(7) 	jmp back to loop
 44:    JEQ  0,8(7) 	while: jmp to end
* <- while
* End of execution.
 54:   HALT  0,0,0 	

okay,看起来很cool,虽然书中作者采用的这种汇编语言格式看上去还是很不爽(个人推崇python的字节码样式),但现在是学习阶段,先学,后面再改成我自己喜欢的格式(真的有后面吗?)。

这里面while语句的字节码是我自己生成的,不知道对不对,一切都得等vm机码完才知道(真的码的完吗?)了。


此文只是我个人娱乐所用,当然如果你不幸浏览到这,发现什么也没get到,很气,那么在这,我推荐《编译原理及实践》这本书,跟着书中源码走一遍,很多都豁然开朗了。一切的技术,plz read the fucking source code!


你可能感兴趣的:(编译原理,杂项)