Workaround from Dick to the string.Replace bug
[mono.git] / mono / monoburg / monoburg.y
1 %{
2 /*
3  * monoburg.y: yacc input grammer
4  *
5  * Author:
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <assert.h>
17 #include <stdarg.h>
18
19 #include "monoburg.h"
20   
21 static int yylineno = 0;
22 static int yylinepos = 0;
23
24 %}
25
26 %union {
27   char *text;
28   int   ivalue;
29   Tree  *tree;
30 }
31
32 %token <text> IDENT
33 %token <text> CODE
34 %token <text> STRING
35 %token  START
36 %token  COST
37 %token  TERM
38 %token  TERMPREFIX
39 %token <ivalue> INTEGER
40
41 %type   <tree>          tree
42 %type   <text>          optcost
43 %type   <text>          optcfunc
44 %type   <text>          optcode
45
46 %%
47
48 decls   : /* empty */ 
49         | START IDENT { start_nonterm ($2); } decls
50         | TERM  tlist decls
51         | TERMPREFIX plist decls
52         | IDENT ':' tree optcost optcode optcfunc { create_rule ($1, $3, $5, $4, $6); } decls 
53         ;
54
55 optcode : /* empty */ { $$ = NULL; }
56         | CODE 
57         ;
58
59 plist   : /* empty */
60         | plist IDENT { create_term_prefix ($2);}
61         ;
62
63 tlist   : /* empty */
64         | tlist IDENT { create_term ($2, -1);}
65         | tlist IDENT '=' INTEGER { create_term ($2, $4); }
66         ;
67
68 tree    : IDENT { $$ = create_tree ($1, NULL, NULL); }
69         | IDENT '(' tree ')' { $$ = create_tree ($1, $3, NULL); }
70         | IDENT '(' tree ',' tree ')' { $$ = create_tree ($1, $3, $5); }
71         ;
72
73 optcost : /* empty */ {$$ = NULL; }
74         | STRING
75         | INTEGER { $$ = g_strdup_printf ("%d", $1); }
76         ;
77
78 optcfunc : /*empty */ { $$ = NULL; }
79          | COST CODE { $$ = $2; }
80          ;
81 %%
82
83 static char input[2048];
84 static char *next = input;
85
86 void 
87 yyerror (char *fmt, ...)
88 {
89   va_list ap;
90
91   va_start(ap, fmt);
92
93   fprintf (stderr, "line %d(%d): ", yylineno, yylinepos);
94   vfprintf (stderr, fmt, ap);
95   fprintf(stderr, "\n");
96
97   va_end (ap);
98
99   exit (-1);
100 }
101
102 static int state = 0;
103
104 void
105 reset_parser ()
106 {
107   state = 0;
108 }
109
110 struct pplist {
111   struct pplist *next;
112   gboolean ignore;
113 };
114
115 static struct pplist *pp = NULL;
116
117 static char*
118 getvar (const char *input)
119 {
120     char *var = g_strchug (g_strdup (input));
121     char *ptr;
122
123     for (ptr = var; *ptr && *ptr != '\n'; ++ptr) {
124         if (g_ascii_isspace (*ptr)) {
125             break;
126         }
127     }
128     *ptr = '\0';
129
130     return var;
131 }
132
133 static void
134 push_if (char *input, gboolean flip)
135 {
136   struct pplist *new_pp = g_new (struct pplist, 1);
137   char *var = getvar (input);
138
139   new_pp->ignore = (g_hash_table_lookup (definedvars, var) == NULL) ^ flip;
140   new_pp->next = pp;
141
142   new_pp->ignore |= (pp ? pp->ignore : 0);
143   pp = new_pp;
144   g_free (var);
145 }
146
147 static void
148 flip_if ()
149 {
150   if (!pp)
151       yyerror ("%%else without %%if");
152
153   pp->ignore = !pp->ignore | (pp->next ? pp->next->ignore : 0);
154 }
155
156 static void
157 pop_if ()
158 {
159   struct pplist *prev_pp = pp;
160
161   if (!pp)
162       yyerror ("%%endif without %%if");
163
164   pp = pp->next;
165   g_free (prev_pp);
166 }
167
168 static char
169 nextchar ()
170 {
171   int next_state ;
172   gboolean ll;
173
174     if (!*next) {
175       next = input;
176       *next = 0;
177       do {
178         if (!fgets (input, sizeof (input), inputfd))
179           return 0;
180
181         ll = (input [0] == '%' && input [1] == '%');
182         next_state = state;
183
184         if (state == 1) {
185           if (!ll && input [0] == '%') {
186             if (!strncmp (&input [1], "ifdef", 5)) {
187               push_if (&input [6], FALSE);
188               ll = TRUE;
189               continue;
190             }
191             else if (!strncmp (&input [1], "ifndef", 6)) {
192               push_if (&input [7], TRUE);
193               ll = TRUE;
194               continue;
195             }
196             else if (!strncmp (&input [1], "else", 4)) {
197               flip_if ();
198               ll = TRUE;
199               continue;
200             }
201             else if (!strncmp (&input [1], "endif", 5)) {
202               pop_if ();
203               ll = TRUE;
204               continue;
205             }
206           }
207           if (pp && pp->ignore) {
208             ll = TRUE;
209             continue;
210           }
211         }
212
213         switch (state) {
214         case 0:
215           if (ll) {
216             next_state = 1;
217           } else 
218             fputs (input, outputfd);
219           break;
220         case 1:
221           if (ll) {
222             next_state = 2;
223             *next = 0;
224           }
225           break;
226         default:
227           return 0;
228         }
229         ll = state != 1 || input[0] == '#';
230         state = next_state;
231         yylineno++;
232       } while (next_state == 2 || ll);
233     } 
234
235     return *next++;
236 }
237
238 void
239 yyparsetail (void)
240 {
241   fputs (input, outputfd);
242   while (fgets (input, sizeof (input), inputfd))
243     fputs (input, outputfd);
244 }
245
246 int 
247 yylex (void) 
248 {
249   char c;
250
251   do {
252
253     if (!(c = nextchar ()))
254       return 0;
255
256     yylinepos = next - input + 1;
257
258     if (isspace (c))
259       continue;
260
261     if (c == '%') {
262       if (!strncmp (next, "start", 5) && isspace (next[5])) {
263         next += 5;
264         return START;
265       }
266
267       if (!strncmp (next, "termprefix", 10) && isspace (next[10])) {
268         next += 10;
269         return TERMPREFIX;
270       }
271
272       if (!strncmp (next, "term", 4) && isspace (next[4])) {
273         next += 4;
274         return TERM;
275       }
276       return c;
277     }
278
279     if (isdigit (c)) {
280             int num = 0;
281
282             do {
283                     num = 10*num + (c - '0');
284             } while (isdigit (c = (*next++)));
285
286             yylval.ivalue = num;
287             return INTEGER;
288     }
289
290     if (isalpha (c)) {
291       char *n = next;
292       int l;
293
294       if (!strncmp (next - 1, "cost", 4) && isspace (next[3])) {
295         next += 4;
296         return COST;
297       }
298
299       while (isalpha (*n) || isdigit (*n) || *n == '_') 
300               n++;
301
302       l = n - next + 1;
303       yylval.text = g_strndup (next - 1, l);
304       next = n;
305       return IDENT;
306     }
307     
308     if (c == '"') {
309       int i = 0;
310       static char buf [100000];
311  
312       while ((c = *next++) != '"' && c)
313         buf [i++] = c;
314       
315       buf [i] = '\0';
316       yylval.text = g_strdup (buf);
317
318       return STRING;
319     }
320
321     if (c == '{') {
322       int i = 0, d = 1;
323       static char buf [100000];
324  
325       while (d && (c = nextchar ())) {
326         buf [i++] = c;
327         assert (i < sizeof (buf));
328
329         switch (c) {
330         case '{': d++; break;
331         case '}': d--; break;
332         default:
333                 break;
334         }
335       }
336       buf [--i] = '\0';
337       yylval.text = g_strdup (buf);
338
339       return CODE;
340     }
341     
342     return c;
343   
344   } while (1);
345 }
346