个人头像

针对可视化实验平台实现小型编译器

发表于2017-11-07 | 分类于

一、原创性声明

参考内容:

二、源语言描述

词法规则:正则表达式
注释: (\/\/{any}[\n]) {;}
常量: [0-9]+|[0-9]
.[0-9]+
变量名:[a-zA-Z][a-zA-Z0-9]
运算符: [()\<>=+-\
\/;{}.,%] (>=) (<=) (==) (!=) (&&) (||) (sin) (cos)
关键字:(begin) (end) (while) (for) (if) (else)
paint平台指令:(delay) (reset) (getwindowsize) (setwindowsize) (setcolor) (setpointsize)
(setlinewidth) (moveto) (lineto) (point) (line) (rotate) (scale) (translate) {
制表符及换行:[\t\n’ ‘]
其他字符非法:.

语法规则:文法
program  _BEGIN function END
function  function stmt
| /Empty/
stmt  ‘;’
| expr ‘;’
| VARIABLE ‘=’ expr ‘;’
| WHILE ‘(‘ expr ‘)’ stmt
| FOR ‘(‘ expr ‘;’ expr ‘;’ expr ‘)’ stmt
| IF ‘(‘ expr ‘)’ stmt %prec IF
| IF ‘(‘ expr ‘)’ stmt ELSE stmt %prec ELSE
| MOVE
| ‘{‘ stmt_list ‘}’
stmt_list  stmt_list stmt
| stmt
MOVE  DELAY ‘(‘ expr ‘)’ ‘;’
| RESET ‘;’
| GETWINDOWSIZE ‘;’
| SETWINDOWSIZE ‘(‘ expr ‘)’ ‘;’
| SETCOLOR ‘(‘ expr ‘,’ expr ‘,’ expr ‘)’ ‘;’
| SETPOINTSIZE ‘(‘ expr ‘)’ ‘;’
| SETLINEWIDTH ‘(‘ expr ‘)’ ‘;’
| MOVETO ‘(‘ expr ‘,’ expr ‘)’ ‘;’
| LINETO ‘(‘ expr ‘,’ expr ‘)’ ‘;’
| POINT ‘(‘ expr ‘,’ expr ‘)’ ‘;’
| LINE ‘(‘ expr ‘,’ expr ‘,’ expr ‘,’ expr ‘)’ ‘;’
| ROTATE ‘(‘ expr ‘)’ ‘;’
| SCALE ‘(‘ expr ‘,’ expr ‘)’ ‘;’
| TRANSLATE ‘(‘ expr ‘,’ expr ‘)’ ‘;’
expr  NUMBER
| VARIABLE
| ‘-‘expr %prec UMINUS
| expr ‘+’ expr
| expr ‘-‘ expr
| expr ‘*’ expr
| expr ‘/‘ expr
| expr ‘<’ expr
| expr ‘>’ expr
| SIN ‘(‘ expr ‘)’
| COS ‘(‘ expr ‘)’
| expr ‘%’ expr
| expr GE expr
| expr LE expr
| expr NE expr
| expr EQ expr
| expr AND expr
| expr OR expr
| ‘(‘expr ‘)’

三、实现方案

1.搭建平台测试环境,将 *.dll 复制到 C:\Windows\System32
2.编译运行 robot 平台提供的编译程序示例,了解一个小型编译器的实现过程。
3.运行paint平台指令,了解指令格式及功能
4.编写paint.lex词法分析文件,包含对五类单词的定义:关键字、标识符、常量、界符、算符
5.编写 paint.yacc语法分析文件,通过BNF定义语法规则
6.编写node.h,定义语法树节点的数据类型
7.编写util.c 对识别的终结符建立节点,自上而下构造语法树 ,然后自下而上进行规约
8.编写高级语言源文件测试程序,生成目标文件后在paint平台上执行

四、创新和亮点

  1. 可将高级语言程序翻译为paint平台所能接受的指令序列,并存入文件,在paint平台上加载运行,支持while循环结构,if-else分支结构,并且支持多层嵌套
  2. 程序定义了一个语法树的节点,节点可以是数字,操作符,变量索引类型,节点如果是操作符,可以继续递归节点
  3. 每个stmt对应一个树形图,对于每个操作符,保证一个可递归的规则
  4. 定义了拓展实现函数,生成不同类型的树节点,对语法树进行解释执行,释放节点等操作
  5. 将数据类型定义为浮点型,提高运算精度
  6. 添加sin,cos,相反数等运算
  7. 测试程序包括paint平台所有指令,使用循环根据函数的极坐标绘制了心形线,二次函数曲线等

五、运行结果

测试用例:
source_code.txt

begin
    r=25;
    setcolor(1,0.5,0);  //设置颜色
    //字母C
    angle=250;
    while(angle!=360)
    {
        x=r*cos(180-angle)-45;
        y=r*sin(180-angle);
        point(x,y);  //画点
        angle=angle+1;
    }
    angle=1;
    while(angle!=110)
    {
        x=r*cos(180-angle)-45;
        y=r*sin(180-angle);
        point(x,y);  //画点
        angle=angle+1;
    }
    //字母P
    angle=85;
    setcolor(0.5,0.5,1);  //设置颜色
    while(angle!=275)
    {
        x=r*cos(180-angle)+45;
        y=r*sin(180-angle);
        point(x,y);  //画点
        angle=angle+1;
    }
    setlinewidth(4);
    line(42,25,42,-60);
    delay(2);
    reset;
    //心形线
    a=50;
    angle=0;
    setcolor(1,0,0);  //设置颜色
    while(angle!=360&&a>20)
    {
        r=a*(1-sin(angle));
        x=r*cos(angle);
        y=r*sin(angle);
        point(x,y);  //画点
        angle=angle+1;
    }
    if(angle>=360)
    {
        setwindowsize(200); 
        delay(0.5);
        rotate(360);   //旋转
        rotate(-360);
        delay(0.5);
        translate(0,80);   //向上平移
        delay(0.5);
        translate(0,-40); 
        setcolor(0,1,0);
        x=78;
            //抛物线
        while(x<=182)
        {
            y=0.04*(x-130)*(x-130)-100;
            point(x,y);  //画点
            x=x+0.7;
        }
        setcolor(0,0,1);
        setlinewidth(4);
        line(-120,10,-140,10);
        line(-130,10,-130,-100);
        line(-113,-100,-147,-100);
    }
    //循环放大与缩小
    i=0;
    while(i<8)
    {
        if(i%2==1)
        {
            scale(2,2);
            delay(0.5);
        }
        else
        {
            scale(0.5,0.5);
            delay(0.5);
        }
        i=i+1;
    }
    end

测试结果:

生成目标文件 paint.txt,执行该文件的命令,得到以下图案:


Compilers Principles,I love u

六、源代码

https://github.com/nicahead/compiler.git