|
1 | 1 | /*
|
2 | 2 | * Exercise 5-18. Make dcl recover from input error.
|
| 3 | + * |
3 | 4 | * By Faisal Saadatmand
|
4 | 5 | */
|
5 | 6 |
|
| 7 | +#include <ctype.h> |
6 | 8 | #include <stdio.h>
|
7 | 9 | #include <string.h>
|
8 |
| -#include <ctype.h> |
9 | 10 |
|
10 |
| -#define MAXTOKEN 100 |
11 |
| -#define BUFSIZE 100 |
12 |
| -#define EMPTY_LINE (tokentype == '\n') |
13 |
| -#define RECOVER(c) while (((c) = getch()) != '\n') |
14 |
| -#define SKIP_BLANKS(c) while (((c) = getch()) == ' ' || (c) == '\t') |
| 11 | +#define BUFSIZE 100 |
| 12 | +#define MAXLEN 1000 |
| 13 | +#define MAXTOKEN 100 |
15 | 14 |
|
16 |
| -enum { NAME, PARENS, BRACKETS, ERROR }; |
| 15 | +enum { NAME, PARENS, BRACKETS }; |
| 16 | +enum { GOOD, FAIL }; |
17 | 17 |
|
18 | 18 | /* functions */
|
19 |
| -int gettoken(void); |
20 | 19 | void dcl(void);
|
21 | 20 | void dirdcl(void);
|
22 |
| -int getch(void); |
23 |
| -void ungetch(int); |
| 21 | +int gettoken(); |
| 22 | +void errmsg(const char *); |
24 | 23 |
|
25 | 24 | /* globals */
|
26 |
| -char token[MAXTOKEN]; /* last token string */ |
27 |
| -int tokentype; /* type of last token */ |
28 |
| -char name[MAXTOKEN]; /* identifier name */ |
29 |
| -char datatype[MAXTOKEN]; /* data type = char, int, etc. */ |
30 |
| -char out[1000]; |
31 |
| -int buf[BUFSIZE]; /* buffer from ungetch */ |
32 |
| -int bufp; /* next free position in buf */ |
33 |
| -int pushedEOF; /* signals EOF has been pushed-back */ |
| 25 | +int buf[BUFSIZE]; /* buffer from ungetch */ |
| 26 | +int bufp = 0; /* next free position in buf */ |
| 27 | +int tokentype; /* type of last token */ |
| 28 | +char token[MAXTOKEN]; /* last token string */ |
| 29 | +char name[MAXTOKEN]; /* identifier name */ |
| 30 | +char datatype[MAXTOKEN]; /* data type = char, int, etc. */ |
| 31 | +char out[MAXLEN]; /* composed output string */ |
| 32 | +char state; /* flag to propagate the current state of parsing */ |
| 33 | + |
| 34 | +/* dcl: parse a declarator */ |
| 35 | +void dcl(void) |
| 36 | +{ |
| 37 | + int ns; /* number of asterisks */ |
| 38 | + |
| 39 | + for (ns = 0; gettoken() == '*'; ++ns) /* count *'s */ |
| 40 | + ; |
| 41 | + dirdcl(); |
| 42 | + while (ns-- > 0) |
| 43 | + strcat(out, " pointer to"); |
| 44 | +} |
34 | 45 |
|
35 |
| -/* gettoekn: return next token */ |
| 46 | +/* dirdcl: parse a direct declarator */ |
| 47 | +void dirdcl(void) |
| 48 | +{ |
| 49 | + int type; |
| 50 | + |
| 51 | + if (tokentype == '(') { /* ( dcl ) */ |
| 52 | + dcl(); |
| 53 | + if (tokentype != ')') |
| 54 | + errmsg("error: missing )\n"); |
| 55 | + } else if (tokentype == NAME) /* variable name */ |
| 56 | + strcpy(name, token); |
| 57 | + else |
| 58 | + errmsg("error: expected name of (dcl)\n"); |
| 59 | + while ((type = gettoken()) == PARENS || type == BRACKETS) |
| 60 | + if (type == PARENS) |
| 61 | + strcat(out, " function returning"); |
| 62 | + else { |
| 63 | + strcat(out, " array"); |
| 64 | + strcat(out, token); |
| 65 | + strcat(out, " of"); |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +/* errmsg: print error message, set state flag to FAIL */ |
| 70 | +void errmsg(const char *msg) |
| 71 | +{ |
| 72 | + printf("%s", msg); |
| 73 | + state = FAIL; /* propagate state of parsing to allow for error recovery */ |
| 74 | +} |
| 75 | + |
| 76 | +/* gettoken: return next token */ |
36 | 77 | int gettoken(void)
|
37 | 78 | {
|
38 | 79 | int c, getch(void);
|
39 | 80 | void ungetch(int);
|
40 | 81 | char *p = token;
|
41 | 82 |
|
42 |
| - SKIP_BLANKS(c); |
43 |
| - |
| 83 | + if (state == FAIL) { |
| 84 | + state = GOOD; |
| 85 | + return tokentype; /* push back the previous token */ |
| 86 | + } |
| 87 | + while ((c = getch()) == ' ' || c == '\t') |
| 88 | + ; |
44 | 89 | if (c == '(') {
|
45 |
| - SKIP_BLANKS(c); /* allow spaces in parens */ |
46 |
| - if (c == ')') { |
| 90 | + if ((c = getch()) == ')') { |
47 | 91 | strcpy(token, "()");
|
48 | 92 | return tokentype = PARENS;
|
49 |
| - } else { |
50 |
| - ungetch(c); |
51 |
| - return tokentype = '('; |
52 | 93 | }
|
53 |
| - } else if (c == '[') { |
54 |
| - for (*p++ = c; (*p = getch()) != ']'; p++) |
55 |
| - if (*p == '\n') /* error check: missing ']' */ |
56 |
| - return *p; |
57 |
| - *++p = '\0'; |
| 94 | + ungetch(c); |
| 95 | + return tokentype = '('; |
| 96 | + } |
| 97 | + if (c == '[') { |
| 98 | + for (*p++ = c; (*p++ = getch()) != ']'; ) |
| 99 | + ; |
| 100 | + *p = '\0'; |
58 | 101 | return tokentype = BRACKETS;
|
59 |
| - } else if (isalpha(c)) { |
60 |
| - for (*p++ = c; isalnum(c = getch()); p++) |
61 |
| - *p = c; |
| 102 | + } |
| 103 | + if (isalpha(c)) { |
| 104 | + for (*p++ = c; isalnum(c = getch()); ) |
| 105 | + *p++ = c; |
62 | 106 | *p = '\0';
|
63 | 107 | ungetch(c);
|
64 | 108 | return tokentype = NAME;
|
65 |
| - } else |
66 |
| - return tokentype = c; |
| 109 | + } |
| 110 | + return tokentype = c; |
67 | 111 | }
|
68 | 112 |
|
69 | 113 | /* getch: get a (possibly pushed back) character */
|
70 | 114 | int getch(void)
|
71 | 115 | {
|
72 |
| - return (bufp > 0) ? buf[--bufp] : (pushedEOF) ? EOF : getchar(); |
| 116 | + return (bufp > 0) ? buf[--bufp] : getchar(); |
73 | 117 | }
|
74 | 118 |
|
75 | 119 | /* ungerch: push character back on input */
|
76 | 120 | void ungetch(int c)
|
77 | 121 | {
|
78 |
| - if (c == EOF) { |
79 |
| - pushedEOF = 1; |
80 |
| - return; |
81 |
| - } |
82 |
| - |
83 | 122 | if (bufp >= BUFSIZE)
|
84 | 123 | printf("ungetch: too many characters\n");
|
85 | 124 | else
|
86 | 125 | buf[bufp++] = c;
|
87 | 126 | }
|
88 | 127 |
|
89 |
| -/* dcl: parse a declarator */ |
90 |
| -void dcl (void) |
91 |
| -{ |
92 |
| - int ns; |
93 |
| - |
94 |
| - for (ns = 0; gettoken() == '*'; ) /*count *'s */ |
95 |
| - ns++; |
96 |
| - dirdcl(); |
97 |
| - while (ns-- > 0) |
98 |
| - strcat(out, " pointer to"); |
99 |
| -} |
100 |
| - |
101 |
| -/* dirdcl: parse a direct declarator */ |
102 |
| -void dirdcl(void) |
103 |
| -{ |
104 |
| - int type; |
105 |
| - |
106 |
| - if (tokentype == '(') { /* ( dcl ) */ |
107 |
| - dcl (); |
108 |
| - if (tokentype != ')') { |
109 |
| - printf("error: missing )\n"); |
110 |
| - tokentype = ERROR; |
111 |
| - } |
112 |
| - } else if (tokentype == NAME) { /* variable name */ |
113 |
| - strcpy(name, token); |
114 |
| - } else { |
115 |
| - printf("error: expected name or (dcl)\n"); |
116 |
| - tokentype = ERROR; |
117 |
| - } |
118 |
| - |
119 |
| - if (tokentype == ERROR) |
120 |
| - return; |
121 |
| - |
122 |
| - while ((type = gettoken()) == PARENS || type == BRACKETS) |
123 |
| - if (type == PARENS) |
124 |
| - strcat(out, " function returning"); |
125 |
| - else { |
126 |
| - strcat(out, " array"); |
127 |
| - strcat(out, token); |
128 |
| - strcat(out, " of"); |
129 |
| - } |
130 |
| -} |
131 |
| - |
132 | 128 | /* convert declaration to words */
|
133 |
| -int main(void) |
| 129 | +int main(void) |
134 | 130 | {
|
135 |
| - int c; |
136 |
| - |
137 |
| - while (gettoken() != EOF) { /* last token on line */ |
138 |
| - strcpy(datatype, token); /* is the datatype */ |
| 131 | + while (gettoken() != EOF) { /* first token on line */ |
| 132 | + if (tokentype == '\n') /* skip empty lines */ |
| 133 | + continue; |
| 134 | + strcpy(datatype, token); /* is the datatype */ |
139 | 135 | out[0] = '\0';
|
140 |
| - if (EMPTY_LINE) |
141 |
| - continue; /* skip empty input lines */ |
142 |
| - dcl(); |
143 |
| - if (tokentype != '\n') { |
144 |
| - printf("syntax error\n"); |
145 |
| -// RECOVER(c); |
146 |
| -// ungetch(c); |
147 |
| - } else |
| 136 | + dcl(); /* parse rest of line */ |
| 137 | + if (tokentype != '\n') |
| 138 | + printf("%s", "syntax error\n"); |
| 139 | + else if (state == GOOD) |
148 | 140 | printf("%s: %s %s\n", name, out, datatype);
|
149 | 141 | }
|
150 | 142 | return 0;
|
|
0 commit comments