Move the sources to trunk
[opencv] / apps / cvenv / EiC / preexpr.c
1 /* preexpr.c
2  *
3  *      (C) Copyright Feb  2 1996, Edmond J. Breen.
4  *                 ALL RIGHTS RESERVED.
5  * This code may be copied for personal, non-profit use only.
6  *
7  */
8
9 #ifndef _STANDALONE
10
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <limits.h>
15 #include "xalloc.h"
16 #include "preproc.h"
17
18 #endif
19
20
21 /*ppint expr(int k);*/
22
23 /* typedef unsigned long ppint;   the preprocessor integer */
24
25 typedef struct {
26     union {
27         long s;           /* signed value */
28         unsigned long u;  /* unsigned value */
29     }v;
30     int type;
31 }ppint;
32 /* methods */
33 #define sval(x)  ((x).v.s)
34 #define uval(x)  ((x).v.u)
35 #define tval(x)  ((x).type)
36
37 #define USIGN  1
38 #define SIGN   2
39
40 static ppint do_binary(int tk, ppint left, ppint right);
41 static int getTok(int k);
42 static ppint EiC_expr_unary(void);
43 static ppint get_number(void);
44 static ppint EiC_ifexpr(int k);
45
46
47 enum { LOR = 1, LAND, BOR,  XOR,   AND,    EQ,  NEQ,  LT, LEQ,
48         GT, GEQ, LSHFT, RSHFT,PLUS, MINUS, TIMES, DIV, MOD};
49
50 static char *S;
51 static int TK =0;
52
53 #define _StrSz_ 100
54
55 static void replaceDefines(char *S)
56 {
57     char str[50];
58     int cmode = 0;
59     char *p;
60     p = S;
61     while(*S != '\0') {
62         if(!cmode && (isalpha(*S) || *S == '_')) {
63             if(S[0] == 'd' && S[1] == 'e' &&
64                S[2] == 'f' && S[3] == 'i' &&
65                S[4] == 'n' && S[5] == 'e' &&
66                S[6] == 'd' && !isalpha(S[7]) &&
67                S[7] != '_') {
68                 int br = 0;
69                 int i;
70                 S+=7;
71                 skipfws(S);
72                 if(*S=='(') {
73                     S++;
74                     br = 1;
75                     skipfws(S);
76                 }
77                 i = 0;
78                 while(i < 50 && (isalpha(*S) || *S == '_' || isdigit(*S)))
79                     str[i++] = *S++;
80                 str[i] = '\0';
81                 if(br) {
82                     skipfws(S);
83                     if(*S != ')') 
84                         EiC_pre_error("Missing ')'");
85                     else
86                         S++;
87                 }
88                 if(str[0] != '\0') {
89                     if(EiC_ismacroid(str) > -1)
90                         *p = '1';
91                     else
92                         *p = '0';
93                     ++p;
94                 } else
95                     EiC_pre_error("Missing identifier");
96                 continue;
97             } 
98             do 
99                 *p++ = *S++;
100             while(isalpha(*S) || *S == '_' );
101             continue;
102         } if(*S == '\'')
103             cmode = !cmode;
104         *p++ = *S++;
105     }
106     *p = '\0';
107 }
108
109 static void replaceIdentifiers(char *S)
110 {
111     int i;
112     char str[50];
113     char *p;
114     int cmode = 0;
115
116     p = S;    
117     
118     while(1) {
119         while(isspace(*S))
120             *p++ = *S++;
121         if(!*S)
122             return;
123         if(!isalpha(*S) && *S != '_') {
124             if(isdigit(*S) || *S == '\'') { /* skip throu numbers or literals*/
125                 while(*S && !isspace(*S))
126                     *p++ = *S++;
127             } else 
128                 while(*S && !isspace(*S) && *S != '_' && ispunct(*S))
129                     *p++ =  *S++;
130             continue;
131         }
132         if(!cmode) {
133             i = 0;
134             while(i < 50 && (isalpha(*S) || *S == '_' || isdigit(*S)) )
135                 str[i++] = *S++;
136             str[i] = '\0';
137             if(strcmp(str,"sizeof") == 0)
138                 EiC_pre_error("Illegal sizeof operator");
139             else
140                 *p++ = '0';
141         } else
142             *p++ = *S++;
143     }
144 }
145
146
147 int EiC_cpp_parse(char *s)
148 {
149
150     ppint res;
151     S = s;
152     replaceDefines(S);
153
154 #ifdef DEBUG
155     printf("return [%s]\n",S);
156 #endif
157
158     S = s  = EiC_process2(S,0,0);
159
160     replaceIdentifiers(S);
161
162 #ifdef DEBUG
163     printf("return [%s]\n",S);
164 #endif
165
166     res = EiC_ifexpr(0);
167
168     if(s)
169         xfree(s);
170
171     if(tval(res) == SIGN)
172         return sval(res);
173     else
174         return uval(res);
175 }
176
177 static ppint EiC_ifexpr(int k)
178 {
179     ppint res;
180     int k1, tk;
181     res = EiC_expr_unary();
182     for(k1 = 10; k1 >= k; k1--)
183         while((tk = getTok(k1))) 
184             res = do_binary(tk, res,EiC_ifexpr(k1>8?k1:k1+1));
185     return res;
186 }
187
188 #define eval(a,l,r,op)\
189 {\
190      if(tval(l) == SIGN)\
191          sval(a) = sval(l) op sval(r);\
192      else\
193          uval(a) = uval(l) op uval(r);\
194 }
195                  
196
197 static ppint do_binary(int tk, ppint left, ppint right)
198 {
199     ppint r;
200
201     if(tval(left) == USIGN || tval(right) == USIGN)
202         tval(r) = tval(left) = tval(right) = USIGN;
203     else
204         tval(r) = tval(left) = tval(right) = SIGN;
205     
206
207         
208     switch(tk) {
209       case BOR: eval(r,left,right, | ); break;
210       case XOR: eval(r,left,right, ^ ); break;
211       case AND: eval(r,left,right, & ); break;
212       case LT:  eval(r,left,right, < ); break;
213       case LEQ: eval(r,left,right, <= ); break;
214       case EQ:  eval(r,left,right,  == ); break;
215       case NEQ: eval(r,left,right,  != ); break;
216       case GT:  eval(r,left,right, > ); break;
217       case GEQ: eval(r,left,right, >= ); break;
218       case LOR: eval(r,left,right, || ); break;
219       case LAND: eval(r,left,right, && ); break;
220       case LSHFT: eval(r,left,right, << ); break;
221       case RSHFT: eval(r,left,right, >> ); break;       
222       case PLUS: eval(r,left,right, + ); break;
223       case MINUS: eval(r,left,right, - ); break;
224       case TIMES: eval(r,left,right, * ); break;
225       case DIV: eval(r,left,right, / ); break;
226       case MOD: eval(r,left,right, % ); break;
227     }
228     return r;
229 }
230
231 static int getTok(int k)
232 {
233     TK = 0;
234     
235     while(isspace(*S))
236         S++;
237         
238     switch(k) {
239       case 1: /* LOR */
240         if(*S == '|' && *(S+1) == '|') {S+=2; TK = LOR;}
241         break;
242       case 2: /* LAND */
243         if(*S == '&' && *(S+1) == '&') {S+=2; TK = LAND;}
244       case 3: /* BOR */
245         if(*S == '|' && *(S+1) != '|') {S++; TK = BOR;}
246         break;
247       case 4: /* XOR */
248         if(*S == '^') {S++; TK = GEQ;}
249         break;
250       case 5: /* AND */
251         if(*S == '&' && *(S+1) != '&') {S++; TK = GEQ;}
252         break;
253       case 6: /* EQ, NEQ */
254         if(*S == '=' && *(S+1) == '=') {S+=2; TK = EQ;}
255         else if(*S == '!' && *(S+1) == '=') {S+=2; TK = NEQ;}
256         break;
257       case 7: /* LT, LEQ, GT, GEQ */
258         if(*S == '<') {
259             S++;
260             if(*S == '='){S++;TK = LEQ;}
261             else TK = LT;
262         } else if(*S == '>') {
263             S++;
264             if(*S == '='){S++; TK = GEQ;}
265             else TK = GT;
266         }
267         break;
268       case 8:  /* LSHFT, RSHFT */
269         if(*S == '<' && *(S+1) == '<') {S+=2; TK = LSHFT;}
270         else if(*S == '>' && *(S+1) == '>') {S+=2; TK = RSHFT;}
271         break;
272       case 9: /* PLUS, MINUS */
273         if(*S == '-') {S++;TK = MINUS;}
274         else if(*S == '+') {S++; TK = PLUS;}
275         break;
276       case 10: /* TIMES, DIV, MOD */
277         if(*S == '*') {S++;TK = TIMES;}
278         else if(*S == '/') {S++; TK = DIV;}
279         else if(*S == '%') {S++; TK = MOD;}
280         break;
281     }
282     return TK;
283 }
284
285 static int get_oct(int x)
286 {
287     return x>='0'&&x<='7'? x-'0':-1;
288 }
289
290 static int get_hex(int x)
291 {
292     
293     if (x >= '0' && x <= '9')
294         x -= '0';
295     else if (x >= 'a' && x <= 'f')
296          x = x - 'a' + 10;
297     else if (x >= 'A' && x <= 'F')
298         x = x - 'A' + 10;
299     else
300         x = -1;
301     return x;
302 }
303
304 static int get_dec(int x)
305 {
306     return x >= '0' && x <= '9' ? x-'0':-1;
307 }
308
309
310 static ppint get_number()   /* collect hex, octal and decimal integers */
311 {
312     int (*f)(int x);
313     int radix,val;
314     ppint res = {{0},SIGN};
315
316     if(*S == '0') {
317         S++;
318         if(*S == 'x' || *S == 'X') { /* get hex number */
319             S++;
320             radix = 16;
321             f = get_hex;
322         } else { /* get octal number */
323             radix = 8;
324             f = get_oct;
325         }
326     } else { /* get decimal number */
327         radix = 10;
328         f = get_dec;
329     }
330     while((val = (*f)(*S++)) >= 0)
331         uval(res) = uval(res) * radix + val;
332     S--;
333
334     if(uval(res) > LONG_MAX)
335         tval(res) = USIGN;
336     
337     /* check for prefix */    
338     if(*S=='u' || *S=='U') {
339         S++;
340         tval(res) = USIGN;
341     } if(*S=='l' || *S=='L')
342         S++;
343     return res;
344 }
345         
346
347 static int get_charConst()
348 {
349     
350     int c;
351     switch (*S) {
352       case 'n': c = '\n'; break; /* newline */
353       case 't': c = '\t'; break; /* tabspace */
354       case 'v': c = '\v'; break; /* vertical tab */
355       case 'b': c = '\b'; break; /* backspace */
356       case 'r': c = '\r'; break; /* carriage return */
357       case 'f': c = '\f'; break; /* formfeed */
358       case 'a': c = '\a'; break; /* bell */
359       case '\\': c = '\\'; break; /* backslash */
360       case '\'': c = '\''; break; /* single quote */
361       case '"': c = '\"'; break; /* double quote */
362       case 'x':                 /* string of hex characters */
363       case 'X':{
364           int i, val = 0;
365           S++;
366           while ((i = get_hex(*S)) > -1) {
367               S++;
368               val = val * 16 + i;
369           }
370           if (val > 255)
371               EiC_pre_error("Illegal character hex value");
372           c = val;
373       }
374         break;
375       default:
376         if (isdigit(*S)) {      /* treat as octal characters */
377             int i, val = 0;
378             while ((i = get_oct(*S)) > -1) {
379                 val = val * 8 + i;
380                 S++;
381             }
382             if (val > 255)
383                 EiC_pre_error("Illegal character octal value");
384             c = val;
385         } else {
386             EiC_pre_error("Illegal character escape sequence `\\%c'", *S);
387             c = *S++;
388         }
389         break;
390     }
391     return c;
392 }
393
394 static ppint EiC_expr_unary()
395 {
396     ppint res;
397     
398     while(isspace(*S))
399         S++;
400     if(isdigit(*S)) {
401         res = get_number();
402     } else if( *S == '(') {
403         S++;
404         res = EiC_ifexpr(0);
405         if(*S != ')')
406             EiC_pre_error("Unbalanced parenthesis");
407         S++;
408     } else if(*S == '!') {
409         S++;
410         res = EiC_expr_unary();
411         uval(res) = !uval(res);
412     } else if(*S == '-') {
413         S++;
414         if(*S == '-')
415             EiC_pre_error("-- not allowed in operand of #if");
416         res = EiC_expr_unary(); 
417         tval(res) = SIGN;
418         sval(res) = -uval(res);
419     } else if(*S == '+') {
420         S++;
421         if(*S == '+')
422             EiC_pre_error("++ not allowed in operand of #if");
423         res = EiC_expr_unary();
424     } else if(*S == '~') {
425         S++;
426         res = EiC_expr_unary();
427         uval(res) = ~uval(res);
428     } else if(*S == '\'') { /* char constants */
429         S++;
430         if(*S == '\\') {
431             S++;
432             uval(res) = get_charConst();
433         } else
434             uval(res) = *S++;
435         if(*S != '\'')
436             EiC_pre_error("Missing closing single quote '");
437         else
438             S++;
439         tval(res) = SIGN;
440     } else
441         EiC_pre_error("Illegal constant expression");
442     return res;
443 }
444
445
446
447
448
449
450
451