Algorithm 调车场算法的扩展与实现问题

Algorithm 调车场算法的扩展与实现问题,algorithm,go,compiler-construction,implementation,abstract-syntax-tree,Algorithm,Go,Compiler Construction,Implementation,Abstract Syntax Tree,让我向您介绍我目前的项目(这显然会产生我面临的问题,因此我在这里发布)。我正在为一种过于简单的语言编写一个所谓的“编译器”。我已经构建了一个VM来运行生成的字节码,即相关的Lexer(这个项目都是可选的)。我的问题在于表达式解析位。我使用Dijkstra的调车场算法将后缀表达式转换为相应的AST结构,并且我无法正确地调整算法以生成正确的AST,如果并且仅当我尝试实现函数调用和数组下标 这里是算法实现的示例(我相信一切都是不言自明的) func(p*解析器)调车场(输入令牌.TQueue)*ast

让我向您介绍我目前的项目(这显然会产生我面临的问题,因此我在这里发布)。我正在为一种过于简单的语言编写一个所谓的“编译器”。我已经构建了一个VM来运行生成的字节码,即相关的Lexer(这个项目都是可选的)。我的问题在于表达式解析位。我使用Dijkstra的调车场算法将后缀表达式转换为相应的AST结构,并且我无法正确地调整算法以生成正确的AST,如果并且仅当我尝试实现函数调用和数组下标

这里是算法实现的示例(我相信一切都是不言自明的)

func(p*解析器)调车场(输入令牌.TQueue)*ast.Node{
变量操作数ast.NStack
var运算符*token.TStack
操作数=make(ast.NStack,0)
operators=token.TokenStack()
对于tok:=input.Dequeue();tok.Sym!=“EOF”;tok=input.Dequeue(){
开关类{
案例“LParen”:
操作员推送(tok)
案例“RParen”:
为了{
//从堆栈中弹出项((“或运算符”)
if运算符.Empty(){
p、 errorf(“第%d行的括号不匹配,应为“(”匹配表达式中的右括号),p.lno)
}
op:=operators.Pop()
如果运算符号=“(”{
中断//放弃“(”
}
如果是一元(op.Sym){
节点:=ast.MakeNode(*op)
node.AddChild(操作数.Pop())
操作数推送(节点)
打破
}
RHS:=操作数。Pop()
LHS:=操作数。Pop()
操作数.Push(ast.MakeParentNode(*op,RHS,LHS))
}
违约:
如果o1,isOp:=道具[tok.Sym];isOp{
//token是一个操作符
for!operators.Empty(){
/考虑堆栈上的顶部项目
op:=operators.PeekTop()
如果o2,isOp:=prOps[op.Sym];!isOp | o1.prec>o2.prec | o1.prec==o2.prec&&o1.rAssoc{
打破
}
//最上面的项目是需要删除的操作员
op=operators.Pop()
如果是一元(op.Sym){
节点:=ast.MakeNode(*op)
node.AddChild(操作数.Pop())
操作数推送(节点)
打破
}
RHS:=操作数。Pop()
LHS:=操作数。Pop()
操作数.Push(ast.MakeParentNode(*op,RHS,LHS))
}
//将操作符(新操作符)推到堆栈
操作员推送(tok)
}否则{
操作数.Push(ast.MakeNode(*tok))
}
}
}
//结果是排出堆栈
for!operators.Empty(){
if运算符.PeekTop().Sym==“(”{
p、 errorf(“第%d行的括号不匹配,应为“)”与表达式中的前一个括号匹配”,p.lno)
}
RHS:=操作数。Pop()
LHS:=操作数。Pop()
操作数.Push(ast.MakeParentNode(*operators.Pop(),RHS,LHS))
}
结果:=操作数。Pop()
for!操作数。空(){
result.AddSibling(操作数.Pop())
}
返回结果
}
这个想法非常简单,当您遇到来自运算符堆栈的二元运算符时,您会从操作数堆栈中弹出两个节点,将它们设置为遇到的运算符的子级(如果运算符为一元运算符,则为一个)。然后将结果节点推送到操作数堆栈上

例如,此输入:

c = 0;
a = 1 << 3 + 2;
结果(显然)不正确:

┣━ Number           0
┣━ Function         bar
┗━ Function         foo
当我应该有:

┗━ Function         foo
    ┗━ Function         bar
        ┗━ Number        0
我的第一个问题是:为了支持函数调用的AST生成,我必须对我的实现进行哪些修改?因为我在互联网上找到的关于SY算法的所有信息总是生成RPN字符串

另一件事是输入,例如:

-i++;
生成有效的输出:

┗━ UnaryMinus       -u
    ┗━ PlusPlus         ++
        ┗━ Identifier       'i'
但是
(-i++);
报告和不平衡的括号表达式

与操作员一起使用的
映射是:

var prOps=map[string]结构{
预处理
拉索克布尔酒店
}{
“++”:{50,false},”--“:{50,false},
“:{40,false},”[“:{40,false},
“!”:{30,true},“~”:{30,true},
“-u:{29,true},”--u:{29,true},“++u:{29,true},”,
“**”:{28,对},
“*”:{27,false},”/“:{27,false},”%:{27,false},
“+”:{26,false},“-”:{26,false},

“>>”:{25,false},“=”:{24,false},“你的项目看起来很有趣,大约六个月前我做了一个布尔表达式的小解析器,Go的源代码在解析器方面帮助了我很多,刷新了我关于语言理论的知识。我建议你看看Go的包:)顺便说一句,我是DijkstraI的超级粉丝。我投票决定将这个问题作为离题题题来结束,因为它已经被交叉发布在一个更合适的Stack Exchange站点上。将来,请只在一个Stack Exchange站点上发布您的问题。有关更多信息,请参阅。
-i++;
┗━ UnaryMinus       -u
    ┗━ PlusPlus         ++
        ┗━ Identifier       'i'