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 void Demo() { // note that in the real world cases, you'd need to use SlangPatcher.Patch() // on whole compile units to get proper codedom objects back. This method is // simply "close enough for government work" and may not work for languages // other than VB while (true) { Console.Write("Slang>"); var s = Console.ReadLine(); if (null != s) { s = s.Trim(); } if (string.IsNullOrEmpty(s)) { break; } var isStatement = s.EndsWith(";") || s.EndsWith("}"); CodeObject co = null; try { if (isStatement) { co = SlangParser.ParseStatement(s, true); } else { co = SlangParser.ParseExpression(s); } } catch (SlangSyntaxException ex) { Console.WriteLine("Error: " + ex.Message); } if (null != co) { var ccu = _RootCode(co); try { SlangPatcher.Patch(ccu); } catch (Exception ex) { Console.WriteLine("Warning: Error resolving code - " + ex.Message); } var tc = new CodeDomTypeConverter(); var item = (ccu.Namespaces[0].Types[0].Members[0] as CodeMemberMethod).Statements[0]; if (!isStatement) { co = item; var es = item as CodeExpressionStatement; if (null != es) { co = es.Expression; } } else { co = item; } s = CodeDomUtility.ToString(co); s = s.Trim(); Console.Write("C#: "); Console.WriteLine(s); s = CodeDomUtility.ToString(co, "vb"); s = s.Trim(); Console.Write("VB: "); Console.WriteLine(s); s = CodeDomUtility.ToString(CodeDomUtility.Literal(co, tc)); s = s.Trim(); Console.Write("CodeDom: "); Console.WriteLine(s); if (null != SlangPatcher.GetNextUnresolvedElement(ccu)) { Console.WriteLine("Warning: Not all of the code could be resolved."); } } } }
static void _GenerateSymbolConstants(CodeTypeDeclaration target, IList <string> symbolTable) { // generate symbol constants for (int ic = symbolTable.Count, i = 0; i < ic; ++i) { var symbol = symbolTable[i]; if (null != symbol) { var s = _MakeSafeName(symbol); s = _MakeUniqueMember(target, s); var constField = CodeDomUtility.Field(typeof(int), s, MemberAttributes.Const | MemberAttributes.Public, CodeDomUtility.Literal(i)); target.Members.Add(constField); } } }