我正在使用JavaScript编写一个C编译器,这仅仅是为了丰富自己(目前还没有实际用途,而且我可能不会维护它)。
我编写了一个词法分析器,可以成功地对任何字符串进行标记化,只要给出一组正则表达式列表和与该正则表达式匹配的类型。
我已经成功地对C源代码进行了标记化(相当简化的C,公平地说;我需要添加更多的标记化模式来捕获所有内容)。现在,我想构建AST作为源语言和翻译汇编之间的中间形式。
为了做到这一点,我正在尝试实现一个函数,它使用上下文无关文法,该文法定义为一个对象,其中:
- 键 → 目标(表达式、函数声明、强制转换表达式等),以及 - 值 → 映射数组
(其中映射是由构成目标的符号组成的数组[顺序很重要])。
以下是一个示例CFG,可以提供给解析器使用(这是从this C grammar改编的摘录):
我编写了一个词法分析器,可以成功地对任何字符串进行标记化,只要给出一组正则表达式列表和与该正则表达式匹配的类型。
我已经成功地对C源代码进行了标记化(相当简化的C,公平地说;我需要添加更多的标记化模式来捕获所有内容)。现在,我想构建AST作为源语言和翻译汇编之间的中间形式。
为了做到这一点,我正在尝试实现一个函数,它使用上下文无关文法,该文法定义为一个对象,其中:
- 键 → 目标(表达式、函数声明、强制转换表达式等),以及 - 值 → 映射数组
(其中映射是由构成目标的符号组成的数组[顺序很重要])。
以下是一个示例CFG,可以提供给解析器使用(这是从this C grammar改编的摘录):
var cfg = {
"cast_exp": [
["unary_exp"],
["(", "type_name", ")", "cast_exp"]
],
"unary_exp": [
["primary_exp"],
["++", "unary_exp"],
["--", "unary_exp"]
],
"primary_exp": [
["id"]
]
};
id
是我分词器捕获的类型之一,因此我认为我们可以将 "primary_exp" 视为起始符号。
现在,我的想法是递归地执行这个过程;也就是说,捕获第一个标记并将其与一个起始符号进行匹配。对剩余的标记进行递归处理,在上一次调用中匹配到的目标作为参数传递,并查看由刚刚匹配到的目标组成的产生式规则。
这对我来说没有太多意义,我认为我会陷入无限递归(或在非常长的源文件上遇到堆栈溢出)。
我该如何编写一个函数,能够遍历我的标记数组,并使用上述 CFG 构建 AST? 因为我正在做这个工作以丰富自己并挑战自己,如果您愿意,您可以提供代码,但我更希望得到指导和广义上的算法描述。