New test.
[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   input [0] = '\0';
262 }
263
264 int 
265 yylex (void) 
266 {
267   char c;
268
269   do {
270
271     if (!(c = nextchar ()))
272       return 0;
273
274     yylinepos = next - input + 1;
275
276     if (isspace (c))
277       continue;
278
279     if (c == '%') {
280       if (!strncmp (next, "start", 5) && isspace (next[5])) {
281         next += 5;
282         return START;
283       }
284
285       if (!strncmp (next, "termprefix", 10) && isspace (next[10])) {
286         next += 10;
287         return TERMPREFIX;
288       }
289
290       if (!strncmp (next, "term", 4) && isspace (next[4])) {
291         next += 4;
292         return TERM;
293       }
294       return c;
295     }
296
297     if (isdigit (c)) {
298             int num = 0;
299
300             do {
301                     num = 10*num + (c - '0');
302             } while (isdigit (c = (*next++)));
303
304             yylval.ivalue = num;
305             return INTEGER;
306     }
307
308     if (isalpha (c)) {
309       char *n = next;
310       int l;
311
312       if (!strncmp (next - 1, "cost", 4) && isspace (next[3])) {
313         next += 4;
314         return COST;
315       }
316
317       while (isalpha (*n) || isdigit (*n) || *n == '_') 
318               n++;
319
320       l = n - next + 1;
321       yylval.text = g_strndup (next - 1, l);
322       next = n;
323       return IDENT;
324     }
325     
326     if (c == '"') {
327       int i = 0;
328       static char buf [100000];
329  
330       while ((c = *next++) != '"' && c)
331         buf [i++] = c;
332       
333       buf [i] = '\0';
334       yylval.text = g_strdup (buf);
335
336       return STRING;
337     }
338
339     if (c == '{') {
340       int i = 0, d = 1;
341       static char buf [100000];
342  
343       while (d && (c = nextchar ())) {
344         buf [i++] = c;
345         assert (i < sizeof (buf));
346
347         switch (c) {
348         case '{': d++; break;
349         case '}': d--; break;
350         default:
351                 break;
352         }
353       }
354       buf [--i] = '\0';
355       yylval.text = g_strdup (buf);
356
357       return CODE;
358     }
359     
360     return c;
361   
362   } while (1);
363 }
364