Пример #1
0
        public static CodeCompileUnit Demo1()
        {
            // evaluates a simple expression
            var res = new CodeDomResolver();

            Console.WriteLine(res.Evaluate(SlangParser.ParseExpression("5*4-7")));

            // takes this file and get a codedom from it
            var ccu = SlangParser.ReadCompileUnitFrom("..\\..\\Demo1.cs");

            ccu.ReferencedAssemblies.Add("CodeDomGoKit.dll");
            ccu.ReferencedAssemblies.Add(typeof(CodeObject).Assembly.GetName().ToString());
            // now patch the parsed codedom so it's correct
            // NOTE: slang can't actually bind to this because it is a paramarray method
            // but we don't care here because it's not necessary. Slang only binds to what
            // it needs to and we never need the return type anyway (which is void)
            SlangPatcher.Patch(ccu);
            // now write it out in VB
            Console.WriteLine(CodeDomUtility.ToString(ccu, "vb"));
            // return the code we generated so we can use it for other demos
            // yay recycling
            Console.WriteLine("Press any key...");
            Console.ReadKey();
            Console.Clear();
            return(ccu);
        }
Пример #2
0
        static void RunResolver()
        {
            byte[] data;
            using (var stream = File.OpenRead(@"myfile.bin"))
            {
                data = new byte[(int)stream.Length];
                stream.Read(data, 0, data.Length);
            }

            // create a resolver
            var res = new CodeDomResolver();

            // read the resolver sample into the compile unit
            CodeCompileUnit ccu;

            using (var stm = File.OpenRead(@"..\..\Resolver.cs"))
                ccu = SlangParser.ReadCompileUnitFrom(stm);

            // remember to patch it!
            SlangPatcher.Patch(ccu);

            Console.Error.WriteLine(CU.ToString(ccu));

            // add the compile unit to the resolver
            res.CompileUnits.Add(ccu);

            // prepare the resolver
            // any time you add compile units you'll need
            // to call Refresh()
            res.Refresh();

            // go through all expressions in the
            // graph and try to get their type
            CodeDomVisitor.Visit(ccu, (ctx) => {
                var expr = ctx.Target as CodeExpression;
                if (null != expr)
                {
                    // we want everything except CodeTypeReferenceExpression
                    var ctre = expr as CodeTypeReferenceExpression;
                    if (null == ctre)
                    {
                        // get the scope of the expression
                        var scope             = res.GetScope(expr);
                        CodeTypeReference ctr = res.TryGetTypeOfExpression(expr, scope);
                        if (null != ctr)
                        {
                            Console.WriteLine(CU.ToString(expr) + " is type: " + CU.ToString(ctr));
                            Console.WriteLine("Scope Dump:");
                            Console.WriteLine(scope.ToString());
                        }
                    }
                }
            });
        }
Пример #3
0
        static void RunTemplate()
        {
            // compute the primes. algorithm borrowed
            // from SLax at https://stackoverflow.com/questions/1510124/program-to-find-prime-numbers
            var primesMax = 100;
            var primesArr = Enumerable.Range(0, (int)Math.Floor(2.52 * Math.Sqrt(primesMax) / Math.Log(primesMax))).Aggregate(
                Enumerable.Range(2, primesMax - 1).ToList(),
                (result, index) =>
            {
                var bp = result[index]; var sqr = bp * bp;
                result.RemoveAll(i => i >= sqr && i % bp == 0);
                return(result);
            }
                ).ToArray();

            // read the template into the compile unit
            CodeCompileUnit ccu;

            using (var stm = File.OpenRead(@"..\..\Template.cs"))
                ccu = SlangParser.ReadCompileUnitFrom(stm);

            // patch it either before or after modifying it
            SlangPatcher.Patch(ccu);

            // find the target namespace and change it
            var ns = ccu.TryGetNamespace("T_NAMESPACE");

            ns.Name = "TestNS";
            // find the target class
            var type = ns.TryGetType("T_TYPE");

            // change the name
            type.Name = "TestPrimes";
            // get the Primes field:
            var primes = type.TryGetMember("Primes") as CodeMemberField;

            // change the init expression to the primes array
            primes.InitExpression = CU.Literal(primesArr);

            // fixup any references to T_NAMESPACE or T_TYPE
            CodeDomVisitor.Visit(ccu, (ctx) => {
                var ctr = ctx.Target as CodeTypeReference;
                if (null != ctr)
                {
                    ctr.BaseType = ctr.BaseType.Replace("T_NAMESPACE", ns.Name).Replace("T_TYPE", type.Name);
                }
            });

            // already patched prior
            // SlangPatcher.Patch(ccu);

            // now write the result out
            Console.WriteLine(CU.ToString(ccu));
        }
Пример #4
0
        static void Demo2()
        {
            var sw = new StringWriter();

            using (var sr = new StreamReader(@"..\..\Test.tt"))
                SlangPreprocessor.Preprocess(sr, sw);
            var ccu = SlangParser.ParseCompileUnit(sw.ToString());

            SlangPatcher.Patch(ccu);
            Console.WriteLine(CodeDomUtility.ToString(ccu));
            Console.WriteLine("Press any key...");
            Console.ReadKey();
            Console.Clear();
        }
Пример #5
0
        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.");
                    }
                }
            }
        }
Пример #6
0
        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);
        }
Пример #7
0
        /*static int Test()
         * {
         *      string input;
         *      using (var sr = new StreamReader(@"..\..\data2.json"))
         *              input = sr.ReadToEnd();
         *      var tokenizer = new JsonTokenizer(input);
         *      var xbnf = XbnfDocument.ReadFrom(@"..\..\json.xbnf");
         *      XbnfGenerationInfo info;
         *      XbnfConvert.TryCreateGenerationInfo(xbnf, out info);
         *      int ts;
         *      var symbols =XbnfConvert.GetSymbolTable(info, out ts);
         *      CfgGlrParseTable parseTable;
         *      info.Cfg.RebuildCache();
         *      info.Cfg.TryToGlrParseTable(out parseTable, LRTableKind.Lalr1);
         *      var errorSentinels = new List<int>();
         *      var i = 0;
         *      var parseAttributes = new ParseAttribute[symbols.Count][];
         *      foreach(var attrs in info.Cfg.AttributeSets)
         *      {
         *              var id = symbols.IndexOf(attrs.Key);
         *              int jc = attrs.Value.Count;
         *              parseAttributes[id] = new ParseAttribute[jc];
         *              for(var j=0;j<jc;++j)
         *              {
         *                      var attr = attrs.Value[j];
         *                      parseAttributes[id][j] = new ParseAttribute(attr.Name, attr.Value);
         *                      if ("errorSentinel" == attr.Name && attr.Value is bool && ((bool)attr.Value))
         *                              errorSentinels.Add(id);
         *
         *              }
         ++i;
         *      }
         *      for (i = 0; i < parseAttributes.Length; i++)
         *              if (null == parseAttributes[i])
         *                      parseAttributes[i] = new ParseAttribute[0];
         *
         *      var parser = new GlrTableParser(parseTable.ToArray(symbols), symbols.ToArray(), parseAttributes, errorSentinels.ToArray(),tokenizer);
         *      foreach (var pt in parser.ParseReductions(false, true, false))
         *      {
         *              Console.WriteLine(pt.ToString("t"));
         *      }
         *      return 0;
         * }*/
        public static int Run(string[] args, TextReader stdin, TextWriter stdout, TextWriter stderr)
        {
            int        result = 0;
            TextWriter output = null;

            string inputfile     = null;
            string outputfile    = null;
            string rolexfile     = null;
            string codenamespace = null;
            string codelanguage  = null;
            string codeclass     = null;
            string yaccfile      = null;
            bool   verbose       = false;
            bool   noshared      = false;
            bool   ifstale       = false;
            bool   fast          = false;
            bool   noparser      = false;

            try
            {
                if (0 == args.Length)
                {
                    _PrintUsage(stderr);
                    return(-1);
                }
                if (args[0].StartsWith("/"))
                {
                    throw new ArgumentException("Missing input file.");
                }

                // process the command line args
                inputfile = args[0];
                for (var i = 1; i < args.Length; ++i)
                {
                    switch (args[i])
                    {
                    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 "/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 "/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 "/yacc":
                        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
                        yaccfile = args[i];
                        break;

                    case "/ifstale":
                        ifstale = true;
                        break;

                    case "/fast":
                        fast = true;
                        break;

                    case "/noparser":
                        noparser = true;
                        break;

                    case "/noshared":
                        noshared = true;
                        break;

                    case "/verbose":
                        verbose = true;
                        break;

                    case "/rolex":
                        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
                        rolexfile = args[i];
                        break;

                    default:
                        throw new ArgumentException(string.Format("Unknown switch {0}", args[i]));
                    }
                }
                if (null != outputfile && noparser)
                {
                    throw new ArgumentException("<noparser> and <ouputfile> cannot both be specified.", "outputfile");
                }

                if (null == codeclass)
                {
                    if (null != outputfile)
                    {
                        codeclass = Path.GetFileNameWithoutExtension(outputfile);
                    }
                    else
                    {
                        codeclass = Path.GetFileNameWithoutExtension(inputfile);
                    }
                }


                // override the options with our document's options
                var doc = XbnfDocument.ReadFrom(inputfile);
                var oi  = -1;
                oi = doc.Options.IndexOf("outputfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        outputfile = s;
                        if ("" == outputfile)
                        {
                            outputfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != outputfile)
                    {
                        if (!Path.IsPathRooted(outputfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            outputfile = Path.GetFullPath(Path.Combine(dir, outputfile));
                        }
                    }
                }
                oi = doc.Options.IndexOf("rolexfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        rolexfile = s;
                        if ("" == rolexfile)
                        {
                            rolexfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != rolexfile)
                    {
                        if (!Path.IsPathRooted(rolexfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            rolexfile = Path.GetFullPath(Path.Combine(dir, rolexfile));
                        }
                    }
                }

                oi = doc.Options.IndexOf("yaccfile");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        rolexfile = s;
                        if ("" == yaccfile)
                        {
                            yaccfile = null;
                        }
                    }
                    // if it's specified in the doc we need to make it doc relative
                    if (null != yaccfile)
                    {
                        if (!Path.IsPathRooted(yaccfile))
                        {
                            var dir = Path.GetDirectoryName(Path.GetFullPath(inputfile));
                            rolexfile = Path.GetFullPath(Path.Combine(dir, yaccfile));
                        }
                    }
                }


                oi = doc.Options.IndexOf("codenamespace");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        codenamespace = s;
                    }
                }
                oi = doc.Options.IndexOf("codelanguage");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (!string.IsNullOrEmpty(s))
                    {
                        codelanguage = s;
                    }
                }
                oi = doc.Options.IndexOf("codeclass");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    var s = o as string;
                    if (null != s)
                    {
                        codeclass = s;
                        if ("" == codeclass)
                        {
                            if (null != outputfile)
                            {
                                codeclass = Path.GetFileNameWithoutExtension(outputfile);
                            }
                            else
                            {
                                codeclass = Path.GetFileNameWithoutExtension(inputfile);
                            }
                        }
                    }
                }
                oi = doc.Options.IndexOf("verbose");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    if (o is bool)
                    {
                        verbose = (bool)o;
                    }
                }
                oi = doc.Options.IndexOf("fast");
                if (-1 < oi)
                {
                    var o = doc.Options[oi].Value;
                    if (o is bool)
                    {
                        fast = (bool)o;
                    }
                }
                if (fast && null != codelanguage)
                {
                    throw new ArgumentException("<codelanguage> and <fast> cannot both be specified. The <fast> option is C# only.");
                }

                var stale = true;
                if (ifstale)
                {
                    stale = false;
                    if (!stale && null != rolexfile)
                    {
                        if (_IsStale(inputfile, rolexfile))
                        {
                            stale = true;
                        }
                    }
                    if (!stale && null != yaccfile)
                    {
                        if (_IsStale(inputfile, yaccfile))
                        {
                            stale = true;
                        }
                    }

                    if (!stale)
                    {
                        var files = XbnfDocument.GetResources(inputfile);
                        foreach (var s in files)
                        {
                            if (_IsStale(s, outputfile))
                            {
                                stale = true;
                                break;
                            }
                        }
                    }
                    // see if our exe has changed
                    if (!stale && null != outputfile && _IsStale(CodeBase, outputfile))
                    {
                        stale = true;
                    }
                }

                if (!stale)
                {
                    stderr.WriteLine("Skipped building of the following because they were not stale:");
                    if (null != outputfile)
                    {
                        stderr.WriteLine("Output file: " + outputfile);
                    }
                    if (null != rolexfile)
                    {
                        stderr.WriteLine("Rolex file: " + rolexfile);
                    }
                    if (null != yaccfile)
                    {
                        stderr.WriteLine("YACC file: " + yaccfile);
                    }
                }
                else
                {
                    stderr.WriteLine("{0} is building the following:", Name);
                    if (null != outputfile)
                    {
                        stderr.WriteLine("Output file: " + outputfile);
                    }
                    if (null != rolexfile)
                    {
                        stderr.WriteLine("Rolex file: " + rolexfile);
                    }
                    if (null != yaccfile)
                    {
                        stderr.WriteLine("YACC file: " + yaccfile);
                    }
                    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 isLexerOnly = true;
                    if (doc.HasNonTerminalProductions)
                    {
                        isLexerOnly = false;
                    }
                    else
                    {
                        foreach (var include in doc.Includes)
                        {
                            if (include.Document.HasNonTerminalProductions)
                            {
                                isLexerOnly = false;
                                break;
                            }
                        }
                    }
                    // we need to prepare it by marking every terminal
                    // with an attribute if it isn't already. we use
                    // "terminal" because it doesn't impact terminals
                    // in any way, but this way the CfgDocument can
                    // "see" them.
                    for (int ic = doc.Productions.Count, i = 0; i < ic; ++i)
                    {
                        var p = doc.Productions[i];
                        if (p.IsTerminal && 0 == p.Attributes.Count)
                        {
                            p.Attributes.Add(new XbnfAttribute("terminal", true));
                        }
                    }

                    XbnfGenerationInfo genInfo;
                    var msgs = XbnfConvert.TryCreateGenerationInfo(doc, out genInfo);

                    foreach (var msg in msgs)
                    {
                        if (verbose || ErrorLevel.Information != msg.ErrorLevel)
                        {
                            stderr.WriteLine(msg);
                        }
                    }
                    foreach (var msg in msgs)
                    {
                        if (msg.ErrorLevel == ErrorLevel.Error)
                        {
                            throw new Exception(msg.ToString());
                        }
                    }
                    CfgDocument primaryCfg = genInfo.Cfg;
                    doc = genInfo.Xbnf;
                    if (!isLexerOnly)
                    {
                        if (verbose)
                        {
                            stderr.WriteLine("Final grammar:");
                            stderr.WriteLine(primaryCfg.ToString());
                            stderr.WriteLine();
                        }
                        foreach (var msg in msgs)
                        {
                            if (msg.ErrorLevel == ErrorLevel.Error)
                            {
                                throw new Exception(msg.ToString());
                            }
                        }
                        if (!noparser)
                        {
                            var ccu = CodeGenerator.GenerateCompileUnit(genInfo, codeclass, codenamespace, fast);
                            ccu.Namespaces.Add(new CodeNamespace(codenamespace ?? ""));
                            var ccuNS     = ccu.Namespaces[ccu.Namespaces.Count - 1];
                            var ccuShared = CodeGenerator.GenerateSharedCompileUnit(codenamespace);
                            ccu.ReferencedAssemblies.Add(typeof(TypeConverter).Assembly.GetName().ToString());

                            if (fast)
                            {
                                CD.CodeDomVisitor.Visit(ccu, (ctx) =>
                                {
                                    var vd = ctx.Target as CodeVariableDeclarationStatement;
                                    if (null != vd && CD.CodeDomResolver.IsNullOrVoidType(vd.Type))
                                    {
                                        vd.Type = C.Type("var");
                                    }
                                }, CD.CodeDomVisitTargets.All & ~(CD.CodeDomVisitTargets.Expressions | CD.CodeDomVisitTargets.Comments | CD.CodeDomVisitTargets.Attributes | CD.CodeDomVisitTargets.Directives | CD.CodeDomVisitTargets.Types | CD.CodeDomVisitTargets.TypeRefs));
                                CD.CodeDomVisitor.Visit(ccuShared, (ctx) =>
                                {
                                    var vd = ctx.Target as CodeVariableDeclarationStatement;
                                    if (null != vd && CD.CodeDomResolver.IsNullOrVoidType(vd.Type))
                                    {
                                        vd.Type = C.Type("var");
                                    }
                                }, CD.CodeDomVisitTargets.All & ~(CD.CodeDomVisitTargets.Expressions | CD.CodeDomVisitTargets.Comments | CD.CodeDomVisitTargets.Attributes | CD.CodeDomVisitTargets.Directives | CD.CodeDomVisitTargets.Types | CD.CodeDomVisitTargets.TypeRefs));
                            }
                            else
                            {
                                SlangPatcher.Patch(ccu, ccuShared);
                                var co = SlangPatcher.GetNextUnresolvedElement(ccu);
                                if (null != co)
                                {
                                    stderr.WriteLine("Warning: Not all of the elements could be resolved. The generated code may not be correct in all languages.");
                                    stderr.WriteLine("  Next unresolved: {0}", C.ToString(co).Trim());
                                }
                            }
                            if (!noshared)
                            {
                                CodeGenerator.ImportCompileUnit(ccuNS, ccuShared);
                            }

                            var prov = CodeDomProvider.CreateProvider(codelanguage);

                            if (null != outputfile)
                            {
                                var sw = new StreamWriter(outputfile);
                                sw.BaseStream.SetLength(0);
                                output = sw;
                            }
                            else
                            {
                                output = stdout;
                            }
                            var opts = new CodeGeneratorOptions();
                            opts.VerbatimOrder            = true;
                            opts.BlankLinesBetweenMembers = false;
                            prov.GenerateCodeFromCompileUnit(ccu, output, opts);
                            output.Flush();
                            output.Close();
                            output = null;
                        }
                    }
                    else
                    {
                        stderr.WriteLine("{0} skipped parser generation because there are no non-terminals and no imports defined.", Name);
                    }

                    if (null != rolexfile)
                    {
                        var sw = new StreamWriter(rolexfile);
                        sw.BaseStream.SetLength(0);
                        output = sw;
                        output.WriteLine(XbnfConvert.ToRolexSpec(genInfo));
                        output.Flush();
                        output.Close();
                        output = null;
                    }
                    if (null != yaccfile)
                    {
                        var sw = new StreamWriter(yaccfile);
                        sw.BaseStream.SetLength(0);
                        output = sw;
                        output.WriteLine(genInfo.Cfg.ToString("y"));
                        output.Flush();
                        output.Close();
                        output = null;
                    }
                }
            }
#if !DEBUG
            catch (Exception ex)
            {
                result = _ReportError(ex, stderr);
            }
#endif
            finally
            {
                stderr.Close();
                stdout.Close();
                if (outputfile != null && null != output)
                {
                    output.Close();
                }
            }
            return(result);
        }