public static int Run(string[] args, TextReader stdin, TextWriter stdout, TextWriter stderr) { // our return code var result = 0; // app parameters string inputfile = null; string outputfile = null; string codeclass = null; string codelanguage = null; string codenamespace = null; string externaltoken = null; string nfagraph = null; string dfagraph = null; bool ignorecase = false; bool noshared = false; bool ifstale = false; // our working variables TextReader input = null; TextWriter output = null; try { if (0 == args.Length) { _PrintUsage(stderr); result = -1; } else if (args[0].StartsWith("/")) { throw new ArgumentException("Missing input file."); } else { // process the command line args inputfile = args[0]; for (var i = 1; i < args.Length; ++i) { switch (args[i].ToLowerInvariant()) { case "/output": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance outputfile = args[i]; break; case "/class": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codeclass = args[i]; break; case "/language": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codelanguage = args[i]; break; case "/namespace": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codenamespace = args[i]; break; case "/external": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance externaltoken = args[i]; break; case "/nfagraph": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance nfagraph = args[i]; break; case "/dfagraph": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance dfagraph = args[i]; break; case "/ignorecase": ignorecase = true; break; case "/noshared": noshared = true; break; case "/ifstale": ifstale = true; break; default: throw new ArgumentException(string.Format("Unknown switch {0}", args[i])); } } // now build it if (string.IsNullOrEmpty(codeclass)) { // default we want it to be named after the code file // otherwise we'll use inputfile if (null != outputfile) { codeclass = Path.GetFileNameWithoutExtension(outputfile); } else { codeclass = Path.GetFileNameWithoutExtension(inputfile); } } if (string.IsNullOrEmpty(codelanguage)) { if (!string.IsNullOrEmpty(outputfile)) { codelanguage = Path.GetExtension(outputfile); if (codelanguage.StartsWith(".")) { codelanguage = codelanguage.Substring(1); } } if (string.IsNullOrEmpty(codelanguage)) { codelanguage = "cs"; } } var stale = true; if (ifstale && null != outputfile) { stale = _IsStale(inputfile, outputfile); if (!stale) { stale = _IsStale(CodeBase, outputfile); } } if (!stale) { stderr.WriteLine("{0} skipped building {1} because it was not stale.", Name, outputfile); } else { if (null != outputfile) { stderr.Write("{0} is building file: {1}", Name, outputfile); } else { stderr.Write("{0} is building tokenizer.", Name); } input = new StreamReader(inputfile); var rules = new List <LexRule>(); string line; while (null != (line = input.ReadLine())) { var lc = LexContext.Create(line); lc.TrySkipCCommentsAndWhiteSpace(); if (-1 != lc.Current) { rules.Add(LexRule.Parse(lc)); } } input.Close(); input = null; LexRule.FillRuleIds(rules); var ccu = new CodeCompileUnit(); var cns = new CodeNamespace(); if (!string.IsNullOrEmpty(codenamespace)) { cns.Name = codenamespace; } ccu.Namespaces.Add(cns); var fa = _BuildLexer(rules, ignorecase, inputfile); var symbolTable = _BuildSymbolTable(rules); var symids = new int[symbolTable.Length]; for (var i = 0; i < symbolTable.Length; ++i) { symids[i] = i; } var blockEnds = _BuildBlockEnds(rules); var nodeFlags = _BuildNodeFlags(rules); if (null != nfagraph) { fa.RenderToFile(nfagraph); } fa = fa.ToDfa(); DfaEntry[] dfaTable = null; dfaTable = _ToDfaStateTable(fa, symids); if (!noshared) { if (string.IsNullOrEmpty(externaltoken)) { // import our Export/Token.cs into the library _ImportCompileUnit(Deslanged.Token, cns); } // import our Export/TableTokenizer.cs into the library _ImportCompileUnit(Deslanged.TableTokenizer, cns); } if (!string.IsNullOrEmpty(externaltoken)) { cns.Imports.Add(new CodeNamespaceImport(externaltoken)); } var origName = "Rolex."; CodeTypeDeclaration td = null; if (null == td) { td = Deslanged.TableTokenizerTemplate.Namespaces[1].Types[0]; origName += td.Name; td.Name = codeclass; CodeGenerator.GenerateSymbolConstants(td, symbolTable); } CodeDomVisitor.Visit(td, (ctx) => { var tr = ctx.Target as CodeTypeReference; if (null != tr) { if (0 == string.Compare(origName, tr.BaseType, StringComparison.InvariantCulture)) { tr.BaseType = codeclass; } } }); CodeMemberField f = null; f = CodeDomUtility.GetByName("DfaTable", td.Members) as CodeMemberField; f.InitExpression = CodeGenerator.GenerateDfaTableInitializer(dfaTable); f = CodeDomUtility.GetByName("NodeFlags", td.Members) as CodeMemberField; f.InitExpression = CodeDomUtility.Literal(nodeFlags); f = CodeDomUtility.GetByName("BlockEnds", td.Members) as CodeMemberField; f.InitExpression = CodeDomUtility.Literal(blockEnds); cns.Types.Add(td); var hasColNS = false; foreach (CodeNamespaceImport nsi in cns.Imports) { if (0 == string.Compare(nsi.Namespace, "System.Collections.Generic", StringComparison.InvariantCulture)) { hasColNS = true; break; } } if (!hasColNS) { cns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic")); } stderr.WriteLine(); var prov = CodeDomProvider.CreateProvider(codelanguage); var opts = new CodeGeneratorOptions(); opts.BlankLinesBetweenMembers = false; opts.VerbatimOrder = true; if (null == outputfile) { output = stdout; } else { // open the file and truncate it if necessary var stm = File.Open(outputfile, FileMode.Create); stm.SetLength(0); output = new StreamWriter(stm); } prov.GenerateCodeFromCompileUnit(ccu, output, opts); } } } // we don't like to catch in debug mode #if !DEBUG catch (Exception ex) { result = _ReportError(ex, stderr); } #endif finally { // close the input file if necessary if (null != input) { input.Close(); } // close the output file if necessary if (null != outputfile && null != output) { output.Close(); } } return(result); }
static int Main(string[] args) { var result = 0; string outputfile = null; string codeclass = null; string codenamespace = null; string codelanguage = null; string t4language = null; string t4arguments = null; bool noserialize = false; bool ifstale = false; bool mutable = false; TextReader input = null; TextWriter output = null; try { var asms = new List <string>(args.Length); var inputs = new List <string>(args.Length); if (0 == args.Length) { _PrintUsage(); result = -1; } else if (args[0].StartsWith("/")) { throw new ArgumentException("Missing input file."); } else { int start = 0; // process the command line args for (start = 0; start < args.Length; ++start) { var a = args[start]; if (a.StartsWith("/")) { break; } inputs.Add(a); } for (var i = start; i < args.Length; ++i) { switch (args[i]) { case "/output": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance outputfile = args[i]; break; case "/language": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codelanguage = args[i]; break; case "/t4language": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance t4language = args[i]; break; case "/t4args": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance t4arguments = args[i]; break; case "/class": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codeclass = args[i]; break; case "/namespace": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codenamespace = args[i]; break; case "/asms": if (args.Length - 1 == i) // check to see if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; while (i < args.Length && !args[i].StartsWith("/")) { asms.Add(args[i]); ++i; } if (0 == asms.Count) { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i - 1].Substring(1))); } break; case "/ifstale": ifstale = true; break; case "/mutable": mutable = true; break; case "/noserialize": noserialize = true; break; default: throw new ArgumentException(string.Format("Unknown switch {0}", args[i])); } } // now build it. if (string.IsNullOrEmpty(t4language)) { t4language = "cs"; } if (string.IsNullOrEmpty(codelanguage)) { if (!string.IsNullOrEmpty(outputfile)) { codelanguage = Path.GetExtension(outputfile); if (codelanguage.StartsWith(".")) { codelanguage = codelanguage.Substring(1); } } if (string.IsNullOrEmpty(codelanguage)) { codelanguage = "cs"; } } var stale = true; if (ifstale && null != outputfile) { stale = false; foreach (var f in inputs) { if (_IsStale(f, outputfile) || _IsStale(_CodeBase, outputfile)) { stale = true; break; } } } if (!stale) { Console.Error.WriteLine("{0} skipped cook of {1} because it was not stale.", _Name, outputfile); } else { // main build code here if (null != outputfile) { Console.Error.Write("{0} is cooking {1}.", _Name, outputfile); } else { Console.Error.Write("{0} is cooking deslanged code.", _Name); } #region Load Builder CodeCompileUnit builderCcu = null; using (var stm = typeof(Program).Assembly.GetManifestResourceStream("Deslang.Shared.CodeDomBuilder.cs")) { builderCcu = SlangParser.ReadCompileUnitFrom(stm); } builderCcu.ReferencedAssemblies.Add(typeof(CodeObject).Assembly.GetName().ToString()); SlangPatcher.Patch(builderCcu); #endregion var donor = builderCcu.Namespaces[1].Types[0]; Console.Error.WriteLine(); var sb = new StringBuilder(); var sw = new StringWriter(sb); var ccus = new CodeCompileUnit[inputs.Count]; var targs = new Dictionary <string, object>(); if (null != t4arguments) { var ta = t4arguments.Split('&'); for (var i = 0; i < ta.Length; i++) { var tap = ta[i].Split('='); var n = tap[0]; object o = null; if (1 < tap.Length) { o = Uri.UnescapeDataString(tap[1]); } targs[n] = o; } } for (var i = 0; i < ccus.Length; i++) { var f = inputs[i]; sb.Clear(); input = new StreamReader(f); SlangPreprocessor.Preprocess(input, sw, targs, t4language); input.Close(); input = null; var ccu = SlangParser.ParseCompileUnit(sw.ToString()); if (0 == i) { ccu.ReferencedAssemblies.AddRange(asms.ToArray()); ccu.ReferencedAssemblies.Add(typeof(CodeObject).Assembly.GetName().ToString()); } ccus[i] = ccu; } // now our unpatched input is in ccus SlangPatcher.Patch(ccus); var co = SlangPatcher.GetNextUnresolvedElement(ccus); int l = 0, c = 0; long p = 0L; if (null != co) { Console.Error.Write("Warning - input was not entirely resolved. Output may not be valid. Next unresolved element is: " + CodeDomUtility.ToString(co)); var o = co.UserData["slang:line"]; if (o is int) { l = (int)o; } o = co.UserData["slang:column"]; if (o is int) { c = (int)o; } o = co.UserData["slang:position"]; if (o is long) { p = (long)o; } } if (l + c + p > 0) { Console.Error.WriteLine(" at line {0}, column {1}, position {2}", l, c, p); } else { Console.Error.WriteLine(); } var ns = new CodeNamespace(); var ccuFinal = new CodeCompileUnit(); ccuFinal.Namespaces.Add(ns); if (!noserialize) { // now they're patched. Let's serialize. // create our namespace and compileunit. if (string.IsNullOrEmpty(codeclass)) { codeclass = "Deslanged"; } var cls = new CodeTypeDeclaration(codeclass); cls.IsClass = true; cls.IsPartial = true; cls.TypeAttributes = TypeAttributes.NotPublic; for (var i = 0; i < ccus.Length; i++) { var ccuInit = C.Literal(ccus[i], new CodeDomTypeConverter()); V.Visit(ccuInit, (ctx) => { var tr = ctx.Target as CodeTypeReference; if (null != tr) { if (tr.BaseType.StartsWith("System.CodeDom.")) { tr.BaseType = tr.BaseType.Substring(15); } else if (tr.BaseType.StartsWith("System.Reflection.")) { tr.BaseType = tr.BaseType.Substring(18); } } // look for our uses of codedombuilder var mi = ctx.Target as CodeMethodInvokeExpression; if (null != mi) { var tref = mi.Method.TargetObject as CodeTypeReferenceExpression; if (null != tref) { if (0 == string.Compare("CD.CodeDomBuilder", tref.Type.BaseType, StringComparison.InvariantCulture)) { mi.Method.TargetObject = C.TypeRef(codeclass); // find the method in our donor type; var m = C.GetByName(mi.Method.MethodName, donor.Members); if (null != m) // if it hasn't already been moved { // move it m.Name = "_" + m.Name; m.Attributes = (m.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private; donor.Members.Remove(m); cls.Members.Add(m); } mi.Method.MethodName = "_" + mi.Method.MethodName; } } } }); var name = Path.GetFileNameWithoutExtension(inputs[i]); if (mutable) { var fld = C.Field(typeof(CodeCompileUnit), name, MemberAttributes.Public | MemberAttributes.Static, ccuInit); cls.Members.Add(fld); } else { var prop = C.Property(typeof(CodeCompileUnit), name, MemberAttributes.Public | MemberAttributes.Static); prop.GetStatements.Add(C.Return(ccuInit)); cls.Members.Add(prop); } } if (!string.IsNullOrEmpty(codenamespace)) { ns.Name = codenamespace; } ns.Types.Add(cls); ns.Imports.Add(new CodeNamespaceImport("System.CodeDom")); ns.Imports.Add(new CodeNamespaceImport("System.Reflection")); } else { foreach (var ccu in ccus) { foreach (CodeDirective dir in ccu.StartDirectives) { ccuFinal.StartDirectives.Add(dir); } foreach (CodeDirective dir in ccu.EndDirectives) { ccuFinal.EndDirectives.Add(dir); } foreach (CodeAttributeDeclaration attr in ccu.AssemblyCustomAttributes) { ccuFinal.AssemblyCustomAttributes.Add(attr); } foreach (CodeNamespace cns in ccu.Namespaces) { var ccns = CodeDomUtility.GetByName(cns.Name, ccuFinal.Namespaces); if (null == ccns) { ccns = new CodeNamespace(); ccns.Name = cns.Name; ccuFinal.Namespaces.Add(ccns); } foreach (CodeNamespaceImport nsi in cns.Imports) { var found = false; foreach (CodeNamespaceImport nnsi in ccns.Imports) { if (nnsi.Namespace.Equals(nsi.Namespace, StringComparison.Ordinal)) { found = true; break; } } if (!found) { ccns.Imports.Add(nsi); } } foreach (CodeCommentStatement ccs in cns.Comments) { ccns.Comments.Add(ccs); } foreach (CodeTypeDeclaration td in cns.Types) { ccns.Types.Add(td); } } } } // we're ready with ccuFinal var prov = CodeDomProvider.CreateProvider(codelanguage); var opts = new CodeGeneratorOptions(); opts.BlankLinesBetweenMembers = false; opts.VerbatimOrder = true; if (null == outputfile) { output = Console.Out; } else { // open the file and truncate it if necessary var stm = File.Open(outputfile, FileMode.Create); stm.SetLength(0); output = new StreamWriter(stm); } prov.GenerateCodeFromCompileUnit(ccuFinal, output, opts); } } } #if !DEBUG catch (Exception ex) { result = _ReportError(ex); } #endif finally { if (null != input) { input.Close(); input = null; } if (null != outputfile && null != output) { output.Close(); output = null; } } return(result); }