public override Paradigma IdentificaParadigma(Dictionary<string, string> dades, Dictionary<string, string> excepcions)
 {
     // PER_FER: Decidir si admetre l'article a tots els topònims amb vocal inicial (ja que es diu "l'Europa d'entreguerres")
     // PER_FER: Si es permeten articles, s'haurien de detectar els femenins (com "Itàlia")
     PC_multi pars = new PC_multi();
     string[] trossos = dades["ent"].Split(' ');
     for (int i = 0; i < trossos.Length; i++)
     {
         string tros = trossos[i];
         if (Cat.EsMin(tros))
             continue;
         if (tros.EndsWith(","))
             tros = tros.Substring(0, tros.Length - 1);
         bool admetD = false, admetL = false;
         Match match;
         if ((match = reArticleApostrofat.Match(tros)).Success)
         {
             admetL = true;
             tros = match.Groups[1].Value;
         }
         else if ((match = reDeApostrofada.Match(tros)).Success)
         {
             admetD = true;
             tros = match.Groups[1].Value;
         }
         else if (Paraula.TeVocalInicial(tros) && i == 0)
         {
             admetD = true;
             admetL = true;  // volem "l'Europa d'entreguerres"
         }
         pars.Add(new PC_toponim(tros, admetD, admetL));
     }
     return pars;
 }
        public override Paradigma IdentificaParadigma(Dictionary<string, string> dades,
            Dictionary<string, string> excepcions)
        {
            if (excepcions != null && excepcions.ContainsKey("PRECALC"))
                return Precalc(excepcions["PRECALC"], dades);
            if (!dades.ContainsKey("ent"))
                throw new Exception("No es troba l'arrel");
            string ent = dades["ent"];
            string arrel = dades["arrel"];
            bool nocat = false;
            bool nom = false, pron = false, adj = false, masc = false, fem = false, sing = false, plural = false;
            bool verb = false;
            bool art = false, conj = false, adv = false, prep = false, interj = false;
            bool loc = false, locadj = false, locadv = false, locprep = false;
            #region Explora les categories
            int idxCat = 1;
            while (true)
            {
                string nomCat = String.Format("cat{0}", idxCat);
                string cat = Dades(dades, nomCat);
                if (cat != null)
                {
                    switch (cat)
                    {
                        case "m.":
                        case "m. ant.":
                        case "m. pop.":
                            nom = true;
                            masc = true;
                            sing = true;
                            plural = true;
                            break;
                        case "f.":
                        case "f. pop.":
                        case "f. obs.":
                            nom = true;
                            fem = true;
                            sing = true;
                            plural = true;
                            break;
                        case "m. pl.":
                            nom = true;
                            masc = true;
                            plural = true;
                            break;
                        case "f. pl.":
                            nom = true;
                            fem = true;
                            plural = true;
                            break;
                        case "pl.":
                            nom = true;
                            plural = true;
                            break;
                        case "m. i f.":
                        case "m. o f.":
                            masc = true;
                            fem = true;
                            nom = true;
                            sing = true;
                            plural = true;
                            break;
                        case "adj. i m.":
                        case "m. i adj.":
                            adj = true;
                            masc = true;
                            nom = true;
                            sing = true;
                            plural = true;
                            break;
                        case "adj. i f.":
                        case "f. i adj.":
                            adj = true;
                            fem = true;
                            nom = true;
                            sing = true;
                            plural = true;
                            break;
                        case "adj. i pron.":
                            adj = true;
                            pron = true;
                            sing = true;
                            plural = true;
                            break;
                        case "adj.":
                            adj = true;
                            sing = true;
                            plural = true;
                            break;
                        case "adj. i m. i f.":
                        case "adj. i m. i f. pop.":
                            adj = true;
                            nom = true;
                            masc = true;
                            fem = true;
                            sing = true;
                            plural = true;
                            break;
                        case "prep.":
                            prep = true;
                            break;
                        case "loc. prep.":
                            locprep = true;
                            loc = true;
                            break;
                        case "loc. adj.":
                            locadj = true;
                            loc = true;
                            break;
                        case "art.":
                            art = true;
                            break;
                        case "adv.":
                            adv = true;
                            break;
                        case "loc. adv.":
                            locadv = true;
                            loc = true;
                            break;
                        case "loc. adj. i loc. adv.":
                            locadj = true;
                            locadv = true;
                            loc = true;
                            break;
                        case "interj.":
                            interj = true;
                            break;
                        case "conj.":
                            conj = true;
                            break;
                        case "pron.":
                            if (!verb)
                                pron = true;
                            break;
                        case "v.":
                        case "v. pron.":
                        case "v. tr.":
                        case "v. tr. ant.":
                        case "v. intr.":
                        case "intr.":
                        case "tr.":
                        case "tr. pron.":
                        case "v. intr. i pron.":
                        case "v. tr. i pron.":
                        case "v. tr. i intr.":
                        case "v. intr. i tr.":
                        case "v. intr. pron.":
                        case "v. tr. i intr. pron.":
                            verb = true;
                            break;
                        case "???":
                            nocat = true;
                            break;
                        case "sing.":
                            nom = true;
                            sing = true;
                            break;
                        case "m. sing.":
                            masc = true;
                            nom = true;
                            sing = true;
                            break;
                        case "f. sing.":
                            fem = true;
                            nom = true;
                            sing = true;
                            break;
                        default:
                            throw new Exception(String.Format("No sé què fer amb {0} (\"{1}\")", dades[nomCat], dades["arrel"]));
                    }
                    idxCat += 1;
                }
                else
                    break;
            }

            #endregion
            List<ParadigmaCat> pars = new List<ParadigmaCat>();
            if (nocat)
                pars.Add(paradigmes["???"]);
            if (verb)
                pars.Add(IdVerb(arrel, dades, excepcions));
            if (loc && !(nom || adj))
            {
                if (locprep)
                    pars.Add(paradigmes["LOC PREP"]);
                if (locadj)
                    pars.Add(paradigmes["LOC ADJ"]);
                if (locadv)
                    pars.Add(paradigmes["LOC ADV"]);
            }
            else
            {
                // Si hi ha adjectius, tenim ja totes les formes generades
                if (adj)
                    pars.Add(Id4(arrel, ADJ, dades, excepcions));
                //else if ((masc && fem) || plural)
                else if (masc && fem)
                    pars.Add(Id4(arrel, N, dades, excepcions));
                else {
                    // PER_FER: generar les altres categories encara que hi hagi adjectius o m. i f.
                    if (nom)
                    {
                        if (plural && !sing)
                            pars.Add(paradigmes[fem ? "NPF" : "NPM"]);
                        else if (!plural && sing)
                            pars.Add(paradigmes[fem ? "NSF" : "NSM"]);
                        else if (masc)
                            pars.Add(Id2(arrel, NM, dades, excepcions));
                        else if (fem)
                            pars.Add(Id2(arrel, NF, dades, excepcions));
                        else
                            pars.Add(Id2(arrel, N, dades, excepcions));
                    }
                    if (pron)
                    {
                        // PER_FER: Hi pot haver pronoms que no admetin "de"
                        if (Paraula.TeVocalInicial(arrel))
                            pars.Add(paradigmes["PRON, D+"]);
                        else
                            pars.Add(paradigmes["PRON, D-"]);
                    }
                    if (prep)
                        pars.Add(paradigmes["PREP"]);
                    if (conj)
                        pars.Add(paradigmes["CONJ"]);
                    if (adv)
                    {
                        if (arrel.EndsWith("ment") || !Paraula.TeVocalInicial(arrel))
                            pars.Add(paradigmes["ADV, D-"]);
                        else
                            pars.Add(paradigmes["ADV, D+"]);
                    }
                    if (interj)
                        pars.Add(paradigmes["INTERJ"]);
                    if (art)
                        pars.Add(paradigmes["ART"]);
                }
            }
            if (pars.Count == 0) throw new Exception(String.Format(@"Sense paradigma per a ""{0}""", ent));
            if (pars.Count == 1)
                return pars[0];
            else
            {
                PC_multi multi = new PC_multi();
                foreach (ParadigmaCat par in pars)
                    multi.Add(par);
                return multi;
            }
        }
 /// <summary>
 /// Calcula el paradigma per a adjectius i masculins/femenins.
 /// El resultat pot tenir dues terminacions (abacial), tres (feliç) o quatre (blanc).
 /// </summary>
 private ParadigmaCat Id4(string arrel, MorfoGram morfoGram, Dictionary<string, string> dades, Dictionary<string, string> exc)
 {
     bool admetArticle = (exc == null || !exc.ContainsKey("NOART"));
     string fem;
     string masc = ParadigmaCat.Arrel0(arrel, out fem);
     if (exc != null && exc.ContainsKey("PLU") && exc["PLU"].Contains(" "))
     {
         string[] trossos = exc["PLU"].Split(' ');
         if (trossos.Length != 2) throw new Exception("S'esperaven dos trossos: " + exc["PLU"]);
         Dictionary<string, string> exc2 = new Dictionary<string, string>(exc);
         exc2["PLU"] = trossos[0];
         ParadigmaCat parMasc = Id2(masc, morfoGram | mgMasc, dades, exc2);
         exc2["PLU"] = trossos[1];
         ParadigmaCat parFem = Id2(fem, morfoGram | mgFem, dades, exc2);
         return new PC_multi(parMasc, parFem);
     }
     if (fem == masc)
     {
         // Si hi ha una forma, vol dir que és igual per al masculí i el femení, almenys en singular
         ParadigmaCat par = Id2(arrel, morfoGram, dades, exc);
         if (arrel.EndsWith("ç"))
         {
             // Si termina en 'ç', hi ha dues formes per al plural
             PC_multi pars = new PC_multi(par);
             Paraula fpl = new Paraula(arrel.Substring(0, arrel.Length - 1) + "ces");
             pars.Add(new PC_formaFixada("plural en -ces", new MorfoGram(morfoGram.Cat, MorfoGram.eGen.F, MorfoGram.eNbre.PL),
                 fpl, fpl.VocalInicial, false));
             return pars;
         }
         else
             return par;
     }
     else // (fem != null)
     {
         Paraula pMasc = new Paraula(masc);
         foreach (char id in "FJBHKL")
         {
             if (id == 'H' && (!pMasc.Aguda || !pMasc.VocalFinal))
                 continue;
             Regla regla = regles.Llista[id.ToString()];
             List<Mot> femenins = regla.Genera(masc, mgFemSg, regles, Marques.totes, true);
             if (femenins.Count == 0)
                 continue;
             if (femenins.Exists(delegate(Mot mot) { return mot.Forma == fem; }))
             {
                 string idPar = String.Format("{0}, MFSP, {1}, D{2}, L{3}",
                     morfoGram.Cat == MorfoGram.eCat.ADJ ? "A" : "N",
                     id.ToString(),
                     pMasc.VocalInicial ? "+" : "-",
                     pMasc.VocalInicial && admetArticle ? "+" : "-");
                 ParadigmaCat par = paradigmes[idPar];
                 Paraula pFem = new Paraula(fem);
                 if (pFem.PotApostrofar(true)&& admetArticle)
                 {
                     MorfoGram mgFS = new MorfoGram(mgFemSg);
                     mgFS.Cat = morfoGram.Cat;
                     par = new PC_multi(par, new PC_formaFixada("femení singular, D+, L+", mgFS, pFem, true, true));
                     // PERFER: No hauríem d'admetre "d'" ja que està inclòs dins l'altre paradigma
                 }
                 return par;
             }
         }
         return new PC_multi(Id2(masc, mgMascSg, dades, exc), Id2(fem, mgFemSg, dades, exc));
     }
 }
 private Paradigma Precalc(string precalc, Dictionary<string, string> dades)
 {
     string[] trossos = precalc.Split(' ');
     PC_multi pars = new PC_multi();
     foreach (string tros in trossos)
     {
         if (tros.Contains("/"))
         {
             string[] parts = tros.Split('/');
             if (parts.Length != 2) throw new Exception("Error de format: " + tros);
             string forma = parts[0];
             string[] flags = new string[parts[1].Length];
             for (int i = 0; i < parts[1].Length; i++)
                 flags[i] = parts[1][i].ToString();
             pars.Add(new PC_precalc(forma, null, flags));
         }
         else
             pars.Add(new PC_formaFixada("tros precalculat", NO_MG, new Paraula(tros), false, false));
     }
     return pars;
 }
 /// <summary>
 /// Calcula el paradigma per a paraules amb singular i plural.
 /// </summary>
 private ParadigmaCat Id2(string arrel, MorfoGram morfoGram, Dictionary<string, string> dades, 
     Dictionary<string, string> exc)
 {
     // PERFER: mirar "dijous"
     bool admetArticle = (exc == null || !exc.ContainsKey("NOART"));
     string arrel0, arrel1;
     arrel0 = ParadigmaCat.Arrel0(arrel, out arrel1);
     if (arrel1 != arrel0)
     {
         // PER_FER: unificar amb Precalc()
         // Tenim una paraula amb trossos
         PC_multi par = new PC_multi();
         string[] trossos = arrel.Split(' ');
         for (int i = 0; i < trossos.Length; i++)
         {
             if (trossos.Length == 0)
                 continue;
             // PER_FER: la paraula pot tenir articles i preposicions
             Paraula ptros = new Paraula(trossos[i]);
             if (i == 0)
                 par.Add(new PC_formaFixada("Entrada amb espais, primer tros", morfoGram, ptros,
                     ptros.PotApostrofar(), ptros.PotApostrofar(morfoGram.Gen == MorfoGram.eGen.F)));
             else
                 par.Add(new PC_formaFixada("Entrada amb espais, tros interior", morfoGram, ptros, false, false));
         }
         return par;
     }
     Paraula paraula = new Paraula(arrel0);
     Debug.Assert(!paraula.Forma.Contains(" "), "No hi ha d'haver espais a l'arrel");
     if (exc != null)
     {
         // suposam que el singular i el plural tenen el mateix valor de VocalInicial
         string plural = Dades(exc, "PLU");
         if (plural != null)
         {
             if (plural.Contains(" "))
             {
                 // Hi ha més d'un plural
                 string[] trossos = plural.Split(' ');
                 PC_multi par = new PC_multi();
                 foreach (string tros in trossos)
                     par.Add(new PC_plural_precalc(morfoGram, paraula, tros, paraula.VocalInicial,
                         paraula.VocalInicial && admetArticle));
                 return par;
             }
             return new PC_plural_precalc(morfoGram, paraula,
                 plural, paraula.VocalInicial, paraula.VocalInicial && admetArticle);
         }
     }
     string admet = String.Format("D{0}, L{1}", paraula.VocalInicial ? "+" : "-",
         paraula.VocalInicial && admetArticle ? "+" : "-");
     if (morfoGram.Cat == MorfoGram.eCat.ADJ)
     {
         string id = null;
         if (paraula.VocalFinal && paraula.Aguda)
             id = "A2T, -ns, " + admet;
         else if (paraula.SxcFinal && paraula.Aguda)
             id = "A2T, -os, " + admet;
         else
             id = "A2T, -s, " + admet;
         return paradigmes[id];
     }
     else // (no és un adjectiu, ho tractam com un nom)
     {
         string id = null;
         if (morfoGram.Gen == MorfoGram.eGen.F)
         {
             // exemples: mà, casa
             if (paraula.VocalFinal && paraula.Aguda)
                 id = "NF, -ns, " + admet;
             else if (paraula.SxcFinal && paraula.Aguda)
                 id = "NF, -s, " + admet;
             // PERFER: comprovar que el plural de "falç" és "falçs"
             else
                 id = "NF, -s, " + admet;
         }
         else // (la paraula és masculina o no té gènere)
         {
             // exemples: ca, moix, peu
             if (paraula.VocalFinal && paraula.Aguda)
                 id = "NM, -ns, " + admet;
             else if (paraula.SxcFinal && paraula.Aguda)
                 id = "NM, -os, " + admet;
             else
                 id = "NM, -s, " + admet;
         }
         return paradigmes[id];
     }
     //throw new Exception("No sé què fer amb " + arrel);
 }