singrdk/base/Windows/csic/parser/disambiguate.cs

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++;
}
}
}