kernel/CalcMatR.js

/*
 * Created by yvesb on 12/12/2016.
 */
/*
 * MathGraph32 Javascript : Software for animating online dynamic mathematics figures
 * https://www.mathgraph32.org/
 * @version 5.1.2
 * @Author Yves Biton (yves.biton@sesamath.net)
 * @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
 */

import CCbGlob from './CCbGlob'
import Pointeur from '../types/Pointeur'
import Ope from '../types/Ope'
import Opef4v from '../types/Opef4v'
import Opef5v from '../types/Opef5v'
import Fonte from '../types/Fonte'
import CAppelFonction from '../objets/CAppelFonction'
import CAppelFonctionNVar from '../objets/CAppelFonctionNVar'
import CTermMat from '../objets/CTermMat'
import CConstante from '../objets/CConstante'
import CFonction from '../objets/CFonction'
import CFonction2Var from '../objets/CFonction2Var'
import CFonction3Var from '../objets/CFonction3Var'
import CIntegraleDansFormule from '../objets/CIntegraleDansFormule'
import CPrimitive from '../objets/CPrimitive'
import CMoinsUnaire from '../objets/CMoinsUnaire'
import CVariableFormelle from '../objets/CVariableFormelle'
import CResultatValeur from '../objets/CResultatValeur'
import COp from '../objets/COperation'
import CPuissance from '../objets/CPuissance'
import CCbNull from '../objets/CCbNull'
import CSommeMatDansForm from 'src/objets/CSommeMatDansForm'
import CProduitMatDansForm from 'src/objets/CProduitMatDansForm'

/**
 * Fonction statique récursive créant un arbre binaire de calcul à partir de la chaîne
 * de caractères ch représentant le calcul, la chaîne étant interprétée de pdebut à pfin.
 * nomsVariablesFormelles est un array dont les éléments représentent les noms éventuels des variables
 * formelles quand le calcul évalué représente une fonction.
 * Le calcul renvoie un résultat réel.
 * Fonction appelée creeCalculBase dans la version Java.
 * @param {string} ch  La chaîne décrivant le  calcul.
 * @param {CListeObjets} ptListe  La liste propriétaire du calcul à créer.
 * @param {number} pdebut  L'indice du début de l'interprétationde la chaîne
 * @param {number} pfin  : L'indice de la fin de l'interprétationde la chaîne
 * @param {string[]} nomsVariablesFormelles  Un tableau donnant les noms des variables
 * formelles dans le cas où le calcul est utilisé à l'intérieur d'une focntion de
 * une ou plusieurs variables.
 * @param {CListeObjets} listeSource  La liste source des objets utilisables (ne diffère de ptListe que pour les exercices de construction)
 * @returns {CCb}
 */
function ccbmat (ch, ptListe, pdebut, pfin, nomsVariablesFormelles, listeSource) {
  if (arguments.length <= 5) listeSource = ptListe
  try {
    // Spécial JavaScript car pas d'erreur levée par charAt si pdebut > pFin
    if (pdebut > pfin) throw new Error()
    const info = { x: 0, y: 0 } // Contiendra dans x l'indice du caractère
    // précédent et dans y l'opérateur trouvé
    let ptr, car, op, indicePremiereVirg, operande1, operande2, indiceParF, indiceDeuxiemeVirg, indiceTroisiemeVirg
    let nomVariableSommation, tabcal, deb, nomVariableFormelle2, fin
    // Int nomF = new Int();
    const nomF = new Pointeur(null)
    let longNom
    const ptVa = new Pointeur(null)
    const parametreTrouve = new Pointeur(0)
    const nombreVar = new Pointeur(0)
    // On élimine les blancs de début
    car = ch.charAt(pdebut)
    while ((car === ' ') && (pdebut < pfin)) {
      pdebut++
      car = ch.charAt(pdebut)
    }
    // Puis de fin
    car = ch.charAt(pfin)
    while ((car === ' ') && (pdebut < pfin)) {
      pfin--
      car = ch.charAt(pfin)
    }
    // On recherche d'abord les opérateurs de ou logique
    ptr = CCbGlob.premierOperateurLogique('|', ch, pdebut, pfin, info)
    if (ptr !== -1) {
      return new COp(ptListe, CalcMatR.ccbmat(ch, ptListe, pdebut,
        info.x, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe, ptr + 1,
        pfin, nomsVariablesFormelles, listeSource), info.y)
    }
    // On recherche ensuite les opérateurs de et logique
    ptr = CCbGlob.premierOperateurLogique('&', ch, pdebut, pfin, info)
    if (ptr !== -1) {
      return new COp(ptListe, CalcMatR.ccbmat(ch, ptListe, pdebut,
        info.x, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe, ptr + 1,
        pfin, nomsVariablesFormelles, listeSource), info.y)
    }

    // On recherche d'abord les opérateurs d'inégalités
    ptr = CCbGlob.premiereInegalite(ch, pdebut, pfin, info)
    if (ptr !== -1) {
      return new COp(ptListe, CalcMatR.ccbmat(ch, ptListe, pdebut,
        info.x, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe, ptr + 1,
        pfin, nomsVariablesFormelles, listeSource), info.y)
    } else {
      // On recherche ensuite les operateurs d'addition ou soustraction
      ptr = CCbGlob.premiereSomme(ch, pdebut, pfin)
      if (ptr !== -1) {
        // On regarde d'abord si la chaine commence par un signe - ou
        // un signe +
        car = ch.charAt(ptr)
        if (car === '+') { op = Ope.Plus } else { op = Ope.Moin }
        if (ptr === pdebut) {
          car = ch.charAt(ptr)
          if (car === '+') {
            return CalcMatR.ccbmat(ch, ptListe, pdebut + 1, pfin,
              nomsVariablesFormelles, listeSource)
          } else {
            return new CMoinsUnaire(ptListe, CalcMatR.ccbmat(ch, ptListe,
              pdebut + 1, pfin, nomsVariablesFormelles, listeSource))
          }
        } else {
          return new COp(ptListe, CalcMatR.ccbmat(ch, ptListe, pdebut,
            ptr - 1, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe,
            ptr + 1, pfin, nomsVariablesFormelles, listeSource), op)
        }
      } else {
        // if (ptr !== NULL)
        ptr = CCbGlob.premierProduit(ch, pdebut, pfin)
        if (ptr !== -1) {
          car = ch.charAt(ptr)
          if (car === '*') { op = Ope.Mult } else { op = Ope.Divi }
          return new COp(ptListe, CalcMatR.ccbmat(ch, ptListe, pdebut,
            ptr - 1, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe,
            ptr + 1, pfin, nomsVariablesFormelles, listeSource), op)
        } else {
          // Le calcul ne contient ni addition, ni différence, ni produit
          // ni quotient}
          // Attention : par rapport à la version C++ 1.8, autorisation
          // du symbole ² d'élévation au carré.
          ptr = CCbGlob.premierePuissance(ch, pdebut, pfin)
          if (ptr !== -1) {
            if (ch.charAt(ptr) === '²') {
              return new CPuissance(ptListe, CalcMatR.ccbmat(ch, ptListe,
                pdebut, ptr - 1, nomsVariablesFormelles, listeSource), new CConstante(ptListe, 2))
            } else {
              return new CPuissance(ptListe, CalcMatR.ccbmat(ch, ptListe,
                pdebut, ptr - 1, nomsVariablesFormelles, listeSource), CalcMatR.ccbmat(ch, ptListe,
                ptr + 1, pfin, nomsVariablesFormelles, listeSource))
            }
          } else {
            // On regarde si la chaine commence par le nom d'une fonction
            // ou d'une valeur déjà définie
            longNom = listeSource.commenceParNomFonctionOuValeurOuParametre(
              ch.substring(pdebut), nomsVariablesFormelles, ptVa, nomF, parametreTrouve, nombreVar)
            if (longNom > 0) {
              if (parametreTrouve.getValue() !== -1) { return new CVariableFormelle(ptListe, parametreTrouve.getValue()) } else {
                if (ptVa.getValue() === null) {
                  // Modification version 3.0. Il faut regarder si la fonction
                  // est une fonction de plusieurs paramètres ou non
                  // Ajouté version 4.7.4.1
                  if (CCbGlob.parentheseFermante(ch, pdebut + longNom) === -1) throw new Error()

                  if (nombreVar.getValue() === 1) {
                    return new CFonction(ptListe, nomF.getValue(),
                      CalcMatR.ccbmat(ch, ptListe, pdebut + longNom, pfin,
                        nomsVariablesFormelles, listeSource))
                  } else {
                    if (nombreVar.getValue() === 2) {
                      indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut +
                        longNom + 1)
                      operande1 = CalcMatR.ccbmat(ch, ptListe,
                        pdebut + longNom + 1, indicePremiereVirg - 1,
                        nomsVariablesFormelles, listeSource)
                      indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch,
                        indicePremiereVirg + 1)
                      // A revoir plus tard si on crée des fonctions de trois
                      // variables ou plus
                      operande2 = CalcMatR.ccbmat(ch, ptListe,
                        indicePremiereVirg + 1, indiceParF - 1,
                        nomsVariablesFormelles, listeSource)
                      return new CFonction2Var(ptListe, nomF.getValue(),
                        operande1, operande2)
                    } else {
                      if (nombreVar.getValue() === 3) { // 3 variables
                        // var operande1;
                        indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut +
                          longNom + 1)
                        operande1 = CalcMatR.ccbmat(ch, ptListe, pdebut +
                          longNom + 1, indicePremiereVirg - 1,
                        nomsVariablesFormelles, listeSource)
                        indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremiereVirg + 1)
                        operande2 = CalcMatR.ccbmat(ch, ptListe,
                          indicePremiereVirg + 1, indiceDeuxiemeVirg - 1,
                          nomsVariablesFormelles, listeSource)
                        indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceDeuxiemeVirg + 1)
                        // A revoir plus tard si on crée des fonctions de trois
                        // variables ou plus
                        const operande3 = CalcMatR.ccbmat(ch, ptListe,
                          indiceDeuxiemeVirg + 1, indiceParF - 1,
                          nomsVariablesFormelles, listeSource)
                        return new CFonction3Var(ptListe, nomF.getValue(),
                          operande1, operande2, operande3)
                      } else {
                        if (nombreVar.getValue() === 4) {
                          // Seules fonctions à 4 variables : Cas d'une intégrale ou calcul de primitive prise entre deux bornes
                          indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut + longNom + 1)
                          indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremiereVirg + 1)
                          indiceTroisiemeVirg = CCbGlob.premiereVirgule(ch, indiceDeuxiemeVirg + 1)
                          indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceTroisiemeVirg + 1)
                          nomVariableSommation = ch.substring(indicePremiereVirg + 1, indiceDeuxiemeVirg)
                          nomVariableSommation = nomVariableSommation.trim()
                          const n = (nomsVariablesFormelles !== null) ? nomsVariablesFormelles.length : 0
                          // String[] nomVariableFormelle2 = new String[n + 1];
                          nomVariableFormelle2 = new Array(n + 1)
                          // Code nettoyé version mtgApp
                          for (let j = 0; j < n; j++) nomVariableFormelle2[j] = nomsVariablesFormelles[j]
                          // nomVariableFormelle2[n+1] = new String(nomVariableSommation);
                          nomVariableFormelle2[n] = nomVariableSommation
                          const Classef4var = (nomF.getValue() === Opef4v.integrale) ? CIntegraleDansFormule : CPrimitive
                          return new Classef4var(
                            ptListe,
                            CalcMatR.ccbmat(ch, ptListe, pdebut + longNom + 1,
                              indicePremiereVirg - 1, nomVariableFormelle2, listeSource),
                            CalcMatR.ccbmat(ch, ptListe,
                              indiceDeuxiemeVirg + 1,
                              indiceTroisiemeVirg - 1, nomsVariablesFormelles, listeSource),
                            CalcMatR.ccbmat(ch, ptListe,
                              indiceTroisiemeVirg + 1, indiceParF - 1,
                              nomsVariablesFormelles, listeSource), nomVariableSommation,
                            false)
                        } else {
                          // fonctions à 5 variables : la somme indicée et
                          // produit indicé
                          indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut + longNom + 1)
                          indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremiereVirg + 1)
                          indiceTroisiemeVirg = CCbGlob.premiereVirgule(ch, indiceDeuxiemeVirg + 1)
                          const indiceQuatriemeVirg = CCbGlob.premiereVirgule(ch, indiceTroisiemeVirg + 1)
                          indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceQuatriemeVirg + 1)
                          nomVariableSommation = ch.substring(indicePremiereVirg + 1, indiceDeuxiemeVirg)
                          nomVariableSommation = nomVariableSommation.trim()
                          const n = (nomsVariablesFormelles !== null) ? nomsVariablesFormelles.length : 0
                          // String[] nomVariableFormelle2 = new String[n + 1];
                          nomVariableFormelle2 = new Array(n + 1)
                          for (let j = 0; j < n; j++) { nomVariableFormelle2[j] = nomsVariablesFormelles[j] }
                          nomVariableFormelle2[n] = nomVariableSommation
                          if (nomF.getValue() === Opef5v.somme) {
                            const calculASommer = CalcMatR.ccbmat(ch, ptListe, pdebut + longNom +
                              1, indicePremiereVirg - 1, nomVariableFormelle2, listeSource)
                            return new CSommeMatDansForm(ptListe, calculASommer, CalcMatR.ccbmat(ch, ptListe,
                              indiceDeuxiemeVirg + 1, indiceTroisiemeVirg - 1,
                              nomVariableFormelle2, listeSource), CalcMatR.ccbmat(ch, ptListe,
                              indiceTroisiemeVirg + 1, indiceQuatriemeVirg - 1,
                              nomVariableFormelle2, listeSource), CalcMatR.ccbmat(ch, ptListe,
                              indiceQuatriemeVirg + 1, indiceParF - 1, nomVariableFormelle2, listeSource),
                            nomVariableSommation)
                          } else {
                            return new CProduitMatDansForm(ptListe,
                              CalcMatR.ccbmat(ch, ptListe, pdebut + longNom +
                                1, indicePremiereVirg - 1,
                              nomVariableFormelle2, listeSource), CalcMatR.ccbmat(ch, ptListe,
                                indiceDeuxiemeVirg + 1, indiceTroisiemeVirg - 1,
                                nomVariableFormelle2, listeSource), CalcMatR.ccbmat(ch, ptListe,
                                indiceTroisiemeVirg + 1, indiceQuatriemeVirg - 1,
                                nomVariableFormelle2, listeSource), CalcMatR.ccbmat(ch, ptListe,
                                indiceQuatriemeVirg + 1, indiceParF - 1, nomVariableFormelle2, listeSource),
                              nomVariableSommation)
                          }
                        }
                      }
                    }
                  }
                } else {
                  if (ptVa.getValue().estFonctionOuSuite()) {
                    // Ajouté version 4.7.4.1
                    if (CCbGlob.parentheseFermante(ch, pdebut + longNom) === -1) {
                      throw new Error()
                    }
                    const calc = ptVa.getValue()
                    const nbvar = calc.nombreVariables()
                    if (nbvar === 1) {
                      return new CAppelFonction(ptListe,
                        ptVa.getValue(), CalcMatR.ccbmat(ch, ptListe, pdebut + longNom, pfin,
                          nomsVariablesFormelles, listeSource))
                    } else {
                      // Ccb[] tabcal = new Ccb[nbvar];
                      tabcal = new Array(nbvar)
                      deb = pdebut + longNom
                      fin = 0
                      for (let i = 0; i < nbvar - 1; i++) {
                        fin = CCbGlob.premiereVirgule(ch, deb + 1)
                        tabcal[i] = CalcMatR.ccbmat(ch, ptListe, deb + 1, fin - 1, nomsVariablesFormelles, listeSource)
                        deb = fin
                      }
                      deb++
                      fin = CCbGlob.parentheseFermanteApresVirgule(ch, deb)
                      tabcal[nbvar - 1] = CalcMatR.ccbmat(ch, ptListe, deb,
                        fin - 1, nomsVariablesFormelles, listeSource)
                      if (ptVa.getValue().estMatrice()) return new CTermMat(ptListe, tabcal[0], tabcal[1], ptVa)
                      else return new CAppelFonctionNVar(ptListe, nbvar, ptVa.getValue(), tabcal)
                    }
                  } else {
                    // Un nom de matrice pas suivi d'une parenthèse est une référence à la matrice elle-même
                    if (ptVa.getValue().estMatrice() && ch.charAt(pdebut + longNom) === '(') {
                      tabcal = new Array(2)
                      deb = pdebut + longNom
                      fin = CCbGlob.premiereVirgule(ch, deb + 1)
                      tabcal[0] = CalcMatR.ccbmat(ch, ptListe, deb + 1, fin - 1, nomsVariablesFormelles, listeSource)
                      deb = fin + 1
                      fin = CCbGlob.parentheseFermanteApresVirgule(ch, deb)
                      tabcal[1] = CalcMatR.ccbmat(ch, ptListe, deb,
                        fin - 1, nomsVariablesFormelles, listeSource)
                      return new CTermMat(ptListe, tabcal[0], tabcal[1], ptVa.getValue())
                    } else {
                      return new CResultatValeur(ptListe, ptVa.getValue())
                    }
                  }
                }
              }
            } else {
              // Dans le cas où l'expression commence par une parenthèse
              // ouvrante, elle finit par une fermante et il suffit
              // d'évaluer ce que la parenthèse contient
              car = ch.charAt(pdebut)
              // Si le premier caractère est une parenthèse ouvrante
              // il faut faire attention car le dernier peut être
              // un espace.
              // Cela a donné un bug dans la version 16 bits
              if (car === '(') {
                if (CCbGlob.parentheseFermante(ch, pdebut) === -1) throw new Error()
                else {
                  return CalcMatR.ccbmat(ch, ptListe, pdebut + 1,
                    CCbGlob.parentheseFermante(ch, pdebut) - 1, nomsVariablesFormelles, listeSource)
                }
              } else {
                // Le résultat ne peut être que numérique}
                const chaineNombre = ch.substring(pdebut, pfin + 1)
                if (chaineNombre === '') throw new Error() // Spécial JavaScript
                if (Fonte.estDecimalCorrect(chaineNombre)) {
                  const f = parseFloat(chaineNombre)
                  if (isNaN(f)) throw new Error()
                  else return new CConstante(ptListe, f)
                } else return new CCbNull(chaineNombre)
              }
            }
          }
        }
      }
    }
  } catch (e) {
    // Amélioration version 4.7.4.1 : Même si l'expression est incorrecte, on remplace les * de multiplication par des \times
    // Supprimé version 4.9.3
    const ch1 = ch.substring(pdebut, pfin + 1)
    // Amélioration version 4.9.3
    if ((ch1.charAt(0) === '(') && (ch1.length >= 1)) { // Cas d'une parenthèse ouvrante non fermée
      return CalcMatR.ccbmat(ch, ptListe, pdebut + 1, pfin, nomsVariablesFormelles, listeSource)
    }
    return new CCbNull(ch1)
    // return new CCbNull(stb.toString());
  }
}
/**
 * Fonction récursive vérifiant la syntaxe de l'expression réelle contenue dans ch en
 * tenant compte du fait qu'elle ne doit pas utiliser de valeur dont l'indice
 * dans ptListe est strictement supérieur à indiceMaxiDansListe.
 * Le calcul doit être réel.
 * @param {CListeObjets} ptListe  La liste propriétaire du calcul analysé
 * @param {string} ch  La chaîne dans laquelle se fait la recherche syntaxique.
 * @param {Pointeur} indiceErreur  getValeur renverra l'indice de l'erreur
 * de syntaxe dans la chapine s'il y en a une.
 * @param {number} indiceMaxiDansListe  L'indice maxi d'interprétation dans la chaîne ch.
 * @param {string[]} parametreFormel  Un tableau représentant les noms de la ou des variables formelles
 * d'une fonction de une ou plusieurs variables.
 * @returns {boolean} : true si la syntaxe est correcte, false sinon.
 */
function verifieSyntaxe (ptListe, ch,
  indiceErreur, indiceMaxiDansListe, parametreFormel) {
  let i
  let indiceDansListe
  let pdebut
  let car, carSuivant
  let erreur
  let itemPrecedent
  let itemSuivant = 0
  let pointDecimalRencontre
  let sommeParentheses
  let longNom
  const nomF = new Pointeur()
  const ptVa = new Pointeur()
  let queDesBlancs
  const parametreTrouve = new Pointeur(0)
  const nombreVariables = new Pointeur(0)
  let nivPar = 0 // Niveau de parenthèses
  const appelFonction = new Array(CCbGlob.nombreMaxParentheses + 1) // Tableau de booléens 64 niveaux de parenthèses imbriqués maxi
  for (let j = 0; j <= CCbGlob.nombreMaxParentheses; j++) appelFonction[j] = false
  erreur = false
  const longueurCh = ch.length
  // On vérifie d'abord qu'il n'y a pas d'erreur de parenthèse
  if (longueurCh === 0) {
    indiceErreur.setValue(0)
    return false
  }
  i = 0
  sommeParentheses = 0
  while ((i < longueurCh) && (sommeParentheses >= 0)) {
    car = ch.charAt(i)
    switch (car) {
      case '(':
        sommeParentheses++
        break
      case ')':
        sommeParentheses--
    } // switch
    i++
  }
  if (sommeParentheses !== 0) {
    indiceErreur.setValue(i)
    return false
  }
  if (ch === '.') {
    indiceErreur.setValue(0)
    return false
  }
  i = 0
  // Tout se passe au début comme si l'expression était précédée
  // d'une parenthèse ouvrante
  itemPrecedent = CCbGlob.ParOuvrante
  while ((i < longueurCh) && !erreur) {
    car = ch.charAt(i)
    pointDecimalRencontre = false
    if (Fonte.chiffre(car) || (car === '.')) {
      while ((Fonte.chiffre(car) || (car === '.')) && (i < longueurCh) &&
      !erreur) {
        if (car === '.') {
          if (pointDecimalRencontre) {
            erreur = true
            indiceErreur.setValue(i - 1)
            // IndiceMessageErreur = IDE_SYNTAXE1;
          } else { pointDecimalRencontre = true }
        }
        i++
        if (i < longueurCh) { car = ch.charAt(i) }
      } // while
      if (!erreur) { itemSuivant = CCbGlob.Nombre }
    } else {
      // cas où le caractère en cours n'est pas un nombre
      // le caractère en cours n'est pas un chiffre ou un point décimal}
      pdebut = i
      // On regarde si cela commence par le nom d'une fonction ou
      // une valeur déjà définie
      longNom = ptListe.commenceParNomFonctionOuValeurOuParametre(
        ch.substring(pdebut), parametreFormel, ptVa, nomF, parametreTrouve, nombreVariables)
      if (longNom > 0) {
        if (parametreTrouve.getValue() !== -1) {
          itemSuivant = CCbGlob.Valeur
          i = i + longNom
        } else {
          appelFonction[nivPar + 1] = true
          if (ptVa.getValue() === null) {
            if (((i + longNom) < ch.length) &&
              ch.charAt(i + longNom) !== '(') {
              erreur = true
              indiceErreur.setValue(i + longNom)
            } else {
              itemSuivant = CCbGlob.Fonction
              // Ajout version 4.5.2 pour corriger un bug
              if (!CCbGlob.autorisationSyntaxe(itemPrecedent, itemSuivant)) {
                erreur = true
                indiceErreur.setValue(i)
                break
              }
              // Fin ajout
              // Il faut regarder si la fonction est de plusieurs variables
              const nvirg = CCbGlob.NombreVirgules(ch, i + longNom + 1)
              if (nvirg !== nombreVariables.getValue() - 1) {
                if (nvirg <= nombreVariables.getValue() - 1) {
                  indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch, i +
                    longNom + 1, nvirg))
                } else {
                  indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch, i +
                    longNom + 1, nombreVariables.getValue() - 1) - 1)
                }
                erreur = true
              } else {
                // Si le nombre de variables est supérieur ou égal à 4, il
                // s'agit soit d'un calcul d'intégrale
                // soit d'une somme indicée pour laquelle la syntaxe est la
                // même
                if (nombreVariables.getValue() >= 4) {
                  nivPar++
                  const indicePremVirg = CCbGlob.premiereVirgule(ch, i + longNom + 1)
                  const chformuleASommer = ch.substring(i + longNom + 1, indicePremVirg)
                  const indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremVirg + 1)
                  let nomVariableSommation = ch.substring(indicePremVirg + 1, indiceDeuxiemeVirg)
                  // Il faut retirer les espaces de début et de fin
                  // On vérifie si le nom de variable formelle pour la somme est valable
                  nomVariableSommation = nomVariableSommation.trim()
                  if (!ptListe
                  // Ci-dessous paramètre bAccepNamei à true on accepte i comme variable de sommation
                    .validationNomCalculSansMessage(nomVariableSommation, true) ||
                    ptListe.egalNomValeurOuFonctionOuMesure(nomVariableSommation, -1)) {
                    erreur = true
                    indiceErreur.setValue(indiceDeuxiemeVirg)
                  } else {
                    // On vérifie si la syntaxe du calcul à sommer est
                    // correct.
                    // Pour cela on appelle à nouveau vérifieSyntaxe
                    const indiceErreur2 = new Pointeur(0)
                    const n = (parametreFormel !== null) ? parametreFormel.length : 0
                    const parametreFormel2 = new Array(n + 1)
                    for (let j = 0; j < n; j++) parametreFormel2[j] = parametreFormel[j]
                    parametreFormel2[n] = nomVariableSommation
                    if (!CalcMatR.verifieSyntaxe(ptListe, chformuleASommer,
                      indiceErreur2, indiceMaxiDansListe, parametreFormel2)) {
                      erreur = true
                      indiceErreur.setValue(i + longNom + 1 + indiceErreur2.getValue())
                    } else {
                      i = indiceDeuxiemeVirg + 1
                      itemPrecedent = CCbGlob.Valeur
                      itemSuivant = CCbGlob.Virgule
                    }
                  }
                } else { i += longNom }
              }
            }
          } else {
            const vd = ptVa.getValue()
            indiceDansListe = ptListe.indexOf(vd)
            if (indiceDansListe > indiceMaxiDansListe) {
              erreur = true
              indiceErreur.setValue(i)
            } else {
              i += longNom
              if (vd.estFonctionOuSuite()) {
                if ((i < ch.length) && ch.charAt(i) !== '(') {
                  erreur = true
                  indiceErreur.setValue(i + longNom)
                } else {
                  itemSuivant = CCbGlob.Fonction
                  const nbvar = vd.nombreVariables()
                  if (nbvar >= 2) {
                    const nvirg = CCbGlob.NombreVirgules(ch, i + 1)
                    if (nvirg !== nombreVariables.getValue() - 1) {
                      if (nvirg <= nombreVariables.getValue() - 1) {
                        indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch,
                          i + 1, nvirg))
                      } else {
                        indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch,
                          i + 1, nombreVariables.getValue() - 1) - 1)
                      }
                      erreur = true
                    }
                  } else {
                    // Bug corrigé version 4.6 : Il ne faut pas qu'un appel de fonction d'une variable comprenne des virgules
                    if (CCbGlob.NombreVirgules(ch, i + 1) > 0) {
                      indiceErreur.setValue(ch.indexOf(',', i + 1))
                      erreur = true
                    }
                  }
                }
              } else {
                if (vd.estMatrice()) {
                  if ((i < ch.length) && ch.charAt(i) === '(') {
                    // Un nom de matrice suivi de deux paramètres fait référence à un terme de la matrice
                    itemSuivant = CCbGlob.Fonction
                    const nvirg = CCbGlob.NombreVirgules(ch, i + 1)
                    if (nvirg !== 1) {
                      if (nvirg <= 1) {
                        indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch,
                          i + 1, nvirg))
                      } else {
                        indiceErreur.setValue(CCbGlob.indiceCaractereVirgule(ch,
                          i + 1, 1) - 1)
                      }
                      erreur = true
                    }
                  } else itemSuivant = CCbGlob.Valeur
                } else {
                  itemSuivant = CCbGlob.Valeur
                }
              }
            }
          }
        }
      } else {
        switch (car) {
          case '+':
          case '-':
            itemSuivant = CCbGlob.Addition
            i++
            break
          case '*':
          case '/':
            itemSuivant = CCbGlob.Multiplication
            i++
            break
          case '(':
            if (nivPar >= CCbGlob.nombreMaxParentheses - 1) {
              erreur = true
              indiceErreur.setValue(i)
            } else {
              itemSuivant = CCbGlob.ParOuvrante
              i++
              nivPar++
            }
            break
          case ')':
            appelFonction[nivPar] = false
            nivPar--
            itemSuivant = CCbGlob.ParFermante
            i++
            break
          case '^':
            itemSuivant = CCbGlob.Puissance
            i++
            break
          // Ajout par rapport à la version C++ 1.8, autorisation du carré ²
          case '²':
            itemSuivant = CCbGlob.Carre
            i++
            break
          // ni nombre ni opérateur}
          case '<':
            itemSuivant = CCbGlob.Inegalite
            i++
            if (i <= longueurCh - 2) {
              carSuivant = ch.charAt(i)
              if ((carSuivant === '=') || (carSuivant === '>')) { i++ }
            }
            break
          case '>':
            itemSuivant = CCbGlob.Inegalite
            i++
            if (i <= longueurCh - 2) {
              carSuivant = ch.charAt(i)
              if (carSuivant === '=') { i++ }
            }
            break
          // Ajout version 4.9.5
          case '&':
          case '|':
          case '=':
            itemSuivant = CCbGlob.Inegalite
            i++
            break
          case ' ':
            itemSuivant = CCbGlob.Blanc
            i++
            break
          case ',':
            if (!appelFonction[nivPar]) {
              erreur = true
              indiceErreur.setValue(i)
            } else {
              itemSuivant = CCbGlob.Virgule
              i++
            }
            break
          default: // switch Car
            erreur = true
            indiceErreur.setValue(i - 1)
        } // switch Car
      }// else du if LongNom > 0
    } // else du if Chiffre(Car) || (Car === '.'))
    if (!erreur) {
      if (CCbGlob.autorisationSyntaxe(itemPrecedent, itemSuivant)) {
        if (itemSuivant !== CCbGlob.Blanc) { itemPrecedent = itemSuivant }
      } else {
        erreur = true
        indiceErreur.setValue(i - 1)
      }
    }
  } // while
  // Il faut aussi regarder si la fin de l'expression est correcte
  itemSuivant = CCbGlob.ParFermante
  if (!erreur) {
    if (!CCbGlob.autorisationSyntaxe(itemPrecedent, itemSuivant)) {
      erreur = true
      indiceErreur.setValue(longueurCh)
    }
  }
  if (indiceErreur.getValue() < 0) indiceErreur.setValue(0)
  else if (indiceErreur.getValue() > longueurCh) indiceErreur.setValue(longueurCh)
  // On regarde si la chaîne ne contient que des blancs
  i = 0
  queDesBlancs = true
  while ((i <= longueurCh - 1) && queDesBlancs) {
    car = ch.charAt(i)
    if (car !== ' ') { queDesBlancs = false } else { i++ }
  }
  if (queDesBlancs) {
    erreur = true
    indiceErreur.setValue(longueurCh)
  }
  return !erreur
}

const CalcMatR = {
  ccbmat,
  verifieSyntaxe
}

export default CalcMatR