Git init
[external/mawk.git] / error.c
1
2 /********************************************
3 error.c
4 copyright 1991, 1992 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 /* $Log: error.c,v $
15  * Revision 1.6  1995/06/06  00:18:22  mike
16  * change mawk_exit(1) to mawk_exit(2)
17  *
18  * Revision 1.5  1994/12/13  00:26:33  mike
19  * rt_nr and rt_fnr for run-time error messages
20  *
21  * Revision 1.4  1994/09/23  00:20:00  mike
22  * minor bug fix: handle \ in eat_nl()
23  *
24  * Revision 1.3  1993/07/17  13:22:49  mike
25  * indent and general code cleanup
26  *
27  * Revision 1.2  1993/07/04  12:51:44  mike
28  * start on autoconfig changes
29  *
30  * Revision 1.1.1.1  1993/07/03  18:58:11  mike
31  * move source to cvs
32  *
33  * Revision 5.3  1993/01/22  14:55:46  mike
34  * trivial change for unexpected_char()
35  *
36  * Revision 5.2  1992/10/02  23:26:04  mike
37  * using vargs.h
38  *
39  * Revision 5.1  1991/12/05  07:55:48  brennan
40  * 1.1 pre-release
41  *
42 */
43
44
45 #include  "mawk.h"
46 #include  "scan.h"
47 #include  "bi_vars.h"
48 #include  "vargs.h"
49
50
51 #ifndef  EOF
52 #define  EOF  (-1)
53 #endif
54
55 static void  PROTO( rt_where, (void) ) ;
56 static void  PROTO( missing, (int, char *, int) ) ;
57 static char *PROTO( type_to_str, (int) ) ;
58
59
60 #ifdef  NO_VFPRINTF
61 #define  vfprintf  simple_vfprintf
62 #endif
63
64
65 /* for run time error messages only */
66 unsigned rt_nr , rt_fnr ;
67
68 static struct token_str  {
69 short token ;
70 char *str ; }  token_str[] = {
71 {EOF , "end of file" },
72 {NL , "end of line"},
73 {SEMI_COLON , ";" },
74 {LBRACE , "{" },
75 {RBRACE , "}" },
76 {SC_FAKE_SEMI_COLON, "}"},
77 {LPAREN , "(" },
78 {RPAREN , ")" },
79 {LBOX , "["},
80 {RBOX , "]"},
81 {QMARK , "?"},
82 {COLON , ":"},
83 {OR, "||"},
84 {AND, "&&"},
85 {ASSIGN , "=" },
86 {ADD_ASG, "+="},
87 {SUB_ASG, "-="},
88 {MUL_ASG, "*="},
89 {DIV_ASG, "/="},
90 {MOD_ASG, "%="},
91 {POW_ASG, "^="},
92 {EQ  , "==" },
93 {NEQ , "!="},
94 {LT, "<" },
95 {LTE, "<=" },
96 {GT, ">"},
97 {GTE, ">=" },
98 {MATCH, string_buff},
99 {PLUS , "+" },
100 {MINUS, "-" },
101 {MUL , "*" },
102 {DIV, "/"  },
103 {MOD, "%" },
104 {POW, "^" },
105 {NOT, "!" },
106 {COMMA, "," },
107 {INC_or_DEC , string_buff },
108 {DOUBLE  , string_buff },
109 {STRING_  , string_buff },
110 {ID  , string_buff },
111 {FUNCT_ID  , string_buff },
112 {BUILTIN  , string_buff },
113 {IO_OUT , string_buff },
114 {IO_IN, "<" },
115 {PIPE, "|" },
116 {DOLLAR, "$" },
117 {FIELD, "$" },
118 {0, (char *) 0 }} ;
119
120 /* if paren_cnt >0 and we see one of these, we are missing a ')' */
121 static int missing_rparen[] =
122 { EOF, NL, SEMI_COLON, SC_FAKE_SEMI_COLON, RBRACE, 0 } ;
123
124 /* ditto for '}' */
125 static int missing_rbrace[] =
126 { EOF, BEGIN, END , 0 } ;
127
128 static void missing( c, n , ln)
129   int c ;
130   char *n ;
131   int ln ;
132 { char *s0, *s1 ;
133
134   if ( pfile_name )
135   { s0 = pfile_name ; s1 = ": " ; }
136   else s0 = s1 = "" ;
137
138   errmsg(0, "%s%sline %u: missing %c near %s" ,s0, s1, ln, c, n) ; 
139 }  
140
141 void  yyerror(s)
142   char *s ; /* we won't use s as input 
143   (yacc and bison force this).
144   We will use s for storage to keep lint or the compiler
145   off our back */
146 { struct token_str *p ;
147   int *ip ;
148
149   s = (char *) 0 ;
150
151   for ( p = token_str ; p->token ; p++ )
152       if ( current_token == p->token )
153       { s = p->str ; break ; }
154
155   if ( ! s )  /* search the keywords */
156          s = find_kw_str(current_token) ;
157
158   if ( s )
159   {
160     if ( paren_cnt )
161         for( ip = missing_rparen ; *ip ; ip++)
162           if ( *ip == current_token )
163           { missing(')', s, token_lineno) ;
164             paren_cnt = 0 ;
165             goto done ;
166           }
167
168     if ( brace_cnt )
169         for( ip = missing_rbrace ; *ip ; ip++)
170           if ( *ip == current_token )
171           { missing('}', s, token_lineno) ;
172             brace_cnt = 0 ;
173             goto done ;
174           }
175
176     compile_error("syntax error at or near %s", s) ;
177
178   }
179   else  /* special cases */
180   switch ( current_token )
181   {
182     case UNEXPECTED :
183             unexpected_char() ; 
184             goto done ;
185
186     case BAD_DECIMAL :
187             compile_error(
188               "syntax error in decimal constant %s",
189               string_buff ) ;
190             break ;
191
192     case RE :
193             compile_error(
194             "syntax error at or near /%s/", 
195             string_buff ) ;
196             break ;
197
198     default :
199             compile_error("syntax error") ;
200             break ;
201   }
202   return ;
203
204 done :
205   if ( ++compile_error_count == MAX_COMPILE_ERRORS ) mawk_exit(2) ;
206 }
207
208
209 /* generic error message with a hook into the system error 
210    messages if errnum > 0 */
211
212 void  errmsg VA_ALIST2(int , errnum, char *, format)
213   va_list args ;
214
215   fprintf(stderr, "%s: " , progname) ;
216
217   VA_START2(args, int, errnum, char *, format) ;
218   vfprintf(stderr, format, args) ;
219   va_end(args) ;
220
221   if ( errnum > 0 ) fprintf(stderr, " (%s)" , strerror(errnum) ) ;
222
223   fprintf( stderr, "\n") ;
224 }
225
226 void  compile_error  VA_ALIST(char *, format)
227   va_list args ;
228   char *s0, *s1 ;
229
230   /* with multiple program files put program name in
231      error message */
232   if ( pfile_name )
233   { s0 = pfile_name ; s1 = ": " ; }
234   else
235   { s0 = s1 = "" ; }
236
237   fprintf(stderr, "%s: %s%sline %u: " , progname, s0, s1,token_lineno) ;
238   VA_START(args, char *, format) ;
239   vfprintf(stderr, format, args) ;
240   va_end(args) ;
241   fprintf(stderr, "\n") ;
242   if ( ++compile_error_count == MAX_COMPILE_ERRORS ) mawk_exit(2) ;
243 }
244
245 void  rt_error VA_ALIST( char *, format)
246   va_list args ;
247
248   fprintf(stderr, "%s: run time error: " , progname ) ;
249   VA_START(args, char *, format) ;
250   vfprintf(stderr, format, args) ;
251   va_end(args) ;
252   putc('\n',stderr) ;
253   rt_where() ;
254   mawk_exit(2) ;
255 }
256
257
258 void bozo(s)
259   char *s ;
260
261   errmsg(0, "bozo: %s" , s) ; 
262   mawk_exit(3) ;
263 }
264
265 void overflow(s, size)
266   char *s ; unsigned size ;
267
268   errmsg(0 , "program limit exceeded: %s size=%u", s, size) ;
269   mawk_exit(2) ; 
270 }
271
272
273 /* print as much as we know about where a rt error occured */
274
275 static void rt_where()
276 {
277   if ( FILENAME->type != C_STRING ) cast1_to_s(FILENAME) ;
278
279   fprintf(stderr, "\tFILENAME=\"%s\" FNR=%u NR=%u\n", 
280     string(FILENAME)->str, rt_fnr, rt_nr) ;
281 }
282
283 /* run time */
284 void rt_overflow(s, size)
285   char *s ; unsigned size ;
286
287   errmsg(0 , "program limit exceeded: %s size=%u", s, size) ;
288   rt_where() ;
289   mawk_exit(2) ;
290 }
291
292 void 
293 unexpected_char()
294 { int c = yylval.ival ;
295
296   fprintf(stderr, "%s: %u: ", progname, token_lineno) ;
297   if ( c > ' ' && c < 127 )
298       fprintf(stderr, "unexpected character '%c'\n" , c) ;
299   else
300       fprintf(stderr, "unexpected character 0x%02x\n" , c) ;
301 }
302
303 static char *type_to_str( type )
304   int type ;
305 { char *retval ;
306
307   switch( type )
308   {
309     case  ST_VAR :  retval = "variable" ; break ;
310     case  ST_ARRAY :  retval = "array" ; break ;
311     case  ST_FUNCT :  retval = "function" ; break ;
312     case  ST_LOCAL_VAR : retval = "local variable" ; break ;
313     case  ST_LOCAL_ARRAY : retval = "local array" ; break ;
314     default : bozo("type_to_str") ;
315   }
316   return retval ;
317 }
318
319 /* emit an error message about a type clash */
320 void type_error(p)
321   SYMTAB *p ;
322 { compile_error("illegal reference to %s %s", 
323     type_to_str(p->type) , p->name) ;
324 }
325
326
327
328 #ifdef  NO_VFPRINTF
329
330 /* a minimal vfprintf  */
331 int simple_vfprintf( fp, format, argp)
332   FILE *fp ;
333   char *format ; 
334   va_list  argp ;
335
336   char *q , *p, *t ;
337   int l_flag ;
338   char xbuff[64] ;
339
340   q = format ;
341   xbuff[0] = '%' ;
342
343   while ( *q != 0 )
344   { 
345     if ( *q != '%' )
346     {
347       putc(*q, fp) ; q++ ; continue ;
348     }
349
350     /* mark the start with p */
351     p = ++q ;  t = xbuff + 1 ;
352
353     if ( *q == '-' )  *t++ = *q++ ;
354     while ( scan_code[*(unsigned char*)q] == SC_DIGIT ) *t++ = *q++ ;
355     if ( *q == '.' )
356     { *t++ = *q++ ;
357       while ( scan_code[*(unsigned char*)q] == SC_DIGIT ) *t++ = *q++ ;
358     }
359
360     if ( *q == 'l' )  { l_flag = 1 ; *t++ = *q++ ; }
361     else l_flag = 0 ;
362
363     
364     *t = *q++ ; t[1] = 0 ;
365
366     switch( *t )
367     {
368       case 'c' :  
369       case 'd' :
370       case 'o' :
371       case 'x' :
372       case 'u' :
373            if ( l_flag )  fprintf(fp, xbuff, va_arg(argp,long) ) ;
374            else  fprintf(fp, xbuff, va_arg(argp, int)) ;
375            break ;
376
377       case  's' :
378            fprintf(fp, xbuff, va_arg(argp, char*)) ;
379            break ;
380
381       case  'g' :
382       case  'f' :
383            fprintf(fp, xbuff, va_arg(argp, double)) ;
384            break ;
385
386       default:
387            putc('%', fp) ; 
388            q = p ;
389            break ;
390     }
391   }
392   return 0 ; /* shut up */
393 }
394
395 #endif  /* USE_SIMPLE_VFPRINTF */
396
397