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