コード例 #1
0
			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);
			}
コード例 #2
0
            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)));
                    }
                }
            }
コード例 #3
0
ファイル: LNodeExt.cs プロジェクト: modulexcite/ecsharp
 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);
     }
 }
コード例 #4
0
            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);
            }
コード例 #5
0
ファイル: WithMacro.cs プロジェクト: murven/Loyc
                      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()));
        }
コード例 #6
0
                      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()));
            }
        }
コード例 #7
0
			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());
			}
コード例 #8
0
            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()));
            }
コード例 #9
0
ファイル: Prelude.Les.cs プロジェクト: jonathanvdc/Loyc
		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());
		}
コード例 #10
0
ファイル: Prelude.Les.cs プロジェクト: jonathanvdc/Loyc
        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()));
        }