Stamon 文档站

回到首页
回到上一级

编译器开发文档

这些源码位于src/compiler目录下

我们规定:Stamon源码的文件后缀为.st

词法分析器的变动不大。所以我们先来看看语法分析器。

目前的语法分析器已经没有已知bug了。本次的更改也着重于实现对多文件的语法分析。

最重要的是新增的Compiler.hpp,Compiler主要对编译器进行了封装。你只需要向Compiler提供相应的参数,就能实现编译。

以下是Compiler的讲解:

编写了Ast与AstIr之间的互转工具

这些工具位于src/ir目录下

AstIr是一种中间代码表示形式,可以将Ast展开为一个数组。这样就可以把Ast转为AstIr,并将AstIr以字节码的方式写入。读取时也只需要读取AstIr,并重组成Ast即可。

AstIr的格式和HTML的格式类似:由逻辑单元、数据单元和结束单元组成。一棵Ast可以通过深度优先遍历转为AstIr。

这样的描述也许会较为拗口,我们来看一个示例:

考虑以下Ast:

Add
|-a
|-Sub
|--b
|--1

该Ast可以转为以下AstIr:

<Add>         //此为逻辑单元,以此类推
<data val=a>  //此为数据单元,以此类推
<Sub>
<data val=b>
<data val=1>
<end>         //此为结束单元,以此类推
<end>

这段AstIr和上面的Ast本质上是等价的。这样只需将Ast转为AstIr,就能获得一系列单元,方便存入文件。

逻辑单元本质上就是Ast节点的非叶子节点,数据单元本质上就是Ast节点的叶子节点。

我们先来讲一讲AstIr.cpp

AstIr单元的实现是:

class AstIr {
    public:
        int type;
        /*
            * 一些特别的规定
            * 当type为-1,代表这是一个结束符,即</>
            */
        int data;
        //如果这个IR是字面量或标识符,则data存储着其在常量表中的下标
        //否则存储这个IR的具体信息(例如运算符类型)
        String filename;    //IR所在的文件名
        int lineNo; //IR所在的行号
};

由于Ast当中的叶子节点只有两种可能:标识符或字面量,所以我把两者统一了起来,设立了DataType的子类IdenConstType,这样常量表里也能存储标识符了。

而数据单元作为Ast的叶子节点,他的type统一为AstLeafType。其中AstLeaf是专门为了运行时而定制的。

AstRunning-Ast的区别就在于:Running-Ast的叶子节点皆为AstLeaf,而Ast非然。

AstIrConverter类用于将Ast数据生成为AstIr(同时兼任着AstIr转Running-Ast的任务),它值得关注的接口有:

至此,Stamon的源码将会被转为AstIr,接下来则是写入AstIr至文件了,这一部分的内容位于src/Stamon.hpp,暂时按下不表,在介绍完解释器后会解释。

完成了SFN机制

SFN机制在本项目原所在仓库中有提及,这里再次摘抄:

SFN,全称Stamon For Native。是StamonVM的一个调用外部功能的机制。你可以用它与解释器交互。

用不太准确但方便理解的说法是:SFN和JNI类似,都是一种本地库调用机制。

SFN的源码位于src/sfn/SFN.cpp

SFN在Stamon中的语法规定为sfn port, arg;,其中port必须为字符串,代表着端口号,使用不同的端口号会调用不同的本地库(类似于汇编中的IO),arg则是参数,在调用SFN后,arg可能会变为调用后的结果。

SFN中的本地库可以由用户自定义,可扩展性高,不过我认为应该要给SFN划分具体的标准,哪一部分端口保留用作标准的本地库,哪一部分交给用户自定义。我可能会在后续进行调整。

SFN类的主要接口有:

——改编自工作日志/20240512.md


查看该文件的提交记录