PageRenderTime 118ms CodeModel.GetById 18ms app.highlight 92ms RepoModel.GetById 2ms app.codeStats 0ms

/src/grammar.cpp

https://bitbucket.org/lippo/spanalyzer
C++ | 916 lines | 790 code | 74 blank | 52 comment | 179 complexity | decf0554d5d6cf003c2350b4815f74b2 MD5 | raw file
  1#include "grammar.h"
  2#include <QFile>
  3#include <QString>
  4#include <QTextStream>
  5#include <QHash>
  6#include <QHashIterator>
  7#include <QStringList>
  8#include <QRegExp>
  9#include <QTreeWidget>
 10#include <QTreeWidgetItem>
 11#include <QDebug>
 12#include <QTime>
 13
 14#include <lexem.h>
 15#include <lexer.h>
 16
 17
 18Grammar::Grammar()
 19{
 20    lastNonTerminal = QString();
 21    axiom = QString();
 22    hash = QHash<QString, QList<QList<term> > >();
 23    hash_NoEpsilon = QHash<QString, QList<QList<term> > >();
 24    firstSets = new QHash<QString, QList<QStringList> >;
 25    followSets = new QHash<QString, QList<QStringList> >;
 26    epsilonNonTerminals = QStringList();
 27    K = 1;
 28    K2 = 1;
 29    lex = Lexer();
 30    errorAt = -1;
 31    errorInd = -1;
 32    unattainableNonTerminals = QStringList();
 33    rightRecursion = QStringList();
 34}
 35
 36int Grammar::ReadFromFile(QString fileName)
 37{
 38    // returns 0 - if okay
 39    // line number - if errors
 40    this->allNonTerminals.clear();
 41    this->allTerminals.clear();
 42    this->axiom.clear();
 43    this->hash.clear();
 44    this->hash_NoEpsilon.clear();
 45    this->epsilonNonTerminals.clear();
 46    this->firstSets->clear();
 47    this->followSets->clear();
 48    this->K = 1;
 49
 50    QFile file(fileName);
 51    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
 52        return -1;
 53
 54    QTextStream in(&file);
 55    int lineNum = 1;
 56
 57    // process first line and ramember the axiom
 58    QString line = in.readLine();
 59    if(!ProcessLine(line))
 60            return lineNum;
 61    QHashIterator<QString, QList<QList<term> > > it(hash);
 62    if(!it.hasNext())
 63        return -1;
 64    it.next();
 65    this->axiom = it.key();
 66
 67    while (!in.atEnd()) {
 68        QString line = in.readLine();
 69        if(!ProcessLine(line))
 70            return lineNum;
 71        lineNum++;
 72    }
 73    file.close();
 74    return 0;
 75}
 76
 77bool Grammar::ProcessLine(QString line)
 78{
 79    /* returns true if line was processed without errors; */
 80    if(line.trimmed().isEmpty() || line.startsWith(";"))
 81        return true;
 82    bool continueLastLine = false;
 83
 84    // *parse left part*
 85    int ind = 1;
 86    if(line.startsWith('#')) {
 87        ind = line.indexOf('#', 1) + 1;
 88        lastNonTerminal = UnShield(line.mid(0,ind));
 89        if(!this->allNonTerminals.contains(lastNonTerminal))
 90            this->allNonTerminals.append(lastNonTerminal);
 91    }
 92    else if(line[0].isSpace()) {
 93        continueLastLine = true;
 94    }
 95    line = line.mid(ind).trimmed();
 96
 97    // *parse right part*
 98    // split apart
 99    QStringList parts = line.split(QRegExp("\\s"), QString::SkipEmptyParts);
100    for(int i=0; i<parts.length(); i++) {
101        if(parts[i].startsWith('#') && !parts[i].endsWith('#')) {
102            while(i<parts.length()-1 &&
103                  (!parts[i].endsWith('#') || parts[i].endsWith("\\#")))
104            {
105                parts[i].append(" "+parts[i+1]);
106                parts.removeAt(i+1);
107            }
108            if(!parts[i].endsWith('#') || parts[i].endsWith("\\#"))
109                return false;
110        }
111    }
112
113    // make list of [non]terminals form right part
114    QList<term> right;
115    foreach(QString part, parts) {
116        QString s = UnShield(part);
117        if(part.startsWith('#')) {    // NonTerminal
118            right.append(MakeNonTerm(s));
119            if(!this->allNonTerminals.contains(s))
120                this->allNonTerminals.append(s);
121        }
122        else {      // Terminal
123            right.append(MakeTerm(s));
124            if(!this->allTerminals.contains(s))
125                this->allTerminals.append(s);
126        }
127    }
128    if(right.isEmpty())
129        right.append(MakeTerm(""));
130
131    //QHash<QString, QList<QList<Term> > >::iterator it = ;
132    QList<QList<term> > list = hash.take(lastNonTerminal);
133    if(continueLastLine && !list.isEmpty()) {
134        list.last().append(right);
135    }
136    else {
137        list.append(right);
138    }
139    hash.insert(lastNonTerminal, list);
140    return true;
141}
142
143QString Grammar::ToText()
144{
145    QString res;
146    QHashIterator<QString, QList<QList<term> > > it(hash);
147    while (it.hasNext()) {
148        it.next();
149        foreach(QList<term> termList, it.value()) {
150            res.append(it.key()+" -> ");
151            foreach(term t, termList)
152                res.append(t.s + " ");
153            res.append('\n');
154        }
155    }
156    return res;
157}
158
159QString Grammar::ToText2(QHash<QString, QList<QStringList> > * F)
160{
161    QString res;
162    foreach(QString A, hash.uniqueKeys()) {
163        QString a = A.mid(1, A.length()-2);
164        res.append(a+"\t[");
165        foreach(QStringList sl, F->value(A)) {
166            res.append("[");
167            foreach(QString s, sl) {
168                res.append("'"+s+"'"+", ");
169            }
170            if(res.endsWith(", "))
171                res = res.mid(0, res.length() -2);
172            res.append("], ");
173        }
174        if(res.endsWith(", "))
175            res = res.mid(0, res.length() -2);
176        res.append("]\n");
177    }
178    return res;
179}
180
181QList<QTreeWidgetItem *> Grammar::GetTreeItems(QTreeWidget *treeWidget)
182{
183    QList<QTreeWidgetItem *> treeItems;
184    QHashIterator<QString, QList<QList<term> > > it(hash);
185    while (it.hasNext()) {
186        it.next();
187        QTreeWidgetItem *parent = new QTreeWidgetItem(treeWidget, QStringList(it.key()));
188        if(this->unattainableNonTerminals.contains(it.key())) {
189            parent->setBackgroundColor(0, QColor("blue"));
190        }
191        if(this->rightRecursion.contains(it.key())) {
192            if(this->unattainableNonTerminals.contains(it.key()))
193                parent->setBackgroundColor(0, QColor("green"));
194            else
195                parent->setBackgroundColor(0, QColor("yellow"));
196        }
197
198        QList<QTreeWidgetItem *> alternatives;
199        foreach(QList<term> termList, it.value()) {
200            QString rule;
201            foreach(term t, termList) {
202                rule.append(" " + t.s);
203            }
204            alternatives.append(new QTreeWidgetItem(parent, QStringList(rule)));
205        }
206        treeItems.append(alternatives);
207    }
208    return treeItems;
209}
210
211QList<QTreeWidgetItem *> Grammar::GetFIRSTOrFOLLOWTreeItems(QTreeWidget *treeWidget,
212                                      QHash<QString, QList<QStringList> > * set)
213{
214    QList<QTreeWidgetItem *> treeItems;
215    QHashIterator<QString, QList<QStringList> > it(*set);
216    while (it.hasNext()) {
217        it.next();
218        QTreeWidgetItem *parent = new QTreeWidgetItem(treeWidget, QStringList(it.key()));
219        QList<QTreeWidgetItem *> alternatives;
220        foreach(QStringList sl, it.value()) {
221            QString rule;
222            foreach(QString s, sl) {
223                rule.append(" " + s);
224            }
225            alternatives.append(new QTreeWidgetItem(parent, QStringList(rule)));
226        }
227        treeItems.append(alternatives);
228    }
229    return treeItems;
230}
231
232term Grammar::MakeTerm(QString str)
233{
234    term t(str, true);
235    return t;
236}
237
238term Grammar::MakeNonTerm(QString str)
239{
240    term t(str, false);
241    return t;
242}
243
244QStringList Grammar::GetNonProductiveNonTerminals()
245{
246    // Get names of non-productive nonterminals
247
248    QList<QString> nonTerminals = hash.uniqueKeys();
249    //QSet<QString> ...; // better performance but uncomfortable, use QStringList
250    QStringList productive, maybeProductive, nonProductive;
251
252    // build the list of non-terminals that produce terminals: "productive"
253    // and the list of all others non-terminals: "maybeProductive"
254    bool allTerms = true;
255    foreach(QString s, nonTerminals) {
256        QList<QList<term> > lists = hash.find(s).value();
257        foreach(QList<term> list, lists) {
258            allTerms = true;
259            foreach(term t, list) {
260                if(!t.isTerminal) {
261                    allTerms = false;
262                    break;
263                }
264            }
265            if(allTerms)
266                productive.append(s);
267            else
268                maybeProductive.append(s);
269        }
270    }
271    productive.removeDuplicates();
272    maybeProductive.removeDuplicates();
273
274    bool changes = true;
275    while (changes) {
276        changes = false;
277        foreach(QString tn, maybeProductive) {
278            if(productive.contains(tn)) { // just for confidence
279                maybeProductive.removeAll(tn);
280                continue;
281            }
282            QList<QList<term> > lists = hash.find(tn).value();
283            foreach(QList<term> list, lists) {
284                bool flag = true;
285                foreach(term t, list) {
286                    if(!t.isTerminal && !productive.contains(t.s)) {
287                        flag = false;
288                        break;
289                    }
290                }
291                if(flag) {
292                    productive.append(tn);
293                    maybeProductive.removeAll(tn);
294                    changes = true;
295                    break;
296                }
297            }
298        }
299    }
300
301    // Select non-terminals in RIGHT part that have got no rules
302    // in hash (in grammar) at all
303    QHashIterator<QString, QList<QList<term> > > it(hash);
304    while (it.hasNext()) {
305        it.next();
306        foreach(QList<term> list, it.value()) {
307            foreach(term t, list) {
308                if(!t.isTerminal && !hash.contains(t.s))
309                    nonProductive.append(t.s);
310            }
311        }
312    }
313    nonProductive += maybeProductive;
314    nonProductive.removeDuplicates();
315    return nonProductive;
316}
317
318QStringList Grammar::GetUnattainableNonTerminals()
319{
320    /* no recursion here  */
321    // build the list of attainable nonterminals
322    int i = 0;
323    QStringList attainable(this->axiom); // list of attainable nonterminals
324    while(i < attainable.length()) {
325        QList<QList<term> > lists = hash.find(attainable[i]).value();
326        foreach(QList<term> list, lists) {
327            foreach(term t, list) {
328                if(!t.isTerminal && !attainable.contains(t.s))
329                    attainable.append(t.s);
330            }
331        }
332        i++;
333    }
334
335    // all nonterminals minus attainable
336    QSet<QString> unattainable(this->allNonTerminals.toSet());
337    unattainable.subtract(attainable.toSet());
338
339    this->unattainableNonTerminals = unattainable.toList();
340    return this->unattainableNonTerminals;
341}
342
343void Grammar::RemoveEpsilonRules()
344{
345    this->hash_NoEpsilon = this->GetGrammarWithoutEpsilonRules();
346}
347
348QHash<QString, QList<QList<term> > > Grammar::GetGrammarWithoutEpsilonRules()
349{
350    QHash<QString, QList<QList<term> > > res(hash);
351    bool noEpsilon = false;
352    while(!noEpsilon) {
353        noEpsilon = true;
354        QStringList keys = res.uniqueKeys();
355        foreach(QString key, keys) {
356            QList<QList<term> > lists = res.find(key).value();
357            foreach(QList<term> list, lists) {
358                if(list.isEmpty()) {  // epsilon rule found
359                    noEpsilon = false;
360                    this->_EpsilonRuleFound(key, &res);
361                    break;
362                }
363            }
364            if(!noEpsilon)
365                break;
366        }
367    }
368    return res;
369}
370
371void Grammar::_EpsilonRuleFound(QString s, QHash<QString, QList<QList<term> > > *newHash)
372{
373    bool flag = false;
374    QStringList keys = newHash->uniqueKeys();
375
376    QList<QList<term> > a = newHash->find(s).value();
377    if(a.length() == 1 && a[0].isEmpty()) {
378        newHash->remove(s);
379        flag = true;
380    }
381    else {
382        int i = 0;
383        while(i<a.length()) {
384            if(a[i].isEmpty()) {
385                a.removeAt(i);
386            }
387            else
388                i++;
389        }
390        newHash->insert(s, a);
391    }
392
393
394    foreach(QString key, keys) {        
395        if(key == s)
396            continue;
397
398        QList<QList<term> > lists = newHash->find(key).value();
399
400        for(int i=0; i<lists.length(); i++) {
401            if(lists[i].contains(MakeNonTerm(s))) {
402                QList<term> l = lists[i];
403                l.removeAll(MakeNonTerm(s));
404                if(flag)
405                    lists.replace(i, l);
406                else
407                    lists.append(l);
408                newHash->insert(key, lists);
409            }
410        }
411    }
412}
413
414QStringList Grammar::FindRightRecursion()
415{
416    QStringList res;
417    foreach(QString N, this->hash.uniqueKeys()) {
418        if(TestForRightRecursion(N))
419            res.append(N);
420    }
421    this->rightRecursion = res;
422    return this->rightRecursion;
423}
424
425bool Grammar::TestForRightRecursion(QString X)
426{
427    if(this->epsilonNonTerminals.isEmpty())
428        this->FindEpsilonNonTerminals();
429    if(_isTerminal(X))
430        return false;
431
432    QStringList l;  // TODO!!
433    // S0
434    foreach(QList<term> rule, this->hash.value(X)) {
435        QStringList strRule = this->Rule2StringList(rule);
436        for(int i=rule.length()-1; i>=0; i--) {
437            if( !this->TurnsIntoEpsilon(rule.mid(i+1)) )
438                break;
439            if( !rule[i].isTerminal ) {
440                l.append(rule[i].s);
441            }
442        }
443    }
444    if( l.contains(X) )
445        return true;
446
447    // Si
448    QStringList newL;
449    foreach(QString S, l) {
450        newL.clear();
451        foreach(QList<term> rule, this->hash.value(S)) {
452            QStringList strRule = this->Rule2StringList(rule);
453            for(int i=rule.length()-1; i>=0; i--) {
454                if( i<rule.length()-1 && !this->TurnsIntoEpsilon(rule.mid(i+1, 1)) )
455                    break;
456                if( !rule[i].isTerminal ) {
457                    newL.append(rule[i].s);
458                }
459            }
460        }
461        if( newL.contains(X) )
462            return true;
463        l.append(newL);
464    }
465    return false;
466}
467
468QString Grammar::UnShield(QString s)
469{
470    return s.replace("\\#", "#").replace("\\\\","\\").replace("\\!", "!");
471}
472
473bool Grammar::BuildFIRST(unsigned K)
474{
475    this->K = (int)K;
476    firstSets->clear();
477    foreach(QString nonTerminal, this->allNonTerminals)
478        firstSets->insert(nonTerminal, MakeF0(nonTerminal, K));
479
480    bool changes = true;
481    while(changes) {
482        changes = false;
483        QHash<QString, QList<QStringList> > newFirst = *firstSets;
484        foreach(QString nonTerminal, this->allNonTerminals) {
485            QList<QStringList> Fn = MakeFn(nonTerminal, K);
486            newFirst.insert(nonTerminal, Fn);
487            if(!_cmpFirsts(firstSets->value(nonTerminal), Fn))
488                changes = true;
489        }
490
491        *firstSets = newFirst;  // ?
492    }
493
494
495    // For K==1 only:
496//    bool changes = true;
497//    while(changes) {
498//        changes = false;
499//        QHash<QString, QList<QStringList> > * newFirstSets = new
500//                                          QHash<QString, QList<QStringList> >;
501//
502//        foreach(QString key, this->allNonTerminals) {
503//            QList<QStringList> *newSet = new QList<QStringList>;
504//            foreach(QList<term> rule, hash[key]) { // ???
505//                QList<QStringList> newSubSet = firstSets->value(key);
506//                bool stop = false;
507//                for(int i=0; i<rule.length() && !stop; i++) {
508//                    if(rule[i].isTerminal)
509//                        newSubSet = _terminalExpansion(newSubSet, rule[i].s, K, &stop);
510//                    else
511//                        newSubSet = _nonTerminalExpansion(newSubSet,
512//                                                firstSets->value(rule[i].s),
513//                                                firstSets->value(key), K, &stop);
514//                }
515//                newSet->append(newSubSet);
516//            }
517//            newFirstSets->insert(key, *newSet);
518//        }
519//        this->firstSets = newFirstSets;
520//    }
521    return true;
522}
523
524bool Grammar::_cmpFirsts(QList<QStringList> F1, QList<QStringList> F2)
525{
526    if(F1.length() != F2.length())
527        return false;
528
529    foreach(QStringList f1, F1) {
530        if(!F2.contains(f1))
531            return false;
532        F2.removeAll(f1);
533    }
534    foreach(QStringList f2, F2)
535        if(!F1.contains(f2))
536            return false;
537    return true;
538}
539
540QList<QStringList> Grammar::MakeF0(QString A, int K)
541{
542    QList<QStringList> res;
543    if(this->_isTerminal(A)) {
544        res.append(QStringList(A));
545        return res;
546    }
547
548    foreach(QList<term> rule, hash[A]) {
549        int count = 0;
550        while(count<rule.length() && rule[count].isTerminal && count <= K)
551            count++;
552
553        bool eps = (rule.length() == count)? true:false ;
554        if((count==K && !eps) || (count<=K && eps)) {
555            res.append(Rule2StringList(rule.mid(0, count)));
556        }
557    }
558    return res;
559}
560
561QList<QStringList> Grammar::MakeFn(QString A, int K)
562{
563    QList<QStringList> res;
564    foreach(QList<term> rule, hash[A]) {
565        QList<QStringList> ruleRes;
566        bool undef = false;
567        int i;
568        for(i=0; i<rule.length(); i++) {
569            QList<QStringList> F = FIRST(rule[i].s);
570            if(F.isEmpty()) {
571                undef = true;
572                break;
573            }
574            int flag = 0;
575            ruleRes = SumK(ruleRes, F, K, &flag); // ?
576            if(flag)
577                break;
578        }
579
580        if(!undef)
581            res.append(ruleRes);
582    }
583    res.append(FIRST(A));
584    return this->_removeDuplicates(res);
585}
586
587QList<QStringList> Grammar::SumK(QList<QStringList> L1, QList<QStringList> L2,
588                                 int K, int *flag)
589{
590    QList<QStringList> res;
591    if(flag != NULL) *flag = 1;
592    foreach(QStringList l1, L1)
593        foreach(QStringList l2, L2)
594            res.append(l1+l2);
595
596    if(L2.isEmpty())
597        res = L1;
598    if(L1.isEmpty())
599        res = L2;
600    for(int i=0; i<res.length(); i++) {
601        if(res[i].length() > 1) {
602            if(res[i].count("") == res[i].length()) {
603                res[i].clear();
604                res[i].append("");
605            }
606            else
607                res[i].removeAll("");
608        }
609        while(res[i].length() > K)
610            res[i].removeLast();
611        if( flag != NULL && res[i].length() != K && !res[i].first().isEmpty() )
612            *flag = 0;
613    }
614    res = this->_removeDuplicates(res);
615    return res;
616}
617
618bool Grammar::BuildFOLLOW(unsigned K2)
619{
620    this->K2 = (int)K2;
621    this->followSets->clear();
622    foreach(QString nonTerminal, this->allNonTerminals)
623        followSets->insert(nonTerminal, QList<QStringList>() );
624    QList<QStringList> eps;
625    eps.append(QStringList(""));
626    followSets->insert(this->axiom, eps);
627
628    bool changes = true;
629    while(changes) {
630        changes = false;
631        QHash<QString, QList<QStringList> > newFollow = *followSets;
632        foreach(QString nonTerminal, this->allNonTerminals) {
633            QList<QStringList> followAj = followSets->value(nonTerminal);
634            if(followAj.isEmpty())
635                continue;
636            foreach(QList<term> rule, hash[nonTerminal]) {
637                for(int i=0; i<rule.length(); i++) {
638                    if(rule[i].isTerminal)// || rule[i].s == nonTerminal) // !!
639                        continue;
640                    QList<QStringList> firstW2 = FIRST(Rule2StringList(rule.mid(i+1)), K2);
641                    for(int i=0; i<firstW2.length(); i++) {
642                        while(firstW2[i].length() > (int)K2)
643                            firstW2[i].removeLast();
644                    }
645                    firstW2 = this->_removeDuplicates(firstW2);
646
647                    QList<QStringList> toInsert = SumK(firstW2, followAj, (int)K2, NULL);
648                    toInsert.append(followSets->value(rule[i].s));  // todo
649                    toInsert = this->_removeDuplicates(toInsert);
650
651                    if(!_cmpFirsts(followSets->value(rule[i].s), toInsert)) {
652                        changes = true;
653                        newFollow.insert(rule[i].s, toInsert );
654                    }
655                }
656            }
657        }
658        *followSets = newFollow;
659    }
660    return true;
661}
662
663QStringList Grammar::Rule2StringList(QList<term> rule)
664{
665    QStringList res;
666    for(int i=0; i<rule.length(); i++) {
667        res.append(rule[i].s);
668    }
669    return res;
670}
671
672bool Grammar::FindEpsilonNonTerminals()
673{
674    QStringList res;
675    QStringList keys = this->hash.uniqueKeys();
676
677    // S0
678    foreach(QString key, keys) {
679        foreach(QList<term> rule, this->hash.value(key)) {
680            if(rule.length() == 1 && rule[0].isTerminal && rule[0].s.isEmpty()) {
681                res.append(key);
682                continue;
683            }
684        }
685    }
686    //Si
687    bool flag = true;
688    bool changes = true;
689    while(changes) {
690        changes = false;
691        QStringList toAppend;
692        foreach(QString key, keys) {
693            foreach(QList<term> rule, this->hash.value(key)) {
694                flag = true;
695                if( rule.length() == 1 && rule[0].s == "") {
696                    flag = false;  // the key is allreary in res list
697                }
698                foreach(term t, rule) {
699                    if((t.isTerminal  && !t.s.isEmpty()) ||
700                       (!t.isTerminal && !res.contains(t.s)) )
701                    {
702                        flag = false;
703                        break;
704                    }
705                }
706                if(flag && !res.contains(key) && !toAppend.contains(key)) {
707                    toAppend.append(key);
708                    changes = true;
709                }
710            }
711        }
712        res.append(toAppend);
713    }
714
715    res.removeDuplicates();
716    this->epsilonNonTerminals = res;
717    return true;
718}
719
720bool Grammar::TurnsIntoEpsilon(QString X)
721{
722    if(this->_isTerminal(X))
723        return X.isEmpty();
724    return this->epsilonNonTerminals.contains(X);
725}
726
727bool Grammar::TurnsIntoEpsilon(QList<term> X)
728{
729    foreach(term t, X) {
730        if( (t.isTerminal && !t.s.isEmpty()) ||
731            (!t.isTerminal && !this->epsilonNonTerminals.contains(t.s)) )
732        {
733            return false;
734        }
735    }
736    return true;
737}
738
739QList<QStringList> Grammar::FIRST(QString X)
740{
741    if(_isTerminal(X)) {
742        QList<QStringList> res;
743        res.append(QStringList(X));
744        return res;
745    }
746    return firstSets->value(X);
747}
748
749QList<QStringList> Grammar::FIRST(QStringList L, int K)  // test it
750{
751    if(K == -1)
752        K = this->K;
753    QList<QStringList> res;
754    int q = 0;
755    foreach(QString s, L) {
756        res = SumK(res, FIRST(s), K, &q);
757//        if(q == 1)
758//            break;
759    }
760    return res;
761}
762
763bool Grammar::_isNonTerminal(QString s)
764{
765    if(s.startsWith('#') && s.endsWith('#'))
766        return true;
767    return false;
768}
769
770bool Grammar::_isTerminal(QString s)
771{
772    if(!s.startsWith('#') && !s.endsWith('#'))
773        return true;
774    return false;
775}
776
777QList<QStringList> Grammar::_removeDuplicates(QList<QStringList> L)
778{
779    int k = 0;
780    while(k<L.length()-1) {
781        int l = k+1;
782        while(l<L.length()) {
783            if(L[k] == L[l])
784                L.removeAt(l);
785            else
786                l++;
787        }
788        k++;
789    }
790    return L;
791}
792
793int Grammar::FindK()
794{
795    QStringList keys = this->hash.uniqueKeys();
796    int K = 1;
797    bool flag = true;
798    for(K = 1; K < 3 && flag;) {
799        flag = false;
800        foreach(QString key, keys) {
801            QList<QList<term> > rules = this->hash.value(key);
802            for(int i=0; i<rules.length() && !flag; i++) {
803                if(!rules.isEmpty() && rules[i].first().s.isEmpty())
804                    continue;
805                for(int j=i+1; j<rules.length() && !flag; j++) {
806                    if(!rules.isEmpty() && rules[j].first().s.isEmpty())
807                        continue;
808                    QList<QStringList> follow = followSets->value(key);
809                    QList<QStringList> sumk1 = SumK(FIRST(Rule2StringList(rules[i]), 2), follow, K, NULL);
810                    QList<QStringList> sumk2 = SumK(FIRST(Rule2StringList(rules[j]), 2), follow, K, NULL);
811                    bool flag2 = false;
812                    foreach(QStringList sl1, sumk1) {
813                        foreach(QStringList sl2, sumk2) {
814                            bool flag3 = true;
815                            for(int q=0; q<=K && q<sl1.length() && q<sl2.length(); q++) {
816                                if(sl1[q] != sl2[q]) {
817                                    flag3 = false;
818                                    break;
819                                }
820                                else {
821                                    qDebug()<<"----------------1-"<<sumk1;
822                                    qDebug()<<"----------------2-"<<sumk2;
823                                }
824                            }
825                            if(flag3) {
826                                flag2 = true;
827                                break;
828                            }
829                            if(flag2) break;
830                        }
831                        if(flag2) break;
832                    }
833                    if(flag2) {
834                        flag = true;
835                        break;
836                    }
837                }
838            }
839            if(flag) {break;}
840        }
841        if(flag) {K++;break;}
842        if(!flag) flag = true;
843    }
844    
845    return K;
846}
847
848int Grammar::Go(int i, QString nonterm)
849{
850    int lexInd = i;
851    if(lexInd == -1 || lexInd>=lex.lexemes_list.length()) return -1;
852    QStringList rule;
853    bool hasEps = false;
854    foreach(QList<term> rule1, hash.value(nonterm)) {
855        if(rule1.length()>0 && rule1[0].s == "") {
856            hasEps = true;
857            continue;
858        }
859        QList<QStringList> sumk = SumK(FIRST(Rule2StringList(rule1), 1), followSets->value(nonterm), 1, NULL);
860        if(sumk.isEmpty() || sumk[0].isEmpty()) {
861            hasEps = true;
862            continue;
863        }
864        bool f = false;
865        foreach(QStringList sl, sumk) {
866            if(sl.length() == 0) {
867                continue; // ?
868            }
869            if(lex.lexemes_list[lexInd].terminal.compare(sl[0], Qt::CaseInsensitive) == 0) {  //rule1[0].s) { // ?
870                rule = Rule2StringList(rule1);
871                f = true;
872                break;
873            }
874        }
875        if(f) break;
876    }
877    if(rule.isEmpty()) {
878        if(hasEps) return lexInd;
879        qDebug()<<">> No suitable rule found; "<<QString(lex.lexemes_list.at(lexInd).text);
880        qDebug()<<"   "<<nonterm;
881        //this->errorAt = lexInd;
882        this->errorAt = lex.lexemes_list.at(lexInd).lineNum;
883        this->errorInd = lexInd;
884        Error(lexInd);
885        return -1;
886    }
887    foreach(QString term, rule) {
888        if(_isNonTerminal(term)) {
889            qDebug()<<">> Go()  for "<<term;
890            lexInd = Go(lexInd, term);
891            if(lexInd == -1 || lexInd>=lex.lexemes_list.length())
892                return -1;
893        }
894        else {
895            if(lex.lexemes_list[lexInd].terminal.compare(term, Qt::CaseInsensitive) == 0) {
896                qDebug()<<">> Match: "<<lex.lexemes_list[lexInd].terminal<<" == "<<term;
897                lexInd++;                
898            }
899            else {
900                //this->errorAt = lexInd;
901                if(hasEps) return lexInd;
902                qDebug()<<">> NO Match: "<<lex.lexemes_list[lexInd].terminal<<" != "<<term;
903                this->errorAt = lex.lexemes_list.at(lexInd).lineNum;
904                this->errorInd = lexInd;
905                Error(lexInd);
906                return -1;
907            }
908        }
909    }
910    return lexInd;
911}
912
913void Grammar::Error(int lexInd)
914{
915    qDebug()<<"Error at line"<<this->errorAt<<"; Lexem number "<<lexInd;
916}