1 /* Copyright (C) 2002 Guillaume Bour
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18 /*
19 FIXME:
20 + on ne peut pas comparer 2 bool�ens (vrai = vrai)
21 + on ne peut pas comparer 2 chaines ("a = "a)
22 */
23 %{
24 #include <stdio.h>
25 #include <gtk/gtk.h>
26 #include "turtle.h"
27 #include "mc.h"
28 #include "op.h"
29 #include "list.h"
30 #include "constant.h"
31 #include "variable.h"
32
33 void yyerror(char *error);
34
35 guint linecnt;
36 gchar *input_str;
37 guint curpos;
38
39 extern struct s_turtle my_turtle;
40
41 typedef int(*lexlang_t)(void);
42 lexlang_t lexlang[2] = {
43 enlex,
44 frlex
45 };
46
47 GSList *repeat_instr = NULL;
48 guint loop_ref;
49
50 char *lextxt;
51 %}
52
53 %union {
54 guint intval;
55 gdouble floatval;
56 gboolean boolval;
57 gchar *strval;
58
59 GSList *list;
60 struct s_class *mc;
61 }
62
63 %token TOK_BEGPROC TOK_ENDPROC
64 %token <strval> TOK_PROCNAME TOK_VARIABLE
65 %token TOK_MOVEFORWARD TOK_MOVEBACK
66 %token TOK_TURNRIGHT TOK_TURNLEFT
67 %token TOK_SETPOS TOK_SETHEADING
68 %token TOK_CLEARSCREEN
69 %token TOK_HIDETURTLE TOK_SHOWTURTLE
70 %token TOK_COLOR
71 %token TOK_NOTRACE TOK_TRACE
72 %token TOK_WRITE TOK_STOP
73 %token TOK_RETURN
74 %token TOK_AFFECT TOK_LOCALAFFECT
75 %token TOK_DANCE TOK_SLEEP
76
77 %token TOK_REPEAT TOK_IF
78 %token TOK_WHILE
79
80 %token <intval> TOK_INT
81 %token <floatval> TOK_FLOAT
82 %token <boolval> TOK_BOOL
83 %token <strval> TOK_STRING
84 %token TOK_LOOPCNT TOK_HAZARD
85 %token TOK_GETHEADING
86
87 %type <list> arguments
88 %type <mc> arith_expr bool_expr
89 %type <mc> expression
90
91 %token TOK_LEQ TOK_GEQ
92
93
94 %left '+' '-'
95 %left '*' '/'
96 %left uneg
97 %left '(' ')'
98 %%
99
100 input: procedures statements
101 ;
102
103 procedures:
104 | procedure procedures
105 ;
106
107 procedure: TOK_BEGPROC TOK_PROCNAME
108 { mc_beginning_procedure($2); }
109 parameters statements TOK_ENDPROC
110 { mc_ending_procedure(); }
111 ;
112
113 parameters:
114 | TOK_VARIABLE
115 { mc_add_proc_parameter($1); }
116 parameters
117 ;
118
119 statements:
120 | statement statements
121 ;
122
123 statement: proc_call
124 | repeat_expr
125 | if_expr
126 | while_expr
127
128 | TOK_MOVEFORWARD arith_expr
129 { mc_add_unary_op(OP_MOVEFORWARD, $2); }
130 | TOK_MOVEBACK arith_expr
131 { mc_add_unary_op(OP_MOVEBACK, $2); }
132 | TOK_TURNRIGHT arith_expr
133 { mc_add_unary_op(OP_TURNRIGHT, $2); }
134 | TOK_TURNLEFT arith_expr
135 { mc_add_unary_op(OP_TURNLEFT, $2); }
136 | TOK_SETPOS '[' arith_expr arith_expr ']'
137 { mc_add_binary_op(OP_SETPOS, $3, $4); }
138 | TOK_SETHEADING arith_expr
139 { mc_add_unary_op(OP_SETHEADING, $2); }
140 | TOK_CLEARSCREEN
141 { mc_add_noarg_op(OP_CLEARSCREEN); }
142 | TOK_HIDETURTLE
143 { mc_add_noarg_op(OP_HIDETURTLE); }
144 | TOK_SHOWTURTLE
145 { mc_add_noarg_op(OP_SHOWTURTLE); }
146 //v�rifier que l'interval est OK (0 � 15) => � l'exec
147 | TOK_COLOR arith_expr
148 { mc_add_unary_op(OP_SETPREDEFCOLOR, $2); }
149 //v�rifier que l'interval est OK (0 � 255) => � l'exec
150 | TOK_COLOR '[' arith_expr arith_expr arith_expr ']'
151 {
152 GSList *colors = NULL;
153 struct s_list *mccolors;
154
155 colors = g_slist_append(colors, $3);
156 colors = g_slist_append(colors, $4);
157 colors = g_slist_append(colors, $5);
158
159 mccolors = list_alloc(class_free_from_list);
160 mccolors->GTKList = colors;
161
162 mc_add_unary_op(OP_SETUSERDEFCOLOR, mccolors);
163 }
164 | TOK_NOTRACE
165 { mc_add_noarg_op(OP_NOTRACE); }
166 | TOK_TRACE
167 { mc_add_noarg_op(OP_TRACE); }
168 | TOK_WRITE expression
169 { mc_add_unary_op(OP_WRITE, $2); }
170 | TOK_STOP
171 { mc_add_noarg_op(OP_STOP); }
172 | TOK_RETURN expression
173 { mc_add_unary_op(OP_RETURN, $2); }
174 | TOK_AFFECT TOK_STRING
175 { $<mc>$ = mc_add_variable(VAR_GLOBAL, $2); }
176 expression
177 { mc_add_binary_op(OP_AFFECT, $<mc>3, $4); }
178 | TOK_LOCALAFFECT TOK_STRING
179 { $<mc>$ = mc_add_variable(VAR_LOCAL, $2); }
180 expression
181 { mc_add_binary_op(OP_LOCAFFECT, $<mc>3, $4); }
182
183 | TOK_DANCE
184 { mc_add_noarg_op(OP_DANCE); }
185 | TOK_SLEEP
186 { mc_add_noarg_op(OP_SLEEP); }
187 ;
188
189 proc_call: TOK_PROCNAME
190 {
191 /* we get the pointer onto the procedure (by its name) */
192 $<mc>$ = mc_find_procedure($1);
193 }
194 arguments
195 {
196 struct s_list *plist = NULL;
197
198 if($3 != NULL)
199 {
200 plist = list_alloc(class_free_from_list);
201 plist->GTKList = $3;
202 }
203
204 //~~~
205 mc_add_binary_op(OP_PROCCALL, $<mc>2, plist);
206 }
207 ;
208
209 arguments: { $$ = NULL; }
210 | expression arguments
211 { if($1 != NULL) class_ref($1); $$ = g_slist_prepend($2, $1); }
212 ;
213
214 repeat_expr: TOK_REPEAT
215 { $<mc>$ = mc_add_noarg_op(OP_NOOP); }
216 arith_expr
217 {
218 /* warning: the condition is the third argument !! */
219 $<mc>$ = mc_add_binary_op(OP_REPEAT, NULL, $3);
220 repeat_instr = g_slist_prepend(repeat_instr, $<mc>$);
221 loop_ref = 0;
222 }
223 '[' statements ']'
224 {
225 struct s_class *jmp, *noop;
226
227 jmp = mc_add_unary_op(OP_JUMP, NULL);
228 mc_update_branch(INSTR(jmp),
229 INSTR($<mc>2));
230
231 noop = mc_add_noarg_op(OP_NOOP);
232 mc_update_branch((struct s_instr *)$<mc>4,
233 (struct s_instr *)noop);
234
235 repeat_instr = g_slist_remove(repeat_instr, $<mc>4);
236 }
237 ;
238
239 if_expr: TOK_IF bool_expr
240 { $<mc>$ = mc_add_binary_op(OP_IF, NULL, $2); }
241 '[' statements ']'
242 {
243 struct s_class *noop;
244
245 $<mc>$ = mc_add_unary_op(OP_JUMP, NULL);
246
247 noop = mc_add_noarg_op(OP_NOOP);
248 mc_update_branch(INSTR($<mc>3),
249 INSTR(noop));
250 }
251 else_expr
252 {
253 struct s_class *noop;
254
255 noop = mc_add_noarg_op(OP_NOOP);
256 mc_update_branch(INSTR($<mc>7),
257 INSTR(noop));
258 }
259 ;
260
261 else_expr:
262 | '[' statements ']'
263 ;
264
265 while_expr: TOK_WHILE
266 { $<mc>$ = mc_add_noarg_op(OP_NOOP); }
267 bool_expr
268 {
269 /* warning: the condition is the third argument !! */
270 $<mc>$ = mc_add_binary_op(OP_WHILE, NULL, $3);
271 }
272 '[' statements ']'
273 {
274 struct s_class *jmp, *noop;
275
276 jmp = mc_add_unary_op(OP_JUMP, NULL);
277 mc_update_branch(INSTR(jmp),
278 INSTR($<mc>2));
279
280 noop = mc_add_noarg_op(OP_NOOP);
281 mc_update_branch(INSTR($<mc>4),
282 INSTR(noop));
283
284 }
285 ;
286
287 expression: TOK_STRING
288 { $$ = mc_add_constant(T_STRING, $1); }
289 | bool_expr
290 { $$ = $1; }
291 | arith_expr
292 { $$ = $1; }
293 ;
294
295 bool_expr: TOK_BOOL
296 { $$ = mc_add_constant(T_BOOL, $1); }
297
298 | bool_expr '&' bool_expr
299 { $$ = mc_add_binary_op(OP_AND, $1, $3); }
300 | bool_expr '|' bool_expr
301 { $$ = mc_add_binary_op(OP_OR, $1, $3); }
302
303 | arith_expr '=' arith_expr
304 { $$ = mc_add_binary_op(OP_EQ, $1, $3); }
305 | arith_expr '<' arith_expr
306 { $$ = mc_add_binary_op(OP_LT, $1, $3); }
307 | arith_expr '>' arith_expr
308 { $$ = mc_add_binary_op(OP_GT, $1, $3); }
309 | arith_expr TOK_LEQ arith_expr
310 { $$ = mc_add_binary_op(OP_LEQ, $1, $3); }
311 | arith_expr TOK_GEQ arith_expr
312 { $$ = mc_add_binary_op(OP_GEQ, $1, $3); }
313 ;
314
315 arith_expr: TOK_INT
316 { $$ = mc_add_constant(T_INT, $1); }
317 | TOK_FLOAT
318 { $$ = mc_add_constant(T_FLOAT, $1); }
319 | TOK_VARIABLE
320 { $$ = mc_add_variable_reference($1); }
321 | TOK_LOOPCNT
322 {
323 struct s_class *repeat;
324 /* we must get the reference to the loop counter !!! */
325 loop_ref++;
326 repeat = g_slist_nth_data(repeat_instr, 0);
327 $$ = mc_add_unary_op(OP_LOOPCNT, repeat);
328 }
329 | TOK_HAZARD arith_expr
330 { $$ = mc_add_unary_op(OP_HAZARD, $2); }
331 | TOK_GETHEADING
332 { $$ = mc_add_noarg_op(OP_GETHEADING); }
333
334 | arith_expr '+' arith_expr
335 { $$ = mc_add_binary_op(OP_ADD, $1, $3); }
336 | arith_expr '-' arith_expr
337 { $$ = mc_add_binary_op(OP_SUB, $1, $3); }
338 | arith_expr '*' arith_expr
339 { $$ = mc_add_binary_op(OP_MUL, $1, $3); }
340 | arith_expr '/' arith_expr
341 { $$ = mc_add_binary_op(OP_DIV, $1, $3); }
342 | '-' arith_expr %prec uneg
343 { $$ = mc_add_unary_op(OP_UNEG, $2); }
344 | '(' arith_expr ')'
345 { $$ = $2; }
346 ;
347 %%
348
349 int launch_parser(gchar *program)
350 {
351 input_str = program;
352 curpos = 0;
353 linecnt = 0;
354
355 my_turtle.compilation_failed = FALSE;
356 yyparse();
357
358 return(0);
359 }
360
yyerror(char * error)361 void yyerror(char *error)
362 {
363 my_turtle.compilation_failed = TRUE;
364 printf("%d: invalid logo code: '%s'\n", linecnt, lextxt);
365 }
366
367 /* here we switch between differents languages-parser */
yylex()368 int yylex()
369 {
370 return((*lexlang[my_turtle.locale])());
371 }
372