• 基于C语言的LogoCompiler的设计和原理


    LogoCompiler的设计和原理

    一、前言

    本⽂档并不是项⽬⽂档的⼀部分,我的两位(或者⼀位)队友负责⽂档的撰写,这部分⼯作依然由他们 负责,但我觉得有⼀些内容值得⼀提,⽂档中却没有讲清楚,因此本⽂可以作为补充材料。

    虽然LogoComplier是⼀⻔讲述⾯向过程编程的课程的⼤作业,但是在本项⽬中,⾯向对象编程 (OOP)的技巧和思想⼀以贯之。事实证明,OOP的引⼊使LogoComplier变得更为强⼤、灵活、明 了。⽽且OOP在本项⽬中并不是对功能函数的简单包装,⽽是使⽤了继承、多态,例如Op类是所有操 作的基类,它派⽣出MoveOp、TurnOp、DefOp等,⼦类重写虚函数exec(),以表现不同的⾏为。

    LogoComplier应该被视为⼀种logo语⾔的编译器,因此它的使⽤⽅法与⼤多数编译器类似: ./logoCompiler testcase1.logo

    正常情况下,会在输⼊⽂件相同⽂件夹内⽣成⼀个testcase1.bmp⽂件。

    二、设计思路

    LogoComplier的主要构成包括三部分:词法分析器(Lexer),解释器(Interpreter),执⾏器 (Executor)。

    在这里插入图片描述

    2.1 Lexer

    Lexer的功能是词法分析,是使⽤我们平常构建编译器时⽤的lex和yacc中的lex实现的。我发现 LogoComplier的语法实在太过简单,以⾄于不需要⽤yacc。Lexer把输⼊⽂件中的内容分为⼀个⼀个符 号(Symbol),压⼊队列lexQueue,并将其传给Interpreter,开始第⼆阶段的分析。

    在这里插入图片描述

    2.2 Interpreter

    Interpreter会做⼀些简单的语法检查,然后通过分析lexQueue,调⽤Executor的接⼝,将Symbol序列 转变为可执⾏的Op序列。之后调⽤Executor的run()⽅法,开始第三阶段的执⾏。

    在这里插入图片描述

    2.3 Executor

    Executor负责实际的运算和绘画⼯作。通过Interpreter在第⼆阶段的处理,输⼊的符号序列已经变为了 ⼀连串的Op序列,Executor调⽤每个Op的exec()⽅法。⼀些的Op的集合组成⼀个Function,Executor 内维护⼀个Function的列表和⼀个调⽤堆栈callStack。callStack由若⼲个栈帧StackFrame组成,⼀个 StackFrame中存有当前执⾏的Function指针、返回地址、局部变量。

    Function就相当于我们平时运⾏程序时的代码段,callStack就是运⾏堆栈。

    在这里插入图片描述

    三、⼀些feature和实现⽅式

    3.1 函数调用

    LogoCompiler运⾏时的最外层函数是“0global”,之所以起这个名字,是因为它不是⽤户可使⽤的合法 标识符名,“0global”就相当于C语⾔中的main函数。 由于StackFrame和callStack的存在,实际上函数可以⽀持递归,但是由于语法中没有if⽀持,⽆法设置 递归基,因此递归不可⽤。

    3.2 变量作⽤域

    作⽤域是以Function区分的。Function内的变量会遮蔽外部的变量。

    StackFrame中维护了⼀个Variable的数组,是在当前作⽤域中定义的局部变量。当要引⽤⼀个变量的时 候,会优先在当前作⽤域中寻找,若找不到,会在外层作⽤域中继续寻找,若都找不到,则会报错。

    3.3 VariableWrapper类

    例如MOVE操作可以接受⼀个常数也可以接受⼀个变量,如MOVE 100和MOVE X。为了统⼀两者,我引 ⼊了VariableWrapper类,它可以将Variable和INTCONST字⾯量统⼀起来,并提供getValue()⽅法,在 执⾏时再计算实际的值。这也算是⼀种lazy policy,它还可以配合变量作⽤域,优先查找当前作⽤域中 的同名变量。

    3.4 Op类

    ⼏乎每个Op类都是Executor的友元,可以直接修改其内部变量。

    在这里插入图片描述

    • 每个Op⼦类都重写了exec()函数。

    3.5 错误提示

    我尽量使LogoCompiler⽀持可读的错误提示。⼀些例⼦如下:

    Cannot open the file
    Error at line 1: \
    Error: The file is empty
    Error at line 6: Unexpected symbol: hackhacks
    Runtime Error at line 10: END LOOP not found
    Error: End of file in function definition, did you miss "END FUNC" for
    line()?
    Runtime Error at line 11: arguments do not match
    Runtime warning: Color value out of range, value larger than 255 will be set
    to 255, value smaller than 0 will be set 0
    Error at line 19: Unexpected symbol: END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.6 逆向⽣成logo⽂件

    在 testcases/extended/logoGen ⽂件夹中,有⼀个辅助⼯具 logoGenerator.py ,它可以把任意⼀ 张图⽚,转变为合法的logo⽂件。把该logo⽂件作为输⼊,LogoCompiler可以⽣成完全相同的图⽚。 logo⽂件可能很⼤,但是LogoCompiler可以⾼效地执⾏它。

    在这里插入图片描述

    具体⽤法:

    python3 logoGenerator.py Lenna.png > Lenna.logo
    ./logoCompiler Lenna.logo
    
    
    • 1
    • 2
    • 3

    四、输出展示

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    【自然语言处理】关系抽取 —— GDPNet 讲解
    每天一个数据分析题(三百七十九)- 用户留存
    Filter过滤器
    CTF网络安全题目个人导航【持续更新】
    线性代数的本质(二)——线性变换与矩阵
    C++ 20 新特性简介
    java后端debug排查问题思路
    【博客506】k8s扩展调度器以支撑更灵活的GPU调度
    专访 | 许伟 ——贡献榜 Top4 也只是“开源小白”
    Spring基础之AOP和代理模式
  • 原文地址:https://blog.csdn.net/newlw/article/details/126829840