|
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(charline[], charsymbol[], intcharsCount[], intlen) |
| 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