kernel/CalcC.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 CalcR from '../kernel/CalcR'
import { erreurCalculException } from '../kernel/kernel'
import CAppelFonctionComplexe from '../objets/CAppelFonctionComplexeBase'
import CAppelFonctionComplexeNVar from '../objets/CAppelFonctionComplexeNVar'
import CConstante from '../objets/CConstante'
import CConstantei from '../objets/CConstantei'
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 CSommeDansFormule from '../objets/CSommeDansFormule'
import COp from '../objets/COperation'
import CProduitDansFormule from '../objets/CProduitDansFormule'
import CPuissance from '../objets/CPuissance'
import CResultatValeurComplexe from '../objets/CResultatValeurComplexe'
import CTermMat from '../objets/CTermMat'
import CCbNull from '../objets/CCbNull'

/**
 * 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 complexe.
 * @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 ccbComp (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()
    let ptr
    const info = { x: 0, y: 0 } // Contiendra dans x l'indice du caractère
    // précédent
    // et dans y l'opérateur trouvé (correspond au ptPrecedent et
    // operateurInegalite
    // de la version C++
    // int ptPrecedent;
    // int operateurInegalite;
    let car
    let op
    const nomF = new Pointeur(null)
    const ptVa = new Pointeur(null)
    const parametreTrouve = new Pointeur(0)
    const nombreVar = new Pointeur(0)
    const complexeiTrouve = new Pointeur(false)

    // On élimine les blancs de début
    car = ch.charAt(pdebut)
    while ((car === ' ') && (pdebut < pfin)) {
      pdebut++
      car = ch.charAt(pdebut)
    }
    // On recherche d'abord les opérateurs de ou logique
    ptr = CCbGlob.premierOperateurLogique('|', ch, pdebut, pfin, info)
    if (ptr !== -1) {
      return new COp(ptListe, CalcC.ccbComp(ch, ptListe, pdebut,
        info.x, nomsVariablesFormelles, listeSource), CalcC.ccbComp(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, CalcC.ccbComp(ch, ptListe, pdebut,
        info.x, nomsVariablesFormelles, listeSource), CalcC.ccbComp(ch, ptListe, ptr + 1,
        pfin, nomsVariablesFormelles, listeSource), info.y)
    }
    ptr = CCbGlob.premiereInegalite(ch, pdebut, pfin, info)
    if (ptr !== -1) {
      return new COp(
        ptListe,
        ccbComp(ch, ptListe, pdebut, info.x, nomsVariablesFormelles, listeSource),
        ccbComp(ch, ptListe, ptr + 1, pfin, nomsVariablesFormelles, listeSource),
        info.y
      )
    }

    // 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 ccbComp(ch, ptListe, pdebut + 1, pfin, nomsVariablesFormelles, listeSource)
        }
        return new CMoinsUnaire(ptListe, ccbComp(ch,
          ptListe, pdebut + 1, pfin, nomsVariablesFormelles, listeSource))
      }
      return new COp(
        ptListe,
        ccbComp(ch, ptListe, pdebut, ptr - 1, nomsVariablesFormelles, listeSource),
        ccbComp(ch, ptListe, ptr + 1, pfin, nomsVariablesFormelles, listeSource),
        op
      )
    }

    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,
        ccbComp(ch, ptListe, pdebut, ptr - 1, nomsVariablesFormelles, listeSource),
        ccbComp(ch, ptListe, ptr + 1, pfin, nomsVariablesFormelles, listeSource),
        op
      )
    }

    // 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, ccbComp(ch, ptListe, pdebut, ptr - 1, nomsVariablesFormelles, listeSource), new CConstante(ptListe, 2))
      }
      return new CPuissance(
        ptListe,
        ccbComp(ch, ptListe, pdebut, ptr - 1, nomsVariablesFormelles, listeSource),
        ccbComp(ch, ptListe, ptr + 1, pfin, nomsVariablesFormelles, listeSource)
      )
    }

    // On regarde si la chaine commence par le nom d'une fonction
    // ou d'une valeur déjà définie
    const longNom = ptListe.commenceParNomFonctionOuValeurOuParametreComplexe(
      ch.substring(pdebut), nomsVariablesFormelles, ptVa, nomF, parametreTrouve, complexeiTrouve, nombreVar)

    if (longNom > 0) {
      if (complexeiTrouve.getValue()) {
        return new CConstantei(ptListe)
      }

      if (parametreTrouve.getValue() !== -1) {
        return new CVariableFormelle(ptListe, parametreTrouve.getValue())
      }

      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(erreurCalculException)
        if (nombreVar.getValue() === 1) {
          return new CFonction(ptListe, nomF.getValue(),
            ccbComp(ch, ptListe, pdebut + longNom,
              pfin, nomsVariablesFormelles, listeSource))
        }

        if (nombreVar.getValue() === 2) {
          const indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut +
                            longNom + 1)
          const operande1 = ccbComp(ch, ptListe, pdebut + longNom + 1, indicePremiereVirg - 1, nomsVariablesFormelles, listeSource)
          const indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indicePremiereVirg + 1)
          // A revoir plus tard si on crée des fonctions de trois
          // variables ou plus
          const operande2 = ccbComp(ch, ptListe, indicePremiereVirg + 1, indiceParF - 1, nomsVariablesFormelles, listeSource)
          return new CFonction2Var(ptListe, nomF.getValue(), operande1, operande2)
        }

        if (nombreVar.getValue() === 3) { // 3 variables
          const indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut + longNom + 1)
          // Traitement de syntaxe particulier pour un calcul
          // d'intégrale de fonction, le premier argument devant
          // être le nom
          // d'une fonction prédéfinie
          const operande1 = ccbComp(ch, ptListe,
            pdebut + longNom + 1, indicePremiereVirg - 1,
            nomsVariablesFormelles, listeSource)
          const indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch,
            indicePremiereVirg + 1)
          const operande2 = ccbComp(ch,
            ptListe, indicePremiereVirg + 1,
            indiceDeuxiemeVirg - 1, nomsVariablesFormelles, listeSource)
          const indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceDeuxiemeVirg + 1)
          // A revoir plus tard si on crée des fonctions de
          // trois variables ou plus
          const operande3 = ccbComp(ch, ptListe, indiceDeuxiemeVirg + 1, indiceParF - 1, nomsVariablesFormelles, listeSource)
          return new CFonction3Var(ptListe, nomF.getValue(), operande1, operande2, operande3)
        }

        // Pas de calcul d'intégrale dans un calcul complexe
        if (nombreVar.getValue() === 4) { // Calcul d'intégrale
          // Si les bornes ne sont pas réelles, c'est leur
          // partie réelle qui sera utilisée
          const indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut + longNom + 1)
          const indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremiereVirg + 1)
          const indiceTroisiemeVirg = CCbGlob.premiereVirgule(ch, indiceDeuxiemeVirg + 1)
          const indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceTroisiemeVirg + 1)
          const nomVariableSommation = ch.substring(indicePremiereVirg + 1, indiceDeuxiemeVirg).trim()
          // Un seul paramètre autorisé pour un calcul
          // d'intégrale dans un calcul complexe : la variable
          // formelle
          const nomVariableFormelle3 = new Array(1)
          nomVariableFormelle3[0] = nomVariableSommation
          const Classef4var = (nomF.getValue() === Opef4v.integrale) ? CIntegraleDansFormule : CPrimitive
          return new Classef4var(ptListe,
            CalcR.ccb(ch, ptListe, pdebut + longNom + 1, indicePremiereVirg - 1, nomVariableFormelle3, listeSource),
            ccbComp(ch, ptListe, indiceDeuxiemeVirg + 1, indiceTroisiemeVirg - 1, null, listeSource),
            ccbComp(ch, ptListe, indiceTroisiemeVirg + 1, indiceParF - 1, null, listeSource),
            nomVariableSommation,
            true
          )
        }

        // Fonction à 5 variables : la somme indicée et le
        // produit indicé
        const indicePremiereVirg = CCbGlob.premiereVirgule(ch, pdebut + longNom + 1)
        const indiceDeuxiemeVirg = CCbGlob.premiereVirgule(ch, indicePremiereVirg + 1)
        const indiceTroisiemeVirg = CCbGlob.premiereVirgule(ch, indiceDeuxiemeVirg + 1)
        const indiceQuatriemeVirg = CCbGlob.premiereVirgule(ch, indiceTroisiemeVirg + 1)
        const indiceParF = CCbGlob.parentheseFermanteApresVirgule(ch, indiceQuatriemeVirg + 1)
        const nomVariableSommation = ch.substring(indicePremiereVirg + 1, indiceDeuxiemeVirg).trim()
        let n = 0
        if (nomsVariablesFormelles !== null) n = nomsVariablesFormelles.length
        const nomVariableFormelle2 = new Array(n + 1)
        for (let j = 0; j < n; j++) { nomVariableFormelle2[j] = nomsVariablesFormelles[j] }
        nomVariableFormelle2[n] = nomVariableSommation
        if (nomF.getValue() === Opef5v.sommeC) {
          return new CSommeDansFormule(ptListe,
            ccbComp(ch, ptListe, pdebut +
                                    longNom + 1, indicePremiereVirg - 1, nomVariableFormelle2, listeSource),
            ccbComp(ch, ptListe,
              indiceDeuxiemeVirg + 1, indiceTroisiemeVirg - 1,
              nomVariableFormelle2, listeSource),
            ccbComp(ch, ptListe,
              indiceTroisiemeVirg + 1, indiceQuatriemeVirg - 1,
              nomVariableFormelle2, listeSource),
            ccbComp(ch, ptListe,
              indiceQuatriemeVirg + 1, indiceParF - 1,
              nomVariableFormelle2, listeSource), nomVariableSommation)
        }

        return new CProduitDansFormule(ptListe,
          ccbComp(ch, ptListe, pdebut + longNom + 1, indicePremiereVirg - 1, nomVariableFormelle2, listeSource),
          ccbComp(ch, ptListe, indiceDeuxiemeVirg + 1, indiceTroisiemeVirg - 1, nomVariableFormelle2, listeSource),
          ccbComp(ch, ptListe, indiceTroisiemeVirg + 1, indiceQuatriemeVirg - 1, nomVariableFormelle2, listeSource),
          ccbComp(ch, ptListe, indiceQuatriemeVirg + 1, indiceParF - 1, nomVariableFormelle2),
          nomVariableSommation,
          listeSource
        )
      }

      if (ptVa.getValue().estFonctionOuSuite()) {
        const calc = ptVa.getValue()
        const nbvar = calc.nombreVariables()
        if (nbvar === 1) {
          return new CAppelFonctionComplexe(ptListe, ptVa.getValue(), ccbComp(ch, ptListe, pdebut + longNom, pfin, nomsVariablesFormelles, listeSource))
        }

        const tabcal = new Array(nbvar)
        let deb = pdebut + longNom
        let fin = 0
        for (let i = 0; i < nbvar - 1; i++) {
          fin = CCbGlob.premiereVirgule(ch, deb + 1)
          tabcal[i] = ccbComp(ch, ptListe,
            deb + 1, fin - 1, nomsVariablesFormelles, listeSource)
          deb = fin
        }
        deb++
        fin = CCbGlob.parentheseFermanteApresVirgule(ch, deb)
        tabcal[nbvar - 1] = ccbComp(ch, ptListe,
          deb, fin - 1, nomsVariablesFormelles, listeSource)
        return new CAppelFonctionComplexeNVar(ptListe, nbvar, ptVa.getValue(), tabcal)
      }

      if (ptVa.getValue().estMatrice() && ch.charAt(pdebut + longNom) === '(') {
        const tabcal = new Array(2)
        let deb = pdebut + longNom
        let fin = CCbGlob.premiereVirgule(ch, deb + 1)
        tabcal[0] = CalcR.ccb(ch, ptListe, deb + 1, fin - 1, nomsVariablesFormelles, listeSource)
        deb = fin + 1
        fin = CCbGlob.parentheseFermanteApresVirgule(ch, deb)
        tabcal[1] = CalcR.ccb(ch, ptListe, deb,
          fin - 1, nomsVariablesFormelles, listeSource)
        return new CTermMat(ptListe, tabcal[0], tabcal[1], ptVa.getValue())
      }
      return new CResultatValeurComplexe(ptListe, ptVa.getValue())
    }

    // 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()
      return ccbComp(ch, ptListe, pdebut + 1,
        CCbGlob.parentheseFermante(ch, pdebut) - 1, nomsVariablesFormelles, listeSource)
    }
    // Le résultat ne peut être que numérique}
    let chaineNombre = ''
    let ptch = pdebut
    while ((Fonte.chiffre(car) || (car === '.')) && (ptch <= pfin)) {
      car = ch.charAt(ptch)
      chaineNombre = chaineNombre + car
      ptch++
    }
    if (chaineNombre === '') throw new Error() // Spécial JavaScript
    const f = parseFloat(chaineNombre)
    if (isNaN(f)) throw new Error()
    return new CConstante(ptListe, f)
  } 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 ccbComp(ch, ptListe, pdebut + 1, pfin, nomsVariablesFormelles, listeSource)
    }
    //
    return new CCbNull(ch1)
  }
}

/**
 * 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 est complexe mais peut utiliser des résultats réels.
 * @param {CListeObjets} ptListe  La listeProprietaire du calcul analysé.
 * @param {string} ch  La chaîne dans laquelle se fait la recherche.
 * @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 verifieSyntaxeComplexe (ptListe, ch, indiceErreur, indiceMaxiDansListe,
  parametreFormel) {
  let i, nvirg
  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 complexei = new Pointeur(false)
  const parametreTrouve = new Pointeur(0)
  const nombreVariables = new Pointeur(0)
  let nivPar = 0 // Niveau de parenthèses
  const appelFonction = new Array(CCbGlob.nombreMaxParentheses + 1) // 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
  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.commenceParNomFonctionOuValeurOuParametreComplexe(
        ch.substring(pdebut), parametreFormel, ptVa, nomF, parametreTrouve,
        complexei, nombreVariables)
      if (longNom > 0) {
        if (complexei.getValue()) {
          itemSuivant = CCbGlob.Valeur
          i = i + longNom
        } else {
          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
                }
                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 {
                  // Seule fonction complexe à 4 variables ou plus : le calcul
                  // de somme indicée
                  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)
                    nomVariableSommation = nomVariableSommation.trim()
                    if (!ptListe.validationNomCalculSansMessage(nomVariableSommation) ||
                      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)
                      let n = 0
                      if (parametreFormel !== null) n = parametreFormel.length
                      const parametreFormel2 = new Array(n + 1)
                      for (let j = 0; j < n; j++) parametreFormel2[j] = parametreFormel[j]
                      parametreFormel2[n] = nomVariableSommation
                      let b
                      if ((nombreVariables.getValue() === 4) && (nomF.getValue() === Opef4v.integraleC)) {
                        // Cas d'un calcul d'intégrale
                        // Ne doit utiliser que fonctions ou valeurs réelles
                        // On ne passe donc comme variable formelle que
                        // nomVariableSommation
                        const parametreFormel3 = new Array(1)
                        parametreFormel3[0] = nomVariableSommation
                        b = CalcR.verifieSyntaxe(ptListe, chformuleASommer,
                          indiceErreur2, indiceMaxiDansListe, parametreFormel3)
                      } else {
                        b = verifieSyntaxeComplexe(ptListe, chformuleASommer,
                          indiceErreur2, indiceMaxiDansListe, parametreFormel2)
                      }
                      if (!b) {
                        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) {
                      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
                      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 {
                      erreur = true
                      indiceErreur.setValue(i)
                    }
                  } 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
          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
        // IndiceMessageErreur = IDE_SYNTAXE1;
        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)
  i = 0
  queDesBlancs = true
  while ((i <= longueurCh - 1) && queDesBlancs) {
    car = ch.charAt(i)
    if (car !== ' ') { queDesBlancs = false } else { i++ }
  }
  if (queDesBlancs) {
    // MessageBeep(0);
    erreur = true
    indiceErreur.setValue(longueurCh)
    // IndiceMessageErreur = IDE_SYNTAXE1;
  }
  // if (Erreur) MessageBeep(0);
  return !erreur
}

const CalcC = {
  ccbComp,
  verifieSyntaxeComplexe
}

export default CalcC