static void _VisitUnreferenced(XbnfDocument doc, XbnfExpression expr, HashSet <string> result)
        {
            var r = expr as XbnfRefExpression;

            if (null != r)
            {
                if (!doc.Productions.Contains(r.Symbol))
                {
                    result.Add(r.Symbol);
                }
                return;
            }
            var u = expr as XbnfUnaryExpression;

            if (null != u)
            {
                _VisitUnreferenced(doc, u.Expression, result);
                return;
            }
            var b = expr as XbnfBinaryExpression;

            if (null != b)
            {
                _VisitUnreferenced(doc, b.Left, result);
                _VisitUnreferenced(doc, b.Right, result);
                return;
            }
        }
        static IList <IList <string> > _GetDysOptional(XbnfDocument d, ICollection <string> syms, IDictionary <XbnfExpression, string> tmap, IDictionary <string, XbnfAttributeList> attrs, IList <KeyValuePair <string, IList <string> > > rules, XbnfProduction p, XbnfOptionalExpression ope)
        {
            var l = new List <IList <string> >();

            if (null != ope.Expression)
            {
                l.AddRange(_GetDysjunctions(d, syms, tmap, attrs, rules, p, ope.Expression));
                var ll = new List <string>();
                if (!l.Contains(ll, OrderedCollectionEqualityComparer <string> .Default))
                {
                    l.Add(ll);
                }
            }
            return(l);
        }
        public static IList <IMessage> TryCreateGenerationInfo(XbnfDocument document, out XbnfGenerationInfo genInfo)
        {
            var includes = new XbnfImportList();

            _GatherIncludes(document, includes);
            var incs = new List <XbnfDocument>();

            incs.Add(document);
            foreach (var inc in includes)
            {
                incs.Add(inc.Document);
            }
            var doc = XbnfDocument.Merge(incs);
            var cfg = new CfgDocument();

            return(_TryToGenInfo(doc, cfg, out genInfo));
        }
        public static List <string> GetSymbolTable(XbnfGenerationInfo info, out int termStart)
        {
            var          result = new List <string>();
            var          seen   = new HashSet <string>();
            XbnfDocument xbnf   = info.Xbnf;
            var          cfg    = info.Cfg;

            foreach (var s in cfg.FillNonTerminals())
            {
                if (seen.Add(s))
                {
                    result.Add(s);
                }
            }

            termStart = result.Count;
            var ts = new List <string>();

            foreach (var prod in xbnf.Productions)
            {
                if (prod.IsTerminal)
                {
                    ts.Add(prod.Name);
                }
            }
            foreach (var s in ts)
            {
                //if (0 != string.Compare("#ERROR", s, StringComparison.InvariantCulture) && 0 != string.Compare("#EOS", s, StringComparison.InvariantCulture))
                //{
                if (seen.Add(s))
                {
                    result.Add(s);
                }
                //}
            }

            result.Add("#EOS");
            result.Add("#ERROR");
            return(result);
        }
        static IList <IList <string> > _GetDysConcat(XbnfDocument d, ICollection <string> syms, IDictionary <XbnfExpression, string> tmap, IDictionary <string, XbnfAttributeList> attrs, IList <KeyValuePair <string, IList <string> > > rules, XbnfProduction p, XbnfConcatExpression ce)
        {
            var l = new List <IList <string> >();

            if (null == ce.Right)
            {
                if (null == ce.Left)
                {
                    return(l);
                }
                foreach (var ll in _GetDysjunctions(d, syms, tmap, attrs, rules, p, ce.Left))
                {
                    l.Add(new List <string>(ll));
                }
                return(l);
            }
            else if (null == ce.Left)
            {
                foreach (var ll in _GetDysjunctions(d, syms, tmap, attrs, rules, p, ce.Right))
                {
                    l.Add(new List <string>(ll));
                }
                return(l);
            }
            foreach (var ll in _GetDysjunctions(d, syms, tmap, attrs, rules, p, ce.Left))
            {
                foreach (var ll2 in _GetDysjunctions(d, syms, tmap, attrs, rules, p, ce.Right))
                {
                    var ll3 = new List <string>();
                    ll3.AddRange(ll);
                    ll3.AddRange(ll2);
                    if (!l.Contains(ll3, OrderedCollectionEqualityComparer <string> .Default))
                    {
                        l.Add(ll3);
                    }
                }
            }
            return(l);
        }
 static void _GatherIncludes(XbnfDocument doc, XbnfImportList result)
 {
     for (int ic = doc.Includes.Count, i = 0; i < ic; ++i)
     {
         var inc   = doc.Includes[i];
         var found = false;
         for (int jc = result.Count, j = 0; j < jc; ++j)
         {
             var fn = result[i].Document.FileOrUrl;
             if (!string.IsNullOrEmpty(fn) && 0 == string.Compare(fn, inc.Document.FileOrUrl))
             {
                 found = true;
                 break;
             }
         }
         if (!found)
         {
             result.Add(inc);
             _GatherIncludes(inc.Document, result);
         }
     }
 }
        static IList <IList <string> > _GetDysOr(XbnfDocument d, ICollection <string> syms, IDictionary <XbnfExpression, string> tmap, IDictionary <string, XbnfAttributeList> attrs, IList <KeyValuePair <string, IList <string> > > rules, XbnfProduction p, XbnfOrExpression oe)
        {
            var l = new List <IList <string> >();

            if (null == oe.Left)
            {
                l.Add(new List <string>());
            }
            else
            {
                foreach (var ll in _GetDysjunctions(d, syms, tmap, attrs, rules, p, oe.Left))
                {
                    if (!l.Contains(ll, OrderedCollectionEqualityComparer <string> .Default))
                    {
                        l.Add(ll);
                    }
                }
            }
            if (null == oe.Right)
            {
                var ll = new List <string>();
                if (!l.Contains(ll, OrderedCollectionEqualityComparer <string> .Default))
                {
                    l.Add(ll);
                }
            }
            else
            {
                foreach (var ll in _GetDysjunctions(d, syms, tmap, attrs, rules, p, oe.Right))
                {
                    if (!l.Contains(ll, OrderedCollectionEqualityComparer <string> .Default))
                    {
                        l.Add(ll);
                    }
                }
            }
            return(l);
        }
        static IList <IList <string> > _GetDysRepeat(XbnfDocument d, ICollection <string> syms, IDictionary <XbnfExpression, string> tmap, IDictionary <string, XbnfAttributeList> attrs, IList <KeyValuePair <string, IList <string> > > rules, XbnfProduction p, XbnfRepeatExpression re)
        {
            string sid = null;
            var    sr  = re.Expression as XbnfRefExpression;

            if (null != d && null != sr)
            {
                sid = string.Concat(sr.Symbol, "List");
            }
            if (string.IsNullOrEmpty(sid))
            {
                var cc = re.Expression as XbnfConcatExpression;
                if (null != cc)
                {
                    sr = cc.Right as XbnfRefExpression;
                    if (null != sr)
                    {
                        sid = string.Concat(sr.Symbol, "ListTail");
                    }
                }
            }
            if (string.IsNullOrEmpty(sid))
            {
                sid = string.Concat(p.Name, "List");
            }
            var listId = sid;
            var i      = 2;
            var ss     = listId;

            while (syms.Contains(ss))
            {
                ss = string.Concat(listId, i.ToString());
                ++i;
            }
            syms.Add(ss);
            listId = ss;
            var attr     = new XbnfAttribute("collapsed", true);
            var attr2    = new XbnfAttribute("nowarn", true);
            var attr3    = new XbnfAttribute("factored", true);
            var attrlist = new XbnfAttributeList();

            attrlist.Add(attr);
            attrlist.Add(attr2);
            attrlist.Add(attr3);
            attrs.Add(listId, attrlist);
            var expr =
                new XbnfOrExpression(
                    new XbnfConcatExpression(
                        new XbnfRefExpression(listId), re.Expression), re.Expression);;

            foreach (var nt in _GetDysjunctions(d, syms, tmap, attrs, rules, p, expr))
            {
                var l = new List <string>();
                var r = new KeyValuePair <string, IList <string> >(listId, l);
                foreach (var s in nt)
                {
                    if (1 < r.Value.Count && null == s)
                    {
                        continue;
                    }
                    r.Value.Add(s);
                }
                rules.Add(r);
            }
            if (!re.IsOptional)
            {
                return(new List <IList <string> >(new IList <string>[] { new List <string>(new string[] { listId }) }));
            }
            else
            {
                var res = new List <IList <string> >();
                res.Add(new List <string>(new string[] { listId }));
                res.Add(new List <string>());
                return(res);
            }
        }
        static IList <IList <string> > _GetDysjunctions(
            XbnfDocument d,
            ICollection <string> syms,
            IDictionary <XbnfExpression, string> tmap,
            IDictionary <string, XbnfAttributeList> attrs,
            IList <KeyValuePair <string, IList <string> > > rules,
            XbnfProduction p,
            XbnfExpression e
            )
        {
            var le = e as XbnfLiteralExpression;

            if (null != le)
            {
                var res = new List <IList <string> >();
                var l   = new List <string>();
                l.Add(tmap[le]);
                res.Add(l);
                return(res);
            }
            var rxe = e as XbnfRegexExpression;

            if (null != rxe)
            {
                var res = new List <IList <string> >();
                var l   = new List <string>();
                l.Add(tmap[rxe]);
                res.Add(l);
                return(res);
            }
            var rfe = e as XbnfRefExpression;

            if (null != rfe)
            {
                var res = new List <IList <string> >();
                var l   = new List <string>();
                l.Add(rfe.Symbol);
                res.Add(l);
                return(res);
            }
            var ce = e as XbnfConcatExpression;

            if (null != ce)
            {
                return(_GetDysConcat(d, syms, tmap, attrs, rules, p, ce));
            }

            var oe = e as XbnfOrExpression;

            if (null != oe)
            {
                return(_GetDysOr(d, syms, tmap, attrs, rules, p, oe));
            }
            var ope = e as XbnfOptionalExpression;

            if (null != ope)
            {
                return(_GetDysOptional(d, syms, tmap, attrs, rules, p, ope));
            }
            var re = e as XbnfRepeatExpression;

            if (null != re)
            {
                return(_GetDysRepeat(d, syms, tmap, attrs, rules, p, re));
            }
            throw new NotSupportedException("The specified expression type is not supported.");
        }
        static string _ToRegex(XbnfDocument d, XbnfExpression e, bool first, bool gplex = false)
        {
            var le = e as XbnfLiteralExpression;

            if (null != le)
            {
                var s = _EscapeLiteral(XbnfNode.Escape(le.Value), !gplex);
                if (gplex)
                {
                    s = string.Concat("\"", s, "\"");
                }
                return(s);
            }
            var rxe = e as XbnfRegexExpression;

            if (null != rxe)
            {
                var r = rxe.Value;
                if (gplex)
                {
                    r = r.Replace("\"", "\\\"");
                }
                return(first ? r : string.Concat("(", r, ")"));
            }
            var rfe = e as XbnfRefExpression;

            if (null != rfe)
            {
                _ToRegex(d, d.Productions[rfe.Symbol].Expression, first, gplex);
            }
            var re = e as XbnfRepeatExpression;

            if (null != re)
            {
                if (re.IsOptional)
                {
                    return(string.Concat("(", _ToRegex(d, re.Expression, true, gplex), ")*"));
                }
                else
                {
                    return(string.Concat("(", _ToRegex(d, re.Expression, true, gplex), ")+"));
                }
            }
            var oe = e as XbnfOrExpression;

            if (null != oe)
            {
                if (!first)
                {
                    return(string.Concat("(", _ToRegex(d, oe.Left, false, gplex), "|", _ToRegex(d, oe.Right, false, gplex), ")"));
                }
                else
                {
                    return(string.Concat(_ToRegex(d, oe.Left, false, gplex), "|", _ToRegex(d, oe.Right, false, gplex)));
                }
            }
            var oc = e as XbnfConcatExpression;

            if (null != oc)
            {
                return(string.Concat(_ToRegex(d, oc.Left, false, gplex), _ToRegex(d, oc.Right, false, gplex)));
            }
            var ope = e as XbnfOptionalExpression;

            if (null != ope)
            {
                return(string.Concat("(", _ToRegex(d, ope.Expression, true, gplex), ")?"));
            }
            return("");
        }
        static IList <IMessage> _TryToGenInfo(XbnfDocument document, CfgDocument cfg, out XbnfGenerationInfo genInfo)
        {
            genInfo = default(XbnfGenerationInfo);
            var hasErrors = false;
            var result    = new List <IMessage>();
            var syms      = new HashSet <string>();

            // gather the attributes and production names

            for (int ic = document.Productions.Count, i = 0; i < ic; ++i)
            {
                var p = document.Productions[i];
                if (!syms.Add(p.Name))
                {
                    result.Add(new XbnfMessage(ErrorLevel.Error, -1, string.Format("Duplicate production {0} defined.", p.Name), p.Line, p.Column, p.Position, document.FileOrUrl));
                    hasErrors = true;
                }
                if (0 < p.Attributes.Count)
                {
                    CfgAttributeList attrs;
                    if (!cfg.AttributeSets.TryGetValue(p.Name, out attrs))
                    {
                        attrs = new CfgAttributeList();
                        cfg.AttributeSets.Add(p.Name, attrs);
                    }
                    for (int jc = p.Attributes.Count, j = 0; j < jc; ++j)
                    {
                        var attr = p.Attributes[j];
                        attrs.Add(new CfgAttribute(attr.Name, attr.Value));
                    }
                }
            }

            // use a list dictionary to keep these in order
            var tmap     = new ListDictionary <XbnfExpression, string>();
            var attrSets = new Dictionary <string, XbnfAttributeList>();
            var rules    = new List <KeyValuePair <string, IList <string> > >();
            // below are scratch
            var working = new HashSet <XbnfExpression>();
            var done    = new HashSet <XbnfExpression>();

            // now get the terminals and their ids, declaring if necessary


            for (int ic = document.Productions.Count, i = 0; i < ic; ++i)
            {
                var p = document.Productions[i];
                if (p.IsTerminal)
                {
                    string name;
                    if (!tmap.TryGetValue(p.Expression, out name))
                    {
                        tmap.Add(p.Expression, p.Name);
                    }
                    else
                    {
                        if (name != p.Name)
                        {
                            result.Add(new CfgMessage(ErrorLevel.Error, -1, string.Format("{0} attempts to redefine terminal {1}", name, p.Name), p.Line, p.Column, p.Position, document.FileOrUrl));
                            hasErrors = true;
                        }
                    }
                    done.Add(p.Expression);
                }
                else
                {
                    _VisitFetchTerminals(p.Expression, working);
                }
            }

            if (hasErrors)
            {
                return(result);
            }
            foreach (var term in working)
            {
                if (!done.Contains(term))
                {
                    var newId = _GetImplicitTermId(syms);
                    var found = false;
                    var prod  = document.GetProductionForExpression(term);
                    if (null != prod)
                    {
                        found = true;
                        // recycle this symbol
                        newId = prod.Name;
                    }

                    if (!found)
                    {
                        document.Productions.Add(new XbnfProduction(newId, term));
                    }
                    tmap.Add(term, newId);
                }
            }
            // tmap now contains ALL of our terminal definitions from all of our imports
            // now we can use tmap and syms to help solve the rest of our productions

            var ntd = new Dictionary <string, IList <IList <string> > >();

            for (int ic = document.Productions.Count, i = 0; i < ic; ++i)
            {
                var p = document.Productions[i];


                if (!p.IsTerminal)
                {
                    var dys = _GetDysjunctions(document, syms, tmap, attrSets, rules, p, p.Expression);
                    IList <IList <string> > odys;
                    if (ntd.TryGetValue(p.Name, out odys))
                    {
                        result.Add(new XbnfMessage(ErrorLevel.Error, -1, string.Format("The {0} production was specified more than once", p.Name), p.Line, p.Column, p.Position, document.FileOrUrl));
                        hasErrors = true;
                    }

                    ntd.Add(p.Name, dys);
                    if (hasErrors)
                    {
                        return(result);
                    }
                }
            }
            // now that we've done that, build the rest of our attributes
            foreach (var sattrs in attrSets)
            {
                CfgAttributeList attrs;
                if (!cfg.AttributeSets.TryGetValue(sattrs.Key, out attrs))
                {
                    attrs = new CfgAttributeList();
                    cfg.AttributeSets.Add(sattrs.Key, attrs);
                }
                for (int jc = sattrs.Value.Count, j = 0; j < jc; ++j)
                {
                    var attr = sattrs.Value[j];
                    attrs.Add(new CfgAttribute(attr.Name, attr.Value));
                }
            }

            // now write our main rules
            foreach (var nt in ntd)
            {
                foreach (var l in nt.Value)
                {
                    cfg.Rules.Add(new CfgRule(nt.Key, l));
                }
            }
            // build our secondary rules
            foreach (var rule in rules)
            {
                cfg.Rules.Add(new CfgRule(rule.Key, rule.Value));
            }

            if (hasErrors)
            {
                return(result);
            }
            genInfo.Xbnf        = document;
            genInfo.TerminalMap = tmap;
            genInfo.Cfg         = cfg;
            cfg.RebuildCache();
            return(result);
        }
Exemple #12
0
 public XbnfImport(XbnfDocument document)
 {
     Document = document;
 }
Exemple #13
0
        internal static XbnfProduction Parse(LexContext pc)
        {
            var result = new XbnfProduction();

            pc.TrySkipCCommentsAndWhiteSpace();
            var l = pc.Line;
            var c = pc.Column;
            var p = pc.Position;

            // read identifier
            result.Name = ParseIdentifier(pc);
            // read attributes
            if ('<' == pc.Current)
            {
                pc.Advance();
                while (-1 != pc.Current && '>' != pc.Current)
                {
                    result.Attributes.Add(XbnfAttribute.Parse(pc));
                    pc.TrySkipCCommentsAndWhiteSpace();
                    pc.Expecting('>', ',');
                    if (',' == pc.Current)
                    {
                        pc.Advance();
                    }
                }
                pc.Expecting('>');
                pc.Advance();
            }
            pc.TrySkipCCommentsAndWhiteSpace();
            pc.Expecting('=');

            pc.Advance();
            result.Expression = XbnfExpression.Parse(pc);

            pc.Expecting(';', '=');
            result.SetLocation(l, c, p);
            if (';' == pc.Current)
            {
                pc.Advance();
                return(result);
            }
            if ('=' == pc.Current)
            {
                pc.Advance();
                pc.Expecting('>');
                pc.Advance();
                pc.TrySkipCCommentsAndWhiteSpace();
                pc.Expecting('{');
                pc.Advance();
                l = pc.Line;
                c = pc.Column;
                p = pc.Position;
                var s = XbnfDocument.ReadCode(pc);
                pc.Expecting('}');
                pc.Advance();
                result.Action = new XbnfCode(s);
                result.SetLocation(l, c, p);
            }

            return(result);
        }
Exemple #14
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);
        }