HELPP! I need to read the comments from the c++ file and then use strings to print it in the html file

A standard way to show the documentation of a program in C++ is by having an application that
supports the generation of an html file. The idea is to load this file on a browser to view the
documentation written on it. To make this application work you should know that
documentation comments in a C++ program are delimited by the opening block comment /**
in the initial line and the corresponding closure of a comment */ on the very last line.
All the features that are documented in C++ begin with the @ character followed by a word
that represents the type of documentation. The rest of the line is a string that can contain
several words.
Example:
@progName
@author
@date
@funcName
@desc
@param
@return
Note: When documentation is written you will commonly find it to be with indentations. So it is
possible that the @ character won’t necessarily be the first character of the line. It may have
blank spaces to the left.
You will have to write a program that will ask the user the name of the documented file to read
(This file will be a .cpp extension file). The program must generate the html file with the same
name as the input file. Make sure that the extension of this output file is .html.
The generated file will have <html> tags. You don’t need to know html to see how the tags are
created, an example will be provided to you.

This is how the documented file looks like:
/**
@progName Factorial
@desc Program that has a function to make the calculus of the factorial of a
given number
@author Alfredo Salazar Velez
@date August 28, 2018
*/
#include <iostream>
using namespace std;
/**
@funcName factorial
@desc Gets the calculus of the factorial of a number
@param iNum initial number for which the factorial will be calculated. Must
be a positive integer
@return returns the factorial of iNum
*/
int factorial(int iNum)
{
int iFac = 1;
// Calculate the factorial with a FOR loop
for (int iC = 1; iC <= iNum; iC++)
{
iFac = iFac * iC;
}
return iFac; // This value is returned to caller
}
/**
@funcName validateInteger
@desc Function that asks the user a value and validates that it is in
between 1 and 10
@return returns the value that the user typed in between 1 and 10
*/
int validateInteger()
{
int iNum;
do
{
cout << "Number ";
cin >> iNum;
} while (iNum < 1 || iNum > 10);
return iNum;
}
/**
@funcName main
@desc Ask the value to the user, makes the calculus of the factorial and
shows it
*/
int main()
{
int iNumero, iResult;
iNumero = validateInteger();
iResult = factorial(iNumero);
cout << "Factorial = " << iResult << endl;
return 0;
}

This is how the html file looks like:
<!DOCTYPE html>
<html>
<head>
<title>
Factorial
</title>
</head>
<body>
<h2> Program: Factorial </h2> <br>
<strong> Description </strong> Program that has a function to make the
calculus of the factorial of a given number <br>
<strong> Author: </strong> Alfredo Salazar Velez <br>
<strong> Date: </strong> August 28, 2018<br>
<h3>
<hr><br>Function: factorial<br>
</h3>
<strong> Description: </strong> Gets the calculus of the factorial of a
number <br>
<strong> Parameter: </strong> iNum initial number for which the factorial
will be calculated. Must be a positive integer <br>
<strong> Return: </strong> returns the factorial of iNum <br>
<h3>
<hr><br>Function: validateInteger<br>
</h3>
<strong> Description: </strong> Function that asks the user a value and
validates that it is in between 1 and 10 <br>
<strong> Return: </strong> returns the value that the user typed in between 1
and 10<br>
<h3>
<hr><br>Function: main<br>
</h3>
<strong> Description: </strong> Ask the value to the user, makes the calculus
of the factorial and shows it <br>
</body>
</html>
This is not a homework site. Show what code you've attempted yourself to solve this problem. Be specific about what you need help with.

There are multiple parts of this program that need to work together. I suggest separating each part logically.
1. Opening the document that you are trying to parse as a C++ file stream
2. Iterating through the document, character by character
3. Determining whether or not we are currently in a /* comment section */
4. If a line begins with @, figure out what keyword it's documenting and write the information to your output string.
5. Writing an output document that writes valid HTML to an output file.
An easier way might be to read to whole file into a string and use string.find to get the text between /** and */ and split this chunk into lines and then process each line.
I just want to know how to delimit the section of the comment and then start to read all the data from there.
how to use the while or the if.
Before detecting comments, your program needs to know how to interpret multicharacter and string literals, including raw string literals. Comment markers cannot appear in string literals nor multi-character literals. Since single and double quotes and raw-string delimeters can be commented out, your program can't get away with a naive understanding of comments; you'll have to parse them properly.

For example, consider this snippet, which does not contain a documentation block:
auto something = R\
"( 
/**
@summary something "(whatever)";
// @param foo frobnicator \
*/


Go to your favorite reference page and carefully read about the first three phases of translation, so that you can properly lex C++ at the level of the preprocessor.

Hopefully these acrobatics aren't required. If it's not clear, you should ask your professor what level of correctness is expected of your program.
Last edited on
Wow, I didn't even think of raw strings. Probably outside the scope of maikymoto17's assignment, but did the same complexity exist pre-C++11 as far as comment parsing is concerned?

test
1
2
3
4
5
6
7
8
9
int main()
{
    auto something = R\
    "( 
    /**
    @summary something "(whatever)";
    // @param foo frobnicator \
   */";
}


Edit: Wait... I'm not even sure how to parse that as a human. I know this website isn't updated for C++11, but I can't even get cpp.sh to compile correctly.
mbozzi, can you show a compileable example that shows your code snippet verbatim? :)

Ah, g++ does not like the R\... are you sure that's valid C++?
g++     main.cpp   -o main
main.cpp:5:5: warning: missing terminating " character
     "(
     ^
main.cpp:5:5: error: missing terminating " character
     "(
     ^~
main.cpp:9:6: warning: missing terminating " character
    */";
      ^
main.cpp:9:6: error: missing terminating " character
    */";
      ^~
main.cpp: In function 'int main()':
main.cpp:4:22: error: 'R' was not declared in this scope
     auto something = R\
                      ^~
     "(

make: *** [<builtin>: main] Error 1


This compiles
1
2
3
4
5
6
7
8
int main()
{
    auto something = R"( 
    /**
    @summary something "(whatever)";
    // @param foo frobnicator \
   */";
}
Last edited on
How can I determine whether or not we are currently in a /** comment section */ using basic string functions?
mbozzi, can you show a compileable example that shows your code snippet verbatim? :)

It compiles fine as it stands. Evidence:

Clang & GCC:
http://coliru.stacked-crooked.com/a/fb9a89c634a751da
MSVC:
http://rextester.com/PEI39523

Clearly there's some incompatibility in the cpp.sh toolchain, but I'm confident that snippet is valid C++.
Edit: Looks like you pasted it into a main function, where the block was indented.
If you indent it, after line continuation, what's left is a raw string that goes like this:
 
R    "(my raw string contents)"

But that's illegal because the R must appear directly before the quote:
 
R"(my raw string contents)";


Did the same complexity exist pre-C++11 as far as comment parsing is concerned?

AFAIK, yes - it was just marginally less terrible because raw strings don't exist and single quotes aren't also digit separators. There are probably some other significant changes, but I don't know about them.

From the question, it looks like OP is a beginner to parsing. Hopefully that's not true, because this problem looks pretty tricky.
Last edited on
@mbozzi
Ooooh, it was because of the indentation. Tricky, didn't realize there couldn't be spaces in between the R and quotes. Thanks!


@OP
Sorry if it seems like we're being difficult, but mbozzi made me realize this is actually a bit more difficult to do correctly.

Not only do you need to find where /** and */ delimiters are, you also need to make sure you're not in a string, or (in C++11) a raw string. This requires having context of the current state of the document.
For instance, if you have
1
2
3
4
5
6
    /** \
        \
        \
    */
    
    int i = 0; \

You can't tell if you're actually in a comment or not unless you have more context.
It could look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Example program
#include <iostream>
#include <string>

int main()
{
    // Not a comment:
    
    std::string text =
    "\
    /** \
        \
        \
    */ int i = 0; \
    ";


    // Is a comment:

    /** \
        \
        \
    */ int i = 0; \
}


You also have to make sure you aren't already in a comment:
e.g. /* /* */ int main() {}
comments don't nest.
1
2
//     /*
int main() {}

single line comment overrides the multi-line start

Anyway, if we ignore the difficult parts for now, you need to iterate through every character until you find a "/". If you find a "/", see if the two next characters are both"*". If this is true, then you need to set a state variable to say that we're currently in a comment.
Once you're in a comment, keep iterating until you find a "*" followed by a "/".

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
#include <iostream>
#include <string>
#include <fstream>

/**
  Test comment
*/
int function() {return 42;}

/**
We're inside a documentation comment or whatever it's called.
Yes, this will break with strings that look like comments, among a plethora of other gotchas.
It's just an example.
*/
int main()
{
    std::ifstream fin("main.cpp");

    char ch;
    while (fin.get(ch))
    {
        if ((ch == '/') &&
            fin.get(ch) && (ch == '*') &&
            fin.get(ch) && (ch == '*'))
        {
            std::cout << "Entered comment...\n";

        }
        
        if ((ch == '*') && fin.get(ch) && (ch == '/'))
        {
            std::cout << "Leaving comment...\n";
        }
    }
}

D:\test>main
Entered comment...
Leaving comment...
Entered comment...
Leaving comment...
Last edited on
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
#include <iostream>
#include <fstream>
#include <string>
using namespace std;


int main() {
    
    ifstream inputFile;
    ofstream outputFile;
    string sDirectiva, sInicioFinal, sFile;
    
    inputFile.open("factorial.cpp");
    outputFile.open("factorial.html");
    

    while(!inputFile.eof()){
       
        inputFile >> sInicioFinal;
        
        if(sInicioFinal == "/**"){
            
            while (sInicioFinal != "*/"){
                inputFile >> sDirectiva;
                cout << "enter comment" << endl;
                cout << sInicioFinal << sDirectiva << endl;
                sInicioFinal = "*/";
            }
            cout << "leaving comment" << endl;
        }
    
        





    }
    
    return 0;
}


i have this other way of determining the comment areas. Now how can i create a function to read it and then use the ofstream to create the html file
Last edited on
@Ganado, @mbozzi,
you over-complicate. This is a simple exercise and not real code.
All the features that are documented in C++ begin with the @ character followed by a word
that represents the type of documentation. The rest of the line is a string that can contain
several words.

There is absolutely no need to think about
multicharacter and string literals, including raw string literals.

It should do to extract the comment between /** */ with string.find and string.substr, split it into lines, find and extract the type and treat the rest of the line as the value.

@OP,
I would make first a plan.
1. read the input file name and contruct the output filename.
2. read the file into a string
3. extract the comments into a string
4. transform the comment into html
    4.a split the comment into lines
    4.b transform the comment into html
5. write the html to the file

Yes, I agree, his professor is probably not trying to trick him. But to parse the line, I'm not sure if there's really a way to do that without std::stringstream (or at least, std::stringstream is one of the nicer ways to do it).

@OP,
Here's an example of that, assuming you already have the comment broken up into lines like Thomas said:
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
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

int main()
{
    std::string comment =
      std::string("@progName Factorial\n") + 
                  "@desc Program that has a function to make the calculus of the factorial of a\n"
                  "given number\n"
                  "@author Tio Juan\n"
                  "@date August 28, 2018\n";

    std::cout << comment << "\n";

    std::istringstream iss(comment);
    
    std::vector<std::string> categories;
    std::string word;
    while (iss >> word)
    {
        if (word[0] == '@')
        {
            categories.push_back("");
            if (word == "@progName")
            {
                categories.back() += "Program: ";   
            }
            else if (word == "@desc")
            {
                categories.back() += "Description: ";   
            }
            else
            {
                categories.back() += (word + ": "); // TODO   
            }
        }
        else
        {
            if (categories.size() == 0)
            {
                std::cout << "Error parsing comment\n";
                break;
            }
            categories.back() += (word + " ");
        }
    }
    
    std::cout << "Parsed:\n";
    for (const auto& line : categories)
    {
        std::cout << line << "\n";   
    }
}
Last edited on
@Ganado,
you could use the string functions but they seem less convenient.
1
2
3
4
5
6
7
8
  // please note no error checking done
  auto atPos = param.find('@');
  auto endTag = param.find_first_of(' ', atPos+1);
  if (atPos != string::npos && endTag != string::npos)
  {
    string tag = param.substr(atPos+1, endTag - atPos);
    string comment = param.substr(endTag+1);
  }
Topic archived. No new replies allowed.