Website Summary Files Commits Branches @commit @diff @stats
path: root / homework / 81568 / c2html / cyclomatic.cpp
blob: b7b0c17a16db79821dfe71914723f38d5269e631 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "cyclomatic.h"
#include "html_utils.h"
#include "lexcer.h"
#include "lexconst.h"
#include <stack>

using HTMLUtils::writeToOutput;
using LexCer::TokenClass;
using LexCer::Tokenizer;

// Writing a full parser would give us the change of
// making the cyclomatic graph of the function.
// #courseproject
unsigned ParCer::outputWithCyclomaticComplexity(FILE *in, FILE *out) {
  Tokenizer tokenizer (in, out);

  std::string lexeme;
  double number;
  TokenClass type;
  Token currentToken;
  std::stack<short> history;
  bool inFunction = false;

  #define PAREN false
  std::stack<bool> openedBlocks;
  std::string className = "a";
  unsigned counter = 1;
  unsigned complexity = 1;
  
  do {
    currentToken = tokenizer.nextToken(&lexeme, &number);
    type = currentToken.type;
    
    if (!inFunction) {
      history.push(type);
    } else {
      if (type == TokenClass::RightCurly) {
        if (openedBlocks.empty()) { // end of a function. What one does to avoid parsing 'C'
          inFunction = false;
          fputs("<!-- ", out);
          char closingDiv[100];
          sprintf(closingDiv, "%d --></div>", complexity);
          fputs(closingDiv, out);
          complexity = 1;
        } else {
          openedBlocks.pop();
        }
      }
      else if (type == TokenClass::LeftCurly) {
        openedBlocks.push(PAREN);
      }
      else if (type == TokenClass::Keyword) {
        if (!lexeme.compare("if") ||
            !lexeme.compare("while") ||
            !lexeme.compare("for") ||
            !lexeme.compare("case") ||
            !lexeme.compare("default"))
          {
          ++complexity;
        }
      }
    }

    if (!inFunction && type == TokenClass::LeftCurly) {
      history.pop();
      while (!history.empty() && history.top() == TokenClass::Skip) {
        history.pop();
      }
      
      if (history.top() == TokenClass::RightParen) {
        while (!history.empty() && history.top() != TokenClass::LeftParen)
          history.pop();
        if (!history.empty())
          history.pop();
        while (!history.empty() && history.top() == TokenClass::Skip)
          history.pop();

        if (!history.empty() && history.top() == TokenClass::Identifier) { // We are in a function
          char openingDiv[100];
          sprintf(openingDiv, "<div class=\"func\">", className.c_str());
          fputs(openingDiv, out);
          inFunction = true;
          history = std::stack<short>{};
        }
      }
    }
    
    if (!writeToOutput(out, currentToken))
      break;
    lexeme = "";
    number = 0.0;
  } while (type != TokenClass::Eof ||
           type != TokenClass::Invalid);
  return counter - 1;
}