Pristine Ack-5.5
[Ack-5.5.git] / util / grind / c.c
1 /* $Id: c.c,v 1.12 1994/06/24 10:59:15 ceriel Exp $ */
2
3 /* Language dependant support; this one is for C */
4
5 #include <stdio.h>
6 #include <alloc.h>
7
8 #include "position.h"
9 #include "class.h"
10 #include "langdep.h"
11 #include "Lpars.h"
12 #include "idf.h"
13 #include "token.h"
14 #include "expr.h"
15 #include "tree.h"
16 #include "operator.h"
17 #include "misc.h"
18
19 extern FILE *db_out, *db_in;
20
21 extern int
22         get_name();
23
24 extern double
25         atof();
26
27 static int
28         print_string(),
29         print_char(),
30         get_number(),
31         getstring(),
32         get_token(),
33         print_op(),
34         unop_prio(),
35         binop_prio(),
36         fix_bin_to_pref();
37
38 static long
39         array_elsize();
40
41 static struct langdep c_lang = {
42         0,
43
44         "%ld",
45         "0%lo",
46         "0x%lX",
47         "%lu",
48         "0x%lX",
49         "%.14g",
50
51         "{",
52         "}",
53         "{",
54         "}",
55         "{",
56         "}",
57
58         print_string,
59         print_char,
60         array_elsize,
61         binop_prio,
62         unop_prio,
63         getstring,
64         get_name,
65         get_number,
66         get_token,
67         print_op,
68         fix_bin_to_pref
69 };
70
71 struct langdep *c_dep = &c_lang;
72
73 static void
74 printchar(f, c, esc)
75   FILE  *f;
76   int   c;
77 {
78   c &= 0377;
79   switch(c) {
80   case '\n':
81         fputs("\\n", f);
82         break;
83   case '\t':
84         fputs("\\t", f);
85         break;
86   case '\b':
87         fputs("\\b", f);
88         break;
89   case '\r':
90         fputs("\\r", f);
91         break;
92   case '\f':
93         fputs("\\f", f);
94         break;
95   case '\\':
96         fputs("\\\\", f);
97         break;
98   case '\'':
99   case '"':
100         fprintf(f, c == esc ? "\\%c" : "%c", c);
101         break;
102   default:
103         fprintf(f, (c >= 040 && c < 0177) ? "%c" : "\\%03o", c);
104         break;
105   }
106 }
107
108 static
109 print_char(c)
110   int   c;
111 {
112   putc('\'', db_out);
113   printchar(db_out, c, '\'');
114   putc('\'', db_out);
115 }
116
117 static
118 print_string(f, s, len)
119   FILE  *f;
120   char  *s;
121   int   len;
122 {
123   register char *str = s;
124
125   putc('"', f);
126   while (*str && len-- > 0) printchar(f, *str++, '"');
127   putc('"', f);
128 }
129
130 extern long     int_size;
131
132 static long
133 array_elsize(size)
134   long  size;
135 {
136   if (! (int_size % size)) return size;
137   if (! (size % int_size)) return size;
138   return ((size + int_size - 1) / int_size) * int_size;
139 }
140
141 static int
142 unop_prio(op)
143   int   op;
144 {
145   switch(op) {
146   case E_NOT:
147   case E_BNOT:
148   case E_MIN:
149   case E_DEREF:
150   case E_PLUS:
151   case E_ADDR:
152         return 12;
153   }
154   return 1;
155 }
156
157 static int
158 binop_prio(op)
159   int   op;
160 {
161   switch(op) {
162   case E_OR:
163         return 2;
164   case E_AND:
165         return 3;
166   case E_BOR:
167         return 4;
168   case E_BXOR:
169         return 5;
170   case E_BAND:
171         return 6;
172   case E_EQUAL:
173   case E_NOTEQUAL:
174         return 7;
175   case E_LT:
176   case E_LTEQUAL:
177   case E_GT:
178   case E_GTEQUAL:
179         return 8;
180   case E_LSFT:
181   case E_RSFT:
182         return 9;
183   case E_MIN:
184   case E_PLUS:
185         return 10;
186   case E_MUL:
187   case E_DIV:
188   case E_ZDIV:
189   case E_MOD:
190   case E_ZMOD:
191         return 11;
192   case E_ARRAY:
193   case E_SELECT:
194         return 12;
195   case E_DERSELECT:
196         return 13;
197   }
198   return 1;
199 }
200
201 static int
202 val_in_base(c, base)
203   register int c;
204 {
205   return is_dig(c) 
206         ? c - '0'
207         : base != 16
208           ? -1
209           : is_hex(c)
210             ? (c - 'a' + 10) & 017
211             : -1;
212 }
213
214 static int
215 get_number(c)
216   register int  c;
217 {
218   char buf[512+1];
219   register int base = 10;
220   register char *p = &buf[0];
221   register long val = 0;
222   register int val_c;
223
224   if (c == '0') {
225         /* check if next char is an 'x' or an 'X' */
226         c = getc(db_in);
227         if (c == 'x' || c == 'X') {
228                 base = 16;
229                 c = getc(db_in);
230         }
231         else    base = 8;
232   }
233   while (val_c = val_in_base(c, base), val_c >= 0) {
234         val = val * base + val_c;
235         if (p - buf < 512) *p++ = c;
236         c = getc(db_in);
237   }
238   if (base == 16 || !((c == '.' || c == 'e' || c == 'E'))) {
239         ungetc(c, db_in);
240         tok.ival = val;
241         return INTEGER;
242   }
243   if (c == '.') {
244         if (p - buf < 512) *p++ = c;
245         c = getc(db_in);
246   }
247   while (is_dig(c)) {
248         if (p - buf < 512) *p++ = c;
249         c = getc(db_in);
250   }
251   if (c == 'e' || c == 'E') {
252         if (p - buf < 512) *p++ = c;
253         c = getc(db_in);
254         if (c == '+' || c == '-') {
255                 if (p - buf < 512) *p++ = c;
256                 c = getc(db_in);
257         }
258         if (! is_dig(c)) {
259                 error("malformed floating constant");
260         }
261         while (is_dig(c)) {
262                 if (p - buf < 512) *p++ = c;
263                 c = getc(db_in);
264         }
265   }
266   ungetc(c, db_in);
267   *p++ = 0;
268   if (p == &buf[512+1]) {
269         error("floating point constant too long");
270   }
271   tok.fval = atof(buf);
272   return REAL;
273 }
274
275 static int
276 get_token(c)
277   register int  c;
278 {
279   switch(c) {
280   case '[':
281         tok.ival = E_ARRAY;
282         /* fall through */
283   case '(':
284   case ')':
285   case ']':
286   case '`':
287   case ':':
288   case ',':
289   case '}':
290   case '{':
291   case '\\':
292         return c;
293   case '.':
294         tok.ival = E_SELECT;
295         return SEL_OP;
296   case '+':
297         tok.ival = E_PLUS;
298         return PREF_OR_BIN_OP;
299   case '-':
300         c = getc(db_in);
301         if (c == '>') {
302                 tok.ival = E_DERSELECT;
303                 return BIN_OP;
304         }
305         ungetc(c, db_in);
306         tok.ival = E_MIN;
307         return PREF_OR_BIN_OP;
308   case '*':
309         tok.ival = E_MUL;
310         return PREF_OR_BIN_OP;
311   case '/':
312         tok.ival = E_ZDIV;
313         return BIN_OP;
314   case '%':
315         tok.ival = E_ZMOD;
316         return BIN_OP;
317   case '&':
318         c = getc(db_in);
319         if (c == '&') {
320                 tok.ival = E_AND;
321                 return BIN_OP;
322         }
323         ungetc(c, db_in);
324         tok.ival = E_BAND;
325         return PREF_OR_BIN_OP;
326   case '^':
327         tok.ival = E_BXOR;
328         return BIN_OP;
329   case '|':
330         c = getc(db_in);
331         if (c == '|') {
332                 tok.ival = E_OR;
333         }
334         else {
335                 ungetc(c, db_in);
336                 tok.ival = E_BOR;
337         }
338         return BIN_OP;
339   case '=':
340         c = getc(db_in);
341         if (c == '=') {
342         }
343         else {
344                 ungetc(c, db_in);
345                 warning("== assumed");
346         }
347         tok.ival = E_EQUAL;
348         return BIN_OP;
349   case '<':
350         c = getc(db_in);
351         if (c == '=') {
352                 tok.ival = E_LTEQUAL;
353                 return BIN_OP;
354         }
355         if (c == '<') {
356                 tok.ival = E_LSFT;
357                 return BIN_OP;
358         }
359         ungetc(c, db_in);
360         tok.ival = E_LT;
361         return BIN_OP;
362   case '>':
363         c = getc(db_in);
364         if (c == '=') {
365                 tok.ival = E_GTEQUAL;
366                 return BIN_OP;
367         }
368         if (c == '>') {
369                 tok.ival = E_RSFT;
370                 return BIN_OP;
371         }
372         ungetc(c, db_in);
373         tok.ival = E_GT;
374         return BIN_OP;
375   case '!':
376         c = getc(db_in);
377         if (c == '=') {
378                 tok.ival = E_NOTEQUAL;
379                 return BIN_OP;
380         }
381         ungetc(c, db_in);
382         tok.ival = E_NOT;
383         return PREF_OP;
384   case '~':
385         tok.ival = E_BNOT;
386         return PREF_OP;
387   default:
388         error((c >= 040 && c < 0177) ? "%s'%c'" : "%s'\\0%o'", "illegal character ", c);
389         return LLlex();
390   }
391 }
392
393 static int
394 quoted(ch)
395   int   ch;
396 {
397   /*    quoted() replaces an escaped character sequence by the
398         character meant.
399   */
400   /* first char after backslash already in ch */
401   if (!is_oct(ch)) {            /* a quoted char */
402         switch (ch) {
403         case 'n':
404                 ch = '\n';
405                 break;
406         case 't':
407                 ch = '\t';
408                 break;
409         case 'b':
410                 ch = '\b';
411                 break;
412         case 'r':
413                 ch = '\r';
414                 break;
415         case 'f':
416                 ch = '\f';
417                 break;
418         }
419   }
420   else {                                /* a quoted octal */
421         register int oct = 0, cnt = 0;
422
423         do {
424                 oct = oct*8 + (ch-'0');
425                 ch = getc(db_in);
426         } while (is_oct(ch) && ++cnt < 3);
427         ungetc(ch, db_in);
428         ch = oct;
429   }
430   return ch&0377;
431
432 }
433
434 static int 
435 getstring(c)
436   int   c;
437 {
438   register int ch;
439   char buf[512];
440   register int len = 0;
441
442   while (ch = getc(db_in), ch != c) {
443         if (ch == '\n') {
444                 error("newline in string");
445                 ungetc(ch, db_in);
446                 break;
447         }
448         if (ch == '\\') {
449                 ch = getc(db_in);
450                 ch = quoted(ch);
451         }
452         buf[len++] = ch;
453   }
454   buf[len++] = 0;
455   if (c == '\'') {
456         long val = 0;
457         ch = 0;
458         while (buf[ch] != 0) {
459                 val = (val << 8) + (buf[ch++] & 0377);
460         }
461         tok.ival = val;
462         return INTEGER;
463   }
464   tok.str = Salloc(buf, (unsigned) len);
465   return STRING;
466 }
467
468 static
469 print_op(f, p)
470   FILE          *f;
471   p_tree        p;
472 {
473   switch(p->t_oper) {
474   case OP_UNOP:
475         switch(p->t_whichoper) {
476         case E_MIN:
477                 fputs("-(", f);
478                 print_node(f, p->t_args[0], 0);
479                 putc(')', f);
480                 break;
481         case E_PLUS:
482                 fputs("+(", f);
483                 print_node(f, p->t_args[0], 0);
484                 putc(')', f);
485                 break;
486         case E_NOT:
487                 fputs("!(", f);
488                 print_node(f, p->t_args[0], 0);
489                 putc(')', f);
490                 break;
491         case E_DEREF:
492                 fputs("*(", f);
493                 print_node(f, p->t_args[0], 0);
494                 putc(')', f);
495                 break;
496         case E_BNOT:
497                 fputs("~(", f);
498                 print_node(f, p->t_args[0], 0);
499                 putc(')', f);
500                 break;
501         case E_ADDR:
502                 fputs("&(", f);
503                 print_node(f, p->t_args[0], 0);
504                 putc(')', f);
505                 break;
506         }
507         break;
508   case OP_BINOP:
509         if (p->t_whichoper == E_ARRAY) {
510                 print_node(f, p->t_args[0], 0);
511                 fputs("[", f);
512                 print_node(f, p->t_args[1], 0);
513                 fputs("]", f);
514                 break;
515         }
516         if (p->t_whichoper == E_DERSELECT) {
517                 print_node(f, p->t_args[0], 0);
518                 fputs("->", f);
519                 print_node(f, p->t_args[1], 0);
520                 break;
521         }
522         if (p->t_whichoper == E_SELECT) {
523                 print_node(f, p->t_args[0], 0);
524                 fputs(".", f);
525                 print_node(f, p->t_args[1], 0);
526                 break;
527         }
528         fputs("(", f);
529         print_node(f, p->t_args[0], 0);
530         switch(p->t_whichoper) {
531         case E_LSFT:
532                 fputs("<<", f);
533                 break;
534         case E_RSFT:
535                 fputs(">>", f);
536                 break;
537         case E_AND:
538                 fputs("&&", f);
539                 break;
540         case E_BAND:
541                 fputs("&", f);
542                 break;
543         case E_OR:
544                 fputs("||", f);
545                 break;
546         case E_BOR:
547                 fputs("|", f);
548                 break;
549         case E_BXOR:
550                 fputs("^", f);
551                 break;
552         case E_ZDIV:
553                 fputs("/", f);
554                 break;
555         case E_ZMOD:
556                 fputs("%", f);
557                 break;
558         case E_PLUS:
559                 fputs("+", f);
560                 break;
561         case E_MIN:
562                 fputs("-", f);
563                 break;
564         case E_MUL:
565                 fputs("*", f);
566                 break;
567         case E_EQUAL:
568                 fputs("==", f);
569                 break;
570         case E_NOTEQUAL:
571                 fputs("!=", f);
572                 break;
573         case E_LTEQUAL:
574                 fputs("<=", f);
575                 break;
576         case E_GTEQUAL:
577                 fputs(">=", f);
578                 break;
579         case E_LT:
580                 fputs("<", f);
581                 break;
582         case E_GT:
583                 fputs(">", f);
584                 break;
585         }
586         print_node(f, p->t_args[1], 0);
587         fputs(")", f);
588         break;
589   }
590 }
591
592 static
593 fix_bin_to_pref(p)
594   p_tree        p;
595 {
596   switch(p->t_whichoper) {
597   case E_MUL:
598         p->t_whichoper = E_DEREF;
599         break;
600   case E_BAND:
601         p->t_whichoper = E_ADDR;
602         break;
603   }
604 }