Pristine Ack-5.5
[Ack-5.5.git] / util / ceg / as_parser / eval / eval.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include "states.h"
4
5
6 #define is_letter( c)      ( isalpha( c) || isdigit( c) || c == '_')
7 #define save_or_put(c)     if(previous_state==TEXT)putchar(c);else *bufptr++=c
8
9
10
11 /* This program processes the file 'as.c', and will take care of things like
12  * %d( <expression>), @func( arg), %$(   ), etc.
13  * The main-loop is constructed as a finite automat.
14  */
15
16
17 main()
18 {
19         char buffer[256], *bufptr = buffer;
20         int c, state = TEXT, previous_state = TEXT, depth = 0;
21
22         pr_header();
23         while ( ( c = getchar()) != EOF)
24                 switch ( state) {
25                   case TEXT :
26                                 switch ( c) {
27                                   case '/' : state = SLASH;
28                                              previous_state = TEXT;
29                                              save_or_put( c);
30                                              break;
31                                   case '"' : state = STRING;
32                                              previous_state = TEXT;
33                                              save_or_put( c);
34                                              break;
35                                   case '\'': state = CHAR_CONST;
36                                              previous_state = TEXT;
37                                              save_or_put( c);
38                                              break;
39                                   case '@' : state = AT;
40                                              break;
41                                   default  : putchar( c);
42                                              break;
43                                 }
44                                 break;
45
46
47                   case SLASH :
48                                 state =  ( c == '*' ? COMMENT : TEXT);
49                                 save_or_put( c);
50                                 break;
51                   case COMMENT :
52                                 if ( c == '*')
53                                         state = STAR;
54                                 save_or_put( c);
55                                 break;
56                   case STAR :
57                                 if ( c == '/')
58                                         state = previous_state; 
59                                 else if ( c != '*')
60                                         state = COMMENT;
61                                 save_or_put( c);
62                                 break;
63
64
65
66                   case STRING :
67                                 if ( c == '"')
68                                         state = previous_state;
69                                 else if ( c == '\\')
70                                         state = BACKSLASH_in_STRING;
71                                 save_or_put( c);
72                                 break;
73
74                   case BACKSLASH_in_STRING :
75                                 state = STRING;
76                                 save_or_put( c);
77                                 break;
78
79
80
81
82                   case CHAR_CONST :
83                                 if ( c == '\'')
84                                         state = previous_state;
85                                 else if ( c == '\\')
86                                         state = BACKSLASH_in_CHAR_CONST;
87                                 save_or_put( c);
88                                 break;
89
90                   case BACKSLASH_in_CHAR_CONST :
91                                 state = CHAR_CONST;
92                                 save_or_put( c);
93                                 break;
94
95                                 
96                                 
97                   case AT :     /* @if '(' <CONDITION> ')'
98                                  * @elsif '(' <CONDITION> ')'
99                                  * @else
100                                  * @fi
101                                  * @<IDENTIFIER> '(' <PARAM_LIST> ')'
102                                  */
103                                 if ( is_letter( c))
104                                         *bufptr++ = c;
105                                 else {
106                                         ungetc( c, stdin);
107                                         state = WHITE_SPACE;
108                                 }
109                                 break;
110
111                   case WHITE_SPACE :
112                                 if ( isspace( c))
113                                         *bufptr++ = c;
114                                 else if ( c == '(') {
115                                         *bufptr++ = c;
116                                         depth = 1;
117                                         state = CAL_or_QUEST;
118                                 }
119                                 else {
120                                         *bufptr = '\0';
121                                         pr_ELSE_or_FI( buffer);
122                                         bufptr = buffer;
123                                         ungetc( c, stdin);
124                                         state = TEXT;
125                                 }
126                                 break;
127
128                   case CAL_or_QUEST :   /* match ')' */
129                                 *bufptr++ =c;
130                                 switch ( c) {
131                                   case '(' : depth++;
132                                              break;
133                                   case ')' : depth--;
134                                              if ( depth == 0) {
135                                                      *bufptr = '\0';
136                                                      pr_CALL_or_QUEST( buffer);
137                                                      bufptr = buffer;
138                                                      state = TEXT;
139                                              }
140                                              break;
141                                   case '/' : state = SLASH;
142                                              previous_state = CAL_or_QUEST;
143                                              break;
144                                   case '"' : state = STRING;
145                                              previous_state = CAL_or_QUEST;
146                                              break;
147                                   case '\'': state = CHAR_CONST;
148                                              previous_state = CAL_or_QUEST;
149                                              break;
150                                 }
151                                 break;
152                   default :     
153                                 fprintf( stderr, "Unknown state : %d\n", state);
154                                 break;
155         }
156         exit( 0);
157 }
158
159 pr_header()
160 {
161         printf( "#include \"as_parser.h\"\n");
162         printf( "#line 1 \"as.c\"\n");
163 }
164
165
166 pr_ELSE_or_FI( str)
167 char *str;
168 {
169         if ( strncmp( str, "else", 4) == 0)
170                 printf( "fprint( outfile, \"}\else {\");%s", str+4);
171         else if ( strncmp( str, "fi", 2) == 0)
172                 printf( "fprint( outfile, \"}\");%s", str+2);
173         else
174                 fprintf( stderr, "%s  unexpected!!\n", str);
175 }
176
177
178 pr_CALL_or_QUEST( str)
179 char *str;
180 {
181         if ( strncmp( str, "if", 2) == 0 && !(is_letter( *(str+2))))
182                 pr_if( str);
183         else if ( strncmp( str, "elsif", 5) == 0 && !(is_letter( *(str+5))))
184                 pr_elsif( str);
185         else
186                 pr_call( str);
187 }
188
189
190 /* Adjust 'cur_pos' when necessary */
191
192 pr_call( call)
193 char *call;
194 {
195         char c;
196
197         printf( "{");
198         if ( strncmp( "text", call, 4) == 0 && isdigit( *(call+4))) 
199                 printf( "cur_pos += %d;", *(call+4) - '0');
200         else if ( strncmp( "reloc", call, 5) == 0 && isdigit( *(call+5)))
201                 printf( "cur_pos += %d;", *(call+5) - '0');
202
203         pr_text_with_conversions( call);
204         printf( "fprint( outfile, \";\");");
205         printf( "}");
206         for (; ( c = getchar()) != ';' ; putchar( c));  /* skip ';' */
207 }
208
209 pr_elsif( quest)
210 char *quest;
211 {
212         printf( "fprint( outfile, \"}\else if\");");
213         pr_text_with_conversions( quest+5);
214         printf( "fprint( outfile, \"{\");");
215 }
216
217 pr_if( quest)
218 char *quest;
219 {
220         pr_text_with_conversions( quest);
221         printf( "fprint( outfile, \"{\");");
222 }
223
224
225 pr_text_with_conversions( str)
226 char *str;
227 {
228         char *ptr, *next_conversion(), *pr_conversion();
229
230         while (  ptr = next_conversion( str)) {
231                 /* ptr points to '%'-sign */
232                 *ptr = '\0';
233                 printf( "fprint( outfile, \"");
234                 pr_string( str);
235                 printf( "\");");
236                 *ptr = '%';
237                 str = pr_conversion( ptr);
238         }
239         printf( "fprint( outfile, \"");
240         pr_string( str);
241         printf( "\");");
242 }
243
244
245 pr_string( s)
246 char *s;
247 {
248         for ( ; *s != '\0'; s++)
249                 switch ( *s) {
250                   case '"' : printf( "\\\"");
251                              break;
252
253                   case '\\': printf( "\\\\");
254                              break;
255
256                   case '\n': printf( "\\n");
257                              break;
258
259                   default  : printf( "%c", *s);
260                 }
261 }
262
263
264 char *next_conversion( str)
265 char *str;
266 {
267         char *match();
268
269         while ( *str && *str != '%') {
270                 switch ( *str++) {
271                   case '\'' : str = match( '\'', str) + 1;
272                               break;
273                   case '"'  : str = match( '"', str) + 1;
274                               break;
275                 }
276         }
277         return( *str == '%' ? str : (char *)0);
278 }
279
280 char *match( c, str)
281 char c, *str;
282 {
283         while ( *str && ( *str != c || *(str-1) == '\\'))
284                 str++;
285         return( *str ? str : str-1);
286 }
287
288 char *match_bracket( str)
289 char *str;
290
291 /* find ')', but look at nesting '('-')' pairs, return position of ')'.
292  */
293 {
294         int depth;
295         char *match();
296
297         depth = 1;
298         while ( *str && depth != 0) { 
299                 switch ( *str++) {
300                   case '\'' : str = match( '\'', str+1) + 1;
301                               break;
302                   case '"'  : str = match( '"', str+1) + 1;
303                               break;
304                   case '('  : depth++;
305                               break;
306                   case ')'  : depth--;
307                               break;
308                 }
309         }
310         return( str-1);
311 }
312
313
314 char *find( c, str)
315 char c, *str;
316 {
317         while ( *str && *str != c)
318                 str++;
319         return( str);
320 }
321         
322 char *pr_conversion( str)
323 char *str;
324
325 /* str points to '%'-sign, returns pointer to first character AFTER the
326  * conversion
327  */
328 {
329         char *start, *ptr, *match_bracket(), *find();
330
331         start = find( '(', str+1);
332         *start++ = '\0';
333
334         ptr = match_bracket( start);
335         *ptr = '\0';
336
337         if ( *(str+1) == '$')
338                 printf( "eval( %s);", start);
339         else if ( strncmp( str+1, "dist", 4) == 0)
340                 printf( "dist( %s);", start);
341         else
342                 printf( "fprint( outfile, \"%%%s\", %s);", str+1, start);
343
344         return( ptr+1);
345 }