|
3 | 3 | * errors like unmatched parentheses, brackets and braces. Don't forget about
|
4 | 4 | * quotes, both single and double, escape sequences, and comments. (This
|
5 | 5 | * program is hard if you do it in full generality.)
|
| 6 | + * |
6 | 7 | * By Faisal Saadatmand
|
7 | 8 | */
|
8 | 9 |
|
| 10 | + |
| 11 | +/* NOTE: this is not full generality solution */ |
| 12 | + |
9 | 13 | #include <stdio.h>
|
10 | 14 |
|
11 |
| -#define MAXLINE 1000 |
12 |
| -#define YES 1 |
13 |
| -#define NO 0 |
14 |
| -#define SLASH_ASTERISK 1 |
15 |
| -#define ASTERISK_SLASH 0 |
16 |
| -#define IN 1 |
17 |
| -#define OUT 0 |
| 15 | +#define YES 1 |
| 16 | +#define NO 0 |
| 17 | + |
| 18 | +/* globals */ |
| 19 | +int leftParens = 0; |
| 20 | +int rightParens = 0; |
| 21 | +int leftBrackets = 0; |
| 22 | +int rightBrackets = 0; |
| 23 | +int leftBraces = 0; |
| 24 | +int rightBraces = 0; |
18 | 25 |
|
19 | 26 | /* functions */
|
20 |
| -int getLine(char [], int); |
21 |
| -int findComment(char [], int); |
22 |
| -int delComment(char [], char [], int , int); |
23 |
| -void findCharacter(char [], char [], int [], int); |
24 |
| -void checkSyntax(char [], int [], int); |
25 |
| - |
26 |
| -/* getLine function: read a line into s, return length */ |
27 |
| -int getLine(char s[], int lim) |
| 27 | +void printInfo(); |
| 28 | +int skipChar(int); |
| 29 | +void checkSymbolsBallance(void); |
| 30 | +void countSymbols(void); |
| 31 | +int skipComment(int); |
| 32 | +int skipQuote(int); |
| 33 | + |
| 34 | +/* skipChar: skips n characters in the input stream */ |
| 35 | +int skipChar(int n) |
28 | 36 | {
|
29 |
| - int c, i; |
| 37 | + int c; |
30 | 38 |
|
31 |
| - for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) |
32 |
| - s[i] = c; |
33 |
| - |
34 |
| - if (c == '\n') { |
35 |
| - s[i] = c; |
36 |
| - ++i; |
37 |
| - } |
| 39 | + while (n--) |
| 40 | + c = getchar(); |
| 41 | + return c ; |
| 42 | +} |
38 | 43 |
|
39 |
| - s[i] = '\0'; |
| 44 | +/* skipComment: skip characters in the input stream until encountered the |
| 45 | + * ending symbol of a c-style comment */ |
| 46 | +int skipComment(int c) |
| 47 | +{ |
| 48 | + int stop = NO; |
40 | 49 |
|
41 |
| - return i; |
| 50 | + while (stop == NO && (c = getchar()) != EOF) |
| 51 | + if (c == '*' && (c = getchar()) == '/') |
| 52 | + stop = YES; |
| 53 | + return c; |
42 | 54 | }
|
43 | 55 |
|
44 |
| -/* findComment function: searches line[] for the first occurrence of the first |
45 |
| - * character of a C comment notation and returns the location on finding a single |
46 |
| - * line comment or -1 on failure */ |
47 |
| -int findComment(char line[], int notation) |
| 56 | +/* skipComment: skip characters in the input stream until encountered the |
| 57 | + * ending character of a c-style quote (single or double) */ |
| 58 | +int skipQuote(int type) |
48 | 59 | {
|
49 |
| - int i, j; |
50 |
| - int quoteStart; /* location of the start of the quotation mark */ |
51 |
| - int quoteEnd; /* location of the end of quotation mark */ |
52 |
| - int location; /* location of C comment notation */ |
53 |
| - int comment[2]; /* notation type: start or end */ |
54 |
| - int lookForQuote; /* flag variable */ |
55 |
| - |
56 |
| - location = quoteStart = quoteEnd = -1; |
57 |
| - /* set the appropriate notation */ |
58 |
| - if (notation == SLASH_ASTERISK) { |
59 |
| - comment[0] = '/'; |
60 |
| - comment[1] = '*'; |
61 |
| - } else if (notation == ASTERISK_SLASH) { |
62 |
| - comment[0] = '*'; |
63 |
| - comment[1] = '/'; |
64 |
| - } |
| 60 | + int c, stop = NO, step = 2; |
65 | 61 |
|
66 |
| - lookForQuote = YES; |
67 |
| - /* line[x - 1] check handles escape sequences. It is unnecessary for the |
68 |
| - * start of the quote but is added for the sake of correctness. */ |
69 |
| - for (i = 0; line[i] != '\0'; ++i) { |
70 |
| - if (line[i] == comment[0] && line[i + 1] == comment[1]) { |
71 |
| - if (notation == ASTERISK_SLASH) |
72 |
| - location = i + 1; /* end of comment including notation */ |
73 |
| - else |
74 |
| - location = i; /* start of comment including notation */ |
75 |
| - } |
76 |
| - if (line[i] == '\"' && line[i - 1] != '\\' && lookForQuote == YES) { |
77 |
| - quoteStart = i; |
78 |
| - for (j = i + 1; line[j] != '\0'; ++j) |
79 |
| - if (line[j] == '\"' && line[j - 1] != '\\') |
80 |
| - quoteEnd = j; |
81 |
| - lookForQuote = NO; |
82 |
| - } |
| 62 | + while (stop == NO && (c = getchar()) != EOF) { |
| 63 | + if (c == '\\') |
| 64 | + c = skipChar(step); |
| 65 | + if (c == type) |
| 66 | + stop = YES; |
83 | 67 | }
|
84 |
| - |
85 |
| - /* check if notation is inside a double quotation marks */ |
86 |
| - if (location >= 0 && quoteStart >= 0) |
87 |
| - if (location > quoteStart && location < quoteEnd) |
88 |
| - location = -1; /* not a C comment */ |
89 |
| - |
90 |
| - /* check if notation is inside a multi-line double quotation marks */ |
91 |
| - if (location >= 0 && quoteStart >= 0 && quoteEnd < 0) |
92 |
| -// if (location < quoteStart) |
93 |
| - location = -1; /* not a C comment */ |
94 |
| - |
95 |
| - return location; |
| 68 | + return c; |
96 | 69 | }
|
97 | 70 |
|
98 |
| -/* delComment function: deletes C comments from line string stores result in |
99 |
| - * modLine */ |
100 |
| -int delComment(char line[], char modLine[], int start, int end) |
101 |
| -{ |
102 |
| - int i, j; |
103 |
| - int status; |
104 |
| - |
105 |
| - i = j = 0; |
106 |
| - |
107 |
| - /* no notation - delete entire line */ |
108 |
| - if (start < 0 && end < 0) |
109 |
| - for (i = 0; line[i] != '\0'; ++i) |
110 |
| - modLine[i] = '\0'; |
111 |
| - /* start but no end - delete rest of line */ |
112 |
| - else if (start >= 0 && end < 0) |
113 |
| - for (i = 0; i < start; ++i) |
114 |
| - modLine[i] = line[i]; |
115 |
| - /* end but no start - move text after comment to the beginning of line */ |
116 |
| - else if (start < 0 && end >= 0) |
117 |
| - for (j = end + 1; line[j] != '\0'; ++j) { |
118 |
| - modLine[i] = line[j]; |
119 |
| - ++i; |
120 |
| - } |
121 |
| - /* full comment embedded - move text after comment to start location */ |
122 |
| - else if (start >= 0 && end >= 0) { |
123 |
| - for (i = 0; i < start; ++i) |
124 |
| - modLine[i] = line[i]; |
125 |
| - for (j = end + 1; line[j] != '\0'; ++j) { |
126 |
| - modLine[i] = line[j]; |
127 |
| - ++i; |
128 |
| - } |
| 71 | +/* countSymbols: count c-style demarcating symbols for comments and quote */ |
| 72 | +void countSymbols(void) { |
| 73 | + extern int leftParens, rightParens, leftBrackets, rightBrackets, |
| 74 | + leftBraces, rightBraces; |
| 75 | + int c; |
| 76 | + |
| 77 | + while ((c = getchar()) != EOF) { |
| 78 | + if (c == '/' && (c = getchar()) == '*') /* skip comments */ |
| 79 | + c = skipComment(c); |
| 80 | + if (c == '"') /* skip double quotes */ |
| 81 | + c = skipQuote(c); |
| 82 | + if (c == '\'') /* slip single quotes */ |
| 83 | + c = skipQuote(c); |
| 84 | + if (c == '(') |
| 85 | + ++leftParens; |
| 86 | + if (c == ')') |
| 87 | + ++rightParens; |
| 88 | + if (c == '[') |
| 89 | + ++leftBrackets; |
| 90 | + if (c == ']') |
| 91 | + ++rightBrackets; |
| 92 | + if (c == '{') |
| 93 | + ++leftBraces; |
| 94 | + if (c == '}') |
| 95 | + ++rightBraces; |
129 | 96 | }
|
130 |
| - |
131 |
| - /* end of line formatting */ |
132 |
| - if (start < 0 && end < 0) |
133 |
| - modLine[0] = '\n'; |
134 |
| - else if (start >= 0 && end < 0) { |
135 |
| - modLine[i] = '\n'; |
136 |
| - modLine[i + 1] = '\0'; |
137 |
| - } else |
138 |
| - modLine[i] = '\0'; |
139 |
| - |
140 |
| - /* status of the current deleted comment: single or multi-line */ |
141 |
| - status = 0; |
142 |
| - if ((start >= 0 && end < 0) || (start < 0 && end < 0)) |
143 |
| - status = 1; |
144 |
| - else if (start < 0 && end >= 0) |
145 |
| - status = 0; |
146 |
| - |
147 |
| - return status; |
148 | 97 | }
|
149 | 98 |
|
150 |
| -/* findCharcter function: counts the occurrence of a characters from symbol in |
151 |
| - * line and stores results in charsCount. len is the length of symbol array */ |
152 |
| -void findCharacter(char line[], char symbol[], int charsCount[], int len) |
| 99 | +/* checkSymbolsBallance: check if number of c-style demarcating symbols for |
| 100 | + * comments and quotes are balanced. Print an error message if not. */ |
| 101 | +void checkSymbolsBallance(void) |
153 | 102 | {
|
154 |
| - int i, j; |
155 |
| - static int quoteState; /* double quote state flag */ |
156 |
| - |
157 |
| - quoteState = OUT; |
158 |
| - for (i = 0; i <= len ; ++i) |
159 |
| - /* line[x - 1] check handles escape sequences. */ |
160 |
| - for (j = 0; line[j] != '\0'; ++j) |
161 |
| - if (quoteState == OUT && line[j] == '\"' && line[j - 1] != '\\') |
162 |
| - quoteState = IN; |
163 |
| - else if (quoteState == IN && line[j] == '\"' && line[j - 1] != '\\') |
164 |
| - quoteState = OUT; |
165 |
| - else if (line[j] == symbol[i] && line[j + 1] != '\'' && quoteState |
166 |
| - == OUT) |
167 |
| - ++charsCount[i]; |
| 103 | + extern int leftParens, rightParens, leftBrackets, rightBrackets, |
| 104 | + leftBraces, rightBraces; |
| 105 | + |
| 106 | + if (leftParens - rightParens < 0) |
| 107 | + printf("Error: missing '('\n"); |
| 108 | + else if (leftParens - rightParens > 0) |
| 109 | + printf("Error: missing ')'\n"); |
| 110 | + if (leftBrackets - rightBrackets < 0) |
| 111 | + printf("Error: missing '['\n"); |
| 112 | + else if (leftBrackets - rightBrackets > 0) |
| 113 | + printf("Error: missing ']'\n"); |
| 114 | + if (leftBraces - rightBraces < 0) |
| 115 | + printf("Error missing '{'\n"); |
| 116 | + else if (leftBraces - rightBraces > 0) |
| 117 | + printf("Error missing '}'\n"); |
168 | 118 | }
|
169 | 119 |
|
170 |
| -void checkSyntax(char symbol[], int charsCount[], int len) |
| 120 | +/* printInfo: print the number of demarcating symbols for comments and quotes */ |
| 121 | +void printInfo(void) |
171 | 122 | {
|
172 |
| - int i, syntaxError = 0; |
173 |
| - |
174 |
| - for (i = 0; i <= len; i += 2) |
175 |
| - if (charsCount[i] != charsCount[i + 1]) { |
176 |
| - printf("Syntax ERROR: unbalanced number of %c %c\n", |
177 |
| - symbol[i], symbol[i + 1]); |
178 |
| - syntaxError = 1; |
179 |
| - } |
180 |
| - if (syntaxError != 1) |
181 |
| - printf("Syntax check: no errors found\n"); |
| 123 | + extern int leftParens, rightParens, leftBrackets, rightBrackets, |
| 124 | + leftBraces, rightBraces; |
| 125 | + |
| 126 | + printf("'(': %i ')': %i Total: %i\n", |
| 127 | + leftParens, rightParens, leftParens + rightParens); |
| 128 | + printf("'[': %i ']': %i Total: %i\n", |
| 129 | + leftBrackets, rightBrackets, leftBrackets + rightBrackets); |
| 130 | + printf("'{': %i '}': %i Total: %i\n", |
| 131 | + leftBraces, rightBraces, leftBraces + rightBraces); |
182 | 132 | }
|
| 133 | + |
183 | 134 | int main(void)
|
184 | 135 | {
|
185 |
| - int len; /* current line length */ |
186 |
| - int start; /* comment's beginning */ |
187 |
| - int end; /* comment's end */ |
188 |
| - int status; /* multi-line comments flag */ |
189 |
| - char line[MAXLINE]; /* current input line */ |
190 |
| - char modLine[MAXLINE]; /* modified output line */ |
191 |
| - int charsCount[6]; |
192 |
| - char symbol[6] = { '{', '}', '(', ')', '[', ']' }; |
193 |
| - |
194 |
| - for (len = 0; len <= 6 ; ++len) /* use len temporarily as an index */ |
195 |
| - charsCount[len] = 0; |
196 |
| - |
197 |
| - status = 0; |
198 |
| - while ((len = getLine(line, MAXLINE)) > 0) { |
199 |
| - |
200 |
| - start = findComment(line, SLASH_ASTERISK); |
201 |
| - end = findComment(line, ASTERISK_SLASH); |
202 |
| - |
203 |
| - if (start < 0 && end < 0 && status == 0) /* no comment found */ |
204 |
| - findCharacter(line, symbol, charsCount, 5); |
205 |
| - else { |
206 |
| - status = delComment(line, modLine, start, end); |
207 |
| - findCharacter(modLine, symbol, charsCount, 5); |
208 |
| - } |
209 |
| - } |
210 |
| - checkSyntax(symbol, charsCount, 5); |
| 136 | + countSymbols(); |
| 137 | + printInfo(); |
| 138 | + checkSymbolsBallance(); |
211 | 139 | return 0;
|
212 | 140 | }
|
0 commit comments