public static void initGrammar() { lambda = new Terminal("lambda"); identifier = new Identifier("identifier"); constant = new Constant("constant"); myString = new MyString("string"); control = new ControlType("control"); selector = new Selector("selector"); myProperty = new MyProperty("property"); all = new All(); program = new NotTerminal("PROGRAM"); }
/** * pre: balise != null && balise.length > 2 * @param balise * @return */ private Symbol nextSymbol(String balise) { char c1 = balise[0]; char cn = balise[balise.Length - 1]; String name = balise.Substring(1, balise.Length - 2); //System.Console.WriteLine(name + " - " + c1 +" - " + cn); // La balise est un terminal if (c1 == '\'' && cn == '\'') { Terminal symbol; // Si le symbole ne se trouve pas dans la map des terminal, on l'ajoute. if (!terminalMap.ContainsKey(name)) { symbol = new Terminal(name); terminalMap.Add(name, symbol); } else { symbol = terminalMap[name]; } return(symbol); } // La balise est un non terminal else if (c1 == '<' && cn == '>') { NotTerminal symbol; // Si le symbole ne se trouve pas dans la map des non terminal, on l'ajoute. if (!notTerminalMap.ContainsKey(name)) { symbol = new NotTerminal(name); notTerminalMap.Add(name, symbol); } else { symbol = notTerminalMap[name]; } return(symbol); } else { // La balise n'est pas contenue entre '' et <> donc est invalide throw new ParserException("Erreur dans la syntaxe de la grammaire: la balise '" + balise + "' n'est pas entre '' ou <>"); } }
/** * Génère la table de parsing de la grammaire G * dans le tableau à deux dimensions ParsingTable * * @pre Les ensembles p1 de chaque symboles de la grammaire G doivent etre calculés * @pre Les ensembles s1 de chaque symbole de la grammaire G non étendue doivent etre calculés */ public void GenerateParsingTable() { /* * Comme fait au cours, on va créer un tableau en deux dimensions * de taille NonTerminalList.size() et TerminalList.size(). * Le but de ce tableau est de savoir quel règle choisir en fonction * du non terminal courant sur la stack et le symbol lu dans le code * source. * * Soit A -> alpha, pour chaque élément "a" de p1(alpha) * on définit table[A, a] : A -> alpha. * * Si lambda est contenu dans p1(alpha), on va aller voir AUSSI dans * l'ensemble s1(alpha) qui sont les terminaux pouvant se trouver après A * puisque p1(alpha) peut etre vide. On fera donc: * Pour tout b dans s1(A): table[A, b] : A -> alpha */ //Rule[,] table = new Rule[G.NotTerminals().Count(), G.Terminals().Count()]; //Console.WriteLine("Taille table: " + G.NotTerminals().Count() + " et " + G.Terminals().Count()); Rule[,] table = new Rule[NotTerminal.NotTerminalIndex + 1, Terminal.TerminalIndex + 1]; // Parcours des règles foreach (Rule r in G.Rules()) { // On définit A -> alpha NotTerminal A = r.Left(); LinkedList <Symbol> alpha = r.Right(); // On récupère l'ensemble p1(alpha) // On est certain d'avoir un résultat car tous les ensembles // p1 ont été calculés précédement. bool isLambda = false; // Pour chaque "premier terminal" pouvant etre obtenu en dérivant A // On crée table[A, a] : A -> aplha sauf si "a" == Lambda foreach (Terminal a in G.MergeSets(alpha)) { if (a == Grammar.lambda) { isLambda = true; } else { //Console.WriteLine(A + " (" + A.Index() + ") - " + a+ " (" + a.Index() + ")"); table[A.Index(), a.Index()] = r; //System.out.println("table[" + A.getText() + ", " + a.getText() + "] = " + r); } } // Si on a découvert un lambda dans p1(alpha), on va aussi // ajouter les éléments de s1(A) à la liste. if (isLambda) { // Pour tous les terminaux "b" suivant A on fait: // table[A, b] : A -> alpha foreach (Terminal b in A.S1()) { table[A.Index(), b.Index()] = r; //System.out.println("table[" + A.getText() + ", " + b.getText() + "] = " + r); } } } parsingTable = table; }
/** * Vérifie que la première condition pour qu'une grammaire soit LL1 * est correcte. * * @pre Les ensembles P1 de chaque symbole de la grammaire G doivent être calculés. */ public void CheckCondition1() { /* * Cette méthode vérifie que la grammaire G respecte la première condition * LL1 à savoir pour chaque non terminal X, il ne peut pas exister de * dérivations différentes o et o' de X telle que l'intersection de * p1(o) et p1(o') est non vide. En pratique celà pose problème car * il y aura une incohérence lors de la génération de la table de parsing. * * Le principe est simple on crée une relation NotTerminal -> Set of Derivations * Ensuite, pour chaque non terminal, on vérifie qu'aucun * ensemble p1 de ses dérivations ne possède un meme terminal. */ // Génération de la relation NotTerminal -> Ensemble de dérivations if (allLeftNotTerminals == null) { GenerateAllLeftNotTerminal(); } // Soit x -> Y1 | Y2 | .. | Yn // Pour chaque dérivation Yi, on vérifie que l'intersection de p1(Yi) et p1(Yj), // où j>i, est vide. foreach (KeyValuePair <NotTerminal, HashSet <Rule> > entry in allLeftNotTerminals) { NotTerminal x = entry.Key; HashSet <Rule> Y = entry.Value; //System.Console.WriteLine("NonTer: " + x); // Pour chaque Yi int i = 1; foreach (Rule r in Y) { HashSet <Terminal> P1Yi = G.MergeSets(r.Right()); //System.Console.WriteLine("R1: " + r); int j = 1; foreach (Rule r2 in Y) { // Pour chaque Yj où j>i if (j <= i) { j++; continue; } //System.Console.WriteLine("R2: " + r2); HashSet <Terminal> P1Yj = G.MergeSets(r2.Right()); // Intersection de p1(Bi) et p1(Bj) vide ? foreach (Terminal t in P1Yj) { if (P1Yi.Contains(t)) { throw new ParserException("Le non terminal '" + x + "' possède deux dérivations ayant des éléments de p1 identiques: " + " " + t); } } } i++; } } }
public Rule(NotTerminal left, LinkedList <Symbol> right) { this.left = left; this.right = right; }
public void ComputeExtendedRules() { Dictionary <String, NotTerminal> notTerminalNames = new Dictionary <String, NotTerminal>(); // Program' -> lambda LinkedList <Symbol> right = new LinkedList <Symbol>(); right.AddLast(lambda); NotTerminal program2 = new NotTerminal(Grammar.program.GetText() + "'"); extendedRules = new LinkedList <Rule>(rules); extendedRules.AddLast(new Rule(program2, right)); // Program est son propre symbole étendu extendedSymbols.Add(program, program2); // Pour chaque règle, on va créer un symbole étendu // du symbole de gauche. // Y -> alpha X beta // X2 -> beta Y2 foreach (Rule p in rules) { right = new LinkedList <Symbol>(p.Right()); NotTerminal left = p.Left(); //System.Console.WriteLine("Rule - " + p); while (right.Count() > 0) { Symbol symbol = right.First(); right.RemoveFirst(); if (symbol is NotTerminal) { NotTerminal X = (NotTerminal)symbol; // Si on a une règle du style X' -> X', on ne l'ajoute pas if (X == left && right.Count() < 1) { continue; } String X2_Name = X.GetText() + "'"; String Y2_Name = left.GetText() + "'"; NotTerminal X2; if (!notTerminalNames.ContainsKey(X2_Name)) { // Le non terminal étendu X' n'existe pas, on le crée X2 = new NotTerminal(X2_Name); // On l'ajoute à la map qui établit la relation name <--> symbole notTerminalNames.Add(X2_Name, X2); // On ajoute ce nouveau non terminal à la liste des non terminaux notTerminalList.AddLast(X2); } else { X2 = notTerminalNames[X2_Name]; } NotTerminal Y2; if (!notTerminalNames.ContainsKey(Y2_Name)) { // Le non terminal étendu X' n'existe pas, on le crée Y2 = new NotTerminal(Y2_Name); // On l'ajoute à la map qui établit la relation name --> symbole notTerminalNames.Add(Y2_Name, Y2); // On ajoute ce nouveau non terminal à la liste des non terminaux notTerminalList.AddLast(Y2); } else { Y2 = notTerminalNames[Y2_Name]; } // On crée la partie de droite de la règle définissant X2 LinkedList <Symbol> X2_Right = new LinkedList <Symbol>(right); X2_Right.AddLast(Y2); // On ajoute enfin la nouvelle règle créée extendedRules.AddLast(new Rule(X2, X2_Right)); // On définit la relation Symbole --> Symbole étendu //System.Console.WriteLine("NewRule - " + new Rule(X2, X2_Right)); //System.Console.WriteLine("Sym --> SymEtend - " + X + " -> " + X2); if (!extendedSymbols.ContainsKey(X)) { extendedSymbols.Add(X, X2); } } } } }