/jack-compiler

jack语言编译器

Primary LanguageC++

jack-Compiler

效果

Demo1:
class Main 
{
    function void main() 
    {
        String s;
        
        Output.printString("Hello, world!");
        Output.println();
        
        Output.printString("What's your name?");
        Output.println();
        s = Input.readLine();
        Output.printString("Your name is: ");
        Output.printString(s);
        Output.println();
        
        return;
    }

}
运行结果:

图片4

Demo2
class Main 
{
    function void main() 
    {
		Array arr;
		String s;
		int i;
		
		arr = Array.new(5);		// 创建一个大小为5的数组
		i = 0;
		while (i < 5)
		{
			s = Input.readLine();
			arr[i] = s.intValue();
			i = i + 1;
		}
		
		Main.bubble_sort(arr, 5);
		
		i = 0;
		while (i < 5)
		{
			Output.printInt(arr[i]);
			i = i + 1;
		}
		Output.println();
		
		return;
	}
	
	/* 冒泡排序 */
	function void bubble_sort(Array arr, int n)
	{
		int i, j, tmp;
		i = n - 1;
		
		while (i > 0 | i == 0)		// 由于还没有加上 >= 运算符, 所以暂时用这个代替
		{
			j = 0;
			while (j < i)
			{
				if (arr[j] > arr[j + 1])
				{
					tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}
				j = j + 1;
			}
			i = i - 1;
		}
	
		return;
	}
}
运行结果:

图片6

Demo3:
class Main
{
	function void main()
	{
		int a, b, c;
		String s;
		
		s = Input.readLine();
		a = s.intValue();
		
		s = Input.readLine();
		b = s.intValue();
		
		c = Main.gcd(a, b);   
		
		Output.printInt(c);
		Output.println();
		
		return;
	}
	
	// 求最大公约数
	function int gcd(int a, int b)
	{
		if (b == 0)
		{
			return a;
		}
		else
		{
			return Main.gcd(b, a - a / b * b);
			/* a - a / b * b相当于 a % b */
		}
	}
	
}
运行结果:

图片5

[TOC]

背景介绍

去年学了编译原理,但是这门课的理论太多了,而且很难,学得是云里雾里.网上很多大神说学了编译原理之后最好能够实际动手做一个编译器出来,这样对能力有很大的提升.于是就下了定决心,带着写一个编译器的目的来重新学习编译原理.然后开始找公开课,买书,就这样开始了.

jack--语言介绍

语法要素

1, 保留字:

class, constructor, method, function, int, boolean, char, void, 
static, field, if, else, while, return, true, false, null, this  

2, 标识符:

由字母或下划线开头, 后接任意任意个字母或数字或下划线

3, 常量:

int类型的常数规定都是正整数, 没有负整数, 但是可以在正整数前面加上负号, 这是对正整数取负值的一元运算表达式  
String类型的常量是把一个字符串用一对双引号括起来, 与java和C里面的字符串一样  
boolean类型的常量可以是true和false  
常数null表示一个空引用, 实际上就是数值0  

4, 合法的符号:

(   )   [   ]   ,   .   ;   =    +   -   *   /   &   |   ~   <   >   <=   >=   ==   

5, 注释:

与C语言和java一样, 支持两种注释形式, 单行注释//   和多行注释 /*  */  

程序结构

1, jack的基本编程单元是类, 每个类存在于独立的文件中, 可以单独编译, 下面是类的定义形式:

class 类名
{
	成员变量(field)声明 和 静态变量(static)声明	// 比如放在子程序声明之前
	子程序声明	// 子程序声明可以是构造函数声明(construtor), 静态函数声明(function)和方法声明(method)
}

2, 子程序声明:

subroutine 类型 名称 (参数列表)
{
	局部变量声明
	语句
}

3, jack必须至少包含一个Main类, 而且在Main类中必须包含一个function void main() 函数

变量

1, 变量分类

jack中有四种变量类型: 成员变量, 静态变量, 局部变量和参数变量  
成员变量通过field关键字来声明  
静态变量通过static来声明
在函数体的开始声明的变量是局部变量  
在函数声明中声明的变量是参数变量  

2, 数据类型

基本数据类型和对象类型

3, 基本类型

int, boolean, char

4, 对象类型

同java一样, 声明一个对象实际上只是创建一个指向该对象的引用

5, 数组

数组是通过内置类Array类声明的, 用Array声明的对象也是一个引用, 指向堆内存. 
对数组的引用可以与传统的一样
    Array arr;
    arr[3] = 4;
不支持多维数组. 

6, 字符串

字符串是通过内置类String类来声明的, 同样, 用String声明的对象也是一个引用, 指向堆内存, 例如:
    String s;
    char c;
    s = String.new("hello, world!\n");
    c = s.charAt(4);

7, 类型转换

jack是弱类型语言, 没有禁止不同类型之间的转换

语句

1, 赋值语句

变量 = 表达式
变量[表达式] = 表达式    

2, if语句

if(表达式)                     // 不能省略大括号
{
	语句             
}
else
{
    语句
}

3, while语句

while(表达式)
{
    语句
}

4, 函数调用语句

方法名(表达式)
类名.函数名(表达式)

5, return语句

return 表达式
return ;                     // 即使子程序返回void, 也要有return语句

表达式

jack--表达式必须是下列之一:

  • 常数
  • 在作用域内的变量名(变量可以是静态、局部、成员或参数类型)
  • 关键字this, 引用当前对象 (不能用于函数中)
  • 数组语法是: 数组名称[表达式], 其中数组名称是Array类型的变量名
  • 返回值为非空类型的子程序调用
  • 一元运算符 "-" 或 "~" 作前缀的表达式 ** - 表达式: 算术求反 ** ~ 表达式: 布尔求反
  • 形如 "表达式 运算符 表达式" 的表达式, 其中运算符可以是以下二元运算符中的一种; *** + - * / & | <= < >= > ==
  • (表达式): 位于圆括号内的表达式

标准库

标准库包括下面的类

Math        提供基本的数学运算
String      实现字符串String类型和字符串相关操作
Array       实现数组Array类型和数组相关操作
Output      处理屏幕上的文字输出
Input       处理键盘的输入
Memory      处理内存操作
Sys         提供与程序执行相关的服务

Math类

该类实现各种数学运算操作

String类

该类实现String数据类型以及与字符串相关的操作

Array类

该类构造和清除数组

Output类

该类提供在屏幕上打印文本的服务

Input类

该类提供从标准键盘上读取输入的服务

Memory类

该类允许直接访问宿主平台的主内存的服务

Sys类

该类提供与程序指向相关的服务

Demo

##项目介绍

使用说明

在linux下运行compiler.sh或者make就可以编译出jackc.exe和jack.exe了

模块介绍

jack编译器主要有词法分析器,语法分析器,语义分析器,vm代码生成 和 虚拟机

词法分析器

词法分析器的源代码为Scanner.cpp 使用的手工编码的方法实现的
    词法分析器的主要任务是识别源程序中的单词(Token),假如有下面的C代码:

int main()
{
    printf("Hello, world!\n");
    return 0;
}

    通过词法分析器的扫描之后,返回的是一个一个单词(Token):

关键字 int  
标识符 main  
左圆括号 '('  
左花括号 '{'  
标识符 printf
左圆括号 '('  
字符串 "Hello, world!\n"  
右圆括号 ')'  
分号 ';'  
标识符 return  
数字 0  
右花括号 '}'

词法规则

首先定义一些词法规则,即这门语言对能够识别出来的单词,词法规则是用正则表达式来定义的

转移图

根据上面的词法规则可以画出状态转移图(FA),以方便编程

1, 简单的转移图示例:

2, 标识符,整型和浮点型的转移图:

图片1

3, 字符串的转移图:

图片2

4, 字符的转移图 图片3

语法分析器

语法分析器的源代码文件是Parser.cpp 使用的是递归下降的方法实现的
语法分析器有两个任务:
1, 判断源程序是否符合语法规则 2, 生成抽象语法树

jack语言的语法

jack语言的语法由如下的上下文无关文法(BNF)定义.
非粗体字表示非终结符, 粗体字表示终结符

    program -> classlist
    classlist -> classlist class
               | class
    class -> class ID { classVarDecList subroutineDecList }
    classVarDecList -> classVarDecList classVarDec
             	     |
    classVarDec -> static type varNameList ;
                 | field type varNameList ;
    varNameList -> varNameList , ID
                 | ID
    type -> int
          | float
          | char
          | boolean
          | void
          | ID
    subroutineDecList -> subroutineDecList subroutineDec
                       | 
    subroutineDec -> constructor type ID ( params ) subroutineBody
                   | function type ID ( params ) subroutineBody
                   | method type ID (params ) subroutineBody
    params -> paramList
            | 
    paramList -> paramList , param
               | param
    param -> type ID
    subroutineBody -> { varDecList statements }
    varDecList -> varDecList varDec
                | 
    varDec -> type varNameList ;
    statements -> statements statement
                | 
    statement -> assign_statement
               | if_statement
               | while_statement
               | return_statement
               | call_statement ;
    assign_statement -> leftValue = expression ; 
    leftValue -> ID
               | ID [ expression ]
    if_statement -> if ( expression ) statement
                  | if ( expression ) statement else statement
    while_statement -> while ( expression ) { statement }
    return_statement -> return ; 
                      | return expression ;
    call_statement -> ID ( expressions ) 
                    | ID . ID ( expressions )
    expressions -> expression_list
                 | 
    expression_list -> expression_list , expression
                     | expression
    expression -> expression & boolExpression
                | expression | boolExpression
                | boolExpression
    boolExpression -> additive_expression relational_operator additive_expression
                    | additive_expression
    relational_operator -> <= 
                         | >=
                         | ==
                         | <
                         | >
                         | !=
    additive_expression -> additive_expression + term
                         | additive_expression  term
                         | term    
    term -> term * factor
          | term / factor
          | factor
    factor -> - positive_factor
            | positive_factor
    positive_factor -> ~ not_factor
                     | not_factor
    not_factor -> INT_CONST
                | CHAR_CONST
                | STRING_CONST
                | keywordConstant
                | ID
                | ID [ expression ]
                | call_expression
                | ( expression )
    keywordConstant -> true
                     | false
                     | null
                     | this
    call_expression -> ID ( expression )
                     | ID . ID ( expression )

语法树

树的节点类型:

语义分析器

语义规则

符号表

虚拟机