public void Generate(Rule rule) { CGH.BeginRule(rule); _currentRule = rule; _target = new WList<LNode>(); _laVarsNeeded = 0; _separatedMatchCounter = _stopLabelCounter = 0; _recognizerMode = rule.IsRecognizer; _labelsInUse.Clear(); Visit(rule.Pred); if (_laVarsNeeded != 0) { LNode laVars = F.Call(S.Var, CGH.LAType()); for (int i = 0; _laVarsNeeded != 0; i++, _laVarsNeeded >>= 1) if ((_laVarsNeeded & 1) != 0) laVars = laVars.PlusArg(F.Id("la" + i.ToString())); _target.Insert(0, laVars); } LNode method; if (rule.TryWrapperName != null) { Debug.Assert(rule.IsRecognizer); method = F.OnNewLine(CGH.CreateTryWrapperForRecognizer(rule)); _classBody.SpliceAdd(method, S.Splice); } method = CGH.CreateRuleMethod(rule, _target.ToVList()); if (!rule.IsRecognizer) method = F.OnNewLine(method); _classBody.SpliceAdd(method, S.Splice); }
private void AddUserAction(VList <LNode> actions) { int i = _target.Count; _target.AddRange(actions); if (actions.Any(stmt => stmt.Range.StartIndex > 0)) { if (LLPG.AddCsLineDirectives) { // Remove folder name. This only makes sense if the output // file and input file are in the same folder; sadly we have // no access to the output file name, but as of 2015-05 it's // always true that the output file will be in the same folder. string filename = System.IO.Path.GetFileName(_target[i].Range.Source.FileName); var newline = F.Id(S.TriviaNewline); int line = 0; for (; i < _target.Count; i++, line++) { var r = _target[i].Range; if (line != r.Start.Line) { line = r.Start.Line; if (line <= 0) // sometimes occurs for generated `return result` statement { _target.Insert(i++, F.Trivia(S.CsPPRawText, "#line default")); } else { _target.Insert(i++, F.Trivia(S.CsPPRawText, "#line " + line + " " + Ecs.EcsNodePrinter.PrintString(filename, '"'))); } } } if (line > 1) { _target.Add(F.Trivia(S.CsPPRawText, "#line default")); } } else { _target[i] = _target[i].PlusAttr(F.Trivia(S.TriviaSLComment, string.Format(" line {0}", _target[i].Range.Start.Line))); } } }
public static void SpliceInsert(this WList <LNode> list, int index, LNode node, Symbol listName = null) { if (node.Calls(listName ?? CodeSymbols.Splice)) { list.InsertRange(index, node.Args); } else { list.Insert(index, node); } }
public void Generate(Rule rule) { CGH.BeginRule(rule); _currentRule = rule; _target = new WList <LNode>(); _laVarsNeeded = 0; _separatedMatchCounter = _stopLabelCounter = 0; _recognizerMode = rule.IsRecognizer; _labelsInUse.Clear(); Visit(rule.Pred); if (_laVarsNeeded != 0) { LNode laVars = F.Call(S.Var, CGH.LAType()); for (int i = 0; _laVarsNeeded != 0; i++, _laVarsNeeded >>= 1) { if ((_laVarsNeeded & 1) != 0) { laVars = laVars.PlusArg(F.Id("la" + i.ToString())); } } _target.Insert(0, laVars); } LNode method; if (rule.TryWrapperName != null) { Debug.Assert(rule.IsRecognizer); method = F.OnNewLine(CGH.CreateTryWrapperForRecognizer(rule)); _classBody.SpliceAdd(method, S.Splice); } method = CGH.CreateRuleMethod(rule, _target.ToVList()); if (!rule.IsRecognizer) { method = F.OnNewLine(method); } _classBody.SpliceAdd(method, S.Splice); }
Mode = MacroMode.ProcessChildrenBefore)] // post-normal-macro-expansion public static LNode with(LNode fn, IMessageSink sink) { LNode braces; if (fn.ArgCount != 2 || !(braces = fn.Args[1]).Calls(S.Braces)) { return(null); } LNode tmp = F.Id(NextTempName()); WList <LNode> stmts = braces.Args.ToWList(); stmts = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(expr => { if (expr.Calls(S.Dot, 1)) { return(expr.WithArgs(new VList <LNode>(tmp, expr.Args.Last))); } return(null); })); stmts.Insert(0, F.Var(null, tmp.Name, fn.Args[0])); return(F.Braces(stmts.ToVList())); }
Mode = MacroMode.ProcessChildrenBefore)] // post-normal-macro-expansion public static LNode with(LNode fn, IMacroContext context) { LNode braces; if (fn.ArgCount != 2 || !(braces = fn.Args[1]).Calls(S.Braces)) { return(null); } LNode tmp = F.Id(NextTempName(context)); WList <LNode> stmts = braces.Args.ToWList(); stmts = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(expr => { if (expr.Calls(S.Dot, 1)) { return(expr.WithArgs(new VList <LNode>(tmp, expr.Args.Last))); } else if (expr.IsIdNamed("#")) { return(tmp); } return(null); })); stmts.Insert(0, F.Var(null, tmp.Name, fn.Args[0])); if (IsExpressionContext(context)) { stmts.Add(tmp); return(F.Call("#runSequence", stmts.ToVList())); } else { return(F.Braces(stmts.ToVList())); } }
protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair<LNode, string>[] matchingCode, ref Symbol haveLoop) { var braces = F.Braces(); Debug.Assert(tree.Children.Count >= 1); var alts = (Alts)_currentPred; if (tree.Children.Count == 1) return GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop); // From the prediction table, we can generate either an if-else chain: // // if (la0 >= '0' && la0 <= '7') sub_tree_1(); // else if (la0 == '-') sub_tree_2(); // else break; // // or a switch statement: // // switch(la0) { // case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // sub_tree_1(); // break; // case '-': // sub_tree_2(); // break; // default: // goto breakfor; // } // // Assertion levels always need an if-else chain; lookahead levels // consider the complexity of switch vs if and decide which is most // appropriate. Generally "if" is slower, but a switch may require // too many labels since it doesn't support ranges like "la0 >= 'a' // && la0 <= 'z'". // // This class makes if-else chains directly (using IPGTerminalSet. // GenerateTest() to generate the test expressions), but the code // snippet generator (CSG) is used to generate switch statements // because the required code may be more complex. // // We may or may not be generating code inside a for(;;) loop. If we // decide to generate a switch() statement, one of the branches will // usually need to break out of the for loop, but "break" can only // break out of the switch(). In that case, add "stop:" after the // switch() and use "goto stop" instead of "break". WList<LNode> block = new WList<LNode>(); LNode laVar = null; MSet<int> switchCases = new MSet<int>(); IPGTerminalSet[] branchSets = null; bool should = false; if (tree.UsesLA()) { laVar = F.Id("la" + tree.Lookahead.ToString()); if (!tree.IsAssertionLevel) { IPGTerminalSet covered = CGH.EmptySet; branchSets = tree.Children.Select(branch => { var set = branch.Set.Subtract(covered); covered = covered.Union(branch.Set); return set; }).ToArray(); should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch); if (!should) switchCases.Clear(); else if (should && haveLoop == S.For) // Can't "break" out of the for-loop when there is a nested switch, haveLoop = GSymbol.Get(NextStopLabel()); // so use "goto stop". } } LNode[] branchCode = new LNode[tree.Children.Count]; for (int i = 0; i < tree.Children.Count; i++) if (tree.Children[i].IsErrorBranch) { if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value) { Debug.Assert(matchingCode.Length == alts.Arms.Count + 1); branchCode[i] = matchingCode[alts.Arms.Count].A; } else branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead); } else branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop); var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases); if (laVar != null) { block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead))); _laVarsNeeded |= 1ul << tree.Lookahead; } else if (should) laVar = CGH.LA(tree.Lookahead); if (should) { Debug.Assert(switchCases.Count != 0); code = CGH.GenerateSwitch(branchSets, switchCases, branchCode, code, laVar); } block.Add(code); return F.Braces(block.ToVList()); }
protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair <LNode, string>[] matchingCode, ref Symbol haveLoop) { var braces = F.Braces(); Debug.Assert(tree.Children.Count >= 1); var alts = (Alts)_currentPred; if (tree.Children.Count == 1) { return(GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop)); } // From the prediction table, we can generate either an if-else chain: // // if (la0 >= '0' && la0 <= '7') sub_tree_1(); // else if (la0 == '-') sub_tree_2(); // else break; // // or a switch statement: // // switch(la0) { // case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // sub_tree_1(); // break; // case '-': // sub_tree_2(); // break; // default: // goto breakfor; // } // // Assertion levels always need an if-else chain; lookahead levels // consider the complexity of switch vs if and decide which is most // appropriate. Generally "if" is slower, but a switch may require // too many labels since it doesn't support ranges like "la0 >= 'a' // && la0 <= 'z'". // // This class makes if-else chains directly (using IPGTerminalSet. // GenerateTest() to generate the test expressions), but the code // generation helper (CGH) is used to generate switch statements // because the required code may be more complex. // // We may or may not be generating code inside a for(;;) loop. If we // decide to generate a switch() statement, one of the branches will // usually need to break out of the for loop, but "break" can only // break out of the switch(). In that case, add "stop:" after the // switch() and use "goto stop" instead of "break". WList <LNode> block = new WList <LNode>(); LNode laVar = null; MSet <int> switchCases = new MSet <int>(); IPGTerminalSet[] branchSets = null; bool should = false; if (tree.UsesLA()) { laVar = F.Id("la" + tree.Lookahead.ToString()); if (!tree.IsAssertionLevel) { IPGTerminalSet covered = CGH.EmptySet; branchSets = tree.Children.Select(branch => { var set = branch.Set.Subtract(covered); covered = covered.Union(branch.Set); return(set); }).ToArray(); should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch); if (!should) { switchCases.Clear(); } else if (should && haveLoop == S.For) { // Can't "break" out of the for-loop when there is a nested switch, haveLoop = GSymbol.Get(NextStopLabel()); // so use "goto stop". } } } LNode[] branchCode = new LNode[tree.Children.Count]; for (int i = 0; i < tree.Children.Count; i++) { if (tree.Children[i].IsErrorBranch) { if (_recognizerMode) { branchCode[i] = F.Call(S.Return, F.False); } else if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value) { Debug.Assert(matchingCode.Length == alts.Arms.Count + 1); branchCode[i] = matchingCode[alts.Arms.Count].A; } else { branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead); } } else { branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop); } } var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases); if (laVar != null) { block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead))); _laVarsNeeded |= 1ul << tree.Lookahead; } else if (should) { laVar = CGH.LA(tree.Lookahead); } if (should) { Debug.Assert(switchCases.Count != 0); code = CGH.GenerateSwitch(branchSets, branchCode, switchCases, code ?? F.Missing, laVar); } block.Add(code); return(F.Braces(block.ToVList())); }
public static LNode @try(LNode node, IMessageSink sink) { if (!node.IsCall) return null; // try(code, catch, Exception::e, handler, catch, ..., finally, handler) // ...becomes... // #try(#{ stmt1; stmt2; ... }, #catch(#var(Exception, e), handler), #finally(handler)) LNode finallyCode = null; WList<LNode> clauses = new WList<LNode>(); var parts = node.Args; for (int i = parts.Count-2; i >= 1; i -= 2) { var p = parts[i]; if (p.IsIdNamed(_finally)) { if (clauses.Count != 0 || finallyCode != null) sink.Write(Severity.Error, p, "The «finally» clause must come last, there can only be one of them."); finallyCode = parts[i+1]; } else if (p.Name == _catch) { if (p.ArgCount > 0) { if (p.ArgCount > 1) sink.Write(Severity.Error, p, "Expected catch() to take one argument."); // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, p.Args[0], F.Missing, parts[i + 1])); } else { // This is a catch-all clause (the type argument is missing) if (clauses.Count != 0) sink.Write(Severity.Error, p, "The catch-all clause must be the last «catch» clause."); clauses.Add(F.Call(S.Catch, F.Missing, F.Missing, parts[i + 1])); } } else if (i > 1 && parts[i-1].IsIdNamed(_catch)) { // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, AutoRemoveParens(p), F.Missing, parts[i+1])); i--; } else { return Reject(sink, p, "Expected «catch» or «finally» clause here. Clause is missing or malformed."); } if (i == 2) return Reject(sink, parts[1], "Expected «catch» or «finally» clause here. Clause is missing or malformed."); } if (clauses.Count == 0 && finallyCode == null) { Debug.Assert(node.ArgCount <= 1); return Reject(sink, node, "Missing «catch, Type, Code» or «finally, Code» clause"); } if (finallyCode != null) clauses.Add(F.Call(S.Finally, finallyCode)); clauses.Insert(0, node.Args[0]); return node.With(S.Try, clauses.ToVList()); }
public static LNode @try(LNode node, IMessageSink sink) { if (!node.IsCall) { return(null); } // try(code, catch, Exception::e, handler, catch, ..., finally, handler) // ...becomes... // #try(#{ stmt1; stmt2; ... }, #catch(#var(Exception, e), handler), #finally(handler)) LNode finallyCode = null; WList <LNode> clauses = new WList <LNode>(); var parts = node.Args; for (int i = parts.Count - 2; i >= 1; i -= 2) { var p = parts[i]; if (p.IsIdNamed(_finally)) { if (clauses.Count != 0 || finallyCode != null) { sink.Write(Severity.Error, p, "The «finally» clause must come last, there can only be one of them."); } finallyCode = parts[i + 1]; } else if (p.Name == _catch) { if (p.ArgCount > 0) { if (p.ArgCount > 1) { sink.Write(Severity.Error, p, "Expected catch() to take one argument."); } // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, p.Args[0], F.Missing, parts[i + 1])); } else { // This is a catch-all clause (the type argument is missing) if (clauses.Count != 0) { sink.Write(Severity.Error, p, "The catch-all clause must be the last «catch» clause."); } clauses.Add(F.Call(S.Catch, F.Missing, F.Missing, parts[i + 1])); } } else if (i > 1 && parts[i - 1].IsIdNamed(_catch)) { // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, AutoRemoveParens(p), F.Missing, parts[i + 1])); i--; } else { return(Reject(sink, p, "Expected «catch» or «finally» clause here. Clause is missing or malformed.")); } if (i == 2) { return(Reject(sink, parts[1], "Expected «catch» or «finally» clause here. Clause is missing or malformed.")); } } if (clauses.Count == 0 && finallyCode == null) { Debug.Assert(node.ArgCount <= 1); return(Reject(sink, node, "Missing «catch, Type, Code» or «finally, Code» clause")); } if (finallyCode != null) { clauses.Add(F.Call(S.Finally, finallyCode)); } clauses.Insert(0, node.Args[0]); return(node.With(S.Try, clauses.ToVList())); }