Javascript中的抽象语法树递归性如何?
我正在尝试用javascript构建一个编译器,到目前为止,我已经成功构建了一个基于输入创建令牌的lexer: =测试输入(带可选分号): =实际Lexer结果(来自控制台-令牌数组): lexer做得很好(变量和函数的数据和任务是关键字)但是我想创建一些正则表达式,这样就可以捕获函数声明、变量声明等。只使用当前标记对象作为输入 如果是文本,我会用以下正则表达式捕获函数声明:Javascript中的抽象语法树递归性如何?,javascript,regex,recursion,backtracking,recursive-descent,Javascript,Regex,Recursion,Backtracking,Recursive Descent,我正在尝试用javascript构建一个编译器,到目前为止,我已经成功构建了一个基于输入创建令牌的lexer: =测试输入(带可选分号): =实际Lexer结果(来自控制台-令牌数组): lexer做得很好(变量和函数的数据和任务是关键字)但是我想创建一些正则表达式,这样就可以捕获函数声明、变量声明等。只使用当前标记对象作为输入 如果是文本,我会用以下正则表达式捕获函数声明: task\s+[a-zA-Z][a-zA-Z0-9]*\s*\{\s*(1)*\s*\} (1) 是指令块的正则表达式
task\s+[a-zA-Z][a-zA-Z0-9]*\s*\{\s*(1)*\s*\}
(1) 是指令块的正则表达式代码,包括接收等关键字函数
在本例中,有没有一种方法可以匹配变量/函数声明,即从for循环期间更改的索引开始
例如:
=我使用for循环遍历了我的令牌列表,在索引9中,我第一次找到了这个对象:
9: {content: "task", denominal: "keyword"}
=现在,我想开始搜索对象上的函数声明。这意味着:
1) -如果功能正确如声明、论据等
2) -这个函数意味着多少个对象像从索引9到索引30的一样,所有这些对象都形成一个名为“Eat”的函数,它有3个指令块:
- 1个特殊接收指令块,将强制放在函数的开头(甚至为空),包含格式正确的参数[variableName:variableType]
- 1个特殊打印指令块,并正确给出其参数
- 1特殊返回指令块,将强制放在函数开头(如果为空,则不返回任何内容:Void),包含格式正确的参数[variableName:variableType]
Instruction Object:
[0: {
"instruction": "variable_declaration",
"variable_name": "myVariable",
"variable_value": "4",
"variable_type": "Integer"
}
1: {
"instruction": "variable_declaration",
"variable_name": "myVariable2",
"variable_value": ""myName"",
"variable_type": "String"
}
2: {
"instruction": "function_declaration",
"function_name": "Eat",
"body_instructions": [0: {
"instruction": "receives_instruction",
"arguments": [0: {
"argument_name": "whatToEat",
"argument_type": "String"
}
1: {
"argument_name": "howMuchTime",
"argument_type": "Float"
}]
1: {
"instruction": "print_instruction",
"arguments": [0: {
"argument_name": "myVariable",
"argument_value": "4",
"argument_type": "Integer"
}]
2: {
"instruction": "returns_instruction",
"arguments": [0: {
"argument_name": "Nothing",
"argument_value": "",
"argument_type": "Void"
}]
}]
}] // EOF object optional
我感谢你的帮助强>
提前多谢我不知道您的语言的底层语法是什么,但大多数编程语言都基于上下文无关语法,需要比有限自动机(例如regex引擎)更强大的功能来解析它们;他们需要一个下推自动机。尽管一些正则表达式引擎已经被增强以模拟下推自动机,但我还是忍不住觉得,对于下一个阶段,即解析,您需要(或应该)切换到不同的工具。也许可以查看递归下降解析。只要我的两分钱。@Ronaldaronson我很感激你的建议,但是对于这个编译器(至少在它的情况下),我希望尽可能地保持它的基础性-例如,这些变量/函数唯一的声明被制作成在JS代码之后立即“转换”—离.replace()不远但更聪明一点:)问题是,在递归性的情况下,我必须知道“推入”对象的确切位置,这对我来说是最困难的部分。@Ronaldaronson例如,我会从位置“null”开始,然后在创建函数_声明后,我不知道是否应该用“AST[0]”或“AST”替换位置[1] 。最初,这是我的第一个选择,但我发现我不知道如何在代码中设置此位置(通过在新子对象中“输入”或“退出”完整子对象以返回其父对象/数组)。如果你能附上一个具有这种递归性的例子,你将是一个伟大的天才!非常感谢!:):)一个问题是标点符号
}
是否可以出现在函数体中。如果可以,那么你几乎肯定不能用类似正则表达式的工具来完成。你需要更复杂的东西。我还没有做过大量的解析,但我已经成功地用Peg.js编写了一些解析器,并且只使用模拟下推自动机的普通状态机。我认为这两种方法都可以在这里工作。@ScottSauyet请给我一个信息丰富的示例,说明考虑到函数内部没有}(就像Python if-s:))。为我的编译器构建此AST的主要目的是检查基于糟糕输入外观的任何语法错误&以某种方式将此对象转换回JavaScript代码,之后可能会使用eval。因此,主要需要的是对象的实际转换,而不是例外情况,以及是否可以附加任何可能请帮助我(我最初认为是基于递归的方法),这将是非常棒的。非常感谢!
9: {content: "task", denominal: "keyword"}
Instruction Object:
[0: {
"instruction": "variable_declaration",
"variable_name": "myVariable",
"variable_value": "4",
"variable_type": "Integer"
}
1: {
"instruction": "variable_declaration",
"variable_name": "myVariable2",
"variable_value": ""myName"",
"variable_type": "String"
}
2: {
"instruction": "function_declaration",
"function_name": "Eat",
"body_instructions": [0: {
"instruction": "receives_instruction",
"arguments": [0: {
"argument_name": "whatToEat",
"argument_type": "String"
}
1: {
"argument_name": "howMuchTime",
"argument_type": "Float"
}]
1: {
"instruction": "print_instruction",
"arguments": [0: {
"argument_name": "myVariable",
"argument_value": "4",
"argument_type": "Integer"
}]
2: {
"instruction": "returns_instruction",
"arguments": [0: {
"argument_name": "Nothing",
"argument_value": "",
"argument_type": "Void"
}]
}]
}] // EOF object optional