Java 基于调车场算法的三值算子解析
有关上下文,请先阅读 我正在构建自己的编程语言,允许您定义自定义运算符。因为我希望它有尽可能少的编译器内置,它应该允许自定义三元运算符的定义,最好是以Java 基于调车场算法的三值算子解析,java,algorithm,ternary-operator,shunting-yard,Java,Algorithm,Ternary Operator,Shunting Yard,有关上下文,请先阅读 我正在构建自己的编程语言,允许您定义自定义运算符。因为我希望它有尽可能少的编译器内置,它应该允许自定义三元运算符的定义,最好是以 infix operator ? : { precedence 120 } 我的(手工编写的)表达式解析器将嵌套的三元运算符转换为由运算符分隔的操作数列表 a ? b ? c : d : e (a) ? (b) ? (c) : (d) : (d) OperatorChain(operators: [?, ?, :, :], operands:
infix operator ? : { precedence 120 }
我的(手工编写的)表达式解析器将嵌套的三元运算符转换为由运算符分隔的操作数列表
a ? b ? c : d : e
(a) ? (b) ? (c) : (d) : (d)
OperatorChain(operators: [?, ?, :, :], operands: [a, b, c, d, e])
OperatorChain
类现在从范围中的操作员定义中查找操作员,并使用调车场算法的修改版本将列表转换为二进制AST节点,如下所示:
// Note: OperatorElement is a class that merely stores an Identifier, an associated source code position and the resolved operator.
// IValue is the base interface for all Expression AST nodes
final Stack<OperatorElement> operatorStack = new LinkedList<>();
final Stack<IValue> operandStack = new LinkedList<>();
operandStack.push(this.operands[0]);
for (int i = 0; i < this.operatorCount; i++)
{
final OperatorElement element1 = this.operators[i];
OperatorElement element2;
while (!operatorStack.isEmpty())
{
element2 = operatorStack.peek();
final int comparePrecedence = element1.operator.comparePrecedence(element2.operator);
if (comparePrecedence < 0
|| element1.operator.getAssociativity() != IOperator.RIGHT && comparePrecedence == 0)
{
operatorStack.pop();
this.pushCall(operandStack, element2);
}
else
{
break;
}
}
operatorStack.push(element1);
operandStack.push(this.operands[i + 1]);
}
while (!operatorStack.isEmpty())
{
this.pushCall(operandStack, operatorStack.pop());
}
return operandStack.pop().resolve(markers, context);
//注意:OperatorElement是一个仅存储标识符、关联源代码位置和解析运算符的类。
//IValue是所有表达式AST节点的基本接口
最终堆栈运算符Stack=newlinkedlist();
最终堆栈操作数堆栈=新的LinkedList();
操作数堆栈.push(this.operans[0]);
for(int i=0;i
我需要如何修改这个算法来处理三元运算符,包括自定义运算符?我已经用java实现了一个数学解析器,它可以处理三元运算符。其核心是
表达式
方法。输入包含在迭代器it
中,使用it.peek next()
方法查看下一个标记,并it.consume()
移动到下一个标记。它调用prefixSuffix()
读取带有可能的前缀和后缀运算符的常量和变量,例如++x
protected void expression() throws ParseException {
prefixSuffix();
Token t = it.peekNext();
while(t!=null) {
if(t.isBinary()) {
OperatorToken ot = (OperatorToken)t;
Operator op = ot.getBinaryOp();
pushOp(op,ot);
it.consume();
prefixSuffix();
}
else if(t.isTernary()){
OperatorToken ot =(OperatorToken)t;
Operator to = ot.getTernaryOp();
pushOp(to,ot);
it.consume();
prefixSuffix();
}
else
break;
t=it.peekNext();
}
// read all remaining elements off the stack
while(!sentinel.equals(ops.peek())) {
popOp();
}
}
因此,当遇到任何一个令牌时,它调用pushOp
方法将它们推送到堆栈上。每个令牌都有一个关联的运算符,该运算符也被解析为pushOp
pushOp将新操作符与堆栈顶部进行比较,必要时弹出
protected void pushOp(Operator op,Token tok) throws ParseException
{
while(compareOps(ops.peek(),op))
popOp();
ops.push(op);
}
处理十进制运算符的逻辑发生在compareOps
中:
/**
* Compare operators based on their precedence and associativity.
* @param op1
* @param op2
* @return true if op1 has a lower precedence than op2, or equal precedence and a left assoc op, etc.
*/
protected boolean compareOps(Operator op1,Operator op2)
{
if(op1.isTernary() && op2.isTernary()) {
if(op1 instanceof TernaryOperator.RhsTernaryOperator &&
op2 instanceof TernaryOperator.RhsTernaryOperator )
return true;
return false;
}
if(op1 == sentinel ) return false;
if(op2 == sentinel ) return true;
if(op2.isPrefix() && op1.isBinary()) return false;
if(op1.getPrecedence() < op2.getPrecedence()) return true;
if(op1.getPrecedence() == op2.getPrecedence() && op1.isLeftBinding()) return true;
return false;
}
只能遇到三元运算符的右侧。其正下方的操作员应为相应的左手操作员。(任何优先级较低的运算符都已弹出,只有优先级较高的运算符是赋值运算符,不能出现在三元运算符中)
左右手操作器现在都弹出。我正在构建一棵树,生成的最后三个节点被删除,并构造了一个新的三元操作符节点 非常感谢!我设法调整了我的
运算符链
类以支持自定义三值运算符。唯一的区别是,它将前面没有?
的:
视为右关联,尽管这是有意的。
protected void popOp() throws ParseException
{
Operator op = ops.pop();
if(op == implicitMul) {
Node rhs = nodes.pop();
Node lhs = nodes.pop();
Node node = nf.buildOperatorNode(
jep.getOperatorTable().getMultiply(),
lhs, rhs);
nodes.push(node);
}
else if(op.isBinary()) {
Node rhs = nodes.pop();
Node lhs = nodes.pop();
Node node = nf.buildOperatorNode(op, lhs, rhs);
nodes.push(node);
}
else if(op.isUnary()) {
Node lhs = nodes.pop();
Node node = nf.buildOperatorNode(op, lhs);
nodes.push(node);
}
else if(op.isTernary() && op instanceof TernaryOperator.RhsTernaryOperator ) {
Operator op2 = ops.pop();
if(!(op2 instanceof TernaryOperator ) || !((TernaryOperator) op2).getRhsOperator().equals(op)) {
throw new ParseException(
MessageFormat.format(JepMessages.getString("configurableparser.ShuntingYard.NextOperatorShouldHaveBeenMatchingTernaryOp"),op2.getName())); //$NON-NLS-1$
}
Node rhs = nodes.pop();
Node middle = nodes.pop();
Node lhs = nodes.pop();
Node node = nf.buildOperatorNode(op2, new Node[]{lhs,middle,rhs});
nodes.push(node);
}
else {
throw new ParseException(MessageFormat.format(JepMessages.getString("configurableparser.ShuntingYard.InvalidOperatorOnStack"),op.getSymbol())); //$NON-NLS-1$
}
}