public class disambiguate { public static object resolve(nonterminalState node, string nonterm) { System.Collections.Queue q; expression e1; expression e2; switch (nonterm) { default: if (node.queue != null) { node.report(); //System.Console.WriteLine("{0}", node.ToString("")); throw new System.Exception("ambiguous"); } node.report(); return null; case "argument-list": q = node.queue; node.queue = null; argumentList a = (argumentList)parse2AST.rewrite_argument_list(node); foreach (nonterminalState s in q) { argumentList a2 = (argumentList)parse2AST.rewrite_argument_list(s); if (a2.Count < a.Count) a = a2; } return a; case "relational-expression": q = node.queue; node.queue = null; e1 = parse2AST.rewrite_relational_expression(node); int n = TypeArgumentCount(e1); foreach (nonterminalState s in q) { e2 = parse2AST.rewrite_relational_expression(s); int m = TypeArgumentCount(e2); if (m > n) { n = m; e1 = e2; } } return e1; case "if-statement": q = node.queue; node.queue = null; // by picking the short production int count = 0; for (state p = node.rightmost; p != node.below; p = p.below) count++; bool ties = false; foreach (nonterminalState node1 in q) { int c = 0; for (state p = node1.rightmost; p != node1.below; p = p.below) c++; if (c < count) { node = node1; ties = false; count = c; } else if (c == count) { ties = true; } } System.Diagnostics.Debug.Assert(!ties); return parse2AST.rewrite_if_statement(node); case "and-expression": // (e1) & e2 ambiguity q = node.queue; node.queue = null; e1 = parse2AST.rewrite_and_expression(node); System.Diagnostics.Debug.Assert(q.Count == 1); e2 = parse2AST.rewrite_and_expression((nonterminalState) q.Dequeue()); return fix_cast(e1,e2); case "additive-expression": // (e1) + e2 ambiguity q = node.queue; node.queue = null; e1 = parse2AST.rewrite_additive_expression(node); System.Diagnostics.Debug.Assert(q.Count == 1); e2 = parse2AST.rewrite_additive_expression((nonterminalState) q.Dequeue()); return fix_cast(e1,e2); case "unary-expression": // q = node.queue; node.queue = null; e1 = parse2AST.rewrite_unary_expression(node); System.Diagnostics.Debug.Assert(q.Count == 1); e2 = parse2AST.rewrite_unary_expression((nonterminalState) q.Dequeue()); return fix_cast(e1,e2); case "multiplicative-expression": // (e1) * e2 ambiguity q = node.queue; node.queue = null; e1 = parse2AST.rewrite_multiplicative_expression(node); System.Diagnostics.Debug.Assert(q.Count == 1); e2 = parse2AST.rewrite_multiplicative_expression((nonterminalState) q.Dequeue()); return fix_cast(e1,e2); } } static expression fix_cast(expression e1, expression e2) { // the first two cases are simple optimizations for the common case. if (e1 is cast_expression) { if (e2 is invocation_expression) { return e1; } return e2; } else if (e2 is cast_expression) { if (e1 is invocation_expression) { return e2; } return e1; } else { // // This is to handle the pathological case of (a+(b)-c) // or worse, ((a+b)+c-(d)e) // // The code is complicated because neither parse is rooted with a cast... // CastCounter c1 = new CastCounter(); ASTVisitor a1 = new ASTVisitor(c1.fn); e1.visit(a1); CastCounter c2 = new CastCounter(); ASTVisitor a2 = new ASTVisitor(c2.fn); e2.visit(a2); if (c1.Count == c2.Count+1) { return e1; } else if (c1.Count == c2.Count-1) { return e2; } else { // fall off into error message. } } throw new System.Exception("failed to disambiguate expressions"); } static int TypeArgumentCount(expression ast) { ArgumentCounter c = new ArgumentCounter(); ASTVisitor v = new ASTVisitor(c.fn); ast.visit(v); return c.Count; } } class ArgumentCounter { int _count = 0; public int Count { get { return _count; } } public void fn(AST ast) { if (ast is simple_name && ((simple_name)(ast)).typeargs != null) _count += ((simple_name)(ast)).typeargs.Count; else if (ast is member_access && ((member_access)(ast)).typeargs != null) _count += ((member_access)(ast)).typeargs.Count; } } class CastCounter { int _count = 0; public int Count { get { return _count; } } public void fn(AST ast) { if (ast is cast_expression) { _count++; } } }