160 lines
4.5 KiB
C#
160 lines
4.5 KiB
C#
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++;
|
|
}
|
|
}
|
|
}
|