WebGL Tutorial
and more

实现JavaScript在线编译器

撰写时间:2025-02-18

修订时间:2025-02-24

目标设定

下面是一段C语言的代码:

int sum(int a, int b) { return a + b; } int main() { int x = 2 * 3; int y = sum(x, 4); printf(y); }

我们准备使用流的方式,将这段C语言代码分别编译为JavaScript代码及Wasm代码,并在浏览器中分别予以运行。

要点:

  1. 两套语法。是否符合契约约定?函数声明、赋值语句、返回语句。源语法及目标语法。
  2. 能识别为函数。按函数语法解析。包括:返回值、函数名、参数列表、函数体、返回值
  3. 变量。开辟内存空间、存储数值。数据类型、值。
  4. 关键词。实现特定的小功能。int, return, function, let

第一步:词条扫描

const { Lexer } = await import('./Lexer.js'); let src = ` int sum(int a, int b) { return a + b; } int main() { int x = (2 + 3) * 4 / 5; float y = sum(x, 6.78); printf(y); } `; Lexer.Parse(src);

上面去掉了相应的分隔符,所提取出来的词条,严格按源代码的顺序进行提取,并且没有漏掉任何关键信息。这些词条是构建抽象语法树AST, Abstract Syntax Tree)的必要信息。

输入流为单字符的可读流,输出流为多字符的可写流。通过应用流的管道操作,逻辑清晰,代码简练。

词法分析术语

数据类型

数据类型的作用在于在编译阶段为相应的变量分配内存空间。包括:

int
整数
float
浮点数

变量

变量用于在内存中存储数值。在C语言或汇编语言中,先在内存中存储数值,然后在编译阶段建立起符号表,在符号表中将数值的内存地址赋值于相应的变量。如果目标语言直接支持内存地址的操作,则可使用这种方式。

但对于JavaScriptWasm来讲,不需要直接操控数值的内存地址,故变量的AST只需变量名及数值就行了。

表达式