Programme_js

Fermé
djakweb - Modifié le 3 mai 2021 à 06:50
 R0b0x - 5 mai 2021 à 13:46
bonsoir, je suis de retour avec mon probleme. en fait le projet en question est la realisation d'un analyseur lexical.je doit avoir comme valeur de sortir un tableau de token y comprs les separateurs qui vont egalement servire pour l'analyse syntaxique plus tard. le premier probeme que j'ai eu est la fonction print teste seulement la premiere condition et j'ai mis le block de code dans une boucle for mais la console me dit ceci:Uncaught TypeError: Cannot read property '0' of null qui est referencéa la ligne 173.le code que j'ai est le suivant:
//List of all tokens
var tokenList = [
    {
        name: "motsCle",
        hardRegex: /(var|variable|const|constante|fonction|function|procedure|debut|begin|ecrire|write|lire|read|afficher|print|si|if|alors|then|sinon|else|tantque|while|faire|do|repeter|pour|for|De|to|finsi|finPour|finTantque|endWhile|endDoWhile|endFor|entier|integer|reel|double|booleen|boolean|chaine|string|caractere|char|fin|end)$/g,
        softRegex: /(var|variable|const|constante|fonction|function|procedure|debut|begin|fin|end|ecrire|write|lire|read|afficher|print|si|if|alors|then|sinon|else|tantque|while|faire|do|repeter|pour|for|De|to|finsi|finPour|finTantque|endWhile|endDoWhile|endFor|entier|integer|reel|double|booleen|boolean|chaine|string|caractere|char)/g,
        print: "onlyWord"
    }
    ,
    {
        name: "ident",
        hardRegex: /[a-zA-Z_]+[a-zA-Z0-9]*$/g,
        softRegex: /[a-zA-Z_]+[a-zA-Z0-9]*/g,
        print: "wordAndToken"
    },
    {
        name: "affectation",
        hardRegex: /<--$/,
        softRegex: /<--/,
        print: "onlyToken"
    },
    {
        name: "aperateurLogique",
        hardRegex: /><=|\&$/,
        softRegex: /><=|\&/,
        print: "onlyToken"
    },
    {
        name: "numerique",
        hardRegex: /((-)?[0-9]*\.[0-9]+[0-9]*$)|(^(-)?[0-9]+[0-9]*$)/,
        softRegex: /((-)?[0-9]*\.[0-9]+[0-9]*)|(^(-)?[0-9]+[0-9]*)/,
        print: "wordAndToken"
    },
    /*{
        name: "operateur",
        hardRegex: "^\-\/\+\*\%$",
        softRegex: "^\-\/\+\*\%$",
        print: "onlyToken"
    },*/
    {
        name: "plus",
        hardRegex: /\+$/,
        softRegex: /^\+/,
        print: "onlyToken"
    },
    {
        name: "moins",
        hardRegex: /\-$/,
        softRegex: /\-/,
        print: "onlyToken"
    },
    {
        name: "division",
        hardRegex: /\/$/,
        softRegex: /\//,
        print: "onlyToken"
    },
    {
        name: "modulo",
        hardRegex: /\%$/,
        softRegex: /\%/,
        print: "onlyToken"
    },
    {
        name: "pointConcat",
        hardRegex: /\.$/,
        softRegex: /\./,
        print: "onlyToken"
    },
    {
        name: "separateur",
        hardRegex: /\[\]\s,;:\(\)\{\}$/g,
        softRegex: /\[\]\s,;:\(\)\{\}/g,
        print: "onlyToken"
    },
]

//Additional Regexs
var commentRegex = /\\\/*/;


// Useful Variables// variable utilisable
var lexical_analysis;
var partial_lexical_analysis;
var wordsToAnalyse = [] // mot a analyser

//Function to get next token //founction de recuperation du token suivant
function getNextToken(){
    if(wordsToAnalyse.length==0)
        lexicalAnalyzer(null, true)
    token = wordsToAnalyse.shift()
    findToken(token.[https://www.commentcamarche.net/word/ word], token.row)
    console.log(partial_lexical_analysis)
    $('#result').append(partial_lexical_analysis.replace(/&/g, '&')
                                        .replace(/>/g, '>')
                                        .replace(/</g, '<')
                                        .replace(/\n/g,'<br/>'))
}


//Function that splits the code by breaklines and spaces to obtain the WORD
function lexicalAnalyzer(input, only_load) {

    lexical_analysis = "";
    var code;
    if (!input)
        code = document.getElementsByClassName("ace_text-input").value;
    else
        code = input;
    var lines = code.split(/\n/);
    for(var i = 0; i < lines.length; i++){
        var line = lines[i].replace(commentRegex, '');
        var words = splitWithIndex(line)
        for(let word of words){
            if(word.name != ""){
                if(!only_load){ //Sometimes we only need to load all the words but no do the analysis
                    findToken(word, i+1);
                    if(!partial_lexical_analysis.match(tokenList)){
                        i = Number.MAX_SAFE_INTEGER //Force break of two loops
                        break;
                    }
                }
                wordsToAnalyse.push({word:word, row: i+1})
            }
        }
    }
    if(!only_load){
        //console.log(lexical_analysis)
        $('#editor').html(code.replace(/\n/g,'<br/>'))
        $('#result').html(lexical_analysis.replace(/&/g, '&')
                                        .replace(/>/g, '>')
                                        .replace(/</g, '<')
                                        .replace(/\n/g,'<br/>'))
        return lexical_analysis;
    }
}


//Function that finds the token that matches that WORD, but only when it is an absolute match
/* fonction de correspondance entre les mots recuperés et les unités lexicaux definies.
Elle prend en entrée le mot(suite de caracteres) en question et la ligne coorespondante 


*/ 
function findToken(word, row){
   var matched = false;   
   for(let token of tokenList){       
     if(word.name.match(token.hardRegex)){
            matched = true;
            print(token, word.name, word.column, row)
            break;    
     }   
   }    
 if(!matched){       
  deepFindToken(word.name, row, word.column)  
 }
}

//Function that finds the token that matches one word, but only when it is within another onefunction 
deepFindToken(word, row, column) {  
  var matched = false;    
  var min_index_token = Number.MAX_SAFE_INTEGER;   
  var token_to_match=[]    
  var matched_word = [];    
  for (let token of tokenList) {      
    if (word.match(token.softRegex)) {          
      matched = true;           
     // Get index of the matched regexep           
     matched_word = token.softRegex.exec(word)           
     if (matched_word.index < min_index_token) {  
              min_index_token = matched_word.index; 
               token_to_match = token;
     }  else if(matched_word.index == min_index_token){
           if(token_to_match.softRegex.exec(word)[0] != matched_word[0])  
                  token_to_match = token;          
            }     
    } 
   }   
 if (matched) {        
    var matched_regexp = token_to_match.softRegex.exec(word)[0];       
     print(token_to_match, matched_regexp, column, row)     
     if (!(word === matched_regexp) && (matched_regexp.length != 0)) {           
         var cropped_word = word.replace(matched_regexp, '');          
         column += matched_regexp.length
            deepFindToken(cropped_word.trim(), row, column);
      }   
 } else {       
 partial_lexical_analysis = ">>> erreur lexical a la ligne:" + row + " et position: " + column + "\n"       
 lexical_analysis += partial_lexical_analysis   
 }}
//Function that splits by spaces and saves the column of the wordfunction splitWithIndex(line){    
var splits = line.split(/\[\]\s,;:\(\)\{\}/g,).map(item => {        return item.trim()        });    

var words=[]    var index=0    for(let split of splits){        if(split!=' ')            words.push({ column: index+1, name: split})        index += split.length + 1    }    return words}
//Function that prints the token
// fonction qui renvoit les unités lexicales
function print(token, word, column, row){   
 //for(let i =0;i<=token.length;i++){       
 if (token.print == "onlyWord")        
partial_lexical_analysis = "<" + word + "," + row + "," + column + ">\n";       
 else if (token.print == "onlyToken")           
partial_lexical_analysis =  "<" + token.name + "," + row + "," + column + ">\n";          
  else if (token.print == "wordAndToken")                
 partial_lexical_analysis = "<" + token.name + "," + word + "," + row + "," + column + ">\n";      
  lexical_analysis += partial_lexical_analysis;    //}   }
function testInputs(){    const input1 =`  
 var nom , prenom : chaine;    var naissance , age : entier;    
var sexe : caractere;    var statut : chaine;    const limit = 21;    debut        ecrire("entrez votre nom");        lire(nom);        afficher("entrez votre prenom");        lire(prenom);        lire("entrez votre année de naissance" naissance);        lire("entrez votre sexe" sexe);        age <-- 2021-naissance;        si(age<= limit){            statut <-- mineur;                return statut;            }            sinon                 {statut <-- majeur;                return statut;            }        finsi        ecrire(nom." ".prenom." etes age de ".age." et donc ".statut);    fin`;    console.log(lexicalAnalyzer(input1));  }


EDIT : Correction des balises de code ( ajout du LANGAGE )

2 réponses

Salut,
"Cannot read property '0' of null" ligne 173 donc cela vient d'une des valeurs indiqués sur cette ligne:

}  else if(matched_word.index == min_index_token){


Il n'y en a que 3 des valeurs:
matched_word
index
et min_dindex_token.

Hors la variable "index"(attribut d'objet plutôt vu la notation donc interne à un objet spécifique) est définie où?
Pour accèder à un tableau il suffit d'indiquer entre crochets l'index auquel on veut accéder:

var monTableau=['a','b','c'];
var monIndex=0;

console.log(monTableau[monIndex]);
/** va correspondre à l'index 0(la première valeur dans le tableau) du tableau nommé monTableau et affichera dans la console:
a

Par contre ceci n'existe pas pour un tableau donc est faux:
monTableau.monIndex

*/
//-- par contre on peut écrire ceci
var monObjet={
description="objet test",
index=1999
}

console.log(monObjet.index);
/** de la même façon(notation pointée qui correspond à la notation objet, les Array sont des objets mais spéciaux car fournis dans le langage.
*/
console.log(monObjet.description);


Mais ce qui m'intrique c'est que matched_word est d'abord définit comme un tableau puis prend la valeur suivante:

matched_word = token.softRegex.exec([https://www.commentcamarche.net/word/ word])

/** sans savoir ce que renvoi(et de quel "type" est la valeur renvoyée ) de la méthode softRegex de l'objet "token" dur de vous aider mais ça doit être un objet avec un attribut nommé "index" ou un tableau et donc dans ce cas utiliser la notation Array[entierNumerique] ou modifier le prototype de Array éventuellement pour qu'il existe un attribut index dedans(pas la meilleure façon de faire mais ça reste possible, pas la meilleure façon car il existe déjà une méthode qui fait ça la notation entrer crochets et qu'à part vous compliquer la vie pour rien ça sert à rien ici et que même il est encore mieux de définir un objet "ArraySpecifique" en utilisant l'héritage objet et créant un "enfant" de l'objet à modifier qui contiendra les propriétés de son parent + les méthodes plus spécifiques ou autres modifications nécessaires).

*/

Une méthode est une fonction interne à un objet(et accessible par cet objet et nulle part ailleurs : monObjet.maMéthode() ).
Un attribut(toujours en programmation objet) est une variable interne à un objet.

Donc si "token.softRegex.exec(word)" n'affecte pas un tableau en valeur retour de la méthode "matched_word" ne sera plus un tableau(une des particularités de JavaScript qui est dit language "non typé" et donc permet de changer le type d'une variable, il faut donc faire attention à garder l'intégrité de la variable(son type ici un objet Array) soi même parce que le programme ne le fait pas.).

Pour ajouter une valeur dans un tableau il faut utiliser la méthode Array.push(ajoutDansTableau) sinon il n'y aura pas d'index ou ce ne sera pas cohérent(une chaîne de caractères a un index mais ça correspond à un caractère de la chaîne de la même façon qu'un tableau indique plusieurs valeurs ).

https://www.w3schools.com/jsref/jsref_push.asp


Notes:
1)Attention aussi à utiliser l'égalité stricte dans une comparaison ("===" et non "==") si c'est pour comparer des données strictement identiques.

2)Un IF puis else if et else if ... c'est pas très pratique(ça complique tout) et ça implique facilement une erreur, rarement une bonne façon d'écrire du code(car trop complexe à lire et modifier, trouver les erreurs et plus long à écrire).
Il vaut mieux éviter ce genre de structure et utiliser un switch ou une autre méthode(comme des étapes en subdivisant les tests logiques où c'est nécessaire- ce sera pas
SI ALORS SINON A SINON B etc...
mais
SI ALORS RESULTAT1 SINON RESULTAT2 et l'étape suivante traite le résultat que ce soit RESUTLAT1 ou RESULTAT2 avec un simple if en considérant la "mutation des données" renvoyée par chauqe test..

Ici un switch semble approprié et la méthode de traiter la mutation des données beaucoup moins parce que le test est uniquement sur une valeur qui peut avoir plusieurs états possibles = "only word" ,"onlyToken", "word and token" , ou aucune des trois précédentes.(4 états ou valeurs de variable pertinentes et possibles dans le programme, le quatrième indique une valeur qui ne peut-être traitée donc une erreur possible ou une exception-qu'il faudra alors traiter en tant que tel, soit erreur(ex: la valeur doit être obligatoirement word, token ou les 2 mais pas aucune des 3) soit exception.

https://www.w3schools.com/js/js_switch.asp
1
Djakweb Messages postés 2 Date d'inscription samedi 5 septembre 2020 Statut Membre Dernière intervention 4 mai 2021
Modifié le 4 mai 2021 à 14:57
Merci beaucoup pour l'aide que tu m'as apporté et surtout les conseils. J'ai intégré le Switch a la fonction print() mais la boucle ne parcours toujours pas toutes les valeurs possibles.
0
Déjà avez vous corrigé toutes vos erreurs? Et choisit quel "type" d'élément(objet personnalisé,objet de type primaire comme un tableau ou une chaîne de caractères).

Votre code est lacunaire(il manque une partie soit dans votre développement soit que vous ne montrez pas ici, c'est la méthode ".softRegex.exec(word)" par exemple qui n'est décrite nulle part et donc n'existe pas sauf dans un fichier externe éventuel et que vous ne fournissez pas dans ce cas impossible de dire quoique ce soit) et truffé d'erreurs potentielles(on peut pas savoir en l'abse,ce de l'intégralité du code) ou d'erreurs factuelles(utiliser une logique d'Array sur un élément autre qu'n Array ne peut pas fonctionner, sauf si prévu par le programme interchangeabilité des données-et c'est l'une des forces d'un langage non typé comme JS , force qui peut être aussi un inconvénient comme indiqué dans mon message précédent).

Vous devez déjà avoir un code corrigé et fonctionnel(sans erreur et avec la logique/algorithme adapté aux éléments/données/types traités).

Si vous voulez parcourir autre chose qu'un tableau vous avez la méthode forEach qui n'aura pas besoin d'index ou même les operateurs itératifs en JS6 et > et ce sont loin d'être les seules façon de faire.

Ensuite avec un code sans erreurs et avec le bon raisonnement/structure-algorithme- publiez de nouveau votre code si il ne fait pas ce que vous voulez... mais bon déjà vous aurez quelque chose qui peut fonctionner et donc aucune raison que le problème ne soit pas résolu à ce moment.

C'est très simple l'informatique, binaire si j'ose dire et donc beaucoup plus simpliste qu'n raisonnement humain.
Considérez qu'écrire un programme c'est s'adresser à un enfant de 3 mois incapable d'apprendre car il faudra lui répéter tout à chaque fois.
Bien sûr n'importe quel système électronique ou programme informatique est beaucoup moins évolué que le cerveau d'un enfant de 3mois ou d'une sauterelle donc vous devez lui fournir tout ce dont il a besoin et correctement formaté/typé si vous comptez obtenir un résultat.

C'est une image mais c'est factuellement vrai:
Si vous demandez quelle est la couleur du cheval blanc d'Henri IV à un ordinateur il faut d'abord lui expliquer ce qu'est une couleur voire un cheval sinon vous n'aurez pas possibilité d'avoir une réponse.
Ici vous avez pris des raccourcis en pensant en logique humaine qui peut raisonner et tirer une conclusion j'ai l'impression.
Un ordinateur ne le peut simplement pas et si vous lui dites analyse moi un tableau il faut spécifier les critères et bien sûr avoir un tableau, est ce fait? et est ce qu'un tableau est la bonne façon de structurer les informations à traiter?

Dans ce cas vous devez avoir un nouveau code.
Donc mettez le ici si vous n'avez pas le résultat escompté parce que on est dans un domaine technique et que sinon c'est de la voyance et ça ne marche pas la divination il me semble^^.
0