Index: gc_core/py/lang_core/gc_engine.py
==================================================================
--- gc_core/py/lang_core/gc_engine.py
+++ gc_core/py/lang_core/gc_engine.py
@@ -395,59 +395,46 @@
         echo("DA: " + str(dTokenPos[tWord[0]]["lMorph"]))
     echo("FSA: " + str(lMorph))
     return True
 
 
-def morph (dTokenPos, tWord, sPattern, bStrict=True, bNoWord=False):
-    "analyse a tuple (position, word), return True if sPattern in morphologies (disambiguation on)"
-    if not tWord:
-        return bNoWord
-    lMorph = dTokenPos[tWord[0]]["lMorph"]  if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]]  else _oSpellChecker.getMorph(tWord[1])
-    if not lMorph:
-        return False
-    zPattern = re.compile(sPattern)
-    if bStrict:
-        return bool(lMorph) and all(zPattern.search(s)  for s in lMorph)
-    return any(zPattern.search(s)  for s in lMorph)
-
-
-def morphex (dTokenPos, tWord, sPattern, sNegPattern, bNoWord=False):
+def morph (dTokenPos, tWord, sPattern, sNegPattern="", bNoWord=False):
     "analyse a tuple (position, word), returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)"
     if not tWord:
         return bNoWord
     lMorph = dTokenPos[tWord[0]]["lMorph"]  if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]]  else _oSpellChecker.getMorph(tWord[1])
     if not lMorph:
         return False
     # check negative condition
-    zNegPattern = re.compile(sNegPattern)
-    if any(zNegPattern.search(s)  for s in lMorph):
-        return False
+    if sNegPattern:
+        if sNegPattern == "*":
+            # all morph must match sPattern
+            zPattern = re.compile(sPattern)
+            return all(zPattern.search(sMorph)  for sMorph in lMorph)
+        else:
+            zNegPattern = re.compile(sNegPattern)
+            if any(zNegPattern.search(s)  for s in lMorph):
+                return False
     # search sPattern
     zPattern = re.compile(sPattern)
     return any(zPattern.search(s)  for s in lMorph)
 
 
-def analyse (sWord, sPattern, bStrict=True):
-    "analyse a word, return True if sPattern in morphologies (disambiguation off)"
-    lMorph = _oSpellChecker.getMorph(sWord)
-    if not lMorph:
-        return False
-    zPattern = re.compile(sPattern)
-    if bStrict:
-        return bool(lMorph) and all(zPattern.search(s)  for s in lMorph)
-    return any(zPattern.search(s)  for s in lMorph)
-
-
-def analysex (sWord, sPattern, sNegPattern):
+def analyse (sWord, sPattern, sNegPattern=""):
     "analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)"
     lMorph = _oSpellChecker.getMorph(sWord)
     if not lMorph:
         return False
     # check negative condition
-    zNegPattern = re.compile(sNegPattern)
-    if any(zNegPattern.search(s)  for s in lMorph):
-        return False
+    if sNegPattern:
+        if sNegPattern == "*":
+            zPattern = re.compile(sPattern)
+            return all(zPattern.search(sMorph)  for sMorph in lMorph)
+        else:
+            zNegPattern = re.compile(sNegPattern)
+            if any(zNegPattern.search(s)  for s in lMorph):
+                return False
     # search sPattern
     zPattern = re.compile(sPattern)
     return any(zPattern.search(s)  for s in lMorph)
 
 
@@ -1053,12 +1040,10 @@
         return False
     # check negative condition
     if sNegPattern:
         if sNegPattern == "*":
             # all morph must match sPattern
-            if not lMorph:
-                return False
             zPattern = re.compile(sPattern)
             return all(zPattern.search(sMorph)  for sMorph in lMorph)
         else:
             zNegPattern = re.compile(sNegPattern)
             if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
@@ -1080,12 +1065,10 @@
         return False
     # check negative condition
     if sNegPattern:
         if sNegPattern == "*":
             # all morph must match sPattern
-            if not lMorph:
-                return False
             zPattern = re.compile(sPattern)
             return all(zPattern.search(sMorph)  for sMorph in lMorph)
         else:
             zNegPattern = re.compile(sNegPattern)
             if any(zNegPattern.search(sMorph)  for sMorph in lMorph):
@@ -1102,12 +1085,10 @@
         return False
     # check negative condition
     if sNegPattern:
         if sNegPattern == "*":
             # all morph must match sPattern
-            if not lMorph:
-                return False
             zPattern = re.compile(sPattern)
             bResult = all(zPattern.search(sMorph)  for sMorph in lMorph)
             if bResult and bSetMorph:
                 dToken1["lMorph"] = lMorph
             return bResult

Index: gc_lang/fr/rules.grx
==================================================================
--- gc_lang/fr/rules.grx
+++ gc_lang/fr/rules.grx
@@ -450,14 +450,14 @@
     M(?:r|gr|me|[.]) [A-ZÉ]([.])(?=\W+[a-zéèêâîïû]) @@$ <<- ~1>> *
 
 # Patronyme réduit à une seule lettre
 __[s](p_prénom_lettre_point_patronyme)__
     ([A-ZÉÈÂÎ][\w-]+)[  ]([A-ZÉÈÂ][.][  ]([A-ZÉÈÂ][\w-]+)) @@0,$,$
-    <<- morph(\1, ":M[12]", False) and (morph(\3, ":(?:M[12]|V)", False) or not spell(\3)) ~2>> *
+    <<- morph(\1, ":M[12]") and (morph(\3, ":(?:M[12]|V)") or not spell(\3)) ~2>> *
 __[s>(p_prénom_lettre_point)__
     ([A-ZÉÈÂÎ][\w-]+)[  ]([A-ZÉÈÂ][.]) @@0,$
-    <<- morph(\1, ":M[12]", False) and after("^\W+[a-zéèêîïâ]") ~2>> *
+    <<- morph(\1, ":M[12]") and after("^\W+[a-zéèêîïâ]") ~2>> *
 
 # Patronymes composés avec Le/La/Les
 __[s](p_patronyme_composé_avec_le_la_les)__
     [A-ZÉÈÂÎ][\w-]+[-–—]L(?:es?|a) [A-ZÉÈÂÎ][\w-]+ <<- ~>> =\0.replace(" ", "_")
 
@@ -484,11 +484,11 @@
 __[s](p_points_suspension_entre_crochets)__
     \[…\] <<- ~>> *
 __[s](p_mot_entre_crochets)__
     \[({w_1})\] @@1
     <<- \1.isdigit() ~>> *
-    <<- __else__ and morph(\1, ":G", False) ~>> =" " + \1 + " "
+    <<- __else__ and morph(\1, ":G") ~>> =" " + \1 + " "
     <<- __else__ and \1.isalpha() ~>> " _"
 __[s](points_suspension_entre_parenthèses)__
     \(…\)
     <<- ->> […]                 # Pour indiquer une troncature de texte, on utilise usuellement des crochets.
     <<- ~>> *
@@ -663,11 +663,11 @@
 
 # Majuscules après un point
 __[s]/maj(majuscule_après_point)__
     ({w_2})[.] ([a-zéàèîçô]\w*)  @@0,$
     <<- not re.search("(?i)^(?:etc|[A-Z]|chap|cf|fig|hab|litt|circ|coll|r[eé]f|étym|suppl|bibl|bibliogr|cit|op|vol|déc|nov|oct|janv|juil|avr|sept)$", \1)
-        and morph(\1, ":", False) and morph(\2, ":", False)
+        and morph(\1, ":") and morph(\2, ":")
     -2>> =\2.capitalize()                                                                           # Après un point, une majuscule est généralement requise.
 
 TEST: Je suis là. {{viens}}.                                              ->> Viens
 TEST: Ils sont devenus idiots. {{c}}’est peine perdue.
 
@@ -686,19 +686,19 @@
 
 # virgules manquantes
 __[i>/virg(virgule_manquante_avant_etc)__   {w_1}( etc[.])  @@$ <<- -1>> , etc.                     # Avant « etc. », il faut mettre une virgule.
 __[i>/virg(virgule_manquante_avant_car)__
     ({w_1})( car)(?= (?:j[e’]|tu|ils?|nous|vous|elles?|on|les?|l[a’]|ces?|des?|cette|[mts](?:on|a|es))\b)  @@0,$
-    <<- not morph(\1, ":[DR]", False) -2>> , car
+    <<- not morph(\1, ":[DR]") -2>> , car
     # Si « car » est la conjonction de coordination, une virgule est peut-être souhaitable.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3447
 __[i>/virg(virgule_manquante_avant_mais)__
     ({w_1})( mais)(?= (?:j[e’]|tu|ils?|nous|vous|elles?|on)\b)  @@0,$
-    <<- not morph(\1, ">(?:[mtscl]es|[nv]os|quels)/", False) -2>> , mais
+    <<- not morph(\1, ">(?:[mtscl]es|[nv]os|quels)/") -2>> , mais
     # Si « mais » est la conjonction de coordination, une virgule est souhaitable si elle introduit une nouvelle proposition.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3445
 __[i>/virg(virgule_manquante_avant_donc)__
     ({w_1})( donc)(?= (?:j[e’]|tu|ils?|elles?|on)\b)  @@0,$
-    <<- not morph(\1, ":V", False) -2>> , donc
+    <<- not morph(\1, ":V") -2>> , donc
     # Si « donc » est la conjonction de coordination, une virgule est souhaitable si elle introduit une nouvelle proposition.|http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3448
 
 TEST: Un chien, un chat{{ etc.}}                                            ->> , etc.
 TEST: Je suis fatigué{{ car}} ils ont joué toute la nuit.                   ->> , car
 TEST: Je suis fatigué{{ mais}} il a joué toute la nuit.                     ->> , mais
@@ -940,11 +940,11 @@
 # Solution prudente :
 __[i>/typo(typo_apostrophe_manquante_prudence1)!8__
     ne ([mtsl] )([aeéiouhyîèêôû][\w-]*)  @@3,$  <<- -1>> =\1[:-1]+"’"                               # Il manque une apostrophe.
 __[i>/typo(typo_apostrophe_manquante_prudence2)!8__
     (?:je|tu|ils?|nous|vous|on|ça|elles?) ([nmtsl] )([aeéiouhyîèêôû][\w-]*)  @@*,$
-    <<- not option("mapos") and morph(\2, ":V", False) -1>> =\1[:-1]+"’"                            # Il manque probablement une apostrophe.
+    <<- not option("mapos") and morph(\2, ":V") -1>> =\1[:-1]+"’"                                   # Il manque probablement une apostrophe.
 # Solution audacieuse :
 __[s>/typo(typo_apostrophe_manquante_audace1)!8__
     ([ldsncjmtç] )[aeéiouhAEÉIOUHyîèêôûYÎÈÊÔÛ]  @@0
     <<- option("mapos") and not before("(?i)(?:lettre|caractère|glyphe|dimension|variable|fonction|point) *$")
     -1>> =\1[:-1]+"’"                                                                               # Il manque peut-être une apostrophe.
@@ -1093,16 +1093,16 @@
     ((\d+(?:,\d+[⁰¹²³⁴⁵⁶⁷⁸⁹]?|[⁰¹²³⁴⁵⁶⁷⁸⁹]|)) ?)(?:[kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰€$£¥Åℓhj]|min|°C|℃)(?![’'])  @@0,0
     <<- -1>> "\2 "
     # Avec une unité de mesure, mettez un espace insécable.
 __[s]/unit(unit_nbsp_avant_unités2)__
     ((\d+(?:,\d+[⁰¹²³⁴⁵⁶⁷⁸⁹]?|[⁰¹²³⁴⁵⁶⁷⁸⁹])) ?)([a-zA-Zµ][a-zA-Z0-9Ωℓ⁰¹²³⁴⁵⁶⁷⁸⁹/·]*)  @@0,0,$
-    <<- morphex(\3, ";S", ":[VCR]") or mbUnit(\3) or not spell(\3)
+    <<- morph(\3, ";S", ":[VCR]") or mbUnit(\3) or not spell(\3)
     -1>> "\2 "
     # Si “\3” est une unité de mesure, il manque un espace insécable. Si le nombre se rapporte au mot suivant, c’est aussi valable.
 __[s]/unit(unit_nbsp_avant_unités3)__
     ((\d+) )([a-zA-Zµ][a-zA-Z0-9Ωℓ⁰¹²³⁴⁵⁶⁷⁸⁹/·]*)(?![’'])  @@0,0,$
-    <<- (\2.__len__() > 4 and not spell(\3)) or morphex(\3, ";S", ":[VCR]") or mbUnit(\3)
+    <<- (\2.__len__() > 4 and not spell(\3)) or morph(\3, ";S", ":[VCR]") or mbUnit(\3)
     -1>> "\2 "
     # Si “\3” est une unité de mesure, il manque un espace insécable. Si le nombre se rapporte au mot suivant, c’est aussi valable.
 
 TEST: Ça a duré {{3}}µs
 TEST: Ça a duré {{3,5 }}µs
@@ -1136,11 +1136,11 @@
         or after(r"^[   ]*(?:[kcmµn]?(?:[slgJKΩ]|m[²³]?|Wh?|Hz|dB)|[%‰€$£¥Åℓhj]|min|°C|℃)(?![\w’'])")
     ->> =formatNumber(\0)                                                                           # Formatage des grands nombres.
 
 __[s]/num(num_nombre_quatre_chiffres)__
     (?<!,)(\d\d\d\d)[  ]([a-zA-Zµ][a-zA-Z0-9Ωℓ⁰¹²³⁴⁵⁶⁷⁸⁹/·]*) @@0,$
-    <<- morphex(\2, ";S", ":[VCR]") or mbUnit(\2) -1>> =formatNumber(\1)                            # Formatage des grands nombres
+    <<- morph(\2, ";S", ":[VCR]") or mbUnit(\2) -1>> =formatNumber(\1)                              # Formatage des grands nombres
 
 TEST: {{12345}}                                 ->> 12 345
 TEST: {{123456}}                                ->> 123 456
 TEST: {{1234567}}                               ->> 1 234 567
 TEST: {{12345678}}                              ->> 12 345 678
@@ -1192,11 +1192,11 @@
 !!!! Redondances                                                                                  !!
 !!
 !!
 __[i]/redon1(redondances_paragraphe)__
     ({w_4})[  ,.;!?:].*[  ](\1)  @@0,$
-    <<- not morph(\1, ":(?:G|V0)|>(?:t(?:antôt|emps|rès)|loin|souvent|parfois|quelquefois|côte|petit|même)/", False) and not \1[0].isupper()
+    <<- not morph(\1, ":(?:G|V0)|>(?:t(?:antôt|emps|rès)|loin|souvent|parfois|quelquefois|côte|petit|même)/") and not \1[0].isupper()
     -2>> _                                                      # Dans ce paragraphe, répétition de « \1 » (à gauche).
     <<- __also__ -1>> _                                         # Dans ce paragraphe, répétition de « \1 » (à droite).
 
 TEST: __redon1__ Tu es son {{avenir}}. Et lui aussi est ton {{avenir}}.
 TEST: __redon1__ Car parfois il y en a. Mais parfois il n’y en a pas.
@@ -1222,11 +1222,11 @@
 __<s]/ocr(ocr_exclamation1)__
     [  ]I(?![ ’'][aâeéèêëiîïoôuy])
     <<- ->> " !"                                                                                    # Erreur de numérisation ?
 __<s]/ocr(ocr_exclamation2)__
     [  ]1(?= [A-ZÉÈÂÎ])
-    <<- not morph(word(1), ";S", False) and not morph(word(-1), ":R", False) ->> " !"               # Erreur de numérisation ?
+    <<- not morph(word(1), ";S") and not morph(word(-1), ":R") ->> " !"                             # Erreur de numérisation ?
 
 TEST: __ocr__ Oh{{ I}} c’est pas formidable ?
 TEST: __ocr__ Vraiment{{ 1}} Paul n’en savait rien.
 TEST: __ocr__ Ça prendra 1 h.
 TEST: __ocr__ Valeur : 1 KHz.
@@ -1253,12 +1253,12 @@
 
 ## Casse
 __[s]/ocr(ocr_casse1)__
     [A-ZÉÈÂÊÎÔ]{w_1}
     <<- \0.istitle() and before(r"(?i)\w") >>>
-    <<- morphex(\0, ":G", ":M") ->> =\0.lower()                                                     # Erreur de numérisation ? Casse improbable.
-    <<- __else__ and morphex(\0, ":[123][sp]", ":[MNA]|>Est/") ->> =\0.lower()                      # Erreur de numérisation ? Casse improbable.
+    <<- morph(\0, ":G", ":M") ->> =\0.lower()                                                       # Erreur de numérisation ? Casse improbable.
+    <<- __else__ and morph(\0, ":[123][sp]", ":[MNA]|>Est/") ->> =\0.lower()                        # Erreur de numérisation ? Casse improbable.
 
 TEST: __ocr__ votre ami la regarde, {{Vous}} ne l’avez pas achetée
 TEST: __ocr__ pour accommoder son regard, {{La}} lourde forme demeure
 TEST: __ocr__ parler de Nicole, {{Le}} sommeil ne vient pas.
 TEST: __ocr__ a fait de toi, Charles, {{Tu}} étais beau quand
@@ -1426,11 +1426,11 @@
 
 
 ### Traits d’union douteux
 __[i]/tu(tu_trait_union_douteux)__
     ({w1})(?:--|—|–)({w1})  @@0,$
-    <<- spell(\1+"-"+\2) and analyse(\1+"-"+\2, ":", False) ->> \1-\2                               # Trait d’union : un tiret simple suffit.
+    <<- spell(\1+"-"+\2) and analyse(\1+"-"+\2, ":") ->> \1-\2                                      # Trait d’union : un tiret simple suffit.
 
 TEST: Nous préparons une {{contre–attaque}}.
 
 
 !!!! Nombres: typographie                                                                         !!
@@ -1446,15 +1446,15 @@
 
 !!!! Écritures épicènes invariables                                                               !!
 
 __[i](d_typo_écriture_épicène_pluriel)__
     ({w_1}[éuitsrn])_(?:[nt]|)e_s  @@0
-    <<- morphex(\1, ":[NAQ]", ":G") =>> define(\1, [":N:A:Q:e:p"])
+    <<- morph(\1, ":[NAQ]", ":G") =>> define(\1, [":N:A:Q:e:p"])
 
 __[i](d_typo_écriture_épicène_singulier)__
     ({w_2}[éuitsrn])_e  @@0
-    <<- morph(\1, ":[NAQ]", False) =>> define(\1, [":N:A:Q:e:s"])
+    <<- morph(\1, ":[NAQ]") =>> define(\1, [":N:A:Q:e:s"])
 
 
 !!!
 !!!
 !!! Processeur: épuration des signes inutiles et quelques simplifications                         !!
@@ -1473,15 +1473,15 @@
 # le, la ou les chose(s)
 __[i>(p_le_ou_les)__            l[ea] ou les {w_2}([(]s[)]) @@$ <<- ~1>> s
 __[i](p_le_ou_la)__             l(e ou la|a ou le) {w_2} @@1 <<- ~1>> ’
 
 # les références aux notes
-__[i](p_références_aux_notes)__ [a-zéèâàôîù][a-zéèâàôîù-]+(\d+) @@$ <<- not morph(\0, ":", False) ~1>> *
+__[i](p_références_aux_notes)__ [a-zéèâàôîù][a-zéèâàôîù-]+(\d+) @@$ <<- not morph(\0, ":") ~1>> *
 
 # faux positifs avec adverbes de négation
-__[i](p_pas_mal)__              pas mal <<- not morph(word(-1), ":D", False) ~>> *
-__[i](p_pas_assez)__            pas assez ({w_2}) @@$ <<- morph(\1, ":A", False) and not morph(word(-1), ":D", False) ~>> *
+__[i](p_pas_mal)__              pas mal <<- not morph(word(-1), ":D") ~>> *
+__[i](p_pas_assez)__            pas assez ({w_2}) @@$ <<- morph(\1, ":A") and not morph(word(-1), ":D") ~>> *
 
 # faux positifs avec «à chez»
 __[i](p_de_chez_à_chez_pronom)__    de chez \w+ (?:à|jusqu à) chez (?:moi|toi|lui|elles?|eux|nous|vous) <<- ~>> *
 __[i](p_de_chez)__                  (jusqu à|de) chez @@0 <<- ~1>> *
 
@@ -10245,11 +10245,11 @@
 
 !!!! Redondances dans la phrase                                                                   !!
 
 __[i]/redon2(redondances_phrase)__
     ({w_4})[ ,].* (\1)  @@0,$
-        <<- not morph(\1, ":(?:G|V0)|>même/", False) -2>> _             # Dans cette phrase, répétition de « \1 » (à gauche).
+        <<- not morph(\1, ":(?:G|V0)|>même/") -2>> _                    # Dans cette phrase, répétition de « \1 » (à gauche).
         <<- __also__ -1>> _                                             # Dans cette phrase, répétition de « \1 » (à droite).
 
 TEST: __redon2__ Quelle {{imposture}}, c’est d’un ennui, c’est une {{imposture}}.
 TEST: __redon2__ ils sont là côte à côte.
 TEST: __redon2__ Tu avances petit à petit, et tu réussis.
@@ -10260,15 +10260,15 @@
 !!!! Mots composés                                                                                !!
 
 __[i]/mc(mc_mot_composé)__
     ({w2})-({w2})  @@0,$
         <<- not \1.isdigit() and not \2.isdigit()
-            and not morph(\0, ":", False) and not morph(\2, ":G", False) and spell(\1+\2)
+            and not morph(\0, ":") and not morph(\2, ":G") and spell(\1+\2)
         ->> \1\2                                                                                    # Vous pouvez ôter le trait d’union.
         <<- \2 != "là" and not re.search("(?i)^(?:ex|mi|quasi|semi|non|demi|pro|anti|multi|pseudo|proto|extra)$", \1)
-            and not \1.isdigit() and not \2.isdigit() and not morph(\2, ":G", False)
-            and not morph(\0, ":", False) and not spell(\1+\2)
+            and not \1.isdigit() and not \2.isdigit() and not morph(\2, ":G")
+            and not morph(\0, ":") and not spell(\1+\2)
         ->> _                                                                                       # Mot inconnu du dictionnaire.|http://www.dicollecte.org/dictionary.php?prj=fr&unknownword=on
 
 TEST: __mc__ des {{portes-avions}}.
 
 
@@ -13704,11 +13704,11 @@
 TEST: fait pourtant avéré et corroboré par le même sondage.
 TEST: ce fait rapporté par des témoins au-delà de tout soupçon n’est pas contestable.
 
 #__[i]/infi(infi_faire)__
 #    (f(?:ai|[iî]|er|on)\w+) +({w_2}(?:ée?s?|ez))  @@0,$
-#    <<- morph(\1, ">faire/", False) and not before(r"(?i)\b(?:en|[mtsldc]es?|[nv]ous|un) +$") and morphex(\2, ":V", ":M")
+#    <<- morph(\1, ">faire/") and not before(r"(?i)\b(?:en|[mtsldc]es?|[nv]ous|un) +$") and morph(\2, ":V", ":M")
 #        and not (re.search("(?i)^fait$", \1) and \2.endswith("é"))
 #        and not (re.search("(?i)^faits$", \1) and \2.endswith("és"))
 #    -2>> =suggVerbInfi(@)                                                                           # Le verbe devrait être à l’infinitif.