1- // commentDFA.cpp
21
32#include < iostream>
43#include < fstream>
54#include < string>
6- #include < filesystem>
7- #include < sstream>
8-
5+ #include < sstream>
96#include " commentDFA.h"
107
8+ // Helper function: Read the next character and update line count
9+ bool getNextChar (std::ifstream& file, char & ch, int & lineCount) {
10+ file.get (ch);
11+ if (file.eof ()) return false ;
12+ if (ch == ' \n ' ) lineCount++;
13+ return true ;
14+ }
15+
16+ // Helper function: Report error and terminate
17+ void reportError (const std::string& message, int errorLine) {
18+ std::cerr << " ERROR: " << message << " on line " << errorLine << std::endl;
19+ exit (1 );
20+ }
21+
1122// State 0: Normal state, reading and printing code character by character
1223void CommentDFA::state0 (std::ifstream& file, int & lineCount, std::ostringstream& buffer) {
13- char ch;
14- file.get (ch); // Read a character from the file
15- if (file.eof ()) { // Check if the end of file is reached
16- buffer << " \n " ;
17- return ; // End of input, stop the function
18- } else if (ch == ' /' ) { // If the character is '/', move to state1
19- return state1 (file, lineCount, buffer);
20- } else if (ch == ' *' ){
21- if (!state6 (file, lineCount, buffer)) {
22- std::cerr << " ERROR: Program contains C-style, unterminated quote on line " << lineCount;
23- exit (1 );
24- }
24+ char ch;
25+ if (!getNextChar (file, ch, lineCount)) {
26+ buffer << " \n " ; // End of input
2527 return ;
28+ }
29+
30+ if (ch == ' /' ) {
31+ state1 (file, lineCount, buffer);
32+ } else if (ch == ' *' ) {
33+ if (!state6 (file, lineCount, buffer)) {
34+ reportError (" Program contains C-style, unterminated comment" , lineCount);
35+ }
2636 } else if (ch == ' "' ) {
27- int quoteLineCount = 0 ;
2837 buffer << ch;
38+ int quoteLineCount = lineCount;
2939 if (!state5 (file, lineCount, quoteLineCount, buffer)) {
30- std::cerr << " ERROR: Program contains C-style, unterminated quote on line " << lineCount;
31- exit (1 );
32- }
33- return ;
34- } else { // Otherwise, print the character and stay in state0
35- if (ch == ' \n ' ) {
36- lineCount++;
40+ reportError (" Program contains C-style, unterminated quote" , quoteLineCount);
3741 }
42+ } else {
3843 buffer << ch;
39- return state0 (file, lineCount, buffer);
44+ state0 (file, lineCount, buffer);
4045 }
4146}
4247
43- // State 1: After hitting a '/', figure out if it's a comment or a division operator
48+ // State 1: After encountering '/', decide if it's a comment or division operator
4449void CommentDFA::state1 (std::ifstream& file, int & lineCount, std::ostringstream& buffer) {
45- char ch;
46- file.get (ch); // Read the next character
47- if (file.eof ()) { // Check for end of file
48- return ;
49- } else if (ch == ' /' ) { // If it's another '/', we have a C++-style comment, move to state2
50- buffer << " " ; // Add whitespace
51- return state2 (file, lineCount, buffer);
52- } else if (ch == ' *' ) { // If it's a '*', we have a C-style block comment, move to state3
50+ char ch;
51+ if (!getNextChar (file, ch, lineCount)) return ;
52+
53+ if (ch == ' /' ) {
54+ buffer << " " ; // Add whitespace for single-line comment
55+ state2 (file, lineCount, buffer);
56+ } else if (ch == ' *' ) {
57+ buffer << " " ; // Add whitespace for block comment
58+ int startCommentLine = lineCount;
5359 int commentLineCount = 0 ;
54- buffer << " " ; // Add whitespace
55- if (!state3 (file, lineCount, commentLineCount, buffer)) {
56- std::cerr << " ERROR: Program contains C-style, unterminated comment on line " << lineCount;
57- exit (0 );
58- }
59- return ;
60- } else { // Otherwise, it's just a '/', print it and return to state0
61- if (ch == ' \n ' ) {
62- lineCount++;
60+ if (!state3 (file, lineCount, commentLineCount, startCommentLine, buffer)) {
61+ reportError (" Program contains C-style, unterminated comment" , startCommentLine);
6362 }
64- buffer << ' / ' ; // Don't forget to print the first '/' since it's not part of a comment
65- buffer << ch; // Also print the current character
66- return state0 (file, lineCount, buffer);
63+ } else {
64+ buffer << ' / ' << ch;
65+ state0 (file, lineCount, buffer);
6766 }
6867}
6968
70- // State 2: Inside a C++-style line comment, skip characters until newline is reached
69+ // State 2: Inside a C++-style single- line comment
7170void CommentDFA::state2 (std::ifstream& file, int & lineCount, std::ostringstream& buffer) {
72- char ch;
73- file.get (ch); // Read the next character
74- if (ch == ' \n ' ) { // If it's a newline, return to state0 to process the next line
75- lineCount++;
76- buffer << " \n " ; // Add newline
77- return state0 (file, lineCount, buffer);
78- } else {
79- buffer << " " ; // Add whitespace
71+ char ch;
72+ if (!getNextChar (file, ch, lineCount) || ch == ' \n ' ) {
73+ buffer << " \n " ; // End of single-line comment
74+ state0 (file, lineCount, buffer);
75+ return ;
8076 }
81- return state2 (file, lineCount, buffer); // Otherwise, stay in state2, ignoring characters
77+ buffer << " " ; // Replace comment content with spaces
78+ state2 (file, lineCount, buffer);
8279}
8380
84- // State 3: Inside a C-style block comment, look for the closing '*/'
85- bool CommentDFA::state3 (std::ifstream& file, int & lineCount, int & commentLineCount, std::ostringstream& buffer) {
86- char ch;
87- file.get (ch); // Read the next character
88- if (ch == ' *' ) { // If it's a '*', check if it's the start of '*/' (end of comment)
89- return state4 (file, lineCount, commentLineCount, buffer);
81+ // State 3: Inside a C-style block comment
82+ bool CommentDFA::state3 (std::ifstream& file, int & lineCount, int & commentLineCount, int startCommentLine, std::ostringstream& buffer) {
83+ char ch;
84+ if (!getNextChar (file, ch, lineCount)) return false ;
85+
86+ if (ch == ' *' ) {
87+ return state4 (file, lineCount, commentLineCount, startCommentLine, buffer);
9088 } else if (ch == ' \n ' ) {
91- buffer << " \n " ; // Add newline
89+ buffer << " \n " ;
9290 commentLineCount++;
93- }else if (file.eof ()){
94- return false ;
9591 } else {
96- buffer << " " ; // Add whitespace
92+ buffer << " " ;
9793 }
98- return state3 (file, lineCount, commentLineCount, buffer); // Otherwise, stay in state3, ignoring characters
94+ return state3 (file, lineCount, commentLineCount, startCommentLine, buffer);
9995}
10096
101- // State 4: Looking for '/' to close the C-style block comment
102- bool CommentDFA::state4 (std::ifstream& file, int & lineCount, int & commentLineCount, std::ostringstream& buffer) {
103- char ch;
104- file. get (ch); // Read the next character
105- if (ch == ' / ' ) { // If it's '/', the block comment is closed, return to state0
106- buffer << " " ; // Add whitespace
107- lineCount += commentLineCount;
97+ // State 4: Check for '/' to close the C-style block comment
98+ bool CommentDFA::state4 (std::ifstream& file, int & lineCount, int & commentLineCount, int startCommentLine, std::ostringstream& buffer) {
99+ char ch;
100+ if (! getNextChar (file, ch, lineCount)) return false ;
101+
102+ if (ch == ' / ' ) {
103+ buffer << " " ; // Close block comment
108104 state0 (file, lineCount, buffer);
109105 return true ;
110- } else if (ch == ' \n ' ) {
111- buffer << " \n " ; // Add newline
112- commentLineCount++;
113- } else if (file.eof ()){
114- return false ;
115106 } else if (ch == ' *' ) {
116107 file.putback (ch);
108+ } else {
109+ buffer << " " ;
117110 }
118- buffer << " " ; // Add whitespace
119- return state3 (file, lineCount, commentLineCount, buffer); // Otherwise, continue checking inside the block comment
111+ return state3 (file, lineCount, commentLineCount, startCommentLine, buffer);
120112}
121113
122- // State 5: Inside a quoted string (either single or double quotes),
123- // ignore characters inside until the closing quote is found
114+ // State 5: Inside a quoted string
124115bool CommentDFA::state5 (std::ifstream& file, int & lineCount, int & quoteLineCount, std::ostringstream& buffer) {
125- char ch;
126- file.get (ch);
127- if (file.eof ()) { // If end of file is reached, return false
128- return false ;
129- } else if (ch == ' "' ) { // If a closing quote is found, return to state 0
130- buffer << ch; // Output the character
131- lineCount += quoteLineCount; // Increment the line counter
132- state0 (file, lineCount, buffer); // Go back to state 0
133- return true ; // And finally return true
134- } else {
135- buffer << ch; // Otherwise, go to state 5
136- return state5 (file, lineCount, quoteLineCount, buffer);
116+ char ch;
117+ if (!getNextChar (file, ch, lineCount)) return false ;
118+
119+ buffer << ch;
120+ if (ch == ' "' ) {
121+ state0 (file, lineCount, buffer);
122+ return true ;
137123 }
124+ return state5 (file, lineCount, quoteLineCount, buffer);
138125}
139126
140- // State 6: Detected an asterisk ('*'),
141- // check if it's an unterminated C-style block comment
127+ // State 6: Detected an asterisk ('*'), check for unterminated C-style block comment
142128bool CommentDFA::state6 (std::ifstream& file, int & lineCount, std::ostringstream& buffer) {
143- char ch;
144- file.get (ch);
145- if (ch == ' /' ) { // If a slash is found, return false
146- return false ;
147- } else {
129+ char ch;
130+ if (!getNextChar (file, ch, lineCount) || ch != ' /' ) {
148131 buffer << ' *' ;
149- file.putback (ch); // Otherwise, put the character back
150- state0 (file, lineCount, buffer); // Go to state 0
151- return true ; // And return true
132+ if (ch != ' / ' ) file.putback (ch);
133+ state0 (file, lineCount, buffer);
134+ return true ;
152135 }
136+ return false ;
153137}
0 commit comments