using System.Collections; using System.Collections.Generic; using System.Linq; namespace arookas { class sunExpression : sunNode { public sunExpression(sunSourceLocation location) : base(location) { } public override void Compile(sunContext context) { Stack operatorStack = new Stack(32); AnalyzeExpression(context, this, operatorStack); } void AnalyzeExpression(sunContext context, sunExpression expression, Stack operatorStack) { // this implementation assumes that the expression production child list alternates between operand and operator // we can safely assume this as the grammar "operand {binary_operator operand}" enforces it int stackCount = operatorStack.Count; foreach (var node in expression) { if (node is sunOperand) { var operand = node as sunOperand; // term var term = operand.Term; if (term is sunExpression) { AnalyzeExpression(context, term as sunExpression, operatorStack); } else { term.Compile(context); } var unaryOperators = operand.UnaryOperators; if (unaryOperators != null) { unaryOperators.Compile(context); } } else if (node is sunOperator) { var operatorNode = node as sunOperator; while (operatorStack.Count > stackCount && (operatorNode.IsLeftAssociative && operatorNode.Precedence <= operatorStack.Peek().Precedence) || (operatorNode.IsRightAssociative && operatorNode.Precedence < operatorStack.Peek().Precedence)) { operatorStack.Pop().Compile(context); } operatorStack.Push(operatorNode); } } while (operatorStack.Count > stackCount) { operatorStack.Pop().Compile(context); } } } class sunOperand : sunNode { public sunNode UnaryOperators { get { return Count > 1 ? this[0] : null; } } public sunNode Term { get { return this[Count - 1]; } } public sunOperand(sunSourceLocation location) : base(location) { } // operands are compiled in sunExpression.Compile } class sunUnaryOperatorList : sunNode { public sunUnaryOperatorList(sunSourceLocation location) : base(location) { } public override void Compile(sunContext context) { foreach (var child in this.Reverse()) { // compile unary operators in reverse order child.Compile(context); } } } class sunTernaryOperator : sunNode { public sunExpression Condition { get { return this[0] as sunExpression; } } public sunExpression TrueBody { get { return this[1] as sunExpression; } } public sunExpression FalseBody { get { return this[2] as sunExpression; } } public sunTernaryOperator(sunSourceLocation node) : base(node) { } public override void Compile(sunContext context) { Condition.Compile(context); var falsePrologue = context.Text.GotoIfZero(); TrueBody.Compile(context); var trueEpilogue = context.Text.Goto(); context.Text.ClosePoint(falsePrologue); FalseBody.Compile(context); context.Text.ClosePoint(trueEpilogue); } } }