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