1 /********************************************
2 error.c
3 copyright 2008-2014,2016 Thomas E. Dickey
4 copyright 1991-1994,1995 Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 /*
14 * $MawkId: error.c,v 1.23 2016/09/29 23:00:43 tom Exp $
15 */
16
17 #include <mawk.h>
18 #include <scan.h>
19 #include <bi_vars.h>
20
21 /* for run time error messages only */
22 unsigned rt_nr, rt_fnr;
23 /* *INDENT-OFF* */
24 static const struct token_str {
25 short token;
26 const char *str;
27 } token_str[] = {
28 { EOF, "end of file" },
29 { NL, "end of line" },
30 { SEMI_COLON, ";" },
31 { LBRACE, "{" },
32 { RBRACE, "}" },
33 { SC_FAKE_SEMI_COLON, "}" },
34 { LPAREN, "(" },
35 { RPAREN, ")" },
36 { LBOX, "[" },
37 { RBOX, "]" },
38 { QMARK, "?" },
39 { COLON, ":" },
40 { OR, "||" },
41 { AND, "&&" },
42 { ASSIGN, "=" },
43 { ADD_ASG, "+=" },
44 { SUB_ASG, "-=" },
45 { MUL_ASG, "*=" },
46 { DIV_ASG, "/=" },
47 { MOD_ASG, "%=" },
48 { POW_ASG, "^=" },
49 { EQ, "==" },
50 { NEQ, "!=" },
51 { LT, "<" },
52 { LTE, "<=" },
53 { GT, ">" },
54 { GTE, ">=" },
55 { MATCH, string_buff },
56 { PLUS, "+" },
57 { MINUS, "-" },
58 { MUL, "*" },
59 { DIV, "/" },
60 { MOD, "%" },
61 { POW, "^" },
62 { NOT, "!" },
63 { COMMA, "," },
64 { INC_or_DEC, string_buff },
65 { DOUBLE, string_buff },
66 { STRING_, string_buff },
67 { ID, string_buff },
68 { FUNCT_ID, string_buff },
69 { BUILTIN, string_buff },
70 { IO_OUT, string_buff },
71 { IO_IN, "<" },
72 { PIPE, "|" },
73 { DOLLAR, "$" },
74 { FIELD, "$" },
75 { 0, (char *) 0 }
76 };
77 /* *INDENT-ON* */
78
79 /* if paren_cnt >0 and we see one of these, we are missing a ')' */
80 static const int missing_rparen[] =
81 {
82 EOF, NL, SEMI_COLON, SC_FAKE_SEMI_COLON, RBRACE, 0
83 };
84
85 /* ditto for '}' */
86 static const int missing_rbrace[] =
87 {
88 EOF, BEGIN, END, 0
89 };
90
91 static void
missing(int c,const char * n,unsigned ln)92 missing(int c, const char *n, unsigned ln)
93 {
94 const char *s0, *s1;
95
96 if (pfile_name) {
97 s0 = pfile_name;
98 s1 = ": ";
99 } else
100 s0 = s1 = "";
101
102 errmsg(0, "%s%sline %u: missing %c near %s", s0, s1, ln, c, n);
103 }
104
105 /* we won't use s as input
106 (yacc and bison force this).
107 We will use s for storage to keep lint or the compiler
108 off our back.
109 */
110 void
yyerror(const char * s GCC_UNUSED)111 yyerror(const char *s GCC_UNUSED)
112 {
113 const char *ss = 0;
114 const struct token_str *p;
115 const int *ip;
116
117 for (p = token_str; p->token; p++)
118 if (current_token == p->token) {
119 ss = p->str;
120 break;
121 }
122
123 if (!ss) /* search the keywords */
124 ss = find_kw_str(current_token);
125
126 if (ss) {
127 if (paren_cnt)
128 for (ip = missing_rparen; *ip; ip++)
129 if (*ip == current_token) {
130 missing(')', ss, token_lineno);
131 paren_cnt = 0;
132 goto done;
133 }
134
135 if (brace_cnt)
136 for (ip = missing_rbrace; *ip; ip++)
137 if (*ip == current_token) {
138 missing('}', ss, token_lineno);
139 brace_cnt = 0;
140 goto done;
141 }
142
143 compile_error("syntax error at or near %s", ss);
144
145 } else /* special cases */
146 switch (current_token) {
147 case UNEXPECTED:
148 unexpected_char();
149 goto done;
150
151 case BAD_DECIMAL:
152 compile_error(
153 "syntax error in decimal constant %s",
154 string_buff);
155 break;
156
157 case RE:
158 compile_error(
159 "syntax error at or near /%s/",
160 string_buff);
161 break;
162
163 default:
164 compile_error("syntax error");
165 break;
166 }
167 return;
168
169 done:
170 if (++compile_error_count == MAX_COMPILE_ERRORS)
171 mawk_exit(2);
172 }
173
174 /* generic error message with a hook into the system error
175 messages if errnum > 0 */
176
177 void
errmsg(int errnum,const char * format,...)178 errmsg(int errnum, const char *format,...)
179 {
180 va_list args;
181
182 fprintf(stderr, "%s: ", progname);
183
184 #if OPT_TRACE > 0
185 va_start(args, format);
186 Trace("\n?? errmsg \n");
187 TraceVA(format, args);
188 Trace("\n");
189 va_end(args);
190 #endif
191
192 va_start(args, format);
193 vfprintf(stderr, format, args);
194 va_end(args);
195
196 if (errnum > 0)
197 fprintf(stderr, " (%s)", strerror(errnum));
198
199 fprintf(stderr, "\n");
200 }
201
202 void
compile_error(const char * format,...)203 compile_error(const char *format,...)
204 {
205 va_list args;
206 const char *s0, *s1;
207
208 /* with multiple program files put program name in
209 error message */
210 if (pfile_name) {
211 s0 = pfile_name;
212 s1 = ": ";
213 } else {
214 s0 = s1 = "";
215 }
216
217 #ifdef DEBUG
218 fflush(stdout);
219 #endif
220 fprintf(stderr, "%s: %s%sline %u: ", progname, s0, s1, token_lineno);
221 va_start(args, format);
222 vfprintf(stderr, format, args);
223 va_end(args);
224 fprintf(stderr, "\n");
225 if (++compile_error_count == MAX_COMPILE_ERRORS)
226 mawk_exit(2);
227 }
228
229 void
bozo(const char * s)230 bozo(const char *s)
231 {
232 errmsg(0, "bozo: %s", s);
233 mawk_exit(3);
234 }
235
236 void
overflow(const char * s,unsigned size)237 overflow(const char *s, unsigned size)
238 {
239 errmsg(0, "program limit exceeded: %s size=%u", s, size);
240 mawk_exit(2);
241 }
242
243 /* print as much as we know about where a rt error occurred */
244
245 static void
rt_where(void)246 rt_where(void)
247 {
248 if (FILENAME->type != C_STRING)
249 cast1_to_s(FILENAME);
250
251 fprintf(stderr, "\tFILENAME=\"%s\" FNR=%u NR=%u\n",
252 string(FILENAME)->str, rt_fnr, rt_nr);
253 }
254
255 void
rt_error(const char * format,...)256 rt_error(const char *format,...)
257 {
258 va_list args;
259
260 fprintf(stderr, "%s: run time error: ", progname);
261 va_start(args, format);
262 vfprintf(stderr, format, args);
263 va_end(args);
264 putc('\n', stderr);
265 rt_where();
266 mawk_exit(2);
267 }
268
269 /* run time */
270 void
rt_overflow(const char * s,unsigned size)271 rt_overflow(const char *s, unsigned size)
272 {
273 errmsg(0, "program limit exceeded: %s size=%u", s, size);
274 rt_where();
275 mawk_exit(2);
276 }
277
278 void
unexpected_char(void)279 unexpected_char(void)
280 {
281 int c = yylval.ival;
282
283 fprintf(stderr, "%s: %u: ", progname, token_lineno);
284 if (c > ' ' && c < 127)
285 fprintf(stderr, "unexpected character '%c'\n", c);
286 else
287 fprintf(stderr, "unexpected character 0x%02x\n", c);
288 }
289
290 const char *
type_to_str(int type)291 type_to_str(int type)
292 {
293 const char *retval = 0;
294
295 switch (type) {
296 case ST_NONE:
297 retval = "untyped variable";
298 break;
299 case ST_VAR:
300 retval = "variable";
301 break;
302 case ST_KEYWORD:
303 retval = "keyword";
304 break;
305 case ST_BUILTIN:
306 retval = "builtin";
307 break;
308 case ST_ARRAY:
309 retval = "array";
310 break;
311 case ST_FIELD:
312 retval = "field";
313 break;
314 case ST_NR:
315 retval = "NR";
316 break;
317 case ST_ENV:
318 retval = "ENVIRON";
319 break;
320 case ST_FUNCT:
321 retval = "function";
322 break;
323 case ST_LENGTH:
324 retval = "length";
325 break;
326 case ST_LOCAL_VAR:
327 retval = "local variable";
328 break;
329 case ST_LOCAL_NONE:
330 retval = "local untyped variable";
331 break;
332 case ST_LOCAL_ARRAY:
333 retval = "local array";
334 break;
335 default:
336 bozo("type_to_str");
337 }
338 return retval;
339 }
340
341 /* emit an error message about a type clash */
342 void
type_error(SYMTAB * p)343 type_error(SYMTAB * p)
344 {
345 compile_error("illegal reference to %s %s",
346 type_to_str(p->type), p->name);
347 }
348