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