/** Return true if successful */
public virtual bool TranslateLeftRecursiveRule(GrammarRootAST ast,
LeftRecursiveRule r,
string language)
{
//tool.log("grammar", ruleAST.toStringTree());
GrammarAST prevRuleAST = r.ast;
string ruleName = prevRuleAST.GetChild(0).Text;
LeftRecursiveRuleAnalyzer leftRecursiveRuleWalker =
new LeftRecursiveRuleAnalyzer(prevRuleAST, tool, ruleName, language);
bool isLeftRec;
try
{
//System.Console.WriteLine("TESTING ---------------\n" +
// leftRecursiveRuleWalker.Text(ruleAST));
isLeftRec = leftRecursiveRuleWalker.rec_rule();
}
catch (RecognitionException)
{
isLeftRec = false; // didn't match; oh well
}
if (!isLeftRec)
return false;
// replace old rule's AST; first create text of altered rule
GrammarAST RULES = (GrammarAST)ast.GetFirstChildWithType(ANTLRParser.RULES);
string newRuleText = leftRecursiveRuleWalker.GetArtificialOpPrecRule();
//System.Console.WriteLine("created: " + newRuleText);
// now parse within the context of the grammar that originally created
// the AST we are transforming. This could be an imported grammar so
// we cannot just reference this.g because the role might come from
// the imported grammar and not the root grammar (this.g)
RuleAST t = ParseArtificialRule(prevRuleAST.g, newRuleText);
// reuse the name token from the original AST since it refers to the proper source location in the original grammar
((GrammarAST)t.GetChild(0)).Token = ((GrammarAST)prevRuleAST.GetChild(0)).Token;
// update grammar AST and set rule's AST.
RULES.SetChild(prevRuleAST.ChildIndex, t);
r.ast = t;
// Reduce sets in newly created rule tree
GrammarTransformPipeline transform = new GrammarTransformPipeline(g, g.tool);
transform.ReduceBlocksToSets(r.ast);
transform.ExpandParameterizedLoops(r.ast);
// Rerun semantic checks on the new rule
RuleCollector ruleCollector = new RuleCollector(g);
ruleCollector.Visit(t, "rule");
BasicSemanticChecks basics = new BasicSemanticChecks(g, ruleCollector);
// disable the assoc element option checks because they are already
// handled for the pre-transformed rule.
basics.checkAssocElementOption = false;
basics.Visit(t, "rule");
// track recursive alt info for codegen
r.recPrimaryAlts = new List<LeftRecursiveRuleAltInfo>();
foreach (var altInfo in leftRecursiveRuleWalker.prefixAndOtherAlts)
r.recPrimaryAlts.Add(altInfo);
if (r.recPrimaryAlts.Count == 0)
{
tool.errMgr.GrammarError(ErrorType.NO_NON_LR_ALTS, g.fileName, ((GrammarAST)r.ast.GetChild(0)).Token, r.name);
}
r.recOpAlts = new OrderedHashMap<int, LeftRecursiveRuleAltInfo>();
foreach (var pair in leftRecursiveRuleWalker.binaryAlts)
r.recOpAlts[pair.Key] = pair.Value;
foreach (var pair in leftRecursiveRuleWalker.ternaryAlts)
r.recOpAlts[pair.Key] = pair.Value;
foreach (var pair in leftRecursiveRuleWalker.suffixAlts)
r.recOpAlts[pair.Key] = pair.Value;
// walk alt info records and set their altAST to point to appropriate ALT subtree
// from freshly created AST
SetAltASTPointers(r, t);
// update Rule to just one alt and add prec alt
ActionAST arg = (ActionAST)r.ast.GetFirstChildWithType(ANTLRParser.ARG_ACTION);
if (arg != null)
{
r.args = ScopeParser.ParseTypedArgList(arg, arg.Text, g);
r.args.type = AttributeDict.DictType.ARG;
r.args.ast = arg;
arg.resolver = r.alt[1]; // todo: isn't this Rule or something?
}
// define labels on recursive rule refs we delete; they don't point to nodes of course
// these are so $label in action translation works
foreach (System.Tuple<GrammarAST, string> pair in leftRecursiveRuleWalker.leftRecursiveRuleRefLabels)
{
GrammarAST labelNode = pair.Item1;
GrammarAST labelOpNode = (GrammarAST)labelNode.Parent;
GrammarAST elementNode = (GrammarAST)labelOpNode.GetChild(1);
LabelElementPair lp = new LabelElementPair(g, labelNode, elementNode, labelOpNode.Type);
r.alt[1].labelDefs.Map(labelNode.Text, lp);
}
// copy to rule from walker
r.leftRecursiveRuleRefLabels = leftRecursiveRuleWalker.leftRecursiveRuleRefLabels;
tool.Log("grammar", "added: " + t.ToStringTree());
return true;
}